🌐

GradioのREADME

2022/07/02に公開

デモページを作るのに便利そうなGradioREADME.mdを読んでみたいと思います。
Google Colab上で、72時間限定ですが、外部URLから接続できて、便利です。
全世界に公開されてしまうのが気になりますが、ちょっとした認証(ログイン画面?)機能もあるみたいですね。


Gradio: Build Machine Learning Web Apps — in Python

GradioはオープンソースのPythonライブラリで、機械学習やデータサイエンスのデモやWebアプリケーションを構築するために使用されます。

Gradioを使用すると、機械学習モデルやデータサイエンスワークフローの周りに美しいユーザーインターフェイスをすばやく作成し、ブラウザ全体で自分の画像をドラッグアンドドロップしたり、テキストを貼り付けたり、自分の声を録音したり、デモと対話したりすることで、ユーザーが「試してみる」ことができます。

Gradioは次のような場合に便利です。

  • クライアント/コラボレーター/ユーザー/学生のための機械学習モデルのデモ
  • 自動共有可能リンクを使用してモデルを迅速にデプロイし、モデルのパフォーマンスに関するフィードバックを取得する
  • 組み込みの操作ツールと解釈ツールを使用して、開発中にモデルを対話的にデバッグする
    次の「クイックスタート」の対話型バージョンは、https://gradio.app/getting_started にあります。

クイックスタート

前提条件:GradioはPython 3.7以上が必要です。それだけです!

Gradioはどのような問題を解決していますか?😲

機械学習モデル、API、またはデータ サイエンスのワークフローを他のユーザーと共有する最善の方法の1つは、ユーザーや同僚がブラウザーでデモを試せるようにする対話型のデモを作成することです。
Webベースのデモは、ブラウザを使用できる人(技術者だけでなく)が直感的に自分の入力を試して、あなたが構築したものを理解できるので素晴らしいです。
しかし、このようなWebベースのデモの作成は、Webアプリを提供するためのWebホスティングと、デモ用のGUIを構築するためのWeb開発(HTML、CSS、JavaScript)を知る必要があるため、従来は困難でした。
Gradioでは、デモを構築して共有することができます。そして、通常はわずか数行のコードで!それでは始めましょう。

Hello, World⚡

単純な "Hello, World" の例で Gradio を実行するには、次の 3 つの手順を実行します。

  1. pipからGradioをインストールします。サポートされるPythonバージョンは、3.7以上です。
pip install gradio
  1. 以下のコードをPythonスクリプトとして、またはPythonノートブック(またはcolab notebook)で実行します。
import gradio as gr

def greet(name):
    return "Hello " + name + "!!"

demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()
  1. 以下のデモは、Pythonノートブック内に自動的に表示されるか、スクリプトから実行している場合は、http://localhost:7860 のブラウザにポップアップ表示されます。

The Interface class 🧡

デモを作成するために、クラスを定義したことがわかります。このクラスは、ほぼすべての Python関数をユーザーインターフェイスでラップできます。上記の例では、単純なテキストベースの関数を実装しました。しかし、この関数は、音楽ジェネレーターから税計算機、(最も一般的には)事前トレーニング済みの機械学習モデルの推論まで、何でもかまいません。gradio.Interfaceコアクラスは、次の3つの必須パラメーターで初期化されます。

  • fn: 処理を実装する関数
  • inputs: 入力に使用するコンポーネント(例: "text", "image", "audio")
  • outputs: 出力に使用するコンポーネント(例: "text", "image","label")
    Gradioには、20種類以上のコンポーネントが含まれており、そのほとんどは入力または出力として使用できます。(完全なリストについてはドキュメントを参照してください)

Components Attributes 💻

Interfaceに3つの引数を渡し、launch()することでUIを作成します。
しかし、UIコンポーネントの見た目や動作を変更したい場合はどうしたらよいでしょうか。

例えば、入力テキストフィールドをカスタマイズしたいとします。もっと大きくして、テキストヒントを表示させたいとします。文字列のショートカットを使う代わりに、実際の入力クラスである Textbox を使用すれば、コンポーネント属性を通じてより多くのカスタマイズを行うことができます。

import gradio as gr

def greet(name):
    return "Hello " + name + "!"

demo = gr.Interface(
    fn=greet,
    inputs=gr.Textbox(lines=2, placeholder="Name Here..."),
    outputs="text",
)

demo.launch()

Gradioがサポートするすべてのコンポーネントと、それらをカスタマイズするために使用できる属性を見るには、ドキュメントをチェックしてください。

Multiple Inputs and Outputs 🔥

もっと複雑で、複数の入力と出力を持つ関数があったとしよう。以下の例では、文字列、ブール値、数値を受け取り、文字列と数値を返す関数を定義しています。入出力コンポーネントをどのように渡しているか見てみましょう。

import gradio as gr

def greet(name, is_morning, temperature):
    salutation = "Good morning" if is_morning else "Good evening"
    greeting = "%s %s. It is %s degrees today" % (salutation, name, temperature)
    celsius = (temperature - 32) * 5 / 9
    return greeting, round(celsius, 2)

demo = gr.Interface(
    fn=greet,
    inputs=["text", "checkbox", gr.Slider(0, 100)],
    outputs=["text", "number"],
)
demo.launch()

コンポーネントをリストにするだけです。inputsの各コンポーネントは、処理を実装する関数の引数の順番に対応します。outputsの各コンポーネントは、処理を実装する関数の戻り値の順番に対応します。

Images 🎨

image to imageの処理を試してみましょう!
Imageコンポーネントを使用する場合、関数には、指定したサイズのnumpy配列(width, height, 3)を受け取ります。最後の次元がRGB値を表します。戻り値も同様に画像のnumpy配列の形で返します。

import numpy as np

import gradio as gr

def sepia(input_img):
    sepia_filter = np.array(
        [[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]
    )
    sepia_img = input_img.dot(sepia_filter.T)
    sepia_img /= sepia_img.max()
    return sepia_img

demo = gr.Interface(sepia, gr.Image(shape=(200, 200)), "image")

demo.launch()

さらに、Imageインターフェースには「編集」ボタン✏があり、画像をトリミングしたりズームしたりするためのツールを開くことができます。このように画像を操作することで、機械学習モデルの偏りや隠れた欠陥を明らかにすることができます。

画像に加えて、Gradioは、オーディオやビデオなど、他のメディアタイプもサポートしています。これらについては、ドキュメントをお読みください。

DataFrames and Graphs 📈

Gradioを使って、numpy配列、pandasデータフレーム、plotlyグラフなど、代表的なデータライブラリからの入出力をサポートすることができます。以下のデモをご覧ください(関数内の複雑なデータ操作は無視してください!)。

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np

import gradio as gr

def sales_projections(employee_data):
    sales_data = employee_data.iloc[:, 1:4].astype("int").to_numpy()
    regression_values = np.apply_along_axis(
        lambda row: np.array(np.poly1d(np.polyfit([0, 1, 2], row, 2))), 0, sales_data
    )
    projected_months = np.repeat(
        np.expand_dims(np.arange(3, 12), 0), len(sales_data), axis=0
    )
    projected_values = np.array(
        [
            month * month * regression[0] + month * regression[1] + regression[2]
            for month, regression in zip(projected_months, regression_values)
        ]
    )
    plt.plot(projected_values.T)
    plt.legend(employee_data["Name"])
    return employee_data, plt.gcf(), regression_values

demo = gr.Interface(
    sales_projections,
    gr.Dataframe(
        headers=["Name", "Jan Sales", "Feb Sales", "Mar Sales"],
        value=[["Jon", 12, 14, 18], ["Alice", 14, 17, 2], ["Sana", 8, 9.5, 12]],
    ),
    ["dataframe", "plot", "numpy"],
    description="Enter sales figures for employees to predict sales trajectory over year.",
)
demo.launch()

Example Inputs 🦮

ユーザーがinputsに読み込むことができるサンプルデータを提供することができます。これは、inputsが期待する入力値を示すだけでなく、モデルと連動してデータセットを探索することができます。サンプルデータを読み込むには、Interfaceのexamplesにネストしたリストを渡します。
サンプルデータは、各入力コンポーネントの入力値のリストをネストします。各コンポーネントのサンプルデータのフォーマットはドキュメントに記述されています。

import gradio as gr

def calculator(num1, operation, num2):
    if operation == "add":
        return num1 + num2
    elif operation == "subtract":
        return num1 - num2
    elif operation == "multiply":
        return num1 * num2
    elif operation == "divide":
        return num1 / num2

demo = gr.Interface(
    calculator,
    [gr.Number(4), gr.Radio(["add", "subtract", "multiply", "divide"]), "number"],
    "number",
    examples=[
        [5, "add", 3],
        [4, "divide", 2],
        [-4, "multiply", 2.5],
        [0, "subtract", 1.2],
    ],
    title="test calculator",
    description="heres a sample toy calculator. enjoy!",
)

demo.launch()

サンプルデータが多い場合、自動的にページ分割されます。(Interfaceのexamples_per_page引数で設定可能です。)

Live Interfaces 🪁

Interfaceにlive=Trueを設定することで、入力値が変更されると自動的に再計算されます。

import gradio as gr

def calculator(num1, operation, num2):
    if operation == "add":
        return num1 + num2
    elif operation == "subtract":
        return num1 - num2
    elif operation == "multiply":
        return num1 * num2
    elif operation == "divide":
        return num1 / num2

demo = gr.Interface(
    calculator,
    ["number", gr.Radio(["add", "subtract", "multiply", "divide"]), "number"],
    "number",
    live=True,
)

demo.launch()

変更時に自動的に再送信されるため、送信ボタンがないことに注意してください。

Flagging 🚩

出力インターフェースの下に、"Flag"ボタンがあります。テストしているユーザーが、誤った、あるいは予期せぬ動作の出力をする入力値に、インターフェース作成者が確認するために、その入力にフラグを立てることができます。Interfaceのflagging_dir=引数で指定されたフォルダに、フラグを立てた入力をCSVファイルに出力されます。画像や音声などのデータを含むInterfaceの場合、フラグを立てたデータを保存するフォルダも作成されます。
例えば、上記の電卓のインターフェースでは、以下のようなフォルダにフラグを立てたデータが格納されることになります。

+-- calculator.py
+-- flagged/
|   +-- logs.csv

flagged/logs.csv

num1,operation,num2,Output
5,add,7,12
6,subtract,1.5,4.5

上記のimage to imageでは、以下のようなフォルダにフラグを立てたデータが格納されることになります。

+-- sepia.py
+-- flagged/
|   +-- logs.csv
|   +-- im/
|   |   +-- 0.png
|   |   +-- 1.png
|   +-- Output/
|   |   +-- 0.png
|   |   +-- 1.png

flagged/logs.csv

im,Output
im/0.png,Output/0.png
im/1.png,Output/1.png

フラグを立てたフォルダから入力値を確認したり、フラグを立てたフォルダをexamples=引数に指定することにより、サンプルデータに表示することができます。[1]
もしユーザーにフラグを立てる理由を望むのであれば、Interfaceのflagging_options引数に文字列のリストを渡すことができます。ユーザーはフラグを立てる際に、文字列のうちの1つを選択する必要があり、それはCSVに追加のカラムとして保存されます。[2]

Blocks: More Flexibility and Control 🧱

(1)Interfaceは、これまで説明してきたデモを作成するための高レベルの抽象化であり、(2)Blocksは、Webアプリで自由なレイアウトとデータフローを設計するための低レベルのAPIです。Blocksでは、関連するデモのグループ化、ページ上のコンポーネントの表示位置の変更、複雑なデータフローの処理(例えば、出力が他の関数への入力として機能する)、ユーザの入力に基づくコンポーネントのプロパティや可視性の更新といったことが可能です。すべてPythonで実現できます。

例えば、Blocksでは、Pythonのwithステートメントをネストして、以下のようにページ上にコンポーネントをレイアウトしています。

import numpy as np
import gradio as gr

demo = gr.Blocks()

def flip_text(x):
    return x[::-1]

def flip_image(x):
    return np.fliplr(x)

with demo:
    gr.Markdown("Flip text or image files using this demo.")
    with gr.Tabs():
        with gr.TabItem("Flip Text"):
            text_input = gr.Textbox()
            text_output = gr.Textbox()
            text_button = gr.Button("Flip")
        with gr.TabItem("Flip Image"):
            with gr.Row():
                image_input = gr.Image()
                image_output = gr.Image()
            image_button = gr.Button("Flip")
    
    text_button.click(flip_text, inputs=text_input, outputs=text_output)
    image_button.click(flip_image, inputs=image_input, outputs=image_output)
    
demo.launch()

Blocksの詳細は、ドキュメントをお読みください。

Sharing Demos 🌎

Gradioのデモは、launch()メソッドでshare=Trueを設定することで、簡単に公開することができます。

gr.Interface(classify_image, "image", "label").launch(share=True)

これは公開された共有可能なリンクを生成し、誰にでも送ることができます。このリンクを共有すると、ユーザーは自身のブラウザでデモを試すことができます。処理はあなたのデバイスで行われるので(あなたのデバイスがオンである限り!)、パッケージングや依存関係について心配する必要はありません。共有リンクは通常、次のようなものです。XXXXX.gradio.app。リンクはGradioのURLを通じて提供されますが、私たちはあなたのローカルサーバーのプロキシであり、インターフェイスを介して送信されたデータを保存しません。

しかし、これらのリンクは一般にアクセス可能であり、誰もがあなたのデモを利用できることに留意してください!。あなたが書いた関数を通じて機密情報を公開したり、あなたのデバイスで重要な変更が行われないように注意してください。share=False(デフォルト、colab notebooksを除く)にすると、ローカルリンクのみが作成され、特定のユーザーとポートフォワーディングで共有することができるようになります。

共有リンクは72時間後に失効します。永続的なホスティングについては、次のセクションを参照してください。

Hosting Gradio Demo on Spaces 🤗

もしあなたがインターネット上であなたのGradioデモへの永久的なリンクを持ちたいなら、Huggingface Spacesを使用してください。Hugging Face Spacesは、あなたの機械学習モデルを永久にホストするためのインフラを無料で提供します。
あなたのGradioモデルとすべての関連ファイルを含むフォルダをドラッグ&ドロップするか、SpacesをあなたのGitリポジトリに向けると、SpacesはそこからGradioのインターフェースを取得することができます。詳しくはHuggingface Spacesをご覧ください。

Next Steps

Gradioの基本を理解したところで、次のステップを紹介します。

  • 無料のGradioコースで、Gradioに関連するすべてのステップバイステップで、あなた自身の機械学習デモを構築する方法をチェックしてください 📖
  • Gradioは、ユーザーに2つのAPIを提供しています。Interfaceはデモを素早く作成するための高レベルの抽象化であり、Blocksはより制御されたレイアウトとデータフローでWebアプリを設計するための、より自由なAPIです。Blocksについて詳しくはこちら🧱をご覧ください
  • Interfaceに、より高度な機能(認証、解釈、状態など)をデモに追加したい場合は、Interfaceクラスの高度な機能に関するガイドを参照してください 💪
  • 他の人がGradioでどんなデモを作ったか調べたり、基礎となるPythonのコードを見たいだけなら、公開されているHugging Face Spacesを見て、インスピレーションを得てください🤗
脚注
  1. サンプルデータに表示はされるのですが、シングルクォートに囲まれていて入力値そのままではなく使いづらそうです。 ↩︎

  2. サンプルデータには理由が表示されないので、CSVファイルを確認する必要がありそうです。 ↩︎

Discussion