SageMakerで作成したExperimentsを消す

# はじめに

AWSのSagemakerが公開されてからExperimentsを作成したり、
Autopilotを試してみたりしているのではないでしょうか。

ただ、色々試してみてゴミのExperimentsが徐々に溜まってきたのではないでしょうか？
そろそろ使わなくなったExperimentsを消そう！私はそう思った訳です。

# Studioからは消せない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226827/d4cdca86-a7a7-c7ef-acea-e4e84e361f2f.png)

GUIで消せれば良いのにどうやら消す方法はなさそうです。（2020/3/4現在）

# APIで消す

色々調べてたらAPIを使えば消せそうです。
以下を実行！

```Python
import boto3

EXPERIMENT_NAME = '<Experiment名>'

client = boto3.client('sagemaker')

client.delete_experiment(
    ExperimentName=EXPERIMENT_NAME
)
```

```
ClientError: An error occurred (ValidationException) when calling the DeleteExperiment operation: Experiment 'arn:aws:sagemaker:us-east-2:<ID>:experiment/<Experiment名>' has trials and cannot be deleted.
```

どうやらトライアルを消さないといけないようです。
[公式](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker.html#SageMaker.Client.delete_experiment)にも書いてありました。

もうこの先を試した方はわかると思いますが、トライアルも消せません。
関連するTrial Componentの関連付けを外さないといけません。
ここまですればTrialを削除することができます。
あとは全てのTrialを削除するだけです。

最終的に書いたコードは以下の通りです。

```Python
import boto3

EXPERIMENT_NAME = '<Experiment名>'
MAX_RESULTS = 100 # 一度の検索で取得する数
TRY_NUM = 10 # 再実行も含めて実行する数

client = boto3.client('sagemaker')

def delete_experiment(experiment_name, max_results):
    while True:
        # Trial listの取得
        trial_list = client.list_trials(
            ExperimentName=experiment_name,
            MaxResults=max_results,
        )
        trial_num = len(trial_list['TrialSummaries'])

        # 全てのTrialを消したら処理終了
        if trial_num == 0:
            break

        print("Info: Number of trials left: Over {}".format(trial_num))
        # Trial component listの取得
        for trial in trial_list['TrialSummaries']:
            trial_name = trial['TrialName']
            trial_component_list = client.list_trial_components(
                TrialName=trial_name,
                MaxResults=max_results,
            )

            # 関連付けを外す
            for trial_component in trial_component_list['TrialComponentSummaries']:
                trial_component_name = trial_component['TrialComponentName']
                response = client.disassociate_trial_component(
                    TrialComponentName=trial_component_name,
                    TrialName=trial_name
                )

            # Trialの削除
            client.delete_trial(
                TrialName=trial_name
            )
            print("Info: Trial deleted. [{}]".format(trial_name))

    # 全てのTrialを消したらExperimentを削除
    client.delete_experiment(
        ExperimentName=experiment_name
    )
    print("Info: Experiment deleted. [{}]".format(experiment_name))

for i in range(1, TRY_NUM + 1):
    try:
        # Experimentが存在したら削除処理を実行
        experiment_list_all = client.list_experiments(
            MaxResults = MAX_RESULTS
        )
        experiment_name_list = [experiment['ExperimentName'] for experiment in experiment_list_all['ExperimentSummaries']]
        if EXPERIMENT_NAME in experiment_name_list:
            delete_experiment(EXPERIMENT_NAME, MAX_RESULTS)
    except Exception as e:
        print("Error: {}".format(e))
        print("Try: {i}/{max}".format(i=i, max=TRY_NUM))
    except Exception as e:
        print(e)
```

いくつか補足いたします。

#### MAX_RESULTSは何を指定する？

TrialやTrial Componentのリストを取得する際、
取得できる数に限りがあります。
現状では一度のAPIの実行でMax100件までしか取得できません。
そこで一旦MAX_RESULTSとして100の値を入れています。
そのため、Trialを取得するところは無限ループして全てのTrialを削除するまで実行するようになっています。
Autopilotを使うと100個以上Trialが作られることは結構当たり前だと思いますので。。
本当に厳密にやるならばTrial Componentのリストを取得する際も無限ループにすべきだと思うのですが、
現状一つのTrialで100個以上のTrial Componentを作ることはあまりないのかなと思い、
一旦Trialのリスト取得時のみ無限ループさせる形にしました。

#### TRY_NUMは何を指定する？

本処理は何度かリトライ動作を行う処理を入れています。（リトライ回数は自身で必要だと思う数を指定してください。）
この理由としては、Disassociateの処理を行う際にたまになぜか失敗してしまうんですよね。
何回か試してみて分かったのですが間隔として10回に1回くらいですね。（でも本当に回数は気まぐれです）
以下のようなエラーがでます。

```
ClientError: An error occurred (ThrottlingException) when calling the DisassociateTrialComponent operation (reached max retries: 4): Rate exceeded
```

Disassociateの処理自体が失敗しやすいのか、内部でもリトライを行っているのですが、
4回までしか実施できません。
APIでリトライ回数を指定するか、もうちょっとリトライ回数を増やしてくれればよいのですが。。。


# 参考
リトライの処理は下記サイトを参考にさせていただきました。
https://uyamazak.hatenablog.com/entry/2017/01/17/170235