IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> Pytorch拟合直线方法 -> 正文阅读

[人工智能]Pytorch拟合直线方法

学习记录

发现自己对pytorch的网络搭建还是停留在调包情况,准备学习深入一些,先从简单的拟合直线开始。

使用torch拟合直线

这里参考了知乎一个大佬的方法,由于在服务器上写的,好像不能画图。

import numpy as np
import torch
import torch.nn as nn

def linear_model(x):
    return torch.mul(x, w) + b

def get_loss(my_pred, my_y_train):
    return torch.mean((my_pred - my_y_train) ** 2)
    
torch.manual_seed(2)#设置随机数以便操作
x_train = np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168], [9.779], [6.182], [7.59], [2.167], [7.042], [10.791], [5.313], [7.997], [3.1]], dtype=np.float32)
y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573], [3.366], [2.596], [2.53], [1.221], [2.827], [3.465], [1.65], [2.904], [1.3]], dtype=np.float32)
input = torch.from_numpy(x_train)#转换成tensor类型
gt = torch.from_numpy(y_train)
w = torch.randn(1, requires_grad=True)#初始化y = w * x + b的参数
b = torch.randn(1, requires_grad=True)
epoch = 50#设置迭代次数
pred_loss, w_pred, b_pred  = 1, 0, 0#保存最好的一次loss
lr = 1e-3#学习率
for i in range(epoch):
    pred_v = linear_model(input)
    loss = get_loss(pred_v, gt)
    if w.grad:    
        w.grad.zero_()#每次w和b的梯度都要置零
    if b.grad:    
        b.grad.zero_()
    loss.backward()   
    #with torch.no_grad():
        #w.data = w.data - lr * w.grad.data
        #b.data = b.data - lr * b.grad.data
    w.data = w.data - lr * w.grad.data
    b.data = b.data - lr * b.grad.data
    if pred_loss > loss:
        w_pred = w
        b_pred = b
    #print('loss = {}, epoch = {}'.format(loss, i))
print(w_pred, b_pred)

最后的训练结果是

tensor([0.3976], requires_grad=True) tensor([-0.2102], requires_grad=True)

一些分析

loss.backward()的用法

查询相关知识后发现是获取参数本次epoch的梯度,对于直线,获取的是w和b的梯度。在梯度下降算法,梯度定义为函数上升最快的方向,自变量减去该方向可以获取函数下降的最快速度。
损失函数是
J ( w , b ) = ∑ i = 0 15 ( V p r e d _ i ? V g t _ i ) 2 15 J(w, b)=\frac{\sum_{i=0}^{15} (V_{pred\_i} -V_{gt\_i})^2}{15} J(w,b)=15i=015?(Vpred_i??Vgt_i?)2?
其中
V p r e d _ i = w × x i + b V_{pred\_i}=w \times x_i+b Vpred_i?=w×xi?+b
损失函数分别对w和b求偏导数:
? J ( w , b ) ? w = ∑ i = 0 15 2 × ( V p r e d _ i ? V g t _ i ) × x i 15 \frac{\partial J(w, b)}{\partial w}=\frac{\sum_{i=0}^{15} 2\times(V_{pred\_i} -V_{gt\_i})\times x_i}{15} ?w?J(w,b)?=15i=015?2×(Vpred_i??Vgt_i?)×xi??
? J ( w , b ) ? b = ∑ i = 0 15 2 × ( V p r e d _ i ? V g t _ i ) × 1 15 \frac{\partial J(w, b)}{\partial b}=\frac{\sum_{i=0}^{15} 2\times(V_{pred\_i} -V_{gt\_i})\times 1}{15} ?b?J(w,b)?=15i=015?2×(Vpred_i??Vgt_i?)×1?
算出来的 ? J ( w , b ) ? w \frac{\partial J(w, b)}{\partial w} ?w?J(w,b)? ? J ( w , b ) ? b \frac{\partial J(w, b)}{\partial b} ?b?J(w,b)?就是w.grad.datab.grad.data

lr被称为步长或学习率。

为什么每个epoch都要有梯度置零

在每个epoch中都有以下步骤

if w.grad:    
    w.grad.zero_()
    
if b.grad:    
    b.grad.zero_()

因为每次梯度都是要从本次的loss处重新计算梯度。
如果参数的梯度不置零,epoch为3,如图

print('w={}, b={}'.format(w,b))
print('===========')
for i in range(epoch):
    pred_v = linear_model(input)
    loss, delta = get_loss(pred_v, gt)
    grad = torch.mean(2 * torch.mul(delta, input)) 
    # if w.grad:    
    #     w.grad.zero_()#每次w和b的梯度都要置零
    # if b.grad:    
    #     b.grad.zero_()
    loss.backward()   
    w.data = w.data - lr * w.grad.data
    b.data = b.data - lr * b.grad.data
    if pred_loss > loss:
        w_pred = w
        b_pred = b
    print(w.grad, grad, w, b)
w=tensor([0.3923], requires_grad=True), b=tensor([-0.2236], requires_grad=True)
===========
tensor([-0.5801]) tensor(-0.5801, grad_fn=<MeanBackward0>) tensor([0.3929], requires_grad=True) tensor([-0.2232], requires_grad=True)
tensor([-1.1069]) tensor(-0.5269, grad_fn=<MeanBackward0>) tensor([0.3940], requires_grad=True) tensor([-0.2226], requires_grad=True)
tensor([-1.5320]) tensor(-0.4251, grad_fn=<MeanBackward0>) tensor([0.3955], requires_grad=True) tensor([-0.2216], requires_grad=True)

可以看出上一次计算出的梯度值在本次梯度的计算中是累加关系。

#-0.5801 + -0.5269 = -1.1069
#-1.1069 + -0.4251 = -1.5320

参数更新分析

在梯度反向传播时,反向传播这个过程不加入下一次的反向传播中。需要使用w.datab.data去更新两个参数,只改变值,不改变参数的传递。如图:

w.data = w.data - lr * w.grad.data
b.data = b.data - lr * b.grad.data
print(w.grad_fn, b.grad_fn)
exit()
None None

两个都是None?是因为系统将w和b的grad值初始化为None,因此需要加if w.grad:if b.grad:判断是否是第一个epoch,从第二次二者就有梯度值了。

如果使用wb更新的话,wb的更新计算也会加入到计算图中:

w = w - lr * w.grad
b = b - lr * b.grad
print(w.grad_fn, b.grad_fn)
exit()
<SubBackward0 object at 0x7f85cbc768d0> <SubBackward0 object at 0x7f858d088050>

w和b的的grad_fn就不是None。除此之外,w和b的grad也丢了,在第二个epoch时,w.grad会变成NoneType。查阅相关资料,发现参数不再是叶子节点了。

print(w.is_leaf, b.is_leaf)
    w = w - lr * w.grad
    b = b - lr * b.grad
print(w.is_leaf, b.is_leaf)
True True
False False

查询相关的CSDN博客:
如果该张量的属性requires_grad=True,而且是用于直接创建的,也即它的属性grad_fn=None,那么它就是叶子节点。
如果该张量的属性requires_grad=True,但是它不是用户直接创建的,而是由其他张量经过某些运算操作产生的,那么它就不是叶子张量,而是中间节点张量,并且它的属性grad_fn不是None,就出现上述的情况了,表示该张量是通过运算操作获取的。
pytorch的自动梯度机制不会为中间结果保存梯度,即只会为叶子节点计算的梯度保存起来,保存到该叶子节点张量的属性grad中,不会在中间节点张量的属性grad中保存这个张量的梯度。
出于对效率的考虑,中间节点张量的属性gradNone.如果用户需要为中间节点保存梯度的话,可以让这个中间节点调用方法retain_grad(),这样梯度就会保存在这个中间节点的grad属性中。
这跟系统提示的warning一样,就是说w和b变成了中间向量。

UserWarning: The .grad attribute of a Tensor that is not a leaf
Tensor is being accessed. Its .grad attribute won't be populated
during autograd.backward(). If you indeed want the gradient for a
non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If
you access the non-leaf Tensor by mistake, make sure you access
the leaf Tensor instead. See
github.com/pytorch/pytorch/pull/30531 for more informations.

需不需要使用with torch.no_grad()

使用了with torch.no_grad()之后,梯度就会消失,不需要使用。但经过验证,在参数更新时加不加没关系,考虑原因可能是只更新的data值,和梯度没有关系。

总结

分析了简单的拟合直线中的原理及实现,下一步准备研究下多层网络的反馈和卷积网络的参数传递。

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-12-06 15:15:13  更:2021-12-06 15:19:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 2:39:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码