动手学习pyTorch之【线性模型】—— 具体代码实现
Linear-regression
具体原理见我同专栏下的另一篇文章
一些pytorch的函数介绍
基础
y = torch.tensor([0, 2]) y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]]) y_hat[[0, 1], y] tensor([0.1000, 0.5000])
相当于获取 (0,0) 和 (1,2)
正态分布
torch.normal(mean, std, *, generator=None, out=None) # 从一个标准正态分布N~(0,1),提取一个2x2的矩阵 torch.normal(mean=0.,std=1.,size=(2,2)) # 让每一个值服从不同的正态分布 torch.normal(mean=torch.arange(1., 11.), std=torch.arange(1, 0, -0.1)) tensor([ 1.0425, 3.5672, 2.7969, 4.2925, 4.7229, 6.2134,8.0505, 8.1408, 9.0563, 10.0566])
将list中的内容打乱(修改原值)
random.shuffle(indices)
torch的矩阵计算
# 两个张量对应元素相乘 y = torch.mul(X,w)# 两个张量矩阵相乘,可以用利用广播机制进行不同维度的相乘操作 y = torch.matmul(X,w) + b
yield:python生成器,解决使用序列存储大量数据时内存消耗大的问题,用于生成小批量随机样本时
https://blog.csdn.net/mieleizhi0522/article/details/82142856/
for i in range(0,num_examples,batch_size):batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])yield features[batch_indices],labels[batch_indices]
sum:给定一个矩阵
X
,我们可以对所有元素求和(默认情况下), 也可以只求同一个轴上的元素。 如果X
是一个形状为(2, 3)
的张量,我们对列进行求和, 则结果将是一个具有形状(3,)
的向量。 调用时可以指定保持在原始张量的轴数,而不折叠求和的维度。X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) X.sum(0, keepdim=True), X.sum(1, keepdim=True)(tensor([[5., 7., 9.]]),tensor([[ 6.],[15.]]))
tensor的梯度下降
requires_grad:tensor的属性,表示是否要在计算中保留对应的梯度信息,一连串连续的true的节点形成一条求导通路。所有依赖它的节点的requires_grad都为True。
# false表示叶子变量,true表示非叶子变量 w = torch.normal(0,0.01,size=(2,1),requires_grad = True) b = torch.zeros(1,requires_grad = True)
detach:截断反向传播的梯度流,当反向传播经过当前node时,梯度就不再向前传。
也常用于将原数据拷贝出来进行绘图(不影响原数据)
- = 和 = - 的区别
W1 - = learning_rate * W1.grad:在原地修改,之前申请的内存地址不变,仅数据发生了变化。
W1 = W1 - learning_rate*W1.grad :新申请一块内存,原有的W1和更新后的W1内存地址不变
= - 适用于任何情况,- = 只有在grad_fn为None且requires_grad = True的时候不适用。
with torch.no_grad():即使tensor x的requires_grad = True,由x得到的新tensor w的requires_grad也为False,且grad_fn也为None,即不会对w求导(默认情况下requires_grad应该也为True)
计算过程中认为等式右边的tensor的require_grad为False,故即使tensor原本不可以执行 -=操作,这里依旧可以执行,但最终属性还是根据最初的设置判断。
with torch.no_grad(): # 数据不需要计算梯度,也不会进行反向传播for param in params:param -= lr*param.grad / batch_sizeparam.grad.zero_()
先看下面的代码
a = torch.ones(2,requires_grad=True) b = a*2 # b依赖于a,故requires_grad=True print(a, a.grad, a.requires_grad ) # tensor([1., 1.], requires_grad=True) None True print(b, b.grad, b.requires_grad ) # tensor([2., 2.], grad_fn=<MulBackward0>) None Trueb.sum().backward(retain_graph = True) # 回传 print(a, a.grad, a.requires_grad ) #tensor([1., 1.], requires_grad=True) tensor([2., 2.]) Truewith torch.no_grad():a = a + a.grad #生成了一个新变量,no_grad模式下无法求梯度print(a, a.grad, a.requires_grad )# a.grad.zero_() # tensor([3., 3.]) None Falseb.sum().backward(retain_graph = True ) print(a, a.grad ,a.requires_grad ) # tensor([3., 3.]) None Falsewith torch.no_grad():a += a.grad # 可行!逃避了autograd的检测print(a, a.grad, a.requires_grad)# tensor([3., 3.], requires_grad=True) tensor([2., 2.]) Truea.grad.zero_()# tensor([3., 3.], requires_grad=True) tensor([0., 0.]) Trueb.sum().backward(retain_graph = True ) print(a, a.grad ,a.requires_grad ) # tensor([3., 3.], requires_grad=True) tensor([2., 2.]) True # 没加zero:tensor([3., 3.], requires_grad=True) tensor([4., 4.]) True
原本我们希望第二次反向传播时,最后a的输出不包含上一次的梯度(即全新的一次根据loss的求导)但是这里梯度却会被累加。假定我在做一个梯度的更新操作,这个梯度累计越来越大,更新的步长越来越大,loss直接跑飞。所以得加一个梯度清零的操作。
TensorDataset和DataLoader
- TensorDataset:用来对 tensor 进行打包(类似zip)该类通过每一个 tensor 的第一个维度进行索引,因此该类中的 tensor 第一维度必须相等。
- DataLoader:用来包装所使用的数据,每次抛出一批数据
import torch from torch.utils.data import TensorDataset from torch.utils.data import DataLoadera = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 8, 9]]) b = torch.tensor([44, 55, 66, 44, 55, 66, 44, 55, 66, 44, 55, 66]) train_ids = TensorDataset(a, b) # 循环取数据 for x_train, y_label in train_ids:print(x_train, y_label) ''' tensor([1, 2, 3]) tensor(44) tensor([4, 5, 6]) tensor(55) tensor([7, 8, 9]) tensor(66) tensor([1, 2, 3]) tensor(44) tensor([4, 5, 6]) tensor(55) tensor([7, 8, 9]) tensor(66) tensor([1, 2, 3]) tensor(44) tensor([4, 5, 6]) tensor(55) tensor([7, 8, 9]) tensor(66) tensor([1, 2, 3]) tensor(44) tensor([4, 5, 6]) tensor(55) tensor([7, 8, 9]) tensor(66) '''# DataLoader进行数据封装,每次从数据库中每次抽出batch size个样本 train_loader = DataLoader(dataset=train_ids, batch_size=4, shuffle=True) for i, data in enumerate(train_loader, 1): # 注意enumerate返回值有两个,一个是序号,一个是数据(包含训练数据和标签)x_data, label = dataprint(' batch:{0} x_data:{1} label: {2}'.format(i, x_data, label)) ''' batch:1 x_data:tensor([[7, 8, 9],[4, 5, 6],[1, 2, 3],[4, 5, 6]]) label: tensor([66, 55, 44, 55]) batch:2 x_data:tensor([[1, 2, 3],[7, 8, 9],[1, 2, 3],[4, 5, 6]]) label: tensor([44, 66, 44, 55]) batch:3 x_data:tensor([[1, 2, 3],[4, 5, 6],[7, 8, 9],[7, 8, 9]]) label: tensor([44, 55, 66, 66]) '''
torch.flatten(x):默认将张量拉成一维向量,torch.flatten(x,1)为从第二维开始平坦化。torch.flatten(x,0,1) 代表在第一维和第二维之间平坦化
import torch x=torch.randn(2,4,2) print(x)z=torch.flatten(x) print(z)w=torch.flatten(x,1) print(w)''' tensor([[[-0.9814, 0.8251],[ 0.8197, -1.0426],[-0.8185, -1.3367],[-0.6293, 0.6714]],[[-0.5973, -0.0944],[ 0.3720, 0.0672],[ 0.2681, 1.8025],[-0.0606, 0.4855]]])tensor([-0.9814, 0.8251, 0.8197, -1.0426, -0.8185, -1.3367, -0.6293, 0.6714,-0.5973, -0.0944, 0.3720, 0.0672, 0.2681, 1.8025, -0.0606, 0.4855])tensor([[-0.9814, 0.8251, 0.8197, -1.0426, -0.8185, -1.3367, -0.6293, 0.6714] , [-0.5973, -0.0944, 0.3720, 0.0672, 0.2681, 1.8025, -0.0606, 0.4855]]) '''
torch.nn.Flatten():被用在神经网络中,输入为一批数据,第一维为batch,通常要把一个数据拉成一维,而不是将一批数据拉为一维。所以torch.nn.Flatten()默认从第二维开始平坦化。
net. apply():递归地搜索网络内的所有module并把参数表示的函数应用到所有的module上。一般和init函数配套使用。
Logistics
#矢量化后利用线性代数库可以显著提高效率(for循环效率低)
%matplotlib inline
import random
import numpy as np
import torch
from d2l import torch as d2l
# 根据带有噪声的线性模型构造一个人造数据集
def synthetic_data(w,b,num_examples):# 生成size = 1000 * 2 的服从标准正态分布的样本x,即1000个[x1,x2]X = torch.normal(0,1,(num_examples,len(w)))y = torch.matmul(X, w) + b # 一维张量y += torch.normal(0, 0.01, y.shape) # 加噪声return X, y.reshape((-1,1)) # 1000 * 1,不加reshape也可以
# 真实参数,我们希望最后拟合出来的数尽量接近
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features, labels = synthetic_data(true_w,true_b,1000) # 1000个样本,采集两个特征
# featrues中每一行都包含一个二维数据样本,la|bles中每一行都包含一维标签值
print('features:',features[0],'\nlabel:',labels[0])
features: tensor([ 1.4140, -1.3649])
label: tensor([11.6682])
# 生成散点图
d2l.set_figsize()
d2l.plt.scatter(features[:,(1)].detach().numpy(),labels.detach().numpy(),1)
# 随机梯度下降:生成大小为batch_size的小批量
def data_iter(batch_size,features,label):num_examples = len(features)indices = list(range(num_examples))# 样本随机读取,没有特定顺序random.shuffle(indices)# 共生成num_examples/batch_size组,每组个数都是batch_size的随机样本集# 显然可能有样本集可能有重叠,yield局部return,节约内存for i in range(0,num_examples,batch_size):batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])yield features[batch_indices],labels[batch_indices]
# 适合GPU并行运算,连续获得不同的小批量直到遍历完整个数据集
batch_size = 10
for X,y in data_iter(batch_size,features,labels):print(X,'\n',y)break # 没有break会生成100组
tensor([[ 0.1772, -1.1024],[-1.2558, -1.2517],[-0.4269, -0.6371],[-0.1146, 0.6953],[ 0.2708, 1.0730],[ 1.7291, -0.6887],[-0.2078, -0.2044],[-0.3865, -0.8920],[ 2.1464, -0.0057],[-2.1388, -0.6156]]) tensor([[8.2917],[5.9461],[5.5162],[1.6031],[1.0960],[9.9993],[4.4836],[6.4549],[8.5148],[2.0127]])
# 初始化模型参数,之后使用自动微分模块进行梯度下降
w = torch.normal(0,0.01,size=(2,1),requires_grad = True) # 形成求导通路
b = torch.zeros(1,requires_grad = True)
# 根据broadcasting机制,用向量加上一个标量b会加到每个分量上
def linreg(X, w, b):return torch.matmul(X,w)+b# 定义损失函数,注意要转换成维度相同
def squared_loss(y_hat,y):return (y_hat - y.reshape(y_hat.shape))**2/2
# 定义优化算法(小批量)
def sgd(params, lr, batch_size):with torch.no_grad():for param in params:param -= lr*param.grad / batch_size #grad是梯度param.grad.zero_()#清空梯度
# 正式开始训练,very important!
# 每次迭代中读取一小批量训练样本,并得到一组预测,之后开始反向传播
lr = 0.03
num_epochs = 3
net = linreg # 网络类型
loss = squared_lossfor epoch in range(num_epochs):for X,y in data_iter(batch_size,features,labels):l = loss(net(X,w,b),y) # 小批量损失# l的形状是(batch_size,1),故l中所有元素被加到一起以计算梯度l.sum().backward() #梯度回传sgd([w,b],lr,batch_size) # 使用参数的梯度更新参数with torch.no_grad(): train_l = loss(net(features,w,b),labels)print(f'epoch{epoch+1},loss{float(train_l.mean()):f}')
epoch1,loss0.038780
epoch2,loss0.000147
epoch3,loss0.000047
print(w,b)
tensor([[ 2.0002],[-3.3984]], requires_grad=True) tensor([4.1997], requires_grad=True)
标准化实现:
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
true_w = torch.tensor([2,-3.4])
true_b = 4.2
features, labels = synthetic_data(true_w,true_b,1000) # 1000个样本,采集两个特征
# 构造一个PyTorch数据迭代器
# is_train:是否在每个迭代周期内打乱数据
def load_array(data_arrays, batch_size, is_train=True):dataset = data.TensorDataset(*data_arrays) #压缩数据,相当于增广return data.DataLoader(dataset, batch_size, shuffle = is_train) #压缩
batch_size = 10
data_iter = load_array((features, labels),batch_size)
# 通过iter()函数获取这些可迭代对象的迭代器
# 对获取到的迭代器不断使⽤next()函数来获取下⼀条数据
next(iter(data_iter))
[tensor([[ 0.5023, 0.3514],[-0.3454, -0.5636],[-0.7212, 0.3732],[ 1.0469, 0.5950],[ 0.4763, 0.2186],[-0.0729, -0.5102],[ 0.9644, -0.0799],[ 0.2899, 0.2610],[ 0.4827, -0.1519],[ 1.0350, 0.1100]]),tensor([[4.0126],[5.4384],[1.4939],[4.2627],[4.4142],[5.7968],[6.3916],[3.8835],[5.6688],[5.9160]])]
# Sequential类将多个层串联在一起,当给定输入数据时,Sequential实例将数据传到第一层
# 然后将第一层输出作为第二层输入,以此类推
from torch import nn# 此处只有一层,输入特征2(x1,x2),输出特征1(y^)
net = nn.Sequential(nn.Linear(2,1))
# 直接访问参数并进行设定
# 通过_结尾的方法进行参数替换,从而初始化参数
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)# 计算均方误差用MSELoss类
loss = nn.MSELoss()
# 定义优化算法,实例化一个SGD
# 指定待优化的参数net.parameters()
trainer = torch.optim.SGD(net.parameters(),lr=0.03)
'''
通过调用net(X)生成预测并计算损失l(前向传播)
通过进行反向传播来计算梯度
通过调用优化器来更新模型参数
'''
num_epochs = 3 for epoch in range(num_epochs):for X,y in data_iter:l = loss(net(X),y) # 小批量损失trainer.zero_grad()l.backward() #梯度回传trainer.step() # 使用参数的梯度更新参数l = loss(net(features),labels)print(f'epoch{epoch+1},loss{l:f}')
epoch1,loss0.000109
epoch2,loss0.000107
epoch3,loss0.000108
w = net[0].weight.data
b = net[0].bias.data
print(w,b)
tensor([[ 2.0004, -3.3993]]) tensor([4.1999])
softmax
FashionMNIST数据集:
由10个类别的图像组成, 每个类别由训练数据集(train dataset)中的6000张图像和测试数据集(test dataset)中的1000张图像组成。 测试数据集不会用于训练,只用于评估模型性能。
每个输入图像的高度和宽度均为28像素。 数据集由灰度图像组成,其通道数为1。 为简洁起见,将高度ℎ像素、宽度
动手学习pyTorch之【线性模型】—— 具体代码实现相关推荐
- 动手学习pytorch之【感知机】——基础神经网络代码实现
Perceptrons 激活函数的作用:防止隐藏层经过合并后退化为原本的单层线性模型. ReLU线性修正函数是最受欢迎的激活函数(RELU(x) = max(x,0)).另外,挤压函数sigmoid也 ...
- 【动手学习pytorch笔记】24.门控循环单元GRU
GRU 序列中并不是所有信息都同等重要,为了记住重要的信息和遗忘不重要的信息,最早的方法是"长短期记忆"(long-short-term memory,LSTM),这节门控循环单元 ...
- 【动手学习pytorch笔记】28.机器翻译数据集
机器翻译数据集 import os import torch from d2l import torch as d2l 下载和预处理数据集 #@save d2l.DATA_HUB['fra-eng'] ...
- 动手学习pyTorch之【计算过程】——从基础模块类开始
Computation 神经网络块:描述单个层.由多个层组成的组件或整个模型本身(模块化).块由类表示,它的任何子类都必须定义一个将其输入转换为输出的前向传播函数, 并且必须存储任何必需的参数. 注意 ...
- 伯禹公益AI《动手学深度学习PyTorch版》Task 07 学习笔记
伯禹公益AI<动手学深度学习PyTorch版>Task 07 学习笔记 Task 07:优化算法进阶:word2vec:词嵌入进阶 微信昵称:WarmIce 优化算法进阶 emmmm,讲实 ...
- 伯禹公益AI《动手学深度学习PyTorch版》Task 03 学习笔记
伯禹公益AI<动手学深度学习PyTorch版>Task 03 学习笔记 Task 03:过拟合.欠拟合及其解决方案:梯度消失.梯度爆炸:循环神经网络进阶 微信昵称:WarmIce 过拟合. ...
- 动手学习深度学习——Pytorch版教程系列汇总(长期更新版)
动手学习深度学习目录 开发环境配置 1. 基本简介 2. 预备知识 3. 线性神经网络 4. 多层感知器 5. 深度学习计算 6. 卷积神经网络 7. 现代卷积神经网络 8. 循环神经网络 9. 现代 ...
- 【动手学深度学习PyTorch版】6 权重衰退
上一篇移步[动手学深度学习PyTorch版]5 模型选择 + 过拟合和欠拟合_水w的博客-CSDN博客 目录 一.权重衰退 1.1 权重衰退 weight decay:处理过拟合的最常见方法(L2_p ...
- 【 线性模型 Linear-Model 数学原理分析以及源码实现 深度学习 Pytorch笔记 B站刘二大人(1/10)】
线性模型 Linear-Model 数学原理分析以及源码实现 深度学习 Pytorch笔记 B站刘二大人(1/10) 数学原理分析 线性模型是我们在初级数学问题中所遇到的最普遍也是最多的一类问题 在线 ...
最新文章
- P1209 修理牛棚
- 读取word文件中的文本信息
- elasticsearch集群配置文件详述
- 误删oracle数据库文件,误删Oracle数据文件导致数据库无法打开
- java内存图解_图解JAVA内存模型(JMM:JAVA Memory Model)
- 第四章 治病法要(1)
- java自动推断类型_推断:Facebook的新Java静态分析工具
- C++ 处理输入输出错误
- python-面向对向编程-小结
- 运行时动态的开关 Spring Security
- 图像处理:Canny边缘检测算法原理(一)
- NOI.AC NOIP模拟赛 第四场 补记
- Qt中QTableView应用
- CSS背景颜色、背景图片、背景填充
- vb6.0中的Private Declare Function的含义
- [强烈推荐]ring0下文件解锁强制删除工具
- 躲避地震,不要钻入桌子下方
- 佳能2420报错代码E000007-0000
- Discuz! X2.5 数据字典
- 自制黑科技------桌面整理工具
热门文章
- 企业员工计算机基础知识培训心得,计算机员工培训总结
- 查询至少有一门课与学号为“01“的同学所学相同的同学的信息
- 基本的灰度变换函数——幂律(伽马)变换
- 十年,十分爱,10万元广告语征集
- 分享爬取智联的一段源码
- android VTS
- matlab蜘蛛纸牌手机版,蜘蛛纸牌经典版手机版
- 更改软件计算机无法启动怎么办,无法开机:windows未能启动,原因可能是最近更改了硬件或软件...
- 【已解决】VS2019下载超慢的问题
- Java 创建类的四种方式
- 动手学习pytorch之【感知机】——基础神经网络代码实现