-
Notifications
You must be signed in to change notification settings - Fork 14
Add Docker support and update test/demo scripts to use automatic Hugging Face downloads #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 16 commits
2f69e4e
530a886
43aef6e
bb79602
d66a0a0
c43b46b
74d2dab
30eb7fc
53aefde
1ff5d01
8768cc4
ce1c4f0
e122e51
3d1253a
ec10769
6254cc8
d6e1fdb
3bb81e5
f1631c9
962f395
09ce42f
94b5100
b2151a6
ef803e7
bdd95b1
6107a7a
2b1626d
c944d25
e185185
11ab3d3
2f5f771
52c2497
89ff316
9f46de8
478abcd
8098412
1eb00b4
8b402c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| FROM pytorch/pytorch:2.4.1-cuda12.4-cudnn9-runtime | ||
|
|
||
| ARG USERNAME=fmpose3d | ||
| ARG USER_UID=1000 | ||
| ARG USER_GID=1000 | ||
| RUN groupadd ${USERNAME} --gid ${USER_GID} | ||
| RUN useradd -m -s /bin/bash -g ${USERNAME} -u ${USER_UID} ${USERNAME} | ||
| RUN mkdir /app /logs /data | ||
|
|
||
| ENV DEBIAN_FRONTEND=noninteractive | ||
| SHELL ["/bin/bash", "-c"] | ||
| RUN apt-get update -y && apt-get install -yy --no-install-recommends \ | ||
| vim zsh tmux wget curl htop git sudo ssh git-lfs \ | ||
| python3 python3-pip \ | ||
| libgl1-mesa-glx libglib2.0-0 \ | ||
| ffmpeg \ | ||
| && apt-get -y autoclean \ | ||
| && apt-get -y autoremove \ | ||
| && rm -rf /var/lib/apt/lists/* \ | ||
| && apt-get clean | ||
|
|
||
| ENV PATH="/opt/conda/bin:${PATH}" | ||
|
|
||
| # Initialize conda for root just in case and fix symlinks | ||
| RUN ln -fs /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh | ||
|
|
||
| # --- Install FMPose3D from PyPI (as documented in README) --- | ||
| RUN python -m pip install --no-cache-dir --upgrade pip && \ | ||
| python -m pip install --no-cache-dir "fmpose3d[animals,viz]" gdown | ||
|
|
||
| # Allow non-root user to download DLC model weights at runtime | ||
| RUN mkdir -p /opt/conda/lib/python3.11/site-packages/deeplabcut/modelzoo/checkpoints && \ | ||
| chown -R ${USERNAME}:${USERNAME} /opt/conda/lib/python3.11/site-packages/deeplabcut/modelzoo | ||
|
xiu-cs marked this conversation as resolved.
Outdated
|
||
|
|
||
| # Set your user as owner of the home directory before switching | ||
| RUN chown -R ${USERNAME}:${USERNAME} /home/${USERNAME} | ||
|
|
||
| ENV NVIDIA_DRIVER_CAPABILITIES=all | ||
|
|
||
| # --- SWITCH TO USER --- | ||
| USER ${USERNAME} | ||
| ENV HOME=/home/${USERNAME} | ||
| WORKDIR ${HOME} | ||
|
|
||
| # Ensure dotfiles exist | ||
| RUN touch ${HOME}/.bashrc ${HOME}/.zshrc && \ | ||
| chmod 644 ${HOME}/.bashrc ${HOME}/.zshrc | ||
|
|
||
| # Install Oh My Zsh and plugins (MUST come before conda init, since OMZ overwrites .zshrc) | ||
| RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended \ | ||
| && git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions \ | ||
| && git clone https://github.com/zsh-users/zsh-syntax-highlighting ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting \ | ||
| && sed -i 's/^plugins=(.*)$/plugins=(git zsh-autosuggestions zsh-syntax-highlighting)/' ~/.zshrc \ | ||
| && echo "export PATH=\$PATH:${HOME}/.local/bin" >> ~/.zshrc | ||
|
|
||
| # Initialize conda AFTER Oh My Zsh (so conda init block is not overwritten) | ||
| RUN /opt/conda/bin/conda init bash && /opt/conda/bin/conda init zsh | ||
|
|
||
| # Add conda activation to bashrc and zshrc | ||
| RUN echo "conda activate base" >> ${HOME}/.bashrc && \ | ||
| echo "conda activate base" >> ${HOME}/.zshrc | ||
|
|
||
| SHELL ["/bin/zsh", "-c"] | ||
| CMD ["zsh"] | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,79 @@ | ||||||||
| # [USER: ADJUST PATH] | ||||||||
| PROJECT_NAME := fmpose3d | ||||||||
| project_name_lo := $(shell echo $(PROJECT_NAME) | tr '[:upper:]' '[:lower:]') | ||||||||
|
xiu-cs marked this conversation as resolved.
Outdated
|
||||||||
| ####### | ||||||||
| # RUN # | ||||||||
| ####### | ||||||||
|
|
||||||||
| # for local server | ||||||||
| IMG_NAME := fmpose3d | ||||||||
| IMG_TAG := v0.1 | ||||||||
| DOCKERFILE := Dockerfile | ||||||||
| HOST_UID := $(shell id -u) | ||||||||
| HOST_GID := $(shell id -g) | ||||||||
|
xiu-cs marked this conversation as resolved.
Outdated
|
||||||||
| BUILD_ARGS := \ | ||||||||
| --build-arg USERNAME=fmpose3d \ | ||||||||
| --build-arg USER_GID=$(HOST_GID) \ | ||||||||
| --build-arg USER_UID=$(HOST_UID) | ||||||||
|
|
||||||||
| build: | ||||||||
| docker build $(BUILD_ARGS) \ | ||||||||
| -t $(IMG_NAME):$(IMG_TAG) -f $(DOCKERFILE) . | ||||||||
|
|
||||||||
| build-clean: | ||||||||
| docker build --no-cache $(BUILD_ARGS) \ | ||||||||
| -t $(IMG_NAME):$(IMG_TAG) -f $(DOCKERFILE) . | ||||||||
|
|
||||||||
|
|
||||||||
| CONTAINER_NAME := fmpose3d_dev1 | ||||||||
| # [USER: ADJUST] Mount the project root into the container | ||||||||
| HOST_SRC := $(shell pwd) | ||||||||
| DOCKER_SRC := /fmpose3d | ||||||||
| VOLUMES := \ | ||||||||
| --volume $(HOST_SRC):$(DOCKER_SRC) | ||||||||
|
xiu-cs marked this conversation as resolved.
Outdated
|
||||||||
|
|
||||||||
|
|
||||||||
| run: | ||||||||
| docker run -it --gpus all --shm-size=64g --name $(CONTAINER_NAME) -w $(DOCKER_SRC) $(VOLUMES) $(IMG_NAME):$(IMG_TAG) | ||||||||
|
|
||||||||
| exec: | ||||||||
| docker exec -it -w $(DOCKER_SRC) $(CONTAINER_NAME) /bin/zsh | ||||||||
|
|
||||||||
| exec_bash: | ||||||||
| docker exec -it -w $(DOCKER_SRC) $(CONTAINER_NAME) /bin/bash | ||||||||
|
|
||||||||
| stop: | ||||||||
| docker stop $(CONTAINER_NAME) | ||||||||
|
|
||||||||
| rm: | ||||||||
| docker rm $(CONTAINER_NAME) | ||||||||
|
|
||||||||
|
|
||||||||
| ####################### | ||||||||
| # BUILD CORE WITH SRC # | ||||||||
| ####################### | ||||||||
| # [USER: ADJUST SRC PATH] | ||||||||
| SRC_PATH="/home/user/project" | ||||||||
| build_production: | ||||||||
| cp -r $(SRC_PATH) src | ||||||||
| docker build $(BUILD_ARGS) --build-arg src=src \ | ||||||||
| -t $(IMG_NAME):$(IMG_TAG) -f $(DOCKERFILE) . | ||||||||
| rm -r src | ||||||||
|
|
||||||||
| # Help message | ||||||||
| help: | ||||||||
| @echo "Available targets:" | ||||||||
| @echo " build - Build Docker image for local server." | ||||||||
| @echo " run - Run a Docker container with GPU." | ||||||||
| @echo " exec - Attach to running container (zsh)." | ||||||||
| @echo " exec_bash - Attach to running container (bash)." | ||||||||
| @echo " stop - Stop the running container." | ||||||||
| @echo " rm - Remove the stopped container." | ||||||||
| @echo " build_production - Build a Docker image with source code." | ||||||||
| @echo " help - Show this help message." | ||||||||
| @echo "" | ||||||||
| @echo "Usage:" | ||||||||
| @echo " 1. make build" | ||||||||
| @echo " 2. make run" | ||||||||
| @echo " 3. Inside container: pip install -e '.[animals,viz]'" | ||||||||
| @echo " 4. Inside container: sh scripts/FMPose3D_train.sh" | ||||||||
|
Comment on lines
+65
to
+66
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the dockerfile allready installs fmpose, right?
Suggested change
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -113,7 +113,7 @@ def show3Dpose(vals, ax): | |
| def get_pose2D(path, output_dir, type): | ||
|
|
||
| print('\nGenerating 2D pose...') | ||
| keypoints, scores = hrnet_pose(path, det_dim=416, num_peroson=1, gen_output=True, type=type) | ||
| keypoints, scores = hrnet_pose(path, det_dim=416, num_person=1, gen_output=True, type=type) | ||
| keypoints, scores, valid_frames = h36m_coco_format(keypoints, scores) | ||
| re_kpts = revise_kpts(keypoints, scores, valid_frames) | ||
| print('Generating 2D pose successful!') | ||
|
|
@@ -278,8 +278,10 @@ def get_pose3D(path, output_dir, type='image'): | |
|
|
||
| # if args.reload: | ||
| model_dict = model['CFM'].state_dict() | ||
| model_path = args.model_weights_path | ||
| print(model_path) | ||
| from fmpose3d.utils.weights import resolve_weights_path | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably better to move to the top, unless you intentionally want it to load only locally in this function ('lazy loading'). But since it is a lighweight import I don't think it provides a real benefit to keep it here. |
||
| model_path = resolve_weights_path(args.model_weights_path, args.model_type) | ||
|
|
||
| print(f"Loading weights from: {model_path}") | ||
| pre_dict = torch.load(model_path, map_location=device, weights_only=True) | ||
| for name, key in model_dict.items(): | ||
| model_dict[name] = pre_dict[name] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,8 +34,7 @@ | |
| ProgressCallback = Callable[[int, int], None] | ||
|
|
||
|
|
||
| #: HuggingFace repository hosting the official FMPose3D checkpoints. | ||
| _HF_REPO_ID: str = "deruyter92/fmpose_temp" | ||
| from fmpose3d.utils.weights import HF_REPO_ID as _HF_REPO_ID | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good fix, thanks! Maybe just move it to the import block with the other |
||
|
|
||
| # Default camera-to-world rotation quaternion (from the demo script). | ||
| _DEFAULT_CAM_ROTATION = np.array( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| """ | ||
| FMPose3D: monocular 3D Pose Estimation via Flow Matching | ||
|
|
||
| Official implementation of the paper: | ||
| "FMPose3D: monocular 3D Pose Estimation via Flow Matching" | ||
| by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis | ||
| Licensed under Apache 2.0 | ||
| """ |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
| FMPose3D: monocular 3D Pose Estimation via Flow Matching | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Official implementation of the paper: | ||||||||||||||||||||||||||||||
| "FMPose3D: monocular 3D Pose Estimation via Flow Matching" | ||||||||||||||||||||||||||||||
| by Ti Wang, Xiaohang Yu, and Mackenzie Weygandt Mathis | ||||||||||||||||||||||||||||||
| Licensed under Apache 2.0 | ||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| """Shared helpers for resolving / downloading FMPose3D model weights.""" | ||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
+10
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| HF_REPO_ID: str = "deruyter92/fmpose_temp" | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| def resolve_weights_path(model_weights_path: str, model_type: str) -> str: | ||||||||||||||||||||||||||||||
| """Return a local weights path, downloading from Hugging Face Hub if needed. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Parameters | ||||||||||||||||||||||||||||||
| ---------- | ||||||||||||||||||||||||||||||
| model_weights_path : str | ||||||||||||||||||||||||||||||
| User-supplied local path. If falsy the weights are fetched from the | ||||||||||||||||||||||||||||||
| Hugging Face Hub automatically. | ||||||||||||||||||||||||||||||
| model_type : str | ||||||||||||||||||||||||||||||
| Model variant name used to derive the remote filename | ||||||||||||||||||||||||||||||
| (e.g. ``"fmpose3d_humans"`` -> ``fmpose3d_humans.pth``). | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Returns | ||||||||||||||||||||||||||||||
| ------- | ||||||||||||||||||||||||||||||
| str | ||||||||||||||||||||||||||||||
| Absolute path to the weight file on disk. | ||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||
| if model_weights_path: | ||||||||||||||||||||||||||||||
| return model_weights_path | ||||||||||||||||||||||||||||||
|
Comment on lines
+32
to
+33
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider some validation, to avoid difficult-to-debug downstream errors:
Suggested change
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||
| from huggingface_hub import hf_hub_download | ||||||||||||||||||||||||||||||
| except ImportError: | ||||||||||||||||||||||||||||||
| raise ImportError( | ||||||||||||||||||||||||||||||
| "huggingface_hub is required to download model weights. " | ||||||||||||||||||||||||||||||
| "Install it with: pip install huggingface_hub\n" | ||||||||||||||||||||||||||||||
| "Or download the weights manually and pass the local path." | ||||||||||||||||||||||||||||||
| ) from None | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| filename = f"{model_type}.pth" | ||||||||||||||||||||||||||||||
| print( | ||||||||||||||||||||||||||||||
| f"No local weights path specified. " | ||||||||||||||||||||||||||||||
| f"Downloading '{filename}' from Hugging Face ({HF_REPO_ID})..." | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| return hf_hub_download(repo_id=HF_REPO_ID, filename=filename) | ||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -268,7 +268,11 @@ def print_error_action(action_error_sum, is_train): | |
| args.checkpoint = "./checkpoint/" + folder_name | ||
| elif args.train == False: | ||
| # create a new folder for the test results | ||
| args.previous_dir = os.path.dirname(args.model_weights_path) | ||
| if args.model_weights_path: | ||
| args.previous_dir = os.path.dirname(args.model_weights_path) | ||
| else: | ||
| # HuggingFace-downloaded weights: no local dir, use ./checkpoint/ | ||
| args.previous_dir = "./checkpoint" | ||
| args.checkpoint = os.path.join(args.previous_dir, folder_name) | ||
|
|
||
| if not os.path.exists(args.checkpoint): | ||
|
|
@@ -337,8 +341,10 @@ def print_error_action(action_error_sum, is_train): | |
|
|
||
| if args.reload: | ||
| model_dict = model["CFM"].state_dict() | ||
| model_path = args.model_weights_path | ||
| print(model_path) | ||
| from fmpose3d.utils.weights import resolve_weights_path | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider moving this to the top. |
||
| model_path = resolve_weights_path(args.model_weights_path, args.model_type) | ||
|
|
||
| print(f"Loading weights from: {model_path}") | ||
| pre_dict = torch.load(model_path, map_location=device, weights_only=True) | ||
| for name, key in model_dict.items(): | ||
| model_dict[name] = pre_dict[name] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be safe, you could change this to the below suggestion, since the current command may fail if the user allready exists (e.g. in the parent image). But I don't expect that this is a realistic scenario, so you can also keep yours, for better readability.