【PyTorch】3.1 模型创建与nn.Module

本文深入解析PyTorch中nn.Module类的使用方法,详细介绍网络模型搭建的步骤,包括模型创建、损失函数选择、优化器配置及训练过程。同时,通过具体案例展示如何利用LeNet模型进行手写数字识别。
部署运行你感兴趣的模型镜像

目录

一、网络模型创建步骤

1. 机器学习模型训练步骤 

2. 模型创建步骤 

3. 模型构建两要素

二、nn.Module

1. torch.nn的子模块

2. nn.Module的8个字典 

3. nn.Module总结


任务简介

学习nn.Module类以及搭建网络模型步骤。

详细说明

本节介绍网络模型的基本类nn.Module,nn.Module是所有网络层的基本类,它拥有8个有序字典,用于管理模型属性,本节课中将要学习如何构建一个Module。然后通过网络结构和计算图两个角度去观察搭建一个网络模型需要两个步骤:第一步,搭建子模块;第二步,拼接子模块。


一、网络模型创建步骤

1. 机器学习模型训练步骤 

2. 模型创建步骤 

3. 模型构建两要素

测试代码:

import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
import torch.optim as optim
from matplotlib import pyplot as plt
path_lenet = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "model", "lenet.py"))
path_tools = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "tools", "common_tools.py"))
assert os.path.exists(path_lenet), "{}不存在,请将lenet.py文件放到 {}".format(path_lenet, os.path.dirname(path_lenet))
assert os.path.exists(path_tools), "{}不存在,请将common_tools.py文件放到 {}".format(path_tools, os.path.dirname(path_tools))

import sys
hello_pytorch_DIR = os.path.abspath(os.path.dirname(__file__)+os.path.sep+".."+os.path.sep+"..")
sys.path.append(hello_pytorch_DIR)

from model.lenet import LeNet
from tools.my_dataset import RMBDataset
from tools.common_tools import set_seed

set_seed()  # 设置随机种子
rmb_label = {"1": 0, "100": 1}

# 参数设置
MAX_EPOCH = 10
BATCH_SIZE = 16
LR = 0.01
log_interval = 10
val_interval = 1

# ============================ step 1/5 数据 ============================
split_dir = os.path.abspath(os.path.join(BASE_DIR, "..", "..", "data", "rmb_split"))
if not os.path.exists(split_dir):
    raise Exception(r"数据 {} 不存在, 回到lesson-06\1_split_dataset.py生成数据".format(split_dir))
train_dir = os.path.join(split_dir, "train")
valid_dir = os.path.join(split_dir, "valid")

norm_mean = [0.485, 0.456, 0.406]
norm_std = [0.229, 0.224, 0.225]

train_transform = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.RandomCrop(32, padding=4),
    transforms.ToTensor(),
    transforms.Normalize(norm_mean, norm_std),
])

valid_transform = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.ToTensor(),
    transforms.Normalize(norm_mean, norm_std),
])

# 构建MyDataset实例
train_data = RMBDataset(data_dir=train_dir, transform=train_transform)
valid_data = RMBDataset(data_dir=valid_dir, transform=valid_transform)

# 构建DataLoder
train_loader = DataLoader(dataset=train_data, batch_size=BATCH_SIZE, shuffle=True)
valid_loader = DataLoader(dataset=valid_data, batch_size=BATCH_SIZE)

# ============================ step 2/5 模型 ============================
net = LeNet(classes=2)
net.initialize_weights()

# ============================ step 3/5 损失函数 ============================
criterion = nn.CrossEntropyLoss()                                                   # 选择损失函数

# ============================ step 4/5 优化器 ============================
optimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9)                        # 选择优化器
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)     # 设置学习率下降策略

# ============================ step 5/5 训练 ============================
train_curve = list()
valid_curve = list()

for epoch in range(MAX_EPOCH):

    loss_mean = 0.
    correct = 0.
    total = 0.

    net.train()
    for i, data in enumerate(train_loader):

        # forward
        inputs, labels = data
        outputs = net(inputs)

        # backward
        optimizer.zero_grad()
        loss = criterion(outputs, labels)
        loss.backward()

        # update weights
        optimizer.step()

        # 统计分类情况
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).squeeze().sum().numpy()

        # 打印训练信息
        loss_mean += loss.item()
        train_curve.append(loss.item())
        if (i+1) % log_interval == 0:
            loss_mean = loss_mean / log_interval
            print("Training:Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
                epoch, MAX_EPOCH, i+1, len(train_loader), loss_mean, correct / total))
            loss_mean = 0.

    scheduler.step()  # 更新学习率

    # validate the model
    if (epoch+1) % val_interval == 0:

        correct_val = 0.
        total_val = 0.
        loss_val = 0.
        net.eval()
        with torch.no_grad():
            for j, data in enumerate(valid_loader):
                inputs, labels = data
                outputs = net(inputs)
                loss = criterion(outputs, labels)

                _, predicted = torch.max(outputs.data, 1)
                total_val += labels.size(0)
                correct_val += (predicted == labels).squeeze().sum().numpy()

                loss_val += loss.item()

            valid_curve.append(loss_val)
            print("Valid:\t Epoch[{:0>3}/{:0>3}] Iteration[{:0>3}/{:0>3}] Loss: {:.4f} Acc:{:.2%}".format(
                epoch, MAX_EPOCH, j+1, len(valid_loader), loss_val, correct / total))


train_x = range(len(train_curve))
train_y = train_curve

train_iters = len(train_loader)
valid_x = np.arange(1, len(valid_curve)+1) * train_iters*val_interval # 由于valid中记录的是epochloss,需要对记录点进行转换到iterations
valid_y = valid_curve

plt.plot(train_x, train_y, label='Train')
plt.plot(valid_x, valid_y, label='Valid')

plt.legend(loc='upper right')
plt.ylabel('loss value')
plt.xlabel('Iteration')
plt.show()

# ============================ inference ============================

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
test_dir = os.path.join(BASE_DIR, "test_data")

test_data = RMBDataset(data_dir=test_dir, transform=valid_transform)
valid_loader = DataLoader(dataset=test_data, batch_size=1)

for i, data in enumerate(valid_loader):
    # forward
    inputs, labels = data
    outputs = net(inputs)
    _, predicted = torch.max(outputs.data, 1)

    rmb = 1 if predicted.numpy()[0] == 0 else 100
    print("模型获得{}元".format(rmb))

在此处设置断点:

  

step into进入该函数:

class LeNet(nn.Module):
    def __init__(self, classes):   # 构建子模块
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, classes)

    def forward(self, x):    # 拼接子模块,前向传播
        out = F.relu(self.conv1(x))
        out = F.max_pool2d(out, 2)
        out = F.relu(self.conv2(out))
        out = F.max_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out

二、nn.Module

1. torch.nn的子模块

2. nn.Module的8个字典 

3. nn.Module总结

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

### 3.1 `nn.Sequential` 的实现方法 在 PyTorch 中,`nn.Sequential` 是一种用于构建神经网络层的容器类,它允许按照顺序堆叠多个神经网络层,并自动完成前向传播过程。该类支持多种实现方式,包括直接传入多个层对象、使用有序字典(`OrderedDict`)定义层名称和结构,以及通过自定义类实现更复杂的网络结构。最简单的使用方式如下: ```python import torch import torch.nn as nn model = nn.Sequential( nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10) ) ``` 该模型定义了一个三层的前馈神经网络,其中包含一个输入层、一个隐藏层和一个输出层,`nn.ReLU` 用于引入非线性[^2]。 ### 3.2 `nn.Sequential` 的最佳实践 在构建神经网络模型时,合理使用 `nn.Sequential` 可以提高代码的可读性和模块化程度。例如,在卷积神经网络(CNN)中,可以通过 `nn.Sequential` 定义卷积层、归一化层和激活函数的组合: ```python self.conv1 = nn.Sequential( nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, stride=2, padding=1), nn.BatchNorm2d(16), nn.ReLU() ) ``` 该方式将多个操作封装为一个整体,便于管理和复用。此外,为了增强模型的可解释性,可以使用 `OrderedDict` 明确命名每一层: ```python from collections import OrderedDict model = nn.Sequential(OrderedDict([ ('linear1', nn.Linear(784, 256)), ('relu', nn.ReLU()), ('linear2', nn.Linear(256, 10)) ])) ``` 这种方式有助于调试和可视化模型结构,同时支持更灵活的层替换和修改[^1]。 ### 3.3 `nn.Sequential` 的局限性优化策略 尽管 `nn.Sequential` 提供了便捷的模型构建方式,但其本质是按照固定顺序执行前向传播,无法支持复杂的分支结构或多输入输出的场景。例如,对于残差连接、跳跃连接等结构,`nn.Sequential` 无法直接实现,此时需要继承 `nn.Module` 并自定义 `forward` 方法。此外,在调试过程中,`nn.Sequential` 的内部层难以单独访问和修改,因此在需要精细化控制模型行为的场景中,应优先使用更灵活的类定义方式[^1]。 为优化 `nn.Sequential` 的使用体验,建议结合模型可视化工具(如 `torchinfo`)查看网络结构,并在训练过程中对关键层的输出进行监控,以提升模型的可控性和可解释性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值