咚咚

V1

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*28512),
            nn.ReLU(),
            nn.Linear(512512),
            nn.ReLU(),
            nn.Linear(51210),
        )

    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(12828, 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([32828])

nn.Flatten模块

先实例初始化nn.Flatten类,再将每个2维28x28展平为一个784像素值的连续数组

注意:nn.Flatten中的forward操作是从第二维度开始展平的,保留第一维

flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.size())

输出的形状为

torch.Size([3784])

nn.Linear模块

线性层利用其存储的权重和偏差对输入应用线性映射

layer1 = nn.Linear(in_features=28*28, out_features=20# 将28*28维度映射到20
hidden1 = layer1(flat_image) # 只对最后一个维度进行映射
print(hidden1.size())

输出形状为

torch.Size([320])

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.00000.00000.29770.00000.00000.37090.02940.00000.0000,
         0.00000.00000.46630.00000.00000.88640.47620.26380.0000,
         0.07900.0000],
        [0.00000.00000.22980.00000.00000.43740.16650.14050.0000,
         0.00000.00000.00000.11290.00000.80670.38470.27250.0000,
         0.41730.0000],
        [0.00000.00000.69890.00000.00000.00000.00000.00000.0000,
         0.00000.00000.48530.20010.00000.97550.38000.00000.2659,
         0.28860.0000]], grad_fn=<ReluBackward0>)

可以发现nn.ReLU将所有的负值转换为0,正值保持不变

nn.Sequential模块

nn.sequential是一个有序的模块容器。数据按其中的顺序通过所有模块,方便使用

seq_modules = nn.Sequential(
    flatten,
    layer1,
    nn.ReLU(),
    nn.Linear(2010)
# 其中包含了不同的模块,按顺序排列
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([512784]) | 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([512512]) | 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.02190.0020], device='cuda:0', grad_fn=<SliceBackward0>)

Layer: linear_relu_stack.4.weight | Size: torch.Size([10512]) | 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>)

分类:

人工智能

标签:

深度学习

作者介绍

咚咚
V1

哈尔滨工业大学-计算机视觉