LightGBMをSageMakerの独自コンテナで実行する

元ネタの通りに実行したところ、いくつかつまずくポイントがあったのでメモ

# 元ネタ
Amazon SageMakerでLightGBMが使えるコンテナイメージを作ってみた
https://dev.classmethod.jp/articles/sagemaker-container-image-lightgbm/

# やりたいこと
[こちらのXGBoost](https://qiita.com/Roe/items/2b760c908c4dadcfe098)のLightGBM版（下記）を、SageMakerで実行する。ビルトインコンテナではLightGBMは対応していないため、カスタムコンテナが必要。

```py
# SageMaker ノートブックインスタンス上で実行する場合、LightGBMをインストールする必要がある。
!pip install lightgbm
```
lightgbmをインストールしたら、ノートブックインスタンス上でも以下のコードを動かすことができる。

```py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import lightgbm as lgb
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


"""LightGBM で二値分類するサンプルコード"""
# 乳がんデータセットを読み込む
dataset = datasets.load_breast_cancer()
x, y = dataset.data, dataset.target
# データセットを学習用とテスト用に分割する
train_x, test_x, train_y, test_y = train_test_split(x, y,
                                                    test_size=0.2,
                                                    shuffle=True,
                                                    random_state=42,
                                                    stratify=y)
# さらに学習用データを学習用とvalid用に分割する
tr_x, va_x, tr_y, va_y = train_test_split(train_x, train_y,
                                                    test_size=0.2,
                                                    shuffle=True,
                                                    random_state=42,
                                                    stratify=train_y)
# LightGBM が扱うデータセットの形式に直す
dtrain = lgb.Dataset(tr_x, label=tr_y)
dvalid = lgb.Dataset(va_x, label=va_y)
dtest = lgb.Dataset(test_x)

# 学習用のパラメータ
lgb_params = {
    # 二値分類問題
    'objective': 'binary',
    # 評価指標
    'metrics': 'binary_logloss',
}
# モデルを学習する
# バリデーションデータもモデルに渡し、学習の進行とともにスコアがどう変わるかモニタリングする
# watchlistには学習データおよびバリデーションデータをセットする
#watchlist = [(dtrain, 'train'), (dvalid, 'eval')]
model = lgb.train(lgb_params,
                dtrain,
                num_boost_round=50,  # 学習ラウンド数は適当
                #evals=watchlist
                valid_names=['train','valid'], valid_sets=[dtrain, dvalid]
                )

# 予測：検証用データが各クラスに分類される確率を計算する
pred_proba = model.predict(test_x)
# しきい値 0.5 で 0, 1 に丸める
pred = np.where(pred_proba > 0.5, 1, 0)
# 精度 (Accuracy) を検証する
acc = accuracy_score(test_y, pred)
print('Accuracy:', acc)
```
dtrain = lgb.Dataset(tr_x, label=tr_y)
と
lgb_params の中身
と
lgb.train　の中身
と
model.predict(test_x)　でdtestを指定しない
が、XGBoostとの違い。

# ノートブックインスタンス上でOputuna簡単に使える
importするだけ！
https://qiita.com/hideki/items/c09242639fd74abe73a0



# ディレクトリ構成
nginx.confとかも用意する。

# ソースコード変更箇所
Serveの変更箇所がわからない

# デバッグ
学習ジョブで落ちた時に、SageMaker側の問題なのか、コンテナ側の問題なのかの切り分けが難しい、、
コンテナ内で変数printすれば、Cloud Watchにログがでるのか？


# XGBoostはなぜ正常に処理されるのか
https://github.com/aws/sagemaker-xgboost-container/blob/master/src/sagemaker_xgboost_container/algorithm_mode/train.py

```py
# Parse arguments for train() API
early_stopping_rounds = train_cfg.get('early_stopping_rounds')
num_round = train_cfg["num_round"]
```

```
| hyperparameters = hpv.initialize(metrics) |
|:--|
|     validated_train_config = hyperparameters.validate(train_config) |
```
hyperparameters.validateメソッドで型を揃えているっぽい。
ここにいる。(algorithm-toolkitのほう）
https://github.com/aws/sagemaker-xgboost-container/blob/master/src/sagemaker_algorithm_toolkit/hyperparameter_validation.py


```py
| def validate(self, user_hyperparameters): |
|:--|
|         # NOTE: 0. Validate required or fill in default. |
|         for hp in self.hyperparameters: |
|             if hp not in user_hyperparameters: |
|                 if self.hyperparameters[hp].required: |
|                     raise exc.UserError("Missing required hyperparameter: {}".format(hp)) |
|                 elif self.hyperparameters[hp].default is not None: |
|                     user_hyperparameters[hp] = self.hyperparameters[hp].default |
```




ここでハイパーパラメータ処理している？
https://github.com/aws/sagemaker-xgboost-container/blob/master/src/sagemaker_xgboost_container/algorithm_mode/hyperparameter_validation.py

```py

| hpv.IntegerHyperparameter(name="num_round", required=True, |
|:--|
|                                   range=hpv.Interval(min_closed=1), |
|                                   tunable=True, tunable_recommended_range=hpv.Interval( |
|                                       min_closed=1, |
|                                       max_closed=4000, |
|                                       scale=hpv.Interval.LINEAR_SCALE)), |
```

この、IntegerHyperparameterで、int型と指定して読み取っているのではないか？

ここにいる
https://github.com/aws/sagemaker-xgboost-container/blob/master/src/sagemaker_algorithm_toolkit/hyperparameter_validation.py

``` py
| class IntegerHyperparameter(Hyperparameter): |
|:--|
|     def __init__(self, *args, **kwargs): |
|         if kwargs.get("range") is None: |
|             raise exc.AlgorithmError("range must be specified") |
|         super(IntegerHyperparameter, self).__init__(*args, **kwargs) |
|  |
|     @property |
|     def type(self): |
|         return "Integer" |
|  |
|     def parse(self, value): |
|         return int(value) |
|  |
|     def format_range(self): |
|         min_, max_ = self.range.format_as_integer() |
|         return {"IntegerParameterRangeSpecification": {"MinValue": min_, "MaxValue": max_}} |
```

結論：XGBoostはjsonのvalueがstr型になったものを、コンテナ側でint型に修正している。

# 感想
コンテナ内で発生したバグ解析泣ける


# 参考
Amazon SageMakerで独自の学習/推論用コンテナイメージを作ってみる
https://dev.classmethod.jp/articles/sagemaker-container-image-custom/

[AWS]SageMakerで独自の学習コンテナをインフラエンジニア目線でデプロイしてみるHello World!!
https://dev.classmethod.jp/articles/sagemaker-custom-container-deoloy/

Amazon SageMakerでRを使った独自コンテナを作成してみる
https://dev.classmethod.jp/articles/sagemaker-r-container/

AWS SageMakerローカルモードで学ぶコンテナベース機械学習
https://tech-blog.optim.co.jp/entry/2020/04/09/150000

Dockerコンテナを用いたAWS SageMakerのトレーニング
https://qiita.com/kurakura0916/items/e1f02a013e53ebaff348

Amazon SageMakerで独自アルゴリズムを使って学習してみる
https://qiita.com/d_desuyon/items/e5aeabb479f456f69b83

【Techの道も一歩から】第22回「AWS SageMakerで任意のコンテナをデプロイする」
https://buildersbox.corp-sansan.com/entry/2019/10/16/110000

【AWSブログ】Scikit Docker コンテナを構築して、Amazon SageMaker で Scikit-learnモデルのトレーニングとホストを行う
https://aws.amazon.com/jp/blogs/news/train-and-host-scikit-learn-models-in-amazon-sagemaker-by-building-a-scikit-docker-container/

GitHub(日本語):Amazon SageMaker - Bring Your Own Container TensorFlow 2.0 編
https://github.com/aws-samples/amazon-sagemaker-examples-jp/blob/master/workshop/lab_bring-your-own-containers/tensorflow2.0/bring_your_own_container_tf2.ipynb
学習用のカスタムコンテナ作成。推論はできない。

LightGBM Parameters
https://lightgbm.readthedocs.io/en/latest/Parameters.html

LightGBM Parameters Tuning
https://lightgbm.readthedocs.io/en/latest/Parameters-Tuning.html