神经网络|构成|搭建|优化
神经网络基础NN
1. 神经网络组成
1.1 神经网络的构成
神经网络是一种模仿生物神经网络结构和功能的计算模型,由多个神经元串联构成。每个神经元执行的操作可以简化为加权和加上一个激活函数(引入非线性)。神经网络主要由以下几部分构成:
- 输入层:接收外部输入数据。
- 输出层:产生网络的最终输出,通常是加权和的结果。
- 隐藏层:包含加权和与激活函数,用于处理中间信息。
神经网络的特点包括:
- 同一层内的神经元之间没有直接连接。
- 在全连接神经网络中,第N层的每个神经元与第N-1层的所有神经元相连。
- 第N-1层神经元的输出是第N层所有神经元的输入。
- 每个连接都有一个权重值(w系数和b系数)。
在编程接口中,常用的API包括Linear(线性层)和FC(全连接层)。
import torch.nn as nn
# 定义线性层
linear_layer = nn.Linear(in_features, out_features)
# 定义全连接层
fc_layer = nn.Linear(in_features, out_features)
1.2 激活函数
激活函数的主要目的是向神经网络中添加非线性因素,使其能够拟合更复杂的场景,比如曲线和曲面。常见的激活函数有:
- Sigmoid:适用于二分类问题的输出层,输出范围在[0,1]之间,可以解释为概率值。但由于梯度较小,容易导致梯度消失问题。
y = torch.sigmoid(x)
- Tanh:通常在隐藏层中使用,输出范围[-1,1],关于0对称。相比Sigmoid,Tanh的导数更大,更新速度更快,迭代次数更少,但在x远离0点时,梯度可能为0,导致梯度消失。
y = torch.tanh(x)
- ReLU:最常用于隐藏层,计算简单且能有效减少计算量。其输出为0时,可以防止过拟合;但如果大部分神经元输出为0,则可能导致“死亡”现象,此时可考虑使用Leaky ReLU等优化版本。
y = torch.relu(x)
- Softmax:适用于多分类问题的输出层,将输出层的加权和转换为概率值,概率值之和为1,通常配合交叉熵损失函数使用。
y = torch.softmax(scores, dim=0)
选择激活函数时,对于隐藏层优先选择ReLU激活函数,如果效果不佳可尝试其他变体。对于输出层,根据任务类型选择相应的激活函数。
1.3 参数初始化
良好的参数初始化有助于加速训练过程并提高模型性能。权重的初始化方法包括均匀分布、标准正态分布、Kaiming(HE)初始化和Xavier(Glorot)初始化。偏置通常初始化为全0或全1,也可以设置为固定值。
import torch.nn.init as init
# 均匀分布
init.uniform_(linear_layer.weight)
# 标准正态分布
init.normal_(linear_layer.weight, mean=0, std=1)
# Kaiming (HE) 初始化
init.kaiming_uniform_(linear_layer.weight)
init.kaiming_normal_(linear_layer.weight)
# Xavier (Glorot) 初始化
init.xavier_uniform_(linear_layer.weight)
init.xavier_normal_(linear_layer.weight)
# 偏置初始化
init.zeros_(linear_layer.bias)
init.ones_(linear_layer.bias)
# 固定值初始化
init.constant_(linear_layer.weight, value)
1.4 神经网络搭建及参数计算
构建神经网络通常涉及创建一个继承自nn.Module的类,并实现__init__和forward方法。__init__方法用于定义网络结构,包括全连接层和参数初始化;forward方法定义了前向传播过程,将所有层串联起来。可以通过torchsummary库来查看模型结构和计算模型参数量。
import torch.nn as nn
from torchsummary import summary
class MyNet(nn.Module):
def __init__(self):
super(MyNet, self).__init__()
self.fc1 = nn.Linear(in_features, hidden_features)
self.fc2 = nn.Linear(hidden_features, out_features)
# 初始化参数
init.kaiming_normal_(self.fc1.weight)
init.zeros_(self.fc1.bias)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x
# 创建模型实例
model = MyNet()
# 查看模型结构和参数量
summary(model, input_size=(1, in_features))
神经网络的优点在于精度高、性能优越,但也有黑箱性质、训练时间长、网络结构复杂等缺点。
2. 损失函数
损失函数用于衡量模型参数的质量,通过比较网络输出与真实输出的差异来评估模型性能。常见的损失函数包括:
- 多分类:使用
CrossEntropyLoss,结合了softmax和损失计算。
loss_fn = nn.CrossEntropyLoss()
my_loss = loss_fn(predictions, targets).detach().numpy()
- 二分类:使用
BCELoss(二分类交叉熵损失)。
loss_fn = nn.BCELoss()
my_loss = loss_fn(predictions, targets).detach().numpy()
- 回归:使用
L1Loss(MAE)、MSELoss(MSE)或SmoothL1Loss,这些损失函数分别针对不同的回归问题设计。
# MAE损失函数
loss_fn = nn.L1Loss()
my_loss = loss_fn(predictions, targets).detach().numpy()
# MSE损失函数
loss_fn = nn.MSELoss()
my_loss = loss_fn(predictions, targets).detach().numpy()
# SmoothL1损失函数
loss_fn = nn.SmoothL1Loss()
my_loss = loss_fn(predictions, targets).detach().numpy()
3. 网络优化方法
优化方法是训练神经网络的关键,主要包括:
- 前向传播:数据从输入层逐层传递至输出层。
- 反向传播:通过损失函数从后向前计算梯度,并更新参数。
- 梯度下降:寻找损失函数最小化的方法。常用优化算法包括Momentum、AdaGrad、RMSprop和Adam等,它们通过不同的策略改善梯度下降过程。
import torch.optim as optim
# SGD优化器
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# AdaGrad优化器
optimizer = optim.Adagrad(model.parameters(), lr=0.01)
# RMSprop优化器
optimizer = optim.RMSprop(model.parameters(), lr=0.01, alpha=0.9)
# Adam优化器
optimizer = optim.Adam(model.parameters(), lr=0.01, betas=(0.9, 0.999))
此外,学习率衰减方法如等间隔衰减、指定间隔衰减和按指数衰减等,可以帮助模型在训练过程中更好地收敛。
from torch.optim.lr_scheduler import StepLR, MultiStepLR, ExponentialLR
# 等间隔学习率衰减
scheduler = StepLR(optimizer, step_size=50, gamma=0.1)
# 指定间隔学习率衰减
scheduler = MultiStepLR(optimizer, milestones=[50, 125, 160], gamma=0.1)
# 按指数学习率衰减
scheduler = ExponentialLR(optimizer, gamma=0.95)
4. 正则化方法
正则化技术主要用于缓解过拟合问题,常见的方法包括:
- Dropout:随机失活一定比例的神经元,减少模型复杂度。
dropout = nn.Dropout(p=0.4)
y = dropout(y)
- Batch Normalization:对数据进行标准化,然后通过缩放和平移重构数据,有助于加速训练过程。
bn = nn.BatchNorm1d(num_features)
y = bn(y)
5. 案例—手机价格分类
通过构建数据集、定义模型、训练模型和评估模型四个步骤完成手机价格分类任务。优化思路包括调整优化方法、学习率、数据预处理、网络深度、训练轮次和批处理大小等,以提升模型性能。
5.1 流程
- 构建数据集
def create_dataset():
# 创建数据集
pass
- 构建模型
class MobilePriceClassifier(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(MobilePriceClassifier, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
self.fc2 = nn.Linear(hidden_size, output_size)
self.dropout = nn.Dropout(p=0.4)
self.bn = nn.BatchNorm1d(hidden_size)
def forward(self, x):
x = self.fc1(x)
x = self.bn(x)
x = torch.relu(x)
x = self.dropout(x)
x = self.fc2(x)
return x
- 训练模型
def train_model(model, dataloader, criterion, optimizer, num_epochs=25):
for epoch in range(num_epochs):
for inputs, labels in dataloader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
- 评估模型
def evaluate_model(model, dataloader):
model.eval()
correct = 0
total = 0
with torch.no_grad():
for inputs, labels in dataloader:
outputs = model(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = correct / total
return accuracy
5.2 优化思路
- 优化方法:将优化方法由SGD调整为Adam。
- 学习率:将学习率由1e-3调整为1e-4。
- 数据预处理:对数据进行标准化。
- 网络深度:增加网络深度,即增加网络参数量。
- 训练轮次:调整训练轮次。
- 批处理大小:设置
batch_size为2的次方,如4、8、16、32、64、128等。
更多推荐
所有评论(0)