Knitfab v1.4.0 をリリースしました
皆さんこんにちは。株式会社オープンストリーム・技術創発推進室の高岡です。
10月25日に、私たちが開発しているMLOps 管理ツール “Knitfab” の v1.4.0 をリリースしましたので、その変更内容をご紹介いたします。
リリースハイライト
Plan 定義の柔軟性を高めました
Plan に新しいメタデータ “annotation” がつけられるようになりました
コマンドライン引数を指定できるようにしました
もっと多様な Run を表現できるようにしました
Kubernetes ServiceAccount を(Plan 経由で)指定できるようにしました
ライフサイクルフックから、環境変数を注入できるようにしました
Data の Tag を扱いやすくしました
Data の Tag をキーのみに基づいて削除できるようにしました
Data の Tag に対して「削除と追加」を同時に行った場合、「削除が先、追加が後」になるように変更しました
Plan に関する変更
これまで、Plan が「どのような処理をするものか」という情報は、その image と、入出力の Tag だけが手がかりでした。Plan の処理内容は、image 名と Tag を見て思い出す、という不便な状況にあったものと思います。
また、Knitfab は「Plan の処理内容は指定された image のみで決定される」という前提をこれまで置いてきました。このため、同一の image がコマンドライン引数の設定次第で挙動を変更できるときでも、Knitfab はコマンドライン引数ごとに image をビルドすることを要求してきました。image の再利用性について、柔軟さを欠いていたのです。
今回の変更では、こうした不便さにアプローチしました。
Plan の定義に追加の情報として、annotation とコマンドライン引数が設定できるようになりました。
新しいメタデータ “Annotation” で、Plan そのものについての説明などを記録できるようになりました
Annotation は Plan に設定できる新しいメタデータです。
Plan 定義に追加された annotation というフィールドを使って、Plan に Annotation を登録できます。
image: "example.com/train:v1.0"
annotation: # NEW!
- "key=value"
- "description=annotation can have arbitrary text content"
- "creator=takaoka.youta@opst.co.jp"
inputs:
- ...
outputs:
- ...
...
Annotation は、 Data につけることができる Tag とは異なり、ユーザが任意の情報を Plan に付加するだけのものです。Annotation には、“キー=バリュー”形式で任意のエントリを登録することができます(上例参照)。Knitfab はその内容を参照したり、利用したりしません。
もっぱら、その Plan についての解説(description=...)であるとか、作成者の情報(creator=...)であるとかいった、Plan そのもの、Plan 全体についての情報を記載することを想定しています。もちろん、ここに示したもの以外の annotation をつけていただいてもまったく構いません。
Plan の Annotation は、Run や Data の情報を参照する際にも「どんな Plan に基づいていたか」という情報としてついてくるので、十分な Annotation は Data をモデルカードとして運用することを助けてくれるでしょう。
Annotation は Plan 登録後にも変更可能な情報となっています。v1.4.0 からは、knit plan annotate コマンドで Plan のAnnotation を変更できます。
Plan に image のコマンドライン引数を指定できるようになりました
image: "example.com/train:v1.0"
entrypoint: ["python", "main.py"] # NEW!
args: ["--data", "/in/1/data", "--output", "/out/1/model"] # NEW!
inputs:
- path: /in/1/data
tags:
- "format:image/png"
- "mode:train"
- "type:dataset"
- "project:example"
outputs:
- path: /out/1/model
tags:
- "framework:pytorch"
- "type:model"
- "project:example"
...
これまで Plan の image の挙動は、image をビルドしたとき、Dockerfile に「どんな ENTRYPOINT を指定したか」「どんな CMD を指定したか」で決まってしまっていました。確かに、このデザインでも(image をビルドし直しさえすれば)自由にコマンドライン引数を指定できはしますが、とはいえコマンドライン引数を変更するためだけに再ビルド、というのは、やりたいことに対して手間が大きすぎました。
この変更では、次の 2 つの新しいフィールドを Plan 定義に加え、コマンドライン引数を指定できるようにしました。
entrypoint: Dockerfile の ENTRYPOINT ディレクティブを上書きします
args: Dockerfile の CMD ディレクティブを上書きします
いずれも、指定しなければ、それぞれ image デフォルトの挙動に従うようになっています(つまり、これまでの Plan 定義はこれまでどおりの意味合いのままです!)。
また、 knit plan template により image に基づいた Plan 定義を生成すると、image に指定されていた ENTRYPOINT や CMD が entrypoint フィールドや args フィールドに反映されるようになっています。
Run に関する変更
このリリースでは、Run、というか Run として実行される機械学習タスクの表現力を増す変更を行いました。
ServiceAccount を指定できるようになりました
Knitfab は Kubernets の上に構築されています。Run の機械学習タスクは、Kubernetes 的には Pod として実行されています。
さて、その Kubernetes には ServiceAccount という仕組みがあって、これに Role を関連づけることで Kubernetes API に対する RBAC が実現されています。また、クラウドプラットフォームには、この ServiceAccount とマネージドな権限を対応付けることで、マネージドサービスへのAPIリクエストについての認可制御を行っているものがあります(AWS、 GCP)。
これまで、Run のタスクを実行する Kubernetes Pod に、ServiceAccount を付与することができませんでした。したがって、「Kubernetes API を呼び出したい」であるとか、「クラウドプラットフォームにデプロイされた Knitfab 上で、マネージドサービスを利用したい」であるとかいった要求のある Run を表現できませんでした。
v1.4.0 からは、Run の Pod に付与すべき ServiceAccount を、Plan 定義に指定できるようになります。
image: "example.com/train:v1.0"
inputs:
- ...
outputs:
- ...
service_account: SERVICE_ACCOUNT_NAME # NEW!
...
新規フィールド service_account に ServiceAccount 名を指定すると、この Plan に基づいて生成される Run の Pod は、その ServiceAccount がセットされた状態で起動します。
Plan の service_account は、Plan 登録後にも変更できます。service_account を変更するためには、v1.4.0 から追加された knit plan serviceaccountコマンドをお使いください。
動的に環境変数を注入できるようになりました
ライフサイクルフックから、Run のコンテナに環境変数が注入できるようになりました。
Knitfab には、Run の状態が変化するたびに、事前に指定された WebAPI を呼び出す仕組み(ライフサイクルフック)があります。このうち ”Before Starting”(Run が ready から starting になる直前 = Pod を起動する直前)のタイミングでフックが所定のレスポンスを返すことで、Run として実行される Pod のコンテナに環境変数を設定できるようになりました。
Knitfab が期待しているレスポンスは、次の条件を満たすものです。
Content-Type: application/json ヘッダがある
次の構造を含む json である
{
// ...
"knitfabExtension": {
"env": { [key: string]: string }
}
// ...
}
(型は TypeScript の文法を援用して示しました)
Before Starting のタイミングで、フックから上記のようなレスポンスが返されると、Knitfab は knitfabExtension.envオブジェクトを、キーを環境変数名、値を環境変数の値として解釈して、起動する Pod のコンテナに注入します。
もしフックからのレスポンスが上記の条件を満たさなければ、これまで通り、単に無視されます。
この機能を使えば、Run の内容に応じて動的に環境変数を決定する、といったことができるようになります。たとえば、Run に対応して作成した Knitfab 外のリソース(例: Mlflow の Run)と連携させる、などといったことが実現できるようになりますね。
Data に関する変更
Data の Tag について、操作しやすくする変更をくわえました。
キーに基づいて Tag を削除できるようになりました
これまで、Data の Tag を削除するときには、Tag 全体(キーと値)を正確に指定する必要がありました。これは、Data にはキーが同じ Tag を複数セットできることが理由ですが、値が長大な Tag を削除しようと思うと大変でした。
そこで、 knit data tag コマンドに新しいオプション --remove-key を追加しました。
knit data tag --remove-key KEY KNIT-ID
--remove-key に Tag のキーを指定すると、Data からそのキーをもったタグをすべて削除します。
タグの削除と追加は「削除が先、追加が後」の順序で処理されるようになりました
knit data tag コマンドには、Tag の削除(--remove、 --remove-key)と追加(--add)を同時に指定できます。削除と追加を同時に指定された場合、これまでは「追加が先、削除が後」の順で処理してきました。
たとえば
knit data tag --remove some-key:some-value --add some-key:some-value KNIT-ID
とすると、最終的に Tag some-key:some-value は Data に残りませんでした。
今回の変更では、この順序を改めて、「削除が先、追加が後」とします。v1.4.0 からは、上の例の処理結果は「some-key:some-value は Data についた状態になる」です。
この挙動の変更によって、同一キーの Tag の付け替え操作が一回のコマンドで実現できるようになりました。
たとえば、
knit data tag --remove-key project --add project:example KNIT-ID
とすると、 project: をキーとした Tag を(もしあれば)削除して、新しく project:example タグを追加します。全体として、キー project: のタグの値を上書きしたのと同じ結果になります。
これで Tag のつけ外しの手間が多少削減できるものと思います。
ちなみに、Plan のアノテーションを操作するコマンド knit plan annotate も、同様のフラグを、同様の意味合いでサポートしています。削除と追加の順序も同じです。
まとめ
以上、v1.4.0 のリリース内容でした。詳細な内容や更新手順、最新版の CLI などは、GitHub のリリースページからアクセスできます。
今後も、もっと Knitfab を便利にしてゆくつもりです。どうぞよろしくお願いいたします。