こんにちは、技術開発ユニットの三浦です。
3月に入り、だいぶ暖かくなり、風も柔らかく感じるようになりました。近所にある小さな梅の木に、緑色をした小鳥が何羽かとまっていました。「ウグイスだなぁ・・・」としみじみ眺めていたのですが、あとで調べたらその小鳥はウグイスではなく「メジロ」という鳥でした。メジロの方が、自分にとっての「ウグイス色」に近い色をしていることが分かりました。
さて、私には気になったネタをあとで調べようと残しておくメモがあるのですが、今日はその中から1つ、気になっていた「Gradio」というPythonのライブラリを取り上げてみたいと思います。
このライブラリを使えば、自分で作った機械学習のモデルを組み込んだ簡単なアプリをあっという間に作れてしまいます。
Gradioについて
Gradioは機械学習(ML)のモデルを利用するアプリを簡単に作成することができるライブラリです。
私たちの業務の中で、サービスやシステムに搭載するMLモデルを構築することがあります。
その場合、まず利用可能なデータを使ってモデルの学習と検証を行い、精度による評価基準をパスしたり、あるいは定められた期間が過ぎると今度はモデルをテストするフェーズに移ります。
テストフェーズではサービスやシステムで実際に扱われる、あるいはそれに限りなく近いデータを使って、その利用ユーザーにモデルの性能を評価して頂きます。ここでの評価指標は状況に応じて変わります。
そして評価してみると、モデルが上手く判断できないデータが見つかることがあります。それらのデータを見て、モデルの改善のために必要な方針などを検討し、再度モデルを作り、テストフェーズに移る・・・といったことを繰り返していきます。
テストの際には簡単な画面(UI)を用意して、モデルを利用できるようにすることが多いです。また、ちょっとしたデモで技術のプレゼンをする際も、UIがあった方が内容が断然分かりやすくなります。
しかし、機械学習とUI開発を両方こなそうとするとけっこうな負担になります。普段UI開発を専門にしていない機械学習寄りの人が、簡単にUIを用意できる仕組みがあるといいのにな・・・と思っていました。
Gradioを使うと、Pythonだけで簡単にMLモデルを試せるアプリを作ることが出来ます。今回実際にいくつか作ってみましたのでご紹介します。
手書き数字認識アプリ
まずはこちらをご覧ください。
左のスケッチに書いた数字を判定するアプリです。手書き数字画像データ「MNIST」を使って学習したモデルがアプリの裏側で動いています。
このアプリ、UIはGradioを使って以下のような非常にシンプルなコードで実装しています。
import gradio as gr gr.Interface(fn=number_recognision, inputs="sketchpad", outputs="label", ).launch()
inputs="sketchpad"
でアプリの入力、outputs="label"
で出力を決めています。入力と出力の間の処理はfn=number_recognision
で指定しているnumber_recognisioin
関数で実装しています。
number_recognision
は以下のようになっています。
import tensorflow as tf #model = ...... #tensorflow.kerasのモデル def number_recognision(img): img = img[tf.newaxis,...,tf.newaxis] pred = model.predict(img / 255.0)[0] values, indices = tf.math.top_k(pred, k=3) values = values.numpy().tolist() indices = indices.numpy().tolist() confidences = {str(i): v for i, v in zip(indices, values)} return confidences
model
はあらかじめ学習済みのtensorflow.keras
のモデルです。このモデルが出力する予測スコアの上位3つのラベルとスコアを辞書型で返します。この関数の結果を受け取って、Gradioは出力コンポーネント"label"
に結果を反映します。
アプリのUIには、デフォルトで「Flag」というボタンが表示されています。このボタンをクリックすると、今表示されている画像をファイルとして保存することが出来ます。例えば上手くモデルが認識出来なかった画像を残しておき、後で確認したい時に使えます。
また、もう少し細かく画像を分けることも出来ます。Interfaceの生成時にオプションflagging_options
に分類用のラベルリストを指定します。すると、「Flag」クリック時に分類用のラベルを指定することが出来るようになります。
以下のように指定します。
gr.Interface(fn=number_recognision, inputs="sketchpad", outputs="label", flagging_options=['合ってる','間違ってる'] ).launch()
画像と一緒にCSV形式のログファイルも出力されており、そちらにどの画像にどのラベルが付けられたのかが記録されます。
Gradioには様々なinputs
/outputs
用のコンポーネントが用意されています。他にも見ていきましょう。
学習済みモデル評価用アプリ
次に、画像処理の学習済みモデル自体の予測性能を比較することが出来るアプリを作ってみました。
画像を選び、性能を見たいモデルをラジオボタンで選択するとそのモデルのImageNetデータセットラベルの予測結果を見ることが出来ます。
Examplesに表示された画像リストから選んでもいいし、好きな画像を使って予測結果を見ることも出来ます。
どの学習済みモデルをベースモデルに利用したらよいか、見極めるのに便利かな・・・と思いました。
以下、コードになります。
from tensorflow.keras.applications import mobilenet, resnet50, efficientnet import gradio as gr import requests #評価するモデルの読み込みと前処理の紐づけ models = { 'MobileNet':{ 'model':mobilenet.MobileNet( weights='imagenet' ), 'preprocess':mobilenet.preprocess_input }, 'ResNet50':{ 'model':resnet50.ResNet50( weights='imagenet' ), 'preprocess':resnet50.preprocess_input }, 'EfficientNetB0':{ 'model':efficientnet.EfficientNetB0( weights='imagenet' ), 'preprocess':efficientnet.preprocess_input } } #ImageNetのラベルデータの取得 response = requests.get("https://git.io/JJkYN") labels = response.text.split("\n") #input画像を指定のモデルで推論する def classify_image(image, model_label): image = image.reshape((-1, 224, 224, 3)) preprocess = models[model_label]['preprocess'] model = models[model_label]['model'] prediction = model.predict(preprocess(image))[0] values, indices = tf.math.top_k(prediction, k=5) values = values.numpy().tolist() indices = indices.numpy().tolist() confidences = {labels[i]: v for i, v in zip(indices, values)} return confidences #Radioボタンに表示するモデル名リスト model_labels = list(models.keys()) gr.Interface( classify_image, [ gr.inputs.Image(shape=(224, 224)), gr.inputs.Radio(model_labels, type='value', label='BASE MODEL') ], 'label', #サンプル画像 examples=[ ['image/sample1.jpg'], ['image/sample2.jpg'], ['image/sample3.jpg'], ] ).launch()
inputs
はImageとRadioボタンの2つのコンポーネントで構成されています。それらをリストで指定しています。examples=
オプションでサンプルの画像パスを指定します。
Chatbot風テキスト生成アプリ
これまで画像を扱うアプリを見てきましたが、Gradioでは自然言語を扱うアプリを作ることも出来ます。以前の記事でTransformersを使ってみた際に試してみたテキスト生成モデルを、Chatbot風に試すことが出来るアプリを作ってみました。
「Transformers」を使ってみた記事はこちらです。 techblog.cccmk.co.jp
使用したモデルは以前と同様、rinna株式会社様が公開している「rinna/japanese-gpt2-medium」というモデルです。
このようなアプリが出来ました。
左のテキストボックスにテキストを入力して「Submit」すると、それに続く文章が生成され、右側にChat風に表示されていきます。
コードは以下のようになります。
import gradio as gr from transformers import T5Tokenizer, AutoModelForCausalLM model_name = 'rinna/japanese-gpt2-medium' tokenizer = T5Tokenizer.from_pretrained(model_name) tokenizer.do_lower_case = True # due to some bug of tokenizer config loading model = AutoModelForCausalLM.from_pretrained(model_name) def text_generator(text, history): history = history or [] input_data = tokenizer(text, padding=True, return_tensors='pt') prediction = model.generate(**input_data, pad_token_id=tokenizer.eos_token_id, do_sample=True, max_length=30, top_k=50, top_p=0.95, num_return_sequences=1 ) response = tokenizer.decode(prediction[0]) #responseに含まれるインプットテキストを除外する response = response[len(text + '</s> '):] history.append((text,response)) return history, history gr.Interface(fn=text_generator, inputs=['text','state'], outputs=['chatbot','state'], allow_flagging='never' ).launch()
inputs
とoutputs
に'state'
というコンポーネントを指定しています。これはセッション内でデータを保存し続けるための仕組みで、chatbotのこれまでの会話が保存されます。
アプリを共有するには
このように、Gradioを使うと面白いアプリが簡単に作れて楽しいです。
作ったアプリを他のデバイスから利用することも出来ます。いくつか方法はありますが、1つはGradioのInterfaceがlaunch()
メソッドを呼び出すときにオプションshare=True
を指定すると発行される、共有リンクからアクセスする方法です。
仕組みとしてはGradioのサーバ経由でGradioのアプリが動いているデバイスにインターネット経由でアクセスするようです。Google Colaboratoryで実行すると、自動的に共有リンクが生成されます。共有リンクの有効期限は72時間です。
ただしこの共有リンクはインターネットのどこからでもアクセスすることが出来るため、使用する際には十分に注意する必要があります。できる限りデフォルトのshare=False
の設定で使ったほうが良いと思います。
その場合はローカルの環境でport-forwardingを使って別のデバイスから利用することが出来ます。
ちなみに「Flag」ボタンをクリックするとGradioアプリが稼働しているデバイス側にデータが保存されます。
まとめ
ということで、今回はMLモデルを試すアプリをGradioというライブラリを使って作ってみました。色々と活用出来るシーンは多いと思います。モデルを利用するだけでなく、画像の前処理をどうしようか、といったことを検討する段階でも使えそうです。たとえば色々なデータオーギュメンテーションの結果を比較してどれを使うかを決める・・・といった使い方です。
Gradioのように、便利なライブラリがたくさん公開されています。どういった動作をするのかをしっかりと調べたうえで、上手に付き合っていきたいなと思います。