Donald Trump Sentiment Analysis Twitter BOT -AWS SageMaker- 後編
The former post was about writing a SageMaker Notebook and deploying an inference point in AWS. This is to focus on a twitter BOT reacting to our controversial president Donald Trump’s great tweets and generate retweets with sentiment analysis. I used scikit-learn own-container to train twitter corpus and deployed an inference endpoint on AWS SageMaker. Twitter bot part was expected to be coded in Lambda and it retweets his tweets with positive or negative label that is classified by the model. With Layer and Lambda package size limitation (up to 50M) I could not deploy the required libraries on Lambda and Layers. A local code on the server works fine by calling SageMaker inference endpoint. This article is written in Japanese mostly but you can check my repository to clone if you want to reuse the code for other purpose. [1]
AWS LambdaとSageMakerを使用してトランプ大統領のツイートを感情分析するTwitter BOTを作成してみた記事の後編です。Twitter上での感情分析はポジティブ・ネガティブでの2値分類として取り扱います。このTwitter BOTはAWS Lambda上で構築される予定でしたが、Lambda LayerおよびLambda関数のデプロイのサイズ制限から必要なライブラリをアップロードできませんでした(50Mの制限)。サーバ上のコードを実行することでトランプ大統領のツイート内容がポジティブなのかネガティブなのかを判定してリツイートできました。コードはトランプさんの最新ツイートを確認し、SageMakerの推論サービスへ感情分析を問いあわせた後でその結果をリツイートするという動きになっています。
以下の順序でシステムを構築してみます。前編と後編に分けています。この記事は後編です。
- SageMaker and inference point(前編)
- Lambda for Twitter Bot(後編)
- CloudWatch Event(後編)
後編は以下の項目から成り立っています。Lambda上での実装が制限でできなかったためサーバ上からSageMakerの推論サービスを呼び出してリツイートする迄に留まっています。
- Dump TfidfVectorizer pickle
- Write a Lambda function and play with it
- Failed to pack the libraries due to the limitation
Dump TfidfVectorizer pickle
トランプさんのツイートを取得して分析するLambda関数用のコードを書いていきます。その前に取得したツイートのベクトル化が行えるようTfidfVectorizerの結果をダンプして保存しておきます。元データからローカルで走らせた結果を保存してもよいですが、まずはSageMakerコンテナ内でベクトル化した際に同時にS3へ飛ばすことを検討しました。※最終的にはローカルのディレクトリから読みだすことにした
SageMakerのNotebook処理は各種イベントからトリガーすることができます。新しいデータが到着したことをきっかけとして推論サービスのデプロイと同時にTfidfVectorizerを更新するということが可能となります。前回作成したSageMakerコンテナの randomforest/train
を修正してモデルが出力されるディレクトリと同じ場所にTfidfVectorizerを保存するようにしてみました。
We wrap TfidfVectorizer pickle code in our SageMaker container image when we run it. It’s efficient not to go twice loading and running TfidfVectorizer both when we train a model and when we generate a TfidfVectorizer instance. It would suffice as a part of SageMaker code. I altered the code randomforest/train
to save TfidfVectorizer model in the model path as below.
イメージを再度ビルドして同様にローカルでテストします。訓練時に『TfidfVectorizer saved.』と出力されるはずです。
$ docker build -t sklearn-rf-container .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sklearn-rf-container latest a0080be07478 4 hours ago 1.4GB$ ./train_local.sh sklearn-rf-container
Starting the training.
Obtained 12055 features in dataset
X shape: (59440, 12055)
y shape: (59440,)
TfidfVectorizer saved.
Training complete.
local_test/test_dir/model
配下にモデルファイルおよびTfidfVectorizerのモデルファイルである tfidf.pkl
が保存されていれば成功です。
$ ls -al test_dir/model/
total 96712
-rw-r--r-- 1 user user 98190286 Jun 4 18:11 model.pkl
-rw-r--r-- 1 user user 825935 Jun 4 18:11 tfidf.pkl
ここまでは良かったのですがSageMakerは model_path
のファイルを圧縮してS3にアップロードしてしまいます。従ってローカルのテストではこの挙動で問題ないのですが、S3からtfidf.pklのファイルを読み込むということができませんでした。ローカルはモデルファイルもTfidfVectorizerのpickleファイルも生の状態で存在するため問題ありません。一旦ローカルの/tmpディレクトリ以下に保存しておきます。Lambda関数のパッケージへこのディレクトリごと含める予定です。次にこのアプリケーションのメインのコード作成に移っていきたいと思います。
tmp
というディレクトリを作成してダンプしたファイルをコピーしておきました。ローカルでのテストに使用できます。
$ cd lambda_function/
$ mkdir tmp
$ cp ../local_test/test_dir/model/tfidf.pkl tmp/
Write a Lambda function and play with it
Lambdaを使用したTwitter BOTについては多くの記事があるので特筆すべき点はないのですが、今回はPython3.7系で tweepy
を使ったボットにしています。今回の各処理と処理順序ですが、以下でどうでしょうか。
処理順序の例:
- トランプさんの最新ツイートをゲットする
- そのツイートに対して既にリツイートしているか確認する
- リツイートしていない場合は、ツイートをベクトル化する
- ベクトル化したツイートを推論サービスへ投げて分析する
- 分析結果をツイートに対してリツイートする
各種ライブラリとLambdaで実行するPythonファイルをzipでまとめてアップロードする必要がありますが、少しコツが必要です。まずrequirements.txtを書いてライブラリ群をインストールします。 pip3 install -r requirements.txt -t .
でローカルにインストールできます。
# requirements.txtscipy
numpy
textblob
nltk
tweepy
sklearn
ローカルにインストールしたnltkで punkt
wordnet
stopwords
などをローカルのパスにダウンロードしていきます。デプロイについてはAWS Serverless Application Model (AWS SAM)を利用するとYAMLのファイルで効率的に行えます。余力があれば SAM のテンプレートも書いてみようと思います。[2]
こちらの記事を参考にTwitter Appsの作成とローカルからツイートするサンプルを実行してみました。手元の環境はpipenvでpython3.7.3にしてあります。[3]
次にLambdaへアップロードする前にローカルで実装できるか確認してみます。今回使用したtweepyのライブラリではなんとリツイート時のコメントを付与する機能がないようでした。投稿に対象のツイートリンクを含めることで似たようなことが達成できます。実質リツイートではないですが、今回はリツイートとこの方法を組み合わせて進めたいと思います。[4]
ローカルから実行するテストのpythonコードがこちらです。 pilambda_function_local.py
という名前で保存してあります。[5]
実行方法は以下です。{“number”: 1} という形で直近何件のツイートを確認するか指定できます。基本的には1件でOKですが、過去ツイートの確認のために件数を設定できるようにしておきました。
export TW_ACCESS_TOKEN=<your access token>
export TW_ACCESS_TOKEN_SECRET=<your access secret>
export TW_CONSUMER_KEY=<your consumer key>
export TW_CONSUMER_SECRET=<your consumer secret>$ python lambda_function_local.py '{"number": 1}'
以下のようなコンソール出力が得られます。Prediction is: 0はツイートがポジティブと分析されたことを、Prediction is: 1はツイートがネガティブであると分析されたことを意味しています。
Tweet has not been retweeted
TfidfVectorizer loaded successfully
Raw text: ...His primary strength was not military, but rather personal public relations. I gave him a new life, things to do… https://t.co/JeaQ4Zw20X
Preprocessing tweet: ['primary', 'strength', 'military', 'rather', 'personal', 'public', 'relations', 'give', 'new', 'life', 'things', 'https']
Transformed tweet: (0, 10693) 0.2270625316280991
(0, 10198) 0.31967081792921936
(0, 8846) 0.4120126345363282
(0, 8702) 0.2999951014869577
(0, 8510) 0.3112602819322586
(0, 8389) 0.3637290613318961
(0, 7997) 0.353207325189579
(0, 7264) 0.18252031202204097
(0, 6790) 0.3424489892966775
(0, 6149) 0.1772418368866653
(0, 4334) 0.22486629786155096
Precition is: 0Tweet has not been retweeted
TfidfVectorizer loaded successfully
Raw text: ...over the last number of nights. If she doesn’t treat these men and women well, then we’ll bring in a different group of men and women!
Preprocessing tweet: ['last', 'number', 'nights', 'treat', 'men', 'women', 'well', 'bring', 'different', 'group', 'men', 'women']
Transformed tweet: (0, 11788) 0.42034645205954646
(0, 11608) 0.2212333553735369
(0, 10946) 0.28548478576302566
(0, 7486) 0.3083030373241981
(0, 7355) 0.33120024999796227
(0, 6694) 0.44819072815136674
(0, 5990) 0.2212333553735369
(0, 4564) 0.28434202829057964
(0, 2849) 0.29528816200536384
(0, 1398) 0.26505493276550385
Precition is: 1Tweet has not been retweeted
TfidfVectorizer loaded successfully
Raw text: .@Facebook CEO Mark Zuckerberg is today criticizing Twitter. “We have a different policy than Twitter on this. I be… https://t.co/6PocJSbXXf
Preprocessing tweet: ['Facebook', 'CEO', 'Mark', 'Zuckerberg', 'today', 'criticize', 'Twitter', 'different', 'policy', 'Twitter', 'https']
Transformed tweet: (0, 10804) 0.2834928201535288
(0, 8211) 0.5715536249035186
(0, 2849) 0.47482587355695066
(0, 2427) 0.6062166812138425
Precition is: 1
Twitter AppsのAPIキーを正しく設定していれば、対象のツイートに対するコメント付きのツイートを生成して投稿してくれます。以下が実行例です。https://twitter.com/DonaldAnalysis
SageMakerの推論を呼ぶ箇所は boto3
の invoke_endpoint
を使用しています。[6]
ローカルで実装できたのでこのコードをLambdaへ移植したいと思いますが、コードサイズが大きすぎるために実際はLambdaで動かすことができませんでした。詳細は次節にメモしてあります。
Failed to pack the libraries due to the limitation
すべての必要なライブラリとnltkのコーパスをzipファイルにまとめると100M以上となりました。Lambdaのデプロイパッケージは50Mまでなのでそのままではアップロードできません。以下がローカルでインストールに使用したrequirements.txtでした。
# requirements.txtscipy
numpy
textblob
nltk
tweepy
sklearn
そのままではパッケージをアップロードできないため、ライブラリを小分けにしてレイヤー化することを考えました。以下の記事のようにしてsklearnのレイヤー、nltkのレイヤーという風に分割できればメインのLambda関数からそれらのレイヤーを呼びだせます。[7]
まずはsklearnのライブラリをzipファイルにまとめてレイヤーにしようとしましたが、sklearn単体で既に50Mを超えてしまいました。レイヤーのファイルサイズの制限に該当してしまっているためレイヤー化もできません。sklearnはTfidfVectorizerでツイートのベクトル化に使用しているので必須のライブラリです。
$ ls -al
total 61076
drwxr-xr-x 33 user user 4096 Jun 7 15:16 sklearn
-rw-rw-r-- 1 user user 62440341 Jun 7 15:17 sklearn.zip
というわけでLambdaを使用することはあきらめました。ローカルのテストコードの結果の通り環境のあるインスタンス上からの実行が可能なことは確認できています。リポジトリは以下です。[8]
今回はサクッと作りたかったのでラベル分類だけで済む感情分析にしましたが、ツイートに対する応答文の生成でリツイートするなどより現実的なサービスとして利用できるボットへ応用も可能です。Lambda関数やレイヤーのサイズ制限は盲点でしたが、おそらく何かしらの方法で対応することはできると思います。ボットを動かすためだけにサーバ管理するのもうざいのでこの点は引き続き調査します。またあまりうざすぎるボットの作成は自重してください。
Reference
- [1] yuyasugano/donald-trump-twitter-bot
- [2] AWS サーバレスアプリケーションモデル
- [3] Lambda Python3.6でTweetしてみた[with Serverless Framework]
- [4] How to use Tweepy to retweet with a comment
- [5] lambda_function_local.py
- [6] SageMakerRuntime
- [7] pandasをLambdaのLayerとして追加する
- [8] yuyasugano/donald-trump-twitter-bot
- [9] How to build Sentiment Analysis with NLTK and Sciki-learn in Python