You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 09:02:11