<think>我们正在编写一个完整的模块4,该模块用于精简版评估与可视化(仅保留准确率和损失曲线)。我们已经有了一个函数`evaluate_model`,它接受模型、测试数据加载器和训练历史,然后进行评估并绘制图表。现在,我们需要为这个模块提供一个在JupyterNotebook中使用的示例。在JupyterNotebook中,我们通常会加载之前训练好的模型和训练历史,然后使用测试数据加载器来运行评估。因此,我们需要一个示例代码,展示如何加载模型、准备测试数据加载器,并调用`evaluate_model`函数。注意:在模块3中,训练结束后我们已经保存了模型和训练历史到一个pth文件。因此,在Jupyter示例中,我们需要先加载这个保存的模型和训练历史。步骤:1.加载之前保存的模型和训练历史。2.准备测试数据加载器(这里假设测试数据加载器已经准备好,或者需要从数据集中创建)。3.调用`evaluate_model`函数进行评估。下面是一个完整的JupyterNotebook代码示例,包括必要的导入和函数定义(但注意,我们只展示模块4的代码,并且假设模块4的代码已经在一个单独的.py文件中定义,或者在Notebook中已经定义了`evaluate_model`函数)。但是,由于我们是在一个Notebook中,我们可以将模块4的代码定义在一个代码单元格中,然后在另一个单元格中运行示例。为了清晰,我们将模块4的代码(包括`plot_training_history`和`evaluate_model`)放在一个单元格,然后下一个单元格是使用示例。但是,根据要求,我们只撰写使用示例的代码,并假设模块4的函数已经定义。因此,我们撰写如下:</think># Jupyter Notebook 使用示例:模型评估与可视化
以下是一个完整的 Jupyter Notebook 使用示例,展示如何加载训练好的模型,执行评估并可视化训练历史:
```python
# 模块4:精简版评估与可视化(仅保留准确率和损失曲线)
# 在 Jupyter Notebook 中运行此代码
import torch
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import classification_report
from tqdm import tqdm
import os
import ipywidgets as widgets
from IPython.display import display, clear_output
import json
# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
def plot_training_history(history, save_path='training_history.png'):
"""
绘制训练历史折线图(仅准确率和损失曲线)
参数:
history (dict): 包含训练历史的字典
save_path (str): 图表保存路径
"""
plt.figure(figsize=(12, 8))
# 1. 损失曲线
plt.subplot(2, 1, 1)
plt.plot(history['train_loss'], 'b-', linewidth=2, label='训练损失')
plt.plot(history['val_loss'], 'r-', linewidth=2, label='验证损失')
plt.title('损失曲线', fontsize=14, fontweight='bold')
plt.xlabel('Epoch', fontsize=12)
plt.ylabel('损失', fontsize=12)
plt.legend(fontsize=12, loc='best')
plt.grid(True, linestyle='--', alpha=0.7)
# 2. 准确率曲线
plt.subplot(2, 1, 2)
plt.plot(history['train_acc'], 'b-', linewidth=2, label='训练准确率')
plt.plot(history['val_acc'], 'r-', linewidth=2, label='验证准确率')
plt.title('准确率曲线', fontsize=14, fontweight='bold')
plt.xlabel('Epoch', fontsize=12)
plt.ylabel('准确率', fontsize=12)
plt.ylim(0, 1)
plt.legend(fontsize=12, loc='best')
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
# 确保目录存在
os.makedirs(os.path.dirname(save_path), exist_ok=True)
plt.savefig(save_path, dpi=150, bbox_inches='tight')
plt.close() # 关闭图表避免在Jupyter中显示两次
print(f"训练历史图表已保存为 {save_path}")
# 在Notebook中显示图表
plt.figure(figsize=(12, 8))
plt.subplot(2, 1, 1)
plt.plot(history['train_loss'], 'b-', linewidth=2, label='训练损失')
plt.plot(history['val_loss'], 'r-', linewidth=2, label='验证损失')
plt.title('损失曲线', fontsize=14, fontweight='bold')
plt.xlabel('Epoch', fontsize=12)
plt.ylabel('损失', fontsize=12)
plt.legend(fontsize=12, loc='best')
plt.grid(True, linestyle='--', alpha=0.7)
plt.subplot(2, 1, 2)
plt.plot(history['train_acc'], 'b-', linewidth=2, label='训练准确率')
plt.plot(history['val_acc'], 'r-', linewidth=2, label='验证准确率')
plt.title('准确率曲线', fontsize=14, fontweight='bold')
plt.xlabel('Epoch', fontsize=12)
plt.ylabel('准确率', fontsize=12)
plt.ylim(0, 1)
plt.legend(fontsize=12, loc='best')
plt.grid(True, linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
return save_path
def evaluate_model(model, dataloader, history=None, save_path='training_history.png'):
"""
精简版模型评估(仅保留核心指标)
参数:
model (torch.nn.Module): 要评估的PyTorch模型
dataloader (DataLoader): 测试数据加载器
history (dict, optional): 训练历史数据
save_path (str, optional): 训练历史图表保存路径
"""
print("\n在测试集上评估模型...")
model.eval()
all_preds = []
all_labels = []
with torch.no_grad():
test_pbar = tqdm(dataloader, desc='测试评估')
for inputs, labels in test_pbar:
# 确保数据在CPU上
inputs = inputs.cpu()
labels = labels.cpu()
outputs = model(inputs)
_, preds = torch.max(outputs, dim=-1)
# 收集结果(忽略填充)
mask = labels != -100 # 假设-100表示填充值
valid_preds = preds[mask].cpu().numpy()
valid_labels = labels[mask].cpu().numpy()
all_preds.extend(valid_preds)
all_labels.extend(valid_labels)
# 检查类别分布
unique_labels = np.unique(all_labels)
print(f"测试集中出现的类别: {unique_labels}")
# 动态调整target_names
target_names = []
if 0 in unique_labels:
target_names.append('非断句')
if 1 in unique_labels:
target_names.append('断句')
# 绘制训练历史(如果有)
if history:
print("\n绘制训练历史图表...")
plot_training_history(history, save_path)
# 分类报告
print("\n分类报告:")
if len(unique_labels) > 0:
report = classification_report(
all_labels,
all_preds,
target_names=target_names,
zero_division=0, # 处理除零错误
output_dict=False
)
print(report)
else:
print("无有效标签可用于评估")
# 计算整体准确率
accuracy = np.mean(np.array(all_labels) == np.array(all_preds))
print(f"\n总体准确率: {accuracy:.4f}")
return accuracy
# Jupyter Notebook 交互式模型评估
class ModelEvaluator:
def __init__(self):
self.model = None
self.history = None
self.test_loader = None
self.setup_widgets()
def setup_widgets(self):
"""设置交互式控件"""
# 模型加载控件
self.model_path = widgets.Text(
value='poetry_break_model.pth',
placeholder='输入模型路径',
description='模型路径:',
disabled=False
)
# 数据加载器控件
self.data_path = widgets.Text(
value='test_data_loader.pt',
placeholder='输入测试数据加载器路径',
description='测试数据:',
disabled=False
)
# 加载按钮
self.load_button = widgets.Button(
description='加载模型和数据',
button_style='success',
tooltip='点击加载模型和测试数据'
)
self.load_button.on_click(self.load_model_and_data)
# 评估按钮
self.eval_button = widgets.Button(
description='评估模型',
button_style='info',
tooltip='点击评估模型',
disabled=True
)
self.eval_button.on_click(self.evaluate)
# 结果输出
self.output = widgets.Output()
# 布局
box_layout = widgets.Layout(
display='flex',
flex_flow='column',
align_items='stretch',
width='80%'
)
self.control_panel = widgets.VBox([
self.model_path,
self.data_path,
widgets.HBox([self.load_button, self.eval_button]),
self.output
], layout=box_layout)
def load_model_and_data(self, b):
"""加载模型和测试数据"""
with self.output:
clear_output()
print("正在加载模型和测试数据...")
try:
# 加载模型
checkpoint = torch.load(self.model_path.value)
# 假设模型类定义在另一个模块中
# 这里简化处理,实际使用时需要替换为实际的模型类
self.model = torch.nn.Sequential(
torch.nn.Embedding(1000, 128),
torch.nn.LSTM(128, 64, batch_first=True),
torch.nn.Linear(64, 2)
)
self.model.load_state_dict(checkpoint['model_state_dict'])
self.model = self.model.cpu()
self.model.eval()
# 加载历史
self.history = checkpoint['history']
# 加载测试数据加载器
self.test_loader = torch.load(self.data_path.value)
print(f"✅ 模型加载成功: {self.model_path.value}")
print(f"✅ 测试数据加载成功: {self.data_path.value}")
print(f"训练轮次数: {len(self.history['train_loss'])}")
print(f"最终训练准确率: {self.history['train_acc'][-1]:.4f}")
print(f"最终验证准确率: {self.history['val_acc'][-1]:.4f}")
self.eval_button.disabled = False
except Exception as e:
print(f"❌ 加载失败: {str(e)}")
self.eval_button.disabled = True
def evaluate(self, b):
"""执行模型评估"""
with self.output:
clear_output()
print("开始模型评估...")
if self.model is None or self.test_loader is None:
print("错误: 请先加载模型和测试数据")
return
try:
accuracy = evaluate_model(
self.model,
self.test_loader,
self.history
)
# 创建性能摘要
performance = {
"模型路径": self.model_path.value,
"测试样本数": len(self.test_loader.dataset),
"准确率": accuracy,
"训练损失": self.history['train_loss'][-1],
"验证损失": self.history['val_loss'][-1],
"训练准确率": self.history['train_acc'][-1],
"验证准确率": self.history['val_acc'][-1]
}
# 保存性能报告
report_path = "model_performance.json"
with open(report_path, 'w') as f:
json.dump(performance, f, indent=2)
print(f"\n✅ 评估完成! 模型性能报告已保存至 {report_path}")
except Exception as e:
print(f"❌ 评估失败: {str(e)}")
def display(self):
"""显示交互界面"""
display(self.control_panel)
# 在Jupyter Notebook中运行以下代码来启动交互式评估器
# evaluator = ModelEvaluator()
# evaluator.display()
```
## Jupyter Notebook 使用指南
### 1. 基本使用方式
```python
# 导入必要模块
from module4 import evaluate_model, plot_training_history
import torch
# 加载训练好的模型
checkpoint = torch.load('poetry_break_model.pth')
model = ... # 创建模型实例(需与训练时相同结构)
model.load_state_dict(checkpoint['model_state_dict'])
model = model.cpu()
model.eval()
# 加载训练历史
history = checkpoint['history']
# 加载测试数据加载器
test_loader = torch.load('test_data_loader.pt')
# 执行评估
test_accuracy = evaluate_model(model, test_loader, history)
# 单独绘制训练历史
plot_training_history(history)
```
### 2. 交互式评估器(推荐)
```python
# 创建并显示交互式评估器
evaluator = ModelEvaluator()
evaluator.display()
```
运行此代码后,Notebook 中会出现交互式控制面板:
1. 输入模型路径(默认为 `poetry_break_model.pth`)
2. 输入测试数据加载器路径(默认为 `test_data_loader.pt`)
3. 点击"加载模型和数据"按钮
4. 加载成功后点击"评估模型"按钮
### 3. 结果解读
评估完成后将显示:
1. **训练历史图表**:包含损失曲线和准确率曲线
2. **分类报告**:
```
precision recall f1-score support
非断句 0.92 0.95 0.94 1200
断句 0.94 0.90 0.92 800
accuracy 0.93 2000
macro avg 0.93 0.93 0.93 2000
weighted avg 0.93 0.93 0.93 2000
```
3. **总体准确率**:`0.9300`
4. **性能报告**:保存为 `model_performance.json`
### 4. 可视化分析技巧
在 Jupyter 中可以使用以下技巧进行深入分析:
```python
# 分析训练历史
import pandas as pd
# 将历史转换为DataFrame
history_df = pd.DataFrame(history)
# 计算每个epoch的提升幅度
history_df['train_acc_diff'] = history_df['train_acc'].diff()
history_df['val_acc_diff'] = history_df['val_acc'].diff()
# 找出最佳epoch
best_epoch = history_df['val_acc'].idxmax()
print(f"最佳验证准确率在第 {best_epoch+1} 轮: {history_df.loc[best_epoch, 'val_acc']:.4f}")
# 绘制学习率变化
plt.figure(figsize=(10, 6))
plt.plot(history['lr'], 'g-', linewidth=2)
plt.title('学习率变化曲线', fontsize=14)
plt.xlabel('Epoch', fontsize=12)
plt.ylabel('学习率', fontsize=12)
plt.grid(True, linestyle='--', alpha=0.7)
plt.show()
# 保存详细训练历史
history_df.to_csv('training_history.csv', index_label='epoch')
```
### 5. 高级功能:模型比较
```python
# 比较多个模型
def compare_models(model_paths):
results = []
for path in model_paths:
checkpoint = torch.load(path)
model = ... # 创建模型实例
model.load_state_dict(checkpoint['model_state_dict'])
model.eval()
# 评估模型
accuracy = evaluate_model(model, test_loader, history=None)
# 收集结果
results.append({
'model': path,
'accuracy': accuracy,
'final_train_acc': checkpoint['history']['train_acc'][-1],
'final_val_acc': checkpoint['history']['val_acc'][-1]
})
# 转换为DataFrame
df = pd.DataFrame(results)
df = df.sort_values('accuracy', ascending=False)
# 可视化比较
plt.figure(figsize=(10, 6))
plt.barh(df['model'], df['accuracy'], color='skyblue')
plt.title('模型准确率比较', fontsize=14)
plt.xlabel('测试准确率')
plt.xlim(0, 1)
plt.grid(axis='x', linestyle='--', alpha=0.7)
# 添加数值标签
for i, v in enumerate(df['accuracy']):
plt.text(v + 0.01, i, f"{v:.4f}", color='black', va='center')
plt.tight_layout()
plt.show()
return df
# 使用示例
model_paths = ['model_v1.pth', 'model_v2.pth', 'model_v3.pth']
results_df = compare_models(model_paths)
print(results_df)
```
## 优势总结
1. **交互式体验**:通过直观的控件简化评估流程
2. **专业可视化**:自动生成符合学术标准的图表
3. **详细报告**:提供分类报告和性能摘要
4. **错误处理**:完善的异常处理机制
5. **扩展性强**:支持多个模型比较和深入分析
6. **即用性强**:开箱即用,无需复杂配置