目录
一、模型可视化方法
1. 三种主流可视化方案对比
2. torchinfo使用详解
3. 权重分布可视化
二、进度条实现方案
1. 手动实现进度条
2. 自动进度条(推荐)
3. 训练循环集成示例
三、模型推理规范写法
1. 标准推理流程
2. 生产环境推理优化
四、综合应用示例
完整训练-验证-测试流程
五、常见问题解决方案
1. 可视化相关
2. 推理相关
六、扩展技巧
1. 高级进度条功能
2. 模型结构导出
方法 | 工具/库 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
torchinfo | torchinfo.summary() |
轻量级、参数统计全 | 无结构图 | 快速调试 |
权重分布 | matplotlib 直方图 |
直观显示数值分布 | 需手动实现 | 权重分析 |
结构可视化 | torchviz /Netron |
图形化展示 | 依赖外部工具 | 架构设计 |
from torchinfo import summary
# 基本用法
model = MyCNN()
summary(model, input_size=(16, 3, 224, 224)) # batch,channels,height,width
# 输出示例
"""
=================================================================
Layer (type:depth-idx) Output Shape Param #
=================================================================
CNN [16, 10] --
├─Conv2d: 1-1 [16, 32, 222, 222] 896
├─ReLU: 1-2 [16, 32, 222, 222] --
├─MaxPool2d: 1-3 [16, 32, 111, 111] --
├─Flatten: 1-4 [16, 394272] --
├─Linear: 1-5 [16, 10] 3,942,730
=================================================================
Total params: 3,943,626
Trainable params: 3,943,626
Non-trainable params: 0
=================================================================
"""
import matplotlib.pyplot as plt
def plot_weights(model):
weights = []
for name, param in model.named_parameters():
if 'weight' in name:
weights.append(param.data.cpu().numpy().flatten())
plt.figure(figsize=(10, 5))
plt.hist(np.concatenate(weights), bins=50)
plt.title("Weight Distribution")
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.show()
# 训练前后对比
plot_weights(untrained_model)
plot_weights(trained_model)
def manual_progress(iterable, total=None):
total = total or len(iterable)
for i, item in enumerate(iterable, 1):
percent = i / total * 100
bar = '■' * int(percent//2) + ' ' * (50 - int(percent//2))
print(f"\r[{bar}] {percent:.1f}%", end='')
yield item
print() # 换行
# 使用示例
for batch in manual_progress(train_loader):
train_batch(batch)
from tqdm import tqdm
# 基本用法
for epoch in tqdm(range(epochs), desc="Training"):
for batch in tqdm(train_loader, leave=False, desc=f"Epoch {epoch}"):
train_batch(batch)
# 自定义样式
with tqdm(total=len(dataset),
bar_format="{l_bar}{bar:20}{r_bar}",
colour='green') as pbar:
for data in dataloader:
process(data)
pbar.update(len(data))
def train_with_progress(model, loader, epochs):
model.train()
with tqdm(total=epochs * len(loader)) as pbar:
for epoch in range(epochs):
for batch in loader:
loss = train_step(model, batch)
pbar.set_postfix(loss=f"{loss:.4f}")
pbar.update(1)
def inference(model, dataloader, device='cuda'):
model.eval() # 关键:切换到评估模式
predictions = []
with torch.no_grad(): # 禁用梯度计算
for inputs in tqdm(dataloader, desc="Inferencing"):
inputs = inputs.to(device)
outputs = model(inputs)
preds = outputs.argmax(dim=1)
predictions.extend(preds.cpu().numpy())
model.train() # 恢复训练模式(可选)
return predictions
@torch.inference_mode() # PyTorch 1.9+ 更高效
def optimized_inference(model, inputs):
model.eval()
inputs = inputs.to(next(model.parameters()).device)
return model(inputs)
# 使用TorchScript加速
traced_model = torch.jit.trace(model, example_input)
traced_model.save("deploy_model.pt")
def full_pipeline(model, train_loader, val_loader, test_loader, epochs=10):
# 初始可视化
summary(model, input_size=next(iter(train_loader))[0].shape)
plot_weights(model)
# 训练阶段
optimizer = torch.optim.Adam(model.parameters())
for epoch in tqdm(range(epochs), desc="Epochs"):
model.train()
for batch in tqdm(train_loader, leave=False, desc="Training"):
inputs, targets = batch
outputs = model(inputs)
loss = F.cross_entropy(outputs, targets)
loss.backward()
optimizer.step()
optimizer.zero_grad()
# 验证阶段
model.eval()
val_loss, val_acc = evaluate(model, val_loader)
tqdm.write(f"Epoch {epoch}: Val Loss={val_loss:.4f}, Acc={val_acc:.2f}%")
# 最终测试
test_results = inference(model, test_loader)
print(f"\nFinal Test Accuracy: {100 * sum(test_results)/len(test_results):.2f}%")
# 权重分析
plot_weights(model)
问题 | 解决方案 |
---|---|
torchinfo报维度错误 | 检查input_size 与真实输入是否匹配 |
权重分布图显示异常 | 添加plt.clf() 清除之前绘图 |
进度条重复打印 | 设置leave=False 或使用tqdm.write() |
问题 | 解决方案 |
---|---|
推理结果不一致 | 确保model.eval() 和torch.no_grad() |
内存不足 | 减小batch_size 或使用del 及时释放张量 |
速度慢 | 启用torch.inference_mode() 或使用TorchScript |
# 多进度条嵌套
with tqdm(total=100, desc="Main") as pbar_main:
for i in range(10):
with tqdm(total=10, desc=f"Sub {i}", leave=False) as pbar_sub:
for j in range(10):
time.sleep(0.1)
pbar_sub.update(1)
pbar_main.update(1)
# 导出为ONNX格式
torch.onnx.export(
model,
torch.randn(1, 3, 224, 224),
"model.onnx",
input_names=["input"],
output_names=["output"]
)
# 使用Netron可视化
import netron
netron.start("model.onnx")
@浙大疏锦行