ML MonorepoのPantsでの組織化

Organizing ML Monorepo with Pants

プロジェクト間でユーティリティコードの断片をコピー&ペーストしたことはありますか?結果として、同じコードの複数のバージョンが異なるリポジトリに存在することになりましたか?または、データを保存するGCPバケットの名前が更新された後、数十のプロジェクトに対してプルリクエストを作成する必要がありましたか?

上記のような状況は、MLチームで非常に頻繁に発生し、その結果は単一の開発者の迷惑からチームが必要なようにコードを出荷することができない状況まで様々です。幸いなことに、それには対策があります。

さあ、Googleのような主要なテック企業で広く採用されているモノリポスの世界に飛び込んで、どのようにMLワークフローを向上させることができるかを見ていきましょう。モノリポスは、いくつかの欠点があるものの、複雑な機械学習エコシステムを管理するための魅力的な選択肢になります。

我々はモノリポスの利点と欠点について簡単に議論し、なぜそれが機械学習チームにとって優れたアーキテクチャの選択肢であるのかを調べ、BigTechがそれをどのように使用しているかをのぞいてみます。最後に、Pantsビルドシステムの力を活用して、あなたの機械学習モノリポを堅牢なCI/CDビルドシステムに整理する方法を見てみましょう。

MLプロジェクト管理を効率化するために、この旅に乗り込んでください。

モノリポとは何ですか?

機械学習モノリポ | 出典:著者

モノリポ(モノリシックリポジトリの略)は、多くのプロジェクトのコードが同じリポジトリに格納されるソフトウェア開発戦略です。このアイデアは、様々なプログラミング言語で書かれた会社のすべてのコードが一緒に格納されるほど広範囲なものであるか、小さなチームによって開発された数個のPythonプロジェクトが1つのリポジトリにまとめられるほど狭いものであるか、といった具体例があります。

このブログ記事では、機械学習コードを格納するリポジトリに焦点を当てます。

モノリポ vs. ポリリポ

モノリポは、各個別のプロジェクトやコンポーネントが独自のリポジトリを持つポリリポアプローチとは対照的です。両方のアプローチの利点と欠点については、多くが言及されていますが、ここでは基本的な要点に絞りましょう。

モノリポアーキテクチャの利点は次のとおりです:

モノリポアーキテクチャ | 出典:著者
  • 単一のCI/CDパイプライン:個々のリポジトリごとに分散されたデプロイメントの知識がないため、すべてのコントリビュータが同じパイプラインを使用します。
  • アトミックコミット:すべてのプロジェクトが同じリポジトリに存在するため、開発者は複数のプロジェクトにまたがる変更をクロスプロジェクトで行えますが、1つのコミットとしてマージされます。
  • プロジェクト間でのユーティリティとテンプレートの簡単な共有
  • コーディングの標準化と統一化の容易さ
  • コードの発見性の向上

当然、タダ飯はありません。上記の利点の代償として、以下の形で支払いをする必要があります:

  • 拡張性の課題:コードベースが成長するにつれて、モノリポの管理はますます困難になることがあります。非常に大規模なスケールでの場合、クローニング、プル、プッシュのような操作を処理するために強力なツールとサーバーが必要で、時間とリソースをかなり消費するかもしれません。
  • 複雑さ:モノリポの管理はより複雑になる場合があります。特に依存関係とバージョン管理に関しては、注意が必要です。共有コンポーネントの変更は多くのプロジェクトに影響を与える可能性があるため、破壊的な変更を避けるためには追加の注意が必要です。
  • 可視性とアクセス制御:同じリポジトリで作業する場合、誰が何にアクセスできるかを制御するのは難しい場合があります。ある種の法的な問題が発生する可能性がある場合には、特に問題が発生するかもしれません。

モノリポが提供する利点が価値があるかどうかは、各組織やチームごとに決定する必要があります。ただし、極めて大規模なスケールで作業している場合や、極秘のミッションに取り組んでいる場合を除いては、少なくとも私の専門領域である機械学習プロジェクトに関しては、モノリポはほとんどの場合において良いアーキテクチャの選択肢だと主張します。

それがなぜそうなのかについて話しましょう。

モノレポを使った機械学習

モノレポは機械学習プロジェクトに特に適している理由が少なくとも6つあります。

  • 1
    データパイプラインの統合
  • 2
    実験の一貫性
  • 3
    モデルのバージョニングの簡素化
  • 4
    部門間の協力
  • 5
    アトミックな変更
  • 6
    コーディング基準の統一

データパイプラインの統合

機械学習プロジェクトには、データパイプラインが含まれることがよくあります。これらのパイプラインは、データの前処理、変換、モデルへのデータの供給を行います。これらのパイプラインは、MLコードと密接に統合されている場合があります。データパイプラインとMLコードを同じリポジトリに保持することで、この密接な統合を維持し、ワークフローを効率化することができます。

実験の一貫性

機械学習の開発には多くの実験が含まれます。モノレポにすべての実験を持つことで、一貫した環境設定が確保され、異なる実験間でのコードやデータバージョンの違いによる不整合のリスクが減少します。

モデルのバージョニングの簡素化

モノレポでは、コードとモデルのバージョンが同期されます。これは、同じリポジトリにチェックインされるためです。これにより、モデルのバージョンを管理し追跡することが容易になります。これは特に、MLの再現性が重要なプロジェクトで重要です。任意の時点でのコミットSHAを取得するだけで、すべてのモデルとサービスの状態に関する情報が得られます。

部門間の協力

機械学習プロジェクトには、データサイエンティスト、MLエンジニア、ソフトウェアエンジニアの協力がよく含まれます。モノレポは、プロジェクト関連のすべてのコードとリソースの真実の一元的なソースを提供することで、この部門間の協力を促進します。

アトミックな変更

MLの文脈では、モデルのパフォーマンスはデータの前処理、特徴抽出、モデルアーキテクチャ、ポスト処理などのさまざまな相互に関連する要素に依存する場合があります。モノレポでは、アトミックな変更が可能です。これにより、これらのコンポーネントの複数に変更を行うことができ、依存関係が常に同期されることが保証されます。

コーディング基準の統一

最後に、機械学習チームには、ソフトウェアエンジニアリングのバックグラウンドを持たないメンバーも含まれることがよくあります。これらの数学者、統計学者、計量経済学者は、ビジネスの問題を解決するモデルのトレーニングのスキルを持つ頭の良い人々です。ただし、クリーンで読みやすく、メンテナンスが容易なコードを書くことは、常に彼らの強みではありません。

モノレポは、すべてのプロジェクトに対して自動的にコーディング基準をチェックし、強制することで、高いコード品質を確保するだけでなく、エンジニアリングにあまり関心のないチームメンバーが学び成長するのを助けます。

業界における取り組み:有名なモノレポ

ソフトウェア開発の世界では、世界最大かつ最も成功しているいくつかの企業がモノレポを使用しています。以下にいくつかの注目すべき例を示します。

  • Google:Googleは長年にわたりモノレポのアプローチを支持してきました。推定2,000億行のコードを含むコードベース全体が、1つの巨大なリポジトリに含まれています。彼らはそれについて論文をさえ公開しました。
  • Meta:Metaも広範なコードベースにモノレポを使用しています。彼らは、モノレポのサイズと複雑さを処理するために「Mercurial」というバージョン管理システムを作成しました。
  • Twitter:TwitterはPantsというビルドシステムを使用して、長い間モノレポを管理してきました。次に話すビルドシステムです!

Microsoft、Uber、Airbnb、Stripeなどの他の多くの企業も、少なくとも一部のコードベースでモノレポのアプローチを使用しています。

理論はこれくらいにして、実際に機械学習のモノレポをどのように構築するかを見てみましょう。以前は別々のリポジトリだったものを単に1つのフォルダに入れるだけでは、うまくいきません。

PythonでMLモノレポをセットアップする方法は?

このセクションでは、この記事のために作成したサンプルの機械学習リポジトリを基に議論を展開します。それは、有名なデータセットを使用した手書き数字の分類器であるmnistという単一のプロジェクトまたはモジュールを保持するシンプルなモノレポです。

今すぐ知っておく必要があるのは、モノレポのルートにはmnistというディレクトリがあり、その中にモデルのトレーニングのためのいくつかのPythonコード、対応するユニットテスト、トレーニングをコンテナ内で実行するためのDockerfileが含まれているということです。

シンプルにするために、この小さな例を使用しますが、より大きなモノレポでは、mnistはリポジトリのルートにある多くのプロジェクトフォルダの1つにすぎません。各プロジェクトフォルダには、少なくともソースコード、テスト、Dockerファイル、および要件ファイルが含まれます。

ビルドシステム:なぜ必要で、どのように選ぶべきか?

なぜ必要か?

モノレポ内で異なるプロジェクトを開発している異なるチームが、開発ワークフローの一環としてコード以外のアクションを行うことを考えてみてください。彼らは、コードのスタイル規定に準拠するためにリンターを実行し、ユニットテストを実行し、DockerコンテナやPythonホイールなどのアーティファクトをビルドし、それらを外部アーティファクトリポジトリにプッシュし、本番環境に展開します。

テストについて考えてみましょう。

保守しているユーティリティ関数の変更を行い、テストを実行し、すべてが正常に動作しています。しかし、あなたの変更が他のチームのコードに影響を与えていないことを確認するにはどうすればいいでしょうか? もちろん、彼らのテストスイートも実行する必要があります。

しかし、これを行うためには、変更したコードがどこで使用されているかを正確に知る必要があります。コードベースが成長するにつれて、これを手動で見つけることはスケーラブルではありません。もちろん、代わりにすべてのテストを実行することもできますが、それはスケーラブルではありません。

なぜシステムが必要か:テスト | 出典:著者

別の例本番展開

週ごとに展開する場合でも、毎日展開する場合でも、連続的に展開する場合でも、いつ展開するかが来たら、モノレポ内のすべてのサービスをビルドし、本番環境にプッシュする必要があります。しかし、すべての場合においてそれらをすべてビルドする必要がありますか? それはスケールするにつれて時間とコストがかかるかもしれません。

何週間も更新されていないプロジェクトもあります。一方、それらが使用している共有のユーティリティコードは更新されているかもしれません。何をビルドするかをどのように決定しますか? 再び、依存関係に関係があります。理想的には、最近の変更に影響を受けたサービスのみをビルドする必要があります。

なぜシステムが必要か:展開 | 出典:著者

これらすべては、小さなコードベースを持つ簡単なシェルスクリプトで処理できますが、スケールするにつれて、コード共有が始まり、依存関係管理を中心とするさまざまな課題が浮かび上がります。

適切なシステムを選ぶ

上記のすべては、適切なビルドシステムに投資することで問題ではありません。ビルドシステムの主なタスクはコードのビルドです。そして、開発者はビルドするものを指示するだけでよい(「私の最新のコミットに影響を受けるDockerイメージをビルドする」、「私が更新したメソッドを使用するコードをカバーするテストのみを実行する」など)、具体的なビルド方法はシステムに任せるべきです。

いくつかの優れたオープンソースのビルドシステムがあります。ほとんどの機械学習はPythonで行われるため、Pythonのサポートが最も優れているものに焦点を当てましょう。この点で最も人気のある2つの選択肢はBazelとPantsです。

BazelはGoogleの内部ビルドシステムであるBlazeのオープンソース版です。PantsもBlazeから大きな影響を受けており、Bazelと同様の技術的な設計目標を目指しています。興味のある読者は、このブログ記事でPants vs. Bazelの良い比較を見つけることができます(ただし、Pantsの開発者からのものです)。monorepo.toolsの下部にある表も別の比較を提供しています。

どちらのシステムも優れていますが、ここで「優れた」解決策を宣言する意図はありません。とはいえ、Pantsは設定が簡単で、アプローチしやすく、Pythonに最適化されているとよく言われており、機械学習のモノレポには最適です。

私の個人的な経験では、Pantsを選んだ決定的な要因は、アクティブで助けになるコミュニティです。質問や疑問がある場合は、コミュニティのSlackチャンネルに投稿し、支援的な人々がすぐに助けてくれます。

パンツの紹介

さあ、本題に入りましょう!段階的に進めていきますが、異なるパンツの機能とその実装方法を紹介していきます。関連するサンプルリポジトリはこちらで確認できます。

セットアップ

Pantsはpipでインストールできます。このチュートリアルでは、執筆時点での最新安定版である2.15.1を使用します。

pip install pantsbuild.pants==2.15.1

Pantsは、pants.tomlというグローバルマスターコンフィグファイルを介して設定可能です。このファイルでは、Pants自体の動作や、pytestやmypyのような依存ツールの設定などを行うことができます。

まずは、最小限のpants.tomlから始めましょう:

[GLOBAL]

pants_version = "2.15.1"

backend_packages = [

    "pants.backend.python",

]

[source]

root_patterns = ["/"]

[python]

interpreter_constraints = ["==3.9.*"]

グローバルセクションでは、Pantsのバージョンと必要なバックエンドパッケージを定義します。これらのパッケージは、さまざまな機能をサポートするPantsのエンジンです。初めに、Pythonのバックエンドのみを含めます。

ソースセクションでは、ソースをリポジトリのルートに設定します。バージョン2.15以降、これが取得されるようにするために、リポジトリのルートには空のBUILD_ROOTファイルも追加する必要があります。

最後に、Pythonセクションでは、使用するPythonのバージョンを選択します。Pantsは、ここで指定された条件に一致するバージョンをシステム上で検索し、そのバージョンがインストールされていることを確認します。

これでスタートです!次に、ビルドシステムの中核であるBUILDファイルを見てみましょう。

ビルドファイル

ビルドファイルは、宣言的な方法でターゲット(何をビルドするか)とその依存関係(動作に必要なもの)を定義するための設定ファイルです。

ディレクトリツリーのさまざまなレベルに複数のビルドファイルを持つことができます。ファイルが多ければ多いほど、依存関係の管理が細かくなります。実際に、Googleはリポジトリ内のほとんどのディレクトリにビルドファイルを持っています。

この例では、次の3つのビルドファイルを使用します:

  • mnist/BUILD – プロジェクトディレクトリ内のこのビルドファイルでは、プロジェクトのPythonの依存関係とビルドするためのDockerコンテナを定義します。
  • mnist/src/BUILD – ソースコードディレクトリ内のこのビルドファイルでは、Pythonのソース(つまり、Python固有のチェック対象となるファイル)を定義します。
  • mnist/tests/BUILD – テストディレクトリ内のこのビルドファイルでは、Pytestで実行するファイルとこれらのテストを実行するために必要な依存関係を定義します。

mnist/src/BUILDを見てみましょう:

python_sources(

    name="python",

    resolve="mnist",

    sources=["**/*.py"],

)

同時に、mnist/BUILDは次のようになります:

python_requirements(

    name="reqs",

    source="requirements.txt",

    resolve="mnist",

)

ビルドファイル内の2つのエントリは、ターゲットと呼ばれます。まず、Pythonソースターゲットがあります。これをpythonと呼ぶことにしましたが、名前は何でも構いません。Pythonのソースは、ディレクトリ内のすべての.pyファイルと定義します。これはビルドファイルの場所に相対的です。つまり、mnist/srcディレクトリの外にPythonファイルがあっても、これらのソースはmnist/srcフォルダの内容のみをキャプチャします。resolveフィールドについては、後ほど説明します。

次に、Pythonの依存関係ターゲットがあります。これは、PantsがPythonコードを実行するために必要な要件を見つける場所を指定します(再度、ビルドファイルの場所に相対的です。この場合はmnistプロジェクトのルートになります)。

これで開始するには十分です。ビルドファイルの定義が正しいことを確認するために、次のコマンドを実行しましょう:

pants tailor --check update-build-files --check ::

予想通り、「BUILDファイルに必要な変更は見つかりませんでした。」という出力が得られます。良いですね!

このコマンドについてもう少し説明しましょう。要するに、裸のpants tailorコマンドは自動的にビルドファイルを作成することができます。ただし、必要以上に追加する傾向があるため、私は通常、手動で追加した後に上記のコマンドで正確性をチェックします。

末尾の二重セミコロンは、Pantsの表記法で、コマンドをモノリポ全体に対して実行するように指示しています。代わりにmnist:に置き換えることもでき、mnistモジュールに対してのみ実行することができます。

依存関係とロックファイル

効率的な依存関係管理を行うために、Pantsはロックファイルを利用しています。ロックファイルは、各プロジェクトで使用されるすべての依存関係の特定のバージョンとソースを記録します。これには、直接の依存関係と推移的な依存関係の両方が含まれます。

ロックファイルは、この情報をキャプチャすることで、異なる環境とビルドで一貫して同じバージョンの依存関係が使用されることを保証します。つまり、それらは依存関係グラフのスナップショットとして機能し、ビルド間の再現性と一貫性を確保します。

mnistモジュールのためのロックファイルを生成するには、次のpants.tomlへの追加が必要です:

[python]
interpreter_constraints = ["==3.9.*"]
enable_resolves = true
default_resolve = "mnist"

[python.resolves]
mnist = "mnist/mnist.lock"

私たちはresolves(ロックファイルの環境というPantsの用語)を有効にし、mnistに対してファイルパスを渡して定義します。また、デフォルトの解決方法として選択します。これはPythonソースとPythonの依存関係ターゲットに以前渡した解決方法です。これにより、必要な依存関係が何かを知ることができます。これで次のコマンドを実行できます:

pants generate-lockfiles

次の結果が得られます:

Completed: Generate lockfile for mnist
Wrote lockfile for the resolve `mnist` to mnist/mnist.lock

これにより、mnist/mnist.lockというファイルが作成されます。このファイルは、リモートのCI/CDでPantsを使用する場合にはgitでチェックする必要があります。そして当然ですが、requirements.txtファイルを更新するたびに更新する必要があります。

モノリポに複数のプロジェクトがある場合、ロックファイルは必要なプロジェクトのために選択的に生成した方が良いでしょう。例えば、pants generate-lockfiles mnist: を使用します。

セットアップは以上です!では、Pantsを使って何か有用な作業をしましょう。

Pantsを使ったコードスタイルの統一

Pantsは、Black、yapf、Docformatter、Autoflake、Flake8、isort、Pyupgrade、またはBanditなどのPythonのリンターやコードフォーマッターツールをネイティブでサポートしています。これらはすべて同じ方法で使用されます。この例では、BlackとDocformatterを実装しましょう。

そのために、適切な2つのバックエンドをpants.tomlに追加します:

[GLOBAL]
pants_version = "2.15.1"
colors = true
backend_packages = [
    "pants.backend.python",
    "pants.backend.python.lint.docformatter",
    "pants.backend.python.lint.black",
]

もしそれぞれのツールを設定したい場合は、追加のセクションをtomlファイルに以下のように追加することもできますが、今はデフォルトのままにしましょう。

フォーマッターを使用するには、Pantsゴールと呼ばれるものを実行する必要があります。この場合、2つのゴールが関連しています。

まず、lintゴールは両方のツール(バックエンドパッケージのリストにリストされた順番で、つまり先にDocformatter、次にBlack)をチェックモードで実行します。

pants lint ::

Completed: Format with docformatter - docformatter made no changes.
Completed: Format with Black - black made no changes.

✓ black succeeded.
✓ docformatter succeeded.

コードが両方のフォーマッタの基準に準拠しているようです!ただし、そうでない場合は、適切にコードを適合させるためにfmt(”format”の略)ゴールを実行することができます:

pants fmt ::

実際には、これらの2つのフォーマッタ以上を使用したい場合があります。その場合、各フォーマッタの設定を更新して、他のフォーマッタと互換性があることを確認する必要があります。たとえば、ここでデフォルトの設定でBlackを使用している場合、コード行が88文字を超えないことを期待します。

しかし、その後でimportを自動的にソートするためにisortを追加したい場合、それらは衝突します:isortは79文字を超えた後に行を切り詰めます。isortをBlackと互換性のあるものにするには、次のセクションをtomlファイルに含める必要があります:

[isort]
args = [
    "-l=88",
 ]

すべてのフォーマッタは、pants.tomlで同じ方法で設定することができます。それぞれのフォーマッタの基になるツールに引数を渡すことで設定できます。

パンツでのテスト

テストを実行してみましょう!これには2つのステップが必要です。

まず、pants.tomlに適切なセクションを追加します:

[test]
output = "all"
report = false
use_coverage = true

[coverage-py]
global_report = true

[pytest]
args = ["-vv", "-s", "-W ignore::DeprecationWarning", "--no-header"]

これらの設定により、テストが実行される際にテストカバレッジレポートが生成されます。また、pytestの出力を適応するためにいくつかのカスタムオプションも渡しています。

次に、mnist/tests/BUILDファイルに戻り、Pythonテストのターゲットを追加する必要があります:

python_tests(
    name="tests",
    resolve="mnist",
    sources=["test_*.py"],
)

これをテストと呼び、使用するresolve(つまり、lockfile)を指定します。ソースはテストを実行するためにpytestが検索する場所であり、ここでは「test_」で始まるすべての.pyファイルを明示的に渡しています。

これで実行できます:

pants test ::

結果は以下の通りです:


✓ mnist/tests/test_data.py:../tests は 3.83 秒で成功しました。
✓ mnist/tests/test_model.py:../tests は 2.26 秒で成功しました。

Name                               Stmts   Miss  Cover
------------------------------------------------------
__global_coverage__/no-op-exe.py       0      0   100%
mnist/src/data.py                     14      0   100%
mnist/src/model.py                    15      0   100%
mnist/tests/test_data.py              21      1    95%
mnist/tests/test_model.py             20      1    95%
------------------------------------------------------
TOTAL                                 70      2    97%

ご覧の通り、このテストスイートを実行するのに約3秒かかりました。もしもう一度実行すると、結果がすぐに表示されます:

✓ mnist/tests/test_data.py:../tests は 3.83 秒で成功しました(メモ化)。
✓ mnist/tests/test_model.py:../tests は 2.26 秒で成功しました(メモ化)。

Pantsはこれらの結果がメモ化(またはキャッシュされた)であることを示しています。テスト、テストされるコード、または要件に変更がないため、テストを実際に再実行する必要はありません-結果は同じであることが保証されているため、キャッシュから提供されるだけです。

パンツでの静的型チェック

さらに1つのコード品質チェックを追加しましょう。PantsではPythonで静的型をチェックするためにmypyを使用することができます。やることは簡単で、pants.tomlにmypyバックエンドを追加するだけです:”pants.backend.python.typecheck.mypy”。

また、以下の構成セクションも追加することで、mypyの出力をより読みやすく、情報豊富にすることもできます:

[mypy]
args = [
    "--ignore-missing-imports",
    "--local-partial-types",
    "--pretty",
    "--color-output",
    "--error-summary",
    "--show-error-codes",
    "--show-error-context",
]

これで、pants check :: を実行すると以下の結果が得られます:

完了:タイプチェック(MyPy)- mypy - mypy は成功しました。
成功:6つのソースファイルに問題はありません

✓ mypy は成功しました。

パンツでのMLモデルの出荷

出荷について話しましょう。ほとんどの機械学習プロジェクトでは、トレーニングデータの処理、モデルのトレーニング、またはFlaskやFastAPIを使用してAPI経由での提供など、1つ以上のDockerコンテナが関与します。このおもちゃプロジェクトでも、モデルトレーニングのためのコンテナがあります。

PantsはDockerイメージの自動ビルドとプッシュをサポートしています。これがどのように機能するか見てみましょう。

まず、pants.tomlにdockerバックエンドを追加します:pants.backend.docker。さらに、環境変数のいくつかとビルド引数も設定します:

[docker]

build_args = ["SHORT_SHA"]

env_vars = ["DOCKER_CONFIG=%(env.HOME)s/.docker", "HOME", "USER", "PATH"]

これで、mnist/BUILDファイルに2つのターゲットを追加します:filesターゲットとdockerイメージターゲット。

files(

    name="module_files",

    sources=["**/*"],

)

docker_image(

    name="train_mnist",

    dependencies=["mnist:module_files"],

    registries=["docker.io"],

    repository="michaloleszak/mnist",

    image_tags=["latest", "{build_args.SHORT_SHA}"],

)

私たちはdockerのターゲットを「train_mnist」と呼んでいます。依存関係として、コンテナに含めるファイルのリストを渡す必要があります。これを行う最も便利な方法は、このリストを別のファイルターゲットとして定義することです。ここでは、単純にmnistプロジェクトのすべてのファイルを「module_files」というターゲットに含め、それをdockerイメージの依存関係として渡します。

もちろん、コンテナで必要なファイルのサブセットだけが必要であることがわかっている場合は、それらだけを依存関係として渡すのが良いアイデアです。これは、これらの依存関係が変更の影響を受け、再ビルドが必要かどうかをPantsが推論するために使用されるためです。ここでは、module_filesがすべてのファイルを含んでいるため、mnistフォルダ内の任意のファイル(readmeさえも!)が変更されると、Pantsはtrain_mnistのdockerイメージがこの変更の影響を受けたとみなします。

最後に、イメージをプッシュできる外部レジストリとリポジトリ、およびプッシュされるタグを設定することもできます。ここでは、パーソナルなdockerhubリポジトリにイメージをプッシュし、常に「latest」と短いコミットSHAとして渡されるタグを使用します。

これにより、イメージをビルドすることができます。最後の一つだけ: Pantsは独自の環境で動作しているため、ホストからの環境変数を読み取ることはできません。したがって、SHORT_SHA変数が必要なイメージをビルドまたはプッシュするには、Pantsコマンドとともにそれを渡す必要があります。

次のようにイメージをビルドできます:

SHORT_SHA=$(git rev-parse --short HEAD) pants package mnist:train_mnist 

結果は次のようになります:

Completed: Building docker image docker.io/michaloleszak/mnist:latest +1 additional tag.
Built docker images: 
  * docker.io/michaloleszak/mnist:latest
  * docker.io/michaloleszak/mnist:0185754

クイックチェックでイメージが実際にビルドされたことがわかります:

docker images 


REPOSITORY            TAG       IMAGE ID       CREATED              SIZE
michaloleszak/mnist   0185754   d86dca9fb037   About a minute ago   3.71GB
michaloleszak/mnist   latest    d86dca9fb037   About a minute ago   3.71GB

Pantsを使用してイメージをビルドしてプッシュすることもできます。必要なのは、パッケージコマンドをパブリッシュコマンドに置き換えるだけです。

SHORT_SHA=$(git rev-parse --short HEAD) pants publish mnist:train_mnist 

これにより、イメージがビルドされ、私のdockerhubにプッシュされました。

Pants in CI/CD

手動で実行したのと同じコマンドをCI/CDパイプラインの一部として実行することもできます。GitHub ActionsやGoogle CloudBuildなどのサービスを介して実行できます。たとえば、特定のフィーチャーブランチがメインブランチにマージされる前のPRチェックとして、またはマージ後に実行して緑色であることを検証し、コンテナをビルドしてプッシュする前に実行できます。

おもちゃのリポジトリでは、git push時にPantsコマンドを実行し、すべてが正常にパスするまで通過させないpre-pushコミットフックを実装しています。その中で、次のコマンドを実行しています:

pants tailor --check update-build-files --check ::
pants lint ::
pants --changed-since=main --changed-dependees=transitive check
pants test ::

pants checkのためのいくつかの新しいフラグを見ることができます。それは、mypyを使用した型チェックです。変更されたファイルとその推移的な依存関係と比較して変更されたファイルのみで実行されることを保証します。これは、mypyが実行に時間がかかる傾向があるため、実行時間を短縮するために必要なものに制限するために役立ちます。

CI/CDパイプラインでのdockerビルドとプッシュはどのようになりますか?次のようになります:

pants --changed-since=HEAD^ --changed-dependees=transitive --filter-target-type=docker_image publish

パブリッシュコマンドは以前と同じですが、3つの追加の引数があります:

  • –changed-since=HEAD^と–changed-dependees=transitiveは、前のコミットとの比較で変更に影響を受けるコンテナのみがビルドされることを確認します。これは、マージ後のメインブランチで実行するために便利です。
  • –filter-target-type=docker_imageは、Pantsがビルドとプッシュのみを行うことを確認します。なぜなら、pants publishコマンドはdocker以外のターゲットも参照できるからです。たとえば、helmチャートをOCIレジストリに公開するために使用することもできます。

同じことはパンツパッケージにも当てはまります:Dockerイメージのビルドだけでなく、Pythonパッケージも作成することができます。そのため、-filter-target-typeオプションを渡すのが良い習慣です。

結論

モノレポは、機械学習チームにとって頻繁に優れたアーキテクチャの選択肢です。ただし、スケールで管理するには適切なビルドシステムへの投資が必要です。そのようなシステムの1つがPantsです:セットアップと使用が簡単であり、機械学習チームがよく使用する多くのPythonおよびDockerの機能にネイティブサポートを提供しています。

さらに、それは大きく助けになるコミュニティを持つオープンソースプロジェクトです。この記事を読んだ後、ぜひ試してみてください。現在モノリシックリポジトリを持っていなくても、Pantsは日常の作業の多くの側面を効率化し、容易にしてくれます!

参考文献

  • Pantsドキュメンテーション:https://www.pantsbuild.org/
  • Pants vs. Bazelブログ記事:https://blog.pantsbuild.org/pants-vs-bazel/
  • monorepo.tools:https://monorepo.tools/

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

人工知能

AIがDevSecOpsを再構築する3つの方法

開発者は、これらの3つのAI駆動のDevSecOpsトレンドを使用して、組織のセキュリティポスチャを評価することができます

AIテクノロジー

「AIサービスへの大胆な進出:億万長者ビンニー・バンサールの大局変革」

テクノロジーと電子商取引の世界では、Binny Bansalの名前はよく知られています。オンライン小売り大手Flipkartの共同創設者...

データサイエンス

「変革を受け入れる:AWSとNVIDIAが創発的なAIとクラウドイノベーションを進める」

Amazon Web ServicesとNVIDIAは、最新の生成AI技術を世界中の企業にもたらします。 AIとクラウドコンピューティングを結び付...

データサイエンス

情報とエントロピー

1948年、数学者のクロード・E・シャノンが「通信の数学的理論」という記事を発表し、機械学習における重要な概念であるエント...

人工知能

「生成型AIのGPT-3.5からGPT-4への移行の道程」

導入 生成型人工知能(AI)領域におけるGPT-3.5からGPT-4への移行は、言語生成と理解の分野での飛躍的な進化を示しています。...

機械学習

ドメイン固有アプリケーションのためのLLM細かい調整戦略

「LLMファインチューニングとは何か、LLMをドメイン特化アプリケーションに適応する方法、ファインチューニングの種類などを...