こんにちは AIチームの戸田です
今回はタスク指向対話の開発ツールキット、ConvLab-2を使った対話エージェントのPolicyモデルを強化学習を使って構築したいと思います
内容が多くなるので、前編でConvLab-2の対話モジュールの説明、次回の後編でPolicyモデルの学習について書きたいと思います。
ConvLab2
ConvLab-2はオープンソースのタスク指向対話の開発ツールキットです。前身のConvLabのフレームワークを継承しつつ、より多くのデータセットや最先端のモデルに対応するようになっています。パイプライン形式の対話モデルはもちろん、End-to-Endのモデルに対応しています。元の論文はこちらになります: link
対話モデル
一般的な対話システムは複数のモジュールのパイプラインで構成されており、ConvLab-2でも同様にNLU, DST, Policy, NLGという複数のモジュールで対話モデルを構築します。(End-to-Endのモデルも構築可能ですが、本記事では扱いません)
対話のオープンデータの一つ、MultiWoZのエージェントを構築する際は以下のようなコードになります。
from convlab2.nlu.jointBERT.multiwoz import BERTNLU
from convlab2.dst.rule.multiwoz import RuleDST
from convlab2.policy.rule.multiwoz import RulePolicy
from convlab2.nlg.template.multiwoz import TemplateNLG
# BERTを使ったNLUモデル
sys_nlu = BERTNLU()
# ルールベースのDST
sys_dst = RuleDST()
# ルールベースのPolicy
sys_policy = RulePolicy()
# テンプレートベースのNLG
sys_nlg = TemplateNLG(is_user=False)
各モジュールの連携は以下の図のようになります
以下より、各モジュールについて簡単に説明します
NLU: 言語理解
NLUはNatural Language Understandingの略で、ユーザー(人間)側の発話の意図を行います。
以下のようなレストラン予約の対話を考えてみます
ユーザーは
- 場所→渋谷駅
- 料理ジャンル→イタリアン
の条件でレストランを探していることが予測できます。NLUモジュールはユーザーの発話からこの条件を抽出します。
実際の発話では「イタリアン」ではなく、「ピザ」や「ドリア」のようにあらかじめ設定しておいたジャンルに当てはまらない発話をする可能性もあるので
- 場所→渋谷駅 90%
- 料理ジャンル→イタリアン 80%
のように確率で予測するケースが多いです。
以下にConvLab-2でNLUモデルによる発話意図推定を行うサンプルコードを示します。
input_utterance = "I want to find a hotel"
nlu_out = sys_nlu.predict(input_utterance)
print(nlu_out)
[['Inform', 'Hotel', 'none', 'none'], ['Inform', 'Hotel', 'Type', 'hotel']]
ConvLab-2はデフォルトでMultiWoZのタスクが設定されます。例ではホテルを予約しようとしていますね。以下よりこのコードの続きで各モジュールのサンプルコードを示していきます。
DST: 状態更新
DSTはDialog State Trackerの略で、NLUの出力を受けて、現在の対話状態を更新します。上記の対話例だと以下のような更新になります。
一見、特に難しい処理は行っていなさそうですが、NLUの結果が確率で来た際に何%以上で状態を更新するかや、発話意図の候補が複数ある場合など、状態をどのように更新するかのロジックを設定する必要があります。
近年ではNLUとこのDSTを一緒に予測するSUMBTやTRADEといった手法が多く研究されていますが、ConvLab-2ではこのモジュールはDSTとして扱っています。
# 初回のみ
sys_dst.init_session()
dst_out = sys_dst.update(nlu_out)
print(dst_out)
{'belief_state': {'attraction': {'book': {'booked': []},
'semi': {'area': '', 'name': '', 'type': ''}},
'hospital': {'book': {'booked': []}, 'semi': {'department': ''}},
'hotel': {'book': {'booked': [], 'day': '', 'people': '', 'stay': ''},
'semi': {'area': '',
'internet': '',
'name': '',
'parking': '',
'pricerange': '',
'stars': '',
'type': 'hotel'}},
'police': {'book': {'booked': []}, 'semi': {}},
'restaurant': {'book': {'booked': [], 'day': '', 'people': '', 'time': ''},
'semi': {'area': '', 'food': '', 'name': '', 'pricerange': ''}},
'taxi': {'book': {'booked': []},
'semi': {'arriveBy': '',
'departure': '',
'destination': '',
'leaveAt': ''}},
'train': {'book': {'booked': [], 'people': ''},
'semi': {'arriveBy': '',
'day': '',
'departure': '',
'destination': '',
'leaveAt': ''}}},
'history': [],
'request_state': {},
'system_action': [],
'terminated': False,
'user_action': []}
Policy: 行動決定
DSTで更新された対話状態から、システムの次の行動を決定するモジュールです。予約システムや検索システムなどの外部システムとの連携を行う場合もあります。
上記NLUの説明の図では、システム側は予算の確認という追加情報の要求をしていますが、以下のような返答も考えられます
- 現在の状態の絞り込み
- 例: 渋谷駅の北側でしょうか、南側でしょうか?
- 状態の変更要求
- 例: 渋谷駅付近にイタリアンのお店はありませんでした。他の場所で探しますか?
- 予算を聞かずに回答を提示する
- 例: 1件のレストランが見つかりました。店舗名は・・・
現在使われている対話システムの多くは、このPolicyモジュールのロジックを人手で作っていますが、手間のかかる作業なので、対話シミュレーターを使った強化学習で作ろうという研究が昔から盛んです。次回の後編でこちらの学習を試してみたいと思います。
polict_out = sys_policy.predict(dst_out)
print(polict_out)
[['Inform', 'Hotel', 'Choice', '9'],
['Recommend', 'Hotel', 'Name', 'gonville hotel'],
['Recommend', 'Hotel', 'Phone', '01223366611']]
NLG: 言語生成
NLGはNatural Language Generationの略で、Policyから出力された行動に合わせた発話をシステムに行わせるモジュールになります。
主に「この行動の時はこの発話」といったテンプレートベースの手法が使われています。SCLSTMのような、ニューラルネットワークの生成モデルをベースにした手法も研究されているのですが、テンプレートベースの対話完了率90.5%に対してSCLSTMは48.5%とかなり低い精度となっており、まだまだ改善の余地があるようです。
nlg_out = sys_nlg.generate(polict_out)
print(nlg_out)
We have 9 such places . Would gonville hotel work for you ? The phone number of the hotel is 01223366611 .
なお、テンプレートの一覧はConvLab-2のnlg/templateディレクトリからタスクを選んでみることができます。
パイプラインの作成
ここまで各モジュールを別々に紹介してきましたが、ConvLab-2ではPipelineAgentというクラスを使って、これらのモジュールを繋げたパイプラインを作ることが出来ます
from convlab2.dialog_agent.agent import PipelineAgent
# 各モジュールをパイプラインでつなげる
sys_agent = PipelineAgent(sys_nlu, sys_dst, sys_policy, sys_nlg, name='sys')
# テキストを入力するだけでNLGの出力まで得ることが出来ます
sys_agent.response(input_utterance)
おわりに
本記事ではConvLab-2を使った対話エージェントのPolicyモデルの構築の準備段階として、ConvLab-2のモジュールの説明を行いました
次回の後編ではこのPolicyモジュールを強化学習で学習してみたいと思います
最後までお読み頂きありがとうございました!