ワークフローブロックを作成する
ワークフローブロック作成の完全な開発者ガイド:マニフェスト、入力、出力、バッチ処理、フロー制御、次元。
これは、Python で Block クラスを作成するための詳細ガイドです。Workflow 内で少しだけカスタムロジックが必要なだけなら、 動的な Python ブロック を Workflow Definition 内でインライン定義するだけで十分な場合がほとんどです。詳しくは カスタムブロック.
Workflows のブロック開発には、Workflow エコシステムへの理解が必要です。詳細に入る前に、必要な知識を要約しましょう:
理解 Workflow 実行、特に:
Workflow 定義における Workflow ブロックとステップの関係
Workflow ブロックとその manifest がどのように Workflows Compiler
何であるか
次元レベルWorkflow を流れるバッチ指向データのどのように Execution Engine が、入力と出力に関してステップとやり取りするのか
の性質と役割は何か Workflow
の種類どのように
pydanticが動作するかを理解すること
環境のセットアップ
すぐに分かるように、Workflow ブロックの作成は、特定のインターフェースを実装する Python クラスを定義するだけです。この設計により、他の Python コードと同様に、Python インタプリタでブロックを実行できます。ただし、Workflow 実行中には通常他のブロックから提供される、必要な入力をすべて組み立てる際に難しさが生じることがあります。そのため、スムーズに作業するには開発環境を適切にセットアップすることが重要です。標準的な開発プロセスの一部として、次の手順に従うことを推奨します(最初の手順は、後続の貢献では省略できます):
をセットアップし、
conda環境 をインストールして、推論の主要依存関係を推論コントリビューターガイド.に記載のとおりに行ってください。Workflows コードベースの構成に慣れておきましょう。
最小限のブロックを作成する - これを行う方法は次のセクションで学びます。まずは、シンプルなブロック manifest と基本ロジックを実装して、ブロックが期待どおりに動作することを確認してください。
ブロックをプラグインに追加する - ブロックを作成したら、プラグインからエクスポートされるブロック一覧に追加します。Roboflow Core プラグインにブロックを追加する場合は、 loader.py. にあなたのブロックのエントリを追加してください。これを忘れると、ブロックは表示されません!
ブロックを反復的に改善する - 結果に満足できるまで、ブロックの開発と実行を続けてください。以下のセクションでは、さまざまなシナリオでブロックを反復改善する方法を説明します。
Workflows UI を使ってブロックを実行する
マウント済みボリュームを使って inference サーバーを実行することを推奨します(変更のたびにサーバーを再ビルドするよりもはるかに高速です): 推論 サーバー
を実行し、ローカルサーバーを Roboflow UI に接続します:

プレビューをすばやく実行するには:

私のブロックには追加の依存関係が必要です - 事前ビルド済みの `inference` サーバーは使えません
ブロックによっては追加の依存関係が必要になることは自然です。依存関係を追加するには、関連する Docker イメージにインストールされている requirements ファイルのいずれかに含めるだけです(通常は CPU ビルド の 推論 サーバー)。
その後、次を実行します:
次に、今作成したテストタグを指定してローカルビルドを実行できます:
Workflows UI を使わずにブロックを実行する
Roboflow プラットフォームにアクセスできないコントリビューターには、上記セクションで述べたようにサーバーを実行することを推奨します。ただし、UI エディターの代わりに、シンプルな Workflow 定義を作成してサーバーにリクエストを送る必要があります。
UI なしで Workflow を実行する
次のコードスニペットは、Workflow を実行するために 推論 サーバーにリクエストを送る方法を示しています。 inference_sdk は 推論 パッケージに含まれており、サーバー向けの軽量クライアントライブラリとして提供されています。
通常のコントリビューターに推奨される方法
で統合テストを作成することは、 tests/workflows/integration_tests/execution ディレクトリにおいて、開発の反復プロセスの自然な一部です。この方法では、開発とテストを同時に進められ、コードを洗練させる間に貴重なフィードバックが得られます。多少の経験は必要ですが、長期的なコード保守性を大きく高めます。
手順は簡単です:
新しいテストモジュールを作成する: たとえば、次のように名前を付けます
test_workflows_with_my_custom_block.py.サンプル Workflow を作成する: 1つ以上のサンプル Workflow を作成します。ブロックがエコシステム内の他のブロックとうまく連携するのが理想です。
サンプルデータでテストを実行する: テスト内でこれらの Workflow をサンプルデータを使って実行します(通常使用しているサンプルデータを見つけるには、 fixture を確認してください)。
期待される結果をアサートする: 結果が期待どおりであることを検証します。
テストを開発フローに組み込むことで、ブロックの安定性を長期的に保ち、既存ブロックと効果的に連携させることができ、あなたの成果物の表現力を高められます!
次のコマンドでテストを実行できます:
他のテストを例として参照しても、次のテンプレートを使っても構いません:
統合テストテンプレート
行
2で、model_managerfixture が見つかります。これは通常、モデルブロックに必要です。この fixture はModelManagerの抽象化を推論から提供し、モデルのロードとアンロードに使用されます。行
3では、2匹の犬の画像を含む fixture を定義しています(他の fixture を見て、さらに例となる画像を探してください)。行
4は任意の fixture で、テスト対象の Workflow 内のいずれかのブロックが Roboflow API キーを必要とする場合に使用できます。その場合は、テストを実行する前に有効なキーを使ってROBOFLOW_API_KEY環境変数をエクスポートしてください。行
7-11では、Workflow 定義に基づいて Execution Engine が実行時に作成するブロックの初期化パラメータのセットアップを行います。行
19-23では、入力パラメータを注入して Workflow を実行する方法を示しています。runtime_parameters のキーが Workflow 定義で宣言された入力と一致していることを確認してください。行
26以降に、テスト内の例示的なアサーションがあります。
プロトタイプ
Workflow ブロックを作成するには、Workflows ライブラリのコアからいくつかのインポートが必要です。ブロック作成時に役立つインポートの一覧は次のとおりです:
最も重要なのは次のものです:
WorkflowBlock- あなたのブロックの基底クラスWorkflowBlockManifest- ブロック manifest の基底クラス
内部データ表現の理解
お気づきかもしれませんが、 Batch と WorkflowImageData クラスのインポートを推奨しています。これらは、私たちのシステムでビルディングブロックを構築する際に使われる基本コンポーネントです。これらのクラスが全体のアーキテクチャの中でどのように位置づくかをより深く理解するには、 Data Representations ページを参照して、さらに詳しい情報を確認することをお勧めします。
ブロック manifest
manifest は、Workflow ブロックの重要なコンポーネントであり、ブロックを使うために Workflow 定義に配置できるステップ宣言のプロトタイプを定義します。特に、次のことを行います:
使用します
pydanticWorkflow 定義の構文解析を支援するために: 次を継承しますpydantic BaseModelの機能を使って、Workflow 定義を解析および検証します。このスキーマは、pydantic のOpenAPI 標準との統合により、Workflows UI と互換性のある形式へ自動的にエクスポートすることもできます。データバインディングを定義する: 実行中に workflow を流れるデータのセレクタとなる manifest 内のフィールドと、その種類を指定します。
ブロック出力を記述する: ブロックが生成する出力を概説します。
次元性を指定する: 入力と出力の次元性に関するプロパティを詳述します。
バッチ入力と空値を示す: このステップがバッチ入力と空値を受け入れるかどうかを Execution Engine に伝えます。
互換性を確保する: 安定性を保つため、異なる Execution Engine バージョンとの互換性を規定します。詳細は バージョニング.
manifest のスキャフォールディング
manifest の動作を理解するために、ステップごとに定義してみましょう。ここで作成するサンプルブロックは、画像の類似度を計算するものです。まずは import とクラスのスキャフォールディングから始めます:
これは manifest の最小表現です。Compiler と Execution engine にとって重要な 2 つの特別なフィールドを定義しています:
type- 動的なブロックプールに基づく Workflow 定義の構文を解析するために必要です。これはpydantictype discriminator であり、Workflow 定義内の特定のステップを解析する際に、どのブロック manifest を検証すべきかを Compiler が理解できるようにしますname- このプロパティはステップに一意の名前を付け、他のステップがセレクタを通じてそれを選択できるようにするために使われます
入力の追加
比較対象の画像を含む 2 つの入力をステップに受け取らせたいと考えています。
入力の追加
それらの入力定義を manifest に追加する方法を見てみましょう:
の行で
2-9、必要なものがすべて揃うように、いくつかの import を追加しました行
20はimage_1パラメータを定義します。manifest は Workflow Definition のプロトタイプなので、ステップが使用する画像を伝える唯一の方法はセレクタを提供することです。コアライブラリには専用の型としてSelectorがあります。コードベースをさらに深く見ると、これは型エイリアスのコンストラクタ関数であり、pydanticに一致する文字列を期待するよう指示しています$inputs.{name}と$steps.{name}.*のパターンに対応し、さらに追加のスキーマフィールドメタデータを提供して、Workflows エコシステムのコンポーネントに、kindセレクタの背後にあるデータの 画像. 重要な注意: を list として表します。特定の kinds のリストは kind kinds の union として解釈されます Execution Engine によって。を示す
pydanticField(...)属性は、行の後半にあります20は任意ですが、特に Workflows UI と連携することを意図したブロックでは推奨されます行の
23から、image_2パラメータの定義を見つけることができます。これはimage_1.
このような manifest 定義により、Workflow 定義内で次のステップ宣言を扱えます:
この定義により、Compiler と Execution Engine は次のことを行います:
ステップを、type を宣言する Workflow ブロックから初期化する
my_plugin/images_similarity@v1ステップの run メソッドに 2 つのパラメータを供給する:
input_1という型のWorkflowImageDataで渡される画像で埋められますmy_image.imput_2という型のWorkflowImageDataは実行時に、別のステップimage_transformation
manifest にパラメータを追加する
では、ステップの実行に影響するパラメータを追加しましょう。
manifest にパラメータを追加する
行
9importsfloat_zero_to_onekindを定義するために使用される定義。行で
27、次の名前のパラメータの定義を開始しますsimilarity_threshold。manifest は float 値または、kindfloat_zero_to_oneでインポートした Workflow 入力へのセレクタのどちらかを受け入れます9.
このような manifest 定義により、Workflow 定義内で次のステップ宣言を扱えます:
または、代わりに:
ブロック出力の宣言
ブロックの入力定義は成功しましたが、ブロックを正常に実行するために必要な要素がまだいくつか足りません。ブロックの出力を定義しましょう。
ブロック出力の宣言
必要な情報の最小セットは、出力の説明です。さらに、ブロックの安定性を高めるために、実行エンジンの互換性に関する情報を提供することを推奨します。
行
5ステップ出力を記述するために使用されるクラスをインポートします行
11importsブール値kind出力定義で使用するための行
32-39ブロックからの出力を指定するクラスメソッドを宣言します。リスト内の各エントリは、各バッチ要素ごとに1つの戻り値プロパティとそのkind。私たちのブロックはブールフラグを返しますimages_match各画像ペアについて。行
41-43ブロックが Execution Engine と互換性があることを宣言します - 参照: バージョン管理ページ 詳細について
これらの変更の結果:
Execution Engine は、このブロックから作成されたステップが指定された出力を提供するはずであることを理解し、他のステップは入力でそれらの出力を参照できるようになります
Execution Engine がバージョンにないため、ブロックの読み込み機構はそのブロックを読み込みません
v1
詳細を見る: 動的な出力
一部のブロックは、パース後に利用可能なステップマニフェストの内容に関係なく、classmethod を使って出力を任意に定義できない場合があります。これをサポートするために、次の規約を導入しました:
classmethod
describe_outputs(...)name を持つ要素を1つ含むリストを返すものとします*および kind*(別名WILDCARD_KIND)さらに、ブロックマニフェストはインスタンスメソッド
get_actual_outputs(...)を実装し、入力済みのマニフェストデータに基づいて生成可能な実際の出力のリストを提供する必要があります
ブロッククラスの定義
ここまでで、シンプルなブロックのマニフェストは準備できました。引き続き例を見ていきましょう。 応用トピック のセクションで、今は脱線しすぎない程度のより詳細な内容を確認できます。
基本実装
マニフェストが整ったので、ブロックのベースライン実装を準備できます。
ブロックのひな形
行
1,5-6と8-11ブロッククラスとそのすべてのメソッドシグネチャを正しく定義するために必要な追加シンボルを提供するよう、インポート構造に変更を加えました行
53-55クラスメソッドを定義しますget_manifest(...)先ほど作成したマニフェストクラスを単純に返すようにします
ブロックロジックの実装を提供する
それでは、次にブロックへ run(...) メソッドの実装例を追加し、意味のある結果を生成できるようにしましょう。
このセクションの内容は、堅牢なブロック実装を提供するというより、ブロック作成者として Workflow エコシステムとどのようにやり取りするかの例を示すことを目的としています。
`run(...)` メソッドの実装
行で
3OpenCV をインポートします行
55-57ブロックのコンストラクタを定義します。これにより、ブロックの状態は一度だけ初期化され、連続したrun(...)メソッドの呼び出しを通して維持されます。たとえば Execution Engine が動画の連続フレームで実行される場合です行
69-80ブロック機能の実装を提供します。Workflows エコシステムに関して詳細自体は本質的ではありませんが、注目すべき点がいくつかあります:行
69と70〜を活用しますWorkflowImageData抽象化を用いて、どのようにnumpy_imageプロパティを使ってnp.ndarrayWorkflows における画像の内部表現から取得できることを示しています。残りのWorkflowImageDataのプロパティも確認して、さらに発見してみることをお勧めします。ワークフローブロック実行の結果。行
78-80の場合は単なる辞書です キーはマニフェストで宣言された出力名です、行43。宣言したすべての出力を必ず提供してください。そうしないと Execution Engine がエラーを送出します。
でブロックを公開する プラグイン
これでブロックは使用可能な状態になりましたが、Execution Engine はその存在を認識していません。これは、登録済みのプラグインのどれも、あなたが作成したブロックをエクスポートしていないためです。ブロックのバンドル化の詳細は 別ページで説明されていますが、残る作業は、プラグインの load_blocks(...) 関数が返すリストにブロッククラスを追加することです:
応用トピック
入力バッチを処理するブロック
場合によっては、すべての入力データをバッチとして一度に処理すると、ブロックの性能が向上することがあります。これは GPU 上で動作するモデルで起こり得ます。こうした動作モードは Workflows ブロックでサポートされています。ここでは、そのブロックでの使い方の例を示します。
バッチを受け付けるブロックの実装
行
13importsBatchワークフローライブラリのコアにあるクラスで、バッチ要素を保持するための、リストによく似た(ただし読み取り専用の)コンテナを表します行
40-42ブロックのデフォルト動作を変更し、バッチを処理できるようにするクラスメソッドを定義します。メソッドがバッチ指向として認識する各パラメータをマークしていますrun(...)メソッド はバッチ指向として認識します.上記の変更により
run(...)メソッドのシグネチャが変わり、今ではimage_1とimage_2はWorkflowImageDataのインスタンスではなく、そうではなくこの型の要素のバッチです。 重要な注意: 複数のバッチ指向パラメータがある場合、それらのバッチの対応する位置に相互に関連する要素があることを期待します。つまり、私たちのブロックがimage_1[1]をimage_2[1]と比較することが、実際に論理的に意味のある操作になるようにします。行
74-77,85-86必要に応じてバッチ要素全体で処理を実行するために導入すべき変更を示し、バッチ要素を反復処理する方法を紹介します出力がどのように構築されるかに注意することが重要です。行
85では、バッチの各要素に対して、run(...)メソッドから返されるリスト内にそれぞれのエントリが与えられます。順序はバッチ要素の順序と一致していなければなりません。各出力辞書は、ブロック出力で宣言されたすべてのキーを提供する必要があります。
バッチとスカラーの両方を受け付ける入力
それは 比較的まれですが、単一の入力パラメータでバッチ指向データとスカラーの両方を受け付ける必要があるブロックもあり得ます。Execution Engine は、ブロックマニフェストの get_parameters_accepting_batches_and_scalars(...) メソッドを使うことでそれを認識します。以下の例をご覧ください:
行
20-22混在した(スカラーとバッチ指向の両方の)入力データを受け付けることが想定されるマニフェストパラメータを指定します。この段階では、定義は前の例と比べて違いがないことに注意してください。行
24-26指定するget_parameters_accepting_batches_and_scalars(...)メソッドを指定して、ブロックrun(...)メソッドが、指定されたパラメータについてスカラー入力とバッチ指向入力の両方を処理できることを Execution Engine に伝えます。行
45-47混在した性質のパラメータをrun(...)メソッドシグネチャに示します。行
49ブロックロジック内で、想定される出力サイズを把握しておく必要があることを示しています ブロックロジックの中で。そのため、混在入力を持つブロックの実装はかなり難しいのです。通常、ブロックrun(...)メソッドがスカラーで動作する場合、多くの場合(例外は下で説明します)、メソッドは単一の出力辞書を構築します。同様に、バッチ指向入力が受け付けられる場合、それらの入力が想定される出力サイズを定義します。ただしこの場合は、バッチを手動で検出し、そのサイズを取得する必要があります。行
50-54バッチ指向データが検出されたときに異なるロジックを適用する、混在パラメータの通常の扱い方を示します前述のとおり、出力の構築も混在入力の性質に合わせて調整する必要があります。これは行で示されています
65-70
フロー制御ブロックの実装
フロー制御ブロックは、単にデータを処理する他のブロックとはかなり異なります。ここではフロー制御ブロックの作成方法を示しますが、その前に少し理論的な説明をします:
フロー制御ブロックとは、マニフェスト内でステップセレクタとの互換性を宣言するブロックです(ステップへのセレクタは
$steps.{step_name}で定義されます。ステップ出力セレクタに似ていますが、出力名の指定がありません)フロー制御ブロックは出力を登録できず、返すものは
FlowControlオブジェクトFlowControlオブジェクトです。これは、次に選択すべき次のステップ(ステップマニフェストで提供されたセレクタ)を、特定のバッチ要素について(SIMD フロー制御)またはワークフロー実行全体について(非 SIMD フロー制御)指定します
フロー制御の実装
ランダム継続ブロックの実装を例示し、コメントアウトしています
行
10ブロックがフローを制御していることを Execution Engine に通知するために使用されるステップセレクタの型注釈をインポートします行
14importsFlowControlフロー制御ブロックから返すことができる唯一の有効な応答であるクラス行
28ステップセレクタのリストを定義します これによってブロックは実質的にフロー制御ブロックになります行
55と56出力の構築方法を示します -FlowControlオブジェクトはコンテキストとしてNone,文字列または文字列のリスト-Noneバッチ要素のフロー終了を表します。文字列は入力で渡された次のステップのセレクタであることが期待されます。
フロー制御の実装 - バッチ版
ランダム継続ブロックの実装を例示し、コメントアウトしています
行
11ブロックがフローを制御していることを Execution Engine に通知するために使用されるステップセレクタの型注釈をインポートします行
15importsFlowControlフロー制御ブロックから返すことができる唯一の有効な応答であるクラス行
29-32ステップセレクタのリストを定義します これによってブロックは実質的にフロー制御ブロックになります行
38-40の定義を含みますget_parameters_accepting_batches(...)メソッドは、ブロックrun(...)メソッドはバッチ指向の画像パラメータを想定していることを Execution Engine に伝えます。行
59バッチの各要素ごとにフロー制御ガイドを返す必要があることを示しています。画像バッチ。その目的を達成するために、行
60ではバッチの内容を反復処理します。行
61-63出力の構築方法を示します -FlowControlオブジェクトはコンテキストとしてNone,文字列または文字列のリスト-Noneバッチ要素のフロー終了を表します。文字列は入力で渡された次のステップのセレクタであることが期待されます。
ネストされたセレクタ
一部のブロックでは、ブロックマニフェストのフィールドとしてセレクタのリストやセレクタの辞書を提供する必要があります。Execution Engine のバージョン v1 はネストを1階層しかサポートしていないため、セレクタのリストのリストや、セレクタのリストを含む辞書は正しく認識されません。
ネストされたセレクタの実用例を以下に示します。
可変数のモデルからの予測の融合
複数の分類器の予測に対して多数決を行うブロックを作りたいとしましょう。その場合、run メソッドは次のようになるはずです:
ネストされたセレクタ - モデルのアンサンブル
行
23-26セレクタのリストを受け付けられるマニフェストフィールドの定義方法を示します行
50ブロックのrun(...)メソッドへの入力として何を期待すべきかを示します。特定の kind を表すオブジェクトのリストです。ブロックがバッチを受け付ける場合、predictionsフィールドの入力型はList[Batch[sv.Detections]
このようなブロックは、次のステップ宣言と互換性があります:
動的パラメータを可能にするデータ変換付きブロック
場合によっては、ブロックが「名前付き」セレクターのグループを受け入れる必要があります。これらの名前と値は、Workflow 定義の作成者によって定義されます。このような場合、ブロックのマニフェストはセレクターの辞書を受け入れる必要があり、キーがそれらのセレクターの名前として機能します。
入れ子のセレクター - 名前付きセレクター
行
22-25セレクターの辞書を受け入れられるマニフェストフィールドを定義する方法を示します。これは、セレクター名と値の対応付けを提供します行
46ブロックのrun(...)メソッド - セレクターで参照されるオブジェクトの辞書。ブロックがバッチを受け入れる場合、入力型のdataフィールドの入力型はDict[str, Union[Batch[Any], Any]]。バッチではない場合、セレクターで参照される非バッチ指向のデータは自動的にブロードキャストされます。一方、バッチを受け入れるブロックでは、Batchコンテナはバッチ指向の入力のみをラップし、その他の入力は単一値として渡されます。
このようなブロックは、次のステップ宣言と互換性があります:
実際の影響は次のとおりです:
下に
data["a"]内でrun(...)モデルの予測を見つけることができます。例えばsv.Detectionsもしmodel_1が物体検出モデルであれば下に
data["b"]内でrun(...)、という名前の入力パラメータの値が見つかりますmy_parameter
入力と出力の次元数 vs run(...) メソッド
ブロック入力の次元数は、形成において重要な役割を果たします run(...) メソッドのシグネチャに。だからこそ、システムは入力間の次元レベルの差に厳格な上限を課しています(許容される最大差は 1)です。この制約は、ブロックを記述する際の一貫性と予測可能性を確保するために不可欠です。
次元の差が制御されていなければ、の構造を予測するのが難しくなります run(...) メソッド。そうなると開発はより難しく、信頼性も低くなります。そのため、このプロパティの検証は Workflow のコンパイル処理中に厳格に実施されます。
同様に、出力の次元数もメソッドのシグネチャと期待される出力形式に影響します。エコシステムは次のシナリオをサポートしています:
すべての入力が 同じ次元数を持ち 、出力も 変化しない 次元数 - 基本ケース
すべての入力が 同じ次元数を持ち および出力が 減少する 次元数
すべての入力が 同じ次元数を持ち および出力が 増加する 次元数
入力が 異なる次元数を持ち 、出力は〜の次元数を維持することが許可される 参照入力
一貫性を確保し、メソッドシグネチャの曖昧さを防ぐため、入力/出力の次元数の他の組み合わせは許可されません。
次元数が `run(...)` メソッドに与える影響 - バッチ無効
出力の次元数の増加
この例では、予測に基づいて画像の動的クロップを行います。
行で
28-30マニフェストクラスは出力の次元オフセットを宣言します - 値1は、追加するものと理解されるべきです1次元レベルに行であることに注意してください
63、ブロックは空の画像を以降の処理から除外しますが、None出力を持つ辞書の代わりにそれを配置します。これは条件付き実行で使われるものと同じ Execution Engine の動作を利用し、データポイントは下流の処理から除外されます(下流に空の入力を要求するステップがある場合を除く)。行で
64-65単一入力の結果画像とpredictionsが収集されます。これは、登録されたすべての出力をキーとして含む辞書のリストを意味します。Execution Engine は、このステップが各入力要素に対して要素のバッチを返すと理解し、下流ステップの実行中に追跡するための入れ子のインデックス構造を作成します。
出力の次元数の減少
この例では、ブロックがクロップの予測を可視化し、すべてのクロップ予測を1枚の出力画像にまとめたタイルを作成します。
行で
30-32マニフェストクラスは出力の次元オフセットを宣言します - 値-1は、次元レベルを〜だけ減少させるものと理解されるべきです1行で
34-36マニフェストクラスはrun(...)シグネチャが常に安定するよう、自動バッチキャスティングの対象となるメソッド入力を宣言します。自動バッチキャスティングは Execution Engine で導入されましたv0.1.6.0参照してください 変更履歴 詳細について。
行で
53-55出力の次元数の減少がメソッドシグネチャに与える影響がわかります。最初の2つの入力(行で宣言されている36)は人工的に〜でラップされますBatch[]コンテナに、一方でscalar_parameterはプリミティブ型のままです。これは、すべての入力が同じ次元数を持つ場合に、最終次元レベルを占めるすべての要素へアクセスできるようにするため、出力の次元数が減少したときに Execution Engine によって自動的に行われます。もちろん、トップレベルのバッチ内で同じ要素に関連する要素だけがまとめられます。たとえば、2つの入力画像をクロップした場合、それぞれ異なる画像からのクロップは別々にグループ化されます。行
65-66出力がどのように構築されるかを示します - 単一の値が返され、その値は次元数が削減された出力バッチ内で Execution Engine によりインデックス付けされます
異なる入力次元数
この例では、ブロックが元画像のクロップに基づいて予測された検出結果をマージします。結果として、すべての部分的な検出を統合した単一の検出結果を提供します。
行で
31-36マニフェストクラスは入力の次元オフセットを宣言し、画像パラメータがトップレベルであり、image_predictions予測の入れ子バッチであることを示します異なる入力次元数が宣言される場合は常に、次元参照プロパティを指定する必要があります(行を参照
38-40) - この次元レベルは出力次元数の計算に使用されます - この特定のケースでは、画像を指定します。この選択は結果の期待フォーマットに影響します。選択したシナリオでは、登録済みの出力キーをすべて含む単一の辞書を返す必要があります。もし選択がimage_predictionsなら、辞書のリスト(image_predictionsバッチの長さに等しいサイズ)を返します。言い換えれば、get_dimensionality_reference_property(...)どの次元レベルを出力に関連付けるかを示します。行
63-64行で指定された次元オフセットの影響を示します31-36。明らかにimage_predictionsは、〜に関する入れ子バッチです画像。明らかに、特定の画像に関連する入れ子の予測のみがバッチとしてまとめられ、実行時にメソッドへ渡されます。先に述べたように、行
69は単一の辞書となる出力を構築します。これは、出力を〜の次元レベルで登録するためです画像(これも単一要素として渡されました)
次元数が `run(...)` メソッドに与える影響 - バッチ有効
出力の次元数の増加
この例では、予測に基づいて画像の動的クロップを行います。
行で
29-31マニフェストは、ブロックが入力のバッチを受け入れることを宣言しています行で
33-35マニフェストクラスは出力の次元オフセットを宣言します - 値1は、追加するものと理解されるべきです1次元レベルに行で
55-66。入力パラメータのシグネチャは、それがrun(...)メソッドが同じ次元数の入力に対して実行され、それらの入力がバッチで提供されることを反映しています行であることに注意してください
70、ブロックは空の画像を以降の処理から除外しますが、None出力を持つ辞書の代わりにそれを配置します。これは条件付き実行で使われるものと同じ Execution Engine の動作を利用し、データポイントは下流の処理から除外されます(下流に空の入力を要求するステップがある場合を除く)。行で示される出力の構築は
71-73は、入れ子が2段階であることを示しています。まず、ブロックはバッチ上で動作するため、入力バッチ要素ごとに1つの出力を持つ出力のリストを返すことが期待されます。さらに、各入力バッチ要素のこの出力要素は入れ子バッチであることがわかります。したがって、各入力画像と予測に対して、ブロックは出力のリストを生成します。リストの各要素は、各宣言済み出力の値を提供する辞書です。
出力の次元数の減少
この例では、ブロックがクロップの予測を可視化し、すべてのクロップ予測を1枚の出力画像にまとめたタイルを作成します。
行
29-31ブロックが入力としてバッチを受け取ることが期待されることを示すマニフェスト行で
33-35マニフェストクラスは出力の次元オフセットを宣言します - 値-1は、次元レベルを〜だけ減少させるものと理解されるべきです1行で
52-53出力次元数の減少とバッチ処理がメソッドシグネチャに与える影響がわかります。最初の「層」はBatch[]マニフェストがブロックが入力のバッチを受け入れると宣言していることの副作用です。2つ目の「層」は出力次元数の減少によるものです。Execution Engine は、削減される次元を追加のBatch[]コンテナにまとめて入力として提供します。これにより、プログラマーは特定のトップレベルバッチ要素に属するすべての入れ子バッチ要素を収集できます。行
66-67出力がどのように構築されるかを示します - 各トップレベルバッチ要素について、ブロックはすべてのクロップと予測を集約して1つのタイルを作成します。ブロックは入力のバッチを受け入れるため、この処理の結果、トップレベルバッチ要素ごとに1つのタイルが生成されます。したがって、辞書のリストを返すことが期待されます。
異なる入力次元数
この例では、ブロックが元画像のクロップに基づいて予測された検出結果をマージします。結果として、すべての部分的な検出を統合した単一の検出結果を提供します。
行
31-33ブロックが入力としてバッチを受け取ることが期待されることを示すマニフェスト行で
35-40マニフェストクラスは入力の次元オフセットを宣言し、画像パラメータがトップレベルであり、image_predictions予測の入れ子バッチであることを示します異なる入力次元数が宣言される場合は常に、次元参照プロパティを指定する必要があります(行を参照
42-44) - この次元レベルは出力次元数の計算に使用されます - この特定のケースでは、画像。この選択は結果の期待フォーマットに影響します。選択したシナリオでは、〜の各要素に対して単一の辞書を返すことが想定されます画像バッチです。もし選択がimage_predictionsなら、辞書のリスト(入れ子のimage_predictionsバッチの長さに等しいサイズ)を各入力画像バッチ要素ごとに返します。行
66-67行で指定された次元オフセットの影響を示します35-40ならびに行でのバッチ処理の宣言も32-34。最初の「層」はBatch[]コンテナは後者の、入れ子のBatch[Batch[]]〜に対してimages_predictionsは入力次元オフセットの定義に由来します。明らかにimage_predictionsは、〜の特定要素に関連する予測のバッチを保持します画像バッチ。先に述べたように、行
76-77は、〜の各要素ごとに単一の辞書となる出力を構築します画像バッチ
空の入力を受け入れるブロック
前述のとおり、Workflow の実行中に一部のバッチ要素が「空」になることがあります。これはいくつかの要因で起こりえます:
フロー制御の仕組み: 特定の実行分岐が、特定のバッチ要素を隠し、後続ステップで処理されるのを防ぐことがあります。
データ処理ブロックでは: 場合によっては、ブロックが特定のデータポイントに対して意味のある出力を生成できないことがあります。たとえば、Dynamic Crop ブロックはバウンディングボックスのサイズがゼロであればクロップ画像を生成できません。
一部のブロックは、これらの空の入力を扱うように設計されており、たとえば欠落した出力をデフォルト値で置き換えられるブロックがあります。このブロックは、Workflow で構造化された出力を構築する際に特に有用で、一部の要素が空であっても出力に欠落要素がなく、解析しにくくなるのを防ぎます。
空の入力を受け入れるブロック
行で
20-22ブロックが空の入力を受け入れることを示す宣言を見つけるかもしれません行の結果として
20-22は行に見られます41、シグネチャが入力がBatch処理する必要のある空要素を含む可能性があります。実際には、このブロックは空の値を置き換える「人工的」な出力を生成するため、このブロックの出力を参照する、空の入力を受け入れないブロックからそれらの出力を「見える」状態にできます。Execution Engine が実行時に生成したデータで置き換える各入力は、オプション要素を提供する可能性があると考えるべきです。
カスタムコンストラクタ引数を持つブロック
一部のブロックは、外部で構築されたオブジェクトを必要とする場合があります。そのような場合、Workflows Execution Engine の役割はそれらのエンティティをブロックへ渡し、利用可能にすることです。この仕組みは Workflows Compiler を紹介するページでで説明されています。これはブロッククラスからステップを動的に構築する責任を持つコンポーネントだからです。
コンストラクタ引数は次の条件を満たす必要があります:
ブロックによって要求される - クラスメソッドを使用して
WorkflowBlock.get_init_parameters(...)Workflows Execution Engine を実行している環境で提供される:
次のように直接 この 例
デフォルトを使用して Workflow プラグインに登録された
ブロックを定義しながら init パラメータを要求する方法を見てみましょう。
コンストラクタ引数を要求するブロック
行
30-31パラメータなしではないクラスコンストラクタを宣言するブロックがカスタム初期化を必要とすることを Execution Engine に知らせるため、
get_init_parameters(...)行のメソッド33-35提供されなければならないすべてのパラメータ名を列挙します
エアギャップ/オフライン利用可否メタデータ
インターネット接続なしで動作する可能性がある環境(エアギャップ展開)向けにブロックを作成する場合、 WorkflowBlockManifest 3つのオプションのクラスメソッドを公開します。これらをオーバーライドすると、エアギャップ対応のワークフロービルダーがどのブロックをオフラインで使用できるか判断する助けになります。
3つとも妥当なデフォルトを持つため、既存のブロックには 変更は不要です.
get_air_gapped_availability()
ブロックがインターネットなしで動作できるかを宣言します。クラウド API(OpenAI、Anthropic など)を呼び出すブロックでは、これをオーバーライドしてください。
デフォルトでは AirGappedAvailability(available=True) を返します。- 純ロジックのブロック、ローカルネットワークのブロック、および外部接続を必要としないすべてのブロックに適しています。
get_supported_model_variants()
重みをローカルに事前キャッシュできる基盤モデルブロックでは、モデルバリアントIDのリストを返します。ブロックは次の場合にオフラインで利用可能と見なされます いずれかの バリアントにキャッシュ済みアーティファクトがある。
デフォルトでは None。つまり、このブロックはローカルにキャッシュされたモデル重みに依存しません。
get_compatible_task_types()
ユーザーが学習したモデルを受け付ける Roboflow モデルブロックについて、このブロックが扱えるタスク種別を返します。エアギャップ構成のビルダーは、これを使ってキャッシュされたユーザーモデルを互換性のあるブロックに対応付けます。
デフォルトでは None - Roboflow モデルでパラメータ化されないブロック(基盤モデル、ロジックブロック、シンクなど)に適しています。
実行時の制約
一部のブロックは、配備されるランタイム(ホスト型サーバーレス、専用デプロイ、セルフホスト、推論パイプライン)、ステップ実行モード(ローカル vs. リモート)、入力モード(画像 vs. 動画)によって挙動が異なったり、完全に失敗したりします。これを上書きする get_restrictions() on WorkflowBlockManifest これらの注意点をブロック内に一度だけ宣言し、実行エンジン、スキーマエンドポイント、自動生成されるブロックギャラリーがすべて一貫して表示できるようにします。
デフォルトでは []、そのため既存のブロックは 変更は不要です.
重大度: 軽度 対 重大
各制約には 重大度:
Severity.SOFT- ブロックは最後まで実行され、正しい出力形状を返しますが、値が劣化していたり意味をなさなかったりします(例: トラッカーIDがリクエスト間でリセットされる、クールダウンがスロットリングしない、ファイルが一時ディスクに書き込まれる)。ワークフロー自体は動き続けますが、結果はユーザーの期待通りではありません。Severity.HARD- このランタイムではブロックが実行されない/例外を投げる/利用可能な出力を生成できません。エンジンはコンパイルを拒否するか、即時失敗すべきです。
制約の適用範囲を定める
ある RuntimeRestriction は3つの軸の任意の組み合わせに沿って適用範囲を限定できます。ある軸が Noneのままなら、その制約はその軸のすべての値に適用されます。
applies_to_runtimes:Runtime.HOSTED_SERVERLESS,Runtime.DEDICATED_DEPLOYMENT,Runtime.SELF_HOSTED_CPU,Runtime.SELF_HOSTED_GPU,Runtime.INFERENCE_PIPELINE.applies_to_step_execution_modes:StepExecutionMode.LOCAL,StepExecutionMode.REMOTE.applies_to_input_modes:RuntimeInputMode.IMAGE,RuntimeInputMode.VIDEO.
この 注記 フィールドは、失敗モードまたは劣化した挙動を1行で人間が読める形で説明するものです。何が起きるか(例: "track_ids がリクエスト間でリセットされる", "一時的な /tmp に書き込まれる")を述べ、抽象的な前提条件は書かないでください。
共有プリセット
ほとんどの注意点は少数の共通パターンに収まるため、再利用可能なプリセットを dataclass とともにエクスポートし、コードベース全体で表現を一貫させています。まずはこれらを使ってください:
STATEFUL_VIDEO_HTTP_SOFT_RESTRICTION- 動画トラッキング/カウント/集計ブロック向け。動画ごとの状態がプロセス内メモリにあり、ステートレスな HTTP リクエストの間でリセットされます。COOLDOWN_HTTP_SOFT_RESTRICTION- クールダウン/レート制限タイマーがプロセス内メモリに保持されるブロック向けで、そのため複数レプリカの HTTP ランタイムではスロットリングしません。STILL_IMAGE_INPUT_SOFT_RESTRICTION- 時間的文脈(動画または繰り返しフレーム)に依存し、静止画像ではほとんどまたはまったく効果がないブロック向け。
例
動画ごとの状態を保持し、静止画像では意味をなさないラインカウンターブロックは、両方の制約を宣言します:
カスタム制約(例: ホスト型サーバーレスランタイムに存在しない GPU ハードウェアを必要とするブロック)は、以下のようにインラインで宣言します: Severity.HARD ブロックには CUDA GPU が必要です。CPU のみのワーカーでは例外を投げます。
このように宣言された制約は、次の3か所で表示されます:
この
describe_interfaceHTTP ペイロード(RuntimeRestriction.to_dict())、ワークフローの実行前にワークフロークライアントやビルダーがユーザーに警告できます。ブロックの自動生成されるブロックギャラリーページの「Runtime compatibility」セクションにあり、直後の Properties.
実行エンジン。ここでは
Severity.HARD現在のランタイムに対する制約で即時失敗を選べます。
依存リソースの宣言
多くのブロックは実行時に外部リソースを必要とします。Roboflow で学習したモデルや基盤モデルの重み、Roboflow プロジェクト(例: アクティブラーニングの対象、データセットアップロード先)、またはサードパーティのホスト型モデル(OpenAI、Anthropic、OpenRouter など)です。ワークフローが実際に実行されるまで、システム内のどこにも、どのリソースが必要になるかは分かりません。
上書きする discover_dependent_resources() をブロックマニフェストで上書きすると、そのギャップを埋められます。このメソッドは 解析済みのマニフェストインスタンスに対して呼び出されるため、特定ステップの具体的なフィールド値から宣言を計算できます。これにより呼び出し側は、何も実行せずにコンパイル時点でワークフロー全体のリソースを静的に列挙でき、予測可能な実行時間のためにモデル重みを事前読み込みしたり、API キーが参照されているすべてのモデルとプロジェクトにアクセスできることを事前に確認したりといった用途が可能になります。
デフォルトでは None。これは、ブロックが 宣言しない 依存関係を――呼び出し側はそれを 不明として扱わなければなりません。これは意図的に []、これはブロックが外部リソースを必要としないことを明示的に宣言します。既存のブロックに変更は不要です。リソースを使用するブロックはオーバーライドすべきです。
リソースのエンベロープ
ブロックはリソースの形状を独自に定義しません。エンベロープは実行エンジンによって管理されます。A DependentResource は resource_type を、その型に登録された型付き(pydantic)のメタデータエンティティと組み合わせます:
DependentResourceType.ROBOFLOW_PLATFORM_MODEL→RoboflowPlatformModelMetadata(model_id, required_action, execution_location)— Roboflow プラットフォーム経由で提供されるモデル。合成された ID を持つ基盤/コアモデルも含みます(例:clip/ViT-B-32).required_action利用形態を示します:ModelRequiredAction.EXECUTION(重みが取得される、または推論が要求される)かModelRequiredAction.ACCESS(モデルエンティティがプラットフォーム上で到達可能であればよいだけの場合。例: メタデータを付与する監視シンク)。実行の場合、execution_locationはLOCAL,REMOTE、ENVIRONMENT_DEFINEDランタイムでWORKFLOWS_STEP_EXECUTION_MODEによって決定され、コンパイル時には判定できない場合です(ステップ実行モードで分岐するモデルブロックのデフォルト)。DependentResourceType.ROBOFLOW_PLATFORM_PROJECT→RoboflowPlatformProjectMetadata(project_url)— ブロックが読み取りまたは書き込みを行う Roboflow プロジェクトです。DependentResourceType.THIRD_PARTY_MODEL→ThirdPartyModelMetadata(provider, model_id)— 外部プロバイダーによって実行されるモデル。定義上、リモート実行です。
ファクトリヘルパーにより、実装は1行で済みます: roboflow_platform_model(), roboflow_platform_project(), third_party_model().
セレクター値とランタイム解決
マニフェストのフィールドには、具体的な値の代わりにワークフローセレクターが入ることがあります。宣言はそのような値を そのまま — ブロックはセレクターを解決しません。呼び出し側は $inputs.<name> の参照を、ランタイムパラメータが分かり次第置き換えられます; $steps.<name>.<property> の参照は静的にはまったく解決できません。すべてのメタデータエンティティは requires_runtime_resolution() を公開しており、呼び出し側は具体的な識別子と、まだ解決が必要な参照を区別できます。
When the final identifier is a 関数 の field value( clip/<version>、カタログ検索など)、置換された入力値だけでは実行される ID になりません。そのような宣言には model_id_resolver — 必要なものをすべてクロージャに保持した呼び出し可能オブジェクト — を付与し、置換された値を最終 ID に変換します。この resolver はプロセス内の補助にすぎず、シリアライズ、JSON スキーマ、等価性の対象外です。プロセス内の呼び出し側(例: エンジンの初回実行時の事前読み込み)は、入力値を置換した後にこれを呼び出します。resolver は None 値が静的に解決不能であることを宣言するために返すことができます(最終 ID がその1つの値だけに依存しない場合)。その場合、呼び出し側はその依存関係をスキップし、実行時に解決します。例外を投げる場合、その値は本当に無効です。
に合わせてください run() 読み込む
宣言された識別子は、ちょうど run() が要求するものと完全に一致していなければなりません。バージョンフィールドから合成された ID も含みます。ブロックが f"my_family/{self.version}" という形を load_core_model(...) の呼び出し箇所で組み立てているなら、宣言も同じ ID を組み立てる必要があります(そして version フィールドにセレクターが入っている場合は、そのままのセレクターにフォールバックします)。
例
モデルブロックが、自身のモデルと任意のアクティブラーニング対象プロジェクトを宣言する例:
version フィールドからモデル ID を合成するブロックの例:
実行せずにモデルエンティティのみを参照するシンクの例:
宣言すべきでない場合
単に 保持する モデル ID や project-kind の値を一般的なペイロードとして運ぶだけのフィールド(例: 値をクエリパラメータとして転送する webhook シンク)はリソース依存ではありません。そうしたブロックは意図的にデフォルトを維持します。
コアリポジトリの貢献者は、単体テスト(tests/workflows/unit_tests/core_steps/test_dependent_resources.py)が境界を守っていることを認識してください。マニフェストで roboflow_model_id または roboflow_project kind のフィールドを宣言するすべてのコアブロックは、オーバーライドするか、carry-only として明示的に許可リストに載っていなければなりません。 discover_dependent_resources() kind のフィールドを宣言するすべてのコアブロックは、オーバーライドするか、carry-only として明示的に許可リストに載っていなければなりません。
モデル重みを読み込むブロックは モデルマネージャーの外で ( run() 実際に何をするかを確認し、何が model_manager 初期化パラメータに現れるかは確認しない)場合、当面このメソッドを実装すべきではありません。依存関係は未宣言のままです(None).
カスタム Python ブロックは常に Noneを返します。コードは静的解析に対して不透明なため、 不明 が唯一の正直な答えです。
最終更新
役に立ちましたか?