


分散で動く機械学習の学習・推論のコードを、壊さずに直す
機械学習のモデルを、たくさんのプロセスやアクセラレータで学習・推論させるコードを直す時に使う。危ない変更の前に確認を取り、重みのバージョンをそろえ、すべてのランクで集合通信を同じ順に呼ばせ、設定の互換性を守り、飛ばしたテストを報告する。
このAIルールを使うには
## 編集の前にコードを読み、共有設定や公開APIを変える前に確認を取る
編集前に、関連する実装、近隣のパターン、設定の契約、テストを読む。プロジェクトの環境管理ツール、フォーマッター、リンター、pre-commit一式を使い、フックを迂回しない。
認証情報、マシン固有のパス、サービスエンドポイント、クラスタートポロジを決してハードコードしない。トラブルシューティングの近道として、スケジューラ設定を推測したり、アクセラレータドライバーやランタイム一式を再構築したりしない。
次の操作を行う前に判断を仰ぐ。
- 共有設定の構造を変更する。
- 依存関係を追加する。
- ランチャーまたはスケジューラの動作を変える。
- 公開APIを削除、改名、または非互換に変更する。
必要なハードウェアまたはクラスターへのアクセスがない場合は、どの統合検査を省略したかと、その理由を明示する。未検証の分散処理に関する仮定をコードへ変換してはならない。
作業は、学習エンジン、推論エンジン、アルゴリズム、ランチャー、スケジューラ、データセット、報酬、ワークフロー、分散デバッグのサブシステム別に振り分ける。専用の実装ガイドまたはドメインレビュー経路がある場合は、それを使う。
## 処理ごとの役割を分け、データに重みのバージョンを付ける
オーケストレーション、ロールアウト生成、学習、推論、インフラストラクチャ、モデル適応、報酬、データセット、横断的ユーティリティを、それぞれ独立した責務として保つ。
トレーナーは、ループ、データ読み込み、ワークフローを調整する。ロールアウトワークフローは、非同期のエピソード生成を定義する。推論エンジンは出力を生成して重み更新を受け取り、学習エンジンはロールアウトテンソルを受け取り、更新を計算し、新しい重みバージョンを発行する。
非同期システムでは、生成データと更新に明示的な重みバージョンのメタデータを付ける。暗黙に食い違ったモデルバージョンで学習または評価してはならない。
メトリクスは標準トラッカーを通して記録し、成果物は設定された出力ルート配下へ保存し、チェックポイントには正規の保存・復旧経路を使う。可観測性と復旧は実行契約の一部である。
深い継承よりも合成と委譲を優先する。エンジン、ワークフロー、モデルアダプターを個別にテストできる程度に、拡張境界を小さく保つ。
## デバイスからホストへの同期を避けて、アクセラレータで速く動くコードを書く
所有元モジュールの既存の命名、型付け、ログ記録の規約に従う。型ヒントとインポートを明示し、ワイルドカードインポートは決して使わない。負荷の大きい任意依存は、それを必要とする関数またはコード経路の内部に置く。
生のprintではなく、プロジェクトのロガーを使う。ログレコードにはコンポーネントと分散ランクの文脈を含め、並行して生成されたログ出力の発生元を追跡できるようにする。
アクセラレータのホットパスでは、次を守る。
- ログ記録のためにスカラー値やリスト値を取り出すなど、デバイスからホストへの同期を避ける。
- Pythonで個々の要素をループ処理せず、テンソル演算をバッチ化する。
- デバイスとデータ型を明示的に設定する。
- 境界で想定するテンソル形状をアサートする。
ロールアウトワークフローはブロックしないように保つ。非同期エンジン呼び出しとファイル操作をawaitし、非同期エピソード経路へ同期I/Oを持ち込まない。
新機能では、最も近い既存の動作モジュールのパターンに従い、対象を絞ったテストを追加し、無関係なリファクタリングを避ける。
## 設定の項目と公開APIを、互換性を保ったまま変える
設定フィールドは、必須、一般的な任意、まれな任意、内部用の順に並べる。初期化時に検証し、無効な値または制約を示す明確な例外を返す。
公開フィールドには安全な既定値を設ける。廃止前に非推奨化し、確立済みのフィールド型は変更しない。公開設定クラスには、制約と受け入れる値を記載する。
有限のコマンドライン選択肢は、自由形式の文字列ではなく制約付きの型で表す。並行する別構造を作らず、正規の設定データクラスを再利用する。
共有設定、ランチャー、スケジューラ、公開API名は、影響の大きい変更面として扱う。変更説明で互換性への影響を明示し、破壊的または非互換な編集の前に承認を得る。
現在の契約から正しい動作を決められない場合は、既定値をでっち上げず、対象範囲を明確にした後続対応マーカーを残し、未解決の制約を報告する。
## プロセスグループと集合通信を、すべてのランクでそろえる
インポート時にグローバルプロセスグループを決して作成しない。対象のプロセスグループを明示的に渡し、グループへの所属が重要な場合は、そのグループに対してランクを照会する。
デバイスメッシュの次元を、宣言済みの並列化モデルと一致させる。該当する場合は、データシャーディング、テンソル、コンテキスト、エキスパート、エキスパート・テンソルの各軸を含める。
集合通信は全体に関わる契約である。
- 参加するすべてのランクが、同じall-reduceを同じ順序で呼び出さなければならない。
- sumとmeanなど、リダクション演算を意図して選ぶ。
- broadcastでは送信元ランクを明示する。
- barrierは診断用の道具であり、通常の同期手段ではない。
ハングは集合通信シーケンスの不一致を確認して診断する。誤った結果は、リダクションの意味と重みバージョンを確認して診断する。メモリ不足は、モデルの機能を減らす前に、シャーディング、テンソル配置、デバイスの所有関係を確認して診断する。
詳細な分散処理、通信ライブラリ、同期起動の診断機能は、対象を絞ったデバッグに限って使い、問題を理解した後は取り除くか無効にする。
## 分散のテストを行い、飛ばしたテストをプルリクエストに書く
テスト名には、動作、条件、期待結果を含め、準備、実行、検証の構造にする。低速、非同期、アクセラレータ、分散の各テストに印を付け、標準CIが適切なテスト一式を選択できるようにする。
利用できないアクセラレータテストまたは複数ノードテストは、明示的な理由を添えて適切にスキップする。単体レベルの分散動作にはフレームワークの疑似プロセスグループを使い、テスト対象の意味そのものである深いシャーディングや分散テンソルの内部実装をモックしてはならない。
テンソルは、相対許容誤差と絶対許容誤差を明示して比較する。管理された一時パスと、範囲を限定したモンキーパッチを優先する。
まず対象を絞った単体テスト一式を実行し、ハードウェアが利用できる場合は、直接影響を受けるアクセラレータまたは分散テスト一式を続けて実行する。提出前にフォーマット処理とpre-commit一式をすべて実行する。
コマンドラインの参照文書は正規の生成ツールで作成する。リリース文書は、必要な静的設定とパッケージ化を行うプロジェクトラッパーからビルドし、プロジェクト固有の手順を省く下位レベルの文書コマンドは使わない。
プルリクエストには、課題、リスク領域、正確なテストコマンド、理由付きで省略したテスト一式、ハードウェア上の制限を記載する。コミット件名は慣例に沿った命令形にし、レビュー前に作業途中のコミットを取り除く。
