目次
▼ 必要に応じて下記ページを参考に環境を準備すること。
[Python] [1] タスク指向型対話システム (状態遷移ベースの環境準備:MeCab, SCXML)
[Python] [2] タスク指向型対話システム (状態遷移ベースの環境準備:OpenWeatherMap, Telegram)
[Python] [3] タスク指向型対話システム (状態遷移ベースの実装)
▼ Python3.6がインストールされていること。
このページでは、venvの仮想環境(Python3.6)上にNumPyをインストールした環境で、Python対話モード(Pythonインタプリタ)にて実装サンプルを記載している。
※ Python対話モードについては下記を参考。
Python対話モード:[Python] 対話モード (インタプリタ) の使用方法
▼ 対話システムのプログラムについて
この記事で登場するサンプルプログラムは、下記参考文献『Pythonでつくる対話システム』のGitHubサポートページで提供されているプログラムをダウンロードして使用させていただく。
【参考文献】
東中 竜一郎、稲葉 通将、水上 雅博 (2020) 『Pythonでつくる対話システム』株式会社オーム社
【GitHubサポートページ】
https://github.com/dsbook/dsbook
$ pip3 install sklearn
$ pip3 install dill
| 発話行為名 | 発話行為キー | 備考 |
|---|---|---|
| 天気情報の要求 | requet-weather | ユーザーが天気情報を要求している。 |
| 伝達情報の初期化 | initialize | ユーザーが案内の初期化を要求している。 |
| 伝達情報の訂正 | correct-info | ユーザーが発話行為の推定を訂正要求している。 |
| 属性名 | 属性キー | 値 |
|---|---|---|
| 場所(都道府県) | place | 都道府県のいずれか |
| 日付 | date | 今日、明日等の日付 |
| 情報種別 | type | 天気 or 気温 |
requet-weather 福岡の天気は?
requet-weather 明日の福岡の気温教えて
correct-info 大阪じゃなくて福岡です
correct-info 天気じゃなく気温
initialize もう一度はじめから
initialize リセットして!
…
da=request-weather
大阪
大阪 です
明日
明日 です
天気
天気 です
大阪 の明日
大阪 の明日 です
大阪 の天気
大阪 の天気 です
大阪 の天気 を教えてください
明日 の天気
明日 の天気 です
明日 の天気 を教えてください
明日 の大阪 の天気
明日 の大阪 の天気 です
明日 の大阪 の天気 を教えてください
大阪 の明日 の天気
大阪 の明日 の天気 です
大阪 の明日 の天気 を教えてください
da=initialize
もう一度はじめから
はじめから
はじめからお願いします
最初から
最初からお願いします
初期化してください
キャンセル
すべてキャンセル
da=correct-info
大阪 じゃない
大阪 じゃなくて
大阪 じゃないです
大阪 ではありません
明日 じゃない
明日 じゃなくて
明日 じゃないです
明日 ではありません
天気 じゃない
天気 じゃなくて
天気 じゃないです
天気 ではありません
import re
import random
import json
import xml.etree.ElementTree
# 都道府県名のリスト
prefs = ['三重', '京都', '佐賀', '兵庫', '北海道', '千葉', '和歌山', '埼玉', '大分',
'大阪', '奈良', '宮城', '宮崎', '富山', '山口', '山形', '山梨', '岐阜', '岡山',
'岩手', '島根', '広島', '徳島', '愛媛', '愛知', '新潟', '東京',
'栃木', '沖縄', '滋賀', '熊本', '石川', '神奈川', '福井', '福岡', '福島', '秋田',
'群馬', '茨城', '長崎', '長野', '青森', '静岡', '香川', '高知', '鳥取', '鹿児島']
# 日付のリスト
dates = ["今日","明日"]
# 情報種別のリスト
types = ["天気","気温"]
# サンプル文に含まれる単語を置き換えることで学習用事例を作成
def random_generate(root):
buf = ""
# タグがない文章の場合は置き換えしないでそのまま返す
if len(root) == 0:
return root.text
# タグで囲まれた箇所を同じ種類の単語で置き換える
for elem in root:
if elem.tag == "place":
pref = random.choice(prefs)
buf += pref
elif elem.tag == "date":
date = random.choice(dates)
buf += date
elif elem.tag == "type":
_type = random.choice(types)
buf += _type
if elem.tail is not None:
buf += elem.tail
return buf
# 学習用ファイルの書き出し先
fp = open("da_samples.dat","w")
da = ''
# examples.txt ファイルの読み込み
for line in open("examples.txt","r"):
line = line.rstrip()
# da= から始まる行から対話行為タイプを取得
if re.search(r'^da=',line):
da = line.replace('da=','')
# 空行は無視
elif line == "":
pass
else:
# タグの部分を取得するため,周囲にダミーのタグをつけて解析
root = xml.etree.ElementTree.fromstring(""+line+" ")
# 各サンプル文を1000倍に増やす
for i in range(1000):
sample = random_generate(root)
# 対話行為タイプ,発話文,タグとその文字位置を学習用ファイルに書き出す
fp.write(da + "\t" + sample + "\n")
fp.close()
… (省略) …
# 都道府県名のリスト
prefs = ['三重', '京都', '佐賀', '兵庫', '北海道', '千葉', '和歌山', '埼玉', '大分',
'大阪', '奈良', '宮城', '宮崎', '富山', '山口', '山形', '山梨', '岐阜', '岡山',
'岩手', '島根', '広島', '徳島', '愛媛', '愛知', '新潟', '東京',
'栃木', '沖縄', '滋賀', '熊本', '石川', '神奈川', '福井', '福岡', '福島', '秋田',
'群馬', '茨城', '長崎', '長野', '青森', '静岡', '香川', '高知', '鳥取', '鹿児島']
# 日付のリスト
dates = ["今日","明日"]
# 情報種別のリスト
types = ["天気","気温"]
… (省略) …
… (省略) …
# 学習用ファイルの書き出し先
fp = open("da_samples.dat","w")
… (省略) …
… (省略) …
da = ''
# examples.txt ファイルの読み込み
for line in open("examples.txt","r"):
line = line.rstrip()
# da= から始まる行から対話行為タイプを取得
if re.search(r'^da=',line):
da = line.replace('da=','')
# 空行は無視
elif line == "":
pass
else:
# タグの部分を取得するため,周囲にダミーのタグをつけて解析
root = xml.etree.ElementTree.fromstring(""+line+" ")
# 各サンプル文を1000倍に増やす
for i in range(1000):
sample = random_generate(root)
# 対話行為タイプ,発話文,タグとその文字位置を学習用ファイルに書き出す
fp.write(da + "\t" + sample + "\n")
… (省略) …
… (省略) …
# サンプル文に含まれる単語を置き換えることで学習用事例を作成
def random_generate(root):
buf = ""
# タグがない文章の場合は置き換えしないでそのまま返す
if len(root) == 0:
return root.text
# タグで囲まれた箇所を同じ種類の単語で置き換える
for elem in root:
if elem.tag == "place":
pref = random.choice(prefs)
buf += pref
elif elem.tag == "date":
date = random.choice(dates)
buf += date
elif elem.tag == "type":
_type = random.choice(types)
buf += _type
if elem.tail is not None:
buf += elem.tail
return buf
… (省略) …
… (省略) …
fp.close()
… (省略) …
$ python ~/gitlocalrep/dsbook/generate_da_samples.py
$ cat ~/gitlocalrep/dsbook/da_samples.dat
request-weather 高知
request-weather 大分
request-weather 京都
… (省略) …
equest-weather 青森です
request-weather 神奈川です
request-weather 神奈川です
… (省略) …
request-weather 今日
request-weather 明日
request-weather 今日
… (省略) …
initialize もう一度はじめから
initialize はじめから
initialize はじめからお願いします
… (省略) …
correct-info 福岡じゃない
correct-info 神奈川じゃない
correct-info 広島じゃない
… (省略) …