窓を作っては壊していた人のブログ

この謎のブログタイトルの由来を知るものはもういないだろう

ML.NETのTensorFlowモデル学習サポートの簡易的な変遷

数ヶ月の間にAPIガリガリ変わって、以前作ったコードのままでパッケージのバージョンが上げられなくなりました。 マイグレーションどうすればいいの?みたいなマイグレーションガイドが全く存在していないので(experimentalなAPIではありますし…)備忘録的に書いておこうと思います。

あらかじめおことわりしておきますが、公式ドキュメントのSampleにある転移学習とかに使う、みたいなメジャーだったり正道なものは載せないつもりです(コピペで終わるし…)。

ざっくりとした歴史

Microsoft.ML 1.x 以前

machinelearning/release-0.5.md at master · dotnet/machinelearning · GitHub

0.5.0からTensorFlowのPreTrainedモデルのサポートが始まりました。 実際に使い始めたのが0.9.0のタイミングからなのでこの辺りは省略します(

0.9.0ではTrainPipelineに TensorFlowEstimator を渡す形で使われていました。

somepipelines.Append(new TensorFlowEstimator(mlContext, new TensorFlowTransform.Arguments()
{
    ModelLocation = "ModelのPATH"
    InputColumns = new[] { "X" },
    OutputColumns = new[] { "Converted" },
    LabelColumn = "Y",
    TensorFlowLabel = "Y",
    OptimizationOperation = "Optimizer",
    LearningRateOperation = "LearningRate",
    LossOperation = "Loss",
    Epoch = 10,
    ReTrain = true
}));

var model = somepipelines.Fit(preprocessedData);

この辺のTrain方法はtestを見てもなかったはずなので、このやり方でやっている人あまりいないんじゃないかなぁという感じはあります。 この頃は TensorFlow 1.10.0APIを使用しています。 そのためモデルのFreezeなどを行う場合はその付近のバージョンを使っておいた方が良いみたいな事がありました(モデルのフォーマット自体は変わってないから問題ないはずなんだけど…)。

Microsoft.ML 0.11.0、Microsoft.ML.TensorFlow 0.11.0の段階で TensorFlow 1.12.0 に移りましたが、記法などは基本的に変わっていません。

Microsoft.ML 1.0.0

TensorFlowサポートのライブラリのナンバリングがずれている(?)のが完全にトラップでした。 Microsoft.ML.TensorFlow 0.12.0を使っておけば問題ないです。

また記法ですが

somepipelines.Append(mlContext.Model.LoadTensorFlowModel("ModelのPATH")
    .RetrainTensorFlowModel(
     inputColumnNames: new[] { "X"  },
     outputColumnNames: new[] { "Converted" },
     labelColumnName: "Y",
     tensorFlowLabel: "Y",
     optimizationOperation: "Optimizer",
     epoch: 20,
     learningRateOperation: "LearningRate",
     lossOperation: "Loss"
    ));

var model = somepipelines.Fit(preprocessedData);

に変わりました。 これはML.NETのEstimatorのtrainerのinterfaceが変わったことにも影響を受けている印象を受けます。 このバージョンより LoadTensorFlowModel で生成されたEstimatorからScoreやRetrainに繋げられて、非常に書き味の良いAPIに変わっています。 1.0.0以前から 1.0.0に以降する場合はTensorFlowTransformのArgumentの中身をそのままコピペしてメンバではなく引数として渡すだけでマイグレーションは完了します。 これ以降のバージョンはこの記法をベースにしているので、TensorFlowで生成したregressionモデルを再学習したい、みたいな場合はこの書き方を覚えておくと良いと思います。

Microsoft.ML 1.1.0

特に変更点なし。 Microsoft.ML.TensorFlow 0.13.0 に変更と、TensorFlow 1.13.1 がバックエンドになりました。

Microsoft.ML 1.2.0

Retrainが消えました。

Internalize tensorflow API and sanity check APIs from Microsoft.ML.Tensorflow nuget by codemzs · Pull Request #3936 · dotnet/machinelearning · GitHub

Scoreを使わない再学習の方法がパット見見当たらなくなったはずです(これで出来るぞみたいのがあったら教えて下さい)。 Microsoft.ML.TensorFlow 1.2.0 に変更になりました。

Microsoft.ML 1.3.1

Microsoft.ML.TensorFlow 1.3.1 に変更になり、TensorFlow 1.14.0 がバックエンドになりました。

またAPIも変わり、TensorFlowと言わずにDNN Estimatorみたいな扱いになりました(変数名にTensorFlowとかガッツリ残っているけど…)。 その記法が、

somepipelines.Append(mlContext.Model.RetrainDnnModel
(
 inputColumnNames: new[] { "X" },
 outputColumnNames: new[] { "Converted" },
 labelColumnName: "Y",
 dnnLabel: "Y",
 optimizationOperation: "Optimizer",
 epoch: 20,
 learningRateOperation: "LearningRate",
 lossOperation: "Loss",
 modelPath: "ModelのPATH"
));

var model = somepipelines.Fit(preprocessedData);

こんな感じです。 1.0.0以前の書き方にまた戻ったみたいな印象を受けますね…

じゃあこういう風に書けば動くんでしょと思うんですけど、実際動かなくなります。

[DNN Training] Failed save model in Microsoft.ML.Transforms.DnnTransformer.SaveModel · Issue #4191 · dotnet/machinelearning · GitHub

1.4.0-previewで保存までは直る見込みではあるのですが、それを読み込むことが出来ない状態になっています。

PRを送ったのですが、さてどうなることでしょうね……

まとめ

ということで、TensorFlowで学習した、もしくはグラフを作ったモデルを再学習したいという場合は、1.0.0もしくは1.1.0を使うのが最適解となっています。

実際どう書けば良いんだよ、フルのコードはどんな感じだよ、みたいのは

github.com

この辺りを参照ください。