1. 自动微分
step2 创建变量的函数
# 箱子类,存放一个变量数据
class Variable:
def __init__(self, data):
self.data = data
# 函数类的基类
class Function:
# __call__方法是一个特殊的Python方法。
# 定义了这个方法后,当f = Function()时,就可以通过编写f(...)来调用__call__方法了
def __call__(self, input):
x = input.data
y = self.forward(x) # 具体的计算在forward方法中进行
output = Variable(y)
return output
def forward(self, x):
raise NotImplementedError() # 告诉使用了Function类forward方法的人这个方法应该通过继承来实现
# 函数类的具体实现类
class Square(Function):
def forward(self, x):
return x ** 2
if __name__ == "__main__":
x = Variable(10)
f = Square()
y = f(x)
print(type(y))
print(y.data)
step4 数值微分
利用中心差分近似来计算导数:
\[f'(x) \approx \frac{f(x+ \epsilon)-f(x- \epsilon)}{2 \epsilon} \]设计numerical_diff函数:
class Variable:
def __init__(self, data):
self.data = data
class Function:
def __call__(self, input):
x = input.data
y = self.forward(x) # 具体的计算在forward方法中进行
output = Variable(y)
return output
def forward(self, x):
raise NotImplementedError() # 告诉使用了Function类forward方法的人这个方法应该通过继承来实现
class Square(Function):
def forward(self, x):
return x ** 2
def numerical_diff(f, x, eps=1e-4):
x0 = Variable(x.data - eps)
x1 = Variable(x.data + eps)
y0 = f(x0)
y1 = f(x1)
return (y1.data - y0.data) / (2 * eps)
if __name__ == "__main__":
f = Square()
x = Variable(2.0)
dy = numerical_diff(f, x)
print(dy)
复合函数的导数
def f(x):
A = Square()
B = Exp()
C = Square()
return C(B(A(x)))
if __name__ == "__main__":
x = Variable(np.array(0.5))
dy = numerical_diff(f, x)
print(dy)
step6 手动进行反向传播
用反向传播计算导数
import numpy as np
class Variable:
def __init__(self, data):
self.data = data
self.grad = None # gradient梯度的缩写
class Function:
def __call__(self, input):
x = input.data
y = self.forward(x) # 具体的计算在forward方法中进行
output = Variable(y)
self.input = input # 保存输入的变量
# 将input设置为实例变量。
# 这样一来,当调用backward方法时,向函数输入的Variable实例就可以作为self.input使用
return output
def forward(self, x):
raise NotImplementedError() # 告诉使用了Function类forward方法的人这个方法应该通过继承来实现
def backward(self, gy):
raise NotImplementedError()
class Square(Function):
def forward(self, x):
y = x ** 2
return y
def backward(self, gy):
x = self.input.data
gx = 2 * x * gy
return gx
class Exp(Function):
def forward(self, x):
return np.exp(x)
def backward(self, gy):
x = self.input.data
gx = np.exp(x) * gy
return gx
if __name__ == "__main__":
A = Square()
B = Exp()
C = Square()
x = Variable(np.array(0.5))
a = A(x)
b = B(a)
y = C(b)
y.grad = np.array(1.0) # dy/dy = 1
b.grad = C.backward(y.grad)
a.grad = B.backward(b.grad)
x.grad = A.backward(a.grad)
print(x.grad)
step7 反向传播的自动化
import numpy as np
class Variable:
def __init__(self, data):
self.data = data
self.grad = None # gradient梯度的缩写
self.creator = None
def set_creator(self, func):
self.creator = func
def backward(self):
f = self.creator # 1. 获取函数
if f is not None:
x = f.input # 2. 获取函数的输入
x.grad = f.backward(self.grad) # 3. 调用函数的backward方法
x.backward() # 调用自己前面那个变量的backward方法(递归)
class Function:
def __call__(self, input):
x = input.data
y = self.forward(x) # 具体的计算在forward方法中进行
output = Variable(y)
output.set_creator(self) # 让输出变量保存创造者信息
self.input = input # 保存输入的变量
# 将input设置为实例变量。
# 这样一来,当调用backward方法时,向函数输入的Variable实例就可以作为self.input使用
self.output = output # 也保存输出变量
return output
def forward(self, x):
raise NotImplementedError() # 告诉使用了Function类forward方法的人这个方法应该通过继承来实现
def backward(self, gy):
raise NotImplementedError()
class Square(Function):
def forward(self, x):
y = x ** 2
return y
def backward(self, gy):
x = self.input.data
gx = 2 * x * gy
return gx
class Exp(Function):
def forward(self, x):
return np.exp(x)
def backward(self, gy):
x = self.input.data
gx = np.exp(x) * gy
return gx
if __name__ == "__main__":
A = Square()
B = Exp()
C = Square()
x = Variable(np.array(0.5))
a = A(x)
b = B(a)
y = C(b)
y.grad = np.array(1.0) # dy/dy = 1
y.backward()
print(x.grad)
标签:__,入门,读书笔记,self,forward,input,data,自制,def
From: https://www.cnblogs.com/code-pigeon/p/17870682.html