Разница между параметром out = ... и прямым переназначением в NumPy - PullRequest
0 голосов
/ 12 января 2019

Могут ли следующие два np.dot дать одинаковый результат для квадратного массива x?

import numpy as np
x = np.arange(4 * 4).reshape(4, 4)
np.dot(x, x.T, out=x)  # method 1
x[:] = np.dot(x, x.T)  # method 2

Спасибо.

Почему я спрашиваю:

x += x.T не совпадает с x += x.T.copy()

Я не знаю, как работает внутренняя часть np.dot. Np.dot так же рассматривает аргумент out как представление? это нормально, если out - умножить одну из матриц?

Я использую Numpy от Anaconda, которая использует MKL в качестве бэкэнда.

Ответы [ 3 ]

0 голосов
/ 12 января 2019

Да, оба метода создают идентичные массивы.

import numpy as np

def method_1():
    x = np.arange(4 * 4).reshape(4, 4)
    np.dot(x, x.T, out=x)
    return x

def method_2():
    x = np.arange(4 * 4).reshape(4, 4)
    x[:] = np.dot(x, x.T)
    return x

array_1 = method_1()
array_2 = method_2()

print(np.array_equal(array_1, array_2))

дает вывод:

Правда

0 голосов
/ 12 января 2019

У меня установлена ​​более старая версия numpy (1.11.0), где метод # 1 выдает странный вывод. Я понимаю, что это не ожидаемое поведение, и было исправлено в более поздних версиях; но на случай, если это случится с кем-то еще:

Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
>>> import numpy as np
>>> x = np.arange(4 * 4).reshape(4, 4)
>>> np.dot(x, x.T, out=x)
array([[                  14,                   94,                 1011,
                       15589],
       [              115715,          13389961335,         120510577872,
               1861218976248],
       [              182547,       21820147595568,  1728119013671256390,
         5747205779608970957],
       [              249379,       29808359122268,  7151350849816304816,
        -3559891853923251270]])
>>> np.version.version
'1.11.0'

Насколько я могу проверить, по крайней мере, начиная с numpy 1.14.1, метод # 1 дает ожидаемый результат; как метод # 2 делает с обеими версиями.

0 голосов
/ 12 января 2019

Да, они одинаковы, но по производительности я вижу интересные результаты для целочисленных массивов:

import perfplot

def f1(x):
    x = x.copy()
    np.dot(x, x.T, out=x)
    return x

def f2(x):
    x = x.copy()
    x[:] = np.dot(x, x.T)
    return x    

perfplot.show(
    setup=lambda n: np.arange(n * n).reshape(n, n),
    kernels=[f1, f2],
    labels=['out=...', 're-assignment'],
    n_range=[2**k for k in range(0, 9)],
    xlabel='N',
    equality_check=np.allclose
)

enter image description here

Я использовал perfplot для генерации времени графика.


Для массивов с плавающей запятой нет абсолютно никакой разницы.

perfplot.show(
    setup=lambda n: np.arange(n * n).reshape(n, n).astype(float),
    kernels=[f1, f2],
    labels=['out=...', 're-assignment'],
    n_range=[2**k for k in range(0, 9)],
    xlabel='N',
    equality_check=np.allclose
)

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...