📓

JupyterLab利用プロジェクトをGitで管理する方法比較

2024/03/30に公開

TL;DR

楽に設定するだけならば次のような選択でいいと思います。

入っていないようならば以下2つの拡張機能を入れる。

  • jupyterlab-git : JupyterLab上でGitのGUI操作を可能にする
  • nbdime-jupyterlab : ノートブック形式の差分を見やすくする

JupyterLabのみで編集していくならば

  • jupyterlab-jupytext 拡張機能をインストールしペア設定を行う
  • .gitignore でノートブックファイル本体を管理対象から外す

VSCodeなど他の環境でも編集するならば

  • nbstripout ライブラリを利用して 自動的に出力セルの内容を削除 させる

はじめに

プログラミングにおいて、Gitなどのバージョン管理システムによるコードの管理は有用であるという前提があります。この前提は、複数人で進めるプロジェクトだけでなく、一人で行うプロジェクトにおいても当てはまります。多くの開発者がこの考えを共有していると思います。

JupyterLabを利用するプロジェクトでも、Gitを利用することで次のようなメリットを享受できます。

  • チームメンバーの間で簡単にコードを共有できる
  • バージョンごとの差分を簡単に確認できる
  • 「特定のバージョンまで戻す」といった操作が可能になる
  • プルリクエストで変更を扱うことで、変更への心理的障壁を下げられる

しかしながら、個人的にJupyterLabを使用するにあたっては、以下の3つの問題からGitを利用したコード管理に踏み切れないことが多々ありました。

  1. JupyterLab上でGitコマンドを実行するのが面倒
  2. 非エンジニアにも使いやすいインターフェースが必要
  3. 出力セルの内容が差分に現れ、煩雑になりがち

この記事では、個人的な用途を前提としつつ、JupyterLabプロジェクトをGitで管理する際の方法を複数比較し、それぞれの条件に適した選択肢を提案することを目的とします。

環境

JupyterLabについてはDockerの jupyter/minimal-notebook:2023-10-20 イメージを利用しています。Dockerを利用したJupyterLabの起動・アクセス方法については必要に応じて調べてください。

  • Git: 2.34.1
  • JupyterLab: 4.0.7
  • Python: 3.11.6、3.11.7
  • VSCode: 1.87.2
  • パッケージ管理: conda (for jupyter), rye(for VScode)

紹介ライブラリ

以下、Python 3.11 with conda環境で起動しているJupyterLabでのインストール方法を含む、比較対象のライブラリについての情報を挙げていきます。

jupyterlab-git

  • URL: GitHub - jupyterlab/jupyterlab-git
  • インストール方法: jupyterlab-git 拡張機能、あるいは conda install -c conda-forge jupyterlab jupyterlab-git でインストールし、サーバー再起動
  • 説明: JupyterLabのためのGit拡張機能で、GUIを通じてバージョン管理機能を提供しています。ユーザーはJupyterLab内で直接Git操作ができ、コミットやブランチの管理などが可能になります。

JupyterLabの上でコミット、プッシュ、プル、ブランチ作成といった基本的なGitコマンドを実行できます。拡張機能をインストールできる・再起動が可能な環境であるならばインストールしてしまっていいものでしょう。

GUI上での操作となるため、非エンジニアなどコマンドラインでの操作に慣れないメンバーにとって親しみやすく、必須級のものかと思います。

インストールに成功している場合、リポジトリ未設定のフォルダにいる状態でGitらしいメニューをクリックすることで次のようなメニューが出てきます。
リポジトリ未設定状態での表示例

GitをGUIで扱えるようにするだけなので、今回この拡張機能は評価対象としません。

nbdime

  • URL: GitHub - jupyter/nbdime
  • インストール方法: nbdime-jupyterlab 拡張機能あるいは conda install nbdime -c conda-forge
  • 説明: Jupyterノートブックの差分とマージを扱うためのツール。コマンドラインやウェブインターフェースを通じてノートブックの変更点を視覚的に比較できる。

ノートブック形式の差分を人間に見やすいように表示してくれる機能をメインで使っていくであろうツールです。管理対象にノートブック形式を含めるならばあったほうが便利なものでしょう。

拡張機能でインストールした場合は上部の git ボタンを押して表示される差分について自動的に適用されます。差分表示の例を2枚目の画像に掲載します。見ての通り、出力セルの内容に差分がある場合は出力セルの差分も表示されます。

git履歴で差分を表示するボタン
nbdimeを利用したJupyterLab上での差分表示の例

差分を見やすくする機能が主なツールなので、今回は評価対象外とします。

Jupytext

  • URL: PyPI - jupytext
  • インストール方法: jupyterlab-jupytext 拡張機能、あるいは conda install jupytext -c conda-forge
  • 説明: JupyterノートブックをMarkdown文書やPythonスクリプトなどのプレーンテキスト形式に変換するツール。バージョン管理が容易になり、IDEでの編集も可能になる。

ノートブック形式とペアとなるスクリプトを作成できます。ペアのフォーマットはPythonスクリプトやMarkdownなど複数あります。また、RのカーネルなどPython以外のノートブックでも利用できます。

PythonやMarkdownといった、各種ツールでシンタックスハイライトが適用される形式でノートブックファイルを管理できることは、Jupytextの最大の利点です。これにより、GitHubなどのGitホスティングサービスを利用している際に、差分を確認するのが非常に容易になります。

JupyterLab上で編集する場合はノートブックファイル・スクリプトファイルどちらを変更した場合でももう一方にも適切に反映されます。
VSCode上で利用する場合は別途VSCode用の拡張機能のインストールが必要&ノートブック形式を直接編集するとペアでの矛盾を起こせるので注意が必要です。
VSCodeで利用する場合はファイルエクスプローラー上でスクリプトファイルを右クリックし Open as a Jupyter Notebook を選択する必要があります。

Jupytertextの利用方法

検証・動作確認用にjupytextを設定したサンプルリポジトリを作成してあります。
以下の手順はこのリポジトリを作成するときの作業を元に記述しました。

なお、このリポジトリはクローンしてすぐに利用できるよう以下の設定を行っています。

  • VSCode用としてDev Containers
  • JupyterLabでの動作確認として起動用Dockerコマンドの記述
    興味がありましたら実際に試してみてください。

最初にリポジトリを作るときの作業

(ライブラリのインストールは環境ごとの方法で行うこと)

  1. 拡張機能 Jupytextをインストールする
  2. コマンドパレットから、 Pair Notebook with から始まるコマンドを利用してペア設定を行う
    • こだわりがないのならば persent Script で良さそう
  3. ノートブックファイルをGitで管理するか決める
    • 管理しない場合は .gitignore に記載する
  4. 動作を確認しリモートリポジトリへ同期する

「対象フォルダを限定する」や「ノートブックファイルとPythonスクリプトのフォルダを分ける」といった指定を行いたい場合はリポジトリに jupytext.toml を作成するか、 pyproject.toml に設定を記載する必要があります。

サンプルとして、 persent Script 形式で出力されたスクリプトを挙げます。

# -*- coding: utf-8 -*-
# ---
# jupyter:
#   jupytext:
#     custom_cell_magics: kql
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.11.2
#   kernelspec:
#     display_name: Python 3 (ipykernel)
#     language: python
#     name: python3
# ---

# %%
# %load_ext autoreload
# %autoreload 2

# %%
import sys
sys.path.append('../src')  # srcディレクトリへの相対パスを追加

# %%
from data_loader import load_iris_data
from models import train_logistic_regression
from visualizations import plot_pairplot, plot_heatmap
from utils import split_data
from evaluation import evaluate_model

# Load and preprocess data
df = load_iris_data()

# Visualize data
plot_pairplot(df)
plot_heatmap(df)

# Split data into train and test sets
X_train, X_test, y_train, y_test = split_data(df)

# Train and evaluate models
lr_model = train_logistic_regression(X_train, y_train)
lr_accuracy, lr_report = evaluate_model(lr_model, X_test, y_test)
print(f"Logistic Regression Accuracy: {lr_accuracy}")
print(f"Logistic Regression Report:\n{lr_report}")

クローンして利用するときの作業

(ライブラリ・拡張機能のインストールは環境ごとの方法で行うこと)
特になし

nbstripout

  • URL: GitHub - kynan/nbstripout
  • インストール方法: GitHubのリポジトリから直接インストールする必要がある。pip install git+https://github.com/kynan/nbstripout
  • 説明: Jupyterノートブックから出力セルを削除するためのツール。ノートブックを軽量化し、バージョン管理に適した形式にする。コミット時に自動的に動作させることも可能。

ご存知のように、ノートブックの出力セルには画像や表など、差分を管理し辛いものが数多くあります。このライブラリを利用して出力セルを自動的に削除することで、GithubなどのGitホスティングサービス上での差分管理を比較的容易に行うことができます。

あくまで出力セルの内容が削除されるだけで、ファイルタイプはJSON形式であり、入力セルに書かれたPythonはJSONの文字列として格納されています。そのためGithubなどのGitホスティングサービス上での差分閲覧時にはシンタックスハイライトが当たらないなど多少の難があります。

ノートブックファイルをコミットするときに自動的に適用されるフィルターを登録する以外にも、コマンドラインから特定のファイルを指定して実行することもできます。

nbstripoutの利用方法

検証・動作確認用にnbstripoutを設定したサンプルリポジトリを作成してあります。
以下の手順はこのリポジトリを作成するときの作業を元に記述しました。

なお、このリポジトリはクローンしてすぐに利用できるよう以下の設定を行っています。

  • VSCode用としてDev Containers
  • JupyterLabでの動作確認として起動用Dockerコマンドの記述
    興味がありましたら実際に試してみてください。

最初にリポジトリを作るときの作業

(ライブラリのインストールは環境ごとの方法で行うこと)

  1. nbstripoutをインストールする
  2. nbstripout --install --attributes .gitattributes を実行し、フィルターのインストールと設定を行う
  3. 動作を確認しリモートトリポジトリと同期する

動作確認として、出力セルのあるノートブックを作成してコミット後、ブランチの内容を確認し出力セルの内容が含まれていないことを確認してください。
注意点として、ワークツリーのファイルについては出力セルの中身は削除されません。

この方法で設定した場合、すべての箇所のノートブックファイルについて出力セルを削除した状態でコミットされます。出力セルの削除を特定のディレクトリなどに限定したい場合は .gitattributes ファイルを編集する必要があります。

クローンして利用するときの作業

(ライブラリ・拡張機能のインストールは環境ごとの方法で行うこと)

  1. nbstripout --install --attributes .gitattributes を実行する

nbdev

  • URL: GitHub - fastai/nbdev
  • インストール方法: pip install nbdev
  • 説明: Jupyterノートブックを使用して、ドキュメント、テスト、パッケージを含む完全なPythonプロジェクトを開発するためのシステム。ノートブックから直接ソフトウェア開発の全工程を行える。

完全なプロジェクトを作成するためのライブラリなので今回は名前と概要のみ紹介します。ライブラリとしての公開まで視野にいれるなら検討しても良さげなライブラリです。

1. バージョン管理

1.1 環境差異の吸収(JupyterLab and VSCode)

Jupytextの場合

  • ノートブックファイルはGit管理対象から外す
  • JupyterLab上ではノートブック、.pyファイルどちらを編集しても良い
  • VSCodeではPythonファイルを右クリックし Open as a Jupyter Notebook から編集
  • 新規ノートブックファイルの作成はJupyterLab上でのみ行うことを推奨
  • コミット時にノートブックファイルの出力セルの内容が自動的に消えることはない

VSCodeでのメニュー

新規ノートブックファイルの作成はJupyterLab上でのみ行うことを推奨

こちらについて補足しておきます。
VSCode上で新規にノートブックファイル(とペアになるスクリプト)を作成する手順がひと手間多く、各人に強制するのが難しいのではないかと想定しているためです。具体的な手順は以下のとおりです。

  1. 空の新規Pythonファイルを(何らかの方法で)作成する
  2. 右クリックから Open as a Jupyter Notebook で開く

nbstripoutの場合

  • コミット時に実行するよう設定
    • .gitattributes に設定するコマンドがある( nbstripout --install --attributes .gitattributes
  • .gitattributes はそのまま共有可能なため、一人が管理できるならば後はインストール用のノートブックファイルを配布するだけで良い
  • コミットされる内容とワークツリーのファイル内容が異なる事があるため注意が必要

1.2 出力を差分に含めない事ができるか

Jupytextの場合

  • ノートブックファイル自体を含めない対応なら可能
  • ノートブックファイルも管理対象にしつつ出力セルを含めたくない場合はnbstripoutを併用する

nbstripoutの場合

  • 出力セルを差分に含めないためのライブラリ
  • 自動実行を設定したリポジトリでは、差分に含めるようにするための手間が大きい

2. ユーザービリティ

2.1 非エンジニアでも扱いやすいインターフェースがあるか

  • 拡張機能のインストールは非エンジニアにとってどこまで辛いことか評価できないので不明
  • いずれの方法でも初期設定をすることで自動的にライブラリの利用対象にする方法がある
  • Github上での差分が見やすいのはJupytext(Python形式なのでハイライトが効く)
  • インターフェースについて、VSCodeでも編集する場合はnbstripoutが良いかもしれない(右クリックからファイルを開くと言った操作が不要)
    • 操作方法を強制できる or ノートブック形式は管理対象外にするならばどちらでも良さそう

拡張機能をインストールする場合、初期状態のJupyterLabではまず警告画面がでます。
拡張機能インストール前の警告

これにYesを押して進んだ後に、検索窓に適切な検索語(今回は git )を入力し、検索結果フレームから対象の拡張機能(今回は上から3つ目)を選びインストールします。
検索結果画面

この操作が世間一般にとってどの程度難しいことなのかわからないため、難易度不明としました。

2.2 初期設定の簡単さ

  • いずれの方法でも初期設定を行うには一定程度コマンドライン操作に親しんでいたほうが良い
  • テンプレートリポジトリをクローンするだけで設定ファイルを配置できるようにすると便利

Jupytextの場合

  • 拡張機能をインストールする
  • jupytext.toml もしくは pyproject.toml でペア設定を管理できる
  • 特定フォルダについてのみペア設定を適用する運用も可能
    • work 配下は個人名などをつけてノートブック形式のまま管理する、などの運用

nbstripoutの場合

  • conda などでライブラリをインストールする
  • nbstripout --install --attributes .gitattributesでリポジトリにフィルターをインストールする
  • .gitattributes の記述を修正することで特定フォルダについてのみ出力を削除させることが可能

まとめ

この記事では、JupyterLabプロジェクトをGitで管理する際の課題を解決するためにnbdimeやJupytext、nbstripoutといったツールを比較してきました。

nbdimeは、ノートブック形式の差分を人間にとって見やすい形で表示するツールであり、ノートブックファイルをGitで管理する際に便利です。

Jupytextは、JupyterノートブックとPythonスクリプトなどのプレーンテキスト形式とのペアリングを可能にます。
さらに、各ツールでのシンタックスハイライトが効きやすいPythonなどの標準的な形式が出力されます。そのため、各ツールやGitホスティングサービスでの差分表示が見やすいという特徴があります。ただし、新規ノートブックの作成はJupyterLab上で行うことが推奨されます。

nbstripoutは、コミット時にノートブックから出力セルを自動的に削除することで、Gitでの差分管理を容易にします。ただし、コミットされる内容とワークツリーのファイル内容が異なる点に注意が必要です。nbstripoutはあくまで出力セルの内容が削除するのみであり、ファイルタイプはJSON形式のままです。ノートブックの標準的な形式通り、入力セルに書かれたPythonはJSONの文字列として格納されています。そのためGithubなどのGitホスティングサービス上での差分閲覧には多少の難があります。

これらのツールを適切に組み合わせることで、JupyterLabプロジェクトのGit管理における課題を解決し、効率的な開発を行うことができます。ただし、ツールの導入にはある程度のコマンドライン操作に関する知識が必要となります。組織内で統一した方針がある場合、 .gitattributejupytext.toml を適切に設定済みのテンプレートリポジトリを作成するのも良いかもしれません。

VSCodeとの連携も考慮する場合は、通常の編集手順を変える必要がないという点でnbstripoutがよい選択肢となるかもしれません。

この記事が、JupyterLabプロジェクトのGit管理に関する理解を深め、適切なツールの選択と活用に役立てば幸いです。サンプルリポジトリも提供しているので、実際に手を動かして試してみることをお勧めします。

Discussion