diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..7793765 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,31 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile +{ + "name": "Existing Dockerfile", + "build": { + // Sets the run context to the subfolder. + "context": "../sleap_cuda", + // Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename. + "dockerfile": "../sleap_cuda/Dockerfile" + }, + "features": { + }, + "runArgs": [ + "--gpus", "all" + ] + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Uncomment the next line to run commands after the container is created. + // "postCreateCommand": "cat /etc/os-release", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "devcontainer" +} diff --git a/.github/workflows/sleap_cuda_production.yml b/.github/workflows/sleap_cuda_production.yml new file mode 100644 index 0000000..45d3b59 --- /dev/null +++ b/.github/workflows/sleap_cuda_production.yml @@ -0,0 +1,68 @@ +name: Build and Push sleap-cuda (Production Workflow) + +# Run on push to main branch after testing is complete +on: + push: + branches: + - main + paths: + - sleap_cuda/** # Only run on changes to sleap_cuda + +jobs: + build: + runs-on: ubuntu-latest # Only build on Ubuntu for now since Docker is not available on macOS runners + strategy: + matrix: + platform: [linux/amd64] # Only build amd64 for now + max-parallel: 2 # Build both architectures in parallel (if more than one) + outputs: + git_sha: ${{ steps.get_sha.outputs.sha }} + sanitized_platform: ${{ steps.sanitize_platform.outputs.sanitized_platform }} + steps: + - name: Checkout code + # https://github.com/actions/checkout + uses: actions/checkout@v4 + + - name: Get Git SHA + id: get_sha + run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + + - name: Debug Git SHA + run: echo "Git SHA ${{ steps.get_sha.outputs.sha }}" + + # Generate a sanitized platform string with slashes replaced by dashes + - name: Sanitize platform name + id: sanitize_platform + run: | + sanitized_platform="${{ matrix.platform }}" # Copy platform value + sanitized_platform="${sanitized_platform/\//-}" # Replace / with - + echo "sanitized_platform=$sanitized_platform" >> $GITHUB_OUTPUT + + - name: Set up Docker Buildx + # https://github.com/docker/setup-buildx-action + uses: docker/setup-buildx-action@v3 + with: + driver: docker-container # Use a container driver for Buildx (default) + + - name: Log in to Docker Hub + # https://github.com/docker/login-action + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push Docker image + # https://github.com/docker/build-push-action + uses: docker/build-push-action@v6 + with: + context: ./docker # Build context + file: ./docker/Dockerfile # Path to Dockerfile + platforms: ${{ matrix.platform }} + push: true # Push the image to Docker Hub + # Tags for the production images, including the "latest" tag + tags: | + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:latest + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }} + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }}-nvidia-cuda-11.3.1-cudnn8-runtime-ubuntu20.04 + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }}-sleap-1.3.4 + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }}-${{ steps.get_sha.outputs.sha }} \ No newline at end of file diff --git a/.github/workflows/sleap_cuda_test.yml b/.github/workflows/sleap_cuda_test.yml new file mode 100644 index 0000000..e163546 --- /dev/null +++ b/.github/workflows/sleap_cuda_test.yml @@ -0,0 +1,67 @@ +name: Build and Push sleap-cuda (Test Workflow) + +# Run on push to branches other than main for sleap_cuda +on: + push: + branches-ignore: + - main + paths: + - sleap_cuda/** # Only run on changes to sleap_cuda + +jobs: + build: + runs-on: ubuntu-latest # Only build on Ubuntu for now since Docker is not available on macOS runners + strategy: + matrix: + platform: [linux/amd64] # Only build amd64 for now + max-parallel: 2 # Build both architectures in parallel (if more than one) + outputs: + git_sha: ${{ steps.get_sha.outputs.sha }} + sanitized_platform: ${{ steps.sanitize_platform.outputs.sanitized_platform }} + steps: + - name: Checkout code + # https://github.com/actions/checkout + uses: actions/checkout@v4 + + - name: Get Git SHA + id: get_sha + run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + + - name: Debug Git SHA + run: echo "Git SHA ${{ steps.get_sha.outputs.sha }}" + + # Generate a sanitized platform string with slashes replaced by dashes + - name: Sanitize platform name + id: sanitize_platform + run: | + sanitized_platform="${{ matrix.platform }}" # Copy platform value + sanitized_platform="${sanitized_platform/\//-}" # Replace / with - + echo "sanitized_platform=$sanitized_platform" >> $GITHUB_OUTPUT + + - name: Set up Docker Buildx + # https://github.com/docker/setup-buildx-action + uses: docker/setup-buildx-action@v3 + with: + driver: docker-container # Use a container driver for Buildx (default) + + - name: Log in to Docker Hub + # https://github.com/docker/login-action + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push Docker image + # https://github.com/docker/build-push-action + uses: docker/build-push-action@v6 + with: + context: ./sleap_cuda # Build context wrt the root of the repository + file: ./sleap_cuda/Dockerfile # Path to Dockerfile wrt the root of the repository + platforms: ${{ matrix.platform }} + push: true # Push the image to Docker Hub + # Tags all include "-test" to differentiate from production images + tags: | + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }}-test + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }}-nvidia-cuda-11.3.1-cudnn8-runtime-ubuntu20.04-test + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }}-sleap-1.3.4-test + ${{ vars.DOCKERHUB_USERNAME }}/sleap-cuda:${{ steps.sanitize_platform.outputs.sanitized_platform }}-${{ steps.get_sha.outputs.sha }}-test diff --git a/.github/workflows/sleap_vnc_connect_production.yml b/.github/workflows/sleap_vnc_connect_production.yml new file mode 100644 index 0000000..a66ec7c --- /dev/null +++ b/.github/workflows/sleap_vnc_connect_production.yml @@ -0,0 +1,68 @@ +name: Build and Push sleap-vnc-connect (Production Workflow) + +# Run on push to main branch after testing is complete +on: + push: + branches: + - main + paths: + - sleap_vnc_connect/** # Only run on changes to sleap_vnc_connect + +jobs: + build: + runs-on: ubuntu-latest # Only build on Ubuntu for now since Docker is not available on macOS runners + strategy: + matrix: + platform: [linux/amd64] # Only build amd64 for now + max-parallel: 2 # Build both architectures in parallel (if more than one) + outputs: + git_sha: ${{ steps.get_sha.outputs.sha }} + sanitized_platform: ${{ steps.sanitize_platform.outputs.sanitized_platform }} + steps: + - name: Checkout code + # https://github.com/actions/checkout + uses: actions/checkout@v4 + + - name: Get Git SHA + id: get_sha + run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + + - name: Debug Git SHA + run: echo "Git SHA ${{ steps.get_sha.outputs.sha }}" + + # Generate a sanitized platform string with slashes replaced by dashes + - name: Sanitize platform name + id: sanitize_platform + run: | + sanitized_platform="${{ matrix.platform }}" # Copy platform value + sanitized_platform="${sanitized_platform/\//-}" # Replace / with - + echo "sanitized_platform=$sanitized_platform" >> $GITHUB_OUTPUT + + - name: Set up Docker Buildx + # https://github.com/docker/setup-buildx-action + uses: docker/setup-buildx-action@v3 + with: + driver: docker-container # Use a container driver for Buildx (default) + + - name: Log in to Docker Hub + # https://github.com/docker/login-action + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push Docker image + # https://github.com/docker/build-push-action + uses: docker/build-push-action@v6 + with: + context: ./docker # Build context + file: ./docker/Dockerfile # Path to Dockerfile + platforms: ${{ matrix.platform }} + push: true # Push the image to Docker Hub + # Tags for the production images, including the "latest" tag + tags: | + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:latest + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }} + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }}-nvidia-cuda-11.3.1-cudnn8-runtime-ubuntu20.04 + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }}-sleap-1.3.4 + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }}-${{ steps.get_sha.outputs.sha }} \ No newline at end of file diff --git a/.github/workflows/sleap_vnc_connect_test.yml b/.github/workflows/sleap_vnc_connect_test.yml new file mode 100644 index 0000000..d41e300 --- /dev/null +++ b/.github/workflows/sleap_vnc_connect_test.yml @@ -0,0 +1,67 @@ +name: Build and Push sleap-vnc-connect (Test Workflow) + +# Run on push to branches other than main for sleap_vnc_connect +on: + push: + branches-ignore: + - main + paths: + - sleap_vnc_connect/** # Only run on changes to sleap_vnc_connect + +jobs: + build: + runs-on: ubuntu-latest # Only build on Ubuntu for now since Docker is not available on macOS runners + strategy: + matrix: + platform: [linux/amd64] # Only build amd64 for now + max-parallel: 2 # Build both architectures in parallel (if more than one) + outputs: + git_sha: ${{ steps.get_sha.outputs.sha }} + sanitized_platform: ${{ steps.sanitize_platform.outputs.sanitized_platform }} + steps: + - name: Checkout code + # https://github.com/actions/checkout + uses: actions/checkout@v4 + + - name: Get Git SHA + id: get_sha + run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + + - name: Debug Git SHA + run: echo "Git SHA ${{ steps.get_sha.outputs.sha }}" + + # Generate a sanitized platform string with slashes replaced by dashes + - name: Sanitize platform name + id: sanitize_platform + run: | + sanitized_platform="${{ matrix.platform }}" # Copy platform value + sanitized_platform="${sanitized_platform/\//-}" # Replace / with - + echo "sanitized_platform=$sanitized_platform" >> $GITHUB_OUTPUT + + - name: Set up Docker Buildx + # https://github.com/docker/setup-buildx-action + uses: docker/setup-buildx-action@v3 + with: + driver: docker-container # Use a container driver for Buildx (default) + + - name: Log in to Docker Hub + # https://github.com/docker/login-action + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push Docker image + # https://github.com/docker/build-push-action + uses: docker/build-push-action@v6 + with: + context: ./sleap_vnc_connect # Build context wrt the root of the repository + file: ./sleap_vnc_connect/Dockerfile # Path to Dockerfile wrt the root of the repository + platforms: ${{ matrix.platform }} + push: true # Push the image to Docker Hub + # Tags all include "-test" to differentiate from production images + tags: | + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }}-test + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }}-nvidia-cuda-11.3.1-cudnn8-runtime-ubuntu20.04-test + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }}-sleap-1.3.4-test + ${{ vars.DOCKERHUB_USERNAME }}/sleap-vnc-connect:${{ steps.sanitize_platform.outputs.sanitized_platform }}-${{ steps.get_sha.outputs.sha }}-test diff --git a/README.md b/README.md new file mode 100644 index 0000000..602ecf9 --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# sleap-cuda-container + + +## Description +This repo contains a DockerFile for a lightweight container (~2.79 GB) with the PyPI installation of SLEAP and all of its dependencies. The container repository is located at [https://hub.docker.com/repository/docker/eberrigan/sleap-cuda/general](https://hub.docker.com/repository/docker/eberrigan/sleap-cuda/general). + +The base image used is [nvidia/cuda:11.3.1-cudnn8-runtime-ubuntu20.04](https://hub.docker.com/layers/nvidia/cuda/11.3.1-cudnn8-runtime-ubuntu20.04/images/sha256-025a321d3131b688f4ac09d80e9af6221f2d1568b4f9ea6e45a698beebb439c0). +- The Dockerfile is located at `docker/Dockerfile`. +- The repo has CI set up in `.github/workflows` for building and pushing the image when making changes. + - The workflow uses the linux/amd64 platform to build. +- `.devcontainer/devcontainer.json` is convenient for developing inside a container made with the DockerFile using Visual Studio Code. +- Test data for training is located in `tests/data`. + + +## Installation + +**Make sure to have Docker Daemon running first** + + +You can pull the image if you don't have it built locally, or need to update the latest, with + +``` +docker pull eberrigan/sleap-cuda:latest +``` + +## Usage + +Then, to run the image with gpus interactively: + +``` +docker run --gpus all -it eberrigan/sleap-cuda:latest bash +``` + +and test with + +``` +python -c "import sleap; sleap.versions()" && nvidia-smi +``` + +In general, use the syntax + +``` +docker run -v /path/on/host:/path/in/container [other options] image_name [command] +``` + +Note that host paths are absolute. + + +Use this syntax to give host permissions to mounted volumes +``` +docker run -u $(id -u):$(id -g) -v /your/host/directory:/container/directory [options] your-image-name [command] +``` + +``` +docker run -u $(id -u):$(id -g) -v ./tests/data:/workspace/tests/data --gpus all -it eberrigan/sleap-cuda:latest bash +``` + +Test: + +``` + python3 -c "import sleap; print('SLEAP version:', sleap.__version__)" + nvidia-smi # Check that the GPUs are disvoerable + ps aux | grep Xtightvnc # Check that the VNC server is running + sleap-train "tests/data/initial_config.json" "tests/data/dance.mp4.labels.slp" --video-paths "tests/data/dance.mp4" +``` + +**Notes:** + +- The `eberrigan/sleap-cuda` is the Docker registry where the images are pulled from. This is only used when pulling images from the cloud, and not necesary when building/running locally. +- `-it` ensures that you get an interactive terminal. The `i` stands for interactive, and `t` allocates a pseudo-TTY, which is what allows you to interact with the bash shell inside the container. +- The `-v` or `--volume` option mounts the specified directory with the same level of access as the directory has on the host. +- `bash` is the command that gets executed inside the container, which in this case is to start the bash shell. +- Order of operations is 1. Pull (if needed): Get a pre-built image from a registry. 2. Run: Start a container from an image. + +## Contributing + +- Use the `devcontainer.json` to open the repo in a dev container using VS Code. + - There is some test data in the `tests` directory that will be automatically mounted for use since the working directory is the workspace. + - Rebuild the container when you make changes using `Dev Container: Rebuild Container`. + +- Please make a new branch, starting with your name, with any changes, and request a reviewer before merging with the main branch since this image will be used by others. +- Please document using the same conventions (docstrings for each function and class, typing-hints, informative comments). +- Tests are written in the pytest framework. Data used in the tests are defined as fixtures in `tests/fixtures/data.py` (https://docs.pytest.org/en/6.2.x/reference.html#fixtures-api). + + +## Build +To build and push via automated CI, just push changes to a branch. +- Pushes to `main` result in an image with the tag `latest`. +- Pushes to other branches have tags with `-test` appended. +- See `.github/workflows` for testing and production workflows. + +To test `test` images locally use after pushing the `test` images via CI: + +``` +docker pull eberrigan/sleap-cuda:linux-amd64-test +``` + +then + +``` +docker run -v ./tests/data:/workspace/tests/data --gpus all -it eberrigan/sleap-cuda:linux-amd64-test bash +``` + +To build locally for testing you can use the command: + +``` +docker build --platform linux/amd64 ./docker +``` + +## Support +contact Elizabeth at eberrigan@salk.edu diff --git a/sleap_cuda/.dockerignore b/sleap_cuda/.dockerignore new file mode 100644 index 0000000..8a75ad2 --- /dev/null +++ b/sleap_cuda/.dockerignore @@ -0,0 +1,19 @@ +# Ignore Python cache +__pycache__/ +*.pyc +*.pyo + +# Ignore virtual environments +env/ +venv/ + +# Ignore version control and logs +.git/ +*.log + +# Ignore Docker build artifacts +docker/*.tmp + +README.md +.gitignore +terraform/* \ No newline at end of file diff --git a/sleap_cuda/Dockerfile b/sleap_cuda/Dockerfile new file mode 100644 index 0000000..cb580db --- /dev/null +++ b/sleap_cuda/Dockerfile @@ -0,0 +1,38 @@ +# Base image with GPU support +FROM nvidia/cuda:11.3.1-cudnn8-runtime-ubuntu20.04 + +# Set non-interactive mode +ENV DEBIAN_FRONTEND=noninteractive + +# Set user +ENV USER=root + +# Set NVIDIA driver capabilities +ENV NVIDIA_DRIVER_CAPABILITIES=all + +# Set QT debug environment variable to help debug issues with Qt plugins +ENV QT_DEBUG_PLUGINS=1 + +# Install dependencies +# opencv requires opengl https://github.com/conda-forge/opencv-feedstock/issues/401 +# Default python3 is 3.8 in ubuntu 20.04 https://wiki.ubuntu.com/FocalFossa/ReleaseNotes#Python3_by_default +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + libgl1-mesa-glx \ + libglapi-mesa \ + libegl-mesa0 \ + libegl1 \ + libopengl0 \ + libglib2.0-0 \ + libfontconfig1 \ + libgssapi-krb5-2 \ + libdbus-1-3 \ + libx11-xcb1 \ + libxkbcommon-x11-0 \ + python3-pip && \ + python3 -m pip install --upgrade pip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Install SLEAP +RUN pip install --no-cache-dir sleap[pypi]==1.3.4 \ No newline at end of file diff --git a/sleap_cuda/README.md b/sleap_cuda/README.md new file mode 100644 index 0000000..1bc3096 --- /dev/null +++ b/sleap_cuda/README.md @@ -0,0 +1,110 @@ +# sleap-cuda + + +## Description +This repo contains a DockerFile for a lightweight container (~2.79 GB) with the PyPI installation of SLEAP and all of its dependencies. The container repository is located at [https://hub.docker.com/repository/docker/eberrigan/sleap-cuda/general](https://hub.docker.com/repository/docker/eberrigan/sleap-cuda/general). + +The base image used is [nvidia/cuda:11.3.1-cudnn8-runtime-ubuntu20.04](https://hub.docker.com/layers/nvidia/cuda/11.3.1-cudnn8-runtime-ubuntu20.04/images/sha256-025a321d3131b688f4ac09d80e9af6221f2d1568b4f9ea6e45a698beebb439c0). +- The Dockerfile is located at `docker/Dockerfile`. +- The repo has CI set up in `.github/workflows` for building and pushing the image when making changes. + - The workflow uses the linux/amd64 platform to build. +- `.devcontainer/devcontainer.json` is convenient for developing inside a container made with the DockerFile using Visual Studio Code. +- Test data for training is located in `tests/data`. + + +## Installation + +**Make sure to have Docker Daemon running first** + + +You can pull the image if you don't have it built locally, or need to update the latest, with + +``` +docker pull eberrigan/sleap-cuda:latest +``` + +## Usage + +Then, to run the image with gpus interactively: + +``` +docker run --gpus all -it eberrigan/sleap-cuda:latest bash +``` + +and test with + +``` +python -c "import sleap; sleap.versions()" && nvidia-smi +``` + +In general, use the syntax + +``` +docker run -v /path/on/host:/path/in/container [other options] image_name [command] +``` + +Note that host paths are absolute. + + +Use this syntax to give host permissions to mounted volumes +``` +docker run -u $(id -u):$(id -g) -v /your/host/directory:/container/directory [options] your-image-name [command] +``` + +``` +docker run -u $(id -u):$(id -g) -v ./tests/data:/tests/data --gpus all -it eberrigan/sleap-cuda:latest bash +``` + +Test: + +``` + python3 -c "import sleap; print('SLEAP version:', sleap.__version__)" + nvidia-smi # Check that the GPUs are discoverable + sleap-train "tests/data/initial_config.json" "tests/data/dance.mp4.labels.slp" --video-paths "tests/data/dance.mp4" +``` + +**Notes:** + +- The `eberrigan/sleap-cuda` is the Docker registry where the images are pulled from. This is only used when pulling images from the cloud, and not necesary when building/running locally. +- `-it` ensures that you get an interactive terminal. The `i` stands for interactive, and `t` allocates a pseudo-TTY, which is what allows you to interact with the bash shell inside the container. +- The `-v` or `--volume` option mounts the specified directory with the same level of access as the directory has on the host. +- `bash` is the command that gets executed inside the container, which in this case is to start the bash shell. +- Order of operations is 1. Pull (if needed): Get a pre-built image from a registry. 2. Run: Start a container from an image. + +## Contributing + +- Use the `devcontainer.json` to open the repo in a dev container using VS Code. + - There is some test data in the `tests` directory that will be automatically mounted for use since the working directory is the workspace. + - Rebuild the container when you make changes using `Dev Container: Rebuild Container`. + +- Please make a new branch, starting with your name, with any changes, and request a reviewer before merging with the main branch since this image will be used by others. +- Please document using the same conventions (docstrings for each function and class, typing-hints, informative comments). +- Tests are written in the pytest framework. Data used in the tests are defined as fixtures in `tests/fixtures/data.py` (https://docs.pytest.org/en/6.2.x/reference.html#fixtures-api). + + +## Build +To build and push via automated CI, just push changes to a branch. +- Pushes to `main` result in an image with the tag `latest`. +- Pushes to other branches have tags with `-test` appended. +- See `.github/workflows` for testing and production workflows. + +To test `test` images locally use after pushing the `test` images via CI: + +``` +docker pull eberrigan/sleap-cuda:linux-amd64-test +``` + +then + +``` +docker run -v ./tests/data:/tests/data --gpus all -it eberrigan/sleap-cuda:linux-amd64-test bash +``` + +To build locally for testing you can use the command (from the root of the repo): + +``` +docker build --platform linux/amd64 ./sleap_cuda +``` + +## Support +contact Elizabeth at eberrigan@salk.edu diff --git a/sleap_vnc_connect/.dockerignore b/sleap_vnc_connect/.dockerignore new file mode 100644 index 0000000..8a75ad2 --- /dev/null +++ b/sleap_vnc_connect/.dockerignore @@ -0,0 +1,19 @@ +# Ignore Python cache +__pycache__/ +*.pyc +*.pyo + +# Ignore virtual environments +env/ +venv/ + +# Ignore version control and logs +.git/ +*.log + +# Ignore Docker build artifacts +docker/*.tmp + +README.md +.gitignore +terraform/* \ No newline at end of file diff --git a/sleap_vnc_connect/Dockerfile b/sleap_vnc_connect/Dockerfile new file mode 100644 index 0000000..85b34fb --- /dev/null +++ b/sleap_vnc_connect/Dockerfile @@ -0,0 +1,68 @@ +# Base image with GPU support +FROM nvidia/cuda:11.3.1-cudnn8-runtime-ubuntu20.04 + +# Set non-interactive mode +ENV DEBIAN_FRONTEND=noninteractive + +ENV USER=root + +# Install dependencies +# opencv requires opengl https://github.com/conda-forge/opencv-feedstock/issues/401 +# https://medium.com/@gustav0.lewin/how-to-make-a-docker-container-with-vnc-access-f607958141ae +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + libgl1-mesa-glx \ + libglapi-mesa \ + libegl-mesa0 \ + libegl1 \ + libopengl0 \ + libglib2.0-0 \ + libfontconfig1 \ + libgssapi-krb5-2 \ + libdbus-1-3 \ + libx11-xcb1 \ + libxkbcommon-x11-0 \ + xfce4 \ + xfce4-goodies \ + tightvncserver \ + dbus-x11 \ + xfonts-base \ + x11-xserver-utils \ + x11-utils \ + autocutsel \ + python3-pip && \ + python3 -m pip install --upgrade pip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# Install SLEAP +RUN pip install --no-cache-dir sleap[pypi]==1.3.4 + +ENV NVIDIA_DRIVER_CAPABILITIES=all + +# Set QT debug environment variable to help debug issues with Qt plugins +ENV QT_DEBUG_PLUGINS=1 + +# Setup VNC server +RUN mkdir /root/.vnc && \ + echo "password" | vncpasswd -f > /root/.vnc/passwd && \ + chmod 600 /root/.vnc/passwd + +# Create an .Xauthority file +RUN touch /root/.Xauthority + +# Set display resolution (change as needed) +ENV RESOLUTION=1920x1080 + +# Expose VNC port +EXPOSE 5901 + +# Set the working directory in the container +WORKDIR /app + +# Copy a script to start the VNC server +COPY start-vnc.sh start-vnc.sh +RUN chmod +x start-vnc.sh + +# Start the VNC server +ENTRYPOINT ["/app/start-vnc.sh"] \ No newline at end of file diff --git a/sleap_vnc_connect/README.md b/sleap_vnc_connect/README.md new file mode 100644 index 0000000..42eea0c --- /dev/null +++ b/sleap_vnc_connect/README.md @@ -0,0 +1,112 @@ +# sleap-vnc-connect + +The SLEAP GUI will not open in the VNC server and I do not know why! VNC connection works. + +## Description +This repo contains a DockerFile for a lightweight container (~2.79 GB) with the PyPI installation of SLEAP and all of its dependencies. The container repository is located at [https://hub.docker.com/repository/docker/eberrigan/sleap-vnc-connect/general](https://hub.docker.com/repository/docker/eberrigan/sleap-vnc-connect/general). + +The base image used is [nvidia/cuda:11.3.1-cudnn8-runtime-ubuntu20.04](https://hub.docker.com/layers/nvidia/cuda/11.3.1-cudnn8-runtime-ubuntu20.04/images/sha256-025a321d3131b688f4ac09d80e9af6221f2d1568b4f9ea6e45a698beebb439c0). +- The Dockerfile is located at `docker/Dockerfile`. +- The repo has CI set up in `.github/workflows` for building and pushing the image when making changes. + - The workflow uses the linux/amd64 platform to build. +- `.devcontainer/devcontainer.json` is convenient for developing inside a container made with the DockerFile using Visual Studio Code. +- Test data for training is located in `tests/data`. + + +## Installation + +**Make sure to have Docker Daemon running first** + + +You can pull the image if you don't have it built locally, or need to update the latest, with + +``` +docker pull eberrigan/sleap-vnc-connect:latest +``` + +## Usage + +Then, to run the image with gpus interactively: + +``` +docker run --gpus all -it eberrigan/sleap-vnc-connect:latest bash +``` + +and test with + +``` +python -c "import sleap; sleap.versions()" && nvidia-smi +``` + +In general, use the syntax + +``` +docker run -v /path/on/host:/path/in/container [other options] image_name [command] +``` + +Note that host paths are absolute. + + +Use this syntax to give host permissions to mounted volumes +``` +docker run -u $(id -u):$(id -g) -v /your/host/directory:/container/directory [options] your-image-name [command] +``` + +``` +docker run -u $(id -u):$(id -g) -v ./tests/data:/workspace/tests/data --gpus all -it eberrigan/sleap-vnc-connect:latest bash +``` + +Test: + +``` + python3 -c "import sleap; print('SLEAP version:', sleap.__version__)" + nvidia-smi # Check that the GPUs are disvoerable + ps aux | grep Xtightvnc # Check that the VNC server is running + sleap-train "tests/data/initial_config.json" "tests/data/dance.mp4.labels.slp" --video-paths "tests/data/dance.mp4" +``` + +**Notes:** + +- The `eberrigan/sleap-vnc-connect` is the Docker registry where the images are pulled from. This is only used when pulling images from the cloud, and not necesary when building/running locally. +- `-it` ensures that you get an interactive terminal. The `i` stands for interactive, and `t` allocates a pseudo-TTY, which is what allows you to interact with the bash shell inside the container. +- The `-v` or `--volume` option mounts the specified directory with the same level of access as the directory has on the host. +- `bash` is the command that gets executed inside the container, which in this case is to start the bash shell. +- Order of operations is 1. Pull (if needed): Get a pre-built image from a registry. 2. Run: Start a container from an image. + +## Contributing + +- Use the `devcontainer.json` to open the repo in a dev container using VS Code. + - There is some test data in the `tests` directory that will be automatically mounted for use since the working directory is the workspace. + - Rebuild the container when you make changes using `Dev Container: Rebuild Container`. + +- Please make a new branch, starting with your name, with any changes, and request a reviewer before merging with the main branch since this image will be used by others. +- Please document using the same conventions (docstrings for each function and class, typing-hints, informative comments). +- Tests are written in the pytest framework. Data used in the tests are defined as fixtures in `tests/fixtures/data.py` (https://docs.pytest.org/en/6.2.x/reference.html#fixtures-api). + + +## Build +To build and push via automated CI, just push changes to a branch. +- Pushes to `main` result in an image with the tag `latest`. +- Pushes to other branches have tags with `-test` appended. +- See `.github/workflows` for testing and production workflows. + +To test `test` images locally use after pushing the `test` images via CI: + +``` +docker pull eberrigan/sleap-vnc-connect:linux-amd64-test +``` + +then + +``` +docker run -v ./tests/data:/workspace/tests/data --gpus all -it eberrigan/sleap-vnc-connect:linux-amd64-test bash +``` + +To build locally for testing you can use the command: + +``` +docker build --platform linux/amd64 ./docker +``` + +## Support +contact Elizabeth at eberrigan@salk.edu diff --git a/sleap_vnc_connect/start-vnc.sh b/sleap_vnc_connect/start-vnc.sh new file mode 100644 index 0000000..cf741fd --- /dev/null +++ b/sleap_vnc_connect/start-vnc.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +echo 'Updating /etc/hosts file...' +HOSTNAME=$(hostname) +echo "127.0.1.1 $HOSTNAME" >> /etc/hosts + +echo "Checking for any existing VNC server on display :1..." +vncserver -kill :1 || echo "No existing VNC server found. Continuing..." + +echo "Ensuring xstartup is configured..." +mkdir -p /root/.vnc +cat << EOF > /root/.vnc/xstartup +#!/bin/sh +startxfce4 & +autocutsel -fork & +autocutsel -selection PRIMARY -fork & +EOF +chmod +x /root/.vnc/xstartup + +echo "Starting VNC server at $RESOLUTION..." +vncserver -geometry $RESOLUTION & + +echo "VNC server started at $RESOLUTION! ^-^" + +echo "Keeping the container alive..." +tail -f /dev/null diff --git a/tests/data/dance.mp4 b/tests/data/dance.mp4 new file mode 100644 index 0000000..d6b9484 Binary files /dev/null and b/tests/data/dance.mp4 differ diff --git a/tests/data/dance.mp4.labels.slp b/tests/data/dance.mp4.labels.slp new file mode 100644 index 0000000..2d2f34d Binary files /dev/null and b/tests/data/dance.mp4.labels.slp differ diff --git a/tests/data/initial_config.json b/tests/data/initial_config.json new file mode 100644 index 0000000..1d1b070 --- /dev/null +++ b/tests/data/initial_config.json @@ -0,0 +1,165 @@ +{ + "data": { + "labels": { + "training_labels": null, + "validation_labels": null, + "validation_fraction": 0.1, + "test_labels": null, + "split_by_inds": false, + "training_inds": null, + "validation_inds": null, + "test_inds": null, + "search_path_hints": [], + "skeletons": [] + }, + "preprocessing": { + "ensure_rgb": false, + "ensure_grayscale": false, + "imagenet_mode": null, + "input_scaling": 0.5, + "pad_to_stride": null, + "resize_and_pad_to_target": true, + "target_height": null, + "target_width": null + }, + "instance_cropping": { + "center_on_part": "nose", + "crop_size": null, + "crop_size_detection_padding": 16 + } + }, + "model": { + "backbone": { + "leap": null, + "unet": { + "stem_stride": null, + "max_stride": 16, + "output_stride": 2, + "filters": 16, + "filters_rate": 2.0, + "middle_block": true, + "up_interpolate": true, + "stacks": 1 + }, + "hourglass": null, + "resnet": null, + "pretrained_encoder": null + }, + "heads": { + "single_instance": null, + "centroid": { + "anchor_part": "nose", + "sigma": 2.5, + "output_stride": 2, + "loss_weight": 1.0, + "offset_refinement": false + }, + "centered_instance": null, + "multi_instance": null, + "multi_class_bottomup": null, + "multi_class_topdown": null + }, + "base_checkpoint": null + }, + "optimization": { + "preload_data": true, + "augmentation_config": { + "rotate": true, + "rotation_min_angle": -15.0, + "rotation_max_angle": 15.0, + "translate": false, + "translate_min": -5, + "translate_max": 5, + "scale": false, + "scale_min": 0.9, + "scale_max": 1.1, + "uniform_noise": false, + "uniform_noise_min_val": 0.0, + "uniform_noise_max_val": 10.0, + "gaussian_noise": false, + "gaussian_noise_mean": 5.0, + "gaussian_noise_stddev": 1.0, + "contrast": false, + "contrast_min_gamma": 0.5, + "contrast_max_gamma": 2.0, + "brightness": false, + "brightness_min_val": 0.0, + "brightness_max_val": 10.0, + "random_crop": false, + "random_crop_height": 256, + "random_crop_width": 256, + "random_flip": true, + "flip_horizontal": false + }, + "online_shuffling": true, + "shuffle_buffer_size": 128, + "prefetch": true, + "batch_size": 4, + "batches_per_epoch": null, + "min_batches_per_epoch": 200, + "val_batches_per_epoch": null, + "min_val_batches_per_epoch": 10, + "epochs": 200, + "optimizer": "adam", + "initial_learning_rate": 0.0001, + "learning_rate_schedule": { + "reduce_on_plateau": true, + "reduction_factor": 0.5, + "plateau_min_delta": 1e-06, + "plateau_patience": 5, + "plateau_cooldown": 3, + "min_learning_rate": 1e-08 + }, + "hard_keypoint_mining": { + "online_mining": false, + "hard_to_easy_ratio": 2.0, + "min_hard_keypoints": 2, + "max_hard_keypoints": null, + "loss_scale": 5.0 + }, + "early_stopping": { + "stop_training_on_plateau": true, + "plateau_min_delta": 1e-08, + "plateau_patience": 20 + } + }, + "outputs": { + "save_outputs": true, + "run_name": "240430_204148.centroid.n=3", + "run_name_prefix": "", + "run_name_suffix": "", + "runs_folder": "tests/data/models", + "tags": [ + "" + ], + "save_visualizations": true, + "delete_viz_images": true, + "zip_outputs": false, + "log_to_csv": true, + "checkpointing": { + "initial_model": false, + "best_model": true, + "every_epoch": false, + "latest_model": false, + "final_model": false + }, + "tensorboard": { + "write_logs": false, + "loss_frequency": "epoch", + "architecture_graph": false, + "profile_graph": false, + "visualizations": true + }, + "zmq": { + "subscribe_to_controller": true, + "controller_address": "tcp://127.0.0.1:9000", + "controller_polling_timeout": 10, + "publish_updates": true, + "publish_address": "tcp://127.0.0.1:9001" + } + }, + "name": "", + "description": "", + "sleap_version": "1.3.3", + "filename": "tests/data/initial_config.json" +} \ No newline at end of file