211 Views
November 14, 25
スライド概要
主に機械学習やブラックボックス最適化などの分野の研究に取り組む学生に向けて,研究に役立つ開発スキルをまとめた資料です.
興味のある領域:強化学習/機械学習/ブラックボックス最適化
研究のための開発スキル 横浜国立大学総合学術高等研究院 白川研究室 IMS客員助教 清水彰馬 1
前置き ◆この資料は横浜国立大学白川研究室の学生向けに 2025年10月末時点での情報をもとに作成された資料に 一部修正を加えたものです ◆想定している読者 • 授業等を通してプログラミングの基礎や Python の基本的な文法を理解している • 機械学習やブラックボックス最適化の研究をしている学生 • 他の分野でも情報系かコンピュータを使った実験を伴う分野であれば参考になるかも ◆この資料では扱わなかった内容 • モデルのデプロイや運用に関する内容 • Docker や Kubernetes などコンテナに関する内容 • 機械学習やブラックボックス最適化そのものに関する内容 2
Outline ◆資料について ◆プロジェクト管理 ◆コーディング技法 ◆MLOps 3
資料について 4
研究における開発スキルの意義 開発スキルは研究の価値を高めるために役立つ! 再現性 実験結果の再現性を高め実装公開や引き継ぎをスムーズに進める 信頼性 実装や実験設定の誤りを排し信頼に足る実験結果を得る 生産性 作業を効率的に進めて少しでも研究成果を増やす 5
再現性 再現に必要なコードや実行環境を適切に管理 • ソースコードを実行可能な状態で保持 • 実験結果を得たときと同じ実行環境を簡単に用意できるようにする 実験設定の管理と再現手順の明確化 • 必要な実験設定を網羅して分かりやすいかたちで保持 • 明快な手順で誰でも同じ結果が得られるようにする 実験に関わる記録を残して論文化していない部分も再現可能に • 予備実験の結果や考察を確認できるようにしておく • 手法や実験設定の考案に関する議論を残しておく 6
信頼性 実装を公開して実験結果の正当性の根拠を増やす • 他人にも理解しやすい整理されたコードを書く • 実験に関わるソースコード以外のファイルも適切に管理 バグを潰して正しい実験結果を得る • 様々なツールを駆使して早期にバグを検出 • バグが生じにくい方法でのコーディング 方針の誤りなどを早期に発見できる土壌を作る • 実験や問題の設定を適切に管理していつでも議論できるようにしておく • 細部まで把握しやすいように実装する 7
生産性 タスクを整理したり並行して進めることで効率アップ • 忘れないようにタスクをリスト化 • ツールを駆使して複数のタスクをスムーズに進める 手作業になっている煩雑なタスクを自動化・効率化 • 実験設定やログの管理を効率的に行う • プログラムの動作確認を自動で行う 整理されたコードで素早く実験を行う • バグを早期に取り尽くして素早く本番の実験に辿り着く • 拡張性の高いコードで実験設定の変更に素早く対応 8
実装の公開について ◆主要な国際会議では実装の公開が推奨されていることが多い • 実装が公開されていないと再現性や信頼性が低くなるため 論文のインパクトを大きくしたいなら公開した方が良い • 実装の公開を推奨している国際会議や論文誌の例 • NeurIPS, ICLR, TMLR, GECCO • 査読時の評価項目に含まれている場合もある • ICML 2025 Author Instructions: Authors are encouraged to submit code to foster reproducibility. Reproducibility of results and easy availability of code will be taken into account in the decision-making process. ◆公開するつもりで普段から実装していればクオリティも上がるかも 9
資料の意図 研究作業を進める上での引き出しを作る・選択肢を増やす ◆具体的なツールの名前や使い方よりはそれぞれの概念の概要を理解する • その上で現時点で有力と考えているツールの軽い紹介もする ◆必要なときに必要なツールを選べるようになる • ツールには流行り廃りがあり新しいものもどんどん出てくる • ツールの必要性・有用性を認識しツール選びの取っ掛かりにする ◆開発スキルについて普段から意識できるようになる • スキルは急には身に付かないしいきなり完璧には使えない • 今後使ってみたり試してみたりして少しずつ身に付けていってほしい 10
プロジェクト管理 11
プロジェクト管理 ◆ソースコード管理 • 再現に必要なコードの保持 • 複数プロジェクトの同時進行 • 複数マシンでの作業 [1] https://github.com/pallets/flask ◆タスク管理 • 議論の可視化 • 引き継ぎや共有に便利 • 作業効率アップ [2] https://github.com/pallets/flask/issues 12
ソースコード管理 13
ソースコードの管理 バージョン管理 • ソースコードの変更履歴の管理 • 複数人・複数マシンでの編集時に 発生する競合の解決 パッケージ管理 • 依存ライブラリの管理 • 仮想環境や Python のバージョンも 管理できるものも存在 [3] https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow [4] https://docs.astral.sh/uv/concepts/projects/dependencies/#project-dependencies 14
ソースコードの管理 バージョン管理 • ソースコードの変更履歴の管理 • 複数人・複数マシンでの編集時に 発生する競合の解決 パッケージ管理 • 依存ライブラリの管理 • 仮想環境や Python のバージョンも 管理できるものも存在 [3] https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow [4] https://docs.astral.sh/uv/concepts/projects/dependencies/#project-dependencies 15
バージョン管理システム (VCS) 変更履歴の管理 変更履歴を保持することで 様々な機能を提供 • 変更内容の確認 • 過去の状態の復元 AAAA XXXX CCCC DDDD AAAA BBBB CCCC DDDD 2行目を更新 4行目を削除 複数人での並行作業 複数人・複数マシンでの同時並行 作業を可能にするとともに それらの変更を矛盾なくマージ Git, Subversion, Perforce, etc. AAAA XXXX CCCC DDDD 変更を統合 16
研究におけるバージョン管理の意義 ◆実装時・研究室内 • 複数のマシンでの作業 • 複数プロジェクトの 同時進行 • 実験結果とソースコードの バージョンの紐づけ • 実装箇所の明示 • デバッグ 複数マシンでの作業 複数プロジェクトの同時進行 実験結果とソースコードの バージョンの紐づけ 実装箇所の明示 ◆実装の公開 • 論文に使用した バージョンの明示 • 公開後メンテナンスする 場合の修正箇所の明示 [5] https://github.com/astralsh/uv/commit/c826f2b042c78af0b58e1a27c43b8 a5603a0f2b3 17
Git を用いたバージョン管理 Git: 主要な VCS の一つ ローカルとリモートで分散して管理 リポジトリ:変更を管理する場所 • リモートリポジトリ: 専用のサーバに配置される 複数人での共有も可能 • ローカルリポジトリ: 個人が手元で作業するための場所 • push: ローカルの変更をリモートに送信 • pull: リモートの変更をローカルに取得 GitHub, GitLab, Bitbucket, Codeberg, etc. pull リモートリポジトリ push pull push ローカル リポジトリ ローカル リポジトリ commit commit コミット:変更を記録する単位 • 前回からの差分が記録される 18
Git: コミットの流れ ◆ワーキングツリー上で ファイルを編集 ◆編集した内容をインデックスに 登録(ステージする) ◆インデックスに登録されている 内容を変更として確定 インデックスを挟むことで 不要な変更を含めず 適度な量にまとめることが可能 Local Working Tree add Index (Staging Area) commit pull Remote Repository push Repository 19
Git: メッセージとコミットの粒度 コミットメッセージ ◆変更内容を説明するメッセージを記入可能 • git commit –m “<message>” ◆メッセージの書き方 • 変更内容が一行で具体的に想像できるようにする • 例:Semantic Commit Messages • GitHub 等では issue の番号を記入して関連付けが可能 コミットの粒度 ◆一つのコミットは一つの変更に対応させる • メッセージを書くとき「◯◯の追加と××の修正」など長くなるのは良くない ◆なるべくこまめにコミット • コミットが小さすぎるのも良くないが大きすぎるよりはマシ 20
Git: 不要なファイルの除外 ◆Git での管理から除外する方が望ましいファイルもある • ツールのキャッシュファイルや中間生成物 • バイナリファイルなど差分が確認しにくいもの • サイズが大きいファイル • etc. ◆除外方法 • .gitignore ファイルで除外するファイルを指定できる • Python プロジェクト向けテンプレート • テンプレートにないもので除外すると良いもの • データセット • 実験結果 • ログファイルや可視化のために作成した図 21
Git: ブランチ progress-report 履歴を分岐させ複数の状態を 同時に保持できる機能 main 使い所の例 • 別の作業を同時に進行するとき • 進捗報告と実験用コードの実装等 experiment • 動く状態のコードを保持したまま 追加の実装を進めたいとき • 複数マシンでの同期等 主なコマンド git branch : ブランチの一覧を表示 implement git switch –c <branch> : ブランチを作成 & 切り替え git switch <branch> : ブランチを切り替え git branch –d <branch> : ブランチを削除 git merge <branch> : 指定したブランチを現在のブランチに統合 22
Git: その他の主なコマンド ◆git restore <path> • 変更したファイルを復元 • git restore --staged <path> : 指定したファイルをインデックスから削除 ◆git stash • ワーキングツリー上の変更を一時的に退避 • git stash pop : 退避しておいた変更を再度適用 (LIFO) • git stash list : 退避された変更の一覧を表示 ◆git fetch • リモートリポジトリの状態を取得 ◆git commit --amend • 最新のコミットを修正する 23
Git: デバッグに役立つかもしれないコマンド ◆git blame <path> • 指定したファイルの変更履歴を 行単位で確認できる • バグが混入したコミットの特定など • GitHub 上でも使える ◆git bisect • バグが発生したコミットを 二分探索で特定する • 問題がある状態 (good) と 問題がない状態 (bad) を 簡単に判定できるときに使える [6] https://github.com/pytorch/pytorch/blame/3cfbf98ea9d937d23f3700168b22706c95730 8ce/torch/nn/functional.py • 自動テストと組み合わせて使うほか 手動でも可能 24
ソースコードの管理 バージョン管理 • ソースコードの変更履歴の管理 • 複数人・複数マシンでの編集時に 発生する競合の解決 パッケージ管理 • 依存ライブラリの管理 • 仮想環境や Python のバージョンも 管理できるものも存在 [3] https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow [4] https://docs.astral.sh/uv/concepts/projects/dependencies/#project-dependencies 25
パッケージ管理と仮想環境 パッケージ管理 外部ライブラリのバージョンと依存関係を管理 ライブラリのバージョンが変わると実験結果も変わる 再現性確保に必須 仮想環境 システムから隔離された一時的な実行環境※ 個々の仮想環境には異なるバージョンのライブラリが インストール可能 再現性の向上に貢献する要素 numpy v1.26.0 numpy v2.3.0 torch v2.8.0 optuna v4.5.0 numpy v2.1.0 torch v2.6.0 optuna v4.2.1 • 他のプロジェクトからの適切な分離 • 同じバージョンのライブラリが簡単にインストール可能 ※ここでは Python の実行環境のみが対象 26
uv を用いたパッケージ管理 uv: パッケージ管理 + 仮想環境管理 + Python のバージョン管理 • 他の多くのツールと異なり uv 単体で上記三つの全てが可能 • 他のツールよりも10~100倍高速 ◆主なコマンド • uv init <project_name> : 新規プロジェクトの作成 • uv python install <version> : Python のインストール • uv python pin <version> : 使用する Python のバージョンを指定 • uv add <package_name> : 依存関係の追加(仮想環境へライブラリをインストール) • uv remove <package_name> : 依存関係の削除(仮想環境からライブラリをアンインストール) • uv run <command> : 仮想環境内でコマンドを実行 • uv run python main.py など • 依存関係はコマンド実行時に必要に応じて自動でインストールされる • uv sync : 依存関係のインストール • 通常明示的に実行する必要はない 27
uv のプロジェクト構造 uv init でプロジェクトの雛形が自動生成される 仮想環境の実体 Python のバージョン指定 プロジェクトのメタ情報 依存関係もここに記載 <project_name> ├── .venv │ ├── bin │ ├── lib │ └── pyvenv.cfg ├── .python-version ├── README.md ├── main.py ├── pyproject.toml └── uv.lock 依存関係解決後のライブラリのバージョン プロジェクトの構造には色々なパターンが存在 src/ を挟むか,tests/ をどこに置くかなど 実装を追加 <project_name> ├── .venv │ ├── bin │ ├── lib │ └── pyvenv.cfg ├── <project_name> │ ├── main.py │ └── module1.py ├── tests │ ├── conftest.py │ └── test_module1.py ├── .python-version ├── README.md ├── pyproject.toml └── uv.lock 28
パッケージ管理の他の選択肢 ◆pip (+ venv + pyenv) • venv で仮想環境を作り pip でパッケージをインストールするやり方 • pyenv で Python のバージョンを管理できる ◆Poetry (+ pyenv) • Poetry では仮想環境とパッケージ管理が可能 • Python のバージョン管理は別途 pyenv 等が必要 ◆Pixi • パッケージ管理,仮想環境管理,Python のバージョン管理の全てが可能 • Python 以外の言語のパッケージも扱える • conda-forge と PyPI の両方に対応 その他:Hatch, pdm, Pipenv, conda など ※ rye は開発停止して uv に移行しました 29
タスク管理 30
進捗を可視化・記録しよう 進捗の可視化 ◆タスクが整理され進行度合いが把握しやすくなる ◆他の人が確認でき議論の促進につながる ◆研究室内のゼミ等で流用できる? 進捗の記録 ◆後から見返して思い出せる ◆引き継いだ人が論文等になっていない細かい部分を確認できる ◆上手くいかなかった部分とその理由を残しておける cf. 実験ノート 31
課題管理システム (ITS) 課題のリストを管理するシステム ◆課題の情報 • タイトル,作成者,作成日時,担当者 • 詳細 • ステータス ◆機能 [7] https://redmine.jp/overview/ • 課題同士の関連付け • 進捗度合いの可視化 • スケジュールや締切の設定 • 作業の取り組み状況を分析した図表の作成 • カンバン方式でタスク一覧を表示 [8] https://www.atlassian.com/ja/software/jira/tem plates/project-management-templates 32
チケット駆動開発 (TiDD) 開発における全ての作業はチケットを起票してから行われるという開発方式 • チケット:作業項目や課題などを一単位として切り出したもの ◆原則:チケットなしのコミットや作業は不可 • プログラムの変更内容や作業内容が全てチケットとして可視化される • チケットに議論の履歴が残るためプログラムの変更の意図などが把握しやすい ◆大まかな流れ • タスクを分割して書き出しチケットとして発行 • (チケットをイテレーション単位にまとめる) • タスクを選んで取り組む • 完了したらチケットをクローズ • 他のタスクに取り組む 33
GitHub の機能を使ったタスク管理 Issue Milestones [9] https://github.com/ray-project/ray/issues [10] https://github.com/ray-project/ray/milestones Projects Pull Request [11] https://github.com/orgs/ray-project/projects/79/views/4 [12] https://github.com/ray-project/ray/pulls 34
Issue を使ったタスクの整理 Issue をタスクの整理と進捗のメモに使用 タスクの一覧を書き出す チェックボックスで 細かく作業を分割 概要や関連情報などを 書くのも良い 結果や考察などを スレッドにメモ これらの issues はフィクションです 35
Issue の機能 Labels 属性や状態を 表すタグが 付けられる Sub-issues Type 子 issue を 登録して 階層化できる 種類を表す タグが一つ 付けられる [13] https://github.com/rust-lang/rust/issues/131425 他にも担当者の割当や Projects, Milestone などの設定も可能 36
Issue のテンプレート markdown または yaml で作成したファイルをリポジトリの /.github/ISSUE_TEMPLATE/ 以下に置くとテンプレートとして使用可能 [15] https://github.com/pytorch/pytorch/issues [14] https://github.com/pytorch/ pytorch/tree/main/.github/ISSU E_TEMPLATE [15] https://github.com/pytorch/pytorch/issues issue を新規作成する際に テンプレート選択画面が表示される yaml ではフォームが作れる 37
Milestone を使ったタスクの分類と追跡 複数の issues をまとめて中間目標として分類 Milestone ごとに説明や期限を追加可能 [16] https://github.com/pytorch/pytorch/milestones Milestone の一覧 各 Milestone の進捗状況が表示される [17] https://github.com/pytorch/pytorch/milestone/55 Milestone の説明と issue 一覧 38
Projects を使ったタスクの一覧表示 Issue をプロジェクトに登録すると タスクの計画や進捗追跡に使える様々な機能を使用できる [17] https://github.com/orgs/rust-lang/projects/59/views/1 ◆カンバン方式 • タスクを進捗状況などに応じて 分類して一覧表示できる • issue のステータスと連動可能 [18] https://github.com/orgs/wagtail/projects/16/views/4 ◆ロードマップ • タスクの開始時期と締め切りを 設定してガントチャートのように 表示できる 39
Pull Request と Issue の紐付け 本文に Issue の番号を入れるとメンションできる [20] https://github.com/Farama-Foundation/Gymnasium/issues/1417 メンションされた Issue にはメンション元が表示される [19] https://github.com/Farama-Foundation/Gymnasium/pull/1419 [19] https://github.com/FaramaFoundation/Gymnasium/pull/1419 Development 欄で連動させることも可能 (マージすると自動的に Issue も閉じる) 40
ブランチの切り方 ブランチの運用には様々な方法があるが とりあえず取っ付きやすいやり方から始める ◆プロジェクトごとに切る • 研究テーマ A ,研究テーマ B ,進捗報告など都度ブランチを分ける • コードの実装など作業をする際にそこから更にブランチを切って 作業中のブランチと動く状態のブランチを分ける ◆Issue と紐付ける • Issue に対応したブランチを都度作成する • Issue の作業が完了したらマージしてブランチを削除 ◆慣れてきたら有名なブランチ戦略を試してみる • GitHub Flow など 41
(参考)Pull Request を使ったレビュー GitHub 上でブランチをマージするための機能 マージする前にコードのレビューやテストなどができる [21] https://github.com/Genesis-Embodied-AI/Genesis/pull/1812 コードにコメントを付けたり 改善の提案をしたりできる [21] https://github.com/Genesis-Embodied-AI/Genesis/pull/1812 コミットの度に自動でテスト等を 実行できる 42
詳しく知りたい ◆git • Pro Git book • サル先生の Git 入門 ◆GitHub • Issues のドキュメント ◆ブランチ戦略の紹介記事 ◆Python のプロジェクト構造 43
コーディング技法 44
コーディング技法 ◆可読性と静的解析 • 読みやすいコードを書き,実行前にコードの問題を検出する ◆設計技法 • 拡張性の高いコードで効率的に研究を進める ◆デバッグとパフォーマンスの向上 • 素早く本番の実験に辿り着きより多くの実験を回す 45
可読性と静的解析 46
なぜ可読性が重要か 研究の再現性や信頼性の向上に繋がる ◆実装公開 • コードが読みやすければ再現実験の助けになる • 自分の提案手法を他の人に取り入れてもらいやすくなるかも ◆研究室内での共有 • 自分や研究室メンバーにも読みやすくなりバグが見つけやすくなる • 引き継ぐ人の苦労が減る 47
コーディング規約 ソースコードの書き方を統一するガイドライン 可読性や保守性を高める目的で制定される Python におけるコーディング規約 ◆PEP8 • Python が公式に定めているコーディング規約 • インデントの文字数や変数・関数・クラスの命名規則など ◆Google Python Style Guide • Google が定めているコーディング規約 • PEP8 との重複も多い • Linter の使用や型ヒントの明記を推奨 48
可読性向上に役立つツール コーディング規約に準拠できているか手動で確認するのは大変 自動で整形や解析をしてくれるツールを使う Formatter • コード内の改行やスペースなどを自動で整形するツール • Ruff, Black, autopep8 など Linter • コードを実行前に解析し様々な問題を指摘するツール • コーディングスタイルの問題だけでなく構文エラーやバグも検出可能 • Ruff, Flake8, pycodestyle など 静的型チェッカー • 型ヒントをもとに変数や関数の型が正しいか検査するツール • Pyright, mypy, Pyrefly, ty など 全てエディタと連携可能 49
Ruff Ruff の特徴 ◆一つのツールで Formatter と Linter の両方の役割を果たす ◆既存のツールよりも 10-100 倍程度高速 コマンドの例 ◆format • ruff format : カレントディレクトリ下の全てのファイルを整形 • ruff format <path to file or directory> : 指定したパスにある全てのファイルを整形 ◆lint • ruff check : カレントディレクトリ下のファイルを解析 • ruff check --fix : 上記に加え修正可能なエラーを自動で修正 • ruff check --fix --extend-select I : 上記に加え import 文をソート 50
関数・クラスの説明を書く 関数やクラスの説明はコメントではなく docstring で書く reStructuredText スタイル Google スタイル NumPy スタイル def some_func(a, b): def some_func(a, b): def some_func(a, b): """Summary and description. """One line summary. """One line summary. :param a: Description of a :type a: int :param b: Description of b :type b: str :returns: Description of return value :rtype: bool """ return True Extended description. Extended description. Args: a (int): Description of a b (str): Description of b Parameters ---------a: int Description of a b: str Description of b Returns: bool: Description of return value """ return True Ruff などの Linter でスタイルのチェックが可能 • ruff check --select D Returns ------bool Description of return value """ return True 51
Python ファイル以外のフォーマット インデントのサイズや改行文字の種類など一部はエディタの設定で対応 EditorConfig • ファイルのフォーマットに関するエディタの設定を記述できるツール .editorconfig ファイルをプロジェクトルートに置いて使う • エディタが自動で .editorconfig を読み込み root = true ファイル保存時などに自動で整形される [*] エディタごとの利用方法 • VS Code ではプラグインが必要 • EditorConfig for VS Code • PyCharm, Vim, Helix などではプラグイン不要 .editorconfig end_of_line = lf insert_final_newline = true indent_style = space [*.{js,py}] charset = utf-8 [*.py] indent_size = 4 [*.yml] indent_size = 2 52
Python における型ヒント
型ヒント
◆Python では変数や関数の引数・戻り値などに型を明示的に記述可能
◆静的型チェックやエディタによる補完に利用され
Python 自身は型の確認などは行わず完全に無視する
def some_func(a, b):
c = 3
return f"a + b + c = {a + b + c}"
def some_func(a: int, b: int) -> str:
c: int = 3
return f"a + b + c = {a + b + c}"
型の書き方
◆組み込み型や自分で定義したクラスはそのまま書ける
◆複雑な型を書くときは typing モジュールを使う
◆NumPy や PyTorch のテンソルには jaxtyping を使う
53
静的型チェッカー 以下の二つが主流 mypy ◆歴史が古い ◆型ヒントがない関数は無視 ◆代入による変数の型の変化を 許容しない ◆動作が遅い傾向 Pyright ◆比較的新しめ ◆型ヒントがない関数は自動で推論 ◆代入による変数の型の変化を 許容する ◆動作が速い傾向 多くの挙動はどちらも設定で変更可能 • 型推論の能力などに差はあるがどちらが優れているとは言い切れない • テンソルには beartype などの実行時に動作する型チェッカーの併用を推奨 54
(参考)自然言語の Linter textlint 自然言語で書かれた文章の校正に使える Linter スペルミスや読みにくい文章などをある程度検出できる [22] https://textlint-ja.github.io/textlint-rule-preset-ja-technical-writing/ 文章のチェックに使いたいルールをインストールして使用する • 日本語の文章向けのルールは GitHub で複数公開されている 55
設計技法 56
整理された拡張性の高いコードを書く 綺麗に整理されたコードでバグの混入を防ぐ ◆怪しい箇所を見つけやすくなりバグを予防/早期に発見可能 ◆「バグ」ではないが設定や実装がおかしくなっている部分も 早い段階で気付けるようになる 拡張性の高いコードで追加の実験に迅速に対応する ◆実験設定の変更や新しい手法の追加などが素早くできるようになる ◆査読や卒業/修了時の審査で新しい実験を求められても対応しやすくなる 整理された拡張性の高いコードは実験設定の管理も楽になる ◆実験設定やハイパーパラメータを一箇所にまとめられる ◆実装公開や引き継ぎの際の再現実験の助けになる 57
クラス設計:差し替えたい箇所を考える ◆実験設定の変更などの際に差し替えたい箇所 • データセット • モデル • 前処理 • 損失関数・評価関数 • 最適化アルゴリズム • ハイパーパラメータ • etc. 差し替えたい箇所をクラスとして実装しておくと 少ない労力での差し替えが可能 class Trainer: def __init__( self, model: Model, loss: Loss, ) -> None: self.model = model self.loss = loss def train(self): ... model = MLP() loss = MSELoss() Trainer(model, loss) Trainer.train() model = MLP() loss = HuberLoss() Trainer(model, loss) Trainer.train() 渡す引数を変えるだけで 中身は変えずに済ませたい 58
抽象基底クラス (Abstract Base Class) 差し替えたいコンポーネントは抽象基底クラスを用意して インタフェースを明確にする from abc import ABC, abstractmethod class Loss(ABC): @abstractmethod def forward(self, x: float, y: float) -> float: pass 1. abc モジュールの ABC クラスを継承して 抽象基底クラスを定義 2. @abstractmethod デコレータで 抽象メソッドを明示 class MSELoss(Loss): def forward(self, x: float, y: float) -> float: return (x - y) ** 2 class HuberLoss(Loss): def __init__(self, delta: float = 1.0): self.delta = delta def forward(self, x: float, y: float) -> float: return ( (x - y) ** 2 / 2 if abs(x - y) < self.delta else self.delta * (abs(x - y) - self.delta / 2) ) 3. 子クラスで抽象メソッドを実装 子クラス同士で重複する処理があれば親クラス側で実装しておくと良い 59
リスコフの置換原則 差し替えやすいクラスの実装のために意識すると良い原則 オブジェクト指向で用いられる SOLID 原則の一つ (L) if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g. correctness). [23] https://en.wikipedia.org/wiki/Liskov_substitution_principle ※親クラスのオブジェクトが使われている箇所を その子クラスのオブジェクトに差し替えても問題が発生しないように設計する model = MLP() loss = Loss() Trainer(model, loss) Trainer.train() ここを子クラス (MSELoss, HuberLoss) に置き換えても その後のプログラムの動作に問題が生じないようにする 抽象クラスはインスタンス化できないが仮にできるものとして考える 60
クラスのプロパティ
クラスのカプセル化に便利な機能
インスタンス変数への安全なアクセス方法を提供
class Optimizer:
def __init__(self, lr: float) -> None:
self._lr = lr
@property
def lr(self) -> float:
return self._lr
@lr.setter
def lr(self, v: float) -> None:
if v <= 0:
raise ValueError("lr must be positive")
self._lr = v
opt = Optimizer(lr=0.01)
print(opt.lr)
# -> 0.01
opt.lr = 0.2
print(opt.lr)
# -> 0.2
通常のインスタンス変数と同様に使える
内部では getter/setter が呼ばれている
1. @property デコレータで getter を定義
2. @メソッド名.setter デコレータで setter を定義
setter で値のチェックなどができる
61
dataclass を辞書の代わりに使う インスタンス変数を保持するだけのクラスを作る際に便利な機能 実験設定やハイパーパラメータをもたせるのに使える dataclass を使うメリット • 保持させるデータの構造が明確になる • 型が明記できるので静的型チェックの対象にできる • コンストラクタなどいくつかのメソッドが自動で実装される • frozen=True で簡単にイミュータブルにできる from dataclasses import dataclass @dataclass class ExperimentConfig: lr: float num_epochs: int outdir: str = "./output/" @dataclass デコレータを付ける from dataclasses import dataclass cfg = ExperimentConfig( lr=0.01, num_epochs=100, ) 普通のクラスと同様に インスタンス化できる @dataclass(frozen=True) class ExperimentConfig: lr: float num_epochs: int outdir: str = "./output/" イミュータブルにする場合 62
Pydantic による型検証(バリデーション)
dataclass は代入された変数の型が正しいか実行時に確認しない
実行時に型の正しさを保証したい場合は Pydantic を使う
from pydantic import BaseModel
class ExperimentConfig(BaseModel):
lr: float
num_epochs: int
outdir: str = "./output/"
BaseModel クラスを継承する
cfg = ExperimentConfig(
lr=0.01,
num_epochs=100,
)
dataclass と同様に使える
cfg = ExperimentConfig(
lr="0.01",
num_epochs=100,
) # -> ValidationError
誤った型の値を入れると
例外が送出される
from pydantic import BaseModel, field_validator
class ExperimentConfig(BaseModel):
lr: float
num_epochs: int
outdir: str = "./output/"
@field_validator("lr", mode="after")
@classmethod
def is_positive(cls, value: float) -> float:
if value <= 0:
raise ValueError(
f"{value} is not positive"
)
return value
値が満たすべき条件を独自に追加できる
実行時にデータの型や形式の正しさを検証することを一般にバリデーションと呼ぶ
63
依存性の注入 (Dependency Injection) コードの柔軟性を向上させる設計パターン あるオブジェクト A が別のオブジェクト B に依存している際 A 自身に B を生成させるのではなく外部から A に渡すようにする 依存性の注入を利用するとコードの拡張や実験設定の管理がしやすくなる [24] https://python-dependency-injector.ets-labs.org/introduction/di_in_python.html 64
実験設定をプログラムの外から注入する 実験設定を main 関数の引数にして外から渡せるようにする コマンドライン引数を使ったり yaml ファイルを読み込んだりすれば プログラムを一切変更せずに実験設定を変えられる Pydantic Settings を使えば argparse を使わずとも コマンドライン引数で値を指定できるようになる def main(cfg: ExperimentConfig) -> None: ... from pydantic_settings import BaseSettings, SettingsConfigDict class ExperimentConfig(BaseSettings): model_config = SettingsConfigDict(cli_parse_args=True) lr: float num_epochs: int outdir: str = "./output" BaseModel の代わりに BaseSettings クラスを継承して SettingsConfigDict(cli_parse_args=True) を付け足す if __name__ == "__main__": cfg = ExperimentConfig( lr=0.01, num_epochs=100, outdir="./output/", ) main(cfg) 実験設定を外から main 関数に渡す 使用した実験設定を JSON などにシリアライズしてログと一緒に保存しておくと良い 65
デバッグと パフォーマンスの向上 66
実験をたくさん回すために 早期にバグを潰して回したい実験になるべく早く辿り着く ◆ログ出力をする ◆テストを書く ◆小さい実験から始める ◆デバッガを使う 実行速度を上げて回せる実験の量を増やす ◆高速化の基本:ボトルネックの特定 ◆プロファイラでボトルネックを見つける ◆高速化の様々な手段を知っておく 67
print デバッグからの脱却 様々なツールを駆使して効率的にデバッグしよう print デバッグの問題点 ◆後で print を消す必要がある ◆手作業で実行して 出力を見ないといけない ◆変数の値を網羅的に出力して いちいち確認していたら大変 問題点の解消方法 ◆logging モジュールを使って 出力のレベルをコントロール ◆自動テストで手作業の量を削減 ◆エラー発生時等の変数の値を デバッガを使って出力せず確認 68
logging モジュール デバッグ用の情報やプログラムの実行状況など 実験の趣旨に関係ない情報の出力には logging モジュールが使える logging モジュールの特徴 • 出力のレベルを指定できる • デバッグ時に使う重要でない情報や エラー発生時の重要な情報を識別できる • 出力レベルをコマンドライン引数などで 変更できるようにしておけば デバッグ用出力を消す必要がなくなる • 複数の出力先に同時に出力できる • Handler を複数指定することで 標準出力とファイルなど複数箇所に出力可能 • 設定をファイルなどで記述できる import logging logger = logging.getLogger(__name__) handler = logging.StreamHandler() handler.setLevel(logging.INFO) logger.setLevel(logging.INFO) logger.addHandler(handler) logger.info("some info") logger.debug("for debug") ログレベルに INFO を指定しているため デバッグ用の “for debug” は出力されない • 詳細はドキュメントなどを参照 69
単体テスト 関数やメソッドが正しく動作するか自動で検証する方法 出力のほか例外処理やファイル操作なども対象 単体テストの流れ 1. テストしたい関数等についてあらかじめ テスト用のコードと入出力の組を複数用意しておく 2. テストを実行すると以下の処理が行われる • テストツールが自動で関数を呼び出し 出力が期待されるものと一致しているか確認 • 出力の間違いやエラーがまとめて報告される ※単体テストが書きにくいと感じられる場合は 関数等を単体テストが書きやすい大きさまで分割する 入力 出力 正解 -100 -52.3 -1 0 1 23.4 0 0 -1 0 0 23.4 0 0 0 0 1 23.4 自作の ReLU 関数 70
pytest pytest: Python 用の単体テストフレームワーク relu.py 標準ライブラリの unittest モジュールよりこちらが主流 def my_relu(x: float) -> float: return min(0, x) pytest の基本的な使い方 test_relu.py • テストしたいモジュールに対応したファイルを用意 • ファイル名は test_*.py または *_test.py という形式にする • テストしたい関数ごとにテスト用の関数を用意 • 関数名は test で,クラス名は Test で始める • テスト用の関数の中で assert 文を使って 実装した関数が期待した動作をしているか検証 • @pytest.mark.parametrize で複数の入出力をまとめてテスト可能 • CLI で pytest コマンドを実行 • テスト用のモジュール・関数は指定しなくても自動で検出される 浮動小数点数は誤差を含むので等号で比較してはいけない import math import pytest from relu import my_relu @pytest.mark.parametrize( "test_input,expected", [(-1, 0), (0, 0), (5, 5)], ) # 一つ目と三つ目で落ちる def test_my_relu( test_input: float, expected: float ) -> None: output = my_relu(test_input) assert math.isclose( output, expected, ) 71
pytest の使い方 fixture テストに使う補助用の関数・クラスの定義や ファイルの読み込み等の事前準備に使える機能 ◆使い方 • @pytest.fixture デコレータを付けて関数を定義 • fixture として定義した関数の名前を テスト用関数の引数として指定すると fixture の戻り値が実際の引数として渡される import pytest @pytest.fixture def trainer_modules() -> tuple[Model, Loss]: return MLP(), MSELoss() def test_trainer( trainer_modules: tuple[Model, Loss] ) -> None: model, loss = trainer_modules trainer = Trainer(model, loss) assert trainer.model is model テスト対象の関数やクラスが他のオブジェクトに依存している場合 • 依存オブジェクトを生成するのではなく動作を模倣するモックを作る • モックの作成には標準ライブラリの unittest.mock か pytest-mock モジュールを使う • モジュールの比較はこのコメントなどを参照 72
テストしにくい部分のデバッグ 機械学習や最適化では単体テストしにくい処理が頻出 ◆確率的なアルゴリズムで正解の出力を用意しにくい ➢型や shape ,例外処理だけでもテストする ➢シードを固定してテストできる場合は固定する • PyTorch の場合の固定の仕方 ➢複数回実行して統計的な挙動を見る ◆学習部分のロジックなど単体テスト自体がしにくい ➢1エポックだけ,非常に簡単なデータなど小さい実験で動作確認 ➢怪しい箇所ではデバッガを使って変数の状態を確認 73
デバッガ コードを一行ずつ実行したり途中で一時停止/再開したりできるツール 変数の中身を確認したり書き換えたりすることも可能 ◆エディタ付属のデバッガを使う • VS Code や PyCharm には デバッガが付属している • 実行中の行の確認や ブレークポイントの設定が エディタから直接できる ◆pdb を使う • Python 標準ライブラリに 含まれているデバッガ • コード内で breakpoint() 関数を 呼ぶことで起動できる [25] https://code.visualstudio.com/docs/python/debugging 74
コードの実行速度の向上 高速化の基本はボトルネックの特定 • 最も時間が掛かっている処理から 高速化する func_a() func_b() 2倍高速化 2倍高速化 • cf. アムダールの法則 • プロファイラを使って特定する 特定後の高速化の方法 • テンソル演算に書き直す • JIT コンパイル • 並列化する • 高速なライブラリに置き換える • 高速な言語で書き直す • 高速なデータ構造やアルゴリズムに 置き換える func_a() func_b() 実行時間が長い処理を高速化する方が 全体の実行時間を短くできる 75
プロファイラ プログラムの実行時間やメモリの占有量などの情報を分析できるツール プロファイラによって得意なことが異なるので使い分けが必要 • pyinstrument • ボトルネックの特定に特化したプロファイラ • 非同期処理等にも対応 • Line Profiler • 行単位でのプロファイルができる • マルチプロセスや GPU コードなどには非対応 • torch.profiler • PyTorch 用のプロファイラ • cProfile • Python 標準ライブラリに含まれるプロファイラ • 関数の呼び出し回数などを厳密に測定できる • 非同期処理や C 言語で書かれたモジュールなどには非対応 76
高速化の方法 高速な実装が 公開されている? 高速な実装を使う GPU に載せる 参考:Tuning Guide テンソル演算で 書ける? テンソルで実装する 参考:Tensor Puzzles GPU に載る? NumPy で 実装されている? Numba で JIT コンパイル 並列化できる? 並列化する multiprocessing など YES NO 高速な言語/アルゴリズム/ データ構造などを検討 77
(参考)Continuous Integration (CI) コードの変更を頻繁にメインラインに統合していく手法 コードの品質を保ち素早く統合することを目的として コミットの度にビルドやテストを自動で実行する ◆GitHub Actions を使った CI • GitHub 上のリポジトリにコミットやマージをする際に Formatter の適用やテスト,Linter の実行が自動でできる • GitHub Actions で Python のテストなどを行う方法 • GitHub Actions で Ruff を使う方法 78
詳しく知りたい ◆SOLID 原則完全に理解した!になるための本 ◆logging モジュールに関する Qiita 記事 • Pythonでprintを卒業してログ出力をいい感じにする • ログ出力のための print と import logging はやめてほしい ◆pytest の使い方 ◆リーダブルコード 79
MLOps 80
MLOps とは 機械学習のワークフローを自動化・簡素化するための実践的な手法 一般的なコーディング/エンジニアリングの技術に加えて AI 研究に特有の部分にも効率的な手法を取り入れることで 実験の効率化や再現性の向上を目指す • 名前に ML とあるが最適化の研究でも活用可能 • 一般的にはモデルの自動デプロイや運用中の品質監視/改善も含まれるが ここでは実験管理に関する部分のみ扱う 81
MLOps で実現したいこと ハイパーパラメータ 最適化 実験設定の管理 実験管理 ハイパーパラメータを 最適化する 実験の設定や ハイパーパラメータの管理 実験ログの管理と 可視化や検索 Optuna Hydra Ax MLflow Weights & Biases 82
Hydra: 実験設定の管理 Hydra: 設定の管理と柔軟な変更のためのライブラリ yaml ファイルを用いて階層的な設定を構築できる Hydra の利点 • コマンドラインからオーバーライドできる • 複数の実験設定での実験(グリッドサーチなど)が簡単にできる • 出力用のディレクトリやログファイルが自動で作られる • dataclass と組み合わせると実行時の型チェックも可能 • プラグインで HPO との連携も可能 Hydra の注意点 • ワーキングディレクトリが変わる • Pydantic には未対応なので組み合わせにはひと手間必要 83
Hydra の使用例 ◆基本的な使い方 • yaml ファイルを用意 • @hydra.main デコレータを 付けて引数で設定を受け取る ◆コマンド実行例 • そのまま実行 python main.py • loss を Huber loss に変更 python main.py loss=huber • loss と optimizer の 全組み合わせを実行 python main.py -m loss=mse,huber optimizer=sgd,adam • 複数 seed の実験を回す python main.py -m experiment.seed=”range(0,10)” ./ ├─ main.py └─ conf/ ├─ config.yaml ├─ loss/ │ ├─ mse.yaml │ └─ huber.yaml └─ optimizer/ ├─ sgd.yaml └─ adam.yaml from omegaconf import DictConfig import hydra @hydra.main( version_base=None, config_path="conf", config_name="config", ) def main(cfg: DictConfig) -> None: ... if __name__ == "__main__": main() defaults: - loss: mse - optimizer: sgd - _self_ config.yaml experiment: seed: 0 num_epochs: 100 name: mse reduction: mean loss/mse.yaml name: huber reduction: mean delta: 1.0 loss/huber.yaml name: sgd optimizer/sgd.yaml lr: 0.001 weight_decay: 0.0 nesterov: false name: adam optimizer/adam.yaml lr: 0.001 betas: [0.9, 0.999] eps: 1.0e-8 84
Hydra の HPO 用プラグイン Hydra の Sweeper Plugin を使うと Optuna, Ax, Nevergrad といった 最適化ライブラリを用いたハイパーパラメータ最適化が可能 from omegaconf import DictConfig ◆使用手順 import hydra 1. @hydra.main の関数から評価値を返すように変更 • 最大化か最小化かは設定で変えられる 2. 探索空間と最適化アルゴリズムの設定を用意 • 設定方法はドキュメントや各プラグインのサンプルを参照 3. Hydra の sweeper を optuna や ax などに変えて Multi-run モードで実行 • python main.py -m hydra/sweeper=optuna 4. Hydra の出力ディレクトリに結果が保存される @hydra.main( version_base=None, config_path="conf", config_name="config", ) def main(cfg: DictConfig) -> float: x, y = 1, 2 return x**2 + y**2 if __name__ == "__main__": main() Optuna の Pruner はサポートされていないので使いたい場合は工夫が必要(参考リンク) 85
実験管理(トラッキング) 実験中の各種指標の推移と使用したハイパーパラメータを記録し それらを検索・取得する API やインタラクティブな GUI などを提供する 実験結果の管理を助けるツール [26] https://mlflow.org/docs/latest/ml/tracking/ [27] https://docs.wandb.ai/models/track 86
MLflow を使った実験管理 基本的な使い方 1. 実験スクリプトを with mlflow.start_run() の 中に入れる 2. ハイパーパラメータを mlflow.log_param() で, 各種指標を mlflow.log_metric() で記録する 3. 結果が保存される • デフォルトの出力先は ./mlruns/ 結果の確認 • コマンドラインから mlflow ui コマンドを 実行するとサーバが立ち上がり ブラウザから実験結果の一覧を確認できる import mlflow def experiment(num_epochs: int) -> None: loss = 100 for _ in range(num_epochs): loss -= 1 mlflow.log_metric("loss", loss) def main(num_epochs: int) -> None: with mlflow.start_run(): mlflow.log_param("num_epochs", num_epochs) experiment(num_epochs) if __name__ == "__main__": main(num_epochs=100) • デフォルトでは http://localhost:5000 87
MLflow のログをプログラムで取得 基本的な流れ import mlflow • MlflowClient クラスの search_runs() メソッドで実験一覧を取得 client = mlflow.tracking.MlflowClient() experiment_id = "0" runs = client.search_runs(experiment_id) for run in runs: print(run.data.metrics) • ハイパーパラメータや実験日,タグなどの 条件でフィルタを掛けられる(参考リンク) • run.data.metrics で学習の最終結果を取得できる • 学習中の推移が必要な場合は MlflowClient の get_metric_history() メソッドを使う 右のような関数を用意して 各 run ごとに指標を取得し DataFrame などに変換する MLflow のクエリは重いので 繰り返し使う実験結果は CSV などに保存しておくと 後で楽になる import mlflow import pandas as pd def convert_metric_history_to_dataframe(client, run, keys, param_keys): run_id = run.info.run_id df = pd.DataFrame() for key in keys: history = client.get_metric_history(run_id=run_id, key=key) df = pd.concat([df, pd.DataFrame({key: [m.value for m in history]})], axis=1) df["run_id"] = run_id for param_key in param_keys: df[param_key] = run.data.params[param_key] return df 88
MLflow と Hydra を組み合わせる際の注意点
• Hydra が自動生成するファイル(実験設定やログファイルなど)を
mlflow.log_artifact() で記録しておく
• mlflow.log_param() は
階層的な設定に非対応なので
右のような関数を用意して
再帰的に記録すると良い
from typing import Union
import mlflow
from omegaconf import DictConfig, ListConfig, OmegaConf
def log_params_from_dictconfig(params: DictConfig) -> None:
def _log_recursively(parent: str, child: Union[DictConfig, ListConfig]):
if OmegaConf.is_dict(child):
for key, value in child.items():
if OmegaConf.is_dict(value) or OmegaConf.is_list(value):
_log_recursively(f"{parent}.{key}", value)
else:
mlflow.log_param(f"{parent}.{key}", value)
elif OmegaConf.is_list(child):
for i, value in enumerate(child):
mlflow.log_param(f"{parent}.{i}", value)
for key, value in params.items():
_log_recursively(key, value)
[28] https://ymym3412.hatenablog.com/entry/2020/02/09/034644 を参考に作成
89
Weights and Biases (WandB) を使った実験管理
SaaS 型のプラットフォームであり利用にはアカウントが必要
登録後コマンドラインで wandb login コマンドを実行してから利用する
基本的な使い方
MLflow と概ね同じように使える
1. 実験スクリプトを with wandb.init() の中に入れる
ハイパーパラメータは config 引数で渡しておく
2. 各種指標を wandb.Run オブジェクトの
log() メソッドで記録する
• Run オブジェクトは wandb.run でも取得可能
3. 結果が保存される
結果の確認
• WandB のサイトにアクセスして web で確認する
ローカルでは結果を確認できないので注意
import wandb
from wandb import Run
def experiment(num_epochs: int, run: Run) -> None:
loss = 100
for _ in range(num_epochs):
loss -= 1
run.log({"loss": loss})
def main(num_epochs: int) -> None:
with wandb.init(
project="my-experiments",
config={"num_epochs": num_epochs},
) as run:
experiment(num_epochs, run)
if __name__ == "__main__":
main(num_epochs=100)
90
WandB のログをプログラムで取得 基本的な流れ ログの取得には Public API を使う • wandb.Api クラスの runs() メソッドで実験一覧を取得 • MLflow と同様フィルタを掛けられる(参考リンク) • 取得した Runs オブジェクトの histories() メソッドで指標の推移の一部を取得可能 • 各 Run ごとに一定の数をサンプルしたものが返される • 全ての結果が欲しい場合は各 Run で scan_history() メソッドを使う • ハイパーパラメータは各 Run オブジェクトの config 属性で保持されている • 階層的になっている場合もあるので DataFrame のカラム等に使用する場合は flatten する import wandb api = wandb.Api(timeout=29) runs = api.runs(path="my-entity/my-project") print(runs.histories()) for run in runs: for row in run.scan_history(keys=["loss"]): print(row) 91
WandB を使ったハイパーパラメータ最適化
Sweeps を使えばハイパーパラメータ最適化が可能
基本的な流れ
ログに記録された指標を見て最適化
されるので戻り値の変更等は不要
1. wandb.sweep() に HPO の設定を
渡して初期化
2. wandb.agent() に sweep の ID と
実行したい関数を渡して開始
対応アルゴリズム
• 最適化アルゴリズム
• ランダムサーチ,グリッドサーチ,
ベイズ最適化
• Hyperband
import wandb
def main() -> None:
with wandb.init(project="my-sweeps") as run:
loss = experiment(
lr=run.config.lr,
optimizer=run.config.optimizer,
)
run.log({"loss": loss})
if __name__ == "__main__":
sweep_cfg = {
"method": "random",
"metric": {"goal": "minimize", "name": "loss"},
"parameters": {
"lr": {"max": 0.1, "min": 0.0001},
"optimizer": {"values": ["sgd", "adam"]},
},
}
sweep_id = wandb.sweep(sweep=sweep_cfg, project="my-sweeps")
wandb.agent(sweep_id, function=main, count=10)
92
MLflow と WandB の比較 MLflow WandB ハイパーパラメータ最適化 x o ローカルのみでの使用 o x GUI の動作 重め 軽め 可視化機能 シンプル 高機能 料金 無料 一部無料 その他の事項 • WandB は web から GUI にアクセスするので 実験の途中経過などをどこからでも確認できる • 実験結果は確認可能なかたちで長期保存する必要があるので WandB 単体での使用は避けた方が無難かも 93
その他の実験管理ツール ◆Neptune.ai • SaaS 型 ◆Comet • SaaS 型 ◆Trackio • ローカルでも動作する • Hugging Face 製 ◆Sacred • ローカルでも動作する 94
参考:機械学習パイプライン 「データ読み込み→データ前処理→モデルの学習→モデルの評価」 といった機械学習の一連の処理の流れをまとめて行えるようにする仕組み 処理をまとめて実行する仕組みだけでなく 一連の処理を整理して実装するための枠組みやパイプラインの可視化機能なども提供 主要なツール • Scikit-learn Pipeline • Kedro • Flyte • Prefect • ZenML [29] https://kedro.org/#features 95
詳しく知りたい ◆小さく始めて大きく育てるMLOps2020 ◆Neptune.ai による MLOps ツール紹介記事 • 13 Best Tools for ML Experiment Tracking and Management in 2025 • Best Machine Learning Workflow and Pipeline Orchestration Tools 96
出典 [1] Pallets. ”flask.” GitHub, 2025-11-10, https://github.com/pallets/flask. [2] Pallets. ”Issues pallets/flask.” GitHub, 2025-11-10, https://github.com/pallets/flask/issues. [3] Atlassian. “Gitflow ワークフロー.” Atlassian, 2025-11-10, https://www.atlassian.com/ja/git/tutorials/comparing-workflows/gitflow-workflow. [4] Astral. “Managing dependencies.” uv, 2025-11-10, https://docs.astral.sh/uv/concepts/projects/dependencies/#project-dependencies. [5] Astral. “Commit c826f2b.” GitHub, 2025-11-10, https://github.com/astral-sh/uv/commit/c826f2b042c78af0b58e1a27c43b8a5603a0f2b3. [6] PyTorch. “pytorch/torch/nn/functional.py.” GitHub, 2025-11-10, https://github.com/pytorch/pytorch/blame/3cfbf98ea9d937d23f3700168b22706c957308ce/torch/nn/func tional.py. [7] ファーエンドテクノロジー株式会社. “Redmineとは.” Redmine.JP, 2025-11-10, https://redmine.jp/overview/. [8] Atlassian. “Jiraプロジェクト管理テンプレート.” Atlassian, 2025-11-10, https://www.atlassian.com/ja/software/jira/templates/project-management-templates. [9] ray-project. “Issues ray-project/ray.” GitHub, 2025-11-10, https://github.com/ray-project/ray/issues. 97
出典 [10] ray-project. “Milestones.” GitHub, 2025-11-10, https://github.com/ray-project/ray/milestones. [11] ray-project. “K8s and Ray (go/k8s-ray-oss).” GitHub, 2025-11-10, https://github.com/orgs/rayproject/projects/79/views/4. [12] ray-project. “Pull requests ray-project/ray.” GitHub, 2025-11-10, https://github.com/rayproject/ray/pulls. [13] rust-lang. “Tracking Issue for compiletest directive handling bugs and papercuts.” GitHub, 2025-11-12, https://github.com/rust-lang/rust/issues/131425. [14] PyTorch. “pytorch/.github/ISSUE_TEMPLATE.” GitHub, 2025-11-12, https://github.com/pytorch/pytorch/tree/main/.github/ISSUE_TEMPLATE. [15] PyTorch. “Issues pytorch/pytorch.” GitHub, 2025-11-12, https://github.com/pytorch/pytorch/issues. [16] PyTorch. “Milestones pytorch/pytorch.” GitHub, 2025-11-12, https://github.com/pytorch/pytorch/milestones. [17] rust-lang. “Lazy Type Aliases (LTA).” GitHub, 2025-11-12, https://github.com/orgs/rustlang/projects/59/views/1. [18] Wagtail. “Wagtail public roadmap.” GitHub, 2025-11-12, https://github.com/orgs/wagtail/projects/16/views/4. 98
出典 [19] Farama-Foundation. “[Bugfix] fixed step() function in AsyncVectorEnv from hanging forever.” GitHub, 2025-11-12, https://github.com/Farama-Foundation/Gymnasium/pull/1419. [20] Farama-Foundation. “[Bug]AsyncVectorEnv.step_await is blocked infinitely if actions.shape[0] < num_envs.” GitHub, 2025-11-12, https://github.com/Farama-Foundation/Gymnasium/issues/1417. [21] Genesis-Embodied-AI. “[MISC] Import math module instead of constants to avoid violating gstaichi pure checker.” GitHub, 2025-11-12, https://github.com/Genesis-Embodied-AI/Genesis/pull/1812. [22] textlint-ja. “textlint-rule-preset-ja-technical-writing-example.” textlint-rule-preset-ja-technical-writingexample, 2025-11-13, https://textlint-ja.github.io/textlint-rule-preset-ja-technical-writing/. [23] Wikipedia. “Liskov substitution principle.” Wikipedia, 2025-11-13, https://en.wikipedia.org/wiki/Liskov_substitution_principle. [24] Roman Mogylatov. “Dependency injection and inversion of control in Python.” Dependency Injector, 2025-11-13, https://python-dependency-injector.ets-labs.org/introduction/di_in_python.html. [25] Microsoft. “Python debugging in VS Code.” Visual Studio Code documentation, 2025-11-13, https://code.visualstudio.com/docs/python/debugging. [26] MLflow Project. “MLflow Tracking.” MLflow Documentation, 2025-11-13, https://mlflow.org/docs/latest/ml/tracking/. 99
出典 [27] Weights & Biases. “Experiments overview.” Weights & Biases Documentation, 2025-11-13, https://docs.wandb.ai/models/track. [28] ymym3412. “ハイパラ管理のすすめ -ハイパーパラメータをHydra+MLflowで管理しよう-.” やむやむ もやむなし, 2025-11-13, https://ymym3412.hatenablog.com/entry/2020/02/09/034644. [29] LF AI & Data Foundation. “Kedro | An open-source framework for data science code.” kedro, 2025-1113, https://kedro.org/#features. 100