モジュール開発
ディレクトリ構成
モジュールのディレクトリ構成は以下のような形式を参考としてください。
xdata-algo-modules/
├── module-1/ # 別のモジュールプロジェクトディレクトリ
├── module-2/ # 開発対象モジュールプロジェクトディレクトリ
│ ├── src/ # ソースコードディレクトリ
│ │ ├── definitions/
│ │ │ └── definition.json # モジュール定義情報を記述したファイル
│ │ └── xxxxx.py # モジュール内で動作させるソースコード
│ ├── tests/ # テストコードディレクトリ
│ │ └── test_xxxxx.py # テストコード
│ ├── .flake8 # Flake8設定ファイル
│ ├── xxxxx-ci.yml # GitLab Runnerで実行するジョブの設定ファイル(各モジュール用)
│ ├── docker-compose.yml # モジュール用コンテナを起動するためのdocker-compose.ymlファイル
│ ├── docker-compose.dev.yml # 開発用のdocker-compose.ymlファイル
│ ├── Dockerfile # モジュール実行用のDockerfile
│ ├── Dockerfile.dev # linterやformatter実行用のDockerfile
│ ├── Dockerfile.test # テストコード実行用のDockerfile
│ ├── Makefile # 各種コマンドを定義するファイル
│ ├── pyproject.toml # linterなどの設定ファイル
│ └── requirements.txt # ソースコード実行時に必要なパッケージ一覧を記述するファイル
└── .gitlab-ci.yml # GitLab Runnerを実行するための設定ファイル
モジュール内で動作させるソースコード
モジュール実行時に起動させたいソースコードをsrcディレクトリに配置します。
基本的にPythonで作成しますが、必要に応じて別言語でも作成できます。
definition.json
モジュールをxData-FLで動作させる際の定義情報をsrc/definitions/definition.jsonに記述します。
定義情報に記述する情報は以下のような形式となります。(※未確定要素が多いため今後変更になる可能性あり)
{
"name": "<モジュールの名前.java と同様に FQDN の形式で記述する.これによりモジュールを一意に識別出来るようにする>",
"description": "<モジュールの説明>",
"supports": "<TBD モジュールがサポートする機能を列記する>",
"defisnitions": [
"コメント:<ここにパラメータの型の定義を記述>",
{
"name": "<型の名前.definitions 内で一意である必要がある>",
"description": "<型の説明>",
"definition": {
"type": "<データの種別,model (モデル),*model_set (モデル群)*, data (データ),others (その他)>",
"form": "<file (ファイル),directory (ディレクトリ),STDIN/STDOUT, *type が model_set の場合は directory のみ可*>",
"files": [
"コメント:<form が file の場合,ファイルフォーマットの定義>",
{
"name": "<入出力データの名前(ラベル)>",
"path": "<ディレクトリ内のファイルのパス,ワイルドカードを可とする>",
"form": "<file (ファイル) もしくは directory (ディレクトリ)>",
"files": "<forms が direcotry の場合,ディレクトリ内のファイルを定義>",
"format": {
"": "コメント:<form が file の場合,ファイルフォーマットの定義>",
"type": "ファイルの形式 CSV, JSON, Movie など",
"structure": "<ファイルの形式,ファイル種別に応じて異なる>"
}
}
],
"format": {
"": "コメント:<form が file の場合,ファイルフォーマットの定義>",
"type": "ファイルの形式 CSV, JSON, Movie など",
"structure": "<ファイルの形式,ファイル種別に応じて異なる>"
}
}
}
],
"scripts": [
{
"name": "<スクリプト名(ラベル),Web API を呼ぶ際には別途定義するモジュール名と,このスクリプト名を渡すことで実行したい処理を指定する.スクリプト名はモジュール内でユニークである必要がある.モジュールの name と script の name を組み合わせることで,任意のモジュール群からスクリプトを一意に特定できる>",
"description": "<スクリプトの説明.人間 (もしくは LLM) に読ませるための物>",
"path": "<スクリプトの相対パス,モジュール内に開発者が配置したコードのトップディレクトリからの相対パス>",
"type": "<スクリプトの種別,training (model と data を入力して model を出力), prediction (model と data を入力して data (と model) を出力,prediction しながら model の更新を行うタイプのは別のラベルを振った方がいいかも), aggregation (複数の model を入力して model を出力), model_transformation (model を入力して model を出力), data_transformation (data を入力して data を出力)>",
"input": [
"コメント:<ここに入力データの定義を記述>",
{
"name": "<入出力データの名前(ラベル),Web API を呼ぶ際に各入出力のデータをどの(テーブルから取得|テーブルに保存)するかを指定する.スクリプトの入力/出力の name はユニークである必要がある>",
"description": "<入出力データの説明.人間 (もしくは LLM) に読ませるための物>",
"path": "<入力/出力用のディレクトリ内の相対パス>",
"paramtype": "<パラメータの型の name (文字列) もしくは パラメータの型の定義そのもの(連想配列)>"
}
],
"output": [
"コメント:<ここに出力データの定義を記述>",
{
"name": "<入出力データの名前(ラベル),Web API を呼ぶ際に各入出力のデータをどの(テーブルから取得|テーブルに保存)するかを指定する.スクリプトの入力/出力の name はユニークである必要がある>",
"description": "<入出力データの説明.人間 (もしくは LLM) に読ませるための物>",
"path": "<入力/出力用のディレクトリ内の相対パス>",
"paramtype": "<パラメータの型の name (文字列) もしくは パラメータの型の定義そのもの(連想配列)>"
}
]
}
]
}
モジュール定義情報のJSONファイルの例は以下のようになります。
{
"name": "module.fed-avg-module.aggregate",
"description": "FedAvg aggregate module",
"supports": "",
"definitions": {
"the_model": {
"description": "集約前と集約後のモデル",
"definition": {
"type": "model",
"form": "directory",
"files": [
{
"name": "model_data",
"path": "model.dat.xdata_meta",
"form": "file",
"format": {
"type": "json",
"structure": ""
}
},
{
"name": "model_file",
"path": "model.dat",
"form": "file",
"format": {
"type": "state_dict",
"structure": ""
}
}
]
}
}
},
"scripts": {
"fed_avg_aggregate": {
"description": "FedAvg aggregate",
"path": "aggregate",
"type": "aggregation",
"input": {
"input_model_set": {
"description": "input models",
"path": "models",
"paramtype": {
"type": "model_set",
"form": "directory",
"paramtype": "the_model"
}
}
},
"output": {
"output_model": {
"description": "output models",
"path": "aggregated_model",
"paramtype": "the_model"
}
}
}
}
}
テストコード
ソースコードに対してのテストコードをtestsディレクトリに配置します。
CI/CDを実行するために必要に応じてテスト用のソースコードを作成してください。
.flake8
linterのFlake8を設定するためのファイルです。 以下のような形式で記述します。
[flake8]
max-line-length = 88
extend-ignore = E203,E402
GitLab Runnerで実行するジョブの設定ファイル(各モジュール用)
親階層にある.gitlab-ci.ymlで読み込むタスクを定義するためのYAMLファイルです。
ファイル名は任意で設定してください。ジョブ設定の例は以下のような形式となります。
ジョブ内でファイルパスを指定する際は、親階層からのファイルパス(親階層にある.gitlab-ci.ymlファイルからのパス)を指定する必要があることに注意してください。
fed-avg-lint-format-check:
stage: test
tags:
- cpu
image: python:3.10-slim-bullseye
script:
- cd fed-avg-module/
- pip install --upgrade pip
- pip install --no-cache-dir flake8 black
- flake8 .
- black . --check
fed-avg-unit-test-cpu:
stage: test
tags:
- cpu
image: python:3.10-slim-bullseye
variables:
MODEL_DIR: ./test_models
script:
- cd fed-avg-module/
- pip install --upgrade pip
- pip install --no-cache-dir -r requirements.txt
- pip install --no-cache-dir pytest
- pytest
docker-compose.yml
モジュール用コンテナを起動するためのdocker-compose.ymlファイルです。 以下のような形式で記述します。
version: '3'
services:
aggregate:
build:
context: .
dockerfile: Dockerfile
environment:
MODEL_DIR: ./models
volumes:
- ./mnist_models:/work/models
docker-compose.dev.yml
linterやformatter、テストコードを実行するためのコンテナを起動するためのdocker-compose.ymlファイルです。 以下のようにlinterやformatter、テストコードを実行するためのサービスを記述してください。
version: '3'
services:
test_aggregate:
build:
context: .
dockerfile: Dockerfile.test
environment:
MODEL_DIR: ./models
volumes:
- ./src:/work/src
- ./tests:/work/tests
- ./test_models:/work/models
format:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/work/src
- ./tests:/work/tests
command: black .
lint:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/work/src
- ./tests:/work/tests
command: flake8 .
Dockerfile
モジュール実行・ビルド用のDockerfileです。 以下のような形式で記述します。
FROM python:3.10-slim-bullseye
WORKDIR /work
COPY ./requirements.txt /work/
RUN pip install --no-cache-dir -r requirements.txt
COPY ./src/aggregate.py /work/
CMD ["python", "aggregate.py"]
Dockerfile.dev
linterやformatterなど開発時に必要なツールを起動するためのDockerfileです。 以下はflake8とblackをインストールしたPythonコンテナを起動する例です。
FROM python:3.10-slim-bullseye
RUN pip install --no-cache-dir flake8 black
COPY ./pyproject.toml /work/
COPY ./.flake8 /work/
WORKDIR /work
Dockerfile.test
テストコードを実行するコンテナを起動するためのDockerfileです。 以下はpytestをインストールしたコンテナを起動する例です。
FROM python:3.10-slim-bullseye
COPY ./requirements.txt /work/
WORKDIR /work
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir pytest
CMD ["pytest"]
Makefile
開発時などに必要なコマンドをまとめておくファイルです。 以下のような形式でコマンドをまとめておくと頻繫に利用するコマンドを簡単に利用することができます。
dev/test:
docker compose -f docker-compose.dev.yml run --rm test_aggregate
dev/format:
docker compose -f docker-compose.dev.yml run --rm format
dev/lint:
docker compose -f docker-compose.dev.yml run --rm lint
makeコマンドを利用します。make dev/lintのような形式で利用したいコマンドを指定して実行します。
pyproject.toml
Pythonプロジェクト全体の設定をまとめることができるファイルです。 対応したパッケージの設定を記述することができます。以下の内容はblackの設定例です。
[tool.black]
skip-string-normalization = true
target-version = ['py38']
requirements.txt
ソースコード実行時に必要なパッケージ一覧を記述するファイルです。 以下のような形式で記述します。必要に応じてパッケージのバージョン指定などを行ってください。
fsspec==2023.12.1
torch
torchvision
torchaudio
GitLab Runnerを実行するための設定ファイル(親階層にある.gitlab-ci.yml)
モジュール開発時ディレクトリの1階層上にある.gitlab-ci.ymlファイルです。
GitLab Runnerではこのファイルを読み込み、ジョブを実行します。
各モジュールで定義したジョブを読み込んで実行するには、以下のような形式でファイルを記述します。
stages:
- test
- build
- deploy
default:
tags:
- cpu
include:
- local: fed-avg-module/fed-avg-ci.yml