import torch.nn as nn
import torch.nn.functional as F
import torch
class LeNet(nn.Module): # 首先定义一个类 这个类要继承于nn.Module
def __init__(self): # 定义初始化函数 # 在这个类中实现两个方法 一 初始化函数 在搭建网络过程中所需要使用到的网络层结构
super(LeNet, self).__init__() # super函数 在定义这个类的过程中 继承了nn.module super函数解决在多重继承中调用父类可能会出现的问题
self.conv1 = nn.Conv2d(3, 16, 5) # (in_channels输入通道数, out_channels也是卷积核数量, kernel_size卷积核尺寸 # 定义第一个卷积层 就是用nn.Conv2d 内部定义方法
self.pool1 = nn.MaxPool2d(2, 2) # (kernel_size池化核大小,stride or kernel_size 如果不指定就是池化核大小)
self.conv2 = nn.Conv2d(16, 32, 5) #
self.pool2 = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(32 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x): # 定义正向传播过程 实例化这个类之后 将参数传递到这个实例中 就会进行正向传播
x = F.relu(self.conv1(x)) # input(3 x 32 x 32) #output(16 x(32 - 5 + 0x2)/1+1 x 28 )
x = self.pool1(x) # output (16 x 14 x 14)
x = F.relu(self.conv2(x)) # input(16 x 14 x 14) output(32 x 10 x 10)
x = self.pool2(x) # output(32 x 5 x 5)
x = x.view(-1, 32 * 5 * 5) # 展成一维向量 -1为自动填充
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
input1 = torch.rand([32, 3, 32, 32])
model = LeNet()
print(model)
output = model(input1)
model
train
import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
# transform.Compose 将预处理方法打包成一个整体 1.ToTensor 将pil图像或者np数据转化成tensor 2.normalize 使用均值和标准差 来标准化tensor
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
)
# root='./' 把数据集下载到什么地方 一般放在当前目录的data文件夹下 train=True 会导入数据集中训练集 transform为图像预处理
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=36, shuffle=True, num_workers=0)
# 将刚才的数据集导入 batch_size 每一批随机拿出36张拿来训练 shuffle打乱 num_workers=0 不用多线程
# 导入10000张测试图片
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=10000, shuffle=False, num_workers=0)
test_data_iter = iter(testloader) # iter 将testloader转化成可迭代的迭代器
test_image, test_label = test_data_iter.next() # 通过next方法 获取一批数据包括测试的图像 以及图像的标签值 这个非常好用!
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 元组类型 值是不能带变的 对应的标签 index0 就是plane
# def imshow(img):
# img = img / 2 + 0.5 # unnormalize 刚才标准化现在还原
# npimg = img.numpy() # 转化成numpy格式
# plt.imshow(np.transpose(npimg, (1, 2, 0))) # 刚才是channel height width 现在要变为 height width channel 所以从(0 1 2) 改成(1 2 0)
# plt.show() # 用show展示出来
#
# print(' '.join('%5s' % classes[test_label[j]] for j in range(4))) # print labels
# imshow(torchvision.utils.make_grid(test_image)) # show images
net = LeNet()
loss_function = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001) # net.parameters()所需要训练的参数
for epoch in range(5): # 训练集需要训练多少次
running_loss = 0.0 # 累加loss
for step, data in enumerate(trainloader, start=0): # 遍历训练集样本 enumerate 不仅能返回每一批的数据data 还会返回这一批data所对应的步数 也就是index
# gat the inputs, data is a list of [inputs, labels]
inputs, labels = data # 将inputs(输入的图像) labels(标签) 分离出来
optimizer.zero_grad() # 将历史的梯度清零 可以一次性计算多个小的batch
outputs = net(inputs)
loss = loss_function(outputs, labels) # 计算损失
loss.backward() # 反向传播
optimizer.step() # 参数更新 也是权重更新
running_loss += loss.item() # 每次计算完loss 累加到running_loss变量中
if step % 500 == 499: # print every 500 mini_batch
with torch.no_grad(): # torch.no_grad 在接下来过程中 不要计算每个节点的误差损失梯度 少占用内存或者资源
outputs = net(test_image) # 正向传播 # 这里的[1] 代表我们只需要他的index(索引) 只需要知道在哪个地方
predict_y = torch.max(outputs, dim=1)[1] #toech.max 寻找输出的最大的index在哪个位置 网络预测最可能属于哪个类别
# dim = 1 在维度1 上寻找最大的值 [batch, 10] 因为第0个维度对应的是batch 要在输出的十个节点中寻找
accuracy = (predict_y == test_label).sum().item() / test_label.size(0) # 计算出来的是个tensor 要通过item得出数值
# 将预测的标签类别和真实的标签类别进行比较 再求和 在本次测试中预测对了多少个样本
print('[%d, %5d] train_loss: %.3f test_accuracy: %.3f' %
(epoch + 1, step + 1, running_loss / 500, accuracy)) # step 在每一轮中的多少步
running_loss = 0.0 # 将running_loss 清零 进行下一个500步的训练 并计算loss
print('Finished Training')
save_path = './Lenet.pth' # 将模型保存
torch.save(net.state_dict(), save_path)
predict
import torch
import torchvision.transforms as transforms
from PIL import Image
from model import LeNet
transform = transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
net = LeNet()
net.load_state_dict(torch.load('Lenet.pth')) # load_state_dict载入保存的权重文件
im = Image.open('5.jpg') # pillow 载入图像
im = transform(im) # C H W 转化成N C H W
im = torch.unsqueeze(im, dim=0) # unsqueeze 在 0 前面再加上一个维度
with torch.no_grad():
outputs = net(im)
predict = torch.max(outputs, dim=1)[1].data.numpy() # 将index传入classes
print(classes[int(predict)])
完结