Pytorch:二、线性模型;三、梯度下降;四、反向传播


其实就是个函数y=ω * x + b
通过不断调参来确定最优ω/b值从而确定最小损失:

import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
def forward(x):
    return x * w

def loss(x, y):
    y_pred = forward(x)
    return (y_pred - y) * (y_pred - y)

w_list = []
mse_list = []
for w in np.arange(0.0, 4.1, 0.1):
    print('w=', w)
    l_sum = 0
    for x_val, y_val in zip(x_data, y_data):
        y_pred_val = forward(x_val)
        loss_val = loss(x_val, y_val)
        l_sum += loss_val
        print('\t', x_val, y_val, y_pred_val, loss_val)
    print('MSE=', l_sum / 3)
    w_list.append(w)
    mse_list.append(l_sum / 3)
部分结果

画曲线图:

plt.plot(w_list, mse_list)
plt.ylabel('Loss')
plt.xlabel('w')
plt.show()

三、梯度下降法


就是通过求导后找优化的点来找到最优点:

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 cost(xs, ys):
    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)
    return grad / len(xs)

print('Predict (before training)', 4, forward(4))
for epoch in range(100):
    cost_val = cost(x_data, y_data)
    grad_val = gradient(x_data, y_data)
    w -= 0.01 * grad_val
    print('Epoch:', epoch, 'w=', w, 'loss=', cost_val)
print('Predict (after training)', 4, forward(4))


在使用梯度下降时,有时候会因为遇到鞍点而无法找到全局最优点;

随机梯度下降

随机梯度下降是指从已有的N个cost中随机选取一个,即拿单个样本的损失来进行计算。这样就会有随机噪声,从而解决了鞍点问题;

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

#自己把目标函数求导之后把表达式写成函数
def gradient(x, y):
    return 2 * x * (x * w - y)

print('Predict (before training)', 4, forward(4))

for epoch in range(100):
    for x, y in zip(x_data, y_data):
        grad = gradient(x, y)
        #学习率是个超参数,可以自定义
        #在这里是拿一个样本进行更新
        w = w - 0.01 * grad
        print("\tgrad: ", x, y, grad)
        l = loss(x, y)
    
    print("progress:", epoch, "w=", w, "loss=", l)
    
print('Predict (after training)', 4, forward(4))

这样能避免鞍点:第一个遇到鞍点的值可以通过第二个点跨过

意思就是:梯度下降一条线(平均)都下降,随机梯度是随机一个点下降

两种方法比较

可以看到,连续的性能低,但是时间快;单个的性能好,但是时间慢

因此,选择了折中的方法:batch方法,即每次多选几个单个样本来进行计算;


四、 后向传播

可以看出,对于线性神经网络的方程,可以通过展开将其变为一层。但是这并不符合深度学习的情况,所以就加了一个非线性的变化函数——激活函数;

正向传播
逆向传播
求梯度过程

就是先正向传播求解出最终的loss值/表达式,然后再反向传播来求导从而得出梯度(导函数值);loss的值可以保存下来用作可视化

练习题
我的解题

在pytorch中进行正/反向计算

张量还保存了导数,因此用张量来进行计算比较好用;

import torch 

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

#创建一个tensor变量,注意下面的格式
w = torch.Tensor([1.0])
#通过requires_grad来表明其需要计算梯度
w.requires_grad = True

#下面这两个函数实际上在构建计算图
def forward(x):
    return x * w

def loss(x, y):
    y_pred = forward(x)
    return (y_pred - y) ** 2

print("predict (before training", 4, forward(4).item())

for epoch in range(100):
    for x, y in zip(x_data, y_data):
        #构建计算图
        l = loss(x,y)
        #只要backward后计算图就消失了
        l.backward()
        print('\tgrad:',x,y,w.grad.item())
        #grad也是个张量,所以要取其data来进行计算
        #在更新时不能使用d张量
        w.data = w.data - 0.01 * w.grad.data
        #通过backward计算的grad会被累计,所以在更新w之后要对其进行归零
        w.grad.data.zero_()
        
    print("progress:", epoch, l.item())
    
print("predict (after training)", 4, forward(4).item())

可以看到,损失值在一直减少,这也说明在越来越好

总之,反向传播的过程实际上就是:1.先算下loss;2.然后反向传播去算梯度;3.再用梯度下降方法来进行更新权重;

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容