Translate

2022年2月10日木曜日

手っ取り早く異常検知をAIでためす方法としてPyCaretのチュートリアルAO101を翻訳してみた

 異常検知を行うAIを、誰でもかんたんに手っ取り早く実装したい。しかもOSS(ただ)で。

 という、わがままボディな要求があり、そんなものあるわけねえだろ..とおもって調べてみると..見つかった。

PyCaret というPythonパッケージだ。

PyCaret Home: https://pycaret.org/ 


どうもKaggle界では有名なAutoMLパッケージの一つで、極小の手数で複数のモデルを一気に並行評価でき、しかも(AutoMLなので)ハイパーパラメータまで勝手にチューニングしてくれるという..

 kaggleでPyCaretを使っても成績上位にはならないのだけど、どうも就職活動生は人事がわからないだろうことを見越して、「Kaggleに参加している」「成績は上位ではないが、(PyCaretを使って)12のモデルを評価してスコアを出した」とかいってごまかす定番のツールで、これを知ってる知ってないでIT企業人事部の民度が学生にバレるのだという、恐ろしや..

 

とはいえ、機械学習の勉強をあまりしなくても使えるほど、実装のための手数が少ないので、このPyCaretをためすことにした。

 

おあつらえ向きにPyCaretチュートリアルに異常検知に関するチュートリアルがあったので翻訳してみた。

以下、翻訳文であるが、参照の際は At your own riskでお願いします。

-----

異常検知チュートリアル AN0101(Anomaly Detection Tutorial ANO101) - レベル初級

  • PyCaret 2.2を使用
  • 更新日 2020年11月25日

1.0 チュートリアルの目的


異常検知チュートリアル(ANO101) へようこそ。
このチュートリアルは、あなたがPyCaretの初心者で、`pycaret.anomaly` モジュールを使って異常検知を始めようとしていることを想定しています。


このチュートリアルでは、以下のことを学びます:

  • データの取得 :PyCaret リポジトリからデータをインポートするには?
  • 環境のセットアップ :PyCaret で実験環境をセットアップして異常検知モデルの構築を始めるには?
  • モデルの作成 :モデルを作成し、分析に必要なアノマリーラベルを元のデータセットに割り当てるには?
  • モデルのプロット :様々なプロットを使ってモデルの性能を分析する方法
  • モデルによる予測 :学習されたモデルに基づいて、新しいデータセットや未知のデータセットに異常ラベルを割り当てる方法。
  • モデルの保存/読込 :モデルを保存する。将来使用するためにモデルを保存/ロードする方法


読了までの時間:約25分

1.1 PyCaret のインストール


PyCaret を使い始めるための最初のステップは、PyCaret をインストールすることです。PyCaret のインストールは簡単で、数分しかかかりません。以下の手順に従ってください。

ローカルの Jupyter Notebook に PyCaret をインストールする。

pip install pycaret

Google ColabまたはAzureノートブックへのPyCaretのインストール


!pip install pycaret

1.2 前提条件


  • Python 3.6 以上
  • PyCaret 2.0 またはそれ以上
  • PyCaret のリポジトリからデータを読み込むためのインターネット接続環境
  • 異常検知の基礎知識

1.3 Google Colaboratory 使用者への追記


Google Colabで実行している場合、インタラクティブなビジュアルを表示するために、以下のコードをノートブックの先頭で実行してください。

from pycaret.utils import enable_colab
enable_colab()

1.4 参考

Anomaly Detectiom Tutorial (ANO102) - Level Intermediate

https://github.com/pycaret/pycaret/blob/master/tutorials/Anomaly%20Detection%20Tutorial%20Level%20Intermediate%20-%20ANO102.ipynb

Anomaly Detection Tutorial (ANO103) - Level Expert

https://github.com/pycaret/pycaret/blob/master/tutorials/Anomaly%20Detection%20Tutorial%20Level%20Expert%20-%20ANO103.ipynb

訳者注:2022年2月10日時点での上記リンク先はともに未作成。

2.0 異常検知とは?


異常検知とは、データの大部分と大きく異なることによって疑いを抱かせるような、稀な項目、イベント、または観察を特定するタスクをさします。
通常、異常な項目は、銀行詐欺、構造的欠陥、医療問題、テキストの誤りなど、何らかの問題に変換されます。
異常検知技術には大きく分けて3つのカテゴリが存在します。

  • 教師なし異常検知 :ラベル付けされていないテストデータセットから、データセット内の大部分のインスタンスが正常であるという仮定のもと、残りのデータセットに最も適合しないと思われるインスタンスを探し、異常を検出する技術。
  • 教師あり異常検出 :この手法では、「正常」と「異常」のラベルが付けられたデータセットが必要で、分類器を学習させる。
  • 半教師付き異常検知:与えられた正常な学習データセットから正常な振る舞いを表すモデルを構築し、学習したモデルによって生成されるテストインスタンスの尤度をテストする手法です。


`pycaret.anomaly` モジュールは教師なしおよび教師ありの異常検知技術をサポートします。このチュートリアルでは、教師なし異常検知技術のみを取り上げます。

3.0 PyCaret 異常検知モジュール概要


PyCaret 異常検知モジュール `pycaret.anomaly` は、教師なし機械学習モジュールで、データの大部分と大きく異なることによって疑いを持たれるような、稀な項目、イベント、観測を識別するタスクを実行します。

PyCaret 異常検知モジュールは、`setup()` 関数でセットアップを初期化する際に設定できるいくつかの前処理機能を提供します。
12以上のアルゴリズムと、異常検知の結果を分析するためのいくつかのプロットを備えています。
また、PyCaret の異常検知モジュールには `tune_model()` というユニークな関数が実装されており、分類のための `AUC` や回帰のための `R2` など、教師あり学習の目的を最適化するために異常検知モデルのハイパーパラメータを調整することが可能です。

4.0 チュートリアル用データセット


このチュートリアルでは、UCI の Mice Protein Expression というデータセットを使用します。
このデータセットは、大脳皮質の核画分に検出可能なシグナルを生成した77個のタンパク質/タンパク質修飾の発現レベルから構成されています。
このデータセットには、1つのタンパク質につき合計1080の測定値が含まれています。
各測定値は、独立したサンプル/マウスとみなすことができます。
データセットの詳細については、こちらをご覧ください。

データセットへの謝辞

  • Clara Higuera インフォマティクス学部ソフトウェア工学・人工知能学科、コンプルテンセ大学化学部生化学・分子生物学科、スペイン、マドリッド( mailto:clarahiguera@ucm.es )
  • Katheleen J. Gardiner、タンパク質発現データの作成者および所有者は、現在Linda Crnic Institute for Down Syndrome, Department of Pediatrics, Department of Biochemistry and Molecular Genetics, Human Medical Genetics and Genomics, and Neuroscience Programs, University of Colorado, School of Medicine, Aurora, Colorado, USAに在籍( mailto:katheleen.gardiner@ucdenver.edu)
  • Krzysztof J. Ciosは現在、米国バージニア州リッチモンドのバージニア・コモンウェルス大学コンピューターサイエンス学部、およびポーランドのIITiSポーランド科学アカデミーに在籍。( mailto:kcios@vcu.edu )


オリジナルのデータセットとデータディクショナリーは、ここで参照可能。

5.0 データの取得


データをダウンロードし、`pandas` を使って読み込むか、PyCaret のデータレスポジトリを使って `get_data()` 関数で読み込むことができます(インターネット接続が必要)。

from pycaret.datasets import get_data
dataset = get_data('mice')


未見データに対する `predict_model()` 関数のデモを行うため、実験終了時にオリジナルデータセットから5%のサンプル(54サンプル)を取り出し、予測に使用します。
これは、train/test の分割と混同しないように注意する必要があります。
この特別な分割は、実生活のシナリオをシミュレートするために行われます。
別の見方をすれば、この 54 個のサンプルは、この実験が行われた時点では利用できません。

data = dataset.sample(frac=0.95, random_state=786)
data_unseen = dataset.drop(data.index)

data.reset_index(drop=True, inplace=True)
data_unseen.reset_index(drop=True, inplace=True)

print('Data for Modeling: ' + str(data.shape))
print('Unseen Data For Predictions: ' + str(data_unseen.shape))

6.0 PyCaretの環境設定


`setup()` 関数は、PyCaret の環境を初期化し、モデリングとデプロイのためのデータを準備する変換パイプラインを作成します。
`setup()` は PyCaret の他の関数を実行する前に呼び出す必要があります。
この関数は 1 つの必須パラメータである pandas dataframe を受け取ります。
他のパラメータはオプションで、前処理パイプラインをカスタマイズするために使用されます(後のチュートリアルで紹介します)。

`setup()` が実行されると、PyCaret の推論アルゴリズムが、特定のプロパティに基づいて全ての特徴のデータ型を自動的に推論します。
しかし、ほとんどの場合、データ型は正しく推論されますが、常にそうとは限りません。
そのため、`setup()`が実行された後、PyCaret は素性とその推定されたデータ型を含むテーブルを表示します。
この段階で、すべてのデータ型が正しく推論されているかどうかを確認し、Enter キーを押して実験を続行するか、 quit キーを押して実験を終了することができます。
PyCaret は、機械学習実験を行うために必要ないくつかの前処理を自動的に行うため、データ型 を正しく特定することは基本的に重要です。
これらの前処理タスクは、データ型ごとに異なる方法で実行されます。
そのため、データ型が正しく設定されていることが非常に重要です。

後のチュートリアルでは、`setup()` の `numeric_features` と `categorical_features` パラメータを使って PyCaret が推論したデータ型を上書きする方法を学びます。

from pycaret.anomaly import *

exp_ano101 = setup(data, normalize = True,
                   ignore_features = ['MouseID'],
                   session_id = 123)


セットアップが正常に実行されると、いくつかの重要な情報を含むグリッドが表示されます。
情報の多くは `setup()` 実行時に構築される事前処理パイプラインに関連するものです。
これらの機能の多くは、このチュートリアルの目的からは外れています。
しかし、この段階で注意すべきいくつかの重要なことがあります。

  • セッションID session_id :後々の再現性のために、すべての関数でシードとして配布される擬似乱数。`session_id` が渡されない場合、乱数は自動的に生成され、すべての関数に配布されます。本実験では、後日の再現性を考慮して、`session_id` を `123` としています。 
  • 欠測値:元データに欠損値がある場合、 `True` と表示されます。上の情報グリッドで欠損値が `True` になっているのは、データに欠損値が含まれているためで、数値特徴の場合は平均値、カテゴリー特徴の場合は定数を用いて自動的にインプットされます。代入(インピュテーション)方法は `setup()` の `numeric_imputation` と `categorical_imputation` パラメータで変更することができます。
  • オリジナルデータ:データセットの元の形状を表示します。本実験では、`(1026, 82)` で、 1026 個のサンプルと 82 個の特徴を意味しています。
  • 変換後データ :変換後のデータセットが表示されます。元のデータセット `(1026, 82)` の形状が `(1026, 91)` に変換されていることに注意してください。データセットにカテゴリ特徴(後述)が含まれているため、特徴の数が増えています。
  • 数値特徴量 :数値として推定された特徴量の数。本データセットでは、82 特徴中77特徴が数値として推定されました。
  • カテゴリ特徴量 :カテゴリ(分類)として推定された特徴の数。本データセットでは、82特徴中5特徴がカテゴリとして推論されました。また、`ignore_feature` パラメータを用いて、1つのカテゴリ特徴である `MouseID` を無視していることに注目してください。


このように、欠損値の代入(インピュテーション)やカテゴリカルエンコーディングなど、モデリングを行う上で必須となるいくつかのタスクが自動的に処理されることに注目してください。
`setup()` の他のパラメータのほとんどはオプションであり、前処理パイプラインをカスタマイズするために使用されます。
これらのパラメータはこのチュートリアルの対象外ですが、中級者、上級者になれば、もっと詳しく説明する予定です。

7.0 モデルの作成


PyCaret で異常検知モデルを作成するのは簡単で、PyCaret の supervised モジュールでモデルを作成する方法と似ています。
異常検知モデルは `create_model()` 関数を用いて作成します。
この関数では、モデルの名前という必須パラメータを文字列で受け取ります。
この関数は学習済みのモデルオブジェクトを返します。
以下の例をご覧ください:

iforest = create_model('iforest')
print(iforest)


`create_model()` で Isolation Forest モデル を作成しました。
`contamination` (混成)パラメータは `0.05` に設定されていますが、これは `create_model()` で `fraction` (割合)パラメータを渡さない場合のデフォルト値です。
`fraction` パラメータはデータセット中の外れ値の割合を決定します。
以下の例では、`0.025` の割合で1クラスサポートベクターマシンモデルを作成します。

svm = create_model('svm', fraction = 0.025)
print(svm)


`create_model()` の引数を `iforest` から `svm` に置き換えるだけで、1クラスサポートベクターマシンモデル(OCSVM)の異常検知モデルを作成することができました。
`pycaret.anomaly`モジュールでは12のモデルが用意されています。
完全なリストを見るには、`docstring` を見るか、`models` 関数を使用してください。

models()

8.0 モデルの割り当て


モデルを作成したので、データセット(1080サンプル)に異常ラベルを付与し、結果を分析したいと思います。
これを実現するには、`assign_model()` 関数を使用します。

以下の例をご覧ください:

iforest_results = assign_model(iforest)
iforest_results.head()


`Anomary` と `Anomary_Score` の2列が最後に追加されていることに注目してください。
`Anomary` 値 `0` は範囲内の値、`1` は孤立値/Anomalyを表します。
`Anomary_Score` はアルゴリズムによって計算された値で、外れ値にはより大きな異常値スコアが割り当てられます。

`iforest_results` には、`setup()` で削除した `MouseID` 特徴も含まれていることに注意してください。
これはモデルには使用されず、`assign_model()` を使用したときのみデータセットに追加されます。
次のセクションでは、`plot_model()` を使って異常検知の結果を分析する方法を見ていきます。

9.0 モデルのプロット


`plot_model()` 関数は、異常検知モデルを様々な角度から分析するために使用することができます。
この関数は,学習済みモデルオブジェクトを受け取り、プロットを返します。
以下の例を参照してください:

9.1 T分散確率的近傍埋込み法(t-SNE)

plot_model(iforest)



9.2 一様多様体近似と射影

plot_model(iforest, plot = 'umap')

METADATAファイルがないというエラーが出たが..パッケージ導入ミス?!

10.0 未知データに対する予測


`predict_model()` 関数は、新しい未閲覧のデータセットに異常ラベルを割り当てるために使用されます。
ここでは、`data_unseen` に格納されたデータを予測するために `iforest` モデルを使用します。
これは実験の最初に作成されたもので、これまでPyCaretに公開されていなかった54個の新しいサンプルが含まれています。

unseen_predictions = predict_model(iforest, data=data_unseen)
unseen_predictions.head()


`Anomary` 欄は外れ値(1=外れ値、0=非外れ値)を示しています。
`Anomary_Score` 欄はアルゴリズムによって計算された値で、外れ値にはより大きな異常値スコアが割り当てられます。
`predict_model()` 関数を使用して、学習データにラベルを付けることもできます。
以下の例を参照してください:

data_predictions = predict_model(iforest, data = data)
data_predictions.head()

11.0 モデルの保存


ここまでのチュートリアルでは、`iforest` モデルを使って未見データの外れ値ラベルを予測する実験が終了しました。
これで実験は終わりですが、まだ一つの疑問が残っています。
予測すべき新しいデータが増えたらどうなるのだろうか?
もう一度、この実験をやり直さなければならないのだろうか?
答えは「いいえ」です。

実験全体を再実行し、新しいデータに対して予測を生成するためにパイプラインを再構築する必要はありません。PyCaret の組み込み関数 `save_model()` は、変換パイプライン全体と共にモデルを保存し、再利用することができます。

save_model(iforest,'Final IForest Model 25Nov2020')

12.0 保存されたモデルのロード


保存したモデルを将来同じ環境または異なる環境でロードするには、PyCaret の `load_model()` 関数を使用し、保存したモデルを新しい未知のデータに簡単に適用して予測します。

saved_iforest = load_model('Final IForest Model 25Nov2020')

一旦モデルが環境にロードされると、同じ `predict_model()` 関数を使用して新しいデータに対して予測するためにそれを単純に使用することができます。
以下では、上記のセクション10で使用したのと同じ `data_unseen` を予測するために、ロードされたモデルを適用しています:

new_prediction = predict_model(saved_iforest, data=data_unseen)
new_prediction.head()

`unseen_prediction` と `new_prediction` の結果は同じであることに注意してください。

13.0 まとめ/次のステップへ?


このチュートリアルでは、`pycaret.anomaly` の基本的な部分のみを取り上げました。
次のチュートリアルでは、データサイエンティストなら必ず知っておくべき、機械学習パイプラインを完全にカスタマイズできる高度な前処理技術に深入りしていきます。

それでは、次回のチュートリアルでお会いしましょう。Anomaly Detection Tutorial (ANO102) - Level Intermediate へのリンクをたどってください。

------

AO102以降のリンクは、本記事執筆時点では未作成だった。

上記チュートリアルには教師なし学習でのクラスタリングしか書かれていないが、分類についても別のチュートリアル(異常検知データセットではないが)があるので、すぐに理解できると思う。

AutoMLか..むかし昭和一桁の親父が安物カメラをくれたとき、「バカ○○○だからだれでも使えるぞ」といっていたが、AutoMLがまさにそうだ。

情報という科目はAIやデータ分析のちからを養うために入試化されるそうだけど、使うほうがどんどん簡単になるので、なくてもいいかもなあ...



2022年1月12日水曜日

富岳上でTensorFlowサンプルを動かす



前記事

「富岳上に tkinter が使用可能な TensorFlow 2.2.0 をインストールする方法 」
https://fight-tsk.blogspot.com/2021/12/tkinter-tensorflow-220.html


では、TensorFlow2.2.0が動作する環境をPythonともども富士通提供のソースコードからコンパイルして構築した。

富士通提供の富岳でも動作する TensorFlow ソースコード(a64fxブランチ)
https://github.com/fujitsu/tensorflow/tree/fujitsu_v2.2.0_for_a64fx



では、ビルドした環境が正常に動作するのかを確認するにはどうすればいいか。

そのために(?)提供されているのが fcc_build_script/sample_script にあるサンプルコード群である。



ここには

  • 01_resnet
  • 02_OpenMNT
  • 03_Bert
  • 04_Mask-R-CNN

の4つのサンプルコードが用意されている。

これらのディレクトリ内にはバッチスクリプトが提供されており、順番に富岳の計算ノード上で動かせば実行できる


..と思ったのだが、なかなか動作しない。

ここでは、2022/1/12時点の環境で実行するために修正をいれた内容を紹介する。


全体共通


env.src の編集


サンプルコードのスクリプトは基本的に fcc_build_script/env.src を使用する。
このため、env.srcが富岳の環境に合致するように環境変数を変更しておく必要がある。

以下、前記事でも書いた2022/1/12時点で動作した修正箇所である。

PREFIX=${HOME}/.local/aarch64
TCSDS_PATH=/opt/FJSVxtclanga/tcsds-1.2.33
VENV_PATH=${HOME}/.local/aarch64/venv/tensorflow
PREFIXVENV_PATHは各自のホームディレクトリの使い方で異なるので、それぞれに合わせて変更しておく。

01_resnet

10_setup_resnet.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "proc=1"
#PJM -S

11_train_resnet-single.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "proc=1"
#PJM -S
富岳のスレッドは8でそのうち0から3の4つは使用できないので、NUMA_NODEを修正する。
NUMA_NODE=4

12_train_resnet-4process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。
また、複数プロセスの実行となるのでmpiオプションなどが異なっていることに注意のこと。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S
#PJM -L "node=1:noncont"
#PJM --mpi "shape=1,proc=4"
#PJM -j

ステップジョブ実行

ログインノードで 01_resnet ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 10_setup_resnet.sh
pjsub --step --sparam "jid=XXXXXXX" 11_train_resnet-single.sh
pjsub --step --sparam "jid=XXXXXXX" 12_train_resnet-4process.sh

02_OpenNMT

20_setup_OpenNMT の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "proc=1"
#PJM -S

21_train_OpenNMT_Transformer-single.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -L "node=1"
#PJM -S
富岳のスレッドは8でそのうち0から3の4つは使用できないので、NUMA_NODEを修正する。
NUMA_NODE="4,5"

22_train_OpenNMT_Transformer-2process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "shape=1,proc=2"
#PJM -S
環境変数MPIには、並列プログラム実行プレフィックスが格納されている。
デフォルトではなぜか富岳上のmpirunではサポートされていないオプション --display-map 、 --display-allocation 、 --map-by が付いているのでこれらを除去する。

  MPI="mpirun -np 2"

ステップジョブの実行

ログインノードで 02_OpenNMT ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 20_setup_OpenNMT.sh
pjsub --step --sparam "jid=XXXXX" 21_train_OpenNMT_Transformer-single.sh
pjsub --step --sparam "jid=XXXXX" 22_train_OpenNMT_Transformer-2process.sh

03_Bert

300_setup_bert.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

311_create_pretraining_data.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

312_run_pretraining.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

numactl のオプションは変更しなくても良い(使われていないので)。

313_run_pretraining-2process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "shape=1,proc=2"
#PJM --mpi "max-proc-per-node=4"
#PJM -S
環境変数MPIから富岳上のmpirunに実装されていないオプションを除去する。
MPI="mpirun -np 2"

321_create_finetuning.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

322_run_finetuning.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S
環境変数NUMAは使用されていないのでそのままでもよい。

323_run_finetuning-2process.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#!/bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM --mpi "shape=1,proc=2"
#PJM --mpi "max-proc-per-node=4"
#PJM -S
環境変数MPIから富岳上のmpirunに実装されていないオプションを除去する。
MPI="mpirun -np 2"

ステップジョブの実行

ログインノードで 03_bert ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 300_setup_bert.sh
pjsub --step --sparam "jid=XXXXX" 311_create_pretraining_data.sh
pjsub --step --sparam "jid=XXXXX" 312_run_pretraining.sh
pjsub --step --sparam "jid=XXXXX" 313_run_pretraining-2process.sh
pjsub --step --sparam "jid=XXXXX" 321_create_finetuning.sh
pjsub --step --sparam "jid=XXXXX" 322_run_finetuning.sh
pjsub --step --sparam "jid=XXXXX" 323_run_finetuning-2process.sh

04_Mask-R-CNN

libxml2/libxsltのコンパイル

Mask R CNN のトレーニング処理を実行するためには、contextlib2 というPythonパッケージが必要になる。その前提としてlibxml2/libxsltライブラリが必要となるため、先にホームディレクトリ内でコンパイル・インストールする。
http://xmlsoft.org/downloads.html からlibxml2とlibxsltのソースコードをダウンロード
富岳上へソースをコピーし展開(以下では ${HOME}/.tmp 直下に2つとも展開し${HOME}/.local/aarch64へインストールする前提での記述となる)する。
 
cd ${HOME}/.tmp/libxml2
make clean
source ${PYTHONHOME}/bin/activate
./autogen.sh --prefix=${HOME}/.local/aarch64 --with-python-install-dir=${HOME}/.local/aarch64/venv/tensorflow
make
make install
cd ../libxslt
./autogen.sh --prefix=${HOME}/.local/aarch64 --with-python-install-dir=${HOME}/.local/aarch64/venv/tensorflow
make
make install

40_setup_mask-r-cnn.sh の編集

スクリプト先頭のPJMコメントを以下のように修正する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

41-0_download_traindata.sh の編集

スクリプト先頭のPJMコメントを以下のように追加する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

41-1_setup_traindata.sh の編集

スクリプト先頭のPJMコメントを以下のように編集する。
なお rscunit は各自の環境に合わせて編集すること。 

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

42_train_maskrcnn_single.sh の編集

スクリプト先頭のPJMコメントを以下のように編集する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -S

43_train_maskrcnn_multi.sh の編集

スクリプト先頭のPJMコメントを以下のように編集する。
なお rscunit は各自の環境に合わせて編集すること。

#! /bin/bash
#PJM --rsc-list "node=1"
#PJM --rsc-list "rscunit=rscunit_ft99"
#PJM --rsc-list "rscgrp=small"
#PJM --rsc-list "elapse=72:00:00"
#PJM -L "node=1:noncont"
#PJM --mpi "shape=1,proc=2"
#PJM -S
環境変数MPIRUNから富岳上のmpirunに実装されていないオプションを除去する。
MPIRUN="mpirun -np 2"

ステップジョブの実行

ログインノードで 04_Mask-R-CNN ディレクトリ上にてステップジョブ実行する。

chmod +x ./*.sh
pjsub --step 40_setup_mask-r-cnn.sh
pjsub --step --sparam "jid=XXXXX" 41-0_download_traindata.sh
pjsub --step --sparam "jid=XXXXX" 41-1_setup_traindata.sh
pjsub --step --sparam "jid=XXXXX" 42_train_maskrcnn_single.sh
pjsub --step --sparam "jid=XXXXX" 43_train_maskrcnn_multi.sh

以上

2021年12月9日木曜日

富岳上に tkinter が使用可能な TensorFlow 2.2.0 をインストールする方法

 2021/12/09 時点における富岳環境では、TensorFlow 2.2.0 が使用可能であるが、有効にした場合の Python は tkinterが使用できない。

富岳上で動作する TensorFlow 2.2.0 のソースコードは、以下のリポジトリにて管理されている TensorFlow ブランチとして公開されている。
 


上記サイトのWikiに、日本語のセットアップ手順つきで提供されている。
この手順通りに実行することで、 tkinter が無効な TensorFlow 2.2.0 実行環境をホームディレクトリ上に構築することができる。

注意

上記サイトをそのまま実行する場合、以下の項目に注意すること。

  • 必ず富岳計算ノード上で実行する
  • 会話ジョブで実行する場合、オプションなしスクリプト実行は、各スクリプトごとに会話ジョブを終了・立ち上げる(実行に時間がかかるのでタイムアウトで失敗しないように)
  • 失敗したら、使ったリポジトリは削除して、git checkoutからやりなおす
  • 全スクリプトを download オプション付きで実行しておく(これもタイムアウト対策)
  • spack は使わない(ガイドどおりにセットアップしても現時点で動作しない、富岳は環境が頻繁に変わるしサポートも弱い)

そこでこの記事では、上記サイト上のスクリプトを利用して tkinter が有効な Python 管理下での TensorFlow 2.2.0 実行環境を構築する手段を紹介する。
 

注意
本リポジトリは、2021/12/09 時点の富岳環境での動作を確認している。
富岳は、随時かつ頻繁に環境更新がおこなわれているため、本リポジトリの情報がすでに使用できない可能性がある。使用の際は、各自の責任にて判断のこと。

インストール手順

  • 計算ノードへログイン
  • 以下のコマンドを実行

  cd ${HOME}
  mkdir projects
  cd projects
  git clone https://github.com/coolerking/fugaku_sample
  cd fugaku_sample
  git checkout master
  cd tensorflow

  • env.src_fugakuを確認する。env.src は、デフォルトの設定から以下の環境変数を変更している。必要に応じて値を変更する。 
    • PREFIX : バイナリおよびライブラリの配置先ディレクトリ 
    • TCSDS_PATH : 富士通コンパイラのベースディレクトリ(定期的にバージョンが更新される) 
    • VENV_NAME : Python venv環境の配置先ディレクトリ

    PREFIX=${HOME}/.local/aarch64
    TCSDS_PATH=/opt/FJSVxtclanga/tcsds-1.2.33
    VENV_PATH=${HOME}/.local/aarch64/venv/tensorflow

  • 01_tensorflow.sh を確認する。有効なメールアドレスへの書き換えを行う。

  #PJM --mail-list "hogehoge@fugafuga.slack.com"
 

  • 以下のコマンド実行

  chmod +x 01_tensorflow
  pjsub 01_tensorflow.sh

注意

試行時は、ジョブ開始から完了まで7時間半ほどかかった。


TensorFlow 2.2.0 の利用


以下のコマンドを計算ノード上で実行し、venv環境 tensorflow を有効化する。

source ${HOME}/.local/aarch64/venv/tensorflow/bin/activate
動作を確認したい場合は、計算ノード上で以下のコマンドを実行する。
python -c "import tkinter"
python -c "import tensorflow"

備考

  • インストールされる tcl/tk は、富士通コンパイラではなく、gccコンパイラによりビルドされている(Python/TensorFlowは富士通コンパイラでビルドされる)
  • ビルドされるTensorFlowはGPUは使用できない(計算ノードにはGPUが搭載されていない)かわりにoneDNNを使用したCPU高速化が行われている
  • 上記手順を実行するとPython上でMPI相当の実装が可能になる horovod パッケージもあわせて構築される
  • TensorFlow 2.2.0 には、mesh-tensorflow が未実装のバージョンのため使用できない

参考

2021年9月21日火曜日

勝手日本語翻訳→「HuggingFace と Unity を使ってスマートロボットAIを構築する~あなたの命令に従うロボット」

タイムラインにちょっとおもしろそうなハンズオンのリンクが回ってきた

どうもHugging Face上のAPIとUnityで作ったロボットを連携させて、指示文書を英語で入力すると、それに合わせた動作をUnity内のロボットが動いてくれるというプログラムをつくることができるらしい。

ただ..AIはAPIまかせだし、Unity部分はそっくりコピペなので、いちから手順を学べるかというとそうではない。

ただ手順通りにすれば、すぐに動かすことはできそうな状態のようによめたので、シルバーウィークの暇な時間を潰すのにはいいかもしれない。

以下、勝手に日本語化した翻訳文だけど、参照は at your own riskでお願いします。

なお画像については原文画像へのリンクで貼り付けているので、別ウィンドウで開いてみてください

-----

HuggingFace と Unity を使ってスマートロボットAIを構築する~あなたの命令に従うロボット


今日は、プレイヤのテキスト入力に基づいてアクションを実行するこの愛らしいスマートロボットを構築します。


深層言語モデルを使ってテキスト入力を解釈し、行動リストのなかから最も適切なアクションを見つけます。

このシステムで興味深いのは、従来のゲーム開発とは対照的に、すべてのインタラクションをハードコーディングする必要がないことです。
代わりに、与えられたユーザ入力に最も適切なロボットの可能なアクションを選択する言語モデルを使用します。


このプロジェクトの構築には、以下のものを使用します:

  • Unity Game Engine (2020.3.18.f1 and +)
  • (MixとJamによって作成された)Jambo Robot アセット
  • Hugging Face


この記事は、Unity に関する基礎的なスキルをすでに持っている人を対象としています。
ロボットとの対話をためしてみたいだけの場合は、プロジェクトページに移動し、圧縮されたファイルをダウンロードして、ドキュメントに従ってください。
 


では、はじめましょう!

文章類似(Sentence Similarity)判定能力


いきなり実装に飛び込む前に、プロジェクトがどのように機能して、文章類似判定が何であるかを理解する必要があります。

プロジェクトはどのように機能するのか?


このプロジェクトでは、プレイヤにより多くの自由を与えたいと思っています。
ボタンをクリックするだけでロボットに注文を出すのではなくテキストを介してロボットと対話してもらいたいのです。
ロボットにはあらかじめ行動リストをもっていて、プレイヤの指示に最も近いアクション(存在する場合は)を選択する文章類似判定モデルを使用します。


たとえば、「ちょっと赤い箱をつかんで (hey grab me the red box)」と書いた場合、ロボットは「ちょっと赤い箱をつかんで」が何を意味しているのかについてプログラムされていません。
しかし、文章類似判定モデルモデルは、この指示と「赤い立方体を持ってくる」というアクションを結び付けます。


文章類似判定モデルに仕事をまかせるという手法のおかげで、プレーヤによる入力とロボットの行動可能なすべてのインタラクションをを手作業でマッピングするという面倒なプロセスを必要とせずに、信頼性の高いキャラクタAIを構築することができます

文章類似判定とは何か?


文章類似判定は、ソースとなる文章と文章リストが与えられた場合に、文章リストの各文がソースとなる文章とどのくらい類似しているかを計算できる言語モデルでおこないます。
たとえば、ソースとなる文章が「やあ、ここだよ! (Hey there)」の場合 「こんにちは! (Hello)」という行動をあらわす文章がとても近いと判断します。


ここでは、文章変換モデル all-mpnet-base-v2 を使用します。
このモデルを使用すると、入力テキストを指定して、実行するのに最も適切なアクションをロボットに「決定」させることができます。
モデルはすでにトレーニングされているため、すぐに使用することができます。

ステップ1:文章類推判定モデルを選択する

HuggingFace 入門


HuggingFace には、多くのすばらしい言語モデルと、それらをプロジェクトに直接プラグインするためのAPI(Accelerated Inference API)が含まれています。
ただし、最初に アカウントを作成 する必要があります。


アカウントを作成したら、Accelerated Inference APIダッシュボードに移動し、プロファイル(右上隅)とAPIトークンをクリックします。


APIトークンをコピーします。
これは、APIを使用できるようにするために必要なキーです。

セキュリティ上、このキーは共有しないでください。これは秘密キーです。

Accelerated Inference API


APIキーを取得したら、次はモデルを選択します。

ここでは、文章類推判定モデル all-mpnet-base-v2 を選択しました:


他の文章類推判定モデルを自由に試してもかまいません。

素晴らしいのは、Hosted Inference API を使用してWebサイトでモデルを直接試すことができることです。
テストをしてみましょう:


「赤いブロックをつかんできなさい (fetch the red block)」はロボットのアクション「赤い立方体を持ってくる (bring me the red cube)」に近いので、モデルは正しく機能していることがわかります。

このモデルを選択することにしたので、API URL を取得します。
それには、「Deploy」>「Accelerated Inference」をクリックして、


API_URLがコピーできるモーダルを開きます。

これで API を Unity に接続する準備が整いました。

ステップ2:Hugging Face API を Unity に接続する


次に、Hugging FaceモデルAPIをUnityに接続し、使用可能にする必要があります。

Scenes/Tutorial にある Scripts/Tutorial_ を開きます:


シーンは次のようになります。
ロボットはさまざまなオブジェクト(BlueCube、RedCube、RedPillarなど)に囲まれています。


Scripts/Tutorial にて `HuggingFaceAPI_Tutorial.cs` を開きます:


このスクリプトはPOSTリクエストを処理し、プレーヤの入力が行動リスト内の各ロボットアクション文の類似性スコアを返すようにAPIに要求し、そこから最も高い類似性スコアを持つアクションを選択できるようになります。

`HFScore()` :APIの呼び出し


APIを呼び出して結果を処理するには、コルーチン関数を使用します。
このタイプの関数は実行を待機できるため、実行を続行する前に、そのAPIが応答を返すのを待機する必要があります。

  • 最初に、つぎのようなPOSTリクエストのJSONを作成する。


`HuggingFaceAPI_Tutorial.cs`:


public IEnumerator HFScore(string prompt)
{
        // Form the JSON
        var form = new Dictionary<string, object>();
        var attributes = new Dictionary<string, object>();
        attributes["source_sentence"] = prompt;
        attributes["sentences"] = sentences;
        form["inputs"] = attributes;

        var json = Json.Serialize(form);
        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(json);
}

  • 次に、Webリクエストを行い、応答する。


`HuggingFaceAPI_Tutorial.cs`:

public IEnumerator HFScore(string prompt)
{
  ...
 
  // Make the web request
        UnityWebRequest request = UnityWebRequest.Put(model_url, bytes);
        request.SetRequestHeader("Content-Type", "application/json");
        request.SetRequestHeader("Authorization", "Bearer " + hf_api_key);
        request.method = "POST"; // Hack to send POST to server instead of PUT

        yield return request.SendWebRequest();

        // If the request return an error set the error on console.
        if (request.isNetworkError || request.isHttpError)
        {
            Debug.Log(request.error);
            Debug.Log(request.downloadHandler.data);
            yield return request.error;
        }
        else
        {
            JSONNode data = request.downloadHandler.text;
            // Process the result
            yield return ProcessResult(data);
        }
    }

  • 応答は `[0.7777,0.19,0.01]` のような文字列となる。これを操作するには、`float` 配列に変換する必要がある( `ProcessResult(data) にて処理)。

`ProcessResult()` :結果を `float` 配列に変換し、最大スコアと最大スコアインデックスを発見する


APIは文字列 `[0.77, 0.18, 0.01,…]` を返しますが、ここでは最高のスコアとそのインデックスを見つける必要があります。

したがって、結果文字列を浮動小数点数の配列 `[0.77、0.19、0.01]` に変換し、最大スコアと最大スコアインデックスを見つける必要があります。

この処理は `ProcessResult()` 関数でおこないます。

`HuggingFaceAPI_Tutorial.cs`:

/// <summary>
    /// We receive a string like "[0.7777, 0.19, 0.01]", we need to process this data to transform it to an array of floats
    /// [0.77, 0.19, 0.01] to be able to perform operations on it.
    /// </summary>
    /// <param name="result">json return from API call</param>
    private IEnumerator ProcessResult(string result)
    {
        // The data is a score for each possible sentence candidate
        // But, it looks something like this "[0.7777, 0.19, 0.01]"
        // First, we need to remove [ and ]
        string cleanedResult = result.Replace("[", "");
        cleanedResult = cleanedResult.Replace("]", "");

        // Then, we need to split each element of the array and convert to float
        string[] splitArray = cleanedResult.Split(char.Parse(","));
        float[] myFloat = splitArray.Select(float.Parse).ToArray();

        // Now that we have a array of floats, we can find the max score and the index of it.
        // We don't need to return these 2 variables, we'll access them directly since they are public.
        maxScore = myFloat.Max();
        maxScoreIndex = myFloat.ToList().IndexOf(maxScore);

        yield return null;
    }



この関数により、正しいアクションを選択するために `RobotBehavior` で呼び出す `maxScoreIndex` 変数と `maxScore` 変数を更新しました。

インスペクタへ入力する


ロボットの動作に取り組む前の最後のステップは、APIキーとモデルのURLをインスペクタに入力することです。
シーン内の `HuggingFaceAPI` オブジェクトをクリックし、インスペクタで `Model_url` と `Hf_api_key` を更新します。

APIキーを定義する場合は、プロジェクトを共有しないでください。

ステップ3:ロボットの動作を構築する


Unityプロジェクトを HuggingFace Model API に接続したので、ロボットの動作を定義する必要があります。
ロボットにはさまざまなアクションがあり、アクションの選択はAPI出力に依存するという考え方です。

まず、有限ステートマシンを定義する必要があります。
これは、各状態が特定の動作を定義する単純なAIです。

次に、状態を選択するユーティリティ関数を作成し、実行する一連のアクションを作成します。

ステートマシンを定義する


ここでのステートマシンは、各状態は動作を表します。
状態の例として、整列して「こんにちは」と言う、などになります。

エージェントの状態に基づいて、一連のアクションを実行します。
ここでは、7つの状態を定義します。


まず、すべてのアクション可能な状態を `State` という列挙型として作成します。

`JummoBehavior_Tutorial.cs` :

/// <summary>
/// Enum of the different possible states of our Robot
/// </summary>
private enum State
{
  Idle,
  Hello, // Say hello
  Happy, // Be happy
  Puzzled, // Be Puzzled
  MoveTo, // Move to a pillar
  BringObject, // Step one of bring object (move to it and grab it)
  BringObjectToPlayer // Step two of bring object (move to player and drop the object)
}


常に状態をチェックする必要があるため、それぞれのケースが状態であるスイッチシステムを使用して、ステートマシンを `Update()` メソッドに定義します。

状態のケースごとに、エージェントの動作を定義します。

たとえば、状態 `Hello` では、ロボットはプレーヤに向かって移動し、プレーヤに正しく向き合ってから、`hello` アニメーションを起動してから、アイドル状態に戻る必要があります。


すべてを定義しましょう:

`JummoBehavior_Tutorial.cs` :

private void Update()
    {
        // Here's the State Machine, where given its current state, the agent will act accordingly
        switch(state)
        {
            default:
            case State.Idle:
                Debug.Log("STATE IDLE");
                break;

            case State.Hello:
                agent.SetDestination(playerPosition.position);
                if (Vector3.Distance(transform.position, playerPosition.position) < reachedPositionDistance)
                {
                    RotateTo();
                    anim.SetBool("hello", true);
                    state = State.Idle;
                }
                break;

            case State.Happy:
                agent.SetDestination(playerPosition.position);
                if (Vector3.Distance(transform.position, playerPosition.position) < reachedPositionDistance)
                {
                    RotateTo();
                    anim.SetBool("happy", true);
                    state = State.Idle;
                }
                break;

            case State.Puzzled:
                Debug.Log("CASE STATE PUZZLED");
                agent.SetDestination(playerPosition.position);
                if (Vector3.Distance(transform.position, playerPosition.position) < reachedPositionDistance)
                {
                    RotateTo();
                    anim.SetBool("puzzled", true);
                    state = State.Idle;
                }
                break;

            case State.MoveTo:
                agent.SetDestination(goalObject.transform.position);
                
                if (Vector3.Distance(transform.position, goalObject.transform.position) < reachedPositionDistance)
                {
                    state = State.Idle;
                }
                break;

            case State.BringObject:
                // First move to the object
                agent.SetDestination(goalObject.transform.position);
                if (Vector3.Distance(transform.position, goalObject.transform.position) < reachedObjectPositionDistance)
                {
                    Grab(goalObject);
                    state = State.BringObjectToPlayer;
                }
                break;

            case State.BringObjectToPlayer:
                agent.SetDestination(playerPosition.transform.position);
                if (Vector3.Distance(transform.position, playerPosition.transform.position) < reachedObjectPositionDistance)
                {
                    Drop(goalObject);
                    state = State.Idle;
                }
                break;
        }
    }


これで、さまざまな状態ごとの動作を定義できました。

ここでの魔法は、どの状態がプレーヤ入力に最も近いかを定義する言語モデルであるということから生まれました。
そして、ユーティリティ関数では、この状態を呼び出します。

ユーティリティ関数を定義する


アクションリストは次のとおりです:

 

  • SentenceがAPIに供給される
  • Verbは状態をあらわしている
  • Noun(存在する場合)は、対話するオブジェクト(柱、立方体など)をさす


このユーティリティ関数は、プレーヤの入力テキストとの類似性スコアが最も高い文に関連付けられている動詞と名詞を選択します。

しかし最初に多くの奇妙な入力テキストを取り除くために、類似性スコアのしきい値を設定する必要があります(しきい値を `0.20` に設定していますが、このしきい値はアクション数に比例した値を設定する必要があります)。

たとえば、「すべてのウサギを見て (Look all the rabbits)」と言った場合、考えられるアクションはどれも関係ありません。
このため、スコアが最も高いアクションを選択するのではなく、State Puzzled という困惑したアニメーションでロボットをうごかします。


スコアが高い場合は、`state` に対応する `verb` と、(存在する場合は)`noun`( `goalObject` )を取得します。

`verb` に対応する `state` を設定します。
これにより、対応する動作が有効になります。

`JummoBehavior_Tutorial.cs` :


/// <summary>
    /// Utility function: Given the results of HuggingFace API, select the State with the highest score
    /// </summary>
    /// <param name="maxValue">Value of the option with the highest score</param>
    /// <param name="maxIndex">Index of the option with the highest score</param>
    private void Utility(float maxScore, int maxScoreIndex)
    {
        // First we check that the score is > of 0.3, otherwise we let our agent perplexed;
        // This way we can handle strange input text (for instance if we write "Go see the dog!" the agent will be puzzled).
        if (maxScore < 0.20f)
        {
            state = State.Puzzled;
        }
        else
        {
            // Get the verb and noun (if there is one)
            goalObject = GameObject.Find(actionsList[maxScoreIndex].noun);

            string verb = actionsList[maxScoreIndex].verb;

            // Set the Robot State == verb
            state = (State)System.Enum.Parse(typeof(State), verb, true);
        }
    }



これで、ロボットと対話する準備が整いました。

ステップ4:ロボットと対話する


このステップでは、エディタの再生ボタンをクリックするだけです。
そうすれば、あなたはいくつかの指示をだして結果を見ることができます。

指示の入力が終了したら、Enterキーを押すことを忘れないでください。

いくつかのバグ、特にモデルの読み込みのバグがある可能性があります。

ロボットがアイドルモードのままになっている場合は、初回モデル読込中の可能性があるため、45秒ほど待ちます。
コンソールでエラーメッセージを確認してください。

次は?


アクションを追加するにはどうすればよいですか?

例を見てみましょう:

  • `YellowPillar` ゲームオブジェクトをコピーし移動
  • 名前を `GreenPillar` に変更
  • 新しいマテリアルを作成し、それを緑に設定 (RGB:)
  • `GreenPillar` にマテリアルを配置


新しいゲームオブジェクトを配置したので、文を追加する必要があります。
`Jammo_Player` をクリックします。
アクションリストで、プラスボタンをクリックして、次の新しいアクション項目を入力します:

 

  • Move to green pillar
  • Move To
  • GreenColumn


以上になります。



今日はこれですべてになります。

指示に基づいてアクションを実行できるロボットを作成する手順を紹介しました。

これはすばらしいことです。

次にできることとしては、Scripts/Final にあるコードを深く掘り下げ、Scenes/ Finalの最終シーンを確認することなどです。

必要な部分についてはすでにコメントしているので、それは比較的簡単にできるとおもいます。

言語モデルとトランスフォーマについてもっと知りたい場合は、Hugging Face コースをチェックしてください(無料です):

2021年8月17日火曜日

OpenAI Gym 独自Envクラス内でmlflowを使う

OpenAI Gym の独自Envで強化学習を行う場合、評価したいパラメータは独自Envクラス内に埋まってしまう。

このため mlflow を使って実験を管理する場合、独自Envクラス内に実装しないといけなくなる。

たとえば以下のような gym.Env 継承クラスの実装をおこなう。


import gym
import mlflow
from mlflow.tensorflow import autolog # tensorflow実装の場合

class HogehogeTrainEnv(gym.Env):

    def __init__(self):
        :
        # 独自環境クラス初期化処理
        self.step_count = 0
        self.total_reward = 0.0

        :
        # mlflow実行開始
        mlflow.start_run()
        # パラメータとしてenv_idを書き込む
        mlflow.log_param('env_id', 'HogehogeEnv-v0')
        autolog()

    def step(self, action):
        # 累積ステップ数
        self.step_count += 1
        :
        # 観測データ obs 更新
        # エピソード完 done 判定
        # 当該ステップの報酬値 reward 算出
        # その他情報 info の格納

        # エピソード内報酬値合計
        self.total_reward += reward
        :
        # エピソード完了時に報酬値合計を書き込む
        if done:
            ml_metric('total_reward', self.total_reward, step=self.step_count)
            self.total_reward = 0.0
        return obs, reward, done, info

    def close(self):
        :
        # mlflow 実行終了
        mlflow.end_run()


mlflow.log_params() / mlflow.log_param() は同一キーの上書きをする場合エラーを発生させることがある。
 

mlflow.log_metrics() / mlflo.log_metric() は毎step実行すると大量のデータをグラフ化できなくなるので実行タイミングを独自環境ごとに工夫する必要がある。上記スードコードの例ではエピソード完了時のみ書き込みを行っているが、total_timestepsをおおきくすればするほどログ出力が増え、トレーニング処理が増大する。

ログ出力が膨大な場合は mlflow ui するとグラフ表示できなくなることがある。tensorboard を使う場合は mlflowでは指標は書き込まずにパラメータのみ管理するなどの切り分けをして、余計なログを取らないようにする。

上記のクラスはあくまでトレーニング処理用の独自Envクラスとして設計している。評価用Envクラスと共用する場合は、評価時にもmlflowログが出力されることに注意。

上記の例では mlflow.start_run() / mlflow.end_run() を各テンプレートメソッドに埋め込んでいるが、これは Stable Baselines を使用する場合を想定している。Stable Baselinesを使う場合は autolog はどうも機能しないようなので注意。


2021年7月30日金曜日

mlflow ui を Google Colaboratory上で動かす

 
MLflowによるトレーニング結果リストをColab上の実験で使いたい場合、pyngrokを使うと便利。

試していないが、tensorboardなどにも利用可能。

!pip install mlflow

!pip install pyngrok
ngrok はローカルPC上のnginxなどのサービスを外部へ公開することのできるsshトンネリングツール。pygrokはPythonから使用できるPythonパッケージ。
 

  • mlflow ui をバックグラウンド起動

get_ipython().system_raw("mlflow ui --port 5000 &")


ローカルPCの場合 http://127.0.0.1:5000/ をブラウザで開くとmlflow uiが表示されるが、Colab の場合グローバルURLがないと呼び出せない。

  • pyngrok を使って5000番ポートのHTTPサービスをngrokへ登録

from pyngrok import ngrok
ngrok.kill()
ngrok_tunnel = ngrok.connect(addr="5000", proto="http", bind_tls=True)

  • パブリックURLを取得

print("MLflow UI ", ngrok_tunnel.public_url)


実行すると以下のようなURLが出力される。
MLflow UI  https://xxxxxxxxxxxxx.ngrok.io

  • ブラウザの別タブで上記URLを開く


mlflow uiが表示される。
 


以下のコードは、ここのサンプルコードのif __name__ == "__main__":を関数 train() 化しているだけ。

import os
import warnings
import sys

import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNet
from urllib.parse import urlparse
import mlflow
import mlflow.sklearn

import logging

logging.basicConfig(level=logging.WARN)
logger = logging.getLogger(__name__)


def eval_metrics(actual, pred):
    rmse = np.sqrt(mean_squared_error(actual, pred))
    mae = mean_absolute_error(actual, pred)
    r2 = r2_score(actual, pred)
    return rmse, mae, r2


def train(alpha=0.5, l1_ratio=0.5):
    warnings.filterwarnings("ignore")
    np.random.seed(40)

    # Read the wine-quality csv file from the URL
    csv_url = (
        "http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
    )
    try:
        data = pd.read_csv(csv_url, sep=";")
    except Exception as e:
        logger.exception(
            "Unable to download training & test CSV, check your internet connection. Error: %s", e
        )

    # Split the data into training and test sets. (0.75, 0.25) split.
    train, test = train_test_split(data)

    # The predicted column is "quality" which is a scalar from [3, 9]
    train_x = train.drop(["quality"], axis=1)
    test_x = test.drop(["quality"], axis=1)
    train_y = train[["quality"]]
    test_y = test[["quality"]]

    with mlflow.start_run():
        lr = ElasticNet(alpha=alpha, l1_ratio=l1_ratio, random_state=42)
        lr.fit(train_x, train_y)

        predicted_qualities = lr.predict(test_x)

        (rmse, mae, r2) = eval_metrics(test_y, predicted_qualities)

        print("Elasticnet model (alpha=%f, l1_ratio=%f):" % (alpha, l1_ratio))
        print("  RMSE: %s" % rmse)
        print("  MAE: %s" % mae)
        print("  R2: %s" % r2)

        mlflow.log_param("alpha", alpha)
        mlflow.log_param("l1_ratio", l1_ratio)
        mlflow.log_metric("rmse", rmse)
        mlflow.log_metric("r2", r2)
        mlflow.log_metric("mae", mae)

        tracking_url_type_store = urlparse(mlflow.get_tracking_uri()).scheme

        # Model registry does not work with file store
        if tracking_url_type_store != "file":

            # Register the model
            # There are other ways to use the Model Registry, which depends on the use case,
            # please refer to the doc for more information:
            # https://mlflow.org/docs/latest/model-registry.html#api-workflow
            mlflow.sklearn.log_model(lr, "model", registered_model_name="ElasticnetWineModel")
        else:
            mlflow.sklearn.log_model(lr, "model")

Scikit Learnを使ったトレーニングサンプル。MLflowのチュートリアルなので mlflow パッケージを使って実行ディレクトリのしたに作成される mlflowディレクトリにlog_xxx()関数で指定されたパラメータ情報やモデルを格納する。

train()を実行するごとにトレーニング処理を実行する。


  • 1回目のトレーニングを実行

train(alpha=0.5, l1_ratio=0.5)


実行結果例:
Elasticnet model (alpha=0.500000, l1_ratio=0.500000):
  RMSE: 0.7931640229276851
  MAE: 0.6271946374319586
  R2: 0.10862644997792614

  • 別タブで開いたままのmlflow ui の左上のアイコン(もしくはRefreshボタン)を押下


mlflow ui 上に1回目の結果が表示される。



  • 2回目のトレーニングを実行


パラメータを変えて実行。

train(alpha=0.4, l1_ratio=0.51)

実行結果例:
Elasticnet model (alpha=0.400000, l1_ratio=0.510000):
  RMSE: 0.7769749651758281
  MAE: 0.6101625601336331
  R2: 0.14464227762391824

  • 別タブで開いたままのmlflow ui の左上のアイコン(もしくはRefreshボタン)を押下


mlflow ui 上に2回目の結果が追加される。

ngrok は、sshトンネリングを使うため、社内LANなど管理統制下の環境から使用する場合は、各々のセキュリティポリシーに抵触しないか各自で確認のこと。

 

以上

2021年7月28日水曜日

富岳上でTensorFlow/PyTorchを使った機械学習を実行する方法

 

富岳上でTensorFlowやPyTorchを使用する場合、各自で環境設定を行う必要がある。

計算ノードを使う


計算ノードにはGPUが搭載されていないため、CPUのみの環境でトレーニング・推論処理を行うことになる。

現時点(2021年7月28日)では、富岳計算ノードに特化した以下のバージョンTensorFlow/PyTorchが用意されている。


ライブラリ バージョン パス
TensorFlow 2.2.0 /home/apps/oss/TensorFlow-2.2.0
PyTorch 1.7.0 /home/apps/oss/PyTorch-1.7.0


TensorFlow 2.2.0

TensorFlow 2.2.0 バイナリ及びライブラリをパスに追加する。Pythonバイナリも計算ノード用にoneDNNをリンクしたものが用意されている。

TensorFlow 2.2.0 関連パスを環境変数に追加する場合:


export PATH=/home/apps/oss/TensorFlow-2.2.0/bin:$PATH
export LD_LIBRARY_PATH=/home/apps/oss/tensorFlow-2.2.0/lib:/home/apps/oss/TensorFlow-2.2.0/lib64:$LD_LIBRARY_PATH


PyTorch 1.7.0

PyTorch1.7.0も同様にパスに追加する。PyTorchもPythonバイナリから用意されているのだけど、こちらはコンパイルオプション以外に特別なconfigurationがみあたらない。

PyTorch 1.7.0 関連パスを環境変数に追加する場合:


export PATH=/home/apps/oss/PyTorch-1.7.0/bin:$PATH
export LD_LIBRARY_PATH=/home/apps/oss/PyTorch-1.7.0/lib:/home/apps/oss/PyTorch-1.7.0/lib64:$LD_LIBRARY_PATH

 

【注意】

/vol0004/apps/oss には、PyTorch1.6.0やTensorFlow2.1.0のディレクトリも存在するが、メンテナンスされていないため上記のように環境変数を変更しても使用できない。たとえばTensorFlow2.1.0の場合、pipコマンドが使用できないため、独自にpipコマンドスクリプトを変更する必要がある。


上記のバージョン以外の TensorFlow/PyTorchを使用したい場合は、spackコマンドを使うこととなる(ただし、コンパイルオプションなどの問題を個々に対処しなくてはならない)。

たとえば計算ノード上でなにも設定せず spack install py-tensorflow@2.3.1 と実行しても、正常にインストールが成功しない。これは計算ノードがARMv8.2ベースのアーキテクチャCPUを使用していることに起因する。
 

【注意】

富岳には一般ユーザが問い合わせることのできるヘルプデスクが存在するが、初動のレスポンスもあまり早くない(失礼、ご容赦)し、個別のOSS対応を断っていると入門セミナーでおっしゃっており、自分で解決しなくてはならない。

2021/08/03追記併走型利用支援 を開始したとのメール案内がありました。



そのような場合は、次の手段で実行する事が可能になる。
 

プリポストGPUノードを使う


富岳の利用ガイド入門編では紹介されていないが、富岳環境には8ノードだけGPU(V100×2)が搭載されたノードが用意されている。

富岳には踏み台ゲートウェイにあたるログインノード、計算用途に使用する計算ノード以外に、プリポストノードが用意されている。

プリポストノードは、(明確な記述がないため、あくまで私個人の私見)その名称通り『事前処理・事後処理』に使用することを目的としており、本格的NLP処理の前の大量テキストファイルの分かち書きやword2vecによる特徴量計算などの大量メモリを消費する事前処理を行ったり、計算結果を3D CGや動画などに変換しXサーバを立ち上げGUI表示し確認するようなGPUを使用するような事後処理をおこなうためのノードである。

プリポストノードの種類


プリポストノードには以下の3種類のノードが存在する。


ノード種類 ノード数 用途
管理ノード 2(正・副) GPU/大量メモリノードリソースを管理するノード。slurmジョブを適切なノード上で実行し状態を管理する。富岳一般ユーザがログインして使用することはおそらくない。
GPUノード 8 プリポスト環境における計算ノード。2CPU、192GBメモリを搭載した x86_64 アーキテクチャノード。NVIDIA Telsa V100(32GB)×2を搭載。2021年7月27日時点ではCUDA Toolkit 11.2がセットアップ済み。
大容量メモリノード 2 プリポスト環境における計算ノード。4CPU、6TBメモリを搭載した x86_64アーキテクチャノード。GPUは搭載されていない



GPUノード、大容量メモリノードは、富岳計算ノードとことなり x86_64 アーキテクチャのCPUを搭載しているため、PyPI 管理下のパッケージも豊富であるため pip3 コマンドで必要なバージョンのTensorFlow/PyTorchにインストールすることができる。また両方の環境をあわせたPython環境も構築が容易である。
 

利用入門セミナーでGPUノード活用についての説明がなく、また搭載GPUのアーキテクチャも現在では古いため、富岳管理側はこのGPUノードの機械学習用途での利用は想定外であると推察する。このため富岳ユーザがこの方法を使い始めた時、禁止される可能性は十分考えられる。

事前準備


富岳計算ノードへのログインでは pjsub コマンドの対話型ジョブ実行で行っていた。
プリポストノードのGPUノード、大容量メモリノードでは、富岳計算ノードとはことなり Slurm Workload Manager というジョブ管理ツールを使用している。

このため、srun というジョブ実行コマンドの対話型ジョブ実行モードを使ってログインすることとなる。

GPUノードへ対話型ジョブでログインする場合:

srun -p ppsq -N 1 --time=10:00:00 --pty bash -i

上記コマンドを実行すると、slurmが割り当てたどれかひとつのGPUノードへログインすることができる。
 

ppspppmq に変更すると大容量メモリノード(GPUなし)へログインできる。



GPUノード上にログインした状態で venv環境 hogehoge を作成する場合:

mkdir -p ${HOME}/.local
mkdir -p ${HOME}/.local/avx512
cd ${HOME}/.local/avx512
python3 -m venv hogehoge


venv環境 hogehoge を有効にするには source ${HOME}/.local/avx512/hogehoge/bin/activate を実行する。

GPUノード上にログインした状態では、CUDA Tookitへの環境変数設定ができていないため、CUDAを使用するライブラリを使う前に設定する必要がある:

export PATH=${PATH}:/usr/local/cuda-11.2/bin
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda-11.2/lib64

 

バージョン指定したTensorFlowのインストール

spack を使って環境を整えることも可能だが、ローカルPCと同様のセットアップ手順で行いたい場合は、venvを使用することもできる(デフォルトPythonパッケージは3.6.8)。

GPUノード上にログインした状態で(CUDAへのパス追加後) TensorFlow2.5.0をインストールする場合:

pip3 install tensorflow-gpu=2.5.0
 

バージョンを指定したPyTorchのインストール


GPUノード上にログインした状態で(CUDAへのパス追加後) PyTorch1.8.1をインストールする場合:

pip3 install torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio==0.8.1 -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html
 

1.8.1以外の場合のセットアップコマンドは、PyTorchサイトで確認のこと。

GPUノードへバッチジョブ実行する場合は sbatch を使ってスクリプトを slurm キューに格納する。キューの状態を確認する場合は、squeueを実行する。
 

sbatchsrunのオプションである --mail-user / --mail-type を指定すると、ジョブの開始終了などをメールで通知してくれると書かれているが、現時点では動作しない。どうもGPUノード上にメールクライアントがインストールされておらず、spackコマンドでもインストールできないため、メール経由のSlackメッセージ通知を利用するとはできない。→(追記)現在使用可能になりました。

 


デフォルトの設定ではホームディレクトリをテンポラリディレクトリとして使用する。インストール処理を実行すると大量の一時ディレクトリがホーム上に作成されるので注意(環境変数 TMPDIR を設定して変更することが可能)。



上記以上のプリポスト環境の使い方については、富岳ポータルサイト(要アクセス権限)上の「プリポスト環境 利用手引書」を参照のこと。

以上

※2021/10/19 追記

TensofFlowのインストールは可能ですがtf.config.list_physical_devices()を実行すると

CPUだけしか表示されませんでした。

nvidia-smiも同様に認識できませんでした。

考えられる理由としてドライバが古いか他のプロセスで使用中なのか

とも考えましたが、後者であればnvidia-smiは少なくとも表示してくれるはずですので

おそらく前者かな..と。

となるとドライバの再インストールですが..これは一般ユーザでは実行できません。

GPUノードはPCと同等の環境構築手段で使用は可能ですが

GPUを機械学習には現時点では使用できないと考えておいたほうが良いです。

もちろん、このあと環境が更新される可能性はありますが..


2021年7月20日火曜日

MLFlow のクイックスタートを勝手に翻訳してみた

 本文書はMLFlow クイックスタートを勝手に翻訳したものです。

MLflowは、いわゆる MLOps に活用されるソフトウェアで、機械学習のトレーニング処理や推論処理コード(Python, R, Javaなど)に追加して、実行した実験のログを集約的に記録することのできるOSSです(ただし複雑な管理はできないので非プロダクション開発者や Kaggle 参加者などの利用が多いようです)。

参照は、at your own riskでお願いします。

----

MLflowのインストール


以下を実行してMLflowをインストールします。

pip install mlflow

install.packages("mlflow")
mlflow::install_mlflow()

【注意】MLflow は MacOS でも動作します。MacOSデフォルトのPythonで問題が発生した場合は、brew install python pip3 install mlflow を使用して Homebrew パッケージマネージャからPython3をインストールしてみてください。

特定のMLflowモジュールと機能(MLモデルの永続性/推論、成果物ストレージオプションなど)を使用するには、追加のライブラリをインストールする必要がある場合があります。たとえば、mlflow.tensorflowモジュールには TensorFlow がインストールされている必要があります。詳細については、https://github.com/mlflow/mlflow/blob/master/EXTRA_DEPENDENCIES.rst を参照してください

この段階で、チュートリアル に従って、一般的なワークフローにてMLflowを活用する方法をウォークスルーを済ませておくことを勧めます。

クイックスタートのダウンロード

git clone https://github.com/mlflow/mlflow を実行してMLflowのクローンを作成し、クイックスタートコードをダウンロードし、リポジトリの examples サブディレクトリに cd します(この作業ディレクトリを使用して quickstart を実行します)。

MLflowのクローンから直接実行することは避けてください。実行するとチュートリアルの段階でMLflowのPyPiインストールではなく、ソースコード側の MLflow が使用されるためです。
 

Tracking API の使用

MLflow Tracking API は、あなたのデータサイエンスコードから指標と成果物(ファイル)を記録し、あなたの実行の履歴を確認することができます。次のように簡単なPythonスクリプトを作成して、試してみることができます(このサンプルは quickstart/mlflow_tracking.py に含まれています)。

import os
from random import random, randint
from mlflow import log_metric, log_param, log_artifacts

if __name__ == "__main__":
    # Log a parameter (key-value pair)
    log_param("param1", randint(0, 100))

    # Log a metric; metrics can be updated throughout the run
    log_metric("foo", random())
    log_metric("foo", random() + 1)
    log_metric("foo", random() + 2)

    # Log an artifact (output file)
    if not os.path.exists("outputs"):
        os.makedirs("outputs")
    with open("outputs/test.txt", "w") as f:
        f.write("hello world!")
    log_artifacts("outputs")


library(mlflow)

# Log a parameter (key-value pair)
mlflow_log_param("param1", 5)

# Log a metric; metrics can be updated throughout the run
mlflow_log_metric("foo", 1)
mlflow_log_metric("foo", 2)
mlflow_log_metric("foo", 3)

# Log an artifact (output file)
writeLines("Hello world!", "output.txt")
mlflow_log_artifact("output.txt")

Tracking UI の表示


デフォルトでは、プログラムを実行する場所に関係なく、Tracking APIはデータをファイルのローカルの ./mlruns ディレクトリに書き込みます 。その後、MLflowの Tracking UI を実行できます。
 

mlflow ui


mlflow_ui()


表示させるには http://localhost:5000/ を開きます。
 

【注意】

MLflow UIまたはエラーログにメッセージ [CRITICAL] WORKER TIMEOUT が表示される場合は、 http://localhost:5000 の代わりに http://127.0.0.1:5000 を使用してみてください。


MLflow プロジェクトの実行


MLflowを使用すると、コードとその依存関係を、他のデータに対して再現可能な方法で実行可能なプロジェクトとしてパッケージ化できます。各プロジェクトには、そのコードと、その依存関係(Python環境など)を定義する MLproject ファイル、およびプロジェクトで実行できるコマンドおよび引数が含まれています。
 

mlflow run コマンドを使用して、既存のプロジェクトを簡単に実行できます。このコマンドは、ローカルディレクトリまたは GitHub URI のいずれかからプロジェクトを実行します。

mlflow run sklearn_elasticnet_wine -P alpha=0.5

mlflow run https://github.com/mlflow/mlflow-example.git -P alpha=5.0


tutorial には、依存関係を指定する MLproject ファイルを含むサンプルプロジェクトがあります。Tracking サーバを構成していない場合、プロジェクトは Tracking APIデータをローカルの mlruns ディレクトリに記録するため、 mlflow ui を使用してこれらの実行を確認できます。
 

【注意】 

デフォルトでは、 conda を使用してすべての依存関係をインストールします。 conda を使用せずにプロジェクトを実行するには、 mlflow run にオプション --no-condam を指定 できます。この場合、必要な依存関係がPython環境にすでにインストールされていることを確認する必要があります。

詳細については、MLflowプロジェクト を参照してください。
 

モデルの保存と提供


MLflow には、さまざまなツールのモデルをさまざまなフレーバで保存するための汎用 MLmodel フォーマットが含まれています。たとえば、多くのモデルをPython関数として提供できるため、さまざまなツールでモデルを提供するために、 MLmodel ファイルで各モデルをPython関数として解釈する方法を宣言できます。MLflowには、このようなモデルをローカルで実行し、Dockerコンテナまたは商用サービスプラットフォームにエクスポートするためのツールも含まれています。

この機能を説明するために、 mlflow.sklearn パッケージは scikit-learn モデルをMLflowアーティファクトとしてログに記録し、それらを再度ロードして提供することができます。次のように実行できるトレーニングアプリケーションサンプル sklearn_logistic_regression/train.py があります。

python sklearn_logistic_regression/train.py


サンプルを実行すると、実験のMLflow実行IDが出力されます。 mlflow ui を見ると 、実行によって MLmodel 説明ファイルと pickled scikit-learn モデルを含む model フォルダが保存されていることがわかります。成果物ディレクトリ(ここでは「モデル」)内の実行IDとモデルのパスをさまざまなツールに渡すことができます。たとえば、MLflowには、Pythonベースのモデル用の単純なRESTサーバが含まれています。

mlflow models serve -m runs:/<RUN_ID>/model

【注意】

デフォルトでは、サーバはポート番号 5000 で実行されます。そのポートがすでに使用されている場合は、 –-port オプションを使用して別のポートを指定します。

例: mlflow models serve -m runs:/<RUN_ID>/model --port 1234



サーバを起動したら、サンプルデータを渡して、推論を確認できます。

次のサンプルでは、JSONでシリアル化された pandas DataFrame を split オリエンテーション付きでモデルサーバに送信するために curl を使用します。pyfunc モデルサーバで受け入れられる入力データ形式の詳細については、 MLflowデプロイメントツールドキュメント を参照してください。

curl -d '{"columns":["x"], "data":[[1], [-1]]}' -H 'Content-Type: application/json; format=pandas-split' -X POST localhost:5000/invocations

は、次の値を返却します。

[1, 0]

詳細は MLflowモデル を参照してください。
 

リモート Tracking サーバへのログ記録


上記の例では、MLflowはそれが実行されているマシンのローカルファイルシステムにデータを記録します。結果を一元的に管理したり、チーム全体で共有したりするために、リモート Tracking サーバにログを記録するようにMLflowを構成できます。リモート Tracking サーバにアクセスするには、以下のどちらかを実行します:
 

リモートマシンで Tracking サーバを起動


リモートマシンで Tracking サーバを起動 します。

次に、環境変数 MLFLOW_TRACKING_URI をサーバのURIに設定するか、プログラムの先頭に以下を追加することにより、リモート Tracking サーバにログを記録 できます。

import mlflow
mlflow.set_tracking_uri("http://YOUR-SERVER:4040")
mlflow.set_experiment("my-experiment")


library(mlflow)
install_mlflow()
mlflow_set_tracking_uri("http://YOUR-SERVER:4040")
mlflow_set_experiment("/my-experiment")

Databricks CommunityEditionにログイン


または、ホスト型 Tracking サーバを含む無料サービスである Databricks Community Edition にサインアップします。Community Editionは、実稼働のユースケースではなく、迅速な実験を目的としていることに注意してください。サインアップ後、 databricks configure を実行してMLflowのクレデンシャルファイルを作成し、ホストとして https://community.cloud.databricks.com を指定し ます。

Community Edition サーバにログインするには、環境変数 MLFLOW_TRACKING_URIdatabricks に設定するか、プログラムの先頭に以下を追加します。

import mlflow
mlflow.set_tracking_uri("databricks")
# Note: on Databricks, the experiment name passed to set_experiment must be a valid path
# in the workspace, like '/Users/<your-username>/my-experiment'. See
# https://docs.databricks.com/user-guide/workspace.html for more info.
mlflow.set_experiment("/my-experiment")


library(mlflow)
install_mlflow()
mlflow_set_tracking_uri("databricks")
# Note: on Databricks, the experiment name passed to mlflow_set_experiment must be a
# valid path in the workspace, like '/Users/<your-username>/my-experiment'.  See
# https://docs.databricks.com/user-guide/workspace.html for more info.
mlflow_set_experiment("/my-experiment")

-----

機械学習モデルの改善では、コード上もしくは外部パラメータファイルなどのプロパティ上のハイパーパラメータやパラメータをちょこちょこ変えたり、入出力データセットをコロコロ変えながら何度もトレーニング、バリデーション、テスト、推論を実行するサイクルをくりかえす。

たいていは一人作業が多くなるけど、それでも2回前に自分が実行した実験がどんなパラメータでどんなデータセットをどういうモデルで実行したのかを覚えておくことは難しい。一番大きな理由は、トレーニング処理が数時間から数日かかる場合がおおいため、人間側の中短期記憶がだめになっていることが少なくない。

メモすればいい、とはおもうのだけど毎回同じフォーマットで記録することが大変なのだ。特にaccuracyなどの結果指標値は書いたり書かなかったりして何度も同じ実験を繰り返してしまう人は少なくないと思う(じぶんもそうだったりする)。

なので、IT実験はITで管理すべき..ということでMLFlowなどのMLOpsツールが出始めている。MLFlowは、Pythonパッケージで難易度もそれほどたかくないので、いわゆるデータサイエンティストでも入れられる。

データサイエンティストのほとんどの人がコンピュータ工学(CS)好きで、情報システム(IS)がからっきしの人なので、うんたらOpsといったシステムとしてのITを理解する脳が発達していないことが多い。

だから比較的利用がかんたんな MLFlow などに飛びつく人が多いのかもしれない..

【ハーネスエンジニアリングを始める前に】gpt-oss:20b の入出力データから、LLMの動作を理解する

  1. はじめに 最近は、 Cursor や Antigravity などのAIエージェント前提の統合開発環境や、 Claude Desktop や Codex アプリ などのPC上のオブジェクト操作が可能なデスクトップアプリ、 Open Claw といったPC全体の...