▼ 必要に応じて下記ページを参考に環境を準備すること。
[Python] [1] タスク指向型対話システム (状態遷移ベースの環境準備:MeCab, SCXML)
[Python] [2] タスク指向型対話システム (状態遷移ベースの環境準備:OpenWeatherMap, Telegram)
[Python] [3] タスク指向型対話システム (状態遷移ベースの実装)
[Python] [4] タスク指向型対話システム (フレームベースの環境準備:SVM(sklearn))
▼ Python3.6がインストールされていること。
このページでは、venvの仮想環境(Python3.6)上にNumPyをインストールした環境で、Python対話モード(Pythonインタプリタ)にて実装サンプルを記載している。
※ Python対話モードについては下記を参考。
Python対話モード:[Python] 対話モード (インタプリタ) の使用方法
▼ 対話システムのプログラムについて
この記事で登場するサンプルプログラムは、下記参考文献『Pythonでつくる対話システム』のGitHubサポートページで提供されているプログラムをダウンロードして使用させていただく。
【参考文献】
東中 竜一郎、稲葉 通将、水上 雅博 (2020) 『Pythonでつくる対話システム』株式会社オーム社
【GitHubサポートページ】
https://github.com/dsbook/dsbook
import MeCab
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.preprocessing import LabelEncoder
import dill
# MeCabの初期化
mecab = MeCab.Tagger()
mecab.parse('')
sents = []
labels = []
# generate-samples.txt の出力である samples.dat の読み込み
for line in open("da_samples.dat","r"):
line = line.rstrip()
# samples.dat は発話行為タイプ,発話文,タグとその文字位置が含まれている
da, utt = line.split('\t')
words = []
for line in mecab.parse(utt).splitlines():
if line == "EOS":
break
else:
# MeCabの出力から単語を抽出
word, feature_str = line.split("\t")
words.append(word)
# 空白区切りの単語列をsentsに追加
sents.append(" ".join(words))
# 発話行為タイプをlabelsに追加
labels.append(da)
# TfidfVectorizerを用いて,各文をベクトルに変換
vectorizer = TfidfVectorizer(tokenizer=lambda x:x.split(), ngram_range=(1,3))
X = vectorizer.fit_transform(sents)
# LabelEncoderを用いて,ラベルを数値に変換
label_encoder = LabelEncoder()
Y = label_encoder.fit_transform(labels)
# SVMでベクトルからラベルを取得するモデルを学習
svc = SVC(gamma="scale")
svc.fit(X,Y)
# 学習されたモデル等一式を svc.modelに保存
with open("svc.model","wb") as f:
dill.dump(vectorizer, f)
dill.dump(label_encoder, f)
dill.dump(svc, f)
for line in open("da_samples.dat","r"):
line = line.rstrip()
# samples.dat は発話行為タイプ,発話文,タグとその文字位置が含まれている
da, utt = line.split('\t')
words = []
for line in mecab.parse(utt).splitlines():
if line == "EOS":
break
else:
# MeCabの出力から単語を抽出
word, feature_str = line.split("\t")
words.append(word)
# 空白区切りの単語列をsentsに追加
sents.append(" ".join(words))
# 発話行為タイプをlabelsに追加
labels.append(da)
# TfidfVectorizerを用いて,各文をベクトルに変換
vectorizer = TfidfVectorizer(tokenizer=lambda x:x.split(), ngram_range=(1,3))
X = vectorizer.fit_transform(sents)
# LabelEncoderを用いて,ラベルを数値に変換
label_encoder = LabelEncoder()
Y = label_encoder.fit_transform(labels)
# SVMでベクトルからラベルを取得するモデルを学習
svc = SVC(gamma="scale")
svc.fit(X,Y)
# 学習されたモデル等一式を svc.modelに保存
with open("svc.model","wb") as f:
dill.dump(vectorizer, f)
dill.dump(label_encoder, f)
dill.dump(svc, f)
$ python ~/gitlocalrep/dsbook/train_da_model.py
import MeCab
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.preprocessing import LabelEncoder
import dill
mecab = MeCab.Tagger()
mecab.parse('')
# SVMモデルの読み込み
with open("svc.model","rb") as f:
vectorizer = dill.load(f)
label_encoder = dill.load(f)
svc = dill.load(f)
# 発話から発話行為タイプを推定
def extract_da(utt):
words = []
for line in mecab.parse(utt).splitlines():
if line == "EOS":
break
else:
word, feature_str = line.split("\t")
words.append(word)
tokens_str = " ".join(words)
X = vectorizer.transform([tokens_str])
Y = svc.predict(X)
# 数値を対応するラベルに戻す
da = label_encoder.inverse_transform(Y)[0]
return da
for utt in ["大阪の明日の天気","もう一度はじめから","東京じゃなくて"]:
da = extract_da(utt)
print(utt,da)
# SVMモデルの読み込み
with open("svc.model","rb") as f:
vectorizer = dill.load(f)
label_encoder = dill.load(f)
svc = dill.load(f)
# 発話から発話行為タイプを推定
def extract_da(utt):
words = []
for line in mecab.parse(utt).splitlines():
if line == "EOS":
break
else:
word, feature_str = line.split("\t")
words.append(word)
tokens_str = " ".join(words)
X = vectorizer.transform([tokens_str])
Y = svc.predict(X)
# 数値を対応するラベルに戻す
da = label_encoder.inverse_transform(Y)[0]
return da
for utt in ["大阪の明日の天気","もう一度はじめから","東京じゃなくて"]:
da = extract_da(utt)
print(utt,da)
$ python ~/gitlocalrep/dsbook/da_extractor.py
大阪の明日の天気 request-weather
もう一度はじめから initialize
東京じゃなくて correct-info