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

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

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

之前的博客:
深入理解 RNN、LSTM 和 GRU:结构、参数与应用
理解 Conv2d 和 ConvTranspose2d 的输入输出特征形状计算

1. 模型结构概述

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

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

2. 模型代码

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

python 复制代码
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. 可视化模型结构

python 复制代码
from torchinfo import summary
model = CombinedModel()
summary(model, input_size=(64,1, 28, 28))

或者

python 复制代码
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
相关推荐
weixin_4483505010 分钟前
信息技术与数据安全:打造高效、安全的数据处理系统
人工智能·安全·智慧城市·数据治理·数据提取
InternLM13 分钟前
基于华为昇腾910B,实战InternLM个人小助手认知微调
人工智能·机器学习·大模型·internlm·书生
脑极体15 分钟前
华为Mate 70系列,行走在AI山脊
人工智能·华为
W Y30 分钟前
【目前各家的自动驾驶技术都处于哪一级】
人工智能·机器学习·自动驾驶
W Y34 分钟前
【特斯拉的自动驾驶好在哪】
人工智能·机器学习·自动驾驶
CRMEB-嘉嘉1 小时前
智慧领养 科技助力:Java商城系统打造一站式服务平台
人工智能·科技
湘人-汤义1 小时前
transformers训练(NLP)阅读理解(多项选择)
人工智能·自然语言处理
小彭努力中1 小时前
154. tweenjs相机运动动画
前端·深度学习·3d·css3·webgl
要养家的程序猿1 小时前
OpenAI开源Swarm环境搭建&推理测试
人工智能·科技·ai
laufing1 小时前
OD E卷 - 实现【流浪地球】
python·算法·逻辑模拟