knaka Tech-Blog

AI, IoT, DIYエレクトロニクス, データサイエンスについて投稿予定です。

flask+ TF-IDF で、AIチャットボットをweb画面で作成する。自然言語処理(6)

index:

概要

以前の、slackチャット対応のAI チャットボット機能の
関連となります。web画面 UIを自作して、
自然言語処理webサービスを使用する例となります。

UI面は、BotUI のJSライブラリを使用しています。

環境

python 3.5.2
flask
janome
sklearn

コード

github.com

python3 です。

自然言語処理は、
前回と、ほぼ同じです。

web画面

デモの、操作画面となります。

f:id:knaka0209:20190301174106p:plain

処理など

Vue.js の変数(二重括弧)は、
flaskの レンダリング処理で、正常に動作しない為。
V ディレクティブ等を使用しています。

<html>
<head>
  <link href="{{ url_for('static', filename='botui/build/botui.min.css') }}"  rel="stylesheet">
  <link href="{{ url_for('static', filename='botui/build/botui-theme-default.css') }}"  rel="stylesheet">  
  <script src="https://cdn.jsdelivr.net/vue/latest/vue.min.js"></script>
  <script src="https://unpkg.com/botui/build/botui.min.js"></script>
  <script src="{{ url_for('static', filename='axios.min.js') }}?A2"></script>

</head>
<body>
<h1>Bot UI test:</h1>

<div class="botui-app-container" id="botui-app" style="height :400px;">
  <bot-ui></bot-ui>
</div>
<!-- form -->
<center>
  <div id="app">
    <!--
    msg :<span v-text="message"></span>
    -->
    入力:
    <input size="30" name="intext" v-model="message" />
    <button @click="addItem">質問する</button>
  </div>  
</center>

<br />
</body>
<script>
//console.log("#then-aaa");
  var botui = new BotUI('botui-app') // id of container
  //
  new Vue({
    el: '#app',
    data: {
      message: '',
    },
    created:function(){
       console.log("#create-1122");
    },
    methods: {
      update() {
        this.message = 'Vue.js';
      },
      addItem() {
        console.log(this.message );
        //
        botui.message.add({
          human: true,
          content: this.message
        });
        //
        var params = new URLSearchParams();
        params.append('intext', this.message );
        axios.post('./test3', params)
        .then(response =>{
            console.log(response.data );
            //
            botui.message.add({
              content: response.data
            });
        });
        this.message='';
      },
    }
  });

</script>
<script src="{{ url_for('static', filename='app_chat.js') }}?B1"></script>
<!--
-->
</html>


参考のページ

knaka0209.hatenablog.com

keras YOLO3 で、物体検知

index:

概要

以前の、keras 画像認識に関連した内容で、 YOLO3 物体検知
する例となります。

環境

python : 3.5.2
keras
YOLO3

準備

紹介記事が、複数ありましたので。
概要のみです

https://github.com/qqwweee/keras-yolo3
yolo3 の、コピー

・学習済ファイルのコピー、yolov3.weights
wget https://pjreddie.com/media/files/yolov3.weights

・keras読み込み、変換処理 
model_data/yolo.h5 が、作成されます。
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5

手順

python yolo_video.py --image
評価する、jpg等画像ファイル名の入力

・結果を、ファイルに保存する場合、
 yolo_video.py
 の、detect_img を、下記修正を追加すると可能でした。
https://github.com/kuc-arc-f/keras-yolo3-test/blob/master/yolo_video.py

#
def detect_img(yolo):
    while True:
        img = input('Input image filename:')
        try:
            image = Image.open(img)
        except:
            print('Open Error! Try again!')
            continue
        else:
            r_image = yolo.detect_image(image)
            #r_image.show()
            import cv2
            cv2.imwrite("out.jpg", np.asarray(r_image)[..., ::-1])
            r_image.show()
    yolo.close_session()


検出の結果

検出できました。
適当な、画像を指定しましたが。
バウンディングボックス、枠の部分が表示れされています。

f:id:knaka0209:20190301124201j:plain

その他

上記の、関連等に記載がありますが。
tiny版もあるので、容量小さめの weights ファイル
をコピーして、評価できましたが。
認識精度は、落ちそうでした。

参考の設定

github.com

keras LSTM で、文章自動生成を行う。 自然言語処理(5)

index:

概要

前回の、自然言語処理の関連となります。
学習させた文章(書籍など)、を元にLSTM
で、文章を自動生成する仕組みの例です。

テストは、google colab で行いました。

環境

python 3.5.2
janome
keras

コード

github.com

python3 です。

データセット

参考ページと、同じですが。

青空文庫の、モルグ街の殺人事件
https://www.aozora.gr.jp/cards/000094/card605.html

処理など

参考ページと、ほぼ同じですが。
形態素解析は、 janome を使用しています。

・前処理、
before.py 、改行とかの削除

・学習

・評価
モデルを、ロードして。評価
学習データの、一部の文章を指定
その後は、文章の自動生成が可能でした。

#pred
for diversity in [0.2]:  # diversity は 0.2のみ使用 
    print('----- diversity:', diversity)
    generated = ''
    text= get_token("どんなつまらない仕事でも楽しんでやるのだ")
    sentence = text[start_index: start_index + maxlen]
    generated += "".join(sentence)
    print(sentence )
    print('----- Generating with seed: "' + "".join(sentence)+ '"')
    sys.stdout.write(generated)

    for i in range(400):
        x_pred = np.zeros((1, maxlen, len(chars)))
        for t, char in enumerate(sentence):
            x_pred[0, t, char_indices[char]] = 1.

        preds = model.predict(x_pred, verbose=0)[0]
        next_index = sample(preds, diversity)
        next_char = indices_char[next_index]

        generated += next_char
        sentence = sentence[1:]
        # sentence はリストなので append で結合する
        sentence.append(next_char)  

        sys.stdout.write(next_char)
        sys.stdout.flush()
    print()

評価の結果

どんなつまらない仕事でも得てももしそう事件ということを君はよくわかっている。
部屋の窓をそのときには言葉を、この注意をてで、――それに君を言うとおり、
証人たちは荒々しい声については意見が一致しているのに、あの鋭い、
あるいは一人の証人の言うところによれば耳ざわりな、声に関してはひどい意見のものであるたにちがいない。
窓はそこから出るときにしめて行ったのだろう。
その後、猩々は人自身の証人が『鋭いというよりも耳ざわりなものであった。
耳ざわりな声で――鋭いというよりも耳ざわりなものであった。鋭い声とは言えぬ。
荒々しい声のほうの数語は聞きとれた。それはフランス人の言葉だった。
女の声ではないことは確かだ。言った言葉は聞きとれなかった。鋭い声の言葉はわからなかった。
早くて死体た見つかっで、
被害者二人がまだこのときの通り人まだ少しのただ音のレスパネエ夫人を僕と家にうししを
すっかりデュパンがこのあとをほうてのだが)、猩々のたぶんの想像に得られた我々と
部屋の扉を押しあけたときとのあいだの時間については、
証人の言うと鋭い声のものではないがこのパリでは動物はその他考えている
――が『彼はこのこの事件についてはまだなにを錠はかかっていなかった。
その建物には四階のほかにはどこにも家具がないようであった。 
このフランス人は一人の数人の殺人をフランス語て部屋そしてにあいだにデュパン君と書いてぬというしまっと君を、
それから想像デュパンのつづけた「私」 デュパンがこのあとのほうは言葉を、
非常に低い調子で、非常に静かに言っ

・とりあえず、読めなくない程度の文章を
 自動生成して、くれました。

・学習 epochs =60で、
 google colab で、25分程、
 作業PCですと、数時間かかりそうでしたが。

django + nginx + uwsgi の設定 #django

index:

概要

djangoで、nginx + uwsgi を連携し、
webサービスを構築する例となります。

環境

python 3.5
Django
nginx
uwsgi

設定ファイルの例

https://github.com/kuc-arc-f/django_nginx

python3 です。
アプリは、test1

設定方法

django プロジェクト作成、
アプリの追加等は、省略します。
前回の例と、ほぼ同じです。

nginx conf、追加

#
upstream django {
	server 127.0.0.1:8001;
}

#
server {
	listen       80;

	location / {
		uwsgi_pass django;
		include /home/pi/work/django/django1/uwsgi_params;
	}
}

https://github.com/kuc-arc-f/django_nginx/blob/master/nginx_conf/django.conf

・uwsgi_paramsは、
 プロジェクトのパスとなります。(後述します)

・ /etc/nginx/sites-available に、
conf 追加します。

・ /etc/nginx/conf.d/
に、上記のリンク追加します。

 =>既に、confがある場合、削除しておきます。

・nginx 再起動
sudo service nginx stop
sudo service nginx start


uwsgi の設定

・uwsgi_params
プロジェクト内に、配置

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

https://github.com/kuc-arc-f/django_nginx/blob/master/django1/uwsgi_params

・uwsgi の起動
uwsgi --socket :8001 --module django1.wsgi

表示の確認、

http://ip/test1/
表示されます。

参考のページ

knaka0209.hatenablog.com

Slackチャットから、flask+ TF-IDF の応答を出力する。自然言語処理(4)

index:

概要

前回の、自然言語処理の関連となります。
slackチャットからの、入力文章を webhook経由で
AI/機械学習サーバからの応答を出力する例となります。

webhookは、aws EC2 ubuntu16です。
slack app設定は、トリガー単語を検出する。
カンタンな手法で、AI側を起動しています。


・構成の概要は、
Slack入力(質問)
=> Skack appトリガー検出
=> webhook (aws EC2)呼ぶ
=> nginx+ uWSGI 経由で flask 接続
=> 入力文章から、TF-IDFで、学習済みの入力文章
 の類似文章を探す
=> 出力された、入力文章のindex番号から
 応答文章を、引き当てる
=> Slackへ、結果送信
みたいな、流れですね

環境

python 3.5
janome
sklearn
numpy

aws EC2 ,ubuntu16
nginx
uWSGI
flask

参考

https://www.sejuku.net/blog/74469

slack appの、追加方法など

・slack appで、
「Outgoing WebHooks」を追加
(発信Webフック )

・webhook の登録
=>EC2 のエンドポイントを指定。

・トリガー誤の登録( 例は、Bot: にしています。)

コード

github.com


python3 です。

処理など

__init__.py

class VectBase:
    #
    def __init__(self):
        from flaskr.include.nlp_predict import  NlpPredict
        self.pred=NlpPredict()
        #ans=self.pred.answers
        #print("ans-len=", len(ans))
        tokens=self.pred.get_data()
        #print(tokens )
        ret= self.pred.train(tokens )
        self.vectorize= self.pred.get_vectorize()
        print("#end-load-vectorize")
    #
    def predict(self, text ):
        text=self.pred.predict(text )
        #print(text )
        return text
#
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
vect=VectBase()

起動時に、学習処理して。
API応答速度は、高速にできるような形にしています。
( 文章の、件数が多い場合は。遅くなるかもしれませんが )

・webhook
views.py

@app.route('/test2', methods=['GET', 'POST'])
def test2():
    print("test2")
#    print(len(request.form ))
    ret="sorry, nothing response."
    if(len(request.form ) > 0):
        text=request.form['text']
        print(text )
        ret=vect.predict(text )
    #print(ret )
    dic = {"text" : ret }
    return jsonify(dic)

slackから、入力文を受信。
ML評価処理、結果の出力

デモの画面

入力: Bot:利用人数は?
AI応答: 利用人数は、通常プランは10名までです

みたいな、学習させた類似文章の
応答を、引当て。返します

f:id:knaka0209:20190220173036p:plain

まとめ

t2.micro インスタンスで、メモリも少ないのですが。

サーバ起動時間は、遅く。
学習処理の為。数秒かかってます。
評価処理は、1秒以下前後で。
現状だと
Slackのタイムアウト状態には、ならないようです

関連のページ

nginx 設定など
knaka0209.hatenablog.com

TF-IDF
knaka0209.hatenablog.com

flask + nginx + uwsgi, の設定

index:

概要

前回の、flask関連となりますが。
nginx + uwsgi と連携し、flask 活用する例となります。

環境

python 3.5
flask
nginx
uwsgi

インストールなど

nginx:
sudo apt-get install nginx

確認、
sudo service nginx status

停止、起動など
sudo service nginx stop
sudo service nginx start
sudo service nginx restart

Github

github.com



試した、設定ファイル等

設定など

上記の、参考ページ
を参考していますので。ほぼ同様ですが

Nginxの設定


/etc/nginx/conf.d/ 、にconf追加
myapp.conf


#
server {
	listen       80;

	location / {
		include uwsgi_params;
		uwsgi_pass unix:///tmp/uwsgi.sock;
	}
}

=> スペースが含まれる場合、エラーになりましたので。
 タブを使用しています。
https://github.com/kuc-arc-f/flask_myapp/blob/master/nginx_conf/myapp.conf

sockファイルの場所など、適宣きめてます。

/etc/nginx/sites-enabled/ に、リンク設定有る場合は、けします。(rm )

チェック、
sudo nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

successful が、でれば。OKです。

起動しときます。
sudo service nginx start

uwsgi

インストール:
pip3 install uwsgi

flask の起動ファイルを、作成
app.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(host='localhost',  debug=True)

uwsgi コマンドで、起動します。
=> ブラウザで、設置IP を開くと、 Hello world でます。

uwsgi --socket /tmp/uwsgi.sock --module app --callable app --chmod-socket=666

=> uwsgi コマンドが、実行できない場合。
pip3 インストールに、パス設定が不足している場合は。追加します。

export PATH=$PATH:~/.local/bin/


・設定ファイルからの起動
uwsgi --ini myapp.ini

=>iniファイルからの、起動ができるようです。

TF-IDF+ janome で、類似文章の抽出。 自然言語処理(3)

index:

概要

前回の、自然言語処理の関連となります。
TF-IDF TfidfVectorizer + janome で、類似文章の抽出
してみたいと思います。

環境

python 3.5.2
janome
sklearn
numpy

コード

github.com

python3 です。

処理

・前処理、学習

# encoding: utf-8

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

from janome.tokenizer import Tokenizer

#
def get_token(text):
    t = Tokenizer()
    tokens = t.tokenize(text)
    word = ""
    for token in tokens:
        part_of_speech = token.part_of_speech.split(",")[0]
        if part_of_speech == "名詞":
            word +=token.surface + " "
        if part_of_speech == "動詞":
            word +=token.base_form+ " "
        if part_of_speech == "形容詞":
            word +=token.base_form+ " "
        if part_of_speech == "形容動詞":
            word +=token.base_form+ " "
    return word


words1="利用人数は何人ですか?"
words2="契約期間は、ありますか?"
words3="オープンソースですか?"
words4="オンライン決済は、可能ですか?"
words5="製品価格、値段はいくらですか?"

#words= get_token(words1 )
#print(words )
#quit()
words =[]
words.append(words1 )
words.append(words2 )
words.append(words3 )
words.append(words4 )
words.append(words5 )

#print(words )
tokens=[]
for item in words:
    token=get_token(item)
    tokens.append(token)
#
#print(tokens )
docs = np.array(tokens)

vectorizer = TfidfVectorizer(use_idf=True, token_pattern=u'(?u)\\b\\w+\\b')
print(tokens)
#quit()
vecs = vectorizer.fit_transform(docs )


・評価
fit_transformで、学習した結果を。
適当な、文章で cos類似度の計算
類似度の高い、文章を抽出
入力配列から、index 番号を出力
類似度の高い、文章の出力

str="利用人数は?"
#str="契約期間"
#str="価格は?"

instr = get_token(str ).strip()
print("instr=", instr )
x= vectorizer.transform( [  instr ])
#print( "x=",x)
num_sim=cosine_similarity(x , vecs)
print(num_sim )
index = np.argmax( num_sim )

print("word=", words[index])
print()

テスト

['利用 人数 何 人 ', '契約 期間 ある ', 'オープン ソース ', 'オンライン 決済 可能 ? ', '製品 価格 値段 いくら ']
instr= 利用 人数
[[ 0.70710678  0.          0.          0.          0.        ]]
word= 利用人数は何人ですか?

=> 正しく、抽出できました。
追加している。
文章の数が少ないですが、ある程度。判定処理は
正しいようです。
データセットに、応答分を追加しておくと
会話の応答出力も、出力できそうですね。