Pytorch初上手——模型构建

引言

我们接着上一篇文章继续,上次我们创建了数据集,加载了数据集,那么接下来就是搭建模型了。

构建模型

这里推荐看一下Pytorch官方的描述,比较具体。简单来说,神经网络由对数据执行操作的层/模块组成。我们构建的神经网络类继承自torch.nn.Module。我们需要在__init__中初始化神经网络层,然后在forward方法中实现对输入数据的操作。

python 复制代码
class SegmentationNet(nn.Module):
    def __init__(self):

    def forward(self,x):

__init__定义

首先使用super().init()继承一下nn.Module的__init__部分。在自定义模型时,必须在__init__方法的第一行调用,它构建了一个神经网络所需要的容器。之后才可以编写自己的模型层。

python 复制代码
    def __init__(self,n_classes=1):
        super().__init__()
        # 编码器
        self.encoder = nn.Sequential(
            nn.Conv2d(3, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
            nn.Conv2d(128, 256, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
        )
        # 解码器
        self.decoder = nn.Sequential(
            nn.ConvTranspose2d(256, 128, 2, stride=2),# 64->128
            nn.Conv2d(128, 64, 3, padding=1), nn.ReLU(),# 平滑作用,不改变矩阵大小
            nn.ConvTranspose2d(64, 64, 2, stride=2),# 128->256
            nn.Conv2d(64,32, 3, stride = 1,padding = 1),  nn.ReLU(), # 平滑作用,不改变矩阵大小
            nn.ConvTranspose2d(32, 32, 2, stride=2), # 256->512
            nn.Conv2d(32, n_classes,1), # 1*1卷积,降维到单通道
            nn.Sigmoid()  # 二分类概率
        )

这里我们定义了self.encoder和self.decoder两个模型层,但是仔细观察便能发现这两个是容器的类型,里面包含了一系列层。我们用nn.Sequential实现该结构。nn.Sequential 是一个有序的模块容器。数据按照定义的相同顺序通过所有模块。

forward定义

forward 方法实现了从输入到输出的完整计算逻辑,也就是定义了数据如何在网络中流动、变换,最终产生预测结果。定义好forward方法不要直接调用,要通过model(x)间接调用,直接调用会跳过__call__方法,使得其中的钩子逻辑失效,使得模型训练异常。

python 复制代码
# 错误:跳过钩子
output = model.forward(x)

# 正确:调用 __call__,自动触发 hooks
output = model(x)

进行forward方法定义:

python 复制代码
        def forward(self, x):
            return self.decoder(self.encoder(x))

内容逻辑很简单,先进行self.encoder然后进行self.decoder。

模型层

这里介绍一下本示例中用到的模型层,如卷积层,池化层,激活函数层

卷积层

卷积层

实现下采样(提取特征),通过调整卷积核参数进行学习。

输出尺寸 = (W - K + 2P) / S + 1

W:输入矩阵宽度,K:卷积核宽度,P:padding长度,S:stride长度

nn.Conv2d(1, 1, kernel_size=3, stride=1, padding=0)

这个卷积层输入通道数为1,输出通道数为1,卷积核宽度为3,步长为1,padding为0。假设输入矩阵为4*4,那么输出矩阵的尺寸为2*2。

转置卷积层

转置卷积层,实现上采样(恢复分辨率),通过调整卷积核参数进行学习。

输出尺寸 = (W - 1) × S - 2P + K + 输出填充

W:输入矩阵宽度,K:卷积核宽度,P:padding长度,S:stride长度

nn.ConvTranspose2d(1, 1, kernel_size=3, stride=1, padding=0)

这个卷积层输入通道数为1,输出通道数为1,卷积核宽度为3,步长为1,padding为0。假设输入矩阵为2*2,那么输出矩阵的尺寸为4*4。简单来说,就是输入矩阵的每一个数点乘卷积核,得到的矩阵放入对应的位置,最后将每个位置的数叠加后即得到输出矩阵。

不过转置卷积虽然能增加参数,提高分辨率,单容易产生棋盘效应,即因为重叠区域不均匀导致可能产生棋盘状伪影。解决方法是转置卷积+普通卷积,这里的普通卷积的作用是平滑矩阵中的伪影。

池化层

该层主要做的就是降参,降低分辨率。

示例所用的为最大池化层,即:

nn.MaxPool2d(2)

池化窗口宽度为2,将输入矩阵中固定位置的数换为池化窗口范围中最大的数。

激活函数层

非线性激活是模型输入和输出之间产生复杂映射的原因。它们在线性变换后应用,以引入非线性,帮助神经网络学习各种各样的现象。如果没有激活函数,那么多层卷积等价于单层卷积,即线性变换的复合仍是线性。引入非线性后,网络才能学习复杂模式。

nn.ReLU即为一个非线性激活函数。

f(x) = max(0, x)

nn.sigmoid激活函数适合概率值的输出

f(x) = 1 / (1 + e^(-x))

模型参数

如官方文档所说,神经网络内部的许多层都是参数化的,即具有在训练期间优化的相关权重和偏置。继承 nn.Module 会自动跟踪模型对象内定义的所有字段,并使所有参数都可以通过模型的 parameters() 或 named_parameters() 方法访问。

python 复制代码
model = SegmentationNet()
for i in model.named_parameters():
    print(i[0],i[1].size())
python 复制代码
encoder.0.weight torch.Size([64, 3, 3, 3])
encoder.0.bias torch.Size([64])
encoder.3.weight torch.Size([128, 64, 3, 3])
encoder.3.bias torch.Size([128])
encoder.6.weight torch.Size([256, 128, 3, 3])
encoder.6.bias torch.Size([256])
decoder.0.weight torch.Size([256, 128, 2, 2])
decoder.0.bias torch.Size([128])
decoder.1.weight torch.Size([64, 128, 3, 3])
decoder.1.bias torch.Size([64])
decoder.3.weight torch.Size([64, 64, 2, 2])
decoder.3.bias torch.Size([64])
decoder.4.weight torch.Size([32, 64, 3, 3])
decoder.4.bias torch.Size([32])
decoder.6.weight torch.Size([32, 32, 2, 2])
decoder.6.bias torch.Size([32])
decoder.7.weight torch.Size([1, 32, 1, 1])
decoder.7.bias torch.Size([1])

我们也可以打印出该网络总参数量

python 复制代码
total_params = sum(p.numel() for p in model.parameters())
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"总参数量: {total_params:,}")
print(f"可训练参数量: {trainable_params:,}")
python 复制代码
总参数量: 614,881
可训练参数量: 614,881

当然,我们可以测试一下该模型的输出,应该和输入矩阵尺寸相同

python 复制代码
model = SegmentationNet()
x = torch.randn(1, 3, 512, 512)
output = model(x)
print(f"输出尺寸: {output.shape}") 
python 复制代码
输出尺寸: torch.Size([1, 1, 512, 512])

结尾及相关链接

很好,我们已经搭建了神经网络,接下来定义好评估函数和优化器就可以开始训练了呢。

下期见 ദ്ദി (⩌ᴗ⩌ )

相关链接如下:

示例所用数据集:

Huỳnh Trịnh Ngọc. A02025-Medical-Image-Segmentation. https://kaggle.com/competitions/a0-2025-medical-image-segmentation, 2025. Kaggle.

Pytorch链接:

https://pytorch.org/

相关推荐
动物园猫1 小时前
交通事故车辆受损情况数据集分享(适用于YOLO系列深度学习分类检测任务)
深度学习·yolo·分类
陈天伟教授1 小时前
图解人工智能(18)基于知识的人工智能
人工智能
jixunwulian1 小时前
AI边缘智能网关工业安全领域的边缘智能预警方案应用
网络·人工智能·安全
kcuwu.1 小时前
深度学习模型优化完全指南:从“下山“到“刷题“的通俗讲解
人工智能·深度学习
GitCode官方1 小时前
智能进化觉醒!openvela trunk-5.5 发布:端侧 AI Agent 开源和多方位升级
人工智能·开源
小江的记录本1 小时前
【AI大模型选型指南】《2026年5月(最新版)国内外主流AI大模型选型指南》(企业版)
前端·人工智能·后端·ai作画·aigc·ai编程·ai写作
北京华盛恒辉软件开发公司11 小时前
大模型运维深远海漂浮式风电系统已融合人工智能AI软件平台
运维·人工智能
HIT_Weston1 小时前
82、【Agent】【OpenCode】bash 工具提示词(amend 风险)
人工智能·agent·opencode
阿福聊编程1 小时前
Data-Analysis-Agent:用自然语言查数据库的开源 AI 数据分析工具
数据库·人工智能