AWSでAIサービスを使ってみる〜第12回personalize編その②〜

##前回まで
前回まではpersonalizeのレコメンデーション機能を試すために、データの前準備とデータセットを登録するためのpythonファイルを確認しました。

前回記事です。
[AWSでAIサービスを使ってみる〜第11回Personalize編〜](https://qiita.com/AInosukey/items/1939cbac0ac5085f6463)

今回はAWSにpersonalizeで用いるロールの作成と、データの取り込みについて試して行きます。

##ロールを作成する
購入履歴のデータをPersonalizeに取り込むためにS3を利用します。Personalizeに対してS3にアクセスする許可を与えるためにロールを作成します。

以下はロールを作成するプログラムの全体です。

```pers_create_role.py
import boto3
import json

iam = boto3.client('iam')
role_json = {
  "Version":  "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "personalize.amazonaws.com"
        
      },
      "Action": "sts:AssumeRole"
      
    }
  ]
}

#ロールの作成
role = iam.create_role(
  RoleName='Personalize_TestRole',
  AssumeRolePolicyDocument=json.dumps(role_json))

print('role ARN:', role['Role']['Arn'])

#ポリシーの定義
policy_json = {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:ListBucket",
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

#ポリシーの作成
policy = iam.create_policy(
  PolicyName='Personalize_TestPolicy',
  PolicyDocument=json.dumps(policy_json))

print('policy ARN:', policy['Policy']['Arn'])

iam.attach_role_policy(
  RoleName='Personalize_TestRole',
  PolicyArn=policy['Policy']['Arn'])

```

ここからは部分ごとに詳細を解説します。

####ロールの作成部分
```pers_create_role.py
import boto3
import json

iam = boto3.client('iam')
role_json = {
  "Version":  "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "personalize.amazonaws.com"
        
      },
      "Action": "sts:AssumeRole"
      
    }
  ]
}

#ロールの作成
role = iam.create_role(
  RoleName='Personalize_TestRole',
  AssumeRolePolicyDocument=json.dumps(role_json))

print('role ARN:', role['Role']['Arn'])
```

・変数role_jsonに辞書とリストでロールを定義し代入します。
・create_roleメソッドを用いてroleを作成します。

####ポリシーの作成部分

```pers_create_role.py
#ポリシーの定義
policy_json = {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:ListBucket",
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

#ポリシーの作成
policy = iam.create_policy(
  PolicyName='Personalize_TestPolicy',
  PolicyDocument=json.dumps(policy_json))

print('policy ARN:', policy['Policy']['Arn'])

iam.attach_role_policy(
  RoleName='Personalize_TestRole',
  PolicyArn=policy['Policy']['Arn'])

```
・変数policy_jsonに辞書とリストでポリシーを定義し代入します。
・crerate_policyメソッドを用いてpolicyを作成します。
・attach_role_policyメソッドでロールにポリシーを追加します。

###ロール作成の実行
```
ptyhon pers_create_role.py
```
pythonコマンドでロール作成ファイルを実行して下さい。
エラーがなくポリシーARNとロールARNが表示されれば完了です。

##データを取り込む
次にS3にcsvファイルのデータをアップロードして、prsonalizeへのデータ取り込みを行います。
データを取り込むプログラムの全体です

```pers_import_dataset.py
import boto3
import json
import uuid
import time

region = 'ap-northeast-1'
s3 = boto3.client('s3', region)

bucket = str(uuid.uuid1())
print('bucket:', bucket)

s3.create_bucket(
  Bucket=bucket,
  CreateBucketConfiguration={'LocationConstraint': region})

#バケットのポリシーを定義
policy_json = {
  "Version": "2012-10-17",
  "Id": "PersonalizeS3BucketAccessPolicy",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "personalize.amazonaws.com"
      },
    "Action": [
      "s3:ListBucket",
      "s3:GetObject"
    ],
    "Resource": [
      "arn:aws:s3:::"+bucket,
      "arn:aws:s3:::"+bucket+"/*"
    ]
    }
  ]
}
#バケットにポリシーを追加
s3.put_bucket_policy(Bucket=bucket, Policy=json.dumps(policy_json))

file_name = 'interaction.csv'
s3.upload_file(file_name, bucket, file_name)

iam = boto3.client('iam')
#！既存のロールネームを入力
role_arn = iam.get_role(RoleName='Personalize_TestRole')['Role']['Arn']

#データセットグループを取得
personalize = boto3.client('personalize')
for group in personalize.list_dataset_groups()['datasetGroups']:
  #!作成したデータセットグループネームを入力
  if group['name'] == 'Personalize_TestGroup':
    break
group_arn = group['datasetGroupArn']

#データセットを取得
for dataset in personalize.list_datasets(
        datasetGroupArn=group_arn)['datasets']:
  #!作成したデータセットネームを入力
  if dataset['name'] == 'Personalize_TestDataset':
    break
dataset_arn = dataset['datasetArn']

#データ取り込みのジョブ開始
job_arn = personalize.create_dataset_import_job(
  #ジョブネームを取得
  jobName='MyTestJob', datasetArn=dataset_arn,
  dataSource={'dataLocation': 's3://'+bucket+'/'+file_name},
  roleArn=role_arn)['datasetImportJobArn']
print('job ARN:', job_arn)

#データ取り込みのジョブの進捗の表示
start = time.time()
status = ''
while status not in ['ACTIVE', 'CREATE FAILED']:
  status = personalize.describe_dataset_import_job(
      datasetImportJobArn=job_arn)['datasetImportJob']['status']
  time.sleep(10)
  print('{:7.2f} {}'.format(time.time()-start, status))

```

こちらも部分ごと解説していきます。

####インポートとs3バケットの作成
```pers_import_dataset.py
import boto3
import json
import uuid
import time

region = 'ap-northeast-1'
s3 = boto3.client('s3', region)

bucket = str(uuid.uuid1())
print('bucket:', bucket)

s3.create_bucket(
  Bucket=bucket,
  CreateBucketConfiguration={'LocationConstraint': region})
```
importは省略します。
・s3= boto3.clientからs3のサービスクライアントを作成。
・uuid.uuid1()で一意的なIDを生成それを文字列に変換したものをバケット名として利用します。
create_bucketメソッドでs3バケットを作成します。



####バケットのポリシーを定義と追加

```pers_import_dataset.py
#バケットのポリシーを定義
policy_json = {
  "Version": "2012-10-17",
  "Id": "PersonalizeS3BucketAccessPolicy",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "personalize.amazonaws.com"
      },
    "Action": [
      "s3:ListBucket",
      "s3:GetObject"
    ],
    "Resource": [
      "arn:aws:s3:::"+bucket,
      "arn:aws:s3:::"+bucket+"/*"
    ]
    }
  ]
}
#バケットにポリシーを追加
s3.put_bucket_policy(Bucket=bucket, Policy=json.dumps(policy_json))
file_name = 'interaction.csv'
s3.upload_file(file_name, bucket, file_name)
```

・policy_jsonでバケットのポリシーを辞書型の変数へ代入
・put_bucket_policy メソッドでバケットにポリシーを追加
・upload_fileでs3バケットに'interaction.csv'をアップロード



####ロールの情報、データセットグループ、データセットの取得
```pers_import_dataset.py
iam = boto3.client('iam')
#！既存のロールネームを入力
role_arn = iam.get_role(RoleName='Personalize_TestRole')['Role']['Arn']

#データセットグループを取得
personalize = boto3.client('personalize')
for group in personalize.list_dataset_groups()['datasetGroups']:
  #!作成したデータセットグループネームを入力
  if group['name'] == 'Personalize_TestGroup':
    break
group_arn = group['datasetGroupArn']

#データセットを取得
for dataset in personalize.list_datasets(
        datasetGroupArn=group_arn)['datasets']:
  #!作成したデータセットネームを入力
  if dataset['name'] == 'Personalize_TestDataset':
    break
dataset_arn = dataset['datasetArn']
```

・iamサービスクライアントを作成。get_roleメソッドでロールを取得しrole_arnへ
・作成したデータセットグループをlist_dataset_groupsメソッドで取得、group_arnへ
・作成したデータセットをlist_datasetsメソッドで取得、dataset_arnへ


####データの取り込みの開始
```pers_import_dataset.py
#データ取り込みとジョブの作成
job_arn = personalize.create_dataset_import_job(
  #ジョブネームを取得
  jobName='MyTestJob', datasetArn=dataset_arn,
  dataSource={'dataLocation': 's3://'+bucket+'/'+file_name},
  roleArn=role_arn)['datasetImportJobArn']
print('job ARN:', job_arn)

#データ取り込みのジョブの進捗の表示
start = time.time()
status = ''
while status not in ['ACTIVE', 'CREATE FAILED']:
  status = personalize.describe_dataset_import_job(
      datasetImportJobArn=job_arn)['datasetImportJob']['status']
  time.sleep(10)
  print('{:7.2f} {}'.format(time.time()-start, status))

```
・create_dataset_import_jobメソッドでs3上のデータをデータセットへ取り込む取り込むジョブを開始します。jobName'でジョブネームを指定、'dataSource'でデータセットへ取り組む元のs3バケットを指定します。
・データ取り込みのジョブの進捗表示では、not in文で['ACTIVE', 'CREATE FAILED']以外のステータスの時、describe_dataset_import_jobでジョブの進捗を10秒置きに表示します。

###データの取り込みの実行
```
ptyhon pers_import_dataset.py
```
pythonコマンドでデータの取り込みを実行して下さい。
エラーがなく、ジョブが開始されジョブの状態がACTIVEになったら完了です。
ジョブが完了するまで時間がかかるかもしれません。

##まとめ
ロールの作成とデータの取り組みは以上になります。まだまだ続きます。

##参考文献
この記事は以下の情報を参考にして執筆しました。

[AWSでつくるAIプログラミング入門](https://www.amazon.co.jp/AWS%E3%81%A7%E3%81%A4%E3%81%8F%E3%82%8B-AI%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E6%9D%BE%E6%B5%A6-%E5%81%A5%E4%B8%80%E9%83%8E/dp/4798059056)