实现第一个神经网络
PyTorch - 实现你的第一个神经网络
Section titled “PyTorch - 实现你的第一个神经网络”PyTorch 擅长创建和训练神经网络。在本章中,我们将指导你构建一个带有单个隐藏层的简单神经网络,用于执行二分类任务(预测两种结果之一)。
我们将按照以下步骤使用 PyTorch 实现我们的第一个神经网络:
步骤 1:导入必要的库
Section titled “步骤 1:导入必要的库”首先,我们需要导入 PyTorch 库及其神经网络模块(nn)。
import torchimport torch.nn as nn尽早设置计算设备(CPU 或 GPU)是一个好的习惯。这能让你的代码更具可移植性。
# 判断是否有 GPU 可用,否则使用 CPUdevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')print(f'Using device: {device}')步骤 2:定义网络架构和超参数
Section titled “步骤 2:定义网络架构和超参数”接下来,我们定义输入层、隐藏层和输出层的大小,以及训练的批量大小。
# 定义网络参数n_in, n_h, n_out, batch_size = 10, 5, 1, 10 # 输入特征数量, 隐藏层单元数量, 输出单元数量, 批量大小步骤 3:创建虚拟数据
Section titled “步骤 3:创建虚拟数据”神经网络通过将输入数据映射到相应的目标输出进行学习。我们将创建一些随机的输入数据(x)和二分类目标数据(y)。
# 创建虚拟输入和目标张量(数据)# 输入数据: 随机值, 形状为 (批量大小, 输入特征数量)x = torch.randn(batch_size, n_in, device=device)
# 目标数据: 二进制值 (0 或 1), 形状为 (批量大小, 输出单元数量)# 对于二分类任务,目标值应为浮点类型以用于损失计算。y = torch.tensor([ [1.0], [0.0], [0.0], [1.0], [1.0], [1.0], [0.0], [0.0], [1.0], [1.0]], device=device)注意:我们将数据移动到所选的 device 上,以确保计算按预期进行。
步骤 4:定义模型
Section titled “步骤 4:定义模型”我们将使用 nn.Sequential 创建一个简单的前馈网络。它由一个线性层、一个 ReLU 激活函数、另一个线性层组成,此处没有最后的激活函数,因为我们将使用 BCEWithLogitsLoss,它在数值上更稳定。
# 创建一个序列模型model = nn.Sequential( nn.Linear(n_in, n_h), # 第一个线性层(从输入到隐藏层) nn.ReLU(), # ReLU 激活函数 nn.Linear(n_h, n_out) # 第二个线性层(从隐藏层到输出)).to(device) # 将模型移动到选定的设备
print("Model architecture:")print(model)在使用 nn.BCEWithLogitsLoss 时,建议 nn.Linear(n_h, n_out) 之后不加最终的 nn.Sigmoid() 激活函数,因为它以数值上更稳定的方式结合了 Sigmoid 激活和二元交叉熵损失(Binary Cross Entropy loss)。
步骤 5:定义损失函数和优化器
Section titled “步骤 5:定义损失函数和优化器”对于二分类,nn.BCEWithLogitsLoss 是一个合适的损失函数。我们将使用随机梯度下降(SGD)作为我们的优化器。Adam 也是一个非常流行且通常有效的选择。
# 构建损失函数# BCEWithLogitsLoss 适用于二分类,并期望模型输出原始 logits(对数几率)。criterion = nn.BCEWithLogitsLoss()
# 构建优化器(此处为随机梯度下降)# Adam 也是一个非常流行且有效的优化器:torch.optim.Adam(model.parameters(), lr=0.01)optimizer = torch.optim.SGD(model.parameters(), lr=0.01)步骤 6:训练模型(训练循环)
Section titled “步骤 6:训练模型(训练循环)”训练过程包括多次迭代(轮次,epochs)数据,执行前向传播,计算损失,执行反向传播(backward pass),并更新模型的权重。
# 训练循环(梯度下降)epochs = 100 # 增加轮次以更好地演示收敛print("\nStarting training...")for epoch in range(epochs): # 前向传播:通过将 x 传递给模型计算预测的 y y_pred_logits = model(x)
# 计算并打印损失 # y_pred_logits 是原始分数(logits),criterion 会隐式处理 sigmoid 激活。 loss = criterion(y_pred_logits, y) if (epoch + 1) % 10 == 0 or epoch == 0: # 每 10 个轮次和第一个轮次打印一次 print(f'Epoch: {epoch+1}/{epochs}, Loss: {loss.item():.4f}')
# 清零梯度:在计算新梯度之前清除之前的梯度。 # 如果不清零梯度,它们将累积,这通常不是期望的行为。 optimizer.zero_grad()
# 反向传播:计算损失相对于模型参数的梯度。 loss.backward()
# 更新权重:根据计算出的梯度调整模型参数。 optimizer.step()
print("Training finished.")训练循环中的关键步骤:
- 前向传播:输入数据通过网络以获得预测结果。
- 损失计算:量化预测结果与实际目标值之间的差异。
- 清零梯度:清除前一次迭代的梯度。
- 反向传播:计算损失相对于每个模型参数的梯度。
- 优化器更新:使用计算出的梯度更新模型参数(权重)以最小化损失。
步骤 7:观察输出
Section titled “步骤 7:观察输出”在训练过程中,你会看到损失通常会下降,这表明模型正在学习。具体的损失值会因随机初始化而有所不同。
# Example Output (values will differ due to random initialization):# Using device: cuda (or cpu)# Model architecture:# Sequential(# (0): Linear(in_features=10, out_features=5, bias=True)# (1): ReLU()# (2): Linear(in_features=5, out_features=1, bias=True)# )## Starting training...# Epoch: 1/100, Loss: 0.7512# Epoch: 10/100, Loss: 0.7225# Epoch: 20/100, Loss: 0.6953# Epoch: 30/100, Loss: 0.6698# Epoch: 40/100, Loss: 0.6459# Epoch: 50/100, Loss: 0.6235# Epoch: 60/100, Loss: 0.6025# Epoch: 70/100, Loss: 0.5829# Epoch: 80/100, Loss: 0.5645# Epoch: 90/100, Loss: 0.5472# Epoch: 100/100, Loss: 0.5310# Training finished.本示例演示了一个基础的神经网络。在实际应用中,你会使用更大的数据集、可能更复杂的架构,以及数据归一化、验证集和更复杂的超参数调优等技术。如需进一步学习,请查阅 PyTorch 关于 torch.nn、torch.optim 以及使用 Dataset 和 DataLoader 进行数据处理的文档。