2026/5/21 16:43:19
网站建设
项目流程
php网站框架,巴中哪里做网站,百度提交收录入口,汕头名域设计tsai 完整训练流程实践指南
核心目标#xff1a;掌握tsai从数据准备到模型部署的完整工程流程#xff0c;理解每个步骤的目的和注意事项
tsai简介与环境配置
1.1 什么是tsai#xff1f;
tsai (Time Series AI) 是一个基于PyTorch和fastai的时间序列深度学习库#xff0c;专…tsai 完整训练流程实践指南核心目标掌握tsai从数据准备到模型部署的完整工程流程理解每个步骤的目的和注意事项tsai简介与环境配置1.1 什么是tsaitsai (Time Series AI) 是一个基于PyTorch和fastai的时间序列深度学习库专为时间序列分类、回归和预测任务设计。核心特点简洁的API设计类似scikit-learn内置30最先进的时间序列模型自动化的训练流程丰富的数据增强和回调函数支持GPU加速1.2 安装配置基础安装pip install tsai完整安装包含所有依赖pip install tsai[extras]验证安装python -c “from tsai.all import *; print(‘tsai安装成功’)”1.3 导入必要的库标准导入方式from tsai.all import *import numpy as npimport pandas as pdimport matplotlib.pyplot as plt检查GPU是否可用print(fGPU可用: {torch.cuda.is_available()}“)if torch.cuda.is_available():print(fGPU设备: {torch.cuda.get_device_name(0)}”)2. 完整训练流程概览tsai的典型训练流程包含以下9个核心步骤数据准备 → 加载和预处理时间序列数据数据加载器 → 创建TSDataLoaders进行批量加载模型创建 → 选择合适的模型架构创建学习器 → 组装模型、数据、损失函数和指标学习率查找 → 使用lr_find找到最优学习率模型训练 → 使用fit_one_cycle或fit进行训练模型评估 → 在验证集上评估性能模型预测 → 对新数据进行预测保存加载 → 保存模型供后续使用流程图数据 → TSDataLoaders → Model → Learner → lr_find → fit → validate → predict → save3. 步骤1数据准备与加载3.1 步骤目的将原始时间序列数据转换为tsai可以处理的numpy数组格式并进行必要的预处理。3.2 数据格式要求tsai期望的数据格式输入数据 X 的形状X.shape (样本数, 序列长度, 特征数)例如: (1000, 100, 5) 表示1000个样本每个样本100个时间步5个特征标签 y 的形状分类任务: (样本数,) - 例如: (1000,)回归任务: (样本数,) 或 (样本数, 输出维度)3.3 加载UCR/UEA数据集最简单tsai内置了UCR/UEA时间序列分类数据集的加载功能from tsai.data.external import *加载数据集X_train, y_train, X_valid, y_valid get_UCR_data(‘ECG200’)print(f训练集形状: X{X_train.shape}, y{y_train.shape}“)print(f验证集形状: X{X_valid.shape}, y{y_valid.shape}”)print(f类别数量: {len(np.unique(y_train))}“)print(f序列长度: {X_train.shape[1]}”)print(f特征维度: {X_train.shape[2]})注意事项UCR数据集会自动下载到本地缓存数据已经划分好训练集和验证集可以使用get_UCR_list()查看所有可用数据集3.4 加载自定义数据从CSV文件加载df pd.read_csv(‘your_data.csv’)转换为numpy数组假设是单变量时间序列X df.values.reshape(样本数, 序列长度, 1)y labels_array从多个CSV文件加载每个文件一个样本import globdata_files glob.glob(‘data/*.csv’)X_list []y_list []for file in data_files:data pd.read_csv(file).valuesX_list.append(data)# 从文件名或其他来源获取标签label extract_label_from_filename(file)y_list.append(label)X np.array(X_list) # 确保形状是 (N, T, d)y np.array(y_list)print(f数据形状: {X.shape})3.5 数据预处理1. 检查数据质量print(f是否有NaN: {np.isnan(X_train).any()}“)print(f是否有Inf: {np.isinf(X_train).any()}”)print(f数据范围: [{X_train.min():.4f}, {X_train.max():.4f}])2. 处理缺失值如果有if np.isnan(X_train).any():# 前向填充X_train pd.DataFrame(X_train.reshape(-1, X_train.shape[-1])).fillna(method‘ffill’).values.reshape(X_train.shape)X_valid pd.DataFrame(X_valid.reshape(-1, X_valid.shape[-1])).fillna(method‘ffill’).values.reshape(X_valid.shape)3. 数据归一化推荐from sklearn.preprocessing import StandardScaler计算训练集的统计量scaler StandardScaler()X_train_flat X_train.reshape(-1, X_train.shape[-1])scaler.fit(X_train_flat)应用到训练集和验证集X_train_scaled scaler.transform(X_train_flat).reshape(X_train.shape)X_valid_scaled scaler.transform(X_valid.reshape(-1, X_valid.shape[-1])).reshape(X_valid.shape)或者使用简单的min-max归一化X_train_norm (X_train - X_train.min()) / (X_train.max() - X_train.min())X_valid_norm (X_valid - X_train.min()) / (X_train.max() - X_train.min()) # 注意使用训练集的min/maxprint(f归一化后范围: [{X_train_scaled.min():.4f}, {X_train_scaled.max():.4f}])工程注意事项✅ 始终使用训练集的统计量均值、标准差、min、max来归一化验证集和测试集✅ 保存scaler对象用于预测时的数据预处理✅ 检查数据分布确保没有异常值❌ 不要在归一化前就划分训练/验证集会导致数据泄露3.6 数据划分如果数据还没有划分训练/验证集from sklearn.model_selection import train_test_split按比例划分X_train, X_valid, y_train, y_valid train_test_split(X, y,test_size0.2, # 20%作为验证集random_state42, # 设置随机种子保证可复现stratifyy # 分层采样保持类别比例)print(f训练集大小: {len(X_train)}“)print(f验证集大小: {len(X_valid)}”)print(f训练集类别分布: {np.bincount(y_train)}“)print(f验证集类别分布: {np.bincount(y_valid)}”)4. 步骤2创建数据加载器4.1 步骤目的创建TSDataLoaders对象负责批量加载数据batch数据增强可选数据打乱shuffle多进程加载加速4.2 使用get_ts_dls推荐方式from tsai.data.core import get_ts_dls最简单的创建方式dls get_ts_dls(X_train, y_train, # 训练数据X_valid, y_valid, # 验证数据bs64 # batch size批次大小)print(f训练批次数: {len(dls.train)}“)print(f验证批次数: {len(dls.valid)}”)4.3 完整参数配置dls get_ts_dls(X_train, y_train,X_valid, y_valid,bs64, # 批次大小根据显存调整batch_tfmsNone, # 批次级别的数据增强num_workers4, # 数据加载的进程数shuffle_trainTrue, # 训练集是否打乱drop_lastFalse, # 是否丢弃最后不完整的batchdevice‘cuda’ if torch.cuda.is_available() else ‘cpu’)参数说明参数 目的 推荐值 注意事项bs 批次大小影响训练速度和显存占用 32-128 GPU显存小用32大用128num_workers 并行加载数据的进程数 4-8 Windows系统可能需要设为0shuffle_train 打乱训练数据顺序 True 验证集不需要打乱drop_last 丢弃不完整的batch False 数据少时设为False4.4 添加数据增强from tsai.data.transforms import *定义数据增强pipelinebatch_tfms [TSStandardize(), # 标准化TSRandomCrop(seq_len100), # 随机裁剪到固定长度]dls get_ts_dls(X_train, y_train,X_valid, y_valid,bs64,batch_tfmsbatch_tfms)常用数据增强方法1. 时间扭曲from tsai.data.augmentation import TSTimeWarptfm TSTimeWarp(p0.5) # 50%概率应用2. 窗口切片from tsai.data.augmentation import TSWindowSlicetfm TSWindowSlice(p0.3)3. 添加高斯噪声from tsai.data.augmentation import TSGaussianNoisetfm TSGaussianNoise(scale0.1, p0.5)4. 幅度缩放from tsai.data.augmentation import TSMagScaletfm TSMagScale(p0.3)组合多个增强batch_tfms [TSTimeWarp(p0.5),TSGaussianNoise(scale0.05, p0.3),TSMagScale(p0.3)]4.5 检查数据加载器检查一个batchxb, yb dls.one_batch()print(fBatch X shape: {xb.shape}“) # (batch_size, seq_len, features)print(fBatch y shape: {yb.shape}”) # (batch_size,)print(f数据在设备: {xb.device}) # cuda:0 或 cpu可视化batch中的几个样本dls.show_batch(max_n9, figsize(15, 10))工程注意事项✅ batch size尽量选择2的幂次32, 64, 128利于GPU优化✅ 如果训练很慢尝试增加num_workers✅ Windows用户如果遇到multiprocessing错误设置num_workers0❌ 数据增强不要过度可能导致模型学不到真实模式步骤3模型选择与创建5.1 步骤目的根据任务特点和数据特征选择合适的模型架构tsai提供了30预定义模型。5.2 tsai内置模型概览主流模型分类1. 卷积神经网络CNN系列 - 速度快适合大多数场景from tsai.models.InceptionTime import InceptionTimefrom tsai.models.ResNet import ResNetfrom tsai.models.XceptionTime import XceptionTimefrom tsai.models.ResCNN import ResCNN2. 循环神经网络RNN系列 - 适合序列依赖强的任务from tsai.models.RNN import LSTM, GRU, RNNfrom tsai.models.RNNPlus import LSTMPlus, GRUPlus3. Transformer系列 - 适合长序列和复杂依赖from tsai.models.TST import TSTfrom tsai.models.TransformerModel import TransformerModel4. 混合架构from tsai.models.InceptionTimePlus import InceptionTimePlusfrom tsai.models.LSTM_FCN import LSTM_FCN5.3 模型选择指南场景 推荐模型 理由通用分类任务 InceptionTime 性能稳定速度快短序列(100) ResNet, FCN 简单有效长序列(500) TST, InceptionTime 能捕捉长期依赖多变量时间序列 InceptionTime, TST 能处理特征交互时序依赖强 LSTM, GRU 专门设计用于序列资源受限 ResNet, FCN 参数少速度快追求最高精度 InceptionTimePlus, XCM SOTA性能5.4 创建模型示例5.4.1 InceptionTime最推荐from tsai.models.InceptionTime import InceptionTimemodel InceptionTime(c_inX_train.shape[2], # 输入特征数c_outlen(np.unique(y_train)), # 输出类别数seq_lenX_train.shape[1], # 序列长度可选nf32, # 基础滤波器数量depth6 # Inception块的深度)print(f模型参数量: {sum(p.numel() for p in model.parameters()):,})参数调整建议nf控制模型容量数据多用64数据少用16-32depth控制模型深度通常6-12效果好5.4.2 ResNetfrom tsai.models.ResNet import ResNetmodel ResNet(c_inX_train.shape[2],c_outlen(np.unique(y_train)))或自定义层数model ResNet(c_inX_train.shape[2],c_outlen(np.unique(y_train)),layers[64, 128, 128] # 每个残差块的通道数)5.4.3 LSTMfrom tsai.models.RNN import LSTMmodel LSTM(c_inX_train.shape[2],c_outlen(np.unique(y_train)),hidden_size128, # LSTM隐藏层大小n_layers2, # LSTM层数bidirectionalTrue, # 是否双向dropout0.1 # Dropout比例)5.4.4 TST (Time Series Transformer)from tsai.models.TST import TSTmodel TST(c_inX_train.shape[2],c_outlen(np.unique(y_train)),seq_lenX_train.shape[1],d_model128, # Transformer维度n_heads8, # 注意力头数n_layers3, # Transformer层数d_ff256, # 前馈网络维度dropout0.1,max_seq_lenX_train.shape[1])5.5 查看模型结构打印模型结构print(model)查看参数量total_params sum(p.numel() for p in model.parameters())trainable_params sum(p.numel() for p in model.parameters() if p.requires_grad)print(f总参数量: {total_params:,}“)print(f可训练参数量: {trainable_params:,}”)测试前向传播with torch.no_grad():test_input torch.randn(2, X_train.shape[1], X_train.shape[2])test_output model(test_input)print(f输入形状: {test_input.shape}“)print(f输出形状: {test_output.shape}”)工程注意事项✅ 优先尝试InceptionTime适合大多数场景✅ 模型参数量控制在数据量的1/10以下避免过拟合✅ 如果数据量小(1000)选择参数少的模型ResNet, FCN❌ 不要盲目追求复杂模型简单模型往往效果更好步骤4创建学习器6.1 步骤目的Learner是tsai的核心类整合了模型、数据、损失函数、优化器和训练逻辑。6.2 基础创建方式from tsai.learner import *最简单的创建方式分类任务learn Learner(dls, # 数据加载器model, # 模型loss_funcLabelSmoothingCrossEntropy(), # 损失函数metrics[accuracy] # 评估指标)6.3 完整参数配置from functools import partialfrom torch.optim import Adamlearn Learner(dls,model,loss_funcLabelSmoothingCrossEntropy(eps0.1), # Label smoothingopt_funcpartial(Adam, lr1e-3, weight_decay1e-4), # 优化器metrics[accuracy, F1Score(average‘macro’)], # 评估指标cbs[ # 回调函数ShowGraphCallback(), # 显示训练曲线SaveModelCallback(monitor‘accuracy’, fname‘best_model’), # 保存最佳模型EarlyStoppingCallback(monitor‘valid_loss’, patience10) # 早停],path‘./models’ # 模型保存路径)6.4 损失函数选择分类任务from tsai.losses import *1. 标准交叉熵最常用loss_func nn.CrossEntropyLoss()2. Label Smoothing交叉熵推荐防止过拟合loss_func LabelSmoothingCrossEntropy(eps0.1)3. Focal Loss处理类别不平衡loss_func FocalLoss(alpha1, gamma2)回归任务loss_func nn.MSELoss() # 均方误差loss_func nn.L1Loss() # 平均绝对误差损失函数选择指南任务类型 推荐损失 使用场景多分类平衡 LabelSmoothingCrossEntropy 类别数量相近多分类不平衡 FocalLoss 某些类别样本很少二分类 BCEWithLogitsLoss 0/1分类回归 MSELoss 预测连续值6.5 评估指标设置from tsai.metrics import *from sklearn.metrics import accuracy_score, f1_score分类指标metrics [accuracy, # 准确率RocAucBinary(), # 二分类AUCRocAucMulti(), # 多分类AUCF1Score(average‘macro’), # F1分数Precision(average‘macro’), # 精确率Recall(average‘macro’) # 召回率]回归指标metrics [mae, # 平均绝对误差rmse, # 均方根误差mse, # 均方误差R2Score() # R²分数]创建learner时指定learn Learner(dls, model, loss_func, metricsmetrics)6.6 回调函数Callbacks回调函数用于在训练过程中执行特定操作from tsai.callback.core import *1. 可视化训练过程ShowGraphCallback() # 实时显示loss和metrics曲线2. 保存最佳模型SaveModelCallback(monitor‘accuracy’, # 监控的指标fname‘best_model’, # 保存的文件名every_epochFalse, # 是否每个epoch都保存with_optFalse # 是否保存优化器状态)3. 早停Early StoppingEarlyStoppingCallback(monitor‘valid_loss’, # 监控验证损失min_delta0.01, # 最小改善阈值patience10 # 容忍多少个epoch没有改善)4. 学习率调度ReduceLROnPlateau(monitor‘valid_loss’,factor0.5, # 学习率衰减因子patience5)5. 混合精度训练加速训练MixedPrecision()6. TensorBoard记录TensorBoardCallback(log_dir‘runs/experiment1’)组合使用learn Learner(dls, model, loss_func, metrics,cbs[ShowGraphCallback(),SaveModelCallback(monitor‘accuracy’),EarlyStoppingCallback(monitor‘valid_loss’, patience10)])工程注意事项✅ 分类任务推荐使用LabelSmoothingCrossEntropy✅ 始终添加SaveModelCallback保存最佳模型✅ 长时间训练添加EarlyStoppingCallback避免浪费✅ GPU训练时使用MixedPrecision()加速步骤5学习率查找7.1 步骤目的学习率是最重要的超参数。lr_find通过尝试不同的学习率帮助找到最优的学习率范围。7.2 使用lr_find运行学习率查找器lr_min, lr_steep learn.lr_find(start_lr1e-7, # 起始学习率end_lr10, # 结束学习率num_it100, # 迭代次数stop_divTrue, # loss发散时停止suggest_funcs(minimum, steep) # 建议函数)print(f建议的最小学习率: {lr_min:.2e}“)print(f建议的最陡学习率: {lr_steep:.2e}”)可视化学习率-损失曲线learn.recorder.plot_lr_find()7.3 解读lr_find结果lr_find会生成一条曲线- 横轴学习率对数刻度- 纵轴损失值选择学习率的原则1. minimum: 损失最小值对应的学习率2. steep: 损失下降最快的点推荐3. 通常选择steep或略小于steep的值示例输出suggested LR: 1.58E-03 (steep) or 3.98E-03 (minimum)可视化示例学习率曲线通常是这样的Loss | /| /| / -- steep点推荐| /| / \ -- minimum点|/ ___±---------- Learning Rate (log scale)1e-7 1e-27.4 学习率选择技巧策略1使用steep最常用lr lr_steep策略2使用steep的一半更保守lr lr_steep / 2策略3手动选择看曲线lr 1e-3 # 根据曲线手动选择策略4使用范围用于fit_one_cyclelr_max lr_steeplr_min lr_max / 10工程注意事项✅ 每次改变数据或模型后都重新运行lr_find✅ 如果曲线很平说明学习率范围设置不当调整start_lr和end_lr✅ 选择loss下降最快的点而不是最低点❌ 不要选择loss开始上升的区域步骤6模型训练8.1 步骤目的使用训练数据训练模型同时在验证集上评估性能。8.2 fit_one_cycle推荐方法使用1cycle学习率策略训练learn.fit_one_cycle(n_epoch40, # 训练轮数lr_max1e-3, # 最大学习率使用lr_find的结果wd1e-4, # 权重衰减L2正则化pct_start0.3, # warmup阶段占比前30%div25.0, # 初始学习率除数: lr_start lr_max/divdiv_final1e5 # 最终学习率除数: lr_end lr_max/div_final)训练完成后查看结果learn.recorder.plot_loss() # 查看损失曲线learn.recorder.plot_metrics() # 查看指标曲线fit_one_cycle的优势动态调整学习率先增后减结合动量调度训练速度快收敛好通常比固定学习率效果更好8.3 标准训练方法使用固定学习率训练learn.fit(n_epoch40,lr1e-3,wd1e-4)或者分阶段训练先高学习率再低学习率learn.fit(10, lr1e-2, wd1e-4) # 阶段1learn.fit(10, lr1e-3, wd1e-4) # 阶段2learn.fit(20, lr1e-4, wd1e-4) # 阶段3fine-tuning8.4 训练过程监控训练过程中会实时显示epoch train_loss valid_loss accuracy time0 0.693147 0.684932 0.575000 00:031 0.650234 0.640123 0.625000 00:03…查看训练历史print(learn.recorder.values)查看最佳结果print(f最佳验证损失: {min(learn.recorder.values, keylambda x: x[1])[1]:.4f}“)print(f最佳准确率: {max(learn.recorder.values, keylambda x: x[2])[2]:.4f}”)8.5 继续训练如果训练中断或想继续训练learn.fit_one_cycle(20, lr_max1e-4) # 使用更小的学习率继续或者从保存的检查点恢复learn.load(‘best_model’)learn.fit_one_cycle(20, lr_max1e-4)8.6 冻结和解冻Fine-tuning冻结部分层用于迁移学习learn.freeze() # 冻结所有层learn.fit_one_cycle(10, lr_max1e-3) # 只训练最后几层解冻所有层learn.unfreeze()learn.fit_one_cycle(30, lr_max1e-4) # 用更小的学习率训练所有层部分解冻learn.freeze_to(-2) # 冻结除最后2层外的所有层工程注意事项✅ 优先使用fit_one_cycle效果通常更好✅ 训练轮数设置在30-50之间使用早停避免过拟合✅ 权重衰减(wd)推荐值1e-4 到 1e-2✅ 定期保存checkpoint避免训练中断损失❌ 不要设置过大的学习率会导致训练不稳定步骤7模型评估9.1 步骤目的在验证集上全面评估模型性能识别潜在问题。9.2 基础评估获取验证集的损失和指标valid_results learn.validate()print(f验证损失: {valid_results[0]:.4f}“)print(f验证准确率: {valid_results[1]:.4f}”)或者单独获取valid_loss learn.validate()[0]valid_acc learn.validate()[1]9.3 获取预测结果获取验证集的预测结果preds, targets learn.get_preds()preds: 模型输出的概率分类或值回归targets: 真实标签print(f预测形状: {preds.shape}“) # (N, num_classes) 或 (N,)print(f标签形状: {targets.shape}”) # (N,)转换为numpy数组preds_np preds.numpy()targets_np targets.numpy()分类任务获取预测类别if len(preds.shape) 1:y_pred preds.argmax(dim1).numpy()else:y_pred preds.numpy()y_true targets.numpy()9.4 详细评估指标from sklearn.metrics import (accuracy_score,precision_score,recall_score,f1_score,classification_report,confusion_matrix)分类报告print(“” * 50)print(“分类报告”)print(“” * 50)print(classification_report(y_true, y_pred))混淆矩阵cm confusion_matrix(y_true, y_pred)print(“\n混淆矩阵:”)print(cm)各类别的准确率from sklearn.metrics import accuracy_scorefor i in range(len(np.unique(y_true))):mask y_true iacc_i accuracy_score(y_true[mask], y_pred[mask])print(f类别 {i} 准确率: {acc_i:.4f})9.5 可视化评估结果import matplotlib.pyplot as pltimport seaborn as sns1. 混淆矩阵热力图plt.figure(figsize(10, 8))sns.heatmap(cm, annotTrue, fmt‘d’, cmap‘Blues’)plt.ylabel(‘真实标签’)plt.xlabel(‘预测标签’)plt.title(‘混淆矩阵’)plt.show()2. ROC曲线二分类from sklearn.metrics import roc_curve, aucif preds.shape[1] 2: # 二分类fpr, tpr, _ roc_curve(y_true, preds[:, 1].numpy())roc_auc auc(fpr, tpr)plt.figure(figsize(8, 6)) plt.plot(fpr, tpr, labelfROC curve (AUC {roc_auc:.2f})) plt.plot([0, 1], [0, 1], k--) plt.xlabel(假阳性率) plt.ylabel(真阳性率) plt.title(ROC曲线) plt.legend() plt.show()3. 预测概率分布plt.figure(figsize(12, 5))for i in range(preds.shape[1]):plt.subplot(1, preds.shape[1], i1)plt.hist(preds[targetsi, i].numpy(), bins20, alpha0.7)plt.title(f’类别 {i} 的预测概率’)plt.xlabel(‘预测概率’)plt.ylabel(‘样本数’)plt.tight_layout()plt.show()9.6 查看预测样本使用tsai内置的可视化learn.show_results(max_n9, figsize(15, 10))或手动可视化预测错误的样本errors np.where(y_pred ! y_true)[0]print(f错误预测的样本数: {len(errors)})可视化前几个错误样本fig, axes plt.subplots(3, 3, figsize(15, 10))for i, idx in enumerate(errors[:9]):ax axes[i//3, i%3]ax.plot(X_valid[idx, :, 0])ax.set_title(f’真实: {y_true[idx]}, 预测: {y_pred[idx]})plt.tight_layout()plt.show()9.7 测试集评估如果有单独的测试集test_dl dls.test_dl(X_test)获取测试集预测test_preds, test_targets learn.get_preds(dltest_dl)评估test_y_pred test_preds.argmax(dim1).numpy()test_y_true test_targets.numpy()test_acc accuracy_score(test_y_true, test_y_pred)print(f测试集准确率: {test_acc:.4f})工程注意事项✅ 始终在验证集上评估避免在测试集上调参✅ 关注混淆矩阵了解哪些类别容易混淆✅ 检查错误样本理解模型的弱点✅ 如果某些类别表现很差考虑数据增强或调整损失函数步骤8模型预测10.1 步骤目的使用训练好的模型对新数据进行预测。10.2 单样本预测预测单个样本test_sample X_valid[0:1] # 保持3D形状 (1, seq_len, features)方法1使用predict返回概率、类别、原始输出prob, pred_class, raw_output learn.predict(test_sample)print(f预测类别: {pred_class}“)print(f预测概率: {prob}”)print(f各类别概率:“)for i, p in enumerate(prob):print(f” 类别 {i}: {p:.4f})10.3 批量预测预测多个样本test_data X_valid[:100]方法1使用get_predspreds, _ learn.get_preds(dldls.test_dl(test_data))获取预测类别pred_classes preds.argmax(dim1).numpy()print(f预测类别: {pred_classes})方法2直接使用模型learn.model.eval()with torch.no_grad():test_tensor torch.tensor(test_data, dtypetorch.float32)outputs learn.model(test_tensor)pred_probs torch.softmax(outputs, dim1)pred_classes pred_probs.argmax(dim1).numpy()10.4 带数据预处理的预测实际应用中新数据需要和训练数据一样的预处理def predict_with_preprocessing(learn, raw_data, scaler):“”完整的预测流程预处理 - 预测 - 后处理Args: learn: 训练好的learner raw_data: 原始数据 (N, T, d) scaler: 训练时使用的StandardScaler Returns: predictions: 预测结果 # 1. 预处理和训练时保持一致 data_flat raw_data.reshape(-1, raw_data.shape[-1]) data_scaled scaler.transform(data_flat).reshape(raw_data.shape) # 2. 预测 preds, _ learn.get_preds(dllearn.dls.test_dl(data_scaled)) pred_classes preds.argmax(dim1).numpy() # 3. 返回结果 return pred_classes, preds.numpy()使用示例pred_classes, pred_probs predict_with_preprocessing(learn, new_data, scaler)10.5 批量预测并导出结果预测并保存结果到CSVdef batch_predict_and_save(learn, test_data, output_file‘predictions.csv’):“”批量预测并保存结果“”# 预测preds, _ learn.get_preds(dllearn.dls.test_dl(test_data))pred_classes preds.argmax(dim1).numpy()pred_probs preds.numpy()# 创建DataFrame results pd.DataFrame({ sample_id: range(len(pred_classes)), predicted_class: pred_classes, confidence: pred_probs.max(axis1) }) # 添加每个类别的概率 for i in range(pred_probs.shape[1]): results[fprob_class_{i}] pred_probs[:, i] # 保存 results.to_csv(output_file, indexFalse) print(f预测结果已保存到: {output_file}) return results使用results_df batch_predict_and_save(learn, X_test, ‘test_predictions.csv’)工程注意事项✅ 新数据必须经过和训练数据相同的预处理✅ 检查预测置信度对低置信度样本进行人工审核✅ 生产环境中保存预测结果的时间戳和版本信息✅ 监控模型预测的置信度分布变化可能表示数据漂移步骤9模型保存与加载11.1 步骤目的保存训练好的模型用于后续部署或继续训练。11.2 保存模型的三种方式方式1保存模型权重最常用保存模型权重learn.save(‘my_model’) # 保存到 models/my_model.pth加载模型权重learn.load(‘my_model’)指定保存路径learn.save(‘/path/to/models/my_model’)适用场景只保存模型参数文件小需要相同的架构来加载适合实验和调参阶段方式2导出完整learner推荐生产环境导出完整的learner包括模型、数据预处理、配置learn.export(‘my_model.pkl’)加载learnerlearn_loaded load_learner(‘my_model.pkl’)直接用于预测preds learn_loaded.predict(new_data)适用场景部署到生产环境保存完整的训练状态方便他人使用方式3保存PyTorch模型最灵活保存完整模型torch.save(learn.model, ‘model_complete.pth’)加载完整模型model_loaded torch.load(‘model_complete.pth’)或只保存state_dict推荐torch.save(learn.model.state_dict(), ‘model_weights.pth’)加载state_dictmodel InceptionTime(…) # 需要先创建相同架构model.load_state_dict(torch.load(‘model_weights.pth’))11.3 保存完整的模型包import osimport picklefrom datetime import datetimedef save_model_package(learn, scaler, config, save_dir‘./saved_models’):“”保存完整的模型包“”# 创建保存目录timestamp datetime.now().strftime(‘%Y%m%d_%H%M%S’)model_dir os.path.join(save_dir, f’model_{timestamp})os.makedirs(model_dir, exist_okTrue)# 1. 保存learner learn.export(os.path.join(model_dir, learner.pkl)) # 2. 保存模型权重 learn.save(os.path.join(model_dir, weights)) # 3. 保存scaler with open(os.path.join(model_dir, scaler.pkl), wb) as f: pickle.dump(scaler, f) # 4. 保存配置 config[save_date] timestamp with open(os.path.join(model_dir, config.pkl), wb) as f: pickle.dump(config, f) # 5. 保存训练历史 history { train_loss: learn.recorder.losses, valid_loss: [v[0] for v in learn.recorder.values], metrics: [v[1:] for v in learn.recorder.values] } with open(os.path.join(model_dir, history.pkl), wb) as f: pickle.dump(history, f) print(f模型包已保存到: {model_dir}) return model_dirdef load_model_package(model_dir):“”加载完整的模型包“”# 1. 加载learnerlearn load_learner(os.path.join(model_dir, ‘learner.pkl’))# 2. 加载scaler with open(os.path.join(model_dir, scaler.pkl), rb) as f: scaler pickle.load(f) # 3. 加载配置 with open(os.path.join(model_dir, config.pkl), rb) as f: config pickle.load(f) print(f模型包加载成功) print(f保存日期: {config[save_date]}) return learn, scaler, config工程注意事项✅ 生产环境使用export()保存完整learner✅ 保存scaler和配置确保预测时数据处理一致✅ 使用版本号管理模型便于回滚✅ 记录每个模型的训练参数和性能指标tsai工程实践注意事项12.1 数据相关数据质量检查清单def check_data_quality(X, y):“”“检查数据质量”“”print(“” * 50)print(f样本数: {len(X)}“)print(f序列长度: {X.shape[1]}”)print(f特征数: {X.shape[2]}“)print(f类别数: {len(np.unique(y))}”)print(fNaN数量: {np.isnan(X).sum()}“)print(f数据范围: [{X.min():.4f}, {X.max():.4f}]”)print(f类别分布: {np.bincount(y)}“)print(” * 50)处理类别不平衡使用加权损失from tsai.losses import FocalLossloss_func FocalLoss(alpha1, gamma2)或者数据增强batch_tfms [TSTimeWarp(p0.5), TSGaussianNoise(p0.3)]12.2 训练相关防止过拟合数据增强权重衰减wd1e-3Dropout早停减小模型复杂度加速训练混合精度learn.to_fp16()增大batch size更多workersnum_workers8训练稳定性梯度裁剪学习率预热Batch Normalization12.3 调试技巧快速调试流程1. 使用小数据集X_debug X_train[:100]y_debug y_train[:100]2. 检查是否能过拟合dls_debug get_ts_dls(X_debug, y_debug, X_debug, y_debug, bs16)learn Learner(dls_debug, model, loss_func, metrics)learn.fit(10, lr1e-2) # 应该能达到很高的准确率检查模型输出with torch.no_grad():xb, yb dls.one_batch()output learn.model(xb)print(f输入形状: {xb.shape}“)print(f输出形状: {output.shape}”)print(f输出范围: [{output.min():.4f}, {output.max():.4f}]“)13. 完整代码示例“””ECG心电图分类 - 完整训练流程示例“”from tsai.all import *import numpy as npfrom sklearn.preprocessing import StandardScalerfrom sklearn.metrics import classification_report, confusion_matriximport pickle1. 加载数据X_train, y_train, X_valid, y_valid get_UCR_data(‘ECG200’)2. 数据预处理scaler StandardScaler()X_train_flat X_train.reshape(-1, X_train.shape[-1])scaler.fit(X_train_flat)X_train_scaled scaler.transform(X_train_flat).reshape(X_train.shape)X_valid_scaled scaler.transform(X_valid.reshape(-1, X_valid.shape[-1])).reshape(X_valid.shape)3. 创建数据加载器dls get_ts_dls(X_train_scaled, y_train,X_valid_scaled, y_valid,bs64,num_workers4)4. 创建模型model InceptionTime(c_inX_train.shape[2],c_outlen(np.unique(y_train)),nf32,depth6)5. 创建学习器learn Learner(dls,model,loss_funcLabelSmoothingCrossEntropy(eps0.1),metrics[accuracy, F1Score(average‘macro’)],cbs[ShowGraphCallback(),SaveModelCallback(monitor‘accuracy’, fname‘best_model’),EarlyStoppingCallback(monitor‘valid_loss’, patience10)])6. 学习率查找lr_min, lr_steep learn.lr_find()print(f建议学习率: {lr_steep:.2e})7. 训练模型learn.fit_one_cycle(40, lr_maxlr_steep, wd1e-4)8. 评估模型learn.load(‘best_model’)valid_loss, acc, f1 learn.validate()print(f验证准确率: {acc:.4f})9. 获取预测并评估preds, targets learn.get_preds()y_pred preds.argmax(dim1).numpy()y_true targets.numpy()print(classification_report(y_true, y_pred))10. 保存模型learn.export(‘ecg_classifier.pkl’)with open(‘scaler.pkl’, ‘wb’) as f:pickle.dump(scaler, f)print(“训练完成”)14. 常见问题解决方案Q: 数据形状错误解决确保数据是 (N, T, d) 形状if len(X.shape) 2:X X[…, np.newaxis]Q: 损失不下降1. 重新查找学习率lr_min, lr_steep learn.lr_find()2. 检查数据归一化3. 增加模型容量或训练轮数Q: 过拟合1. 增加数据增强batch_tfms [TSTimeWarp(p0.5), TSGaussianNoise(p0.3)]2. 增加权重衰减learn Learner(…, opt_funcpartial(Adam, wd1e-2))3. 使用早停cbs [EarlyStoppingCallback(patience10)]Q: CUDA out of memory1. 减小batch sizedls get_ts_dls(…, bs32)2. 使用混合精度learn.to_fp16()3. 清理缓存torch.cuda.empty_cache()Q: Windows multiprocessing错误设置num_workers0dls get_ts_dls(…, num_workers0)总结核心流程回顾✅ 数据准备加载、归一化、划分✅ 数据加载器get_ts_dls创建✅ 模型创建选择合适架构✅ 学习器组装所有组件✅ 学习率查找lr_find✅ 模型训练fit_one_cycle✅ 模型评估validate和get_preds✅ 模型预测predict✅ 模型保存export关键要点数据预处理要一致优先使用fit_one_cycle添加早停和保存最佳模型生产环境使用export()