Azure ML Python SDK を使う１：データセットをインプットとして使う - その１

# はじめに
Azure Machine Learning Services には UI ベースで機械学習モデルを開発できる Designer や Automated ML が提供されています。これらのツールはシチズンデータサイエンティストが機械学習モデルを開発するのに便利です。また Python によるモデル開発と推論、そして運用自動化までカバーする Python SDK も提供されていて、データサイエンティストのみならず IT 部門がエンタープライズグレードの機械学習システムを構築することができます。
この Python SDK によって例えばデータサイエンティストはモデル学習をリモート仮想マシン上で分散トレーニングさせたりすることもできますが、そのためには Python SDK のお作法を理解しておく必要があります。
ここでそれらのお作法について解説してみます。
# 対象読者
- Azure Machine Learning （以降 Azure ML）の機能・概念をひととおり知っている
- Azure ML Python SDK をこれから触ってみようと考えている

# 今回のスコープ
- Azure ML が提供するパイプライン機能を使わない、もっともシンプルな環境でのデータの受けとり方

パイプラインは一連のスクリプトの単位（あるいはステップ）をいくつか連ねて実行する考え方で、CI/CD パイプラインへの移行を容易にします。
パイプラインを使わないリモート実行では、例えば ローカル PC 上で開発したスクリプトをパワフルなリモート仮想マシン上で実行するユースケースが考えられます。

# 登場アイテム
ここで登場するアイテムは次のとおり。

- CSVファイル（運用を意識して Azure Blob Storage に配置されていると仮定）
- リモート仮想マシン（以降 Azure ML の用語を用いて "コンピューティングクラスター"）
- ローカル PC（ Visual Studio Code, Azure ML Python SDKがインストール済）
    - Python version は 3.8.10、Azure ML Python SDK version は 1.33.0.post1 を利用

![Azureml1png.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106511/bab0bb34-07f4-258c-bfe3-a41cb807e874.png)


またローカル PC 上のフォルダー構造は次のようになっている前提で記述します。 config.json は 利用する Azure ML ワークスペースの情報を保持しているファイルで、ポータルからダウンロードすることができます。ダウンロードしたら、同じディレクトリ内、 .azureml という名前のサブディレクトリ内、または親ディレクトリ内のいずれかに配置しておきます。

![20220704_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106511/e50baa1b-b2ad-bd0d-8c3c-7fc7434ec28d.png)

script.py は blob Storage 上の CSV ファイルを Read して outputs ディレクトリに書きだすだけの簡単な内容でサンプルとして用意しました。
その script.py をコンピューティングクラスターに送りこんで実行させるのが HelloWorld1.ipynb の役目になります。

HelloWorld1.ipynb の手順は以下のとおり。

![Azureml3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106511/69b83ec0-df21-5aa7-d7ed-2e65e1d897a3.png)

# 手順
順番にみていきましょう。

1. パッケージの読込み
<br>まずパッケージを読込みます。
<br> workspace には config.json から Azure ML ワークスペースの情報がセットされ、実験の実行時に変数として渡されます。

    ```python    
    from azureml.core import Workspace, Experiment, Dataset, Datastore, 
    ScriptRunConfig, Environment
    from azureml.core.compute import ComputeTarget
    from azureml.core.compute_target import ComputeTargetException
    from azureml.core.conda_dependencies import CondaDependencies
    from azureml.core.runconfig import DockerConfiguration
    
    workspace = Workspace.from_config()
    ```

1. コンピューティングクラスターの指定
<br>Python SDK でリモートコンピュートリソースを作成することもできますが、ここでは全体の見通しがよくなるように事前にAzure ML Studop ワークスペースでコンピューティングクラスターを作成しておきました。

    ```Python    
    aml_compute_target = "demo-cpucluster"  # <== The name of the cluster being used
    try:
        aml_compute = ComputeTarget(workspace, aml_compute_target)
        print("found existing compute target.")
    except ComputeTargetException:
        print("no compute target with the specified name found")
    ```

1. CSV ファイルのパス指定
<br>ここで demostore は Azure ML Studio ワークスペースに登録したデータストア名です。データストアの BLOB コンテナ内のファイルパスを dataset クラスに渡しています。
表形式のファイルを渡す場合には Tabular.from_delimited_files() を使い、それ以外のファイルやディレクトリを渡す場合は File.from_files() を使います。

    ```python    
    ds = Datastore(workspace, 'demostore')
    dataset = Dataset.Tabular.from_delimited_files(path=(ds, 'work/HelloWorld.txt'))
    ```

1. 環境の指定
<br>ここでは実行環境を指定します。環境名として myenv を指定し、その環境（コンテナイメージ）で使用するパッケージを指定します。


    ```python
    myenv = Environment.from_conda_specification(name="my-env", file_path="conda.yml")
    docker_config = DockerConfiguration(use_docker=True)
    ```
    conda.yml はノートブックと同じフォルダに配置されているものとします。

    ```yml
    name: my-env
    dependencies:
    - python=3.8.5
    
    - pip:
      - azureml-defaults
      - pandas==1.1.4
    channels:
    - anaconda
    - conda-forge
    ```

1. 実行ファイル名の指定
<br>source_directory で リモート実行するスクリプト一式がはいったフォルダ名を指定します。また script でリモート実行のエントリーとなるスクリプトファイル名を指定します。
リモート実行では指定した script_folder 内のファイル、サブディレクトリ全てが コンテナに渡されるので、不要なファイルは配置しないように注意します。
インプットファイル名を as_named_input メソッドで渡します。ここで指定した input_ds が引数として渡されます。

    ```python    
    src = ScriptRunConfig(source_directory='script_folder1', 
                          script='script1.0.py',
                          arguments=[dataset.as_named_input('input_ds')],
                          compute_target=aml_compute,
                          environment=myenv,
                          docker_runtime_config=docker_config)
    ```

1. 実験の実行
<br>experiment_name は実験の表示名として使われます。

    ```python    
    experiment_name = 'ScriptRunConfig1A'
    experiment = Experiment(workspace = workspace, name = experiment_name)
    
    run = experiment.submit(config=src)
    run
    ```
    このセルは非同期に終了するので、実行の終了を待つ場合は 次のステートメントを実行しておきましょう。

    ```python    
    %%time
    # Shows output of the run on stdout.
    run.wait_for_completion(show_output=True)
    ```


1. script1.0.py
<br>リモート実行されるスクリプトの中身です。
get_context() によって呼び出し側スクリプトの実行情報が渡されます。この run の中には引数として渡されるインプットファイル名も含まれているので、これを取り出します。
最後に outputs フォルダに書きだしています。この outputs フォルダは既定で何もしなくても作成され、実行後に実験の 「出力とログ」 から参照することができます。

    ```python
    
    from azureml.core import Run, Dataset
    
    run = Run.get_context()
    print(run.input_datasets)
    
    input_ds = run.input_datasets['input_ds']
    df = input_ds.to_pandas_dataframe()
    
    df.to_csv('./outputs/HelloWorld.csv', mode='w', index=False)
    ```

# おわりに
いかがでしょうか。Azure ML Python SDK の input/output にはいくつかのバリエーションがあって混乱するユーザーも多いのではと思います。
公式ドキュメントの Tutorial や How-to-use-azureml のサンプルは長大なものが多く見とおしが悪いので、シンプルにしたものをポストしていければと思います。


# 参考資料
[Azure Machine Learning SDK for Python とは](https://docs.microsoft.com/ja-jp/python/api/overview/azure/ml/?view=azure-ml-py(URL))
[Train with Azure Machine Learning datasets](https://github.com/Azure/MachineLearningNotebooks/blob/master/how-to-use-azureml/work-with-data/datasets-tutorial/train-with-datasets/train-with-datasets.ipynb)
[Azure ML Python SDK を使う２：データセットをインプットとして使う - その２](https://qiita.com/notanaha/items/30d57590c92b03bc953c)
[Azure ML Python SDK を使う３：アウトプットを Blob ストレージに書きだす - その１](https://qiita.com/notanaha/items/d22ba02b9cc903d281b6)
[Azure ML Python SDK を使う４：アウトプットを Blob ストレージに書きだす - その２](https://qiita.com/notanaha/items/655290670a83f2a00fdc)
[Azure ML Python SDK を使う５：パイプラインの基本](https://qiita.com/notanaha/items/6d86631a5dd9956ed011)