すなぶろスマートフォン用の表示で見るすなぶろPythonistaを目指しているつもりが、Hyのおかげで無事脱線。Clojurian目指すことになりました。この広告は、90日以上更新していないブログに表示しています。人工無脳プログラムと会話(?)しよう!昨今、機械学習やディープラーニングといったキーワードで注目を集めているPython。簡潔な文法から初心者向けの学習目的にも採用されています。いえ、入門書を読んだだけではよくわからないという人も多いはず。「何をどうやって作ればいいの?」「文法はわかったけど書き方がわからない」という疑問は初心者にありがちで、「英語の文法はわかっても読めない・書けない」のと似ています。解決方法はズバリ、人と会話したり、手を動かしてみることです。この記事ではPython初心者、ひいてはプログラミング初心者に「チャットbotを作る」という目標を設定してもらって、具体的な作り方や設計方法を見てもらいます。Microsoftのりんなほど高度なものではありませんが、プログラムとチャットする楽しさを感じながら、プログラミングテクニックを身に着けてもらえればと思います(今回扱うAIは機械学習とは無関係です)。World!'を出力させたときの感動をもう一度味わってください。今回の目標は「とりあえずプログラムと会話する」です。最初はバカバカしいくらい退屈ですが、徐々に成長させていくのでゆっくりやっていきましょう。単行本この商品を含むブログを見る今回のテーマは、Ruby初心者向けの書籍『恋するプログラム』をPythonに書き直し、さらに噛み砕いて説明してみようという試みです。個人的なPython勉強メモでもあり、同時にPython初心者がこの記事を参考にしてくれれば幸いです。書いたコードは随時GitHubに反映させていきます。全体像を把握したい場合は、いつでもsandmark/unmoを参照してください。プロジェクトの準備まずはプロジェクトを作成して、作業する場所を確保します。いっても、ディレクトリを作るだけなので大変なことはありません。今回はホームディレクトリ(~)にrepos/unmo/というディレクトリを作って作業することにします。repos/unmo/この場所にmain.pyというファイルを作成します。別に'main'という名前じゃなくても構わないのですが、それは後々考えることにしましょう。好きなエディタでmain.pyを開いたら、いよいよプログラミング開始です。プログラムと会話するチャットボットであるからには、人間と会話できなければなりません。手始めに「会話する機能」を実装してみましょう。注意点として、ここで言う『会話』というのは必ずしも『意思疎通できる』という意味ではありません。ユーザーが何か入力すると、その返事が返ってくるというだけの、オウム返しのようなものです。オウム返しであっても無いよりはマシですし、今後の改善に期待しましょう。main.pyに以下を記述します(できればコピペではなく、手打ちで写経してみてください)。"""AIの応答を制御するクラス。"""文字列を受け取り、自身のnameに設定する。"""ユーザーからの入力(text)を受け取り、AIの応答を生成して返す。self._nameResponderクラスは「会話する機能をまとめたもの」です。動作させてみましょう。Pythonシェルを開きます。1などのPythonコードを実行することができますが、そういった解説は入門書に任せておきましょう。main.pyをインポートしてみます。Responderエラーが出なければ正常にインポートできています。これは「main.pyからResponderクラスをロード」という意味で、これでPythonシェルからResponderの動作チェックができるようになりました。会話を試みる'こんにちはってなに?'非常にぎこちないですが、会話らしきものが成立しているような気がします。nameが定義されています。__init__は「新たにオブジェクトを作るときに自動的に呼ばれるもの」なので、基本的に使う側が明示的に呼び出す必要はありません。Responder('Oumu-Gaeshi')のタイミングで呼び出されます。nameself._nameにResponderの名前を格納していますが、なぜself.nameではいけないのでしょうか。答えは「外部からの変更を防ぐため」です。self.nameにしてしまうとどうなるか。以下の例を考えてみます。oumu.name'Karasu'エラーも出ずにオブジェクトの名前が変わってしまいました。オウム返ししかできない応答オブジェクトなのに、頭の良いことで有名なカラスになってしまっては困ります。これを防ぐために、self._nameという場所にして、「変更しちゃいけないよ」という意味を込めて保持しているのです。関連してnameメソッドを見てみます。self._nameこれは単純にself._nameの値を返すだけのメソッドですが、定義の前に@propertyというデコレータがついています。nameは本来メソッドなので、呼び出すときはoumu.name()のように括弧を付けなければなりません。「self._nameの中身を知りたいだけ」なので、いちいち括弧を付けるのは煩わしいです。そこで@propertyを付けておけば、括弧を省略できるというわけです。最後にresponseメソッドを見てみましょう。'{}ってなに?'.format(text)「○○ってなに?」という形式にして返しているだけです。文字列の中に変数を埋め込みたいので、ここではformat関数を使っています。{}の部分がtextの値に置き換わるわけです。この辺りは大いに改善の余地がありますが、今はこのままにしておきましょう。使いやすくAIと会話するのにPythonシェルを開いて、変数を作ったりメソッドを呼び出したりするのはナンセンスです。そこで、ユーザーとの便宜を図るためのインターフェイスを作ってみます。Responderはあくまでも「AIの応答を考えるクラス」なので、新たにもっとユーザーに近いクラスを作ります。main.pyに以下を追加してください。"""人工無脳コアクラス。"""文字列を受け取り、コアインスタンスの名前に設定する。Responderインスタンスを作成し、保持する。"""ユーザーからの入力を受け取り、Responderに処理させた結果を返す。self._responder.nameコードよりもコメントのほうが長いですが、この後さらにコードを追加して改良していくことを考えると、スタート地点としては妥当です。Unmoクラスはまさに「人工知能」を表すクラスです。チャットボットの俗称として『人工無脳』という言葉があるのですが、MunoのアナグラムとしてUnmoになっています。漢字で書くと雲母で、宝石の一種であり、きららというかわいい別名もあります。Pythonシェルで実行してみましょう。ai.dialogue('こんにちは')'こんにちはってなに?'応答オブジェクトが同じなので結果は変わりませんが、Responderの作成と保持を自動でやってくれるようになりました。この後どれだけResponderを追加しようと管理はUnmoクラスがやってくれるので、インターフェイス部分の設計に集中できるのです。Unmoクラスの詳細__init__メソッドは、文字列を受け取って自身に名前を付けるとともに、'What'という名前のResponderオブジェクトをself._responderに保持しています。Responder('What')将来的には他にも複数の応答オブジェクトを作り、オウム返しだけではなく様々なアプローチで返答させたいので、人工知能クラス(Unmo)が応答オブジェクト(Responder)を持つのは理にかなっています。self._responder.response(text)現状Responderオブジェクトのresponseメソッドを呼び出しているだけです。人工知能と思考エンジンが接続されているという認識でいい感じです。self._nameResponderクラスと同じく、自分の名前を返すプロパティメソッドです。self._responder.name保持しているResponderオブジェクトの名前を返します。昔ながらのコマンドラインアプリケーションさて、パーツは揃いました。インターフェイスを作って、もっとチャットがスムーズにできるようにしましょう。いえ、いきなりGUIに挑戦するのは無駄にハードルが高いですし、オウム返しするアプリケーションがグラフィカルである必要があるでしょうか。そこで、こんな感じのインターフェイスにしてみたいと思います。「○○ってなに?」と聞かれるとアイデンティティが崩壊しそうになりますが、もう少しの我慢です。インターフェイス部分のコードをmain.pyに追加しましょう。response=response))build_prompt関数はAIの名前を整形して返すヘルパーです。今回のようにUnmoの名前が'proto'で、内部のResponderが'What'なら、proto:What>という表現に変換してくれます。{responder}にはunmo.responder_nameを指定しています。'__main__'という条件式は一見意味がわかりませんが、これはスクリプトとして実行されたときに真になります。mainとしたときには実行されません。場合によってはmain.pyの動作確認のためにPythonシェルからクラスを呼び出したいときもあるでしょう。Trueなんてループが始まったら動作確認も何もないので、それを防止するための仕組みです。proto>このような画面になります。今回作成するAIの名前は'proto'にしました。Trueループが始まります。input()は「ユーザーからの文字列入力を待つ」関数で、引数はプロンプト文字列、戻り値は入力された文字列です。直後のifで、textが空だった場合にループを抜けるようになっています。「○○ってなに?」と聞かれる無限地獄から脱出したい場合は、何も入力せずにEnterキーを叩きましょう。何かしらの入力があった場合は、AIからの返事をresponseに代入して表示します。ここでもformat()関数が登場していますが、build_prompt()関数のときと使い方は一緒ですね。「○○ってなに?」しか返ってこないのではあんまりなので、新しくResponderを追加してみましょう。いくつかの応答をあらかじめ用意しておき、その中からランダムに返すというものです。構造的欠陥が解消されるわけではありませんが、それでも今よりはマシになるでしょう。ここまでのコードはsandmark/unmoに保存されています。【ランクAよりもPython力をつけろ】編スマートPythonプログラミング、引き続き読んでます。Part7(終)前回はマルコフ連鎖で学習・応答するモジュールを作りました。ヶ月)実践CommonLispをちょっとだけ翻訳した人。AIブームもっかい来ないかなと思ってたら本当に来て引く。好きな言語はClojureです。Part2はてなブログをはじめよう!sandmarkさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。