MMdetectionの環境が作れないお前！俺に付いてこい。

Grounding DINOの学習環境を作るのに1日かかったので記録に残しておくぞ。
mim系環境構築で良い思いをしたことが無い。本当に。

条件：
- MMdetection用のDockerコンテナを作る
- Grounding DINOが滞り無く動くことを目指す(多分これが動けばどのモデルも動くよ)
- Ubuntu 22.04
- GPU環境 (RTX6000 Ada x2)
- Nvidia Dockerとかは入ってる前提
- 面倒なので全てのファイルを同一ディレクトリ下に置いた前提で進める

まず`Dockerfile`に以下を書く。ベースのイメージは別のでもいいけど、変なバグ踏みたくなければ同じものを推奨。
1行目以下はMMdetectionにはあまり関係ない。
開発もコンテナ内で行う(Devcontainer)のでインストールパッケージが色々入ってますがよしなにしてください。
あと`requrements.txt`もある前提ですがこれも各自で消すなりなんなり。
```Dockerfile
FROM pytorch/pytorch:2.4.1-cuda11.8-cudnn9-devel

# 開発自体に必要なパッケージ
RUN apt-get update -y \
    && apt-get upgrade -y \
    && apt-get autoremove -y \
    && apt-get install -y software-properties-common \
    && add-apt-repository ppa:git-core/ppa \
    && apt-get update -y

RUN apt-get install -y git \
    vim \
    wget \
    make

# アップデートしないと、opencv系でエラーが起きる時があるため
RUN apt-get install -y libgl1-mesa-dev libglib2.0-0

# pythonのパッケージ
COPY requirements.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt
```

この時、間違っても**以下の内容をDockerfileに含めてはならない**。こいつらは動作環境(コンテナ構築時)を読み取って勝手にCPUのバージョンをインストールしやがる。
```bash
# このコードを使うな！更に下に説明有り
pip install -U openmim
mim install mmengine
mim install "mmcv>=2.0.0" # <- ココ罠
```
対策は、コンテナを立ち上げて[GPU環境のターミナルの状態で実行する](https://anton0825.hatenablog.com/entry/2022/02/05/000000)こと。

とりあえずその説明は後にして、こんな`docker-compose.yaml`を作っておく。
※`${DOCKER_MOUNT_ROOT}`などの部分は`.env`に記載。各自設定すること。
```yaml
version: '3'
services:
  grounding-dino:
    build:
      dockerfile: Dockerfile
    volumes:
      - ${LOCAL_MOUNT_ROOT}:${DOCKER_MOUNT_ROOT}
    ports:
      - ${PORT}:${PORT}
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              capabilities: [gpu]
    tty: true
    stdin_open: true
    ipc: host
    container_name: ${CONTAINER_NAME}
    environment:
      - TZ=Asia/Tokyo
      - NVIDIA_VISIBLE_DEVICES=all
```

でこいつを`Makefile`から立ち上げる。そこで同時にコンテナ立ち上げた後に必要なインストールを記載しておく。(ここがこの記事の一番価値があるとこ)
なお、grounding-dinoの部分はコンテナ名なので各自で指定。あと`/path/to/mmdetection`も。
```Makefile
run:
	docker compose up  -d --build
	docker exec -it grounding-dino pip install -U openmim
	docker exec -it grounding-dino mim install mmengine
	docker exec -it grounding-dino mim install "mmcv<2.2.0"
	docker exec -it grounding-dino pip install -v -e /path/to/mmdetection
	docker exec -it grounding-dino mim install mmdet[multimodal]
	docker exec -it grounding-dino python3 -c "import nltk; nltk.download('punkt_tab'); nltk.download('averaged_perceptron_tagger_eng')"
```

ハマリポイント：
- まずmmcv>=2.0.0が[チュートリアルに書かれている推奨コード](https://mmdetection.readthedocs.io/en/latest/get_started.html)だが、これをやると2.2.0が入ってmmdet動かないとか言い始めるので[mmcv<2.2.0にする](https://qiita.com/takekappa/items/46e94507f5a01abf3b14)
- 一番最後のnltkのやつも結局やるハメになるのでここに入れておく([これはGrounding DINOを動かす場合のみ必要](https://github.com/open-mmlab/mmdetection/blob/main/configs/mm_grounding_dino/usage.md#download-nltk-weight))
- numpy入れるなら1系じゃないとどっかでバグる(requrements.txtでの書き方は`numpy<2`が良い)
- opencv-python入れるなら[opencv-python==4.9.0.80](https://qiita.com/ryoma-jp/items/b7e05e31cf48cc00eb87)にするか、バグが起きてから[手動でコメントアウト](https://qiita.com/ballemech/items/e32d8db300bdc788755a)して解決

本当は`Dockerfile`に明示的にGPU用のmmcvが入るように指定できれば良いと思うが、動けば何でも良いのでそこまでは調べていない。
[[追記] 環境変数設定すると行けるそうです。](https://x.com/yumion7488/status/1930054391597511078)

なお、Grounding DINOのFine-Tuningについては[grayさんの記事](https://zenn.dev/gray_0019/articles/238b476780132a)が詳しい。step-by-stepな説明本当に助かります。ありがとう。

以上。