"""===================================================================================================="""
"""|| Pytorch学习手册 ||"""
"""|| ||"""
"""|| 2021年5月4日 ||"""
"""===================================================================================================="""
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets,transforms
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
'pytorch是一个基于python的科学计算包,主要定位两类人群:'
'· numpy的替代品,可以使用CPU的性能进行计算'
'· 深度学习研究平台具有足够的灵活性和速度'
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@Tensors张量
'tensors类似于numpy的ndarrays,同时tensors可以使用GPU进行计算'
x = torch.empty(size, dtype=torch.long)
x = torch.zeros()
x = torch.rand() #rand生成均匀分布的伪随机数 randn生成标准正态分布的伪随机数
x = torch.tensor([data]) #可直接构造一个张量
x.shape() #获取维度信息,是一个元组 (z, x, y)
#对张量的操作
#加法操作
x = torch.rand(5,3)
y = torch.rand(5,3)
c = x + y
c = torch.add(x,y)
c = torch.empty(5,3)
torch.add(5,3,out=c)
y.add_(x) #把x加给y
'任何使张量发生变化的操作都有一个前缀 _ '
#复制操作
x.copy_(y)
#转置
x.t_()
#可使用标准的NumPy类似的索引操作
print(x[:,1])
#相当于reshape
'size可以是张量的总数,也可以是数组 -1表示自动检测行数或列数'
y = x.view(size)
# 如果你有一个元素tensor,可以使用item获得他的value
y = x.item()
#数据维度的处理
torch.squeeze(tensor) #数据维度压缩
'将数据中维数为1的维度,一行或一列,一个三维(2,1,5)操作后变成(2,5)'
b = a.squeeze(N)
b = torch.squeeze(a,N)
'去掉a中指定的维数N为一的维度'
torch.unsqueeze() #数据维度扩充
'给指定位置加上维数为一的维度,比如原本三行的数据,在0的位置上加了一维就变成了一行三列(1,3)'
a.unsqueeze(N)
b = torch.unsqueeze(a,N)
'在指定位置N上加一个维数为1的维度'
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@torch.nn模块
'torch.nn模块是专门为神经网络设计的模块化接口,.nn构建于autograd之上,可以用来定义和运行神经网络'
'如何定义自己的网络: '
' 1. 需要继承nn.Module的类,并实现forward方法。继承nn.Module类之后,在构造函数中要调用Module的构造函数'
' 2. 一般把网络中具有可学习参数的层放在构造函数__init__()中,如全连接层、卷积层等'
' 3. 不具有可学习参数的层可放在构造函数中'
' 4. 只要在nn.Module中定义了forward函数,backward函数就会被自动实现(利用Autograd)'
' 2. 在forward中可以使用任何Variable支持的函数,在整个pytorch构建的图中,是Variable在流动'
#搭建过程
#定义一个Class,继承nn.Module
import torch.nn as nn
class Net(nn.Module): #Class中主要写两个函数,一个是初始化的__init__函数,另一个是forward函数
def __init__(self):
#固定内容
'__init__中就是定义卷积层,需要super()一下,给父类nn.Module初始化一下'
super(Net, self).__init__()
#定义相关的函数
'定义卷积层,比如第一层定义为conv1,为输入1通道,输出6通道,卷积核5*5的一个卷积层'
'需要注意前后输出通道和输入通道高的一致性,不能够第一个卷积层输出4通道,后一个输入6通道'
self.conv1 = nn.Conv2d(1,20,5)
self.conv2 = nn.Conv2d(20, 20, 5)
def forward(self,x):
#构建模型结构,可以使用torch自带的内容,其他调用__init__里面的函数
'forward中执行真正的数据的流动,输入的x逐层经过各个层,torch.relu为官方提供的函数,最后数据经过流动,返回给外面'
x = torch.relu(self.conv1(x))
'torch.relu为激活函数 r(x) = max(0,x),还有其他的激活函数如tanh和sigmoid都是比较常用的,激活函数是为了进入非线性因素,解决线性模型不能解决的问题'
'tanh很好'
return x
net = Net(1,20,2)
print(net)
#使用顺序容器nn.Sequential搭建
net = nn.Sequential(
nn.Linear(1,20),
nn.ReLU(),
nn.Linear(20,20),
nn.ReLU(),
nn.Linear(20,1)
)
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@构建优化器
'torch.optim是一个实现了各种优化算法的库,大部分常用的方法得到支持,并且接口具备足够多的通用性'
'为了使用torch.optim,需要构建一个optimizer对象,这个对象能够保持当前参数状态并基于计算得到的梯度进行参数更新'
'为了构建一个Optimizer,需要给他一个包含了需要优化的参数(必须都是Variable对象)的iterable,然后就可以设置optimizer的参数选项,比如学习率、权重衰减等'
optimizer = torch.optim.SGD(net.parameters(), lr = 0.1) #随机梯度下降
'Stochastic Grafient Descent SGD(随机梯度下降)是最基础的优化方法,普通的训练方法,需要重复不断的把整套数据放入神经网络NN中训练,'
'这样消耗的计算资源会很大;当我们使用SGD时,会把数据拆分后再分批不断放入NN中计算,每次使用批数据,虽然不能反应整体数据的情况,不过'
'却很大程度上加速了NN的训练过程,而且也不会丢失太多准确率。'
opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.8) #动量加速
'SGD的改良版,在SGD中指定momentun即可'
opt_RMSprop = torch.optim.RMSprop(net_RMSprop.parameters(), lr = 0.0001, alpha = 0.9) #RMSprop
'momentum的升级版,有momentum的惯性原则,和adagrad对错误方向的阻力'
opt_AdaGrad = torch.optim.Adam([var1,var2], lr = 0.0001, betas = (0.9,0.99)) #AdaGrad 使用adam能够很好的达到目标
'AdaGrad优化学习率,使得每一个参数更新都会有自己与众不同的学习率'
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@构造损失函数
'一般来说,Pytorch的损失函数有两种形式:函数形式和模块形式。前者是调用torch.nn.functional库中的函数,通过传入神经网络预测值和目标值来计算损失函数;'
'后者是torch.nn库里的函数,通过建立一个模块的实力,然后通过调用模块的方法来计算最终的损失函数。'
loss_func = torch.nn.MSELoss() #初始化平方损失函数
'对于回归问题一般使用MSELoss损失函数'
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@网络结构的定义
#全连接层
nn.Linear(input, output)
#卷积层
nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)
'in_channels: 输入通道数'
'out_channels: 输出通道数'
'kernel_size: 卷积核的尺寸'
'stride: 步长'
'padding: 添加的边'
#池化层
'位于连续的卷积层中间,用于压缩数据和参数的量,减小过拟合'
nn.MaxPool2d(2,2)
'最大值提取,通常参数设定为(2,2)'
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@激活函数的设置
'激活函数是用来引入非线性因素的,提高神经网络对模型的表达能力,以解决线性模型不能解决的问题'
'对于二分类问题,隐层relu输出sigmoid效果最好'
#修正线性单元Relu
'a = max(0,z) 缺点是Z为负时较慢'
F.relu(Tensor)
#S型函数Sigmoid
'除了二分类问题的输出层,其他不要用,z很大或很小时,速度会很慢'
F.sigmoid(Tensor)
#tanh
'除输出层外效果都很好,但z很大或很小时,速度会很慢'
F.tanh(Tensor)
#归一化
'为减小每一层参数迭代更新后数据分布发生的变化,将迭代更新后的数据进行归一化'
nn.BatchNorm1d(Tensor)
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
# @网络读取
# 'pytorch提供了一个数据读取的方法,其由两个类构成: torch.utils.data.Dataset 和 Dataloader'
#
# #DataLoader封装
# 'DataLoader将Dataset或其子类封装成一个迭代器,可以迭代输出Dataset的内容弄个,同时可以实现多进程、shuffle、不同采样策略、数据校对等处理过程'
# torch.utils.data.DataLoader(dataset, batch_size, shuffle)
# 'dataset: 待封装的对象'
# 'batch_size: 输出的批次大小 64'
# 'shuffle: 是否随机输出 True / False'
#
#
# "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@网络结构的保存和提取
#1. 网络结构的保存
torch.save(name, 'path')
'提取时直接提取相关文件即可'
net = torch.load('path')
#2. 网络参数的保存
'由于在大型神经网络结构中,网络的结构非常复杂,直接保存会占用大量的磁盘空间,所以大多数情况使用网络参数的保存'
torch.save(net.state_dict(), 'path') #保存优化选项默认字典,不保存网络结构
'提取前需建立一样的网络结构,再去提取参数进行恢复'
net = torch.nn.Sequential(
nn.Linear(1,20),
nn.ReLU(),
...
)
net.load_state_dict(torch.load('path'))
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@数据集的处理
'torchvision是pytorch的一个图形库,服务于torch深度学习框架,用于构建计算机视觉模型'
'其主要构成为:'
'1. torchvision.datasets: 加载数据的函数及常用的数据集接口'
'2. torchvision.transforms: 常用的图片变换,裁剪旋转等'
'3. torchvision.models: 包含常用的模型结构,例如AlexNet、VGG、ResNet等'
'4. torchvision.utils: 其它一些有用的方法'
#transforms.compose修改图片
'compose用于管理transform,设置transform'
data_transform = transforms.Compose([
transforms.Resize(d), #修整图片大小d*d
transforms.CenterCrop(d), #从图片中心裁剪图片d*d
transforms.ToTensor(), #读取图像中的像素并转化为0-1的数字
transforms.Normalize(mean = [0.5,0.5,0.5], std = [0.5,0.5,0.5]) #将数据集的数据转化为标准差和均值都为0.5的数据集,(0,1) → (-1,1)
])
#datasets.ImageFolder图像数据加载器
'ImageFolder是一个通用的数据加载器,要求使用以下格式 root/dog/dog1.png'
train_dataset = datasets.ImageFolder(
root = 'root/train/...', #数据集的路径
transform = data_transform #数据集的变换操作
)
#数据集读取
train_lodar = torch.utils.data.DataLoader(
dataset = train_dataset, #数据集名称
batch_size = 4, #输出单批次的大小
shuffle = True, #是否随机输出
)
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@其他
#张量拼接 concatenate
torch.cat(tensors, dim, out)
a = torch.cat((b,c),0/1) #按行0或列1拼接
#随机数
torch.rand(size) #均匀分布 返回[0,1)内均匀分布的随机数
torch.randn(size) #标准正态分布
torch.normal(means, std) #离散正态分布
'means(float,optional): 均值'
'std(Tensor): 标准差'
Tensor = torch.linspace(start, end, steps) #线性间距向量
'返回一个1维张量,包含在区间start和end上均匀间隔的step个点,输出张量的长度由steps决定'
#最大值返回
torch.max(a,0/1) #返回每一列/行中最大的元素,且返回其索引 列/行
...
1 2 3
4 5 6
7 8 9
>>torch.max(a,0)
3
6
9
2
2
2
#Numpy数组转化为Tensor
torch.from_numpy(ndarray)
#通道变化
img = img.numpy().transpose(0,1,2)
"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
@tensorboard可视化
from tensorboardX import SummaryWriter
writer = SummaryWriter
#将标量添加到summary
writer.add_scalar(tag, scalar_value, global_step, walltime)
'tag: 标签'
'scalar_value: 保存的标量名 y'
'global_step: 全局步值 x'
writer.add_scalars()
'tensorboard --logdir=path --host=127.0.0.1'
print(torch.cuda.is_available())
print(torch.cuda.current_device())
print(torch.cuda.get_device_capability(),torch.cuda.get_device_name())