Pytorch深度学习实践笔记 --- 反向传播Back Propagation
Gradient梯度就是对cost(w)求倒数 g = ∂cost(w)/∂w ,代表当前函数cost(w)的趋势Update w = w - a * g(a --- 学习率)= w - a * ∂cost(w)/∂w 梯度开始下降,迭代过程就是根据梯度实现若g<0,此时cost(w)单调减,则w👉;若g>0,cost(w)单调增,则w👈(都是往下降方向走)由于本质是贪心,所以不一定得到全局最
前情提要
梯度下降算法 Gradient Descent
Gradient梯度就是对cost(w)求倒数 g = ∂cost(w)/∂w ,代表当前函数cost(w)的趋势
Update w = w - a * g(a --- 学习率)= w - a * ∂cost(w)/∂w 梯度开始下降,迭代过程就是根据梯度实现
若g<0,此时cost(w)单调减,则w👉;若g>0,cost(w)单调增,则w👈(都是往下降方向走)
由于本质是贪心,所以不一定得到全局最优而是局部最优两者。
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = 1
def forward(x):
return w * x
def cost(xs, ys): # 传进来的是x_data和y_data的列表
cost = 0
for x, y in zip(xs, ys): # 遍历两个列表
y_pred = forward(x)
cost += (y_pred - y) ** 2
return cost / len(xs)
def gradient(xs, ys):
grad = 0
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y) # 对cost求导数 化简后 得
return grad / len(xs)
a = 0.01 # 学习率
for epoch in range(1, 10, 1):
cost_val = cost(x_data, y_data)
grad_val = gradient(x_data, y_data)
w = w - a * grad_val
print(f"Epoch = {epoch}, w = {w}, loss = {cost_val}")
print("-------------------------------------------")
随机梯度下降Stochastic Gradient Descent --- SGD
该算法源于梯度下降算法中的求和导致难以并行运算,只求损失loss可以提高效率。
∂loss/∂w = d(y_pred - y)^2 / dw = 2 * x * (x * w - y)
w = w - a * ∂loss/∂w
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = 1.0
def forward(x):
return x * w
def loss(x, y):
y_pred = forward(x)
return (y_pred - y) ** 2 # y_pred与实际y比较 来算loss
def gradient(x, y):
return 2.0 * x * (x * w - y) # 对loss求导数化简后 得
for epoch in range(1, 10, 1):
for x, y in zip(x_data, y_data):
grad_val = gradient(x, y)
w = w - 0.01 * grad_val # update
print(f"Epoch = {epoch}, w = {w}, loss = {loss(x, y)}")
反向传播 Back Propagation
前提
多层神经网络的局部梯度传递,目的是为了求loss关于w的导数来算梯度即 ∂loss/∂w
数学原理
链式求导
对于两层神经网络:
y_pred = W2(W1*X + b1) + b2
第一层 第二层
= W2*W1*X + (W2*b1 + b2)
= W*X + b
注:根据以上推导,无论几层都能线性表示,所以就没有意义了,于是引入nonlinear function。
计算步骤:
1、create computational graph(forward)
x,w -> f -> f(x,w) -> z -> ... -> loss
2、local gradient 局部梯度 --- 正向目标算出损失
loss -> z ( ∂L/∂z ) -> f( ∂z/∂x , ∂z/∂w ) -> x( ∂L/∂x = ∂L/∂z * ∂z/∂x ) ,w( ∂L/∂w = ... )
3、backward --- 反向目标求梯度
通过反向传播,进行链式求导,更新梯度
以上步骤的进行目的是求 ∂loss/∂w
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w1 = torch.Tensor([1.0]) # 创建一个张量w,Tensor中包含data和grad,data和grad也是Tensor
w1.requires_grad = True # 需要计算梯度
w2 = torch.Tensor([1.0])
w2.requires_grad = True
b = torch.Tensor([1.0])
b.requires_grad = True
def forward(x):
return w1 * x ** 2 + w2 * x + b
def loss(x, y): # 构建计算图, tensor 做计算就会构建计算图
y_pred = forward(x)
return (y_pred - y) ** 2
def gradient(x, y): # ∂loss/∂w
return 2.0 * x * (x * w - y)
print('Predict (before training)',4,forward(4))
a = 0.01 # 设置学习率
for epoch in range(1, 100, 1):
for x, y in zip(x_data, y_data):
l = loss(x, y)
l.backward() # 不断计算梯度
print('\tgrad:', x, y, w1.grad.item(), w2.grad.item(), b.grad.item())#梯度值的标量数值,.item() 方法的作用是将只包含一个元素的 PyTorch tensor 转换为普通的 Python 数值类型(如 float)。这样做是为了打印时更清晰,显示的是具体的数字而不是 tensor 对象。
# 注意这里的grad是一个tensor,所以要取他的data
w1.data = w1.data - a * w1.grad.data
w2.data = w2.data - a * w2.grad.data
b.data = b.data - a * b.grad.data
# 释放之前计算的梯度
w1.grad.data.zero_()
w2.grad.data.zero_()
b.grad.data.zero_()
print('Epoch:', epoch, l.item())
print("predict (after training)", 4, forward(4).item())
更多推荐

所有评论(0)