pytorch开发基础 实操用torch.nn构建神经网络(附代码)
pytorch开发基础 实操用torch.nn构建神经网络(附代码
PyTorch的 torch.nn 是构建神经网络的核心工具,提供了各类“层”来搭建深度学习模型
一、pytorch内置模块
1、核心组件
- Layers(层):包含预定义的神经网络层,如 nn.Linear (全连接层)、 nn.Conv2d (卷积层)、 nn.MaxPool2d (池化层)、 nn.ReLU (激活层)等。每个层自带可学习的权重/偏差参数,调用时接收输入数据。
- Loss Functions(损失函数):提供常用损失计算函数,如 nn.MSELoss (均方误差,回归任务)、 nn.CrossEntropyLoss (交叉熵,分类任务)等,用于计算预测与真实值的差距,辅助参数更新。
- Utilities(工具):包含模型构建工具,如 nn.Sequential (按顺序组合多个层)、 nn.Module (所有网络模块的基类,用于自定义层/模型)。
- Normalization/Regularization Layers(归一化/正则化层):如 nn.Dropout (防止过拟合)、 nn.BatchNorm1d/2d (批量归一化,提升模型性能)。
- Activation Functions(激活函数):如 nn.Sigmoid 、 nn.Tanh 、 nn.Softmax 等,用于引入非线性,让模型学习复杂模式。
2、nn.Linear层
nn.Linear 是全连接层/线性层,用于构建网络的线性部分,构造函数需指定两个参数:
- in_features :输入特征数
- out_features :输出特征数
计算公式
y=xAT+b y = xA^T + b y=xAT+b
其中:
- x:输入张量,形状为 (batch_size, input_features)
- A:权重矩阵,形状为 (input_features, output_features)
- b:偏差向量,形状为 (output_features, )
示例代码
import torch
import torch.nn as nn
#创建线性层,输入特征数为3,输出特征数为2,即纬度
linear_layer = nn.Linear(3,2)
#输入样本
inputs = torch.tensor([[1.0,2.0,3.0],[4.0,5.0,6.0]])
#传入值给线性层向前计算
outputs = linear_layer(inputs)
print(outputs)
#输出:形状为(2,2),包含2个样本的2个输出特征
3、nn.Sigmoid激活函数
nn.Sigmoid 是将任意实数映射到0~1范围的激活函数,数学表达式为:
sigmoid(x)=1/(1+exp(−x)) \text{sigmoid}(x) = 1 / (1 + \exp(-x)) sigmoid(x)=1/(1+exp(−x))
常用于:
- 隐藏层引入非线性
- 二分类任务的输出层(将结果映射为概率)
示例代码
import torch
import torch.nn as nn
# 输入张量
x = torch.tensor([2.0, -1.0, 0.5])
# 定义Sigmoid激活函数
sigmoid = nn.Sigmoid()
# 前向计算
output = sigmoid(x)
print(output)
# 输出:tensor([0.8808, 0.2689, 0.6225])
4、nn.BCELoss损失函数
nn.BCELoss 是二元交叉熵损失函数,用于二分类问题,计算模型输出(概率)与真实标签的差异。
注意事项
- 输入 output 需是0~1的概率值(通常由Sigmoid输出)
- output 与 target 形状需一致
- 可使用 BCEWithLogitsLoss (内部自动结合Sigmoid)替代
示例代码
import torch
import torch.nn as nn
# 创建BCELoss对象
criterion = nn.BCELoss()
# 模型输出(样本属于正类的概率)
output = torch.tensor([0.8, 0.2, 0.4])
# 真实标签(1=正类,0=负类)
target = torch.tensor([1, 0, 1], dtype=torch.float32)
# 计算损失
loss = criterion(output, target)
print(loss)
# 输出:tensor(0.4542)
二、torch.optim优化器
torch.optim 是PyTorch中实现优化算法的模块,用于在模型训练中更新参数以最小化损失函数,核心是 Optimizer 基类(所有优化器的父类)。
1、核心功能
- 接收模型参数的可迭代对象作为输入
- 支持配置学习率调度、权重衰减等行为
2、常见优化器
- SGD优化器:最基础的优化器,根据每个样本的梯度更新模型参数。
- Adam优化器:结合AdaGrad和RMSProp思想的自适应学习率优化器,根据梯度的一阶矩、二阶矩估计更新参数,常用于Transformer等模型训练。
- torch.optim 提供学习率调度工具,可根据训练进度动态调整学习率,提升训练效果。
接下来的实操构建神经网络阶段会用到
三、训练、验证和测试过程
在PyTorch中,通常将数据集划分为训练集、验证集、测试集,分别用于训练模型、调整参数、评估性能,流程如下:
1、数据预处理
对数据进行归一化、计算均值/标准差等处理,再划分成训练集、验证集、测试集。
2、定义模型
通过继承 torch.nn.Module 类,实现 init (定义层)和 forward (前向传播)方法,构建模型架构。
3、定义损失函数和优化器
- 损失函数:使用PyTorch内置函数(如 nn.CrossEntropyLoss 分类任务、 nn.MSELoss 回归任务)。
- 优化器:选择合适的优化器(如 torch.optim.SGD 、 torch.optim.Adam ),传入模型参数与学习率。
用法:
loss_fn = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
4、训练模型(核心步骤)
训练过程在主循环中执行,每个训练批次包含以下步骤:
- 清空梯度:调用 optimizer.zero_grad() 清空之前的梯度(避免累积)。
- 正向传播:输入数据到模型,调用 forward 计算预测值: output = model(input) 。
- 计算损失:将预测值与真实标签传入损失函数: loss = loss_fn(output, target) 。
- 反向传播:调用 loss.backward() 计算参数梯度。
- 更新权重:调用 optimizer.step() 根据梯度更新模型参数。
5、验证模型
每个训练周期结束后,在验证集上测试模型,检查是否过拟合,并调整超参数(如学习率)优化模型。
6、测试模型
训练、验证完成后,在未参与训练/验证的测试集上评估模型性能,得到公正的最终结果。
7、保存和加载模型
使用 torch.save 保存模型, torch.load 加载模型,便于后续预测或继续训练。
四、用PyTorch实现神经网络(实操)
1、实现单层感知机
通过 torch.nn.Module 自定义单层感知机,实现二分类任务。
import torch
import torch.nn as nn
import torch.optim as optim
# 定义感知机模型
class Perceptron(nn.Module):
#继承父类nn.Module
def __init__(self, input_size):
super(Perceptron, self).__init__()#继承父类
self.linear = nn.Linear(input_size, 1) # 继承父类的线性层函数
self.sigmoid = nn.Sigmoid() # 继承父类Sigmoid激活函数
def forward(self, x):
out = self.linear(x)
out = self.sigmoid(out)
return out
# 定义输入数据
X = torch.tensor([[0, 1], [1, 0], [1, 1], [0, 0]], dtype=torch.float32)
y = torch.tensor([[1], [1], [0], [0]], dtype=torch.float32)
# 初始化模型
input_size = X.shape[1]
model = Perceptron(input_size)
print(model)
# 定义优化器和损失函数
criterion = nn.BCELoss() # 二分类交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.1) # SGD优化器
# 训练模型
num_epochs = 1000
for epoch in range(num_epochs):
# 前向传播
outputs = model(X)
loss = criterion(outputs, y)
# 反向传播和优化
optimizer.zero_grad() # 梯度清零
loss.backward() # 反向传播
optimizer.step() # 更新参数
# 每100个epoch打印一次损失
if (epoch+1) % 100 == 0:
print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, loss.item()))
# 测试模型
with torch.no_grad(): # 禁用梯度计算
predicted = model(X)
predicted = torch.round(predicted) # 输出舍入为0或1
accuracy = (predicted == y).sum().item() / y.size(0)
print('Accuracy: {:.2f}%'.format(accuracy * 100))
运行结果
Epoch [200/1000], Loss: 0.6935
Epoch [300/1000], Loss: 0.6933
Epoch [400/1000], Loss: 0.6932
Epoch [500/1000], Loss: 0.6932
Epoch [600/1000], Loss: 0.6932
Epoch [700/1000], Loss: 0.6932
Epoch [800/1000], Loss: 0.6931
Epoch [900/1000], Loss: 0.6931
Epoch [1000/1000], Loss: 0.6931
Accuracy: 25.00%
从这个结果能看出,模型准确率仅 25%,但核心问题是感知机的线性局限性—— 异或问题本身线性不可分,单层感知机无论怎么训练,都无法找到能正确分割所有样本的线性边界,最终只能随机猜测,所以需要多层感知机(神经网络的子集)来解决
2、手动实现简单神经网络(含前向/反向传播)
自定义神经网络类,手动实现前向传播、反向传播和参数更新。
代码实现
import torch
class PyTorchNeuralNetwork:#定义神经网络类
def __init__(self, input_size, hidden_size, output_size):
#初始化神经网络参数
self.input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
# 初始化权重和偏置(requires_grad=True表示需要计算梯度)
self.W1 = torch.randn(self.input_size, self.hidden_size, requires_grad=True)#符合正态分布的初始参数
self.b1 = torch.zeros(1, self.hidden_size, requires_grad=True)
self.W2 = torch.randn(self.hidden_size, self.output_size, requires_grad=True)
self.b2 = torch.zeros(1, self.output_size, requires_grad=True)
def forward(self, X):
# 前向传播
self.z1 = torch.mm(X, self.W1) + self.b1#线性层
self.a1 = torch.tanh(self.z1) # 隐藏层激活函数(tanh)
self.z2 = torch.mm(self.a1, self.W2) + self.b2
self.a2 = torch.sigmoid(self.z2) # 输出层激活函数(Sigmoid)
return self.a2
def backward(self, X, y, learning_rate):
#反向传播
m = X.shape[0] # 样本数量
# 计算输出层的误差
#代码用 MSE(均方误差)处理
dz2 = self.a2 - y
dW2 = (1/m) * torch.mm(self.a1.T, dz2)
db2 = (1/m) * torch.sum(dz2, dim=0, keepdim=True)
# 计算隐藏层的误差
dz1 = torch.mm(dz2, self.W2.T) * (1 - self.a1**2)
dW1 = (1/m) * torch.mm(X.T, dz1)
db1 = (1/m) * torch.sum(dz1, dim=0)
# 更新权重和偏置
self.W2.data -= learning_rate * dW2
self.b2.data -= learning_rate * db2
self.W1.data -= learning_rate * dW1
self.b1.data -= learning_rate * db1
def train(self, X, y, epochs, learning_rate):
for epoch in range(epochs):
# 前向传播
output = self.forward(X)
# 反向传播
self.backward(X, y, learning_rate)
# 计算损失(均方误差)
loss = torch.mean((y - output) ** 2)
# 每1000个epoch打印一次损失
if epoch % 1000 == 0:
print(f"Epoch {epoch}: Loss = {loss.item()}")
# Sigmoid函数(也可直接用torch.sigmoid)
def sigmoid(self, x):
return 1 / (1 + torch.exp(-x))
# 实例化模型并训练
input_size = 15
hidden_size = 10
output_size = 5
pytorch_nn = PyTorchNeuralNetwork(input_size, hidden_size, output_size)
# 生成训练数据
X = torch.randn(100, input_size)
y = torch.randint(0, 2, size=(100, output_size), dtype=torch.float32)
# 训练参数
epochs = 10000
#基于随机权重比较合适的学习率,实际情况需要自行调整
learning_rate = 0.3
# 训练模型
pytorch_nn.train(X, y, epochs, learning_rate)
# 预测示例
input_data_torch = torch.randn(1, input_size)
output_torch = pytorch_nn.forward(input_data_torch)
print("预测结果:", output_torch)
我做了比较详细的注释,供参考学习
原代码会输出类似下文的内容
由于权重和偏置是随机数,所以预测内容和损失不确定,但都会随着迭代次数增多逐渐下降
Epoch 0: Loss = 0.36677706241607666
Epoch 1000: Loss = 0.08712747693061829
Epoch 2000: Loss = 0.0615965873003006
Epoch 3000: Loss = 0.05042863264679909
Epoch 4000: Loss = 0.04471873864531517
Epoch 5000: Loss = 0.04120061919093132
Epoch 6000: Loss = 0.03878163546323776
Epoch 7000: Loss = 0.03701581060886383
Epoch 8000: Loss = 0.03556859865784645
Epoch 9000: Loss = 0.03432784229516983
预测结果: tensor([[2.6203e-08, 1.4003e-12, 1.0000e+00, 9.9853e-01, 2.1654e-09]],
grad_fn=<SigmoidBackward0>)
可见模型损失函数逐渐变小,且训练后预测了结果
3、用torch.nn实现简单神经网络
通过PyTorch构建用于行业云服务用量分类的神经网络模型,包含模型定义、训练、评估全流程。
- 导入依赖依赖库
import torch
import torch.nn as nn
import torch.optim as optim
#使用了torch.nn内置函数,例如线性层Linear,ReLU激活函数等
#定义云服务用量预测模型
class CloudServiceUsageModel(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super(CloudServiceUsageModel, self).__init__()#继承父类初始化
#输入层→隐藏层(线性层+ReLU激活)
self.fc1 = nn.Linear(input_size, hidden_size)
self.relu = nn.ReLU()
#隐藏层→输出层(线性层)
self.fc2 = nn.Linear(hidden_size, num_classes)
def forward(self, x):
#前向传播
out = self.fc1(x)#隐藏层线性层
out = self.relu(out)#隐藏层非线性层
out = self.fc2(out)#到输出层
return out
#准备数据
input_size = 10 #输入特征维度
hidden_size = 5 #隐藏层神经元数
num_classes = 2 #分类类别数
learning_rate = 0.001#学习率,可根据情况自行调整
num_epochs = 1500 #训练轮数
#生成示例数据(100条样本)
X = torch.randn(100, input_size)#符合正态分布的随机数据
Y = torch.randint(0, num_classes, (100,)) #随机生成标签
#划分训练集(80%)和测试集(20%)
train_size = int(0.8 * len(X))
train_X, test_X = X[:train_size], X[train_size:]#切片
train_Y, test_Y = Y[:train_size], Y[train_size:]
#初始化模型,即实例化
model = CloudServiceUsageModel(input_size, hidden_size, num_classes)
#损失函数:交叉熵损失(适用于分类任务)
criterion = nn.CrossEntropyLoss()
#优化器:Adam
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
for epoch in range(num_epochs):
#前向传播:计算预测值
outputs = model(train_X)
#计算损失
loss = criterion(outputs, train_Y)
#反向传播+参数更新
optimizer.zero_grad() #清空梯度
loss.backward() #反向传播计算梯度
optimizer.step() #更新参数
#每10轮打印训练信息
if (epoch + 1) % 100 == 0:
print(f'Epoch {epoch+1}/{num_epochs}, Loss: {loss.item()}')#格式化字符串打印输出
with torch.no_grad(): #评估阶段不计算梯度,用with避免意外修改模型参数
outputs = model(test_X)
#使用”_“ 接收max第一个返回值,但忽略无关数据,如第一个返回值
_, predicted = torch.max(outputs.data, 1) #取预测概率最大的类别
#计算测试集准确率
accuracy = (predicted == test_Y).sum().item() / len(test_Y)
print(f'Test Accuracy: {accuracy}')
这里使用的学习率和迭代次数可以自行修改,如果迭代次数过大会过拟合损失函数很小,但是准确率低,比如:
Epoch 2000/10000, Loss: 0.11056555807590485
Epoch 3000/10000, Loss: 0.047184959053993225
Epoch 4000/10000, Loss: 0.018245236948132515
Epoch 5000/10000, Loss: 0.007836421951651573
Epoch 6000/10000, Loss: 0.0035645291209220886
Epoch 7000/10000, Loss: 0.00182446651160717
Epoch 8000/10000, Loss: 0.0007243022555485368
Epoch 9000/10000, Loss: 0.0003837581316474825
Epoch 10000/10000, Loss: 0.0002305546950083226
Test Accuracy: 0.35
如果学习率小,迭代次数少就会欠拟合,完全没找到规律,比如损失函数很大,准确率也低:
Epoch 10/100, Loss: 0.7022197842597961
Epoch 20/100, Loss: 0.6955064535140991
Epoch 30/100, Loss: 0.6891571879386902
Epoch 40/100, Loss: 0.6826779246330261
Epoch 50/100, Loss: 0.6764296889305115
Epoch 60/100, Loss: 0.6703445315361023
Epoch 70/100, Loss: 0.6642844080924988
Epoch 80/100, Loss: 0.6579297184944153
Epoch 90/100, Loss: 0.6512966752052307
Epoch 100/100, Loss: 0.6450014710426331
Test Accuracy: 0.25
如果按照上文代码参数,应该是类似下文的输出
Epoch 700/1500, Loss: 0.3329385221004486
Epoch 800/1500, Loss: 0.3078838884830475
Epoch 900/1500, Loss: 0.28730684518814087
Epoch 1000/1500, Loss: 0.2641219198703766
Epoch 1100/1500, Loss: 0.24512812495231628
Epoch 1200/1500, Loss: 0.22094109654426575
Epoch 1300/1500, Loss: 0.20565827190876007
Epoch 1400/1500, Loss: 0.1938382387161255
Epoch 1500/1500, Loss: 0.1839798539876938
Test Accuracy: 0.6
这样我们就基于随机数据和torch.nn完成了一个简易神经网络啦,是不是很神奇呢喵~
五、源代码常用模块
后续代码中高频使用的工具模块,提前介绍便于快速理解。
1、nn.Parameter 类
PyTorch中标记需优化参数的核心类,作用:
- 标记可优化参数:将张量包装为 nn.Parameter 后,会被自动加入模型的 parameters() 列表,供优化器更新。
- 参数管理:支持访问/修改参数的数值、形状、设备等信息。
示例:
weight = nn.Parameter(torch.ones(dim)) # 将张量标记为可优化参数
2、typing 模块
Python 3.5+引入的类型提示工具,用于静态类型检查、增强代码可读性。
- 核心作用
- 避免运行时参数/返回值类型不匹配;
- 作为代码文档,明确入参/返回值类型;
- 仅提示,不影响程序运行。
- 常用类型
| 类型 | 说明 |
|---|---|
| int/long/float | 整数/长整型/浮点型 |
| bool/str | 布尔型/字符串类型 |
| List/Tuple/Dict/Set | 列表/元组/字典/集合 |
| Iterable/Iterator | 可迭代/迭代器类型 |
| Generator | 生成器类型 |
- 特殊类型
- Any :任意类型(跳过类型检查);
- Optional[T] :可选类型( T 或 None );
- TypedDict :类型化字典(指定键值对的类型)。
3、logging 模块
Python标准库的日志管理工具,用于记录程序运行信息(替代 print ,更灵活可控)。
- 日志级别(从低到高)
debug (调试信息)、 info (运行信息)、 warning (警告)、 error (错误)、 critical (严重错误)。
- 示例:设置级别为 warning 时,仅输出 warning/error/critical 级别的日志。
- 核心功能
- 多目标输出:日志可输出到控制台、文件、网络等;
- 自定义格式:支持添加日期、时间、日志级别等;
- 日志回滚:自动切割/备份超大日志文件;
- 多线程安全:支持多线程环境下的日志记录;
- 配置文件管理:日志配置与代码解耦。
- 常用函数示例
import logging
# 基础配置(级别、格式)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger() # 获取logger对象
# 输出不同级别日志
logger.debug("调试信息")
logger.info("Reloaded model from ./model") # 示例输出:INFO:root:Reloaded model...
logger.warning("警告信息")
logger.error("错误信息")
logger.exception("带堆栈的错误信息") # 自动记录异常堆栈
4、dataclasses 模块
Python 3.7+引入的数据类工具,通过装饰器 @dataclass 简化数据类的定义(自动生成 init / repr 等方法)。
- 核心特点
- 自动生成方法: init (初始化)、 repr (打印)、 eq (比较)等;
- 类型提示:支持定义属性的类型;
- 不可变性:指定 frozen=True 可创建不可变数据类;
- 继承性:支持继承其他数据类。
- 示例
from dataclasses import dataclass
@dataclass
class Person:
name: str # 字符串类型
age: int # 整数类型
profession: str # 职业类型
# 自动生成__init__,直接实例化
p = Person(name="Alice", age=25, profession="Engineer")
print(p)
# 自动生成__repr__:Person(name='Alice', age=25, profession='Engineer')
5、Fire 模块
Python的命令行接口(CLI)生成工具,自动将Python对象(函数/类)转换为命令行工具(无需手动解析参数)。
- 核心功能
- 自动生成CLI:函数/类直接转为命令行接口;
- 子命令支持:多函数/方法自动转为子命令;
- 自动生成帮助文档: --help 查看参数说明;
- 动态类型转换:命令行输入自动转为Python类型;
- 直接调用任意Python对象:函数、类、库等。
- 示例对比
使用 Fire (简洁)
import fire
def greet(name="World"):
print(f"Hello, {name}!")
if __name__== "__main__":
fire.Fire()
不使用 Fire (手动解析)
import argparse
def greet(name="World"):
print(f"Hello, {name}!")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-name", type=str,default="World")
args = parser.parse_args()
greet(args.name)
- 命令行调用
# 使用Fire的情况:直接传参
python script.py --name Alice
# 输出:Hello, Alice!
# 查看帮助文档
python script.py --help
以上就是全部内容啦,如果觉得神经网络很好玩,内容很有意思的话,别忘了关注,赏点小鱼干喵
更多推荐
所有评论(0)