一、神经网络骨架:
import torch
from torch import nn
#神经网络
class CLH(nn.Module):
def __init__(self):
super().__init__()
def forward(self, input):
output=input+1
return output
clh = CLH()
x = torch.tensor(1.0)
output = clh(x)
print(output)
二、卷积操作:
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]
])
#变化为卷积规定输入格式的维度:这里二维(x,y)转四维(t,z,x,y)
input = torch.reshape(input,(1,1,5,5))
kernel = torch.reshape(kernel,(1,1,3,3))
#对输入矩阵的上下左右进行分别padding扩充1列0,执行一次stride步长为1的卷积
output = F.conv2d(input, kernel, stride=1, padding=1)
print(output)
运行结果:
执行过程:
三、卷积层:
卷积在神经网络中用于提取输入数据的特征,通过与卷积核进行卷积操作来实现特征的提取和学习。
import torchvision
from torch import nn
from torch.utils.data import DataLoader
import torch.nn.functional as F
test_data = torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=False)
#将数据划分为batch,每个batch有64个样本
dataloader = DataLoader(test_data,batch_size=64)
#神经网络
class CLH(nn.Module):
def __init__(self):
super(CLH,self).__init__()
#神经网络中设置一个卷积层,in_channels表示输入通道数,out_channels表示输出通道数,并且卷积核尺寸为3×3的随机矩阵
self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
def forward(self,input):
#对输入数据执行一次二维卷积
return self.conv1(input)
clh = CLH()
#data是一个batch
for data in dataloader:
imgs,targets = data
output = clh(imgs)
#torch.Size([64, 3, 32, 32])表示[batchs大小,每个batch的通道数,每个通道x轴像素数,每个通道y轴像素数]
print(imgs.shape)
#torch.Size([64, 6, 30, 30])表示[batchs大小,每个batch的通道数,每个通道x轴像素数,每个通道y轴像素数]
#其中每个通道由32×32像素变为30×30像素,其余的像素点组合成该batch的其他通道
print(output.shape)
四、池化层:
最大池化的作用是为了保留特征同时将数据量缩小。
例如:1080p图像经过最大池化层变为720p。
import torch
from torch import nn
from torch.nn import MaxPool2d
#输入像素变为tensor类型
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)
#变化为池化规定输入格式的维度:这里二维(x,y)转四维(t,z,x,y)
input = torch.reshape(input,(1,1,5,5))
#神经网络
class CLH(nn.Module):
def __init__(self):
super(CLH,self).__init__()
#神经网络中设置一个池化层,ceil_mode表示池化合覆盖输入数据不够时是否计算
self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
def forward(self,input):
#对输入数据执行一次最大池化操作
return self.maxpool1(input)
#创建神经网络
clh = CLH()
output = clh(input)
print(output)
运行结果:
执行过程:
五、激活函数(以ReLU为例):
import torch
from torch import nn
from torch.nn import MaxPool2d, ReLU
#输入像素变为tensor类型
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)
#变化为池化规定输入格式的维度:这里二维(x,y)转四维(t,z,x,y)
input = torch.reshape(input,(1,1,5,5))
#神经网络
class CLH(nn.Module):
def __init__(self):
super(CLH,self).__init__()
#神经网络中设置一个激活函数
self.relu = ReLU()
def forward(self,input):
#对输入数据执行一次最大池化操作
return self.relu(input)
#创建神经网络
clh = CLH()
output = clh(input)
print(output)
运行结果:
六、模型搭建:
上面的卷积神经网络模型共有8个隐藏层(卷积层+池化层)和1个输出层。
from torch import nn
from torch.nn import Module
from torch.nn import Conv2d
from torch.nn import MaxPool2d, Flatten, Linear, Sequential
import torch
# 神经网络
class CLH(nn.Module):
def __init__(self):
super(CLH, self).__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(),
#全连接(线性)层,输入1024长度的一维向量,学习输入数据的非线性关系,输出64的特征一维向量
Linear(1024, 64),
)
def forward(self, x):
x = self.model1(x)
return x
clh = CLH()
print(clh)
#构建一个全0的输入,batch大小64,三通道,宽高为32×32
input = torch.ones((64, 3, 32, 32))
output = clh(input)
print(output.shape)
输出结果:
七、损失函数、梯度下降:
from torch import nn
from torch.nn import Conv2d
from torch.nn import MaxPool2d,Flatten,Linear, Sequential
import torch
import torchvision
from torch.utils.data import DataLoader
#获取数据,CIFAR10是一个十分类数据集
dataset = torchvision.datasets.CIFAR10("./dataset",train= False, transform =torchvision.transforms.ToTensor(), download=False)
#切分数据为batch
dataloader = DataLoader(dataset, batch_size=1, drop_last=True)
#神经网络模型搭建
class Tudui(nn.Module):
def __init__(self):
super(Tudui,self).__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
tudui = Tudui()
#损失函数
loss = nn.CrossEntropyLoss()
#SGD(随机梯度下降)优化器,用于更新模型clh中的参数以最小化损失函数
optim = torch.optim.SGD(tudui.parameters(), lr=0.01)
#每个batch(data)执行如下操作
for data in dataloader:
#特征和真实标签值
imgs, targets = data
#训练结果
outputs = tudui(imgs)
#计算损失
result_loss = loss(outputs, targets)
#每轮训练梯度清零,避免梯度累积
optim.zero_grad()
#反向传播计算损失函数关于模型各个参数的梯度(偏导数)
result_loss.backward()
#根据梯度更新模型参数,使用梯度下降算法进行参数更新
optim.step()
print(result_loss)
运行结果:
八、模型保存与加载:
保存:
import torchvision
import torch
vgg16 = torchvision.models.vgg16(pretrained=False)
# 保存方式1--保存模型结构及模型参数
torch.save(vgg16,"vgg16_method1.pth")
# 保存方式2--仅保存模型参数存为字典,不保存模型结构(官方推荐)
torch.save(vgg16.state_dict(),"vgg16_method2.pth")
读取:
import torch
import torchvision
# 保存方式1对应的加载模型结构 + 参数方式
model = torch.load("vgg16_method1.pth")
print(model)
# 保存方式2对应的加载模型参数方式
model2 = torch.load("vgg16_method2.pth") #加载的是字典
print(model2)
vgg16 = torchvision.models.vgg16(pretrained=False) #为方式2创建模型结构并加载参数的完整写法
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16)
九、模型训练:
上面的卷积神经网络模型共有8个隐藏层(卷积层+池化层)和1个输出层。
from torch.utils.tensorboard import SummaryWriter
import torch
import torchvision
import torch.nn as nn
from torch.utils.data import DataLoader
# 定义训练的设备
device = torch.device("cuda")
# 准备训练集
train_data = torchvision.datasets.CIFAR10("./dataset", train=True, transform=torchvision.transforms.ToTensor(),
download=True)
# 准备测试集
test_data = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
# len()获取数据集长度
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度为:{}".format(train_data_size))
print("测试数据集的长度为:{}".format(test_data_size))
# 利用dataloader加载数据集,一个batch包含64个图片样本
train_dataloader = DataLoader(train_data, batch_size=64, drop_last=True)
test_dataloader = DataLoader(test_data, batch_size=64, drop_last=True)
# 创建网络模型,这里一般将网络模型单独定义一个文件
class CLH(nn.Module):
def __init__(self):
super(CLH, 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(), # 展平后的序列长度为 64*4*4=1024
#全连接层
nn.Linear(1024, 64),
nn.Linear(64, 10)
)
def forward(self, x):
x = self.model(x)
return x
clh = CLH()
#设置为GPU训练
clh = clh.to(device)
# 损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
# 优化器(梯度下降算法)对clh.parameters()中的参数进行更新
learning_rate = 1e-2
optimizer = torch.optim.SGD(clh.parameters(), lr=learning_rate)
# 设置训练网络的一些参数
# 1.记录训练的次数
total_train_step = 0
# 2.记录测试的次数
total_test_step = 0
# 3.训练的轮数
epoch = 10
# 添加tensorboard可视化结果
writer = SummaryWriter("../logs_train")
#训练epoch轮
for i in range(epoch):
print("-------------第 {} 轮训练开始------------".format(i + 1))
# 训练步骤开始
clh.train()
#对于每个batch(data,包含64张图片)
for data in train_dataloader:
#获取batch中的样本和真实值标签
imgs, targets = data
imgs = imgs.to(device)
targets = targets.to(device)
#该batch的训练结果
output = clh(imgs)
#计算该batch(data)上的损失
loss = loss_fn(output, targets)
# 优化器优化模型
#梯度清零
optimizer.zero_grad()
#计算损失函数关于每个参数的梯度
loss.backward()
#梯度下降算法更新参数
optimizer.step()
total_train_step = total_train_step + 1
print("训练次数:{}, Loss:{}".format(total_train_step, loss.item()))
writer.add_scalar("train_loss", loss.item(), total_train_step)
# 测试步骤开始(感觉更像验证,但是并没有更新一些学习率之类的参数,仅仅进行了测试)
clh.eval()
total_test_loss = 0
total_accuracy = 0
#设置禁止更新梯度,防止测试集更新模型参数
with torch.no_grad():
#对于测试集上的每个batch(data,包含64张图片)
for data in test_dataloader:
imgs, targets = data
imgs = imgs.to(device)
targets = targets.to(device)
#仅计算预测结果而不更新参数(torch.no_grad())
outputs = clh(imgs)
#计算该batch(data)上的损失
loss = loss_fn(outputs, targets)
#计算整个测试集上的损失
total_test_loss = total_test_loss + loss.item()
print("整个测试集上的Loss:{}".format(total_test_loss))
writer.add_scalar("test_loss", total_test_loss, total_test_step)
total_test_step = total_test_step + 1
#每轮(epoch)训练完成后保存该轮的训练模型
torch.save(clh, "clh_{}.pth".format(i))
print("-------------第{}轮训练结束,模型已保存-------------".format(i + 1))
writer.close()
部分执行结果:
十、模型测试:
import torchvision
from PIL import Image
import torch
#注意导入模型结构文件
from CLHmodule import *
#获取测试样本
image_path = "./dog.png"
image = Image.open(image_path)
print(image)
#将测试样本转换为模型规定的格式(和训练集样本尺寸要一样)
image = image.convert('RGB')
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
torchvision.transforms.ToTensor()
])
image = transform(image)
print(image)
image = torch.reshape(image,(1,3,32,32))
#加载模型
model = torch.load("clh_0.pth",map_location=torch.device("cuda"))
print(model)
#执行预测
model.eval()
with torch.no_grad():
image = image.to("cuda")
output = model(image)
#预测结果,十分类结果为10个值的一维向量,表示各个分类上的可能性
print(output)
#输出可能性最大的结果
print(output.argmax(1))
输出结果: