Nano Hash - криптовалюты, майнинг, программирование

Градиент PyTorch отличается от рассчитанного вручную градиента

Я пытаюсь вычислить градиент 1/x без использования автограда Pytorch. Я использую формулу grad(1/x, x) = -1/x**2. Когда я сравниваю свой результат с этой формулой с градиентом, заданным автоградом Pytorch, они разные.

Вот мой код:

a = torch.tensor(np.random.randn(), dtype=dtype, requires_grad=True)
loss = 1/a
loss.backward()
print(a.grad - (-1/(a**2)))

Результат:

tensor(5.9605e-08, grad_fn=<ThAddBackward>)

Может ли кто-нибудь объяснить мне, в чем проблема?


Ответы:


1

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

Давайте посмотрим на ваш пример с добавленным дополнительным print-statement:

a = torch.tensor(np.random.randn(), requires_grad=True)
loss = 1/a
loss.backward()
print(a.grad, (-1/(a**2)))
print(a.grad - (-1/(a**2)))

Поскольку вы используете случайный ввод, вывод, конечно, тоже случайный.
(так что вы не получите те же самые цифры, просто повторите этот эксперимент, и у вас будут похожие примеры).

Иногда в результате вы получите ноль. Но это было не так в вашем первоначальном примере:

tensor(-0.9074) tensor(-0.9074, grad_fn=<MulBackward>)
tensor(5.9605e-08, grad_fn=<ThSubBackward>)

Вы видите, хотя оба отображаются как одно и то же число, но они отличаются одним из последних знаков после запятой. Вот почему вы получаете эту очень маленькую разницу при вычитании обоих.

Эта проблема, как и общая проблема компьютеров, просто некоторые дроби имеют большое или бесконечное количество знаков после запятой, а памяти вашего компьютера нет. Так что в какой-то момент они обрываются.

Итак, то, что вы испытываете здесь, на самом деле является отсутствием точности. А точность зависит от используемого типа числовых данных (например, torch.float32 или torch.float64).

Дополнительную информацию также можно найти здесь:
https://en.wikipedia.org/wiki/Double-precision_floating-point_format


Но это не относится к PyTorch или около того, вот пример Python:

print(29/100*100)

Результат:

28.999999999999996

Изменить:

Как отметил @HOANG GIANG, изменение уравнения на -(1/a)*(1/a) работает хорошо, и результат равен нулю. Вероятно, это так, потому что вычисление, выполненное для вычисления градиента, очень похоже (или то же самое) на -(1/a)*(1/a) в этом случае. Следовательно, он использует те же ошибки округления, поэтому разница равна нулю.

Итак, вот еще один более подходящий пример, чем приведенный выше. Несмотря на то, что -(1/x)*(1/x) математически эквивалентен -1/x^2, он не всегда совпадает при вычислении на компьютере. , в зависимости от значения x:

import numpy as np
print('e1 == e2','x value', '\t'*2, 'round-off error', sep='\t')
print('='*70)
for i in range(10):
    x = np.random.randn()
    e1 = -(1/x)*(1/x)
    e2 = (-1/(x**2))
    print(e1 == e2, x, e1-e2, sep='\t\t')

Выход:

e1 == e2    x value                 round-off error
======================================================================
True        0.2934154339948173      0.0
True        -1.2881863891014191     0.0
True        1.0463038021843876      0.0
True        -0.3388766143622498     0.0
True        -0.6915415747192347     0.0
False       1.3299049850551317      1.1102230246251565e-16
True        -1.2392046539563553     0.0
False       -0.42534236747121645    8.881784197001252e-16
True        1.407198823994324       0.0
False       -0.21798652132356966    3.552713678800501e-15

Несмотря на то, что ошибка округления кажется немного меньше (я пробовал разные случайные значения, и редко ошибка округления встречалась более чем в двух случаях из десяти), но все равно уже есть небольшие отличия при простом расчете 1/x:

import numpy as np
print('e1 == e2','x value', '\t'*2, 'round-off error', sep='\t')
print('='*70)
for i in range(10):
    x = np.random.randn()
    # calculate 1/x
    result = 1/x
    # apply inverse function
    reconstructed_x = 1/result
    # mathematically this should be the same as x
    print(x == reconstructed_x, x, x-reconstructed_x, sep='\t\t')

Выход:

e1 == e2    x value             round-off error
======================================================================
False       0.9382823115235075      1.1102230246251565e-16
True        -0.5081217386356917     0.0
True        -0.04229436058156134    0.0
True        1.1121100294357302      0.0
False       0.4974618312372863      -5.551115123125783e-17
True        -0.20409933212316553    0.0
True        -0.6501652554924282     0.0
True        -3.048057937738731      0.0
True        1.6236075700470816      0.0
True        0.4936926651641918      0.0
13.11.2018
  • Я обнаружил, что когда я меняю порядок вычислений (т.е. моя формула становится -(1/a)*(1/a)), разница становится равной нулю (т.е. == 0) 13.11.2018
  • @HOANGGIANG Да, это хороший момент! Несмотря на то, что -(1/x)*(1/x) математически эквивалентно -1/x^2, это не всегда так при расчете на компьютере. Я сделал правку в конце своего ответа. 13.11.2018
  • @HOANGGIANG Было бы здорово, если бы вы дали мне отзыв по вопросу Может ли кто-нибудь объяснить мне, в чем проблема?. Если вы нашли объяснение полезным, я был бы рад, если вы примете ответ, чтобы оценить приложенные усилия, спасибо! 14.11.2018
  • Извините :) Я только что проголосовал за ваш ответ и забыл принять его как правильный ответ 14.11.2018
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..