Fastai tsai加载最佳模型异常:测试精度不符、预测结果不一致
问题描述
使用tsai库训练时间序列二分类模型时,训练阶段验证集可达70%精度、20%召回,但加载保存的最佳模型测试时,验证集精度无法复现,且测试输出全为0。此外,用不同初始加载器加载同一最佳模型后,对相同数据的预测结果不同。
训练代码:
def train(dataset_idx): print("starting process:", dataset_idx) y_test = load(open(r"y_test_"+str(dataset_idx)+".pkl", 'rb')) X_test = load(open(r"X_test_"+str(dataset_idx)+".pkl", 'rb')) y_train = load(open(r"y_train_"+str(dataset_idx)+".pkl", 'rb')) X_train = load(open(r"X_train_"+str(dataset_idx)+".pkl", 'rb')) l = X_train.shape[0] print("data loaded") X_train = np.concatenate([X_train, X_test], axis=0) y_train = np.concatenate([y_train, y_test], axis=0) del X_test, y_test splits = [i for i in range(l)], [i for i in range(l, X_train.shape[0])] print("dataset generated") tfms = [None, TSClassification()] batch_tfms = TSStandardize() precision = Precision() recall = Recall() save_callback = SaveModelCallback(monitor='valid_loss', comp=None, fname=str(dataset_idx)+'_best_model', every_epoch=False, at_end=False, with_opt=False, reset_on_fit=True) early_stopping = EarlyStoppingCallback(monitor='valid_loss', patience=3) clf = TSClassifier(X_train, y_train, splits=splits, arch="InceptionTimePlus", tfms=tfms, batch_tfms=batch_tfms, bs=[1024], metrics=[precision, recall], cbs=[save_callback, early_stopping]) clf.fit_one_cycle(50, 2.5e-4) clf.export(str(dataset_idx)+".pkl")
测试代码:
learner = TSClassifier(X_sample, y_sample, splits=splits, arch="InceptionTimePlus", tfms=tfms, batch_tfms=batch_tfms) learner.load(str(dataset_idx)+'_best_model') y_pred, _, _ = learner.get_X_preds(X_test) y_pred = y_pred.numpy()[:,0] y_pred = np.asarray(y_pred>0.5).astype(int)
异常场景:
clf = load_learner("models/clf1.pkl") clf .load(str(dataset_idx)+'_best_model') probas, target, preds = clf.get_X_preds(X[splits[1]], y[splits[1]]) clf = load_learner("models/clf2.pkl") clf .load(str(dataset_idx)+'_best_model') probas, target, preds = clf.get_X_preds(X[splits[1]], y[splits[1]])
错误原因分析
- 数据标准化不匹配:训练时
TSStandardize基于训练集(splits[0])计算均值和标准差,但测试时新初始化的TSClassifier会基于X_sample重新计算统计量,导致测试数据分布与训练时不一致,这是输出全0、精度无法复现的核心原因。 - 模型加载上下文不一致:测试时初始化的
TSClassifier与训练时的参数(如数据维度、类别数、变换管道)可能存在差异,导致权重加载后无法正常工作;不同load_learner加载的实例,内部的标准化统计量、数据处理逻辑不同,因此加载同一权重后预测结果不同。 - 导出与加载逻辑混淆:训练时同时用
SaveModelCallback保存权重、clf.export导出完整Learner,测试时混用两种加载方式,导致上下文不匹配。
正确的模型加载与测试方法
方法一:直接加载训练时导出的完整Learner(推荐)
训练时clf.export()已经保存了包含数据处理管道、标准化参数、模型权重的完整实例,测试时直接加载即可,无需重新初始化:
from tsai.all import load_learner # 加载训练时导出的完整Learner learner = load_learner(f"{dataset_idx}.pkl") # 自动复用训练时的标准化逻辑处理测试数据 y_pred, _, _ = learner.get_X_preds(X_test) y_pred = y_pred.numpy()[:, 0] y_pred = np.asarray(y_pred > 0.5).astype(int)
方法二:加载SaveModelCallback保存的权重(需严格匹配上下文)
若必须加载单独的权重文件,需确保测试时的TSClassifier与训练时的初始化参数完全一致,且复用训练集的标准化统计量:
def test(dataset_idx): # 加载训练集数据(用于初始化匹配的标准化逻辑) y_train = load(open(r"y_train_"+str(dataset_idx)+".pkl", 'rb')) X_train = load(open(r"X_train_"+str(dataset_idx)+".pkl", 'rb')) X_test = load(open(r"X_test_"+str(dataset_idx)+".pkl", 'rb')) # 初始化与训练时完全一致的TSClassifier,验证集可设为空 splits = [list(range(len(X_train))), []] tfms = [None, TSClassification()] batch_tfms = TSStandardize() clf = TSClassifier(X_train, y_train, splits=splits, arch="InceptionTimePlus", tfms=tfms, batch_tfms=batch_tfms, bs=1024) # 加载最佳模型权重 clf.load(f"{dataset_idx}_best_model") # 预测测试集,自动使用训练集的标准化参数 y_pred, _, _ = clf.get_X_preds(X_test) y_pred = y_pred.numpy()[:,0] y_pred = np.asarray(y_pred>0.5).astype(int)
解决不同加载器预测结果不同的问题
- 统一使用训练时导出的同一个
dataset_idx.pkl加载Learner,避免使用不同的clf1.pkl/clf2.pkl - 若需使用不同实例,必须保证所有初始化参数(数据维度、类别数、变换管道、标准化逻辑)完全一致,且复用训练集的标准化统计量
内容的提问来源于stack exchange,提问作者Granth
相关产品推荐
相关产品推荐

