画像生成で有名なStable Diffusionや、音声合成で注目される RVC などのAIツールでよく使われているのが gradio と呼ばれるPythonライブラリです。
gradio にはUI用のパーツが豊富に揃っており、これを使うとAIやデータ分析向けの複雑なWeb UIが簡単に作れてしまいます。
とはいうものの、全くのゼロの知識で公式サイトを見ても、gradioの思想やUIパーツごとの振る舞いを理解するには時間が掛ることも事実です。
そこで、今回は gradio で Web UI を作る場合の基本的な考え方や、よく使いそうなパーツの挙動につて、それぞれ画面のスクリーンショットとサンプルソースコードを交えて解説したいと思います。
gradio で作れるWeb UIの例
gradio を使うと、下記のような画面がサクッと作れます。
gradio とは
gradio は、ブラウザで動作する機械学習のデモ画面を、サクッと作ることを目的としたPython用のWeb UI ライブラリです。
画像生成AIで有名なStable Diffusionや、音声合成で脚光を浴びているRVC などに利用されています。
Interface と呼ばれるメソッドに、「やりたい処理を記述した関数」、「入力に使うUIパーツ」、「結果の出力に使うUIパーツ」の3点を指定するだけで、Web UI 画面が作成できるという手軽さが特徴です。
その反面、他のWeb UI用ライブラリと比べてデザイン性は乏しいため、標準のUIパーツのデザインが気に入らないからと、独自のデザインにカスタマイズしたり、標準には無い動作をさせるなど、凝った画面を作るには向いていません。
なお、gradio は機械学習のデモを得意とはしていますが、ファイルの変換や加工などのツール類を作る場合など、機械学習以外の用途でも効力を発揮します。
gradio には数多くの便利なUIパーツや機能が用意されています。
本サイトの記事で全てを説明するのは不可能なので、本サイトの記事に一通り目を通した後で、必要な情報を gradio 公式サイト から入手して下さい。
gradio のインストール方法
gradio のインストールは、Pythonの実行環境で以下の1行を実行するだけです。
1 |
pip install gradio |
実行時に gradio を使うには 以下のインポート文をプログラム先頭に記述しておいて下さい。
1 |
import gradio as gr |
Web UIの起動方法
今回のサンプルソースは Visual Studio Code で動作確認を行っています。ソースコードを実行するとコンソール画面に以下の文言が表示されます。
Running on local URL: http://127.0.0.1:7860
この状態でブラウザのアドレス欄に http://127.0.0.1:7860 を入力して頂ければ、ブラウザ上にWeb UIが表示されます。
尚、ローカル上で他のWeb UIアプリを動作させていた場合、ポートが競合すると 7860 が 7861 や 7862 に変わることがあるので、ご注意ください。
Web UI を作るための3つのステップ
gradio でWeb UIを作るには、次の3つの処理を記述します。
コールバック関数では、画面レイアウトでボタンが押された時に呼び出したい関数を記述します。
画面レイアウトの作成では、画面に表示したいUIパーツと、ボタンなどが押された時のアクション(呼ぶ出したいコールバック関数の名前)を記述します。
Web UIの起動は、launch() メソッドを呼ぶだけなのですが、これを行うことで簡易的なWebサーバが起動し、ブラウザ上でWeb UIが表示できるようになります。
先ほど、launch() メソッドを呼んだあとで、ブラウザのアドレス欄に http://127.0.0.1:7860 を入力すれば、作成した Web UI が表示されると申しましたが、inborwser 引数に True を指定することで、強制的にブラウザに Web UI を表示することが可能です。
webui.launch(inbrowser=True)
gradio の基本構成
先ほど説明した3つのステップに従ってプログラムを書くと以下の様になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import gradio as gr # コールバック関数の定義 def my_func(my_name, is_disp, my_value): return f"### {my_name} ###", my_value * 100 #画面レイアウトの定義(Interfaceを使用) demo = gr.Interface( fn=my_func, inputs=["text", "checkbox", gr.Slider(0, 100)], outputs=["text", "number"] ) # Web UIの起動 demo.launch(inbrowser=True) |
gr.Intaerace) メソッドの inputs 引数に、入力として使いたいUIパーツを列挙し、outputs 引数には、出力として使いたいUIパーツを列挙します。
動作が単純なUIパーツであれば、"text"や"checkbox" などの様に簡易的に記述すれば良いのですが、スライダーなどのように複数のパラメータが必要なUIパーツや、自分でサイズやラベルを指定したい場合は、gradio のメソッド使ってインスタンスを生成する必要があります。
inputs/outputs とUIパーツの関係
inputs と outputs はそれぞれ入力用、出力用のUIパーツを列挙することは説明しましたが、列挙の順番により、上から下へパーツが配置されます。
また、inputs は左側、outputs は右側に表示されます。
このように、パターン化されているため、細かなレイアウトを考える必要が無い分、サクッと簡単に画面レイアウトが作成できる点が強みです。
inputs には「クリアボタン」と「送信」ボタンが、outputs には「フラグする」ボタンが表示されています。
これらは自動で生成されるボタンで、「クリア」はinputs に指定した入力用UIパーツを一括クリアし、「送信」ボタンはUIパーツの値を引数としてコールバック関数を呼び出す動作をします。
「フラグする」は日本人にとって馴染みが無いキーワードですが、これを押すと入力欄の値をローカルのファイルに保存してくれます。
「フラグする」は非常時にすることも可能で、gr.Interface() の allow_flagging 引数に 'never' を指定するだけです。
1 2 3 4 5 6 7 |
#画面レイアウトの定義(Interfaceを使用) demo = gr.Interface( fn=my_func, inputs=["text", "checkbox", gr.Slider(0, 100)], outputs=["text", "number"], allow_flagging='never' ) |
inputs とコールバック関数の引数の関係
inputs に記述したUIパーツは上から順番に画面に表示されますが、コールバック関数には左から右の順で入力値が引き渡されます。
今回は "text","checkbox",gr.Slider(0,100) の3パーツを記述しましたので、my_func が呼び出される際は、 "text"⇒my_name、"checkbox"⇒is_disp、gr.Slider(0,100) ⇒ my_value に値が渡されることになります。
コールバック関数と outputs の関係
コールバック関数の戻り値は、左から右の順に記述した値が、outputs で列挙したUIパーツの上から下への順で反映されます。
今回の場合は '###123###' が output0 に、0が output1 に反映されます。
コールバック関数の引数と inputs のラベルの関係
面白いことに、コールバック関数の引数に記述した引数名が、自動的に inputs で指定したUIパーツのラベルに表示されます。
つまり、英語の表記で良いのであれば、UIパーツのラベルを別途指定する必要が無いのです。
実用的なレイアウトのサンプル
ここでは、よく使われるパーツを組み合わせて、もう少し複雑な画面の作成方法について解説します。
UIパーツにラベルやサイズ、プレイスフォルダーを表示する(単一パーツ)
UIパーツごとに、項目名やプレイスフォルダー(入力欄が未入力状態の時に表示される薄いグレーの文言)を表示したり、入力エリアのサイズを指定する場合、gradio の UIパーツのインスタンスを生成する必要があります。
下記は、入力用のテキストボックスと出力用のラベルに項目名と行幅を設定するサンプルです。
入力、出力ともUIパーツが1つの場合、inputs,outputsにリストで渡す必要はありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import gradio as gr # コールバック関数の定義 def callback_func(inp): return str(int(inp) * int(inp)) # 画面レイアウトの定義 app = gr.Interface( title="計算機", fn=callback_func, inputs=gr.Textbox(label="入力欄",lines=3, placeholder="ここに数値を入れてください..."), outputs=gr.Label(label="計算結果",lines=3) ) # Web UIの起動 app.launch(inbrowser=True) |
UIパーツにラベルやサイズ、プレイスフォルダーを表示する(複数パーツ)
inputs,outputs それぞれに複数のUIパーツを指定する場合は、リスト形式で渡します。また、コールバック関数の引数は inputs で指定したUIパーツの個数分が受け取れるように、またreturn の戻り値は outputs で指定したUIパースの個数分が戻せるようにしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import gradio as gr # コールバック関数の定義 def callback_func(val1,val2,val3): return str(int(val1) * int(val2)), f"気温は {val3} 度です" # 画面レイアウトの定義(Interfaceを使用) app = gr.Interface( title="計算機", fn=callback_func, inputs=[ gr.Textbox(label="入力欄1",lines=3, placeholder="ここに数値を入れてください..."), gr.Textbox(label="入力欄2",lines=5, placeholder="ここに数値を入れてください..."), gr.Slider(label="温度",minimum=0,maximum=100,step=1) ], outputs=[ gr.Label(label="計算結果1",lines=3), gr.Textbox(label="計算結果2",lines=3) ] ) # Web UIの起動 app.launch(inbrowser=True) |
DataFrameを使った一覧表示
テーブル形式の一覧データを画面に表示するには、gr.DataFrame() というUIパーツを利用します。gr.DataFrame() は inputs で使う場合と outputs で使う場合では少々挙動が異なります。
inputs で使う場合は、空の状態から行や列を増やしながら入力したり、値を変更することが可能です。一方outputs で使う場合は、編集機能は無く表示だけになります。
下記のサンプルでは、inputs で指定した gr.DataFrame() の入力値をコールバック関数の第3引数(val3)で受け取り、retrun の第3戻り値(val3 * 3)で返しています。
これにより、全てのセルが3倍(実際には値が3個横並びする)された結果が、outputs で指定された gr.DataFrame() に渡され、画面に表示されることになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import gradio as gr # コールバック関数の定義 def callback_func(val1,val2,val3): return f"値は{val1}です", f"曲線カーブは {val2} 度です",val3 * 3 # 画面レイアウトの定義(Interfaceを使用) app = gr.Interface( title="シミュレーション", fn=callback_func, inputs=[ gr.Textbox(label="入力欄1",lines=3, placeholder="ここに数値を入れてください..."), gr.Dropdown(["曲線A","曲線B","曲線C"],label='入力欄2',lines=5, placeholder="曲線タイプを選択して下さい..."), gr.DataFrame(label="利用者",headers=["氏名", "年齢", "性別"],datatype=["str", "number", "str"],row_count=5) ], outputs=[ gr.Label(label="計算結果1",lines=3), gr.Textbox(label="計算結果2",lines=3), gr.DataFrame(headers=["氏名", "年齢", "性別"],label="利用者") ] ) # Web UIの起動 app.launch(inbrowser=True) |
Bloclsを使った画面レイアウト
ここまでの説明で登場した gr.Interface() とは別に、gr.Blocks() を使って画面レイアウトを作成することも可能です。
gr.Interface()との違いは、複数のUIパーツを1つのパーツとしてまとめることが出来るという点です。
with gr.Blocks() as app : に続けて列挙したUIパーツは、すべてそのブロックに所属することになります。
ブロックの中にはボタンを含ませることができ、ボタン毎にコールバック関数を定義することが可能です。
これを使うと、gr.Interface()よりも複雑はUIを実現することが出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import gradio as gr # コールバック関数の定義 def callback_func(val1,val2): return str(int(val1) * int(val2)) # 画面レイアウトの定義(Blocksを使用) with gr.Blocks() as app: param1 = gr.Textbox(label="パラメータ1") param2 = gr.Textbox(label="パラメータ2") result = gr.Textbox(label="計算結果") greet_btn = gr.Button("実行") greet_btn.click(fn=callback_func, inputs=[param1,param2],outputs=result, api_name="各種設定") # Web UIの起動 app.launch(inbrowser=True) |
gr.Button() はclick メソッドに コールバック関数、inputs、outputs を指定することが可能で、構造的には gr.Interface() と同じです。
見方を変えると、gr.Blocsk()を簡単にしたのがgr.Interface() と考えられます。
Tabを使った画面レイアウト
gr.Blocks() の中にTabを含めることも可能です。with gr.Tab("タブ名") : に続けて列挙したUIパーツは、このTabに所属します。
下記のサンプルでは、複数のTab内でボタンを配置し、exec_btnという同じ名前の変数に格納していますが、それぞれ別のTabに所属しているため、区別されて実行されます(名前が競合して悪さすることはありません)。
gr.Row() が新しく登場しましたが、これを使うとUIパーツを横並びさせることが出来ます。今回は画像のUIパーツを横並びにしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import gradio as gr # コールバック関数の定義(パラメータ計算タブ用) def save_func(val1,val2): return str(int(val1) * int(val2)) # コールバック関数の定義(画像処理タブ用) def synthesis_func(val1,val2): return val1 + val2 # 画面レイアウトの定義(BlocksとTabを使用) with gr.Blocks() as app: gr.Markdown("パラメータ計算と画像処理") with gr.Tab("パラメータ計算"): param1 = gr.Textbox(label="パラメータ1") param2 = gr.Textbox(label="パラメータ2") result_param = gr.Textbox(label="計算結果") exec_btn = gr.Button("計算の実行") exec_btn.click(fn=save_func, inputs=[param1,param2],outputs=result_param, api_name="計算処理") with gr.Tab("画像処理"): with gr.Row(): image1 = gr.Image() image2 = gr.Image() result_img = gr.Image(height=400) exec_btn = gr.Button("合成") exec_btn.click(fn=synthesis_func, inputs=[image1,image2],outputs=result_img, api_name="合成処理") # Web UIの起動 app.launch(inbrowser=True) |
実際に実行した結果は次の様になります。
Blocks内でのDataFrame
gr.Blocks() 内で gr.DataFrame() を使う場合も、ボタンの click メソッドの inputs やoutputs に指定します。
今回の例では、outputs に gr.DataFrame() を指定し、コールバック関数内で pandas の DataFrame を return で返しています。
こうすることによって、gr.DataFrame() に pandas の DataFrame に格納された値は表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import gradio as gr import pandas as pd # コールバック関数の定義 def callback_func(val1,val2): # PandasのサンプルデータをDataFrameに格納 df =pd.util.testing.makeTimeDataFrame(5) return df # 画面レイアウトの定義(Blocksを使用) with gr.Blocks() as app: gr.Markdown("整備記録") address = gr.Textbox(label="住所") select = gr.CheckboxGroup(["トヨタ", "ホンダ", "日産"],label='選択',info="メーカーを選択して下さい。") model = gr.Dropdown(["アルファード","プリウス","クラウン","ステップワゴン"],label="車種") radio = gr.Radio(["東京", "大阪", "京都"], label="都道府県", info="都道府県を選択して下さい。") table = gr.Dataframe(headers=["A","B","C","D"],row_count=5) exec_btn = gr.Button("計算の実行") exec_btn.click(fn=callback_func, inputs=[address,select],outputs=table, api_name="検索結果") app.launch(inbrowser=True) |
実行した結果、以下のように表示されました。gr.DataFrame() の headers 引数にカラム名を記述しても、pandas DataFrame の カラム名が表示されますのでご注意ください。
まとめ
今回は、ブラウザで機械学習のデモを行う場合に最適な gradio ライブラリについて、インストール方法と使い方について、サンプルと図を交えて詳しく解説しました。
ある程度型にはまったUIであれば簡単に作成可能な反面、凝ったレイアウトのWeb UI を作ることには向いていません。
そこを割り切って使うことが出来れば、非常に生産性良く Web UI が開発できると思います。
この記事で gradio に興味を持たれた方は、是非一度お試しください。
コメント