Turing UI実装用のJupyterウィジェット

こんにちは、Habr! Jupyter Notebookでインターフェイスをすばやく作成した経験を共有したいと思います。 シンプルなUIを必要とするある種のタスクがあり、何らかの理由でJupiterで作成したい場合は、catにようこそ。













私はタスクに直面しました:チューリングマシンのビジュアルインターフェイスを実装することです。 おそらく最も簡単なオプションは、デスクトップにC#またはJavaを使用するか、ブラウザのJSに実装することです。 私はdatasaensをするので そして私は木星の脳を持っています -Jupyter Widgetsを使用することにしました。 ハブでは、このテクノロジーに関する情報が見つかりませんでした。修正する必要があります。 この投稿は、読者が既にPython言語に精通しており、Jupyter Notebookで働いていたことを示しています。







Jupyterウィジェット



Jupyterウィジェットは、Jupyterノートブック用のインタラクティブなHTMLウィジェットです。 直接的な目的は、ラップトップをより動的にし、さまざまなコントロールを追加することです。 CSSの知識がなくても、スライダー、ボタン、プログレスバー、その他の要素を数行追加する機会があります。 ご覧のとおり、この技術の主な用途は、シンプルなUIを必要とするプロトタイプ(特にMLプロジェクト用)の迅速な開発です。 単にテーブルやグラフではなく、顧客にインタラクティブなものを表示する必要がある場合、私が最初に試すのはJupiterのウィジェットです(それからplotlyDash )。 データサイエンティストのより日常的な使用例は、インタラクション機能を使用した便利なデバッグです。







Interactは、おそらくこのライブラリで最も使用される機能です。 スライダーを作成し、変更時にいくつかの関数(コールバック)を呼び出します。 これらはすべて1行で実装されます。 多くの便利なアプリケーションを考え出すことができます。たとえば、スライダーを動かすだけで、機械学習モデルがパラメーターや属性の変化にどのように反応するかを見ることができます。 たとえば、xgboostをインポートしませんでしたが、多項式のグラフを作成しただけで、この相互作用自体を使用して次数を変更できます。







xs = np.linspace(-10, 10, 21) def f(x): plt.plot(xs, [math.pow(i, x) for i in xs]) interact(f, x=(0, 5))
      
      





GIF







チューリングマシン



チューリングマシンは、有限状態マシンの概念を拡張したものであり、理論的には任意のアルゴリズムを表現できます。 アルファベット、許可された状態、入力文字、初期状態、および遷移関数によって形式化できます。 機械の主要部分はアルファベット文字のテープで、トランジション機能に従って左右に移動する読み取りヘッドによって順次処理されます。







マシンを「q1」の状態にして、文字「A」を読み取ります。 遷移関数がチェックされ、「q1 A」の組み合わせがある場合、遷移が行われる次の状態、テープ上の現在の位置に書き込まれる文字、および読み取りヘッドがさらに移動する場所がわかります。 そのような組み合わせがない場合(「状態記号」)、マシンの動作は終了します。 この知識は、インターフェースに表示する必要があるものを理解するのに十分なはずです。 Pythonのチューリングマシンの完成したクラスの例はここにあります。必要に応じて少し変更しました。







明確にするために、次のタスクを検討してください。 文字「A」と「B」の配列が与えられます。 すべての文字「B」を削除し、文字「A」を残して配列を圧縮する必要があります。 解決策は、すべての文字「B」を文字「*」に置き換えることです。その後、異なる位置に散在する文字「A」を右にシフトする必要があります。 ログイン例:「#BAABABA#」。 出力は「#### AAAA#」です。 ここで、「#」はサービスの空の文字です。 ネタバレの下の移行機能。







遷移関数
 transition_function = { ('q0', 'A'): ('q0', 'A', 'r'), ('q0', 'B'): ('q0', '*', 'r'), ('q0', '*'): ('q0', '*', 'r'), ('q0', '#'): ('q1', '#', 'l'), ('q1', 'A'): ('q2', 'A', 'l'), ('q1', '*'): ('q1', '#', 'l'), ('q1', '#'): ('q1', '#', 'r'), ('q2', 'A'): ('q3', '*', 'r'), ('q2', '*'): ('q2', '*', 'l'), ('q2', '#'): ('q5', '#', 'r'), ('q3', 'A'): ('q4', 'A', 'l'), ('q3', '*'): ('q3', '*', 'r'), ('q4', '*'): ('q2', 'A', 'l'), ('q5', '*'): ('q5', '#', 'r') }
      
      





可視化



まず、どのUI要素を表示するかを理解する必要があります。









テキストのある行は、ipywidgets.HTMLクラスを使用して表すことができます。 これはhtmlを表示するためのウィジェットで、次のように機能します。







 finish_out = widgets.HTML('In progress') display(finish_out)
      
      





値フィールドの値を変更すると、ウィジェットは自動的に再描画されます。 3つの異なるhtmlウィジェットを使用して、テキストを含む3行を作成します。







行を生成してコマンドを実行するためのボタンは、ipywidgets.Buttonを使用して実行されます。







 step_btn = widgets.Button(description='Step', button_style='primary')
      
      





スライダーは、ipywidgets.IntSliderクラスで表されます。 属性は、許容値の境界を渡すことができます。







 slider = widgets.IntSlider(min=3, max=10, step=1, value=5, description='Length')
      
      





UI要素からのイベントは、コールバックを使用して処理されます。コールバックは、イベントが発生したときに呼び出される関数です。 この場合、ボタンについてはクリックイベントをサブスクライブする必要があり、スライダーについては要素の値を変更するイベントをサブスクライブする必要があります。 これらのコールバック内で、htmlウィジェットの値が変更されます。







 def on_step_btn(d): global is_final if not is_final: is_final = tm.step() line_out.value = tm.get_tape() else: finish_out.value = 'Finish' step_btn.on_click(on_step_btn)
      
      





要素を描画するために、それらすべてを表示関数に渡すことができます。 すべてを一緒に導出すると、次のようになります。













すべてが機能します! これで停止することもできますが、かなり厄介に見えることを認めなければなりません。 修正してみましょう。







より馴染みのある形でコントロールを収集します。 各html行の前にラベルを追加し、ボタンを1行に配置します。この周りに美しいフレームを作成します。 これは、ipywidgets.Layoutおよびipywidgets.Boxを使用して実行できます。 Boxは、複数のウィジェットをリストとして追加できるコンテナーです。 レイアウト属性を使用すると、ボックス内の要素の表示を簡単に制御できます。 最新のCSSのFlexboxテクノロジーのおかげで、要素を適切に配置できます。 ここでは、独自の何かを単純に収集するだけで十分な多くの例を見つけることができます。 最終的には、次のようになりました。







非表示のテキスト
 form_item_layout = Layout( display='flex', flex_flow='row', justify_content='space-between' ) form_items = [ Box([Label(value='Current line value'), line_out], layout=form_item_layout), Box([Label(value='Current transition'), current_out], layout=form_item_layout), Box([Label(value='Status'), finish_out], layout=form_item_layout), Box([Label(value='Tape length'), slider], layout=form_item_layout), Box([gen_btn, step_btn, finish_btn], layout=form_item_layout) ] form = Box(form_items, layout=Layout( display='flex', flex_flow='column', border='solid 2px', align_items='stretch', width='80%' ))
      
      











おわりに



この投稿では、チューリングマシンのビジュアライザーの例を使用してJupyter Widgetsに会いました。 今、あなたはできる 顧客を驚かせる ラップトップにインタラクティブ機能を追加します。 既存のウィジェットの機能がない場合は、独自のウィジェットを作成できますが、これには少なくとも基本的なJSの知識が必要です。 私が遭遇した唯一のマイナス点は、ラップトップを表示しているとき、ウィジェットがまだgithubに表示されていないことです(ウィジェット->ノートブックウィジェットの状態を保存した後でも)。 これがすぐに修正されることを願っています。







すべての美しくてダイナミックなラップトップ!







PS: githubリポジトリへのリンク








All Articles