ML.NET加载SSA训练模型时触发格式无效错误,求排查思路
ML.NET SSA模型加载时触发格式无效异常问题
问题场景
基于ML.NET实现价格预测系统,训练阶段使用ForecastBySsa算法,仅用60条历史数据训练并保存模型为MinuteModel.zip。执行预测逻辑时,调用mlContext.Model.Load(file, out DataViewSchema schema)触发如下异常:
2023-11-15 16:15:23.6143|0|ERROR|Microsoft.Extensions.Hosting.Internal.Host|BackgroundService failed System.InvalidOperationException: Error during class instantiation ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Error during class instantiation ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.FormatException: One of the identified items was in an invalid format. at Microsoft.ML.Transforms.TimeSeries.AdaptiveSingularSpectrumSequenceModelerInternal..ctor(IHostEnvironment env, ModelLoadContext ctx) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Microsoft.ML.Runtime.ComponentCatalog.LoadableClassInfo.CreateInstanceCore(Object[] ctorArgs) --- End of inner exception stack trace --- at Microsoft.ML.Runtime.ComponentCatalog.LoadableClassInfo.CreateInstanceCore(Object[] ctorArgs) at Microsoft.ML.Runtime.ComponentCatalog.TryCreateInstance[TRes](IHostEnvironment env, Type signatureType, TRes& result, String name, String options, Object[] extra) at Microsoft.ML.Runtime.ComponentCatalog.TryCreateInstance[TRes,TSig](IHostEnvironment env, TRes& result, String name, String options, Object[] extra) at Microsoft.ML.ModelLoadContext.TryLoadModelCore[TRes,TSig](IHostEnvironment env, TRes& result, Object[] extra) at Microsoft.ML.ModelLoadContext.TryLoadModel[TRes,TSig](IHostEnvironment env, TRes& result, RepositoryReader rep, Entry ent, String dir, Object[] extra) at Microsoft.ML.ModelLoadContext.LoadModel[TRes,TSig](IHostEnvironment env, TRes& result, RepositoryReader rep, Entry ent, String dir, Object[] extra) at Microsoft.ML.ModelLoadContext.LoadModelOrNull[TRes,TSig](IHostEnvironment env, TRes& result, RepositoryReader rep, String dir, Object[] extra) at Microsoft.ML.ModelLoadContext.LoadModel[TRes,TSig](IHostEnvironment env, TRes& result, String name, Object[] extra) at Microsoft.ML.Transforms.TimeSeries.SsaForecastingBaseWrapper.SsaForecastingBase..ctor(IHostEnvironment env, ModelLoadContext ctx, String name) at Microsoft.ML.Transforms.TimeSeries.SsaForecastingTransformer.Create(IHostEnvironment env, ModelLoadContext ctx) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Microsoft.ML.Runtime.ComponentCatalog.LoadableClassInfo.CreateInstanceCore(Object[] ctorArgs) --- End of inner exception stack trace --- at Microsoft.ML.Runtime.ComponentCatalog.LoadableClassInfo.CreateInstanceCore(Object[] ctorArgs) at Microsoft.ML.Runtime.ComponentCatalog.TryCreateInstance[TRes](IHostEnvironment env, Type signatureType, TRes& result, String name, String options, Object[] extra) at Microsoft.ML.Runtime.ComponentCatalog.TryCreateInstance[TRes,TSig](IHostEnvironment env, TRes& result, String name, String options, Object[] extra) at Microsoft.ML.ModelLoadContext.TryLoadModelCore[TRes,TSig](IHostEnvironment env, TRes& result, Object[] extra) at Microsoft.ML.ModelLoadContext.TryLoadModel[TRes,TSig](IHostEnvironment env, TRes& result, RepositoryReader rep, Entry ent, String dir, Object[] extra) at Microsoft.ML.ModelLoadContext.LoadModel[TRes,TSig](IHostEnvironment env, TRes& result, RepositoryReader rep, Entry ent, String dir, Object[] extra) at Microsoft.ML.ModelLoadContext.LoadModelOrNull[TRes,TSig](IHostEnvironment env, TRes& result, RepositoryReader rep, String dir, Object[] extra) at Microsoft.ML.ModelLoadContext.LoadModel[TRes,TSig](IHostEnvironment env, TRes& result, RepositoryReader rep, String dir, Object[] extra) at Microsoft.ML.ModelOperationsCatalog.Load(Stream stream, DataViewSchema& inputSchema) at Midas.API.Services.PitiasService.MakePredictionsMinuteAsync() in C:\Users\c-lsegrelles\source\repos\Midas\Midas.API\Services\PitiasService.cs:line 460 at Midas.API.Services.PitiasService.MakePredictionsMinuteAsync() in C:\Users\c-lsegrelles\source\repos\Midas\Midas.API\Services\PitiasService.cs:line 461 at Midas.API.Services.PitiasService.MakePredictionsAsync() in C:\Users\c-lsegrelles\source\repos\Midas\Midas.API\Services\PitiasService.cs:line 58 at Midas.API.Services.OrchestratorService.TrainModelAndMakePredictions() in C:\Users\c-lsegrelles\source\repos\Midas\Midas.API\Services\OrchestratorService.cs:line 70 at Midas.API.Services.OrchestratorService.ExecuteAsync(CancellationToken stoppingToken) in C:\Users\c-lsegrelles\source\repos\Midas\Midas.API\Services\OrchestratorService.cs:line 40 at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService)
训练代码
private async Task TrainModel() { var historicPrices = await _priceRepository.GetPricesByQueryAsync(x => !x.Processed); var mlContext = new MLContext(seed: 0); var newData = mlContext.Data.LoadFromEnumerable(historicPrices.Select(p => new PriceForML { Value = (float)p.Value }).ToList()); var trainer = mlContext.Forecasting.ForecastBySsa( outputColumnName: nameof(ForecastResult.Forecast), inputColumnName: nameof(PriceForML.Value), windowSize: 60, seriesLength: 60 * 60 * 24, trainSize: 60 * 60 * 24, horizon: 5, confidenceLevel: 0.95f, confidenceLowerBoundColumn: "ConfidenceLowerBound", confidenceUpperBoundColumn: "ConfidenceUpperBound"); ITransformer trainedModel = trainer.Fit(newData); mlContext.Model.Save(trainedModel, newData.Schema, $"MLModels/MinuteModel.zip"); }
数据模型类
public class PriceForML { public float Value { get; set; } } public class ForecastResult { public float[] Forecast { get; set; } }
预测代码
private async Task MakePredictionsMinuteAsync() { var lastPrice = await _priceRepository.GetLatestPriceByCoinIdAsync(coin.Id); if (File.Exists($"MLModels/MinuteModel.zip") && lastPrice != null) { var mlContext = new MLContext(seed: 0); ITransformer forecaster; try { await using (var file = File.OpenRead($"MLModels/MinuteModel.zip")) { forecaster = mlContext.Model.Load(file, out DataViewSchema schema); } } catch (Exception e) { _logger.LogError(e.Message); continue; } var predictions = forecaster.CreateTimeSeriesEngine<PriceForML, ForecastResult>(mlContext).Predict(new PriceForML() { Value = (float)lastPrice.Value }); if(predictions.Forecast == null) continue; var predictionTime = DateTime.UtcNow; var predictionsToSave = new List<Prediction>(); for (int i = 1; i < predictions.Forecast.Length; i++) { var predictionDT = predictionTime.AddMinutes(i); var prediction = new Prediction { CoinId = coin.Id, PredictedValue = (decimal)predictions.Forecast[i], PredictionDateTime = new DateTime(predictionDT.Year, predictionDT.Month, predictionDT.Day, predictionDT.Hour, predictionDT.Minute, 0), Interval = IntervalTypes.Minute, CreatedDate = DateTime.UtcNow }; predictionsToSave.Add(prediction); } await _predictionRepository.SetPredictionsAsync(predictionsToSave); } }
问题
该异常中提到的“格式无效的项”具体指什么?或者有什么方法可以排查问题根源?
解答
问题根源分析
异常中的“格式无效的项”本质是训练数据量远小于SSA算法要求的序列长度,导致模型保存时内部数据结构异常,加载时解析失败。
查看训练代码的参数:
seriesLength: 60 * 60 * 24(即86400),表示算法期望的时间序列总长度- 但实际训练数据仅60条,远小于该值。
SSA算法依赖足够的序列数据完成时间序列分解,当实际数据量远小于指定的seriesLength时,模型内部的矩阵计算、特征分解会生成不符合预期的中间数据,保存模型时这些异常数据被写入文件,加载时就会触发格式解析错误。
排查与修复步骤
匹配序列长度与实际数据量
调整seriesLength和trainSize参数,使其不超过实际训练数据的数量。比如仅60条数据时,可设置:var trainer = mlContext.Forecasting.ForecastBySsa( outputColumnName: nameof(ForecastResult.Forecast), inputColumnName: nameof(PriceForML.Value), windowSize: 30, // 设置为数据量的一半左右即可 seriesLength: 60, // 等于实际训练数据量 trainSize: 60, horizon: 5, confidenceLevel: 0.95f, confidenceLowerBoundColumn: "ConfidenceLowerBound", confidenceUpperBoundColumn: "ConfidenceUpperBound");验证模型保存完整性
- 训练完成后,检查
MinuteModel.zip的大小是否合理(空模型或异常模型通常体积很小) - 可尝试解压模型文件,确认内部
data文件存在且有有效内容(ML.NET模型为二进制格式,无需直接查看内容,仅需确认文件未损坏)
- 训练完成后,检查
检查数据类型一致性
确保训练和预测时使用的PriceForML类结构完全一致,字段名称、数据类型(float)无差异,避免加载模型时出现schema不匹配。添加训练时的数据量验证
在训练代码中添加日志,确认实际传入的训练数据条数:var dataCount = mlContext.Data.CreateEnumerable<PriceForML>(newData, reuseRowObject: false).Count(); _logger.LogInformation($"实际训练数据条数:{dataCount}");确保数据量符合预期,未出现空数据或数据丢失情况。
内容的提问来源于stack exchange,提问作者Luis Agudo
相关产品推荐
相关产品推荐

