Я пытаюсь изучать входы и выходы обратного распространения.Я понял до того момента, когда я продвигаю нейронную сеть.Однако я не понимаю, как именно код передает градиенты обратно на входы.Например, я не понимаю, как self.u0.grad для sg0 (объект класса SigmoidGate) передается обратно в self.utop.grad addg1 (объект класса AddGate).Это моя проблема.
Моя цель - понять, как градиенты передаются с выхода (Примечание: градиент всегда начинается с +1 в конце, чтобы начать цепочку. Это (по умолчанию) тяга в цепи кего значение увеличилось.) вплоть до входов.
Я попытался отладить скрипт Python, как показано ниже.Мои выводы: Примечание: Самость содержит u0, u1 и utop.Все 3 переменные содержат значение и градиент.1) Переменные self одинаковы, когда я взглянул на все остальные переменные класса.Например, в настоящее время я отлаживаю в mulg1.backward ().Когда я сравниваю собственные переменные класса MultGate (): и класса AddGate ():.Они одинаковы, и их адреса памяти тоже равны.
Адрес памяти класса MultGate (): равен <<strong> main .MultGate объект в 0x0000019681754400>.Адрес памяти класса AddGate (): <<strong> main .MultGate объект в 0x0000019681754400>.
Почему это происходит?Как переменные могут быть разделены между классами?
2) Как значение self.u0.grad sig0 передается в self.utop.grad addg1.Обе переменные указывают на одну и ту же ячейку памяти?
Пожалуйста, дайте мне понимание этой проблемы.
# Referenced from:
# Tutorial: http://karpathy.github.io/neuralnets/
# Code : https://gist.github.com/bmobear/29e29da38a2593c9bcb0d0a434e57022
import math
class Unit:
def __init__(self, value, grad):
self.value = value
self.grad = grad
class MultGate:
def forward(self, u0, u1):
self.u0 = u0 # this is a Unit by itself
self.u1 = u1 # this is a Unit by itself
self.utop = Unit(u0.value*u1.value, 0.0)
return self.utop # return a Unit object
def backward(self):
self.u0.grad += self.u1.value*self.utop.grad
self.u1.grad += self.u0.value*self.utop.grad
class AddGate:
def forward(self, u0, u1):
self.u0 = u0
self.u1 = u1
self.utop = Unit(u0.value+u1.value, 0.0)
return self.utop
def backward(self):
self.u0.grad += 1*self.utop.grad
self.u1.grad += 1*self.utop.grad
class SigmoidGate:
def sigmoid(self, x):
return 1.0/(1+math.exp(-x))
def forward(self, u0):
self.u0 = u0
# print("self.u0 in sigmoid gate is " + str(self.u0.value))
# print("self.sigmoid(u0.value) is " + str(self.sigmoid(u0.value)))
self.utop = Unit(self.sigmoid(u0.value), 0.0)
return self.utop
def backward(self):
shankar = self.sigmoid(self.u0.value)
# print(self.u0.value) ==> 2
# print("s in sigmoid backward function is " + str(s))
# # s = 0.8807970779778823
self.u0.grad += (shankar*(1 - shankar))*self.utop.grad
# print("self.u0.grad is "+str(self.u0.grad))
# # self.u0.grad is 0.10499358540350662
# example time
a = Unit(1.0, 0.0)
b = Unit(2.0, 0.0)
c = Unit(-3.0, 0.0)
x = Unit(-1.0, 0.0)
y = Unit(3.0, 0.0)
mulg0 = MultGate()
mulg1 = MultGate()
addg0 = AddGate()
addg1 = AddGate()
sg0 = SigmoidGate()
def forwardNeuron():
ax = mulg0.forward(a, x) # ax is a Unit object, a * x = -1
by = mulg1.forward(b, y) # by is a Unit object, b * y = 6
ax_p_by = addg0.forward(ax, by) # ax_p_by is a Unit object; a*x + b*y = 5
ax_p_by_p_c = addg1.forward(ax_p_by, c)
return sg0.forward(ax_p_by_p_c) # returns a Unit object
s = forwardNeuron() # s is sg0.forward(ax_p_by_p_c) where sg0 is Sigmoid Gate
# before backpropagating
# print("forward pass 0 is : "+str(s.value) + " gradient is " + str(s.grad))
# backward pass
# call all gates in reverse order
# after backpropagating
s.grad = 1.0 # set the gradient from 0 to 1.0
print("forward pass 0 is : "+str(s.value) + " gradient is " + str(s.grad))
sg0.backward() # writes gradient into ax_p_by_p_c
addg1.backward() # writes gradients into ax_p_by and c
addg0.backward() # writes gradients into ax and by
mulg1.backward() # writes gradients into b and y
mulg0.backward() # writes gradients into a and x
print("backward pass ", [a.grad, b.grad, c.grad, x.grad, y.grad])
step_size = 0.01
a.value += step_size*a.grad # a.grad is -0.105
b.value += step_size*b.grad # b.grad is 0.315
c.value += step_size*c.grad # c.grad is 0.105
x.value += step_size*x.grad # x.grad is 0.105
y.value += step_size*y.grad # y.grad is 0.210
s = forwardNeuron()
print("forward pass 1 is : "+str(s.value))
Ожидаемый и правильный вывод