Translate

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 などに飛びつく人が多いのかもしれない..

2021年7月8日木曜日

gradio を使って6行でできるAI日本語文章要約サンプルを試す


今日、ふと次のようなタイムラインが流れてきた。

https://twitter.com/abidlabs/status/1412826272770793474?s=20

ようは、たった6行でアラビア語の文章を要約文にできるというもの。

gradioというパッケージはよくしらないが、どうもモデル自体をリポジトリからロードしているようだ。

とすると、arという文字列をjaにすれば、日本語の要約サンプルがかけるんじゃ..とおもい Google Corab 上でためしてみた。


!pip install gradio

import gradio as gr
from gradio.mix import Series


ja2en = gr.Interface.load("Helsinki-NLP/opus-mt-ja-en", src="huggingface", inputs="textbox")
summarizer = gr.Interface.load("facebook/bart-large-cnn", src="huggingface")
en2
jap = gr.Interface.load("Helsinki-NLP/opus-mt-en-jap", src="huggingface")

Series(
ja2en, summarizer, en2jap).launch(debug=True)



結局置換( s/ar/ja/g )では動作しなくて英語から日本語にするときのラベルは上記のようにjapと書かないとだめだった。

..物議をかもしそうなラベル名だけど..まあ、ここでは華麗に無視をして..



で、何を試そうかな..とおもい次の記事をコピペしてSubmitしてみた。



..で、結果は..

日 が 暮れ る と , 人 が 眠 る こと な く , 夜 が 眠 っ て い る 時 , その 熟練 な 人々 の 前 に 置 か れ る . これ は 突陽 を 失 お う と する 事 で あ っ て , 日 が 暗 く な る の を 見 た . しかし これ は 幻 を 見 る こと が でき な い .


..コレジャナイ感満載..

それこそ昔 Seaquence2Sequence で試したときのアウトプットのような文章が..

..有料サービスで提供している企業もあるわけだし..
..まあ、そんなかんたんにつくれるわけないか...


でも、gradio というPythonパッケージはおもしろそう。

以下トップページの文章(翻訳):

Gradioを使用すると TensorFlow モデルや PyTorch モデル、さらには任意のPython関数を中心にカスタマイズ可能なUIコンポーネントをすばやく作成できます。コンポーネントを組み合わせて、任意の入力と出力をサポートします。Gradio コアライブラリは無料で OSSです



ちょっとおぼえておくと、いいかも..

2021年7月6日火曜日

Spackプライベートインスタンス内の独自環境下でチェイニングを使う

ホームディレクトリなどに各自でSpackを配置した状態で使用するプライベートインスタンスの場合、パブリックインスタンス(/optなどの配下にspackを配置して複数ユーザで共用する)側でspack install済みのパッケージが透過的にみることはできない。

このような場合、チェイニングという機能を使うことでパブリック側インストール済みパッケージをspack loadできるようにする。

方法は、ホームディレクトリ以下の.spackディレクトリにupstreams.yamlというファイルを作る。

たとえばパブリック側のSpack環境が/opt/hogehoge/spack以下にある場合、

upstreams:
  spack-public-instance:
    install_tree: /opt/hogehoge/spack/opt/spack


と、記述することでパブリック側パッケージがspack find で参照可能になる。


しかし、プライベートインスタンス内でさらにspack env create で独自Spack環境をつくると、このチェイニングが効かなくなる。

そのような場合は ~/.spack/upstreams.yaml を以下のように追記すればよい(fugafugaユーザのホーム直下にspackディレクトリがある場合)。

upstreams:
  spack-public-instance:
    install_tree: /opt/hogehoge/spack/opt/spack
  spack-private-instance:
    install_tree: /home/fugafuga/spack/opt/spack


これでパブリック側のパッケージとプライベート側のパッケージを透過的にspack findすることができる。


..が、独自Spack環境を作成する場合は、排他状態(spack installをいちからじぶんでやりたい)を望んで作る事が多い(プライベートデフォルト環境下で十分)ので、需要はあまりないかもしれないが...


2021年6月30日水曜日

富岳上で実行したジョブの開始・終了・ステータスをSlackで受ける

富岳上でジョブを実行する際に pjsub コマンドを使います。


pjsub には様々なオプションがあるのですが、このなかに指定イベントごとにメールを送信するオプションがあります。


オプションの詳細は man pjsub を参照してください。たくさんあります。



これと SlackアプリのEmailを組み合わせれば、メールではなく直接Slackへのメッセージとして受け取ることができます。

Slack アプリ Email
https://slack.com/apps/A0F81496D-email?tab=more_info
 

Slackアプリサイトにてインストールボタンを押して、どのチャネルへ送信するかを指定すると、送信先メールアドレス(ex. hogehoge@workspace_name.slack.com)を受け取ることができます。

pjsub の引数に -m b,e,s --maillist "hogehoge@workspace_name.slack.com" と指定すればOK。

引数にいちいち指定するのが面倒くさい場合は、ジョブスクリプト上部のPJMオプション指定箇所に、以下のように指定すればOKです。

#!/bin/bash
:
#PJM -m b,e,s
#PJM --mail-list "
hogehoge@workspace_name.slack.com"
#PJM -S
:

-mの後ろがメール送信が発生するイベントを指定しています。ここでは開始、終了、ステータスを指定していますが、ほかのイベントについては man pjsub-m の箇所を読んでください(-Sは、ステータスを表示させるために必要)。

p.s.

実行ジョブ監視にログインノード上で watch pjstat -E している人も多いと思うのですが、おそらく私のネットワーク環境の問題だと思いますが、SSH接続がたまにぷつんと切れてしまうので..メールへ送ってましたが..ジョブスクリプト開発中はやたらめったらpjsubするので、ほぼスパムメール状態に..

 

あと、たくさんの種類のジョブを投げる人はジョブ名をつけたほうがよいとおもいます。

pjコマンドは宣言的な設計になっており、APIもあるのでIPリーチャブルな環境にあるCIサーバ(BLUE WATERのWebinerで紹介していたjenkinsみたいなやつ、スパコンの場合はslumというのがあるそうですが..よく知りません)があれば、CI管理画面上で完結できるので、たぶんそちらが正解なのかもしれませんが..


2021年6月29日火曜日

富岳でホームディレクトリの.sshを削除してしまった件

今回の情報は..役に立つ人がいるのか、わかりませんが、忘備録としてのこしておきます。



スーパーコンピュータ富岳上でいろんなジョブを実行していたのですが、
うっかりそのジョブの中で~/.sshを消してしまいました。

そうするとどうなるかというと..

次にSSH接続するときにエラーになって接続できなくなります。


でヘルプデスクへ問い合わせたところ公開鍵を再登録してくれという返事が..


富岳では、以下の2つの手順をおこないます。
・クライアントPC側のPuTTY Genなどで鍵ペアを作成
・利用者ポータルにて公開鍵登録


すでに鍵ペアは作成済みであるので、2番めの項目のみを実行します。

・クライアントPC側のブラウザから富岳ポータルを開く
・利用者ポータルリンクをふむ
・publickey registration リンクをふむ
・鍵ペア作成時に取得した公開鍵文字列をコピー&ペースト
・Registerボタン押下


これでホームディレクトリの.sshディレクトリ内に公開鍵に関する情報が登録されます。
あとは再度クライアントPCからユーザID、パスフレーズをつかってSSH接続しなおせばOKです。

 

ほかの公開鍵で接続する場合もにたようなポータルサイトのような機能をもつことがおおいので、富岳以外の場合もあせらずまずポータルに公開鍵登録機能がないかしらべてみてください。

2021年5月25日火曜日

富岳にdonkeycarパッケージをインストールする

 表題の手順をgithub上に公開しました。

GitHub: Donkeycar on Fugaku
https://github.com/coolerking/donkeycar_on_fugaku



去年あたりからニュース画像でもおなじみになってきたスーパーコンピュータ富岳ですが、OSSを使った計算を行う場合は多少厄介になります。

すでにインストール済みのものであればよいのですが、未インストールであり、さらに依存関係のあるOSパッケージ管理ツール管理化のパッケージを使用する場合、一般ユーザの許可されている権限でなんとかしないといけないので、いろいろややこしくなります。

自分が思いつく方法は、以下の2種類になります。
 

  • ホームディレクトリ上でソースからコンパイル
  • spack を使ってコンパイル&インストール


ホームディレクトリ上にソースコードを展開して、手動でビルドするときに、`--prefix` オプションでホームディレクトリ上のサブディレクトリ(ex. `~/local/aarch64fx` )にして`make install`したときにこのディレクトリに書き込まれるようにする方法です。

自分は Slackware 時代からのLinuxユーザなので、この手の手順にはなれていますが、依存関係のあるパッケージをたどっていくと..やがて LLVM まで到達してしまい、この方法であっているのか?..と。

で、富岳ポータルサイト(登録ユーザのみが参照可能)のコンテンツを調べ直したところ、Spackを使うことを推奨しているようです。

Spackは、スーパーコンピュータ上でOSSをインストールするためのツールで、Pythonで動作します(富岳にも最初からインストールされている)。なので、http://github.com/spack/spack.git をチェックアウトするだけで動作します。

Spackはpyenvやvirtualenv、condaなどのように"環境"を作ることができるので、デフォルトの環境ではなく、用途に合わせて個々の"環境"を作ることができます(削除もコマンド1発)。この"環境"の中にインストールすればOKです。最初の環境であるルート環境に入るには、用意されたセットアップシェルを実行します。

# インストール
git clone https://github.com/spack/spack.git ~/spack
cd ~/spack
git checkout releases/<使いたいバージョン>

# ルート環境に入る
. ~/spack/share/setup-env.sh


これでspackコマンドが使用可能になります。

独自の"環境"を作る場合も、spackコマンドを使用します。

# 環境 hogehoge を作成する
spack env create hogehoge
# 環境 hogehoge に入る
spack env activate hogehoge
# インストール可能なOSSパッケージをリスト
spack list
# インストール済みパッケージのリスト
spack find
# openblasパッケージをインストール
spack install openblas
# 環境 hogehoge から抜ける(ルート環境にもどる)
spack env deactivate
# 環境 hogehoge を削除する(確認なし)
spack env remove hogehoge


spack install で指定する引数によっては、OSSバージョン、使用するコンパイラおよびバージョン、リンクオプションなどを指定可能です。

# 富岳ではterminfoをリンクする場合-ltinfoを使う
spack install mesa ldlibs="-ltinfo"


spack install されると、~/spack/var/spack/environments/<Spack環境名>/.spack-env/view以下のbinlibincludeへインストールされます。これらへのパスなどの環境変数はspack env activate時にセットされます。

ただし、pipからフォークされるcmakeなどのオプションにまで到達しない場合があるので、個別にセットする必要があるケースもあります(Pythonパッケージをpipでインストールする際には内部でcmakeすることがあります)。このあたりはトライ&エラーでみつけていくしかありません。

Pythonパッケージの一部もspackからインストールできます。もちろんpipも可能ですが、一般ユーザではグローバルインストールはできないので、--userオプションを付けないと動きません。


富岳は会話型とジョブ型の2種類の実行方法がありますが、spack installが会話型だと制限時間内に終わらないことがあるため、それなりのボリュームのパッケージはジョブ型で実行(pjsubコマンドでシェルを実行)する必要があります。


あと、TensorFlow2.2.0/PyTorch1.7.0はあらかじめインストールされたパスが公開されているので、これらへパスを変更することで使用可能になります。Spackでもインストールできそうですが、富岳管理者が提供しているので、コンパイラ最適化オプションをきちんとつけて作成している(..とおもいます)はずなので、こちらをつかうほうがよいでしょう。

執筆時点のTensorFlow2.1.0は、pipが移動元パスになっているので、使用するには工夫が必要。


なのでvirtualenvなどのPython環境と、Spack環境を併用するのがよいと、私は判断しました。最初に紹介したGitHub上のスクリプトも、それを前提に作成しています。

細かい使い方はSpackのドキュメントを参照してみてください。チュートリアルもありますし、Youtubeに英語ですが概要紹介のセッション動画も投稿されています(字幕翻訳させれば内容はわかるとおもいます)。



 

 

ご参考まで。

Google Colab相当の環境をローカルPC上のDocker Composeで実現する

 Docker Composeの有料版に、お金を払いたくない ^H^Hが使えない ため古いゲーミングPC(GeForce3080)にDocker Composeを入れてその上のコンテナでGoogle Colab相当のノート操作ができないかためしてみた: コンテナイメージとして a...