[JAWS-UG CLI] Amazon MachineLearning 入門 (1) データソースの作成（学習モデルの作成用）

# この記事について

[JAWS-UG CLI専門支部 #67 MachineLearning入門](https://jawsug-cli.doorkeeper.jp/events/41917)で実施するハンズオン用の手順書です。


# Amazon Machine Learningとは

教師あり学習が可能なフルマネージドサービスです。
学習モデルの生成および学習モデルを使った予測を実行することができます。

組込済みのアルゴリズムを使うことで、非常に簡単に機械学習をはじめることができます。
二項分類、多項分類、回帰分析を行うことが可能です。
ただし、特定のアルゴリズムしか利用できないため、より柔軟性を求める場合は他の方法を検討する必要があります。

簡単に初めてみることができるという意味では、かなり素晴らしいサービスだと思います。


# 用語について

Developers.IOに素晴らしいまとめがあります。

[Amazon Machine Learning: 主な用語と関連リソースについて](http://dev.classmethod.jp/cloud/aws/amazon-machine-learning-glossary-and-resources/)


# 料金について

無償枠はありません。
数十円のコストが発生すると思います。


# 前提条件

## 必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

- MachineLearningのフルコントロール権限
- S3のフルコントロール権限
- STSの関するフルコントロール権限

# 0. 準備

## 0.1. リージョンを指定

```bash:コマンド
export AWS_DEFAULT_REGION="eu-west-1"
```

## 0.2. 資格情報を確認


```bash:コマンド
aws configure list
```

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

```text:結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************GMWA         iam-role
secret_key     ****************obFC         iam-role
    region                eu-west-1              env    AWS_DEFAULT_REGION
```

## 0.3. バージョン確認

```bash:コマンド
aws --version
```

```text:結果
aws-cli/1.11.5 Python/2.7.12 Linux/4.4.19-29.55.amzn1.x86_64 botocore/1.4.62
```

## 0.4. バージョンアップ（必要に応じて）

```bash:コマンド
sudo pip install -U awscli
```


# 1. データソースの作成準備

## 1.1. S3バケットの作成

### AWS IDの取得

```bash:コマンド
AWS_ID=$(aws sts get-caller-identity \
    --query Account \
    --output text) \
    && echo ${AWS_ID}
```

```text:結果
************
```


### バケット名の指定

```bash:コマンド
BUCKET_NAME="jawsug-cli-ml-${AWS_ID}" \
    && echo ${BUCKET_NAME}
```

```text:結果
jawsug-cli-ml-************
```

同名のバケットがないことを確認

```bash:コマンド
aws s3 ls ${BUCKET_NAME}
```

```text:結果
An error occurred (NoSuchBucket) when calling the ListObjects operation: The specified bucket does not exist
```

### 変数の確認

```bash:コマンド
cat << ETX

    BUCKET_NAME: "${BUCKET_NAME}"
    AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION}

ETX
```

```text:結果

    BUCKET_NAME: "jawsug-cli-ml-************"
    AWS_DEFAULT_REGION: eu-west-1

```


### バケットの作成

```bash:コマンド
aws s3 mb s3://${BUCKET_NAME}
```

もしくは

```bash:コマンド
aws s3api create-bucket \
    --bucket ${BUCKET_NAME} \
    --create-bucket-configuration "LocationConstraint=${AWS_DEFAULT_REGION}"
```

```text:結果
make_bucket: s3://jawsug-cli-ml-************/
```

もしくは

```text:結果
{
    "Location": "http://jawsug-cli-ml-************.s3.amazonaws.com/"
}
```


### 作成されたバケットの確認

```bash:コマンド
aws s3 ls | grep ${BUCKET_NAME}
```

```text:結果
2016-09-10 15:48:12 jawsug-cli-ml-************
```

## 1.2. バケットポリシーの生成

### ポリシーファイル名の指定

```bash:コマンド
BUCKET_POLICY_FILE="poricy_for_ml.json"
```


### 変数の確認

```bash:コマンド
cat << ETX

    BUCKET_POLICY_FILE: ${BUCKET_POLICY_FILE}
    BUCKET_NAME: "${BUCKET_NAME}"

ETX
```

```text:結果

    BUCKET_POLICY_FILE: poricy_for_ml.json
    BUCKET_NAME: "jawsug-cli-ml-************"

```


### ポリシーファイルの生成

MachineLearningが作成したS3バケットへデータを読み書きできるようにするため、バケットポリシーを定義します。

ポリシーの定義は以下の公式ドキュメントを参照してください。

[Granting Amazon ML Permissions to Read Your Data from Amazon S3](http://docs.aws.amazon.com/ja_jp/machine-learning/latest/dg/granting-amazon-ml-permissions-to-read-your-data-from-amazon-s3.html)

[Granting Amazon ML Permissions to Output Predictions to Amazon S3](http://docs.aws.amazon.com/ja_jp/machine-learning/latest/dg/granting-amazon-ml-permissions-to-output-predictions-to-amazon-s3.html)


```bash:コマンド
cat << EOF > ${BUCKET_POLICY_FILE}
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "machinelearning.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::${BUCKET_NAME}/*"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "machinelearning.amazonaws.com"
      },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::${BUCKET_NAME}"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "machinelearning.amazonaws.com"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::${BUCKET_NAME}/*"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "machinelearning.amazonaws.com"
      },
      "Action": "s3:PutObjectAcl",
      "Resource": "arn:aws:s3:::${BUCKET_NAME}/*",
      "Condition": { "StringEquals": { "s3:x-amz-acl":"bucket-owner-full-control" }}
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "machinelearning.amazonaws.com"
      },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::${BUCKET_NAME}"
    }
  ]
}
EOF

cat ${BUCKET_POLICY_FILE}
```


### ポリシーファイルの検証

```bash:コマンド
jsonlint -q ${BUCKET_POLICY_FILE}
```


## 1.3. バケットポリシーの設定



### ポリシーの適用

```bash:コマンド
aws s3api put-bucket-policy \
    --bucket ${BUCKET_NAME} \
    --policy file://${BUCKET_POLICY_FILE}
```

```text:結果
（返値無し）
```

### 適用結果の確認

```bash:コマンド
aws s3api get-bucket-policy \
    --bucket ${BUCKET_NAME}
```

```json:結果
{
    "Policy": "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"machinelearning.amazonaws.com\"},\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::jawsug-cli-ml-************/*\"},{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"machinelearning.amazonaws.com\"},\"Action\":\"s3:ListBucket\",\"Resource\":\"arn:aws:s3:::jawsug-cli-ml-************\"},{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"machinelearning.amazonaws.com\"},\"Action\":[\"s3:GetObject\",\"s3:PutObject\"],\"Resource\":\"arn:aws:s3:::jawsug-cli-ml-************/*\"},{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"machinelearning.amazonaws.com\"},\"Action\":\"s3:PutObjectAcl\",\"Resource\":\"arn:aws:s3:::jawsug-cli-ml-************/*\",\"Condition\":{\"StringEquals\":{\"s3:x-amz-acl\":\"bucket-owner-full-control\"}}},{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"machinelearning.amazonaws.com\"},\"Action\":\"s3:ListBucket\",\"Resource\":\"arn:aws:s3:::jawsug-cli-ml-************\"}]}"
}
```


# 2. データの準備

## 2.1. サンプルデータのダウンロード

AWSが提供するサンプルデータを利用します。

[Step 1: Prepare Your Data](http://docs.aws.amazon.com/ja_jp/machine-learning/latest/dg/step-1-download-edit-and-upload-data.html)

### 学習用データのダウンロード

```bash:コマンド
curl https://s3.amazonaws.com/aml-sample-data/banking.csv > banking.csv
```

```text:結果
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 4768k  100 4768k    0     0   846k      0  0:00:05  0:00:05 --:--:--  981k
```



### ファイルを確認

```bash:コマンド
ls -al | grep banking
```

```text:結果
-rw-rw-r-- 1 ec2-user ec2-user 4882918 Apr  2  2015 banking.csv
```

## 2.2. スキーマファイルの生成

先ほどダウンロードしたCSVファイルの構造を定義するためのスキーマファイルを作成します。
学習モデルの作成時にデータを併せて必要となります。

### ヘッダー情報の確認

CSVの1列目を確認します

```bash:コマンド
head -1 banking.csv
```

```text:結果
age,job,marital,education,default,housing,loan,contact,month,day_of_week,duration,campaign,pdays,previous,poutcome,emp_var_rate,cons_price_idx,cons_conf_idx,euribor3m,nr_employed,y
```

### ファイル名の指定

```bash:コマンド
DATA_SCHEMA_FILE="data_schema.json"
```


### スキーマファイルの生成

スキーマファイルの定義方法は、以下の公式ドキュメントを参照してください。

[Creating a Data Schema for Amazon ML](http://docs.aws.amazon.com/ja_jp/machine-learning/latest/dg/creating-a-data-schema-for-amazon-ml.html)

今回のサンプルは二項分類用のサンプルで、ターゲット変数として指定された`y`の属性が`BINARY`になっています。


```bash:コマンド
cat << EOF > ${DATA_SCHEMA_FILE}
{
  "version":"1.0",
  "rowId":null,
  "rowWeight":null,
  "targetAttributeName":"y",
  "dataFormat":"CSV",
  "dataFileContainsHeader":true,
  "attributes":[
    {"attributeName":"age","attributeType":"NUMERIC"},
    {"attributeName":"job","attributeType":"CATEGORICAL"},
    {"attributeName":"marital","attributeType":"CATEGORICAL"},
    {"attributeName":"education","attributeType":"CATEGORICAL"},
    {"attributeName":"default","attributeType":"CATEGORICAL"},
    {"attributeName":"housing","attributeType":"CATEGORICAL"},
    {"attributeName":"loan","attributeType":"CATEGORICAL"},
    {"attributeName":"contact","attributeType":"CATEGORICAL"},
    {"attributeName":"month","attributeType":"CATEGORICAL"},
    {"attributeName":"day_of_week","attributeType":"CATEGORICAL"},
    {"attributeName":"duration","attributeType":"NUMERIC"},
    {"attributeName":"campaign","attributeType":"NUMERIC"},
    {"attributeName":"pdays","attributeType":"NUMERIC"},
    {"attributeName":"previous","attributeType":"NUMERIC"},
    {"attributeName":"poutcome","attributeType":"CATEGORICAL"},
    {"attributeName":"emp_var_rate","attributeType":"NUMERIC"},
    {"attributeName":"cons_price_idx","attributeType":"NUMERIC"},
    {"attributeName":"cons_conf_idx","attributeType":"NUMERIC"},
    {"attributeName":"euribor3m","attributeType":"NUMERIC"},
    {"attributeName":"nr_employed","attributeType":"NUMERIC"},
    {"attributeName":"y","attributeType":"BINARY"}
  ],
  "excludedAttributeNames":[]
}
EOF

cat ${DATA_SCHEMA_FILE}
```

### スキーマファイルの検証

```bash:コマンド
jsonlint -q ${DATA_SCHEMA_FILE}
```


## 2.3. 学習用データのアップロード

### アップロードするファイル名を指定

```bash:コマンド
TRAINING_DATA_FILE="banking.csv"
```

### ファイルのアップロード

```bash:コマンド
aws s3 cp ${TRAINING_DATA_FILE} s3://${BUCKET_NAME}
aws s3 cp ${DATA_SCHEMA_FILE} s3://${BUCKET_NAME}
```

```text:結果
upload: ./banking.csv to s3://jawsug-cli-ml-************/banking.csv
upload: ./data_schema.json to s3://jawsug-cli-ml-************/data_schema.json
```


### アップロードされたファイルを確認

```bash:コマンド
aws s3 ls ${BUCKET_NAME}
```

```text:結果
2016-10-15 05:18:06    4882918 banking.csv
2016-10-15 05:18:26       1485 data_schema.json
```


# 3. データソースの作成

## 3.1. データソースの作成（学習用データ）

### データソースIDの指定

```bash:コマンド
TRAINING_DATA_SOURCE_ID="training-cli-${AWS_ID}-$(date +%Y%m%d%H)"
```

### データソーススペックファイル名の指定

学習データとそのスキーマを定義したファイルです。
学習モデルの作成時に使用します。

```bash:コマンド
TRAINING_DATA_SOURCE_SPEC_FILE="data_source_spec.json"
```

### 変数の確認

```bash:コマンド
cat << ETX

    TRAINING_DATA_SOURCE_SPEC_FILE: ${TRAINING_DATA_SOURCE_SPEC_FILE}
    BUCKET_NAME: ${BUCKET_NAME}
    TRAINING_DATA_FILE: ${TRAINING_DATA_FILE}
    DATA_SCHEMA_FILE:${DATA_SCHEMA_FILE}

ETX
```

```text:結果

    TRAINING_DATA_SOURCE_SPEC_FILE: data_source_spec.json
    BUCKET_NAME: jawsug-cli-ml-************
    TRAINING_DATA_FILE: banking.csv
    DATA_SCHEMA_FILE:data_schema.json

```


### データソーススペックファイルの生成

```bash:コマンド
cat << EOF > ${TRAINING_DATA_SOURCE_SPEC_FILE}
{
  "DataLocationS3": "s3://${BUCKET_NAME}/${TRAINING_DATA_FILE}",
  "DataSchemaLocationS3": "s3://${BUCKET_NAME}/${DATA_SCHEMA_FILE}"
}
EOF

cat ${TRAINING_DATA_SOURCE_SPEC_FILE}
```

```text:結果
{
  "DataLocationS3": "s3://jawsug-cli-ml-************/banking.csv",
  "DataSchemaLocationS3": "s3://jawsug-cli-ml-************/data_schema.json"
}
```

### データソーススペックファイルの検証

```bash:コマンド
jsonlint -q ${TRAINING_DATA_SOURCE_SPEC_FILE}
```


### 変数の確認

```bash:コマンド
cat << ETX

    TRAINING_DATA_SOURCE_ID: ${TRAINING_DATA_SOURCE_ID}
    TRAINING_DATA_SOURCE_SPEC_FILE: ${TRAINING_DATA_SOURCE_SPEC_FILE}

ETX
```

```text:結果

    TRAINING_DATA_SOURCE_ID: training-cli-************-2016102305
    TRAINING_DATA_SOURCE_SPEC_FILE: data_source_spec.json

```

### データソースの作成

学習用データのため、`--compute-statistics`オプションを付けてください。

データソースは、特に指定をしない場合には学習用で7割／評価用で3割を使用します。（評価については後述します。）

```bash:コマンド
aws machinelearning create-data-source-from-s3 \
    --data-source-id ${TRAINING_DATA_SOURCE_ID} \
    --data-spec file://${TRAINING_DATA_SOURCE_SPEC_FILE} \
    --compute-statistics
```

```json:結果
{
    "DataSourceId": "training-cli-************-2016102305"
}
```


### データソースの確認

```bash:コマンド
aws machinelearning get-data-source \
    --data-source-id ${TRAINING_DATA_SOURCE_ID}
```

完了前には以下のような結果になります。（5分くらいかかります）

```json:結果
{
    "Status": "INPROGRESS",
    "NumberOfFiles": 1,
    "DataLocationS3": "s3://jawsug-cli-ml-************/banking.csv",
    "CreatedByIamUser": "arn:aws:iam::************:user/user01",
    "DataSizeInBytes": 4882918,
    "ComputeStatistics": true,
    "LastUpdatedAt": 1474607447.288,
    "DataSourceId": "training-cli-************",
    "StartedAt": 1474607198.565,
    "LogUri": "https://eml-prod-dub-emr.s3.amazonaws.com/************-ds-training-cli/userlog/************-ds-training-cli?AWSAccessKeyId=********************&Expires=1475212248&Signature=********************************",
    "Message": "Current Step: ADVANCED_STATISTICS (2/2) 100%",
    "CreatedAt": 1474607196.128
}
```


完了後には以下のような結果になります。

```json:結果
{
    "Status": "COMPLETED",
    "ComputeTime": 1440000,
    "NumberOfFiles": 1,
    "DataLocationS3": "s3://jawsug-cli-ml-************/banking.csv",
    "CreatedByIamUser": "arn:aws:iam::************:user/user01",
    "DataSizeInBytes": 4882918,
    "ComputeStatistics": true,
    "LastUpdatedAt": 1474607449.889,
    "DataSourceId": "training-cli-************",
    "StartedAt": 1474607198.565,
    "LogUri": "https://eml-prod-dub-emr.s3.amazonaws.com/************-ds-training-cli/userlog/************-ds-training-cli?AWSAccessKeyId=********************&Expires=1475212375&Signature=********************************",
    "CreatedAt": 1474607196.128,
    "FinishedAt": 1474607449.889
}
```

### ログの確認

```bash:コマンド
TRAINING_DATA_SOURCE_LOG_URI=$(aws machinelearning get-data-source \
    --data-source-id ${TRAINING_DATA_SOURCE_ID} \
    --query LogUri \
    --output text) \
    && curl ${TRAINING_DATA_SOURCE_LOG_URI}
```

```text:結果
（省略）
```

### データソースの一覧

```bash:コマンド
aws machinelearning describe-data-sources
```

```json:結果
{
    "Results": [
        {
            "Status": "COMPLETED",
            "ComputeTime": 1328000,
            "NumberOfFiles": 1,
            "DataLocationS3": "s3://jawsug-cli-ml-************/banking.csv",
            "CreatedByIamUser": "arn:aws:sts::************:assumed-role/CLI/i-*****************",
            "DataSizeInBytes": 4882918,
            "ComputeStatistics": true,
            "LastUpdatedAt": 1476510103.939,
            "DataSourceId": "training-cli-************",
            "StartedAt": 1476509858.962,
            "CreatedAt": 1476509856.297,
            "FinishedAt": 1476510103.939
        }
    ]
}
```

以上です。