雑談対話モデルを動かす環境構築にハマった話

この記事は、[AIRS-Lab Advent Calendar 2021](https://qiita.com/advent-calendar/2021/airs-lab)の12/20分の記事です。

本来の記事タイトルは「**シナリオ型チャットボットと雑談対話モデルを統合したみた**」にするつもりでしたが、結果的にこのタイトルになりました。

久しぶりにせっかく記事を書くのなら、と意気込んだものの、新しいことをやろうとすると、やっぱりハマりますね、環境構築。やろうと思ったことに辿り着けないまま期限を迎えたので、ハマったことを中心に、やりたかったことを共有します！

:::note info
2021/12/21更新 記事最後の統合作業に誤りがあったので修正して、HAPPY? ENDになりました。失礼しました。
:::

### チャットボットと雑談力

私事ですが、今年の年初に『[チャットボットの教科書](https://www.amazon.co.jp/gp/product/4822295990)』という本を出版しました。この本は、主に「**仕事で**」使うチャットボットを作りたい方を想定読者として、オープンソースのチャットボット開発プラットフォーム「[Botpress](https://chatbot.today/botpress/)」を解説した本です。[^book]

[^book]: 機械学習の本ではなく、主にWebサイトやアプリを「チャットボット化」するにはどうすればいいかを、システム開発目線で書いています。ご興味あればご覧ください

ここでいう「仕事で」とは主に、情報検索や申込手続きといった「タスク」を処理することを目的としたものであることを意味します。逆に言えば、「タスク」を持たない会話≒「**雑談**」は対象としていませんでした。

一方で、チャットボットに対して雑談が期待されるシーンも増えてきましたね。まぁ、もともとチャットボットは、こんなにビジネスに使われるようになる前は「お喋り用のおもちゃ」がほとんどだったわけですが、近年では技術的ブレイクスルーによって性能が急激に向上しましたし、「[エアフレンド](https://airfriend.ai/ja/)」を代表として一般向けにサービス化されたものもあり、チャットボットの雑談力に対する世の中の期待が大きく上がったように思います。

### 従来型チャットボットで雑談対話モデルを活用したい

今後は、高度な雑談ができるチャットボットがもっと一般的になり、API提供してくれるクラウドサービスも多く出てくるでしょう。そしてそのとき、これまでの「仕事用の」チャットボットには、高度な雑談機能を取り込んで「**統合**」することが求められると考えられます。高度な雑談ができるからといって、タスクを処理するシナリオや、メニューベースの会話が急に不要になるとは考えにくいからです。

そのような「**シナリオやルールベースの会話と、生成ベースの雑談とを、どう統合するか**」という問題は、既に色々なところで研究・開発されていると思いますが、実務レベルでの知見が広く共有されているとは思えません。（僕が知らないだけかもしれませんが…）そのため、この記事では「試してみた」レベルの作品を提示しよう！と、思っていました。

が、残念ながら道半ばで時間切れになりました。。今回は、その試みの記録だけ、簡単ですが以下に残します。

# システム構成

今回作成するシステム構成を以下のように考えました。

![overview-.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356716/d783758a-8366-5a15-5747-929e472a4905.png)

利用するモジュールは以下のものです。

### japanese-dialog-transformers （雑談対話システム）

https://github.com/nttcslab/japanese-dialog-transformers

NTTのCSLabが2021年9月に公開した日本語のTransformer対話モデルです。[2020年の対話システムライブコンペティション](https://dialog-system-live-competition.github.io/dslc3/result.html)で優勝したモデルを、誰でも自分で動かすことができます。

対話サービスの開発に利用することは認められていないのであくまで検証用ですが、純粋に会話を楽しめる応答がされるので、「こういうものが実際に使えるようになったら、どう応用できるだろう」という模索をするのに良いと思いました。

### fairseq-jp-dialog-api （対話システムAPI）

https://github.com/tktkbohshi/fairseq-jp-dialog-api

上記の対話システムは、それ単体ではターミナル上のCLIからしか操作できません。今回は、後述の「シナリオベースのチャットボットシステム」と統合して使いたいので、APIから操作できるようにする必要があります。

このモジュールは、上記の対話システムに対してAPIを追加してくれるものです。このAPIを利用すれば、ユーザーの発話テキストをHTTPリクエストとして送信し、対話システムの応答をHTTPレスポンスとして得ることができます。（tktk_bohさん、ありがとうございます）

### Botpress （チャットボット開発プラットフォーム）

https://github.com/botpress/botpress

チャットボットの開発フレームワークとランタイム、そして管理・運用のためのGUIツールなどを含むパッケージソフトウェアです。JavaScriptベースなのでWeb開発と相性が良く、前述の『チャットボットの教科書』でも採用しています。今回は「シナリオベースのチャットボットシステム」の例として利用します。

# M1 Macbookへのインストール（BAD ENDルート）

上記のようなシステムを、当初はローカル環境で再現しようと考え、M1プロセッサのMacbookへインストールしました。

## 対話システム

この対話システムを動かすには、リポジトリのREADMEに記載の通り、以下のソフトウェアが必要です。しかし、これが素直にはいきません。

#### Python 3.8.10 on miniconda

minicondaには、M1(Apple Silicon)バイナリが用意されています。しかし、M1バイナリではインストール後に起動できない問題に直面します。（後述）一方、x86バイナリなら起動まで進みますが、代わりに激遅問題が発生します。（後述）

#### CUDA 11.1/10.2

macOSでは既にCUDAがサポートされなくなっているので、CUDA 11.1は使えません。CUDA 10.2までなら動くのでインストールします。

#### Pytorch 1.8.2

1.8.2は、macOSではソースからビルドするしかありません。しかし、ソースからビルドするのは面倒そうで、macOSだとまたハマる臭いしかしません。そのためビルドは避け、最新Stable版でも行けると踏んで、pipから1.10.1を入れました。

#### fairseq 1.0.0a0

READMEにはコミットID「8adff65ab30dd5f3a3589315bbc1fafad52943e7」のものを使え、とあるので、以下のURLからチェックアウトして、ビルドしました。

https://github.com/pytorch/fairseq/tree/8adff65ab30dd5f3a3589315bbc1fafad52943e7

macOSだけ、インストール時に必要なフラグが異なるので注意。
`CFLAGS="-stdlib=libc++" pip install --editable ./`

#### sentencepiece 0.1.96

最初は、minicondaのM1バイナリをインストールしましたので、以下のIssueに該当しました。M1 Macだと問題があるので、ソースから入れろというものです。コメントの手順で入ります。

https://github.com/google/sentencepiece/issues/608

しかし、いざ対話モデルを起動しようとするとエラーになります。エラーは、sentencepieceをimportできないというものです。

どうやらバイナリに関係する印象のエラーなので（雑な判断）、ここで、minicondaをx86バイナリに変更して入れ直しました。すると起動できるようになりました。やったー。（BAD ENDへ邁進）

### CLIで動作確認

READMEに記載のコマンドを、モデルのファイル名だけ修正して、以下の内容をstart.shなどに入れて実行します。

```
python scripts/dialog.py data/sample/bin/ \
 --path checkpoints/japanese-dialog-transformer-1.6B-persona50k.pt \
 --beam 80 \
 --min-len 10 \
 --source-lang src \
 --target-lang dst \
 --tokenizer space \
 --bpe sentencepiece \
 --sentencepiece-model data/dicts/sp_oall_32k.model \
 --no-repeat-ngram-size 3 \
 --nbest 80 \
 --sampling \
 --sampling-topp 0.9 \
 --temperature 1.0 \
 --show-nbest 5
```

起動して、「>>」というプロンプトが出たら、何か入力してみます。

```
2021-12-20 18:50:20 | INFO | fairseq.tasks.translation | [src] dictionary: 32002 types
2021-12-20 18:50:20 | INFO | dialog | loading model(s) from checkpoints/japanese-dialog-transformer-1.6B-persona50k.pt
2021-12-20 18:50:50 | INFO | dialog | loading done
0.0 こんにちは。よろしくお願いします。
2021-12-20 18:50:51 | INFO | dialog | [('こんにちは。よろしくお願いします。', 0.0)]
('こんにちは。よろしくお願いします。', '')
>>今日は寒いですね。
```

しばらくすると以下の応答がありました。（長いので中略）

```
W-0	174.879	seconds
2021-12-20 18:54:49 | INFO | dialog | system_utt_cands: D-0	-1.6943604946136475	本当ですね。私は救急救命士です。お仕事はなにをされているんですか?
2021-12-20 18:54:49 | INFO | dialog | system_utt_cands: D-0	-1.9483416080474854	寒いですね。私は島根に住んでいるのですが、あなたはどこに住んでいるんですか?
（中略）

sys: 本当ですね。私は救急救命士です。お仕事はなにをされているんですか?
>>
```

**所要時間、174秒。おそっ。**

こんなの、穏便なHTTPクライアントでもtimeoutしてもおかしくありません。いかにM1 Macでも、x86バイナリではダメそうです。

**BAD END**

亀「もうちょっとだけ続くんじゃ」

### その他のもののインストール

#### 対話システムAPI

リポジトリをチェックアウトして、依存ライブラリをインストールします。

```
% git clone git@github.com:tktkbohshi/fairseq-jp-dialog-api.git
% cd fairseq-jp-dialog-api
% pip install -r requirements.txt 
```

インストールが終わったら、以下のように起動します。[^dir]

[^dir]: ディレクトリとしてfairseq-jp-dialog-apiとjapanese-dialog-transformersが並列にあるものとします

```
DATA_PATH=../japanese-dialog-transformers/data/sample/bin \
MODEL_PATH=../japanese-dialog-transformers/checkpoints/japanese-dialog-transformer-1.6B-persona50k.pt \
bash flask-fairseq.sh
```

#### Botpress

公式サイトからバイナリをダウンロードしてきて起動します。[^bpmac]

https://botpress.com/

[^bpmac]: macOS Catalina以降ではセキュリティを解除する必要があります。[拙著の読者サポートページ](https://chatbot.today/for-readers/)を参照してください。

## 雑に統合してみる

今回は統合の検討に時間をとることができませんでしたが、簡単に繋いで動作確認をしてみましょう。

Botpressで新しくボットを作成して、下図のようなロジックを組みます。

* Botpress NLUのインテントに合致したら、フローで対応
* Botpress NLUのインテントに合致しなければ、雑談対話システムから応答を取得

Botpress NLUのインテントとして、ここでは「contact」（問い合わせの要求）というインテントがあるものとして、以下のフローを組みました。

![Botpress Studio – ntt-ds-integration 2021-12-21 07-15-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356716/01f737d0-69c8-e951-bbca-25c427b4a52d.png)

#### 使ってみる

これで、先ほどの入力を実行してみます。うまくいけば雑談対話モデルからの応答があるはずです。さあこい！

![Botpress Studio – ntt-ds-integration 2021-12-21 07-18-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356716/7c8aedec-d651-60c2-0a83-8021bd005a9b.png)

キターーーーーー！

が、動いたとはいえ、応答には1分近くかかりました。先ほどCLIで動かした時よりも速いですが、やはりこのまま検証を進めるのは辛いところです。

~~**BAD END**~~
次回へ続く！

## 次回予告

次回、AWS EC2 g4dnインスタンスを使って爆速雑談インテグレーション！[^next]

みんな見てくれよな！！

[^next]: M1 Macでももっと早く動かす方法があればどなたか教えてください。。