当前位置: 首页 > article >正文

深度学习基本单元结构与输入输出维度解析

深度学习基本单元结构与输入输出维度解析

在深度学习领域,模型的设计和结构是理解其性能和应用的关键。本文将介绍深度学习中的基本单元结构,包括卷积神经网络(CNN)、反卷积(转置卷积)、循环神经网络(RNN)、门控循环单元(GRU)和长短期记忆网络(LSTM),并详细讨论每个单元的输入和输出维度。我们将以 MNIST 数据集为例,展示这些基本单元如何组合在一起构建复杂的模型。
之前的博客:
深入理解 RNN、LSTM 和 GRU:结构、参数与应用
理解 Conv2d 和 ConvTranspose2d 的输入输出特征形状计算

1. 模型结构概述

我们构建的模型包含以下主要部分:

  • 卷积神经网络(CNN)
  • 反卷积(转置卷积)
  • 循环神经网络(RNN)
  • 门控循环单元(GRU)
  • 长短期记忆网络(LSTM)
  • 全连接层

2. 模型代码

以下是实现综合模型的代码:

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.transforms as transforms
from torchvision import datasets
from torch.utils.data import DataLoader

# 定义模型
class CombinedModel(nn.Module):
    def __init__(self):
        super(CombinedModel, self).__init__()

        # CNN 部分
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)  # 输入: (1, 28, 28) -> 输出: (32, 28, 28)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)  # 最大池化层
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)  # 输入: (32, 28, 28) -> 输出: (64, 28, 28)

        # 反卷积部分
        self.deconv = nn.ConvTranspose2d(64, 32, kernel_size=2, stride=2)  # 输入: (64, 14, 14) -> 输出: (32, 28, 28)

        # RNN 部分
        self.rnn_input_size = 32 * 14 * 14  # 输入到 RNN 的特征数
        self.rnn = nn.RNN(input_size=self.rnn_input_size, hidden_size=128, num_layers=1,
                          batch_first=True)  # 输入: (batch_size, seq_len, input_size)

        # GRU 部分
        self.gru = nn.GRU(input_size=128, hidden_size=64, num_layers=1,
                          batch_first=True)  # 输入: (batch_size, seq_len, input_size)

        # LSTM 部分
        self.lstm = nn.LSTM(input_size=64, hidden_size=32, num_layers=1,
                            batch_first=True)  # 输入: (batch_size, seq_len, input_size)

        # 全连接层
        self.fc = nn.Linear(32, 10)  # 输出: (batch_size, 10)

    def forward(self, x):
        # CNN 部分
        print(f'Input shape: {x.shape}')  # 输入形状: (batch_size, 1, 28, 28)
        x = self.pool(torch.relu(self.conv1(x)))  # 输出: (batch_size, 32, 28, 28)
        print(f'After conv1 and pool: {x.shape}')
        x = self.pool(torch.relu(self.conv2(x)))  # 输出: (batch_size, 64, 14, 14)
        print(f'After conv2 and pool: {x.shape}')

        # 反卷积部分
        x = self.deconv(x)  # 输出: (batch_size, 32, 14, 14)
        print(f'After deconv: {x.shape}')

        # 将数据展平并调整形状以输入到 RNN
        x = x.view(x.size(0), -1)  # 展平为 (batch_size, 32 * 14 * 14)
        print(f'After flattening: {x.shape}')
        x = x.unsqueeze(1)  # 添加序列长度维度,变为 (batch_size, 1, 32 * 14 * 14)
        print(f'After unsqueeze for RNN: {x.shape}')

        # RNN 部分
        x, _ = self.rnn(x)  # 输出: (batch_size, 1, 128)
        print(f'After RNN: {x.shape}')

        # GRU 部分
        x, _ = self.gru(x)  # 输出: (batch_size, 1, 64)
        print(f'After GRU: {x.shape}')

        # LSTM 部分
        x, _ = self.lstm(x)  # 输出: (batch_size, 1, 32)
        print(f'After LSTM: {x.shape}')

        # 取最后一个时间步的输出
        x = x[:, -1, :]  # 输出: (batch_size, 32)
        print(f'After selecting last time step: {x.shape}')

        # 全连接层
        x = self.fc(x)  # 输出: (batch_size, 10)
        print(f'Output shape: {x.shape}')

        return x

# 3. 数据加载
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))  # MNIST 数据集的均值和标准差
])

# 下载 MNIST 数据集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)

train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)

# 4. 训练模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = CombinedModel().to(device)
criterion = nn.CrossEntropyLoss()  # 损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)  # 优化器

# 训练过程
num_epochs = 5
for epoch in range(num_epochs):
    model.train()
    running_loss = 0.0
    correct = 0
    total = 0

    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)  # 将数据移动到设备
        optimizer.zero_grad()  # 清空梯度
        outputs = model(images)  # 前向传播
        loss = criterion(outputs, labels)  # 计算损失
        loss.backward()  # 反向传播
        optimizer.step()  # 更新参数

        running_loss += loss.item()
        _, predicted = torch.max(outputs.data, 1)  # 获取预测结果
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

    avg_loss = running_loss / len(train_loader)
    accuracy = 100 * correct / total
    print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {avg_loss:.4f}, Accuracy: {accuracy:.2f}%')

# 5. 评估模型
model.eval()
correct = 0
total = 0
with torch.no_grad():
    for images, labels in test_loader:
        images, labels = images.to(device), labels.to(device)  # 将数据移动到设备
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)  # 获取预测结果
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(f'Accuracy of the model on the test images: {100 * correct / total:.2f}%')

3. 每个基本单元的输入输出维度

3.1 CNN 部分

  1. 输入(batch_size, 1, 28, 28)

    • 这是 MNIST 数据集的输入形状,其中 1 表示单通道(灰度图像),28x28 是图像的高度和宽度。
  2. 卷积层 1

    • self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
    • 输入形状(batch_size, 1, 28, 28)
    • 输出形状(batch_size, 32, 28, 28)
    • 32 个特征图,空间维度保持不变。
  3. 最大池化层 1

    • 输入形状(batch_size, 32, 28, 28)
    • 输出形状(batch_size, 32, 14, 14)
    • 高度和宽度减半。
  4. 卷积层 2

    • self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
    • 输入形状(batch_size, 32, 14, 14)
    • 输出形状(batch_size, 64, 14, 14)
    • 64 个特征图,空间维度保持不变。
  5. 最大池化层 2

    • 输入形状(batch_size, 64, 14, 14)
    • 输出形状(batch_size, 64, 7, 7)
    • 高度和宽度再次减半。

3.2 反卷积部分

  1. 反卷积层
    • self.deconv = nn.ConvTranspose2d(64, 32, kernel_size=2, stride=2)
    • 输入形状(batch_size, 64, 7, 7)
    • 输出形状(batch_size, 32, 14, 14)
    • 高度和宽度翻倍。

3.3 RNN 部分

  1. 展平

    • x = x.view(x.size(0), -1)
    • 输入形状(batch_size, 32, 14, 14)
    • 输出形状(batch_size, 6272) # 这里的 6272 是 32 * 14 * 14
    • 将特征图展平为一个向量。
  2. 添加序列长度维度

    • x = x.unsqueeze(1)
    • 输入形状(batch_size, 6272)
    • 输出形状(batch_size, 1, 6272)
    • 添加序列长度维度,表示只有一个时间步。
  3. RNN

    • 输入形状(batch_size, 1, 6272)
    • 输出形状(batch_size, 1, 128)
    • RNN 输出的隐藏状态,隐藏层大小为 128。

3.4 GRU 和 LSTM 部分

  1. GRU

    • 输入形状(batch_size, 1, 128)
    • 输出形状(batch_size, 1, 64)
    • GRU 输出的隐藏状态,隐藏层大小为 64。
  2. LSTM

    • 输入形状(batch_size, 1, 64)
    • 输出形状(batch_size, 1, 32)
    • LSTM 输出的隐藏状态,隐藏层大小为 32。

3.5 全连接层

  1. 全连接层
    • self.fc = nn.Linear(32, 10)
    • 输入形状(batch_size, 32)
    • 输出形状(batch_size, 10)
    • 最终输出的类别数(10 类,表示 MNIST 的数字 0-9)。

4. 可视化模型结构

from torchinfo import summary
model = CombinedModel()
summary(model, input_size=(64,1, 28, 28))

或者

import torch
import torch.nn as nn
from torchviz import make_dot
model = CombinedModel()
dummy_input = torch.randn(1, 1, 28, 28)  # (batch_size, channels, height, width)
output = model(dummy_input)
dot = make_dot(output, params=dict(model.named_parameters()))
dot.render("model_structure", format="png")  # 生成 model_structure.png

在这里插入图片描述


http://www.kler.cn/a/414802.html

相关文章:

  • 如何启用本机GPU硬件加速猿大师播放器网页同时播放多路RTSP H.265 1080P高清摄像头RTSP视频流?
  • 有关物流无人机与快递配送的协同研究
  • 面试——HashMap的并发问题
  • Linux中离线安装gcc
  • leetcode 二叉树的最大深度
  • 深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录
  • C语言根据字符串变量获取/设置结构体成员值
  • c++基础开发环境vscode+mingw-w64
  • 【Oracle11g SQL详解】WHERE 子句的条件筛选及常用操作符
  • Seata使用ZooKeeper作为注册中心
  • 【面向对象的程序设计——集合框架】主要接口
  • java charAt()返回数值型 详解
  • python之Flask入门—路由参数
  • 从数据孤岛到数据协同:企业如何构建安全的数据共享生态?
  • php 导出excel 带图片
  • 基于Matlab的图像去噪算法仿真
  • 用 llama.cpp 体验 Meta 的 Llama AI 模型
  • 软件工程头歌实训作业:Junit实训入门篇
  • 一个高效的Java对象映射库Orika
  • SpringBoot 接口加密SM2非对称加密算法 国密算法 公钥加密 私钥解密
  • 使用Alpine镜像作为基础镜像的Dockerfile配置
  • 154. tweenjs相机运动动画
  • sqlmap使用过程中的每个步骤及其相关命令
  • 3D格式转换工具HOOPS Exchange如何保证不同CAD数据准确性和一致性?
  • js:函数
  • 【Db First】.NET开源 ORM 框架 SqlSugar 系列