先日もちらっと書きました。現行tf2onnx(1.16.1)はnumpy 1.26.4までにしないとダメです。
python -m tf2onnx.convert --saved-model .\saved_model_multi_output\ --output Shinba.onnx
自分はAnacondaの仮想環境使ってるので、Anaconda PowerShell Prompt使って仮想環境をアクティブにして上記コマンドでSavedModel形式の
# TensorSpec を生成(shapeは共通なので固定) input_signature = [ tf.TensorSpec([None, 1], dtype, name=name) for name, dtype in feature_info ] @tf.function(input_signature=input_signature) def serve_fn(*features): return {"output": model(list(features))} saved_model_path = "saved_model_multi_output" tf.saved_model.save(model, saved_model_path, signatures={"serving_default": serve_fn})
とした方を指定して変換。出来上がるShiba.onnxは1.53GBってデカイ! Netron使って開いてみると
って感じです。まあ、こんなのはどうでもいいですが、Graph Properties開くと
と表示されるのが重要で、これを元に
internal class TFShinbaOnnxInput { [ColumnName("baba")] [VectorType(1)] public int[] baba { get; set; } [ColumnName("course")] [VectorType(1)] public int[] course { get; set; } [ColumnName("joucd")] [VectorType(1)] public int[] joucd { get; set; } [ColumnName("kaisaikai")] [VectorType(1)] public float[] kaisaikai { get; set; } [ColumnName("kaisainichi")] [VectorType(1)] public float[] kaisainichi { get; set; } [ColumnName("kaisaituki")] [VectorType(1)] public int[] kaisaituki { get; set; } [ColumnName("kyori")] [VectorType(1)] public float[] kyori { get; set; } [ColumnName("tenko")] [VectorType(1)] public int[] tenko { get; set; } [ColumnName("tousu")] [VectorType(1)] public float[] tousu { get; set; } [ColumnName("trackcd")] [VectorType(1)] public int[] trackcd { get; set; } // uma10 [ColumnName("uma10bareidays")] [VectorType(1)] public float[] uma10bareidays { get; set; } ...
って感じの入力クラスを準備して、先程のGraph Propertiesの最後まで行くと確認出来る出力部分も確認して
internal class TFShinbaOnnxOutput { [ColumnName("output")] public float[] output { get; set; } }
てな感じの出力クラスも用意。
MLContext mLContext = new MLContext(); var inputType = typeof(TFShinbaOnnxInput); // int[]のColumnName一覧 var intColumnNames = inputType.GetProperties() .Where(p => p.PropertyType == typeof(int[]) && p.GetCustomAttributesData().Any(a => a.AttributeType == typeof(ColumnNameAttribute))) .Select(p => p.GetCustomAttributesData() .FirstOrDefault(a => a.AttributeType == typeof(ColumnNameAttribute)) ?.ConstructorArguments[0].Value?.ToString() ?? p.Name) .ToList(); // float[]のColumnName一覧 var floatColumnNames = inputType.GetProperties() .Where(p => p.PropertyType == typeof(float[]) && p.GetCustomAttributesData().Any(a => a.AttributeType == typeof(ColumnNameAttribute))) .Select(p => p.GetCustomAttributesData() .FirstOrDefault(a => a.AttributeType == typeof(ColumnNameAttribute)) ?.ConstructorArguments[0].Value?.ToString() ?? p.Name) .ToList(); var allInputColumns = intColumnNames.Concat(floatColumnNames).ToArray(); var pipeline = mLContext.Transforms.ApplyOnnxModel( modelFile: Properties.Settings.Default.TF_Shinba_Onnx, outputColumnNames: new[] { "output" }, // Netronで確認した出力名 inputColumnNames: allInputColumns // 入力名と一致させる ); var emptyData = mLContext.Data.LoadFromEnumerable(new List<TFShinbaOnnxInput>()); var model = pipeline.Fit(emptyData); var predictionEngine = mLContext.Model.CreatePredictionEngine<TFShinbaOnnxInput, TFShinbaOnnxOutput>(model); var input = new TFShinbaOnnxInput(); input.SetValue(_baba, _courseKB, byte.Parse(_jouCD), _kai, _nichi, _tuki, _kyori, _tenko, _tousu, _trackCD, raceDetails); var prediction = predictionEngine.Predict(input);
って感じにC#でモデルロードして予測が出来ますね😁
0 件のコメント:
コメントを投稿