Матричное умножение на CPU (numpy) и GPU (gnumpy) дает разные результаты

Я использую gnumpy для ускорения некоторых вычислений в обучении нейронной сети, выполняя их на GPU. Я получаю желаемое ускорение, но немного беспокоюсь о различиях в результатах numpy (cpu) и gnumpy (gpu).

Для иллюстрации проблемы у меня есть следующий тестовый скрипт:

import gnumpy as gpu import numpy as np n = 400 a = np.random.uniform(low=0., high=1., size=(n, n)).astype(np.float32) b = np.random.uniform(low=0., high=1., size=(n, n)).astype(np.float32) ga = gpu.garray(a) gb = gpu.garray(b) ga = ga.dot(gb) a = a.dot(b) print ga.as_numpy_array(dtype=np.float32) - a 

который обеспечивает выход:

 [[ 1.52587891e-05 -2.28881836e-05 2.28881836e-05 ..., -1.52587891e-05 3.81469727e-05 1.52587891e-05] [ -5.34057617e-05 -1.52587891e-05 0.00000000e+00 ..., 1.52587891e-05 0.00000000e+00 1.52587891e-05] [ -1.52587891e-05 -2.28881836e-05 5.34057617e-05 ..., 2.28881836e-05 0.00000000e+00 -7.62939453e-06] ..., [ 0.00000000e+00 1.52587891e-05 3.81469727e-05 ..., 3.05175781e-05 0.00000000e+00 -2.28881836e-05] [ 7.62939453e-06 -7.62939453e-06 -2.28881836e-05 ..., 1.52587891e-05 7.62939453e-06 1.52587891e-05] [ 1.52587891e-05 7.62939453e-06 2.28881836e-05 ..., -1.52587891e-05 7.62939453e-06 3.05175781e-05]] 

Как вы можете видеть, различия составляют величину 10 ^ -5.

Поэтому возникает вопрос: следует ли беспокоиться об этих различиях или это ожидаемое поведение?

Дополнительная информация:

  • Графический процессор: GeForce GTX 770;
  • numpy version: 1.6.1

Я заметил проблему, когда я использовал проверку градиента (с конечной разностной аппроксимацией), чтобы проверить, что небольшие изменения, которые я сделал для переключения с numpy на gnumpy, не нарушали ничего. Поскольку можно ожидать, что проверка градиента не будет работать с 32-битной точностью (gnumpy не поддерживает float64), но, к моему удивлению, ошибки различались между CPU и GPU при использовании той же точности.

Ниже приведены ошибки в CPU и GPU на небольшой тестовой нейронной сети: ошибки проверки градиента

Поскольку величины ошибок схожи, я думаю, что эти различия в порядке?

После прочтения статьи , упомянутой в комментарии BenC, я совершенно уверен, что различия могут быть объяснены главным образом одним из устройств, использующим инструкцию с объединенным умножением (FMA), а другая нет.

Я привел пример из статьи:

 import gnumpy as gpu import numpy as np a=np.array([1.907607,-.7862027, 1.147311, .9604002], dtype=np.float32) b=np.array([-.9355000, -.6915108, 1.724470, -.7097529], dtype=np.float32) ga = gpu.garray(a) gb = gpu.garray(b) ga = ga.dot(gb) a = a.dot(b) print "CPU", a print "GPU", ga print "DIFF", ga - a >>>CPU 0.0559577 >>>GPU 0.0559577569366 >>>DIFF 8.19563865662e-08 

… и разница похожа на FMA по сравнению с серийным алгоритмом (хотя по некоторым причинам оба результата отличаются от точного результата больше, чем в статье).

GPU, который я использую (GeForce GTX 770), поддерживает инструкцию FMA, в то время как у CPU нет (у меня есть Ivy Bridge Intel® Xeon (R) CPU E3-1225 V2, но Intel представила инструкцию FMA3 в своих продуктах с Haswell).

Другие возможные объяснения включают в себя различные математические библиотеки, используемые в фоновом режиме, или различия в последовательности операций, вызванные, например, разным уровнем распараллеливания на CPU и GPU.

One Solution collect form web for “Матричное умножение на CPU (numpy) и GPU (gnumpy) дает разные результаты”

Я бы рекомендовал использовать np.allclose для проверки того, являются ли два массива с плавающей точкой почти равными.

В то время как вы смотрите только на абсолютную разницу между значениями в ваших двух массивах результатов, np.allclose также учитывает их относительные различия. Предположим, например, что значения в ваших входных массивах были на 1000 раз больше – тогда абсолютные различия между этими двумя результатами также будут на 1000 раз больше, но это не означает, что два точечных продукта были менее точными.

np.allclose вернет True только в том случае, если для каждой соответствующей пары элементов в двух тестовых массивах выполнено следующее условие: a и b :

 abs(a - b) <= (atol + rtol * abs(b)) 

По умолчанию rtol=1e-5 и atol=1e-8 . Эти допуски являются хорошим «правилом», но достаточно ли они в вашем случае будут зависеть от вашего конкретного приложения. Например, если вы имеете дело со значениями <1e-8, то абсолютная разница 1e-8 будет полной катастрофой!

Если вы попробуете называть np.allclose на двух ваших результатах с допуском по умолчанию, вы обнаружите, что np.allclose возвращает True . Я предполагаю, что эти различия, вероятно, достаточно малы, что их не стоит беспокоиться. Это зависит от того, что вы делаете с результатами.

  • Как ограничить ширину окна корреляции в Numpy?
  • Обобщить операцию разрезания в массиве NumPy
  • Условно заполняемые элементы в объекте pandas groupby - векторное решение с использованием numpy? Является ли групповой подход неправильным?
  • Почему функция numpy random.choice () прекращена?
  • многоуровневый массив объектов
  • Именованный массив dtype: Разница между и ?
  • Numpy: Как случайное разбиение / выбор матрицы на n-различные матрицы
  • numpy: какова логика функций argmin () и argmax ()?
  • Выберите строки из Numpy Rec Array
  • Как импортировать данные из разных типов из массива в массив Python Numpy?
  • Как преобразовать матрицу столбца или строки в диагональную матрицу в Python?
  • Python - лучший язык программирования в мире.