Вы должны использовать .zero_grad()
с оптимизатором, поэтому optimizer.zero_grad()
, а не потери или модель, как это предлагается в комментариях (хотя модель в порядке, но она не ясна или не читаема IMO).
За исключением этоговаши параметры обновляются нормально, поэтому ошибка не на стороне PyTorch.
На основе предоставленных вами значений градиента:
gradients = [tensor([[-0.2800, -0.4200], [-0.3000, -0.4500]]),
tensor([[-0.8500, -0.4800]])]
Давайте умножим их все на вашу скорость обучения (0,05):
gradients_times_lr = [tensor([[-0.014, -0.021], [-0.015, -0.0225]]),
tensor([[-0.0425, -0.024]])]
Наконец, давайте применим обычный SGD (тета - = градиент * lr), чтобы получить точно такие же результаты, как в PyTorch:
parameters = [tensor([[0.1240, 0.2310], [0.1350, 0.1025]]),
tensor([[0.1825, 0.1740]])]
То, что вы сделали, взялоградиенты, рассчитанные PyTorch и умноженные на результат предыдущего узла и , это не так, как он работает! .
Что вы сделали:
w5= 0.14 -(0.191-1)*1*0.85*0.05= 0.14 + 0.034= 0.174
Что должно быть сделано (с использованием результатов PyTorch):
w5 = 0.14 - (-0.85*0.05) = 0.1825
Нет умножения предыдущего узла, это делается за сценой (это то, что делает .backprop()
- вычисляет правильные градиенты для всех узлов), нет необходимостиумножьте их на предыдущие.
Если вы хотите рассчитать их вручную, вы должны начать с убытка (с дельтой, равной единице) и обратно до конца ( здесь не используют скорость обучения,это другая история! ).
После того, как все они рассчитаны, вы можете умножить каждый вес на скорость обучения оптимизаторов (или любую другую формулу по этому вопросу, например, Momentum), и после этого вы получитеправильное обновление.
Как рассчитать backprop
Скорость обучения не является частью обратного распространения, оставьте это в покое, пока вы не вычислите все градиенты (это смешивает отдельные алгоритмы вместе,процедуры оптимизации и обратного распространения).
1.Производная от общей ошибки по выходным данным
Ну, я не знаю, почему вы используете Средняя абсолютная ошибка (в то время как в учебнике это Средняя квадратичная ошибка ),и поэтому оба эти результата различаются.Но пойдем с твоим выбором.
Производная от |y_true - y_pred |wrt для y_pred равно 1 , поэтому ЭТО не то же самое, что потеря.Измените на MSE , чтобы получить равные результаты (здесь, производная будет (1/2 * y_pred - y_true), но мы обычно умножаем MSE на два, чтобы удалить первое умножение).
В случае MSE вы умножаете значение потери, но оно полностью зависит от функции потерь (было немного прискорбно, что использованное вами руководство не указало на это).
2.Производная полной ошибки по w5
Скорее всего, вы могли бы пойти отсюда, но ... Производная полной ошибки по w5 - это результат h1 (в данном случае 0,85).Мы умножаем его на производную от общей ошибки по выводу (это 1!) И получаем 0,85, как это сделано в PyTorch.Та же идея относится и к w6.
Я серьезно советую вам не путать скорость обучения с backprop, вы усложняете свою жизнь (а с IMO backprop, это нелегко, довольно нелогично), иэто две разные вещи (не могу не подчеркнуть, что достаточно одной).
Этот источник хорош, более пошаговый, с немного более сложной сетевой идеей (включая активации), так что вы можете лучше понять, если вы пройдете через все это.
Кроме того, если вы действительно заинтересованы (и вам, кажется, интересны), чтобы узнать больше подробностей об этом, рассчитайте поправки на вес для других оптимизаторов (скажем, нестеров), чтобы вы знали, почему мы должны сохранятьэти идеи разделились.