神经网络
构建神经网络的一般步骤如下:
- 确定网络的结构:这包括输入层、输出层和隐藏层的数量以及每层中的节点数等。
- 收集和准备数据:这包括收集训练数据、清洗数据、转换数据格式等。
- 初始化权重:权重是神经元之间的连接强度,需要在训练前随机初始化。
- 前向传播计算:根据输入数据和权重计算输出结果。
- 计算损失函数:损失函数衡量预测输出和真实输出之间的误差。
- 反向传播计算:反向传播是一种优化算法,用于调整权重以最小化损失函数。
- 更新权重:根据反向传播算法计算出的梯度更新权重,以优化模型。
- 重复以上步骤:反复执行前向传播和反向传播,调整权重,直到损失函数收敛。
- 测试和评估模型:使用测试数据集对模型进行评估和测试。
- 使用模型进行预测:使用已训练的模型对新数据进行预测。
1.继承Module构建神经网络
构建神经网络
import torch import torch.nn as nn from torch import optim from torchvision import datasets, transforms from torch.nn.functional import conv2d, cross_entropy class SimpleCNN(nn.Module): def __init__(self, in_channel=1): super(SimpleCNN, self).__init__() self.conv1 = nn.Conv2d(in_channel, 4, 5, 2, 0) self.relu1 = nn.ReLU() self.conv2 = nn.Conv2d(4, 8, 3, 2, 0) self.relu2 = nn.ReLU() self.linear = nn.Linear(200, 10) def forward(self, x): x = self.conv1(x) x = self.relu1(x) x = self.conv2(x) x = self.relu2(x) x = x.view(-1, 200) x = self.linear(x) return x
这个程序定义了一个简单的CNN模型 SimpleCNN
,用于进行图像分类任务。它包含以下几个部分:
- 导入所需的 PyTorch 模块。这些模块是
torch
、nn
、optim
、datasets
、transforms
和nn.functional
。
- 定义了一个名为
SimpleCNN
的类,继承了nn.Module
。
在 __init__
函数中定义模型的结构。这个模型包含两层卷积层和一个全连接层:
- 第1层卷积层:输入通道数为
in_channel
,输出通道数为 4,卷积核大小为 5x5,步长为 2,填充为 0。 - 第1个ReLU激活函数:将卷积层的输出进行非线性变换。
- 第2层卷积层:输入通道数为 4,输出通道数为 8,卷积核大小为 3x3,步长为 2,填充为 0。
- 第2个ReLU激活函数:再次对卷积层的输出进行非线性变换。
- 平铺层:将卷积层的输出展成一维向量。
- 全连接层:输入大小为 200,输出大小为 10,用于输出分类结果。
- 在
forward
函数中实现模型的前向传播过程。将输入x
依次经过卷积层、ReLU激活函数、卷积层、ReLU激活函数和全连接层处理,最终输出分类结果。
#测试 model = SimpleCNN() data = torch.randn(3, 1, 28, 28) output = model(data) output.shape
torch.Size([3, 10])
卷积层计算
(28-5)/2+1=12
(12-3)/2+1=5
3×1×28×28
3×4×12×12
3×8×5×5
3×200
3×10
神经网络模型
model
SimpleCNN( (conv1): Conv2d(1, 4, kernel_size=(5, 5), stride=(2, 2)) (relu1): ReLU() (conv2): Conv2d(4, 8, kernel_size=(3, 3), stride=(2, 2)) (relu2): ReLU() (linear): Linear(in_features=200, out_features=10, bias=True) )
for key, value in model._modules.items(): print(key, value)
conv1 Conv2d(1, 4, kernel_size=(5, 5), stride=(2, 2)) relu1 ReLU() conv2 Conv2d(4, 8, kernel_size=(3, 3), stride=(2, 2)) relu2 ReLU() linear Linear(in_features=200, out_features=10, bias=True)
model = SimpleCNN() model.parameters() for p in model.parameters(): print(p.shape)
torch.Size([4, 1, 5, 5]) torch.Size([4]) torch.Size([8, 4, 3, 3]) torch.Size([8]) torch.Size([10, 200]) torch.Size([10])
导入数据集
train_batch_size = 100 #一共60000个数据,100个数据一组,一共600组(N=100) test_batch_size = 100 #一共10000个数据,100个数据一组,一共100组(N=100) # 训练集 train_loader = torch.utils.data.DataLoader( datasets.MNIST( './data',train=True,download=True, transform=transforms.Compose([ transforms.ToTensor(), #转为tensor transforms.Normalize((0.5),(0.5)) #正则化 ]) ), batch_size = train_batch_size, shuffle=True #打乱位置 ) # 测试集 test_loader = torch.utils.data.DataLoader( datasets.MNIST( './data',train=False,download=True, transform=transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5),(0.5)) ]) ), batch_size = test_batch_size, shuffle=False )
这段代码主要用于加载 MNIST 数据集,并生成对应的数据加载器 train_loader
和 test_loader
。具体包含以下几个步骤:
- 定义训练集的批次大小
train_batch_size
,设为 100。 - 定义测试集的批次大小
test_batch_size
,也设为 100。 - 调用
torch.utils.data.DataLoader
函数生成训练集加载器train_loader
,加载器将使用datasets.MNIST
函数加载 MNIST 数据集,并进行以下操作:
- 设置 MNIST 数据集的路径为
./data
。 - 将数据集设置为训练集,下载数据集。
- 对数据进行
transforms.Compose
序列变换操作,包括:
transforms.ToTensor()
:将数据转为 Tensor 类型。
transforms.Normalize((0.5),(0.5))
:将数据进行正则化。
- 将训练集数据划分为大小为
train_batch_size
的批次,进行随机打乱。
- 调用
torch.utils.data.DataLoader
函数生成测试集加载器test_loader
,加载器将使用datasets.MNIST
函数加载 MNIST 数据集,并进行相同的处理流程,但测试集不需要随机打乱。
这样生成的 train_loader
和 test_loader
可以用于对数据进行批量加载,方便后续的模型训练和评估。
训练测试
alpha = 0.1 #学习率 epochs = 100 #训练次数 interval = 100 #打印间隔 for epoch in range(epochs): optimizer = optim.SGD(model.parameters(), lr=0.1) for i, (data, label) in enumerate(train_loader): output = model(data) optimizer.zero_grad() #梯度归零 loss = cross_entropy(output, label) #交叉熵函数 loss.backward() #反向求导 optimizer.step() #更新参数 if i % interval == 0: print("Epoch %03d [%03d/%03d]\tLoss:%.4f"%(epoch, i, len(train_loader), loss.item())) correct_num = 0 total_num = 0 with torch.no_grad(): for data, label in test_loader: output = model(data) pred = output.max(1)[1] correct_num += (pred == label).sum().item() total_num += len(data) acc = correct_num / total_num print('...Testing @ Epoch %03d\tAcc:%.4f'%(epoch, acc))
Epoch 000 [000/600] Loss:2.2848 Epoch 000 [100/600] Loss:0.4144 Epoch 000 [200/600] Loss:0.2014 Epoch 000 [300/600] Loss:0.2790 Epoch 000 [400/600] Loss:0.1858 Epoch 000 [500/600] Loss:0.1649 ...Testing @ Epoch 000 Acc:0.9538 Epoch 001 [000/600] Loss:0.1593 Epoch 001 [100/600] Loss:0.2436 Epoch 001 [200/600] Loss:0.0649 Epoch 001 [300/600] Loss:0.2830 Epoch 001 [400/600] Loss:0.1208 Epoch 001 [500/600] Loss:0.0937 ...Testing @ Epoch 001 Acc:0.9678 Epoch 002 [000/600] Loss:0.1210 Epoch 002 [100/600] Loss:0.0737 Epoch 002 [200/600] Loss:0.0857 Epoch 002 [300/600] Loss:0.0712 Epoch 002 [400/600] Loss:0.2700 Epoch 002 [500/600] Loss:0.0849 ...Testing @ Epoch 002 Acc:0.9708 Epoch 003 [000/600] Loss:0.1094 Epoch 003 [100/600] Loss:0.0727 Epoch 003 [200/600] Loss:0.1756 Epoch 003 [300/600] Loss:0.1473 Epoch 003 [400/600] Loss:0.1013 Epoch 003 [500/600] Loss:0.0879 ...Testing @ Epoch 003 Acc:0.9741 Epoch 004 [000/600] Loss:0.1503 Epoch 004 [100/600] Loss:0.0832 Epoch 004 [200/600] Loss:0.0731 Epoch 004 [300/600] Loss:0.1040 Epoch 004 [400/600] Loss:0.0720 Epoch 004 [500/600] Loss:0.0490 ...Testing @ Epoch 004 Acc:0.9745 Epoch 005 [000/600] Loss:0.0720 Epoch 005 [100/600] Loss:0.1124 Epoch 005 [200/600] Loss:0.0674 Epoch 005 [300/600] Loss:0.0477 Epoch 005 [400/600] Loss:0.1164 Epoch 005 [500/600] Loss:0.0662 ...Testing @ Epoch 005 Acc:0.9758 Epoch 006 [000/600] Loss:0.0445 Epoch 006 [100/600] Loss:0.0500 Epoch 006 [200/600] Loss:0.0236 Epoch 006 [300/600] Loss:0.1068 Epoch 006 [400/600] Loss:0.0767 Epoch 006 [500/600] Loss:0.0549 ...Testing @ Epoch 006 Acc:0.9800 Epoch 007 [000/600] Loss:0.0539 Epoch 007 [100/600] Loss:0.0319 Epoch 007 [200/600] Loss:0.1369 Epoch 007 [300/600] Loss:0.0301 Epoch 007 [400/600] Loss:0.0881 Epoch 007 [500/600] Loss:0.0642 ...Testing @ Epoch 007 Acc:0.9792 Epoch 008 [000/600] Loss:0.0564 Epoch 008 [100/600] Loss:0.0845 Epoch 008 [200/600] Loss:0.1877 Epoch 008 [300/600] Loss:0.0963 Epoch 008 [400/600] Loss:0.0671 Epoch 008 [500/600] Loss:0.1053 ...Testing @ Epoch 008 Acc:0.9757 Epoch 009 [000/600] Loss:0.0117 Epoch 009 [100/600] Loss:0.0201 Epoch 009 [200/600] Loss:0.1933 Epoch 009 [300/600] Loss:0.0726 Epoch 009 [400/600] Loss:0.0449 Epoch 009 [500/600] Loss:0.1415 ...Testing @ Epoch 009 Acc:0.9807 Epoch 010 [000/600] Loss:0.0505 Epoch 010 [100/600] Loss:0.0410 Epoch 010 [200/600] Loss:0.0325 Epoch 010 [300/600] Loss:0.0403 Epoch 010 [400/600] Loss:0.0249 Epoch 010 [500/600] Loss:0.0682 ...Testing @ Epoch 010 Acc:0.9805 Epoch 011 [000/600] Loss:0.0816 Epoch 011 [100/600] Loss:0.1179 Epoch 011 [200/600] Loss:0.1244 Epoch 011 [300/600] Loss:0.0465 Epoch 011 [400/600] Loss:0.1324 Epoch 011 [500/600] Loss:0.0763 ...Testing @ Epoch 011 Acc:0.9799 ……
这段代码实现了简单 CNN 模型的训练和测试,具体实现步骤如下:
- 定义学习率
alpha
,设为 0.1。 - 定义训练次数
epochs
,设为 100。 - 定义打印间隔
interval
,设为 100。 - 使用
range
函数循环epochs
次,进行模型训练和测试。 - 在每个 epoch 循环中,定义优化器
optimizer
,使用随机梯度下降法(SGD)优化器,对模型参数进行更新。 - 循环训练数据加载器
train_loader
中的数据,对数据进行前向传播,计算损失函数(交叉熵函数),通过反向传播求解梯度,并通过优化器对模型参数进行更新。 - 在每个间隔
interval
打印一次训练进度,输出当前训练的 epoch、批次、总批次数和当前损失函数值,以及测试集的准确率。 - 在每个 epoch 循环的末尾,使用
torch.no_grad()
防止梯度更新,在测试集加载器test_loader
中进行数据的前向传播,计算模型的预测值和真实值,计算模型的准确率并输出。
这样就完成了模型的训练和测试,通过输出可以了解模型的训练进度和测试效果。
2.结构化构建神经网络
构建神经网络
Model = nn.Sequential( nn.Conv2d(1, 4, 5, 2, 0), nn.ReLU(), nn.Conv2d(4, 8, 3, 2, 0), nn.ReLU(), nn.Flatten(), nn.Linear(200, 10) )
神经网络模型
Model
Sequential( (0): Conv2d(1, 4, kernel_size=(5, 5), stride=(2, 2)) (1): ReLU() (2): Conv2d(4, 8, kernel_size=(3, 3), stride=(2, 2)) (3): ReLU() (4): Flatten(start_dim=1, end_dim=-1) (5): Linear(in_features=200, out_features=10, bias=True) )
#测试 data = torch.randn(3, 1, 28, 28) output = Model(data) output.shape
torch.Size([3, 10])
for p in Model.parameters(): print(p.shape)
torch.Size([4, 1, 5, 5]) torch.Size([4]) torch.Size([8, 4, 3, 3]) torch.Size([8]) torch.Size([10, 200]) torch.Size([10])
训练测试
alpha = 0.1 #学习率 epochs = 100 #训练次数 interval = 100 #打印间隔 for epoch in range(epochs): optimizer = optim.SGD(Model.parameters(), lr=0.1) for i, (data, label) in enumerate(train_loader): output = Model(data) optimizer.zero_grad() #梯度归零 loss = cross_entropy(output, label) #交叉熵函数 loss.backward() #反向求导 optimizer.step() #更新参数 if i % interval == 0: print("Epoch %03d [%03d/%03d]\tLoss:%.4f"%(epoch, i, len(train_loader), loss.item())) correct_num = 0 total_num = 0 with torch.no_grad(): for data, label in test_loader: output = Model(data) pred = output.max(1)[1] correct_num += (pred == label).sum().item() total_num += len(data) acc = correct_num / total_num print('...Testing @ Epoch %03d\tAcc:%.4f'%(epoch, acc))
Epoch 000 [000/600] Loss:2.3005 Epoch 000 [100/600] Loss:0.3855 Epoch 000 [200/600] Loss:0.2832 Epoch 000 [300/600] Loss:0.3216 Epoch 000 [400/600] Loss:0.2495 Epoch 000 [500/600] Loss:0.0687 ...Testing @ Epoch 000 Acc:0.9554 Epoch 001 [000/600] Loss:0.1364 Epoch 001 [100/600] Loss:0.2104 Epoch 001 [200/600] Loss:0.1206 Epoch 001 [300/600] Loss:0.0859 Epoch 001 [400/600] Loss:0.1187 Epoch 001 [500/600] Loss:0.1903 ...Testing @ Epoch 001 Acc:0.9668 Epoch 002 [000/600] Loss:0.1893 Epoch 002 [100/600] Loss:0.1033 Epoch 002 [200/600] Loss:0.1633 Epoch 002 [300/600] Loss:0.1038 Epoch 002 [400/600] Loss:0.1250 Epoch 002 [500/600] Loss:0.2345 ...Testing @ Epoch 002 Acc:0.9725 Epoch 003 [000/600] Loss:0.0566 Epoch 003 [100/600] Loss:0.1781 Epoch 003 [200/600] Loss:0.0779 Epoch 003 [300/600] Loss:0.2852 Epoch 003 [400/600] Loss:0.0428 Epoch 003 [500/600] Loss:0.1369 ...Testing @ Epoch 003 Acc:0.9714 Epoch 004 [000/600] Loss:0.1098 Epoch 004 [100/600] Loss:0.1288 Epoch 004 [200/600] Loss:0.1078 Epoch 004 [300/600] Loss:0.1325 Epoch 004 [400/600] Loss:0.0649 Epoch 004 [500/600] Loss:0.0683 ...Testing @ Epoch 004 Acc:0.9739 Epoch 005 [000/600] Loss:0.0984 Epoch 005 [100/600] Loss:0.1322 Epoch 005 [200/600] Loss:0.0641 Epoch 005 [300/600] Loss:0.0769 Epoch 005 [400/600] Loss:0.1507 Epoch 005 [500/600] Loss:0.0377 ...Testing @ Epoch 005 Acc:0.9742 Epoch 006 [000/600] Loss:0.0954 Epoch 006 [100/600] Loss:0.0889 Epoch 006 [200/600] Loss:0.0666 Epoch 006 [300/600] Loss:0.0448 Epoch 006 [400/600] Loss:0.0285 Epoch 006 [500/600] Loss:0.0581 ...Testing @ Epoch 006 Acc:0.9773 Epoch 007 [000/600] Loss:0.0305 Epoch 007 [100/600] Loss:0.0651 Epoch 007 [200/600] Loss:0.1007 Epoch 007 [300/600] Loss:0.1537 Epoch 007 [400/600] Loss:0.0233 Epoch 007 [500/600] Loss:0.0925 ...Testing @ Epoch 007 Acc:0.9750 Epoch 008 [000/600] Loss:0.1807 Epoch 008 [100/600] Loss:0.0373 Epoch 008 [200/600] Loss:0.0600 Epoch 008 [300/600] Loss:0.2233 Epoch 008 [400/600] Loss:0.0469 Epoch 008 [500/600] Loss:0.0817 ...Testing @ Epoch 008 Acc:0.9795 Epoch 009 [000/600] Loss:0.1331 Epoch 009 [100/600] Loss:0.1417 Epoch 009 [200/600] Loss:0.0429 Epoch 009 [300/600] Loss:0.0552 Epoch 009 [400/600] Loss:0.0117 Epoch 009 [500/600] Loss:0.0611 ...Testing @ Epoch 009 Acc:0.9780 Epoch 010 [000/600] Loss:0.0386 Epoch 010 [100/600] Loss:0.2372 Epoch 010 [200/600] Loss:0.0092 Epoch 010 [300/600] Loss:0.0623 Epoch 010 [400/600] Loss:0.0530 Epoch 010 [500/600] Loss:0.0345 ...Testing @ Epoch 010 Acc:0.9797 Epoch 011 [000/600] Loss:0.1051 Epoch 011 [100/600] Loss:0.0507 Epoch 011 [200/600] Loss:0.1075 Epoch 011 [300/600] Loss:0.0414 Epoch 011 [400/600] Loss:0.0256 Epoch 011 [500/600] Loss:0.0631 ...Testing @ Epoch 011 Acc:0.9778 Epoch 012 [000/600] Loss:0.0873 Epoch 012 [100/600] Loss:0.0693 Epoch 012 [200/600] Loss:0.0779 Epoch 012 [300/600] Loss:0.2842 Epoch 012 [400/600] Loss:0.0314 Epoch 012 [500/600] Loss:0.0197 ...Testing @ Epoch 012 Acc:0.9778 ……
3.函数式操作
见《PyTorch应用实战二:实现卷积神经网络进行图像分类》