咚咚
2022/03/01阅读:51主题:默认主题
<pytorch系列4>: 构建神经网络模型
微信公众号:咚咚学AI
神经网络由执行数据操作的层/模块组成。
torch.nn命名空间提供了构建自己的神经网络所需的所有模块。
PyTorch 中的每个模块继承于nn.Module 。
神经网络是一个由其他模块(层)组成的模块。这种嵌套结构允许轻松地构建和管理复杂的架构
接下来,我们将构建一个神经网络来对 FashionMNIST 数据集中的图像进行分类
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
训练设备的选择
如果GPU可用,就选择在GPU上进行训练,否则我们继续使用 CPU
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using {device} device")
假如GPU可用,则输出
Using cuda device
构建神经网络类
通过继承nn.Module对神经网络进行定义。
并在 __ init __ 中初始化神经网络层。
每个nn.Module子类在 forward 方法中实现对输入数据的操作。
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
接下来创建了一个NeuralNetwork的实例,并把它移动到设备上,并打印出它的结构。
model = NeuralNetwork().to(device)
print(model)
输出为
NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
)
)
接下来,我们通过给神经网络模型传入一张图像来预测其所属类别概率。
X = torch.rand(1, 28, 28, device=device) # 输入数据需要和模型在同一个设备上
logits = model(X) # 会调用forward方法进行操作X
pred_probab = nn.Softmax(dim=1)(logits) # 对生成的十个数进行概率化,总和等于1
y_pred = pred_probab.argmax(1) # 获取十个数中最大数的索引,就是所属类别
print(f"Predicted class: {y_pred}")
输出为
、
Predicted class: tensor([9], device='cuda:0')
模型层
接下来对模型中的每个层进行详细分析,我们使用三张大小为28x28作为输入
input_image = torch.rand(3,28,28)
print(input_image.size())
输出形状为
torch.Size([3, 28, 28])
nn.Flatten模块
先实例初始化nn.Flatten类,再将每个2维28x28展平为一个784像素值的连续数组
注意:nn.Flatten中的forward操作是从第二维度开始展平的,保留第一维
flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.size())
输出的形状为
torch.Size([3, 784])
nn.Linear模块
线性层利用其存储的权重和偏差对输入应用线性映射
layer1 = nn.Linear(in_features=28*28, out_features=20) # 将28*28维度映射到20
hidden1 = layer1(flat_image) # 只对最后一个维度进行映射
print(hidden1.size())
输出形状为
torch.Size([3, 20])
nn.ReLU模块
非线性激活在模型的输入和输出之间创建复杂的映射。它们在线性变换之后被用来引入非线性,有助于提高网络的学习能力。
print(f"Before ReLU: {hidden1}\n\n")
hidden1 = nn.ReLU()(hidden1)
print(f"After ReLU: {hidden1}")
输出为
Before ReLU: tensor([[-0.2237, -0.2367, 0.2977, -0.3347, -0.4724, 0.3709, 0.0294, -0.0807,
-0.5721, -0.1723, -0.8035, 0.4663, -0.0803, -0.2520, 0.8864, 0.4762,
0.2638, -0.1566, 0.0790, -0.0876],
[-0.2885, -0.3101, 0.2298, -0.4918, -0.3310, 0.4374, 0.1665, 0.1405,
-0.5300, -0.3482, -0.4831, -0.0948, 0.1129, -0.3147, 0.8067, 0.3847,
0.2725, -0.0671, 0.4173, -0.3192],
[-0.2258, -0.1209, 0.6989, -0.4547, -0.3201, -0.1266, -0.1083, -0.0766,
-0.2590, -0.3851, -0.7130, 0.4853, 0.2001, -0.3398, 0.9755, 0.3800,
-0.0782, 0.2659, 0.2886, -0.5325]], grad_fn=<AddmmBackward0>)
After ReLU: tensor([[0.0000, 0.0000, 0.2977, 0.0000, 0.0000, 0.3709, 0.0294, 0.0000, 0.0000,
0.0000, 0.0000, 0.4663, 0.0000, 0.0000, 0.8864, 0.4762, 0.2638, 0.0000,
0.0790, 0.0000],
[0.0000, 0.0000, 0.2298, 0.0000, 0.0000, 0.4374, 0.1665, 0.1405, 0.0000,
0.0000, 0.0000, 0.0000, 0.1129, 0.0000, 0.8067, 0.3847, 0.2725, 0.0000,
0.4173, 0.0000],
[0.0000, 0.0000, 0.6989, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.4853, 0.2001, 0.0000, 0.9755, 0.3800, 0.0000, 0.2659,
0.2886, 0.0000]], grad_fn=<ReluBackward0>)
可以发现nn.ReLU将所有的负值转换为0,正值保持不变
nn.Sequential模块
nn.sequential是一个有序的模块容器。数据按其中的顺序通过所有模块,方便使用
seq_modules = nn.Sequential(
flatten,
layer1,
nn.ReLU(),
nn.Linear(20, 10)
) # 其中包含了不同的模块,按顺序排列
input_image = torch.rand(3,28,28)
logits = seq_modules(input_image) # 按顺序执行每个模块
nn.Softmax模块
神经网络的最后一个线性层返回logits(原始值在[-infty,infty]中)
nn.Softmax模块将每个Logit缩放到数值[0,1]范围内(数值总和为1),代表模型对每个类别的预测概率。
softmax = nn.Softmax(dim=1) # dim表示对哪个维度进行操作
pred_probab = softmax(logits)
模型参数
神经网络中的许多层都是参数化的,即具有在训练期间优化的相关权重和偏差。
nn.Module子类自动跟踪模型内部定义的所有参数,并使用模型的 **parameters ()**或 **named _ parameters ()**方法访问所有参数。
print(f"Model structure: {model}\n\n")
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")
输出为
Model structure: NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1) # 没有参数
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True) # 含有权重和偏置
(1): ReLU() # 没有参数
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
)
)
Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values : tensor([[ 0.0033, -0.0081, -0.0354, ..., -0.0335, 0.0070, 0.0030],
[ 0.0106, -0.0064, 0.0300, ..., 0.0071, -0.0062, 0.0169]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values : tensor([-0.0193, -0.0153], device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values : tensor([[ 0.0408, 0.0078, 0.0300, ..., 0.0058, -0.0142, -0.0226],
[ 0.0319, -0.0063, -0.0093, ..., -0.0096, 0.0352, 0.0178]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values : tensor([0.0219, 0.0020], device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values : tensor([[ 0.0076, 0.0076, 0.0433, ..., 0.0178, 0.0230, 0.0227],
[-0.0396, -0.0042, 0.0342, ..., -0.0364, -0.0184, -0.0329]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values : tensor([-0.0380, -0.0044], device='cuda:0', grad_fn=<SliceBackward0>)
作者介绍
咚咚
哈尔滨工业大学-计算机视觉