AWS & Game Advent Calendar 2020 の10日目の記事です。
はじめに
ゲームにおけるチート行為は大変厄介なものです。チート行為を野放しにすることは、他のゲームユーザーの体験を著しく損なう上に、ゲームの運営自体にも損害を与えかねません。
しかし、これらのチート行為の検出は、従来、ゲーム運営を熟知したエンジニアが統計処理などを駆使して人力で検知を行う、非常に属人的で効率の悪いものでした。また、不正検知の自動化といっても、特定の閾値を定めただけの単純なスクリプトを流す程度の対策が取られてきました。
それなら、近年、半ば魔法の言葉となりつつある、機械学習を用いてある程度チート検出が自動化できたらどんなに効率的なことでしょう。
しかし、機械学習といっても、これまた、機械学習や統計処理を熟知したエンジニアやデータサイエンティストが必要になってきます。そのようなスキルを持ったエンジニアは、どこの会社にもいるわけではありません。
そこで、本記事では、近年注目を集めている AutoML
1 を用いた異常検知技術を使って、ゲームログからチートユーザーの検出をしてみることにします。
前提条件
利用サービス
- Amazon SageMaker Autopilot
- Amazon Athena
- [Machine Learning (ML) with Amazon Athena (Preview)] (https://docs.aws.amazon.com/ja_jp/athena/latest/ug/querying-mlmodel.html)
今回利用するデータ
全てこちらの github リポジトリから参照できます。
手順の大まかな流れ
- 擬似的なゲームログを用意してあるので、最初にそれをダウンロードします
- ゲームログは学習用データと検証用データのデータセットに分かれています
- 学習用のデータセットを用いて、AWSのAutoMLサービスであるAmazon SageMaker Autopilotにてログからチートを検出する機械学習モデルを作成します
- 最適なモデルをデプロイしたあと、検証用のデータセットを用いてモデルの精度を確認します
- 検証用のデータを運用中の新規のゲームログと見立てて、Amazon Athenaを使って作成した機械学習モデルを呼び出し、ゲームログに不正が含まれていないかを推論します
今回利用するゲームログ
今回、チート検出に利用するゲームログの内容を下記に示します。
こちらのログは、実際のゲームのログではなく、あるプログラムにより機械的に作成されたログであり、一定(全体の26%程度)のチートによる不正データを含むログとなっています。一般的なRPGやパズルゲーム、音ゲーなどのスコアや得点を伴う時系列のログを想定しています。ゲームログの内容を下記に簡単に示します。
-
player_id
: プレイヤーごとに付与されている一意のユーザーID。 -
level
、score
: ゲーム内でのユーザーのレベルやスキルを示す。 -
gold
やpotions
: ユーザーの所有するゲーム内のアイテム数を示すカラム。 -
cheat_label
: あらかじめゲームのイベントログが不正(チート)なのか、正常なのかラベリングしたカラム。fraud
は不正を表し、チートのレコードであることを示す。legit
は正常なレコードであることを示す。 -
timestamp
: 各ユーザーのアクションやイベントの発生日時。
ここで重要なのは、cheat_label
カラムに示されるように、学習用のデータセットにはあらかじめ各レコードの情報が不正なのか(fraud
)、正常なのか(legit
)という正解のラベリングがされていることです。これからモデルを作成する際に利用するAutoMLであるSageMaker Autopilotは教師あり学習により機械学習モデルを作成するサービスであるため、学習用データセットへの事前のラベルづけは必須になってきます。
AutoMLによる推論モデル作成手順
Amazon SageMaker Studio のセットアップ
こちらの詳細手順は割愛します。詳しくは、こちらを参照してください。
ゲームログのデータセットをダウンロード
SageMaker Studio上からnotebookを開いて下記のコードを貼り付けて実行します。今回のチート検出に使う学習用のデータセットをダウンロードします。
%%sh
wget https://raw.githubusercontent.com/zentahori/sagemaker-autopilot-cheat-detection-sample/main/dataset/sample_playerlog_for_training.csv
続いて、同じように下記のコードを貼り付けて実行します。こちらは、モデル検証用のデータセットのダウンロードになります。
%%sh
wget https://raw.githubusercontent.com/zentahori/sagemaker-autopilot-cheat-detection-sample/main/dataset/sample_playerlog_for_validation.csv
次に下記のコードをnotebook上で実行して、ダウンロードしたデータセットの中身を確認しておきましょう。
import pandas as pd
cheat = pd.read_csv('sample_playerlog_for_training.csv')
cheat[:10]
validation_data = pd.read_csv('sample_playerlog_for_validation.csv')
validation_data[:10]
学習用のデータセットをS3にアップロード
次に、SageMaker Autopilotでデータセットを読み込んでモデルを作成するために、一旦学習のデータセットをS3にアップロードします。下記のコードをnotebook上で実行します。
import sagemaker
prefix = 'sagemaker/cheat-detection/input'
sess = sagemaker.Session()
uri = sess.upload_data(path="./sample_playerlog_for_training.csv", key_prefix=prefix)
print(uri)
こちらを実行するとアップロード先のS3バケットのURLが表示されるので、控えておきます。
あとでこちらの バケットのURLは使用します。今回使用しているS3バケットは、デフォルトのS3バケットであることに注意してください。
s3://sagemaker-us-west-2-ACCOUNT_NUMBER/sagemaker/cheat-detection/input/sample_playerlog_for_training.csv
SageMaker Autopilotによるチート検出モデルの自動作成
注意: 詳細については、こちらを参考にしてください。
SageMaker StudioのLauncherから「Build models automatically」をクリックします。
AUTOPILOT EXPERIMENT SETTINGS
が開くので、下記の設定値をそれぞれ入力します。
-
Experiment Name
: cheat-detection-sample -
CONNECT YOUR DATA
- 入力の
S3 bucket address
: 先ほど上記の手順で表示した S3 URL- (例 s3://sagemaker-us-east-2-[ACCOUNT-NUMBER]/sagemaker/cheat-detection/input/sample_playerlog_for_training.csv)
-
Target
: cheat_label
- 入力の
-
Output data location (S3 bucket)
- 出力先の
S3 bucket address
: s3://sagemaker-us-east-2-[ACCOUNT-NUMBER]/sagemaker/cheat-detection/output
- 出力先の
そのほかの値は全てデフォルトのままで、最後に Create Experiment
をクリックして実験を開始します。
実験が開始されると、下記のようにAutopilotが自動でデータを解析して、必要な前処理や特徴量エンジニアリングやハイパーパラメータの最適化までを全て自動で実行します。
処理時間はデータ量にも依存しますが、今回のデータ量では終了までにおよそ3時間ほどかかりました。
最適なモデルをデプロイする
実験完了後、 Trials
タブを開くと、Experimentが様々なアルゴリズムや条件を適用して複数の異なるチューニングのモデルを作成したモデル一覧が見られます。その中で、上部に☆印付きで Best
と書かれた精度の高い最適なチューニングをされたモデルがあるので、選択状態にして Deploy model
をクリックします。
そのまま Deploy model
というタブが開くので、エンドポイントに名前を付け (cheat-detection-sample
など)、すべての設定をデフォルトのままにします。Deploy model
をクリックします。モデルが、Amazon SageMaker によって管理される HTTPS エンドポイントにデプロイされます。
モデルの精度を検証する
モデルのデプロイが完了したら、検証用のデータセットを用いてモデルの精度を検証してみます。検証用のデータセットは、学習用のデータセットとは別でモデルに対しては未知のデータのはずです。
ここでは boto3 SDK の invoke_endpoint
API を使用して、機械学習モデルの精度を表す重要なメトリクスである正確性、適合率、再現率、F1 スコアを計算します。
SageMaker StudioでNotebookを開き、以下のコードをコピーして貼り付け、実行します。
import boto3, sys
ep_name = 'cheat-detection-sample'
sm_rt = boto3.Session().client('runtime.sagemaker')
tn=tp=fn=fp=count=0
with open('sample_playerlog_for_validation.csv') as f:
lines = f.readlines()
# length = len(lines)
for l in lines[1:2000]: # Skip header
l = l.split(',') # Split CSV line into features
label = l[8] # Store 'yes'/'no' label
del l[8] # Remove label
l = ','.join(l) # Rebuild CSV line without label
response = sm_rt.invoke_endpoint(EndpointName=ep_name,
ContentType='text/csv',
Accept='text/csv', Body=l)
response = response['Body'].read().decode("utf-8")
#print ("label %s response %s" %(label,response))
if 'fraud' in label:
# Sample is positive
if 'fraud' in response:
# True positive
tp=tp+1
else:
# False negative
fn=fn+1
else:
# Sample is negative
if 'legit' in response:
# True negative
tn=tn+1
else:
# False positive
fp=fp+1
count = count+1
if (count % 100 == 0):
sys.stdout.write(str(count)+' ')
print ("Done")
accuracy = (tp+tn)/(tp+tn+fp+fn)
precision = tp/(tp+fp)
recall = tp/(tp+fn)
f1 = (2*precision*recall)/(precision+recall)
print ("%.4f %.4f %.4f %.4f" % (accuracy, precision, recall, f1))
print ("tp:%d fn:%d tn:%d fp:%d" % (tp, fn, tn, fp))
データ2000ポイントの集計が終わると、以下のような出力が表示されます。
100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400 1500 1600 1700 1800 1900 Done
0.9995 0.9981 1.0000 0.9990
tp:525 fn:0 tn:1473 fp:1
これを表にまとめると下記のようになります。
メトリクス | 数値 | 説明 |
---|---|---|
Accuracy (正解率) | 0.9995 | チートあり、なしと予測したデータのうち、実際に正解したものの割合: accuracy = (tp+tn)/(tp+tn+fp+fn) |
Precision (適合率) | 0.9981 | チートと予測したデータのうち実際にチートであるものの割合: precision = tp/(tp+fp) |
Recall (再現性) | 1.0000 | 実際にチートであるデータのうち、チートと予測されたものの割合: recall = tp/(tp+fn) |
F1 スコア | 0.9990 | 適合率と再現率の調和平均: f1 = (2precisionrecall)/(precision+recall) |
この表から分かるように、Recall (再現性) は100%であり、全て取りこぼしなく不正データ(チートであるとラベルされたデータ)は不正である、とこのモデルは正しく推論できていることを示しています。
Athenaを使ってゲームログからチート予測をする
Machine Learning (ML) with Amazon Athena を利用すれば、直接Athenaのクエリからチート予測の推論モデルを呼び出し、S3に保存されているログをスキャンして、チートの予測をすることが可能です。
ここでは、検証用のデータセットをS3に保存して、Athenaを用いてチート検出する手順を見て行きます。
分析データとデータソースの準備
Notebookへ下記のコードをコピーして検証用のデータセットをS3へアップロードしておきます。この際に出力された、S3のURLをメモしておきます。
prefix = 'sagemaker/cheat-detection/sample-data'
sess = sagemaker.Session()
uri = sess.upload_data(path="./sample_playerlog_for_validation.csv", key_prefix=prefix)
print(uri)
Management consoleのAmazon Athenaの画面に移動して、AWS Glue Crawlerを用いて新規テーブルを作成します。 Glue Crawlerを用いたテーブルの作成詳細についてはこちらを参照してください。
Glue Crawlerに cheat-detection-sample
などと名前をつけて次に進みます。
Add a data store
のステップでは下記のように Include Path
に先ほどメモした検証用のデータのアップロード先のパスを指定します。
最後にクローラーの出力先のデータベースを設定します。新規にデータベースを作成して、データベース名をcheat-detection-sample
とします。
Crawlerの設定が完了したら、最後に Run crawler
を実行してデータソースからテーブルを作成します。クーロールが完了するとcheat-detection-sample
という名前のデータベースとその中に sample_data
というテーブルが出来上がっているはずです。
モデルを使用してAthenaでチート分析を行う
さて、データソースが準備できたところで、Athenaの画面に戻りましょう。
下記のクエリをコピーして、Athenaのクエリエディタに貼り付け、クエリを実行してみます。
USING FUNCTION predict_cheating_log(player_id BIGINT, level BIGINT, score BIGINT, units BIGINT, gold BIGINT, potions BIGINT, friends BIGINT, inv_items BIGINT, timestamp VARCHAR)
RETURNS VARCHAR TYPE
SAGEMAKER_INVOKE_ENDPOINT WITH (sagemaker_endpoint = 'cheat-detection-sample')
SELECT *, predict_cheating_log(player_id, level, score, units, gold, potions, friends, inv_items, timestamp) AS cheat
FROM "cheat-detection-sample"."sample_data"
WHERE predict_cheating_log(player_id, level, score, units, gold, potions, friends, inv_items, timestamp) = 'fraud' limit 100;
実行すると、作成たモデルがチートと判断したユーザーのレコードの最初の100件を取ってきて表示します。
cheat列に記載されているのが推論によりチートと判断されたレコードです。fraud
ならチート、legit
なら正常です。
推論によるcheat列の結果と事前にラベルづけされた正解データを示すcheat_labelの情報が一致しいていることが確認できると思います。
結果の一番最初に表示されいてるplayer_id
が15316
のユーザーが怪しいと思えば、下記のクエリを実行して、このユーザーの行動ログを全て表示してみます。
そうすると、他の時間帯においても、常にチート行為をしていることがわかります。
USING FUNCTION predict_cheating_log(player_id BIGINT, level BIGINT, score BIGINT, units BIGINT, gold BIGINT, potions BIGINT, friends BIGINT, inv_items BIGINT, timestamp VARCHAR)
RETURNS VARCHAR TYPE
SAGEMAKER_INVOKE_ENDPOINT WITH (sagemaker_endpoint = 'cheat-detection-sample')
SELECT *, predict_cheating_log(player_id, level, score, units, gold, potions, friends, inv_items, timestamp) AS cheat
FROM "cheat-detection-sample"."sample_data"
WHERE player_id = 15316;
お片づけ
最後に、今回利用したリソースを削除しておきます。SageMaker Studioのnotebook上へ下記のコードをコピーしてリソースを削除します。
sess.delete_endpoint(endpoint_name=ep_name)
%%sh
aws s3 rm --recursive s3://sagemaker-us-east-2-ACCOUNT_NUMBER/sagemaker/cheat-detection/
-
AutoML (Automated Machine Learning) は、自動化された機械学習のことであり、機械学習や深層学習への深い知識がなくても強力な機械学習モデルの構築を可能にするフレームワークやサービスのこと。 ↩