深度学习——神经网路的基本搭建
我们使用经典的MNIST数据集,这是一个广泛用于机器学习入门的手写数字识别基准数据集。训练集:60,000张28×28像素的灰度图像测试集:10,000张同样规格的图像类别:0-9共10个数字类别像素值范围:0-255(黑色到白色)
·
深度学习中的神经网络是通过堆叠各种层(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
模型特点说明
- 权重初始化:使用Xavier初始化方法,根据输入输出维度自动调整初始化范围,有助于缓解梯度消失/爆炸问题
- 激活函数选择:隐藏层使用sigmoid激活函数,将输出压缩到(0,1)区间
- 输出层设计:直接输出logits(未归一化的分数),与后续的交叉熵损失函数配合使用
- 参数数量:总参数约为784×128 + 128×256 + 256×10 = 136,704个可训练参数
更多推荐
所有评论(0)