南宁专业网站制作公司,php公司网站系统,长沙建立企业网站,wordpress 加速模型可视化与推理 知识点回顾#xff1a; 三种不同的模型可视化方法#xff1a;推荐torchinfo打印summary权重分布可视化进度条功能#xff1a;手动和自动写法#xff0c;让打印结果更加美观推理的写法#xff1a;评估模式 模型结构可视化 理解一个深度学习网络最重要的2点… 模型可视化与推理 知识点回顾 三种不同的模型可视化方法推荐torchinfo打印summary权重分布可视化进度条功能手动和自动写法让打印结果更加美观推理的写法评估模式 模型结构可视化 理解一个深度学习网络最重要的2点 1. 了解损失如何定义的知道损失从何而来----把抽象的任务通过损失函数量化出来 2. 了解参数总量即知道每一层的设计---层设计决定参数总量 为了了解参数总量我们需要知道层设计以及每一层参数的数量。下面介绍1几个层可视化工具 1. nn.model自带的方法 # nn.Module 的内置功能直接输出模型结构
print(model) 这是最基础、最简单的方法会直接打印模型对象它会输出模型的结构显示模型中各个层的名称和参数信息 # nn.Module 的内置功能返回模型的可训练参数迭代器
for name, param in model.named_parameters():print(fParameter name: {name}, Shape: {param.shape}) 可以将模型中带有weight的参数即权重提取出来并转为 numpy 数组形式对其计算统计分布并且绘制可视化图表 # 提取权重数据
import numpy as np
weight_data {}
for name, param in model.named_parameters():if weight in name:weight_data[name] param.detach().cpu().numpy()# 可视化权重分布
fig, axes plt.subplots(1, len(weight_data), figsize(15, 5))
fig.suptitle(Weight Distribution of Layers)for i, (name, weights) in enumerate(weight_data.items()):# 展平权重张量为一维数组weights_flat weights.flatten()# 绘制直方图axes[i].hist(weights_flat, bins50, alpha0.7)axes[i].set_title(name)axes[i].set_xlabel(Weight Value)axes[i].set_ylabel(Frequency)axes[i].grid(True, linestyle--, alpha0.7)plt.tight_layout()
plt.subplots_adjust(top0.85)
plt.show()# 计算并打印每层权重的统计信息
print(\n 权重统计信息 )
for name, weights in weight_data.items():mean np.mean(weights)std np.std(weights)min_val np.min(weights)max_val np.max(weights)print(f{name}:)print(f 均值: {mean:.6f})print(f 标准差: {std:.6f})print(f 最小值: {min_val:.6f})print(f 最大值: {max_val:.6f})print(- * 30) 对比 fc1.weight 和 fc2.weight 的统计信息 可以发现它们的均值、标准差、最值等存在差异。这反映了不同层在模型中的作用不同。权重统计信息可以为超参数调整提供参考。 2.torchsummary库的summary方法 # pip install torchsummary -i https://pypi.tuna.tsinghua.edu.cn/simple from torchsummary import summary
# 打印模型摘要可以放置在模型定义后面
summary(model, input_size(4,)) 该方法不显示输入层的尺寸因为输入的神经网是自己设置的所以不需要显示输入层的尺寸。但是在使用该方法时input_size(4,) 参数是必需的因为 PyTorch 需要知道输入数据的形状才能推断模型各层的输出形状和参数数量。 这是因为PyTorch 的模型在定义时是动态的它不会预先知道输入数据的具体形状。nn.Linear(4, 10) 只定义了 “输入维度是 4输出维度是 10”但不知道输入的批量大小和其他维度比如卷积层需要知道输入的通道数、高度、宽度等信息。----并非所有输入数据都是结构化数据 因此要生成模型摘要如每层的输出形状、参数数量必须提供一个示例输入形状让 PyTorch “运行” 一次模型从而推断出各层的信息。 summary 函数的核心逻辑是 1. 创建一个与 input_size 形状匹配的虚拟输入张量通常填充零 2. 将虚拟输入传递给模型执行一次前向传播但不计算梯度 3. 记录每一层的输入和输出形状以及参数数量 4. 生成可读的摘要报告 构建神经网络的时候
1. 输入层不需要写x多少个特征 输入层就有多少神经元
2. 隐藏层需要写从第一个隐藏层可以看出特征的个数
3. 输出层的神经元和任务有关比如分类任务输出层有3个神经元一个对应每个类别
可学习参数计算
1. Linear-1对应self.fc1 nn.Linear(4, 10)表明前一层有4个神经元这一层有10个神经元每2个神经元之间靠着线相连所有有4*10个权重参数10个偏置参数50个参数
2. relu层不涉及可学习参数可以把它和前一个线性层看成一层图上也是这个含义
3. Linear-3层对应代码 self.fc2 nn.Linear(10,3),10*3个权重参数3个偏置33个参数
总参数83个占用内存几乎为0
1.3 torchinfo库的summary方法 torchinfo 是提供比 torchsummary 更详细的模型摘要信息包括每层的输入输出形状、参数数量、计算量等。
# pip install torchinfo -i https://pypi.tuna.tsinghua.edu.cn/simple
from torchinfo import summary
summary(model, input_size(4, ))
进度条功能
tqdm这个库非常适合用在循环中观察进度。尤其在深度学习这种训练是循环的场景中。他最核心的逻辑如下 1. 创建一个进度条对象并传入总迭代次数。一般用with语句创建对象这样对象会在with语句结束后自动销毁保证资源释放。with是常见的上下文管理器这样的使用方式还有用with打开文件结束后会自动关闭文件。 2. 更新进度条通过pbar.update(n)指定每次前进的步数n适用于非固定步长的循环。 1.手动更新
from tqdm import tqdm # 先导入tqdm库
import time # 用于模拟耗时操作# 创建一个总步数为10的进度条
with tqdm(total10) as pbar: # pbar是进度条对象的变量名# pbar 是 progress bar进度条的缩写约定俗成的命名习惯。for i in range(10): # 循环10次对应进度条的10步time.sleep(0.5) # 模拟每次循环耗时0.5秒pbar.update(1) # 每次循环后进度条前进1步
from tqdm import tqdm
import time# 创建进度条时添加描述desc和单位unit
with tqdm(total5, desc下载文件, unit个) as pbar:# 进度条这个对象可以设置描述和单位# desc是描述在左侧显示# unit是单位在进度条右侧显示for i in range(5):time.sleep(1)pbar.update(1) # 每次循环进度1 unit 参数的核心作用是明确进度条中每个进度单位的含义使可视化信息更具可读性。在深度学习训练中常用的单位包括 epoch训练轮次遍历整个数据集一次。batch批次每次梯度更新处理的样本组。sample样本单个数据点 2.自动更新
from tqdm import tqdm
import time# 直接将range(3)传给tqdm自动生成进度条
# 这个写法我觉得是有点神奇的直接可以给这个对象内部传入一个可迭代对象然后自动生成进度条
for i in tqdm(range(3), desc处理任务, unitepoch):time.sleep(1)
for i in tqdm(range(3), desc处理任务, unit个)这个写法则不需要在循环中调用update()方法更加简洁。实际上这2种写法都随意选取这里都介绍下 # 用tqdm的set_postfix方法在进度条右侧显示实时数据如当前循环的数值、计算结果等
from tqdm import tqdm
import timetotal 0 # 初始化总和
with tqdm(total10, desc累加进度) as pbar:for i in range(1, 11):time.sleep(0.3)total i # 累加123...10pbar.update(1) # 进度1pbar.set_postfix({当前总和: total}) # 显示实时总和
完整代码
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import time
import matplotlib.pyplot as plt
from tqdm import tqdm # 导入tqdm库用于进度条显示# 设置GPU设备
device torch.device(cuda:0 if torch.cuda.is_available() else cpu)
print(f使用设备: {device})# 加载鸢尾花数据集
iris load_iris()
X iris.data # 特征数据
y iris.target # 标签数据# 划分训练集和测试集
X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42)# 归一化数据
scaler MinMaxScaler()
X_train scaler.fit_transform(X_train)
X_test scaler.transform(X_test)# 将数据转换为PyTorch张量并移至GPU
X_train torch.FloatTensor(X_train).to(device)
y_train torch.LongTensor(y_train).to(device)
X_test torch.FloatTensor(X_test).to(device)
y_test torch.LongTensor(y_test).to(device)class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.fc1 nn.Linear(4, 10) # 输入层到隐藏层self.relu nn.ReLU()self.fc2 nn.Linear(10, 3) # 隐藏层到输出层def forward(self, x):out self.fc1(x)out self.relu(out)out self.fc2(out)return out# 实例化模型并移至GPU
model MLP().to(device)# 分类问题使用交叉熵损失函数
criterion nn.CrossEntropyLoss()# 使用随机梯度下降优化器
optimizer optim.SGD(model.parameters(), lr0.01)# 训练模型
num_epochs 20000 # 训练的轮数# 用于存储每100个epoch的损失值和对应的epoch数
losses []
epochs []start_time time.time() # 记录开始时间# 创建tqdm进度条
with tqdm(totalnum_epochs, desc训练进度, unitepoch) as pbar:# 训练模型for epoch in range(num_epochs):# 前向传播outputs model(X_train) # 隐式调用forward函数loss criterion(outputs, y_train)# 反向传播和优化optimizer.zero_grad()loss.backward()optimizer.step()# 记录损失值并更新进度条if (epoch 1) % 200 0:losses.append(loss.item())epochs.append(epoch 1)# 更新进度条的描述信息pbar.set_postfix({Loss: f{loss.item():.4f}})# 每1000个epoch更新一次进度条if (epoch 1) % 1000 0:pbar.update(1000) # 更新进度条# 确保进度条达到100%if pbar.n num_epochs:pbar.update(num_epochs - pbar.n) # 计算剩余的进度并更新time_all time.time() - start_time # 计算训练时间
print(fTraining time: {time_all:.2f} seconds)# # 可视化损失曲线
# plt.figure(figsize(10, 6))
# plt.plot(epochs, losses)
# plt.xlabel(Epoch)
# plt.ylabel(Loss)
# plt.title(Training Loss over Epochs)
# plt.grid(True)
# plt.show()模型的推理
测试这个词在大模型领域叫做推理inference意味着把数据输入到训练好的模型的过程。 # 在测试集上评估模型此时model内部已经是训练好的参数了
# 评估模型
model.eval() # 设置模型为评估模式
with torch.no_grad(): # torch.no_grad()的作用是禁用梯度计算可以提高模型推理速度outputs model(X_test) # 对测试数据进行前向传播获得预测结果_, predicted torch.max(outputs, 1) # torch.max(outputs, 1)返回每行的最大值和对应的索引#这个函数返回2个值分别是最大值和对应索引参数1是在第1维度行上找最大值_ 是Python的约定表示忽略这个返回值所以这个写法是找到每一行最大值的下标# 此时outputs是一个tensorp每一行是一个样本每一行有3个值分别是属于3个类别的概率取最大值的下标就是预测的类别# predicted y_test判断预测值和真实值是否相等返回一个tensor1表示相等0表示不等然后求和再除以y_test.size(0)得到准确率# 因为这个时候数据是tensor所以需要用item()方法将tensor转化为Python的标量# 之所以不用sklearn的accuracy_score函数是因为这个函数是在CPU上运行的需要将数据转移到CPU上这样会慢一些# size(0)获取第0维的长度即样本数量correct (predicted y_test).sum().item() # 计算预测正确的样本数accuracy correct / y_test.size(0)print(f测试集准确率: {accuracy * 100:.2f}%)
模型的评估模式简单来说就是评估阶段会关闭一些训练相关的操作和策略 比如更新参数 正则化等操作确保模型输出结果的稳定性和一致性。
浙大疏锦行