b站小土堆的pytorch教学视频,实在是太好了。不光教代码的语法功能,更重要的是教你看pytorch官网。
本文作为学习笔记,将小土堆提供的GPU训练代码进行详解分析,(因为这个案例基本上综合了小土堆前面讲过的所有内容)防止自己忘了。可以随时查看。
import torch
import torchvision
from torch.utils.tensorboard import SummaryWriter
# from model import *
# 准备数据集
from torch import nn
from torch.utils.data import DataLoader
train_data = torchvision.datasets.CIFAR10(root="../data", train=True, transform=torchvision.transforms.ToTensor(),
download=True)
test_data = torchvision.datasets.CIFAR10(root="../data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
# length 长度
train_data_size = len(train_data)
test_data_size = len(test_data)
# 如果train_data_size=10, 训练数据集的长度为:10
print("训练数据集的长度为:{}".format(train_data_size))
print("测试数据集的长度为:{}".format(test_data_size))
# 利用 DataLoader 来加载数据集
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
# 创建网络模型
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.model(x)
return x
tudui = Tudui()
#网络模型cuda
if torch.cuda.is_available():
tudui = tudui.cuda()
# 损失函数
loss_fn = nn.CrossEntropyLoss()
if torch.cuda.is_available():
loss_fn = loss_fn.cuda()
# 优化器
# learning_rate = 0.01
# 1e-2=1 x (10)^(-2) = 1 /100 = 0.01
learning_rate = 1e-2
optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)
# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10
# 添加tensorboard
writer = SummaryWriter("../logs_train")
for i in range(epoch):
print("-------第 {} 轮训练开始-------".format(i+1))
# 训练步骤开始
tudui.train()
for data in train_dataloader:
imgs, targets = data
if torch.cuda.is_available():
#图像cuda;标签cuda
#训练集和测试集都要有
imgs = imgs.cuda()
targets = targets.cuda()
outputs = tudui(imgs)
loss = loss_fn(outputs, targets)
# 优化器优化模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step = total_train_step + 1
if total_train_step % 100 == 0:
print("训练次数:{}, Loss: {}".format(total_train_step, loss.item()))
writer.add_scalar("train_loss", loss.item(), total_train_step)
# 测试步骤开始
tudui.eval()
total_test_loss = 0
total_accuracy = 0
with torch.no_grad():
for data in test_dataloader:
imgs, targets = data
if torch.cuda.is_available():
imgs = imgs.cuda()
targets = targets.cuda()
outputs = tudui(imgs)
loss = loss_fn(outputs, targets)
total_test_loss = total_test_loss + loss.item()
accuracy = (outputs.argmax(1) == targets).sum()
total_accuracy = total_accuracy + accuracy
print("整体测试集上的Loss: {}".format(total_test_loss))
print("整体测试集上的正确率: {}".format(total_accuracy/test_data_size))
writer.add_scalar("test_loss", total_test_loss, total_test_step)
writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
total_test_step = total_test_step + 1
torch.save(tudui, "tudui_{}.pth".format(i))
print("模型已保存")
writer.close()
在pytorch官网可以选择下载不同的数据集,步骤如下:
之后选择torchvision(视觉类),torchtext(文本),torchaudio(语音)
此处选择的是视觉类,进入pytorchvision后
选择左侧选择torchvision.datasets,在左侧就可以看到,各种数据集,根据需要选择一个。即可看到他的使用下载方法;
比如此处选择CIFAR;以此为例来讲解数据集下载使用方法
root:你要将文件夹下载到哪个路径
train:是否下载训练集(True表示下载训练节,False表示下载测试集,transform:转换数据集的类型,转换成tensor类型,便于训练;target_transform不太清楚这个参数,download为True表示下载False则不下载)
#下载路径为../data;第二个参数表示现在训练集;第三个参数表示下载成tensor类型,最后将download设置为true
train_data = torchvision.datasets.CIFAR10(root="../data", train=True, transform=torchvision.transforms.ToTensor(),
download=True)
#,train=False 表示下载测试集
test_data = torchvision.datasets.CIFAR10(root="../data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
加载数据集方式主要使用的是DataLoader;我们不管是自己制作的数据集,还是从网上下载的数据集,当我们把这些数据送到神经网络训练的时候,我们必须用一些特定的方式送给神经网络。这便是DataLoader的作用,比如最常见的batch_size。有时数据集非常的大几万甚至几十万张图片,一张一张送进送进神经网络效率太低,所以我们要成批(batch_size)的送给神经网络。还有我们是否对数据集打乱等等。
在官网上从如下位置找到(进入官网,选择Docs,选择Pytorch)在左侧找到torch.utils.data(在很靠下的位置)
或者直接在搜索框DataLoader
表红的是一些常用的参数
dataset:要送进神经网络的数据集
batch_size:以图片为例,每次送几张图片给神经网络(好多人也叫喂feed)
num_workers=0代表用多少进程加载数据,0表示用主进程加载数据 ;
drop_last:表示是否舍去最后多余的数据;举个例子,比如我们有10000张图片,batch_size=64;
10000%64=16;我们是否要舍弃最后这16张图片;True表示舍弃;False代表不舍弃
所有参考资料都可以在Pytorch官网->Docs->torch.nn找到
所有神经网络的基类,你构建的神经网络必须继承这个基类,然后实现他内部的一些方法从而搭建自己的神经网络。
import torch
from torch import nn
#继承nn.module,并重写他的方法
class Tudui(nn.Module):
def __init__(self):
super().__init__()
#重写forward函数
def forward(self, input):
output = input + 1
return output
#实例化对象
tudui = Tudui()
x = torch.tensor(1.0)
output = tudui(x)
print(output)
卷积层详述_ZHAO-CSDN博客_卷积层
卷积层是实现神经网络的主要部分
左侧可以理解为输入图像
中间就是卷积核
最右侧是输出
仍然在torch.nn里,中间nn.Conv1d ,nn.Conv2d,nn.Conv3d分别是1维卷积,二维卷积,三维卷积
最常用的还是二维卷积,就像上图。
in_channels:输入的通道数;最初的输入一般都是3(RGB),或者1(灰度图);之后每一层输入通道数都应为前一层的输出通道数
out_channels:输出通道数
kernel_size:巻积核大小(上图中所展示的就是3*3,填写参数时仅需写一个3即可)
stride:步长;卷积核在图像上每次移动的距离,上图为1
padding_mode:在图像周围补充0;默认padding_mode=0;就是不填充0;padding_mode=1;就是在图像周围填一圈0;
dilation:正常情况下为1;为2则代表空洞卷积
bias:偏置;卷积可以想象成是做了一次乘法,偏执就是作一次加法;
神经网络训练过程中就是在不断的调解卷积核里的这些参数和偏置的参数;调整到通过一个输入可以达到我们想要的输出。
N:batch_size
C:通道数
H,W:图像的高和宽
self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
按照上面的公式输出如下:
H=(3+2*0-1*(3-1)-1)/1 +1=2
W=(3+2*0-1*(3-1)-1)/1 +1=2
池化层比较常用的有最大池化平均池化等
最大池化指的是在卷积核覆盖的区域,取出最大值,平均池化指将卷积核区域内的数取平均
最大池化一般用来提取特征
参数与卷积层基本一致,不过不用指定输入和输出
展平将多维数据展平成一维数据,例如
一幅32*32的彩色图像可以展平成32*32*3=3072的一维数据,最后的3代表三通道
#32batch_size,1通道。大小为5*5,
input = torch.randn(32, 1, 5, 5)
m = nn.Sequential(
#输入通道为1。输出通道数为32。卷积核大小:5。stride(步长为1),padding=1;填充一圈0;
nn.Conv2d(1, 32, 5, 1, 1),
nn.Flatten()
)
output = m(input)
output.size()
结果
torch.Size([32, 288])
先计算经过卷积操作之后的内容
H=(5+2*1-1*(5-1)-1)/1 +1=3
W=(5+2*1-1*(5-1)-1)/1 +1=3
通道数32,展成1维是32*3*3=288
并且batch_size=32;所以最后的结果是[32,288];
输入[x1,x2,........xd]每一个都乘以权重并相加再加上偏置后得到输出
参数input一般为输入的维度,weight为权重的维度(输出)要在训练的过程中不断调整权重的数值
bias为偏置;True则有偏置,False则无偏置;
import torch
import torchvision
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("../data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=64, drop_last=True)
#全连接
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
#输入特征数(全都是1维的有196608个,一个batch_size内图片展成1维是这么大),第二个参数是输出特征数
self.linear1 = Linear(196608, 10)
def forward(self, input):
output = self.linear1(input)
return output
tudui = Tudui()
for data in dataloader:
imgs, targets = data
print(imgs.shape)
#展平成1维,和reshape成(1,1,1,-1)类似
output = torch.flatten(imgs)
print(output.shape)
output = tudui(output)
print(output.shape)
首先下载CIFAR10数据,用DataLoader加载数据batch_size=64;
先展平,再送到线性层;展平后大小计算
64*32*32*3=196608
所以
输入为196608,输出为10
self.linear1 = Linear(196608, 10)
损失函数总体上的思想指的是计算神经网络预测出的结果和标签的差别,计算方式多种多样,每一种方式都代表一类算法。
最简单的两类包是绝对值误差和平方差
很简单就是将神经网络的输出当作输入,与标签求差再平方,最终的平方误差可以取均值或者求和。目标是使神经网络输出与标签之差越来越小,减小误差需要用到优化器,下一节介绍。
import torch
from torch.nn import L1Loss
from torch import nn
inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)
#1 barch_size 1通道,1行,三列
inputs = torch.reshape(inputs, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))
#直接相减
loss = L1Loss(reduction='sum')
result = loss(inputs, targets)
#平方差
loss_mse = nn.MSELoss()
result_mse = loss_mse(inputs, targets)
print(result)
print(result_mse)
优化器总体思想是通过计算梯度,对神经网络的参数进行优化。得到最满意的输出
使用优化器第一步要先构建优化器,一般不同的优化器参数很不相同,所以使用到哪种优化器需要看相应的简介进行参数填充。不过绝大部分优化器都有lr(学习率这一参数);
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)
for input, target in dataset:
#首先要将梯度设置为0,这样上一步的梯度不会对这一步产生影响
optimizer.zero_grad()
#通过神经网络获得输出
output = model(input)
#计算神经网络输出与target的差值(各种损失函数求出的值)
loss = loss_fn(output, target)
#反响传播
loss.backward()
#根据梯度进行优化卷积核或者全连接层权重内的数值,减小损失函数的值
optimizer.step()
tensorboard主要是用来显示图像;它不是pytorch自带的所以需要提前安装它;
pip install tensorboard
使用方法也很简单;
from torch.utils.tensorboard import SummaryWriter
import numpy as np
#构建,括号中的参数为图像保存路径(并不是图像,是一种特殊格式文件)
#通过tensorboard --logdir=logs --port =600x(logs为输出图表文件夹名字)查看输出结果
##后面可以设置端口
writer = SummaryWriter('../logs_trai')
for n_iter in range(100):
#第一个参数是标题,第二个参数是y轴,第三个参数是x轴
writer.add_scalar('Loss/train', np.random.random(), n_iter)
writer.add_scalar('Loss/test', np.random.random(), n_iter)
writer.add_scalar('Accuracy/train', np.random.random(), n_iter)
writer.add_scalar('Accuracy/test', np.random.random(), n_iter)
for i in range(epoch):
print("-------第 {} 轮训练开始-------".format(i+1))
# 训练步骤开始
tudui.train()
for data in train_dataloader:
imgs, targets = data
imgs = imgs.to(device)#加入cuda
targets = targets.to(device)#加入cuda
outputs = tudui(imgs)
loss = loss_fn(outputs, targets)
# 优化器优化模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step = total_train_step + 1
if total_train_step % 100 == 0:
print("训练次数:{}, Loss: {}".format(total_train_step, loss.item()))
writer.add_scalar("train_loss", loss.item(), total_train_step)
# 测试步骤开始
tudui.eval()
total_test_loss = 0
total_accuracy = 0
with torch.no_grad():
for data in test_dataloader:
imgs, targets = data
imgs = imgs.to(device)#加入cuda
targets = targets.to(device)#加入cuda
outputs = tudui(imgs)
loss = loss_fn(outputs, targets)
total_test_loss = total_test_loss + loss.item()
accuracy = (outputs.argmax(1) == targets).sum()
total_accuracy = total_accuracy + accuracy
print("整体测试集上的Loss: {}".format(total_test_loss))
print("整体测试集上的正确率: {}".format(total_accuracy/test_data_size))
writer.add_scalar("test_loss", total_test_loss, total_test_step)
writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
total_test_step = total_test_step + 1
torch.save(tudui, "tudui_{}.pth".format(i))
print("模型已保存")