Azure ML Python SDK を使う４：アウトプットを Blob ストレージに書きだす - その２

#今回の内容
今回の内容は、前回の [Azure ML Python SDK を使う３：アウトプットを Blob ストレージに書きだす - その１](https://qiita.com/notanaha/items/d22ba02b9cc903d281b6) とほぼ同じで、インプットがファイルではなくフォルダになるところが異なっています。ただそれだけだと面白くないので、実際にいくつかのパッケージをコンテナに渡すサンプルをくっつけてみようと思います。

#登場アイテム
今回はインプットとして特定のファイルではなくフォルダを指定するため、下図の work2/input/ 配下にファイルが複数存在するという前提です。それ以外はこれまでと同じようにリモート仮想マシンや Jupyter Notebook があります。

- リモート仮想マシン（以降 Azure ML の用語を用いて "コンピューティングクラスター"）
- Jupyter Notebook
    - Azure Machine Learning Studio のコンピューティングインスタンスから起動したもの
    - カーネルは Python 3.8 - AzureML、Azure ML Python SDK バージョン 1.33.0 で検証しています

![Azureml2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106511/5c8705f1-4ea1-d378-344d-63c7ebdac0e5.png)

Python SDK のバージョンを確認するには、

```python
import azureml.core
print("SDK version:", azureml.core.VERSION)
```

Notebook のフォルダー構造はこれまでと変わりません。

![20220705_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106511/a1a8cc19-7785-b9dc-2150-99298354e1b9.png)

script2.2.py は work2/input/ の中に保存されたファイルのファイル名を CSV ファイルにまとめて work2/output/output1/ に保存します。わざわざサブフォルダ output1 を設定したのは、script2.2.py でのフォルダ作成サンプルとするためです。

HelloWorld2.2.ipynb の手順は前回と同じで以下のとおりになります。
![Azureml5-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106511/64b40804-1d59-2063-b56c-8e2d60addb31.png)




# 手順
これまでどおり手順をみていきます。

1. パッケージの読込み
<br>パッケージを読込みます。


    ```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
    from azureml.data import OutputFileDatasetConfig
    
    workspace = Workspace.from_config()
    ```

1. コンピューティングクラスターの指定
<br>コンピューティングクラスターを指定します。

    ```Python    
    aml_compute_target = "demo-cpucluster1"  # <== 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. input と output フォルダの指定
<br>demostore は Azure ML Workspace に登録したデータストア名です。データストアの BLOB コンテナ内のファイルパスを dataset クラスに渡しています。

    ```Python
    ds = Datastore(workspace, 'demostore')
    input_data = Dataset.File.from_files(ds.path('work2/input/')).as_named_input('input_ds').as_mount()
    
    output = OutputFileDatasetConfig(destination=(ds, 'work2/output')) 
    ```

1. 環境の指定
<br>冒頭に記載したとおり今回は実際にいくつかのパッケージを指定してみました。指定方法のサンプルとするために記述しただけで、特に意味はありません。

    ```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
      - opencv-python-headless
      - numpy
      - tensorflow
      - matplotlib
      - Pillow
    channels:
    - anaconda
    - conda-forge
    ```

1. 実行ファイル名の指定
<br>source_directory で リモート実行するスクリプト一式がはいったフォルダ名を指定します。また script でリモート実行のエントリーとなるスクリプトファイル名を指定します。
リモート実行では source_directory 内のファイル、サブディレクトリ全てが コンテナに渡されるので、不要なファイルは配置しないように注意します。
引数名 datadir で input_data を、引数名 output で output を渡します。
また compute_target でコンピューティングクラスター名を指定し、environment で Environment をインスタンス化した myenv を渡しています。

    ```python   
    src = ScriptRunConfig(source_directory='script_folder2', 
                          script='script2.2.py', 
                          arguments =['--datadir', input_data, '--output', output],
                          compute_target=aml_compute,
                          environment=myenv,
                          docker_runtime_config=docker_config)
    ```

1. 実験の実行
<br>スクリプトを実行します。

    ```python    
    exp = Experiment(workspace, 'work-test')
    run = exp.submit(config=src)
    ```
    このセルは非同期に終了するので、実行の終了を待つ場合は 次のステートメントを実行します。

    ```python    
    %%time
    run.wait_for_completion(show_output=True)
    ```


1. script2.2.py
<br>リモート実行されるスクリプトの中身です。上述のとおり、work2/input/ の中に保存されたファイルのファイル名をデータフレームにまとめて work2/output/output1/ に outfile.csv という名前で保存します。output1/ はこのスクリプト中で作成されています。

    ```python        
    import argparse
    import os
    import cv2
    import numpy as np
    import pandas as pd
    import math
    import tensorflow as tf
    import PIL
    import matplotlib
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--datadir', type=str, help="data directory")
    parser.add_argument('--output', type=str, help="output")
    args = parser.parse_args()
    
    print("Argument 1: %s" % args.datadir)
    print("Argument 2: %s" % args.output)
    
    print("cv2: %s" % cv2.__version__)
    print("numpy: %s" % np.__version__)
    print("pandas: %s" % pd.__version__)
    print("tensorflow: %s" % tf.__version__)
    print("matplotlib: %s" % matplotlib.__version__)
    print("PIL: %s" % PIL.__version__)
    
    file_dict = {}
    file_dict_df = pd.DataFrame([])
    i = 0
    
    for fname in next(os.walk(args.datadir))[2]:
        print('processing', fname)
        i += 1
        infname = os.path.join(args.datadir, fname)
    
        file_dict['num'] = i
        file_dict['file name'] = fname
        file_dict_df = file_dict_df.append([file_dict])
    
    os.makedirs(args.output + '/output1', exist_ok=True)
    outfname = os.path.join(args.output, 'output1/outfile.csv')
    file_dict_df.to_csv(outfname, index=False, encoding='shift-JIS')
    ```

# おわりに
いかがでしょうか。Azure ML Python SDK を使う１～４で Azure ML Python SDK の基本操作がお分かりいただけたと思います。次回はパイプラインについてご紹介しようと思います。


# 参考資料
[Azure Machine Learning SDK for Python とは](https://docs.microsoft.com/ja-jp/python/api/overview/azure/ml/?view=azure-ml-py)
[Azure/MachineLearningNotebooks](https://github.com/Azure/MachineLearningNotebooks)
[Azure ML Python SDK を使う１：データセットをインプットとして使う - その１](https://qiita.com/notanaha/items/89fd11fff8eb3fead176)
[Azure ML Python SDK を使う２：データセットをインプットとして使う - その２](https://qiita.com/notanaha/items/30d57590c92b03bc953c)
[Azure ML Python SDK を使う３：データセットをインプットとして使う - その１](https://qiita.com/notanaha/items/d22ba02b9cc903d281b6)
[Azure ML Python SDK を使う５：パイプラインの基本](https://qiita.com/notanaha/items/6d86631a5dd9956ed011)