先日もちらっと書きました。現行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 件のコメント:
コメントを投稿