深度学习中的神经网络是通过堆叠各种层(Layer)来构建的,PyTorch 提供了灵活的接口来定义和训练这些网络。以下是神经网络的基本搭建步骤和关键概念:

1. 神经网络的核心组件

(1) 层(Layer)
线性层(全连接层)

nn.Linear(in_features, out_features)

  • 这是最基本的神经网络层,用于输入和输出之间的线性变换
  • 示例:nn.Linear(784, 256)将784维输入(如28x28展平的MNIST图像)映射到256维输出
  • 内部实现:y = xW^T + b,其中W是权重矩阵,b是偏置项
卷积层

nn.Conv2d(in_channels, out_channels, kernel_size)

  • 主要用于处理图像等具有空间结构的数据
  • 示例:nn.Conv2d(3, 16, 3)处理3通道的RGB图像,输出16个特征图,使用3x3的卷积核
  • 可选参数:stride(步长)、padding(填充)、dilation(膨胀系数)等
  • 实际操作:在输入上滑动卷积核,计算局部感受野的点积
激活函数
  • nn.ReLU()(最常用):
    • 公式:f(x) = max(0, x)
    • 优点:计算简单,能缓解梯度消失问题
  • nn.Sigmoid()(二分类输出层):
    • 公式:f(x) = 1/(1+e^-x)
    • 输出范围(0,1),适用于概率输出
  • nn.Softmax()(多分类输出层):
    • 公式:f(x_i) = e^{x_i}/Σe^{x_j}
    • 将输出转换为概率分布,总和为1
(2) 损失函数(Loss Function)
分类任务
  • nn.CrossEntropyLoss()(结合了Softmax和负对数似然)
    • 适用于多分类问题
    • 示例:图像分类任务中预测10个类别的概率
    • 内部实现:先应用log_softmax,再计算负对数似然
回归任务
  • nn.MSELoss()(均方误差)
    • 公式:L = 1/n Σ(y_pred - y_true)^2
    • 适用于连续值预测任务,如房价预测
(3) 优化器(Optimizer)
随机梯度下降
  • torch.optim.SGD(model.parameters(), lr=0.01)
    • 基本形式:θ = θ - η∇θ
    • 可配置参数:动量(momentum)、权重衰减(weight decay)
    • 适用于大规模数据集
Adam优化器
  • torch.optim.Adam(model.parameters(), lr=0.001)(更常用)
    • 结合了动量法和自适应学习率
    • 默认参数通常表现良好,是很多任务的默认选择
    • 实现了自适应矩估计,对不同的参数有不同的学习率

数据集加载与探索

MNIST数据集介绍

我们使用经典的MNIST数据集,这是一个广泛用于机器学习入门的手写数字识别基准数据集。该数据集由Yann LeCun等人收集整理,包含:

  • 训练集:60,000张28×28像素的灰度图像
  • 测试集:10,000张同样规格的图像
  • 类别:0-9共10个数字类别
  • 像素值范围:0-255(黑色到白色)

数据预处理

我们使用PyTorch的transforms模块进行数据预处理:

from torchvision import datasets, transforms

# 定义数据转换
transform = transforms.Compose([
    transforms.ToTensor(),  # 将PIL图像转换为PyTorch张量
    transforms.Normalize((0.1307,), (0.3081,))  # 使用MNIST的均值和标准差进行归一化
])

# 下载并加载数据集
training_data = datasets.MNIST(
    root='./data',          # 数据存储路径
    train=True,             # 加载训练集
    download=True,          # 如果本地不存在则下载
    transform=transform     # 应用上述转换
)

test_data = datasets.MNIST(
    root='./data',
    train=False,            # 加载测试集
    download=True,
    transform=transform
)

数据可视化

为了更好地理解数据分布,我们可以可视化部分样本:

import matplotlib.pyplot as plt
import numpy as np

# 设置随机种子保证可重复性
np.random.seed(42)

figure = plt.figure(figsize=(10, 10))
for i in range(16):
    idx = np.random.randint(0, len(training_data))
    img, label = training_data[idx]
    
    # 反归一化以便正确显示
    img = img * 0.3081 + 0.1307
    
    ax = figure.add_subplot(4, 4, i+1)
    ax.set_title(f"Label: {label}", fontsize=12)
    ax.axis('off')
    plt.imshow(img.squeeze(), cmap='gray', vmin=0, vmax=1)
plt.tight_layout()
plt.show()

数据加载器配置

为了提高训练效率并实现小批量梯度下降,我们使用DataLoader进行批处理:

from torch.utils.data import DataLoader

# 设置批量大小
batch_size = 64

# 创建数据加载器
train_loader = DataLoader(
    training_data,
    batch_size=batch_size,
    shuffle=True,          # 每个epoch重新打乱数据
    num_workers=2,         # 使用2个子进程加载数据
    pin_memory=True        # 提高GPU传输效率
)

test_loader = DataLoader(
    test_data,
    batch_size=batch_size,
    shuffle=False,         # 测试集不需要打乱
    num_workers=2,
    pin_memory=True
)

神经网络模型设计

我们构建一个包含两个隐藏层的全连接神经网络,以下是详细设计:

import torch
import torch.nn as nn
import torch.nn.init as init

class NeuralNet(nn.Module):
    def __init__(self):
        super().__init__()
        # 网络层定义
        self.flatten = nn.Flatten()  # 将28x28图像展平为784维向量
        
        # 第一隐藏层:784输入,128输出
        self.hidden1 = nn.Linear(28 * 28, 128)
        
        # 第二隐藏层:128输入,256输出
        self.hidden2 = nn.Linear(128, 256)
        
        # 输出层:256输入,10输出(对应10个类别)
        self.output = nn.Linear(256, 10)
        
        # 初始化权重
        self._initialize_weights()
    
    def _initialize_weights(self):
        # 使用Xavier/Glorot初始化方法
        init.xavier_uniform_(self.hidden1.weight)
        init.zeros_(self.hidden1.bias)
        
        init.xavier_uniform_(self.hidden2.weight)
        init.zeros_(self.hidden2.bias)
        
        init.xavier_uniform_(self.output.weight)
        init.zeros_(self.output.bias)
    
    def forward(self, x):
        # 前向传播过程
        x = self.flatten(x)
        x = self.hidden1(x)
        x = torch.sigmoid(x)  # 第一隐藏层使用sigmoid激活
        
        x = self.hidden2(x)
        x = torch.sigmoid(x)  # 第二隐藏层使用sigmoid激活
        
        x = self.output(x)    # 输出层不使用激活函数(与交叉熵损失配合)
        return x

模型特点说明

  1. 权重初始化:使用Xavier初始化方法,根据输入输出维度自动调整初始化范围,有助于缓解梯度消失/爆炸问题
  2. 激活函数选择:隐藏层使用sigmoid激活函数,将输出压缩到(0,1)区间
  3. 输出层设计:直接输出logits(未归一化的分数),与后续的交叉熵损失函数配合使用
  4. 参数数量:总参数约为784×128 + 128×256 + 256×10 = 136,704个可训练参数
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐