目录
pytorch官网:torchvision — Torchvision master documentation (pytorch.org)
一、前期准备
1、PyTorch环境配置
1、创建虚拟环境
1、conda create -n pycyy python=3.7 -c 镜像地址
以下是一些常见的conda镜像地址:
- 清华大学:
https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
- 阿里云:
https://mirrors.aliyun.com/anaconda/pkgs/main/
- 北京外国语大学:
https://mirrors.bfsu.edu.cn/anaconda/pkgs/main/
2、conda activate pycyy
3、在pytorch官网复制上述python版本对应的pytorch配置代码,如:conda install pytorch torchvision torchaudio cpuonly -c pytorch
[i]
2、配置GitHub上下载的项目
1、利用PyCharm打开项目:File->Open
2、配置相应的虚拟环境:File->Setting->Project->Python解释器。然后选择对应的虚拟环境
3、直接运行代码,右键->run
4、如果提示某些包没有发现,可以用
-
conda activate pycyy
-
conda install 包名
-
pip insatll 包名
利用搜索引擎找原因 - 包名不对、通道不对,或者其他原因
5、可选 - 最好把requirements.txt文件内容当做参考,有选择性使用
3、jupyter的使用
-
conda activate pycyy
-
jupyter notebook D:
[i]
Jupyter Notebook(pycyy)属性:
[i]
目标:D:\software\anaconda\Ana\python.exe D:\software\anaconda\Ana\cwp.py D:\software\anaconda\Ana\envs\pycyy D:\software\anaconda\Ana\envs\pycyy\python.exe D:\software\anaconda\Ana\envs\pycyy\Scripts\jupyter-notebook-script.py "%USERPROFILE%/"
将"%USERPROFILE%/"改为"D:\"即打开Jupyter Notebook(pycyy)直接进入D盘,不用在每次都执行jupyter notebook D:命令
2、加载数据初认识
1、Dataset
提供一种方式获取数据及其label
-
如何获取每一个数据及其label
-
告诉我们总共有多少个数据
2、Dataloader
为网络提供不同的数据形式(如压缩形式)
3、使用Python Console查看类的属性
可以看到图片的宽、高等相关属性信息
4、Tensorboard
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter("logs")
# writer.add_image()
for i in range(100):
writer.add_scalar("y=x",i,i)
writer.close()
tensorboard --logdir=logs --port=6007,指定端口打开tensorboard 页面
tensorboard 页面如下:
绘制了一个y=x的函数
5、Transforms
from PIL import Image
from torchvision import transforms
image_path = "data/train/ants_image/6743948_2b8c096dda.jpg"
img = Image.open(image_path)
tensor_trans = transforms.ToTensor()
tensor_img = tensor_trans(img)
print(tensor_img)
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\Transforms.py tensor([[[0.6549, 0.5451, 0.5765, ..., 0.7451, 0.7451, 0.7647], [0.4078, 0.4471, 0.5373, ..., 0.8118, 0.8431, 0.8627], [0.3529, 0.5804, 0.7490, ..., 0.6824, 0.8314, 0.8824], ..., [0.5490, 0.5412, 0.4353, ..., 0.6510, 0.6706, 0.6275], [0.8824, 0.5020, 0.8353, ..., 0.6745, 0.6706, 0.5608], [0.6235, 0.3961, 0.7765, ..., 0.7765, 0.6784, 0.6196]], [[0.6235, 0.5020, 0.5294, ..., 0.6706, 0.6353, 0.6353], [0.3529, 0.3922, 0.4824, ..., 0.7451, 0.7608, 0.7569], [0.2863, 0.5098, 0.6863, ..., 0.6196, 0.7725, 0.8157], ..., [0.4824, 0.4667, 0.3529, ..., 0.5569, 0.5843, 0.5529], [0.8314, 0.4392, 0.7608, ..., 0.5843, 0.5882, 0.4863], [0.5922, 0.3490, 0.7059, ..., 0.6902, 0.5961, 0.5490]], [[0.5412, 0.4157, 0.4353, ..., 0.6118, 0.5804, 0.5686], [0.3529, 0.3804, 0.4471, ..., 0.6431, 0.6471, 0.6392], [0.3569, 0.5569, 0.6902, ..., 0.4784, 0.6118, 0.6431], ..., [0.4039, 0.4000, 0.2863, ..., 0.5098, 0.5294, 0.4941], [0.7569, 0.3765, 0.7059, ..., 0.5216, 0.5216, 0.4196], [0.5176, 0.2863, 0.6588, ..., 0.6078, 0.5137, 0.4627]]]) Process finished with exit code 0
6、torchvision中数据集的使用
import torchvision
from torch.utils.tensorboard import SummaryWriter
dataset_transform = torchvision.transforms.Compose([
torchvision.transforms.ToTensor()
])
train_set = torchvision.datasets.CIFAR10(root="./dataset", train=True, transform=dataset_transform, download=True)
test_set = torchvision.datasets.CIFAR10(root="./dataset", train=True, transform=dataset_transform, download=True)
# img, target = test_set[0]
# print(img)
# print(target)
# img.show()
writer = SummaryWriter("p10")
for i in range(10):
img,target = test_set[i]
writer.add_image("test_set", img, i)
writer.close()
[i]
二、模型搭建
7、nn.Module
Neural network简称nn,nn.Module为神经网络的基本骨架的搭建
import torch
from torch import nn
class Jzh(nn.Module):
# 初始化
def __int__(self):
super(Jzh, self).__int__()
# 功能函数
def forward(self, input):
output = input + 1
return output
jzh = Jzh()
x = torch.tensor(1.0)
output = jzh(x)
print(output)
7.1模型size
import torch
# 输入图像
input = torch.tensor([[1, 2, 0, 3, 1],
[0, 1, 2, 3, 1],
[1, 2, 1, 0, 0],
[5, 2, 3, 1, 1],
[2, 1, 0, 1, 1]])
# 卷积核
kernel = torch.tensor([[1, 2, 1],
[0, 1, 0],
[2, 1, 0]])
# 换一种数据的输入方式,这样打印出来的数据会有所不同
input = torch.reshape(input, (1, 1, 5, 5))
kernel = torch.reshape(kernel, (1, 1, 3, 3))
print(input.shape)
print(kernel.shape)
如下是不做torch.reshape()操作输出的数据尺寸:
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_conv.py
torch.Size([5, 5])
torch.Size([3, 3])Process finished with exit code 0
如下是经过orch.reshape()操作输出的数据尺寸:
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_conv.py
torch.Size([1, 1, 5, 5])
torch.Size([1, 1, 3, 3])Process finished with exit code 0
7.2模型conv
7.2.1卷积过程
import torch
import torch.nn.functional as F
# 输入图像
input = torch.tensor([[1, 2, 0, 3, 1],
[0, 1, 2, 3, 1],
[1, 2, 1, 0, 0],
[5, 2, 3, 1, 1],
[2, 1, 0, 1, 1]])
# 卷积核
kernel = torch.tensor([[1, 2, 1],
[0, 1, 0],
[2, 1, 0]])
# 换一种数据的输入方式,这样打印出来的数据会有所不同
input = torch.reshape(input, (1, 1, 5, 5))
kernel = torch.reshape(kernel, (1, 1, 3, 3))
print(input.shape)
print(kernel.shape)
output = F.conv2d(input, kernel, stride=1)
print(output)
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_conv.py
torch.Size([1, 1, 5, 5])
torch.Size([1, 1, 3, 3])
tensor([[[[10, 12, 12],
[18, 16, 16],
[13, 9, 3]]]])Process finished with exit code 0
若再补充如下代码:
output2 = F.conv2d(input, kernel, stride=1, padding=1)
print(output2)
则输出为:
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_conv.py
torch.Size([1, 1, 5, 5])
torch.Size([1, 1, 3, 3])
tensor([[[[10, 12, 12],
[18, 16, 16],
[13, 9, 3]]]])
tensor([[[[ 1, 3, 4, 10, 8],
[ 5, 10, 12, 12, 6],
[ 7, 18, 16, 16, 8],
[11, 13, 9, 3, 4],
[14, 13, 9, 7, 4]]]])Process finished with exit code 0
7.2.2卷积效果:
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10("./data_conv2d", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=64)
class Jzh(nn.Module):
def __init__(self):
super(Jzh, self).__init__()
# out_channels实际上就是卷积核的数量,有多少个卷积之后就输出几幅图像
self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
def forward(self, x):
x = self.conv1(x)
return x
jzh = Jzh()
print(jzh)
writer = SummaryWriter("./logs")
step = 0
for data in dataloader:
imgs, targets = data
output = jzh(imgs)
print(imgs.shape)
print(output.shape)
# 输入时的大小:torch.Size([64, 3, 32, 32])
writer.add_images("input", imgs, step)
# torch.Size([64, 6, 30, 30]) -> [xxx, 3, 30, 30]
# 3保证输出的仍是三维的数据与输入时一致,这样就能正常显示输出图像
output = torch.reshape(output, (-1, 3, 30, 30))
# 输出时的大小:
writer.add_images("output", output, step)
step = step + 1
writer.close()
[i]
7.3模型pooling
import torch
from torch import nn
from torch.nn import MaxPool2d
input = torch.tensor([[1, 2, 0, 3, 1],
[0, 1, 2, 3, 1],
[1, 2, 1, 0, 0],
[5, 2, 3, 1, 1],
[2, 1, 0, 1, 1]], dtype=torch.float32)
# -1表示自动计算batch_size;1表示一个channel;5、5表示5*5的输入图像
# batch size(批量大小)是一个超参数,它指的是在进行模型训练或评估时,每次迭代所使用的数据样本的数量。
input = torch.reshape(input, (-1, 1, 5, 5))
print(input.shape)
class Jzh(nn.Module):
def __init__(self):
super(Jzh, self).__init__()
# ceil_mode表示不足三列或者三行的按照三行然后去池中的最大值
self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
def forward(self, input):
output = self.maxpool1(input)
return output
jzh = Jzh()
output = jzh(input)
print(output)
经池化后输出为:
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_maxpool.py
torch.Size([1, 1, 5, 5])
tensor([[[[2., 3.],
[5., 1.]]]])Process finished with exit code 0
加载CIRF10数据集进行池化操作:
import torch
import torchvision
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10("./data_pool", train=False, download=True,
transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64)
# 用于创建一个数据加载器(DataLoader),它将数据集(dataset)分成大小为64的批次。
class Jzh(nn.Module):
def __init__(self):
super(Jzh, self).__init__()
# ceil_mode表示不足三列或者三行的按照三行然后去池中的最大值
self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
def forward(self, input):
output = self.maxpool1(input)
return output
jzh = Jzh()
writer = SummaryWriter("logs_maxpool")
step = 0
for data in dataloader:
imgs, targets = data
writer.add_images("input", imgs, step)
output = jzh(imgs)
writer.add_images("output", output, step)
step = step+1
writer.close()
[i]
7.4模型非线性激活
import torch
import torchvision
from torch import nn
from torch.nn import ReLU, Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
input = torch.tensor([[1, -0.5],
[-1, 3]])
input = torch.reshape(input, (-1, 1, 2, 2))
print(input.shape)
dataset = torchvision.datasets.CIFAR10("./data_pool", train=False, download=True,
transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64)
class Jzh(nn.Module):
def __init__(self):
super().__init__()
self.relu1 = ReLU()
self.sigmoid1 = Sigmoid()
def forward(self, input):
# 将输入的实数值映射到介于0和1之间的输出
output = self.sigmoid1(input)
return output
jzh=Jzh()
writer = SummaryWriter("logs_sigmoid1")
step = 0
for data in dataloader:
imgs, targets = data
writer.add_images("input", imgs, global_step=step)
output = jzh(imgs)
writer.add_images("output", output, step)
step = step+1
writer.close()
激活函数向图像引入非线性特征:
[i]
7.5模型全连接
import torch
import torchvision
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("./data_linear", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=64, drop_last=True)
class Jzh(nn.Module):
def __init__(self):
super().__init__()
# 将图片展平成torch.Size([1, 1, 1, 196608])格式
self.linear1 = Linear(196608, 10)
def forward(self, input):
output = self.linear1(input)
return output
jzh = Jzh()
for data in dataloader:
imgs, target = data
print(imgs.shape)
# output = torch.reshape(imgs, (1, 1, 1, -1))
# 上述代码可以由下一行代码替换,并直接输出成torch.Size([196608])
output =torch.flatten(imgs)
print(output.shape)
output = jzh(output)
print(output.shape)
三、搭建小实战
8、CIFAR10模型
Inputs -> 第一层Feature maps 层的计算可由如下公式得出:
[i]
计算过程为:
[ 32 + 2padding - 1(5-1) - 1 ] / stride + 1 = 32 , 得出padding=2,stride=1
对应代码为:self.conv1 = Conv2d(3, 32, 5, padding=2)
import torch
from torch import nn
from torch.nn import MaxPool2d, Flatten, Linear, Conv2d, Sequential
from torch.utils.tensorboard import SummaryWriter
class Jzh(nn.Module):
def __init__(self):
super().__init__()
# 第一种写法
# self.conv1 = Conv2d(3, 32, 5, padding=2)
# self.maxpool1 = MaxPool2d(2)
# self.conv2 = Conv2d(32, 32, 5, padding=2)
# self.maxpool2 = MaxPool2d(2)
# self.conv3 = Conv2d(32, 64, 5, padding=2)
# self.maxpool3 = MaxPool2d(2)
# self.flatten = Flatten()
# self.linear1 = Linear(1024, 64)
# self.linear2 = Linear(64, 10)
# 第二种写法
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
# 第一种写法
# x = self.conv1(x)
# x = self.maxpool1(x)
# x = self.conv2(x)
# x = self.maxpool2(x)
# x = self.conv3(x)
# x = self.maxpool3(x)
# x = self.flatten(x)
# x = self.linear1(x)
# x = self.linear2(x)
# 第二种写法
x = self.model1(x)
return x
jzh = Jzh()
print(jzh)
# torch.ones((64, 3, 32, 32))里的参数注意和Conv2d(32, 32, 5, padding=2)作区分,这里的64指batch_size
input = torch.ones((64, 3, 32, 32))
output = jzh(input)
# 检验输出结果是否为torch.Size([64, 10]),因为这是一个是分类的模型,若是则证明self.linear2 = Linear(64, 10)正常执行
print(output.shape)
writer = SummaryWriter("./logs_seq")
# jzh 是一个 PyTorch 模型,input 是输入数据,这个函数会将模型的计算图添加到 TensorBoard,以便在可视化时查看模型的结构
writer.add_graph(jzh, input)
writer.close()
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_CIFAR10.py
Jzh(
(model1): Sequential(
(0): Conv2d(3, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(4): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Flatten(start_dim=1, end_dim=-1)
(7): Linear(in_features=1024, out_features=64, bias=True)
(8): Linear(in_features=64, out_features=10, bias=True)
)
)
torch.Size([64, 10])Process finished with exit code 0
模型结构图:
[i]
9、Lose Function
9.1基本使用
LogSoftmax用于计算log-softmax激活。它的作用是将输入张量中的每个元素进行指数运算后归一化,然后取对数。这样可以将原始输出转换为概率分布,便于在分类任务中使用
计算公式如下:
注意,深度学习中的log默认是以e为底的即ln
import torch
from torch import nn
from torch.nn import L1Loss, MSELoss
inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)
inputs = torch.reshape(inputs, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))
loss = L1Loss()
# result=(0+0+2)/3
result = loss(inputs, targets)
loss_mse = MSELoss()
result_mse = loss_mse(inputs, targets)
print(result)
print(result_mse)
x = torch.tensor([0.1, 0.2, 0.3])
y = torch.tensor([1])
x = torch.reshape(x, (1, 3))
loss_cross = nn.CrossEntropyLoss()
result_cross = loss_cross(x, y)
print(result_cross)
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_loss.py
tensor(0.6667)
tensor(1.3333)
tensor(1.1019)Process finished with exit code 0
9.2实际作用
-
计算实际输出和目标之间的差距
import torch import torchvision from torch import nn from torch.nn import MaxPool2d, Flatten, Linear, Conv2d, Sequential from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter dataset = torchvision.datasets.CIFAR10("./data_linear", train=False, transform=torchvision.transforms.ToTensor(), download=True) dataloader = DataLoader(dataset, batch_size=1) class Jzh(nn.Module): def __init__(self): super().__init__() # 第二种写法 self.model1 = Sequential( Conv2d(3, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 32, 5, padding=2), MaxPool2d(2), Conv2d(32, 64, 5, padding=2), MaxPool2d(2), Flatten(), Linear(1024, 64), Linear(64, 10) ) def forward(self, x): # 第二种写法 x = self.model1(x) return x loss = nn.CrossEntropyLoss() jzh = Jzh() for data in dataloader: imgs, targets = data outputs = jzh(imgs) result_loss = loss(outputs, targets) print(result_loss)
部分输出结果:
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_loss_network.py
Files already downloaded and verified
tensor(2.3428, grad_fn=<NllLossBackward0>)
tensor(2.3684, grad_fn=<NllLossBackward0>)
tensor(2.3722, grad_fn=<NllLossBackward0>)
tensor(2.3924, grad_fn=<NllLossBackward0>)
tensor(2.3649, grad_fn=<NllLossBackward0>)
tensor(2.3878, grad_fn=<NllLossBackward0>)
tensor(2.1113, grad_fn=<NllLossBackward0>) -
为我们更新输出提供一定的依据:反向传播and优化器
主体部分不变,在上述代码中增加如下sgd优化器代码:
loss = nn.CrossEntropyLoss() jzh = Jzh() # lr为学习速率,一般模型训练开始时设置较大,模型训练后期设置较小 optim = torch.optim.SGD(jzh.parameters(), 0.01) for epoch in range(20): running_loss = 0.0 # 下面这个for仅代表循环一次 for data in dataloader: imgs, targets = data outputs = jzh(imgs) result_loss = loss(outputs, targets) # 清零梯度 optim.zero_grad() # 计算每个节点参数的梯度,方便后续用优化器对其优化 result_loss.backward() optim.step() # 这一轮整体误差总和 running_loss = running_loss + result_loss print(running_loss)
部分运行结果:
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\nn_optim.py
Files already downloaded and verified
tensor(18591.2637, grad_fn=<AddBackward0>)
tensor(16061.7539, grad_fn=<AddBackward0>)
tensor(15454.4775, grad_fn=<AddBackward0>)
tensor(15985.7441, grad_fn=<AddBackward0>)
tensor(18142.6211, grad_fn=<AddBackward0>)
tensor(20303.0449, grad_fn=<AddBackward0>)
tensor(22268.1523, grad_fn=<AddBackward0>)
tensor(23856.8047, grad_fn=<AddBackward0>)
tensor(25047.0723, grad_fn=<AddBackward0>)
四、现有网络模型的使用及修改
10、vgg16
import torchvision
from torchvision.models import VGG16_Weights
from torch import nn
# train_data = torchvision.datasets.ImageNet("./data_imagenet", split='train', download=True,
# transform=torchvision.transforms.ToTensor())
# vgg16_false = torchvision.models.vgg16(pretrained=False)
# 设置成true则下载的是一个已经预训练过的模型
# vgg16_true = torchvision.models.vgg16(pretrained=True)
# 下列语句为新版本模型加载代码,新版本默认没有预训练,如需预训练则需加上weights=VGG16_Weights.DEFAULT
vgg16_true = torchvision.models.vgg16(weights=VGG16_Weights.DEFAULT)
print(vgg16_true)
train_data = torchvision.datasets.CIFAR10("./dataset", train=True, transform=torchvision.transforms.ToTensor(),
download=True)
# 对模型进行修改,从1000分类修改成10分类
vgg16_true.classifier.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_true)
VGG1000分类和10分类输出对比:
VGG(
(features): Sequential(
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace=True)
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU(inplace=True)
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(6): ReLU(inplace=True)
(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): ReLU(inplace=True)
(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(13): ReLU(inplace=True)
(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): ReLU(inplace=True)
(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(18): ReLU(inplace=True)
(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): ReLU(inplace=True)
(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(22): ReLU(inplace=True)
(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(25): ReLU(inplace=True)
(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(27): ReLU(inplace=True)
(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(29): ReLU(inplace=True)
(30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
(classifier): Sequential(
(0): Linear(in_features=25088, out_features=4096, bias=True)
(1): ReLU(inplace=True)
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU(inplace=True)
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=1000, bias=True)
)
)
改成10分类则在(6): Linear(in_features=4096, out_features=1000, bias=True)之后多添加了一层线性层:
(add_linear): Linear(in_features=1000, out_features=10, bias=True)
10.1模型的保存与读取
model_save
import torch
import torchvision
from torch import nn
vgg16 = torchvision.models.vgg16(weights=None)
# 第一种保存方式,模型结构+模型参数
torch.save(vgg16, "vgg16_method1.pth")
# 第二种保存方式,模型参数(保存成字典形式),官方推荐,但这样输出的就不再是一个网络模型了,需要使用还要进行相关操作
torch.save(vgg16.state_dict(), "vgg16_method2.pth")
# 方式一有陷阱(如果自己搭建模型的话)
class Jzh(nn.Module):
def __init__(self):
super(Jzh, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
def forward(self, x):
x = self.conv1(x)
return x
jzh = Jzh()
torch.save(jzh, "jzh_method1.pth")
model_load
import torch
import torchvision
from model_save import *
from torch import nn
# 对应方式1,加载模型
model = torch.load("vgg16_method1.pth")
# print(model)
# 对应方式2,加载模型
vgg16 = torchvision.models.vgg16(weights=None)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
# model = torch.load("vgg16_method2.pth")
print(vgg16)
# 方式一陷阱,自己创建的模型需要在这里定义一下,但是from model_save import *下面代码就可以不要了,
# model_save文件定义过了,直接加载模型打印
# class Jzh(nn.Module):
# def __init__(self):
# super(Jzh, self).__init__()
# self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
#
# def forward(self, x):
# x = self.conv1(x)
# return x
model = torch.load('jzh_method1.pth')
print(model)
五、完整的模型训练套路
11、模型训练
11.1train
import torch
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from model import *
# 准备数据集
train_data = torchvision.datasets.CIFAR10(root="./data_taolu", train=True, transform=torchvision.transforms.ToTensor(),
download=True)
test_data = torchvision.datasets.CIFAR10(root="./data_taolu", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
train_data_size = len(train_data)
test_data_size = len(test_data)
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)
# 创建网络模型
jzh = Jzh()
# 创建损失函数
loss_fn = nn.CrossEntropyLoss()
# 优化器
# learning_rate = 0.01
# 1e-2=1 x (10)^(-2) = 1/100 = 0.01
learning_rate = 1e-2
optimizer = torch.optim.SGD(jzh.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))
# 训练步骤开始
jzh.train()
for data in train_dataloader:
imgs, targets = data
outputs = jzh(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)
# 测试步骤开始
jzh.eval()
total_test_loss = 0
total_accuracy = 0
with torch.no_grad():
for data in test_dataloader:
imgs, targets = data
outputs = jzh(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(jzh, "jzh_{}.pth".format(i))
print("模型已保存")
writer.close()
11.2model
import torch
from torch import nn
# 搭建神经网络
class Jzh(nn.Module):
def __init__(self):
super(Jzh, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 32, 5, 1, padding=2),
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, 1, padding=2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, padding=2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.model(x)
return x
if __name__ == '__main__':
jzh = Jzh()
input = torch.ones((64, 3, 32, 32))
output = jzh(input)
print(output.shape)
部分输出结果:
训练数据集的长度为:50000
测试数据集的长度为:10000
------第 1 轮训练开始------
训练次数: 100, loss: 2.2846009731292725
训练次数: 200, loss: 2.2844748497009277
训练次数: 300, loss: 2.2514917850494385
训练次数: 400, loss: 2.148555278778076
训练次数: 500, loss: 2.1040234565734863
训练次数: 600, loss: 2.033297061920166
训练次数: 700, loss: 1.9678012132644653
整体测试集上的loss: 320.23996794223785
整体测试集上的正确率: 0.26930001378059387
模型已保存
------第 2 轮训练开始------
训练次数: 800, loss: 1.8451868295669556
训练次数: 900, loss: 1.8664506673812866
训练次数: 1000, loss: 1.905165433883667
训练次数: 1100, loss: 1.979297161102295
训练次数: 1200, loss: 1.6892757415771484
训练次数: 1300, loss: 1.655542254447937
训练次数: 1400, loss: 1.725655436515808
训练次数: 1500, loss: 1.8056442737579346
整体测试集上的loss: 287.658221244812
整体测试集上的正确率: 0.3418999910354614
模型已保存
模型tensorboard图:
[i]
[i]
[i]
总结来说,完整的模型训练套路为:准备数据,加载数据,准备模型,设置损失函数,设置优化器,开始训练,最后验证,结果聚合展示
12、模型测试
12.1test
import torch
import torchvision
from PIL import Image
from torch import nn
image_path = "./imgs/airplan.png"
image = Image.open(image_path)
# 保留颜色通道,加上这一步后可以适应png、jpg各种格式图片
# image = image.convert('RGB')
print(image)
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)),
torchvision.transforms.ToTensor()])
image = transform(image)
print(image.shape)
class Jzh(nn.Module):
def __init__(self):
super(Jzh, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 32, 5, 1, padding=2),
nn.MaxPool2d(2),
nn.Conv2d(32, 32, 5, 1, padding=2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, padding=2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.model(x)
return x
model = torch.load("./jzh_9.pth")
# 若使用GPU训练的模型,一定要使用下述语句将其映射到CPU上
# model = torch.load("jzh_gpu.pth" ,map_location=torch.device('cpu'))
print(model)
# 数据要和模型一致
image = torch.reshape(image, (1, 3, 32, 32))
model.eval()
with torch.no_grad():
output = model(image)
print(output)
如图为CIFAR10数据集对应的物体类别:
[i]
如下为预测结果:
D:\software\anaconda\Ana\envs\pycyy\python.exe D:\code\Python\pycyy\test.py
<PIL.PngImagePlugin.PngImageFile image mode=RGB size=295x183 at 0x21FE599AC08>
torch.Size([3, 32, 32])
Jzh(
(model): Sequential(
(0): Conv2d(3, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(4): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Flatten(start_dim=1, end_dim=-1)
(7): Linear(in_features=1024, out_features=64, bias=True)
(8): Linear(in_features=64, out_features=10, bias=True)
)
)
tensor([[10.5353, 1.8883, 1.5429, -2.5516, 0.0149, -4.7008, -5.5488, -5.0510,
3.8907, -1.5681]])
tensor([0])Process finished with exit code 0
其中airplan对应类别下标为00,其预测概率最大,模型预测正确
后续将继续学习github上优秀的开源项目,加油!!!
Author:####Jzh##