見出し画像

gradio 入門 (4) - 主な機能

「gradio」の主な機能をまとめました。

前回

1. サンプルデータ

「gradio」は、インターフェイスに簡単にロードできるサンプルデータを提供できます。 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":
        if num2 == 0:
            raise gr.Error("Cannot divide by zero!")
        return num1 / num2

# Interfaceの作成
demo = gr.Interface(
    calculator,
    [
        "number",
        gr.Radio(["add", "subtract", "multiply", "divide"]),
        "number"
    ],
    "number",

    # Examples
    examples=[
        [5, "add", 3],
        [4, "divide", 2],
        [-4, "multiply", 2.5],
        [0, "subtract", 1.2],
    ],

    title="Toy Calculator",
    description="Here's a sample toy calculator. Allows you to calculate things like $2+2=4$",
)

# 起動
demo.launch()

詳しくは「More On Examples」を参照。

2. エラー

「gradio」は、カスタムエラーメッセージをユーザーに表示することができます。gr.Error("custom message") でエラーメッセージを表示できます。
詳しくは、「ドキュメント」を参照。

3. 説明的なコンテンツ

Interfaceのコンストラクタには、このコンテンツの移動先を指定する3つの引数があります。

・title : Interfaceの最上部に表示するタイトル (text)
・description : タイトルの直下に表示する説明。 (text / markdown / html)
・article : Interfaceの最下部に表示する記事 (text / markdown / html)

Blocks を使用している場合は、gr.Markdown() または gr.HTML() で、どこにでも挿入できます。

label はコンポーネントの上部に表示するテキストで、すべてのコンポーネントに存在します。info は Textbox や Radio などのフォーム要素の詳細情報を表示します。

gr.Number(label='Age', info='In years, must be greater than 0')

4. フラグ

デフォルトでは、Interfaceには「フラグ」ボタンがあります。 Interfaceをテストしているユーザーが、モデルの誤った動作や予期せぬ動作など、興味深い出力を伴う入力を確認した場合、その入力にフラグを立てて確認できるようにすることができます。 Interface コンストラクタの flagging_dir 引数によって指定するディレクトリ内で、CSV ファイルにフラグ付き入力が記録されます。Interfaceに画像コンポーネントやオーディオコンポーネントなどのファイルデータが含まれる場合、それらのフラグ付きデータも保存するフォルダが作成されます。

たとえば、上記の電卓Interfaceでは、次のようなデータが保存されます。

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

・flagged/logs.csv

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

5. 前処理と後処理

「gradio」には、画像、音声、ビデオなど、さまざまな種類のデータを処理できるコンポーネントが含まれています。ほとんどのコンポーネントは入力または出力の両方として使用できます。

コンポーネントが入力として使用されるとき、「gradio」は自動的に、ユーザーのブラウザから送信されたデータ型(Webカメラのスナップショットのbase64表現など)から、関数が受け入れることができる形式(numpy配列など)に変換するために必要な前処理を行います。

同様に、コンポーネントが出力として使用される場合、「gradio」は、関数から返されるデータ(画像パスのリストなど)から、ユーザーのブラウザに表示できる形式(base64形式の画像のギャラリーなど)に変換するために必要な後処理を行います。

画像コンポーネントを構築するときにパラメータを使用して前処理を制御できます。

次の例では、画像は元のサイズに関係なく、 PILに変換され、(100, 100) にリシェイプされます。

img = gr.Image(shape=(100, 100), type="pil")

次の例では、画像の元のサイズを維持しますが、numpy 配列に変換する前に色を反転します。

img = gr.Image(invert_colors=True, type="numpy")

詳しくは、ドキュメント を参照。

6. スタイリング

「gradio」のテーマは、アプリの外観と操作性をカスタマイズする最も簡単な方法です。様々なテーマから選択することも、独自のテーマを作成することもできます。 これを行うには、theme= kwarg をInterfaceのコンストラクターで theme を指定します。

demo = gr.Interface(..., theme=gr.themes.Monochrome())

「gradio」 には、事前構築済みテーマセット (gr.themes.*) が付属しています。これらのテーマを拡張することも、最初から作成することもできます。
詳しくは、「テーマ設定ガイド」を参照。

スタイル機能を追加するには、css を使用して任意のCSSをアプリに渡します。「gradio」の基本クラスは gradio-container なので、背景色を変更するには、次のように記述します。

with gr.Interface(css=".gradio-container {background-color: red}") as demo:

一部のコンポーネントは、style() でスタイル設定できます。

img = gr.Image("lion.jpg").style(height='24', rounded=False)

詳しくはドキュメントを参照。

7. キュー

InterfaceとBlocksのqueue()を呼ぶことで、呼び出しをキューで管理することができます。これによって、一度に一定数の要求のみが処理されます。アプリで大量のトラフィックが予想される場合や、ネットワークタイムアウト(1分以上の関数処理)の防止に利用できます。

・Interface

demo = gr.Interface(...).queue()
demo.launch()

・Blocks

with gr.Blocks() as demo:
    #...
demo.queue()
demo.launch()

一度に処理されるリクエストの数は次のように指定できます。

demo.queue(concurrency_count=3)

詳しくは、ドキュメントを参照。

ブロックでのキューイングに特定の関数のみを指定するには「queue=True」を使います。

with gr.Blocks() as demo2:
    num1 = gr.Number()
    num2 = gr.Number()
    output = gr.Number()
    gr.Button("Add").click(
        lambda a, b: a + b, [num1, num2], output)
    gr.Button("Multiply").click(
        lambda a, b: a * b, [num1, num2], output, queue=True)
demo2.launch()

8. イテレーティブ出力

単一の出力を一度に表示するのではなく、一連の出力をストリーミングしたい場合があります。最終画像に至るまでの各ステップで生成される画像を表示する画像生成モデルや、1 単語ずつストリーミングするチャットボットなどがあります。

このような場合、通常の関数の代わりに generator を指定します。generator は、関数は単一の戻り値ではなく、一連の値を生成する必要があります。 通常、yield は何らかのループ内に置かれます。

以下は、指定された数値までカウントする generator の例です。

def my_generator(x):
    for i in range(x):
        yield i

generatorの呼び出し例は、次のとおりです。

    gen = my_generator(2)

    str = next(gen)
    print(str)

    str = next(gen)
    print(str)

    str = next(gen)
    print(str)
0
1
Traceback (most recent call last):
  File "XXX"
    str = next(gen)
StopIteration


以下は、画像出力の前にいくつかのノイズを出力する (偽の) 画像生成モデルの例です。「gradio」に generator を提供するには、基になるInterfaceまたはBlocksでqueueを有効にする必要があります。

import time

import gradio as gr
import numpy as np

# 画像を返す前にgeneratorを {steps} 回返すコア fn を定義
def fake_diffusion(steps):
    for _ in range(steps):
        time.sleep(1)
        image = np.random.random((600, 600, 3))
        yield image
    image = "https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg"
    yield image


# Interfaceの作成
demo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3), outputs="image")

# generatorにはqueueが必要
demo.queue()

# 起動
demo.launch()

9. プログレスバー

「gradio」は、プログレスバーの機能もサポートしています。これを有効にするには、関数のprogressにgr.Progress()を指定するだけです。次に、progress()に0〜1を指定するか、progress.tqdm()で進行状況を追跡します。進行状況を更新するにはキューイングを有効にする必要があります。

import time
import gradio as gr

# 関数の定義
def slowly_reverse(word, progress=gr.Progress()):
    progress(0, desc="Starting")
    time.sleep(1)
    progress(0.05)
    new_string = ""
    for letter in progress.tqdm(word, desc="Reversing"):
        time.sleep(0.25)
        new_string = letter + new_string
    return new_string


# Interfaceの作成
demo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())

# progressにはqueueが必要
demo.queue(concurrency_count=10)

# 起動
demo.launch()

tqdmを使用する場合は、デフォルトの引数を gr.Progress(track_tqdm=True) にすることで、関数内に存在する tqdm.tqdm から進行状況の更新を自動的にレポートしてもらうことができます。

10. バッチ関数

「gradio」はバッチ関数を渡す機能をサポートしています。 バッチ関数は、入力のリストを受け取り、予測のリストを返す関数です。

たとえば、次のバッチ関数は 2 つの入力リスト (単語のリストと int のリスト) を受け取り、トリミングされた単語のリストを出力として返します。

import time

def trim_words(words, lens):
    trimmed_words = []
    time.sleep(5)
    for w, l in zip(words, lens):
        trimmed_words.append(w[:int(l)])        
    return [trimmed_words]

バッチ関数の利点は、queueを有効にすると、gradio サーバーが受信リクエストを自動的にバッチ処理して並列処理できるため、速度が向上する可能性があることです。

・Interface

# Interfaceの作成
demo = gr.Interface(trim_words, ["textbox", "number"], ["output"], 
    batch=True, 
    max_batch_size=16
)

# 起動
demo.queue()
demo.launch()

・Blocks

import gradio as gr

# Blocksの生成
with gr.Blocks() as demo:
    with gr.Row():
        word = gr.Textbox(label="word")
        leng = gr.Number(label="leng")
        output = gr.Textbox(label="Output")
    with gr.Row():
        run = gr.Button()

    event = run.click(trim_words, [word, leng], output, 
        batch=True, 
        max_batch_size=16
    )

# 起動
demo.queue()
demo.launch()

上記の例では、各リクエストが個別に処理される (合計推論時間は 80 秒) のではなく、16 個のリクエストが並行して処理されます (合計推論時間は 5 秒)。 多くの HuggingFace TransformersとDiffusersモデルは、gradio のバッチモードで非常に自然に動作します。(Diffusersを使用してバッチで画像を生成するデモの例)

バッチ関数を使用するには、基になるInterfaceまたはBlocksでqueueを有効にする必要があります。




この記事が気に入ったらサポートをしてみませんか?