目录
[2.3 Dim=1/Rank=1](#2.3 Dim=1/Rank=1)
[2.4 Dim=2/Rank=2](#2.4 Dim=2/Rank=2)
[4.2 前向传播](#4.2 前向传播)
[4.4 三行搞定!](#4.4 三行搞定!)
[4.5 准确率](#4.5 准确率)
[5.1 One-hot编码](#5.1 One-hot编码)
[5.2 保存一些量](#5.2 保存一些量)
[5.3 标准化操作](#5.3 标准化操作)
[5.4 构建网络模型](#5.4 构建网络模型)
[5.5 简单方法构建网络模型](#5.5 简单方法构建网络模型)
[6.2 卷积网络模块构建](#6.2 卷积网络模块构建)
7.2加载models中提供的模型,并直接用训练好的权重当作初始化参数
[7.5 训练模块](#7.5 训练模块)
8.6任务6:根据写好的class类实例化自己的dataloader
[9.1 文本任务数据预处理](#9.1 文本任务数据预处理)
pytorch简介
通常,PyTorch 的用途如下:
- 替代 NumPy 以利用 GPU 的强大功能。
- 提供最大灵活性和速度的深度学习研究平台。
PyTorch 是一个由以下组件组成的库
|-----------------------|---------------------------------------------------------------|
| Component | 描述 |
| torch | 类似 NumPy 的 Tensor 库,具有强大的 GPU 支持 |
| torch.autograd | 基于 Tape 的自动微分库,支持 Torch 中所有可微分的张量操作 |
| torch.jit | 编译堆栈 (TorchScript),用于从 PyTorch 代码创建可序列化和可优化的模型 |
| torch.nn | 与 autograd 深度集成的神经网络库,旨在实现最大的灵活性 |
| torch.multiprocessing | Python 多处理,但具有跨进程的神奇 torch Tensors 内存共享功能。适用于数据加载和 Hogwild 训练 |
| torch.ultis | DataLoader 和其他实用函数以方便使用 |
**总的来说,是支持 GPU 的张量库,**如果您使用 NumPy,那么您就使用了 Tensors(又名 ndarray)。
本文需要python语言的基础。对于pytorch,学习方法是,边用边学,Torch只是个框架,查的过程才是学习的过程。
1.线性回归
求loss的最小值,得出y与WiX+bi最接近的Wi和bi,这里y是(-∞ , + ∞) 的,这就称为Linear Regression(线性回归,拟合)。在Linear Regression添加激活函数,使得y是0 *,*的,这就是Logistic Regression
2.数据类型
之前Numpy一般是在CPU上运行,数据类型是ndarray,而在Pytorch上,数据类型是Tensor(张量),且一般是在GPU上运行的。
对于string类型,pytorch没有提供,但是可以①利用one-hot方法,即将字母改为一个1维向量。
对于输入的数据,一般是array类型,需要将其转换为Tensor类型,方法如下:x_in_trans=map(torch.tensor,(x_in)),其中map是一个映射函数,将x_in转换为x_in_trans,格式由array转换为tensor。
|------------------------|----------------------------|--------------------|-------------------------|
| Data Tpye | dytpe | CPU Tensor | GPU Tensor |
| 32bit floating point | torch.float32/torch.float | torch.FloatTensor | Torch.cuda.FloatTensor |
| 64bit floating point | torch.float64/torch.double | torch.DoubleTensor | Torch.cuda.DoubleTensor |
| 8bit integer(unsigned) | torch.uint8 | torch.ByteTensor | Torch.cuda.ByteTensor |
| 8bit integer(signed) | torch.int8 | torch.CharTensor | torch.cuda.CharTensor |
| 16bit integer(signed) | torch.int16/torch.short | torch.ShortTensor | Torch.cuda.ShortTensor |
| 32bit integer(signed) | torch.int32/torch.int | torch.IntTensor | Torch.cuda.IntTensor |
| 64bit integer(signed) | torch.int64/torch.long | torch.LongTensor | torch.cuda.LongTensor |
2.1数据类型检验
可以用a.type()显示数据类型,也可以用isinstance(a,torch.FloatTensor)进行检验,利用这个data=data.cuda(),可以将数据转换在cuda上
2.2Dimension=0/Rank=0
Dim=0的数据(标量),用于loss值的计算。
2.3 Dim=1/Rank=1
可以是1*n的向量,在torch统称为张量,常用于Bias偏置量,也用于Linear Input线性层的输出。
2.4 Dim=2/Rank=2
注意,Dim指的是维度,如a是2行3列的矩阵,则它的维度dim=2是2维的,size是它的形状,是size([2,3]),表示它的形状是2行3列的,也就是shape。即a.shape输出torch.size([2,3]),size是列表。a.size(0)表示的是size的第一个数据,即为2。同样的a.shape[0]输出也是2。Dim=2的张量,常用于LinearInput batch
3.一些方法
x.shape即可获取x的格式。torch.size返回一个元组(tuple),包含了 PyTorch 张量 x 的各个维度的尺寸信息。注意,x.shape也返回一个元组(tuple),包含了 PyTorch 张量 x 的各个维度的尺寸信息。
torch.nn.functional内置了一些常用的损失函数和激活函数。如cross_entropy交叉熵损失函数。import torch.nn.functional as F;然后loss_func=F.cross_entropy,即可指定loss_func是交叉熵损失函数。
x.mm(weights)+bias即实现wx+b操作,mm指的是矩阵乘法。对于w,它最开始是随机初始化weights=torch.randn([a,b],dtype=torch.float,requires_grad=True)即可完成对weights的随机初始化为a行b列的矩阵,randn是随机初始化方法,dtype=torch.float指的是元素为float类型,requires_grad=True表示是否需要更新。
4.Pytorch完成分类任务
4.1模型参数
python
class Model_Name (nn.Module):
def __init__(self):
super().__init__()
self.hidden1=nn.Linear(784a,128b)
self.hidden2=nn.Linear(128a,256b)
self.out=nn.Linear(256a,10b)
self.dropout=nn.Dropout(0.5)
Model_Name 是要定义的类名,它必须继承nn.Module父类。def init(self)是构造函数,这是接下来构建模型时必备的一些属性、一些参数。self.hidden1=nn.Linear(a,b)是利用了Linear函数实现"全连接"(wx+b),其中a表示输入,b表示输出(即输入784,输出128),需要几层就构建几层,对于分类任务,最后输出也是全连接,就是self.out=nn.Linear(256a,10b),即输出10个分类. self.dropout=nn.Dropout(0.5)表示Dropout,0.5表示按照50%杀死部分"神经元"。以上就是模型所需的参数、属性。
在torch中,前向传播需要自行定义,反向传播是自动的。
4.2 前向传播
python
def forward(self,x):
x=F.relu(self.hidden1(x))
x=self.dropout(x)
x=F.relu(self.hidden2(x))
x=self.dropout(x)
x=self.out(x)
return x
输入是x,这个x是数据中的batch数据的特征,如x是64*784,表示 batch是64,特征是784个(64个样本,每个样本784个特征)。这个前向传播利用到了模型参数中的东西。
以上过程貌似没有定义权重参数,但是实则是pytorch自动定义了。利用以下方法获取哥哥权重参数:
python
net = Model_Name()
for name,parameter in net.named_parameter():
print(name,parameter,parameter.size())
利用net实例化,再利用net调用named_parameter()即可获取这些参数的名字及参数。
4.3训练以及验证
python
def fit(steps,model,loss_func,opt,train_dl,valid_dl):
for step in range(steps):
model.train()
for xb,yb in train_dl:
loss.batch(model,loss_func,xb,yb,opt)
model.valid()
with torch.no_grad():
losses,nums=zip(
*[loss_batch(model,loss_func,xb,yb) for xb,yb in valid_dl]
)
Val_loss=np.sum(np.multiply(losses,nums))/np.sum(nums)
print('当前step:'+str(step),'验证集损失:'+str(val_loss))
steps指的是迭代次数,model是模型,loss_func是损失函数,opt是优化器,train_dl,valid_dl是训练集和验证集。这里的steps相当于epoch,而下面的for循环指的是batch(假如一共有 1000 个数据,每次训练100 个,则batch 就是100 (每次训练100 个数据),而epoch 就是10 (次迭代))。后面的zip就是python的基础了,是打包解包的方法。
以下是优化器的定义:
python
def get_model():
model= Model_Name()
return model,optim.SGD(model.parameters(),lr=0.001)
其中model定义了模型,optim调用SGD优化器,表示的是梯度下降,model.parameters()表示的是接下来要更新什么参数(这里就是全更新),lr是学习率。除了SGD,还有Adam,更为常用。
以下是loss.batch 的定义:
python
def loss_batch(model,loss_func,xb,yb,opt=None):
loss=loss_func(model(xb),yb)
if opt is not None:
loss.backward()
opt.step()
opt.zero_grad()
return loss.item(),len(xb)
这个loss_batch函数的目的就是求出损失loss(model(xb)是预测值,yb是真实值),其次是更新权重参数w,b(如果有优化器,就利用backward()进行反向传播,step()就是参数更新)。原本第一次,第二次,第n次迭代毫无关系,但是torch会进行累计,所以利用opt.zero_grad()将梯度置为零。将这三步视为必备,必须这样写。
4.4 三行搞定!
python
train_dl,valid_dl=get_data(train_ds,valid_ds,bs)
model,opt=get_model()
fit(20,l,loss_func,opt,train_dl,valid_dl)
获取数据,获得模型和优化器,训练以及验证
4.5 准确率
python
correct=0
total=0
for xb,yb in valid_ld:
outputs = model(xb)
_,predicted=torch.max(outputs.data,1)
total+=yb.size(0)
correct+=(predicted==yb).sum().item()
print('Aurracy of network :%d,%%'%(100*correct/total))
准确率在验证集或者测试集上完成计算.
5、Pytorch完成回归任务
回归任务就是经过一系列神经网络,返回一个值
5.1 One-hot编码
利用pandas的get_dummies函数完成
5.2 保存一些量
①将标签值存下②去掉标签值的那一列存下③保存名字④将features转换为ndarray格式。
5.3 标准化操作
将原本不是以中心对称的数据点,拉回来,使其中心对称
5.4 构建网络模型
将输入数据转换为tensor格式。requires_grad表示要进行梯度更新。并指定学习率(就是更新梯度幅度的大小,再乘上学习率,就是在已知更新方向的基础上,要走多少距离,这个距离要小一点),在定义losses损失列表。
这是前向传播的部分,mm是矩阵乘法,hidden经过wx+b操作,在进行relu非线性激活函数,在一层后得到预测结果,并计算损失,将损失值添加进losses损失列表中(转化为ndarray格式,是因为matplotlib支持ndarray而不支持tensor)
(以上代码依然在前向传播的for循环中)反向传播直接利用backward()完成,更新参数时,利用w.grad.data拿到梯度值,并乘以学习率,负号是因为:**看似是梯度下降,是下山问题,但是实际是沿着梯度反方向去更新,是想找什么参数,让损失最低。**由于每次迭代无关,所以然后清零。更新参数这个写法比较麻烦,实际是可以直接调包的。
5.5 简单方法构建网络模型
batch_size是方便计算损失的(原先的是每个数据都进行计算损失,但是实际上数据量及其庞大,所以每batch_size大小的数据再进行一次损失计算)。Sequential就是顺序进行,按顺序完成操作(先全连接,再激活函数:sigmoid和relu都行,再全连接)。损失计算也是调包,利用MSELoss损失函数。然后就是优化器,之前是w拿到梯度乘上学习率再添负号,现在是直接利用Adam优化器,并指定优化参数和学习率。Adam思想如下,利用惯性方向,进行平行四边形法则,得到最优方向。
利用batch思想进行。每次只训练一个batch的数据(要加上start和end索引,以方便取出)。
6、Pytorch实现卷积神经网络
6.1导入数据集
导入MNIST数据集,train=True指定训练集,train=False指定验证集,利用transform包将数据更改为tensor类型.
6.2 卷积网络模块构建
CNN是类名字,init()是构造函数,Conv2d表示的二维卷积,Conv3d就是三位卷积,一般用于视频;Conv2d里面的元素,一是in_channel是通道数,1就是灰度图,3就是RGB图像;out_channel输出特征图个数(也是卷积核的个数);kernel_size是卷积核大小;stride是步长;padding是填充操作,padding为2就是在图像周围添加两圈的0。然后就是Relu非线性映射。再然后就是MasPool2d最大池化(kernelSize=2是在2*2进行池化)。
然后就是第二个卷积,(16是in_channel是上个卷积的输出,32是out_channel,5是卷积核大小,1是步长,2是填充)。再继续进行,最终要进行全连接。
6.3前向传播
x是输入,是batch×C×H×W的张量。x.view类似于reshape操作,将数据变为H为x.size(0),W为自动计算的结果,-1表示自动计算。全连接之前先要进行reshape(即view)操作。
6.4准确率
pred后面的[1]表示:max会返回两个值,第一个是这个最大值,第二个是最大值对于的索引,pred拿到的就是索引。然后统计相等的总数。
6.5训练网络模型
nn.CrossEntropyLoss()为常用的交叉熵损失函数的写法,损失函数为交叉熵损失函数,并定义优化器。
利用enumerate枚举,可以得出一batch idx,他就是个计数(1,2,3.......),利用该计数,可以在后面的batch idx%100=0的情况下进行validation(即每过100次跑一次验证集)。net train就是训练;output得到预测值;loss计算损失;梯度清理;反向传播;参数更新;算准确率正确多少个;将多少个正确的保存。
准确率计算是在验证集if语句下的,用于计算准确率,并打印。
7、图像识别常用模块解读
7.1数据读取与图像预处理
data_transformer中制定了所有图像的预处理操作,ImageFolder假设所有的文件按文件夹保存好,每个文件夹下面存储同一类图片,文件夹名字为分类名字。
Data Augmetation 数据增强:所有黑体
++训练集预处理++ :transformer.Compose指的是按顺序完成下列操作:Resize将图像转换为指定长宽的大小(这个大小很重要,越大效果越好但是时间越慢);RandomRoatation (a)指的是在-a到a之间的角度随机旋转(最大45);CenterCrop (64)指的是从中心随机裁剪为长宽是64的图像;RandomHorizontaFlip (p=0.5)是随机垂直翻转, p=0.5是翻转概率;ColorJitter (brightness=0.2,contrast=0.1,saturation=0.3,hue=0.1)依次分别是亮度、对比度、饱和度、色相(这个方法用的很少);RandomGrayscale(p=0.025)指的是概率转换为灰度图(用的更少)。ToTensor转行为tensor格式,Normalize标准化(第一个是标准差,第二个是均值,每个元素指的是RGB三通道,这个数据来源是大型数据集的结果)
++验证集预处理++:不用数据增强。直接resize成想要的的大小,并转化为tensor,并且进行归一化(数据用的是训练集的均值方差数据)。
x是字典的key,在datasets调用ImageFolder。这里的方法不重要,后续有更为通用的方法。
7.2加载models中提供的模型,并直接用训练好的权重当作初始化参数
就是backbone特征提取器,常见的有resnet,alexnet,vgg等等。使用方法有两个,一是在别人论文源码中,将模型复制过来,二是torchvision收录了一些经典网络,可以直接调包。
迁移学习:利用被人的模型以及权重训练自己的数据集。 那么别人的模型如resnet并没有训练过花朵的数据集,这些权重能直接用吗?答案是可以的 ,因为它本身就是提取特征的,权重描述了提取特征好坏的能力 ,而不是针对不同数据集有不同权重。我们要做的只是**微调。**如何微调?调什么参数?若你的数据集比较小,则大部分不用改,只改小部分(如只改输出层)这个方法称为"冻住"。若数据集不大不小,则"冻住"区域小一些(只改从输出层向上几层)。若数据集很大,则每一层都调整权重。最少最少输出层得调整。
model_name指定为resnet,feature extract指定为ture,指的是不更新任何权重。
判断训练设备,是CPU还是GPU。
指定模型为resnet18,即用的是18层的resnet,速度较快,也可以50层的或者153层的,根据条件选择。观察它的网络结构,发现每次卷积完会有BatchNorm2d操作,是因为开始预处理时已经经过了归一化操作,但是在每次卷积之后,分布会发生变化,所以需要再次归一化,使网络学习更好。这个BN层在每次卷积之后都添加。在最后全连接之前,resnet18进行的是全局平均池化(指定步长为1),类似于reshape(学习卷积时在全连接之前将数据拉为长条),加入现在数据是14*14*512,就是将14*14的数据取平均为一个值,512分别操作得到512个值。
设置set_parameter_requires_grad函数用于判断是否更新权重参数,for循环是遍历所有的模型参数,查看是否更新。
通过如下函数,将模型更改为自己的。
7.3设置哪些层需要训练
模型保存为pt文件(保存的是网络结构图,所有的w,b权重参数,以后可以直接用该pt文件)。然后将所有的模型参数保存在param_to_update,如果当params.requires_grad为True的时候,才将param放进param_to_update。这些参数要在opt优化器进行更新。
7.4参数更新
利用Adam更新参数,并定义了衰减策略,用的是stepLR,stepsize是每10次执行衰减,gamma表示学习率变为原来的gamma倍。还定义了交叉熵损失函数。
7.5 训练模块
定义时间、最好的准确率、训练设备、四个list、学习率、最好的模型
8、Dataloader文件标注
标注文件一般是txt文件、json文件、xaml文件等等。
原始数据,先进行随机打乱random shuffle,得到队列,每多少个构成一个batch。
8.1任务1:读取txt文件中的路径和标签
定义一个字典数据data infos,key是图片名字,v是图片内容,然后打开文件,以readline每行去读,strip是去掉换行符等等、split是字符串切分,以空格切分,将其存放在samples列表变量中(格式是[xxx,lables],xxx是名字,一个大list有许多小list)。然后遍历samples这个大list,再在data infos以xxx为key,以lables为v,构建字典。
8.2任务2:分别把标签和数据存放在list中
需要把所有的keys转换为list,所有的values转化为list,这是dataloader将来会在这里提数据。
8.3任务3:数据路径得完整
因为一会要用这个路径去读取数据,所以路径得加上前缀。任务不同,数据不同,方法不同,但是一定要读到图像数据。
把前面的train dir与img路径合并。
8.4任务4:将上述三步写在一起
首先导入Dataset和Dataloader包。并且构造函数__init__和__getitem__函数必须存在。完成的是两个list,一个是存放所有图像数据路径的list,一个是存放所有标签的list。
__init__完成的是两个list,一个是存放所有图像数据路径的list,一个是存放所有标签的list。__getitem__的两个参数都不要更改,idx是随机的索引,首先是得到图像数据和标签数据,判断要不要数据增强,并将标签数据转换为tensor格式。会执行batch次__getitem__函数,batch自己指定,这batch个数据会进入模型。
load annotation函数是将字典转换成list。
8.5任务5:数据预处理(transform)
同样在__getitem__函数中完成。在transform这里就完成了数据转换为tensor格式。代码和之前一模一样。
8.6任务6:根据写好的class类实例化自己的dataloader
实例化两个,train dataset和val dataset。
利用Dataloader包完成构建dataloader,传入对应的参数即可。
8.7任务7:用前试试,整个数据和标签对应下,看看对不对
利用iter.(train_loader).next()试试,是一个batch数据。suqeeze是压缩某个没用的维度,可有可无。permute是转换维度的,tensor是BGR格式,先转为RGB格式,再变为numpy格式,方便画图。
9、LSTM文本任务
文本数据标签文件。新闻主题分类,包含训练集、验证集、测试集。
9.1 文本任务数据预处理
Google认为英文文本适合分词,中文文本适合分字,我们以分字进行,这是第一步。第二部是ID替换,有一个大的预料表(包含5000个常用字),每个字对应一个ID序号,将每个字替换为序号,这样文本转换为一个数字组成的list。第三步是映射表,即就是Embedding,词嵌入,将这个list转换为一个词向量(这个向量是大型企业训练出的,如搜狗,腾讯)。综上所述,预料表将文本转换为ID,映射表将ID转换为向量。