Нестабильность умножения матриц с числами float32 в numpy на python3 - PullRequest
4 голосов
/ 25 апреля 2019

Я столкнулся со странным явлением, когда вычислял скалярное произведение матриц, используя numpy. Короче говоря, для математически идентичных вычислений numpy дает мне разные результаты.

Следующий фрагмент кода иллюстрирует проблему:

import numpy as np
np.set_printoptions(precision=10)
np.random.seed(2)  # for reproducibility

# create matrices:
A = np.random.rand(300, 1)
A = A/np.sum(A)
A = np.repeat(A, 15, 1)
B = np.random.rand(300, 300)

# convert data to float32:
A_star = A.astype("float32")
B_star = B.astype("float32")

# do the matrix multiplication A'BA and take the diagonal:
res_star = np.diag(A_star.transpose().dot(B_star.dot(A_star)))

# print the results:
print(res_star)

При запуске в python3.5 с numpy1.11.1 на машине с Windows печатается следующий массив:

[0.5000683069  0.5000683069  0.5000683069  0.5000683069  0.5000683069
 0.5000683069  0.5000683069  0.5000683069  0.5000683069  0.5000683069
 0.5000683069  0.5000683069  0.5000681877  0.5000681877  0.5000683069]

Обратите внимание, что значения в res_star[12:14] отличаются от других элементов массива - хотя математически можно ожидать, что они совпадают.

Мои собственные исследования этих различий не были особенно успешными, но, думаю, я немного их сузил:

  • с dtype float64 значения в полученном массиве идентичны
  • в случае значений float32 различия в значениях обычно начинаются только с 7-го знака после запятой (области, где заканчивается точность float32)

Тем не менее, для меня эти выводы не могут реально объяснить различия в массиве, поскольку происходит одна и та же математическая операция (они действительно объясняют различия в значениях, если бы я вычислял те же точечные произведения на тех же матрицах с dtype float64). Кроме того, для разных начальных чисел и размеров матрицы результирующие значения могут фактически совпадать, поэтому это поведение не соответствует.

  • на машине UNIX приведенный выше фрагмент кода возвращает идентичные цифры (по крайней мере, в этой конкретной конфигурации)

Сейчас

1) что вызывает такое поведение и

2) как я могу обеспечить идентичные результаты в массиве, не меняя dtype на float64?

...