Git Product home page Git Product logo

kilosort3-docker's Introduction

kilosort3-docker

Automated build of Docker image with Kilosort3, Matlab, required toolboxes, and mex gpu binaries.

What is this?

To goal of this repo is to document and produce a working Kilosort3 environment as a Docker image.

This takes advantage of Docker tooling provided by Mathworks, including a Matlab base image and Dockerfile and the mpm package manager.

With or without Docker you'll still need a Matlab license and NVIDIA GPU hardware. Hopefully other setup and testing chores can be captured here in this repo and shared via Docker images, making things easier to reproduce and share.

Outline

Here's a summary of the host config and Docker image stack that go into this Kilosort3 environment.

Kilosort3 Docker environment includes Docker image layers and host config.

Host config

Some host configuration is required to support GPU-accelerated Docker containers. It should be possible to accomplish equvalent setup on Windows 11 or Linux, and to go from there with the exact same Docker images.

Windows 11 (plus Linux via WSL 2)

NVIDIA Docker setup for Windows 11 is documented well by both Canonical and NVIDIA.

The setup requires Windows 11 (or some later builds of Windows 10). It uses Windows NVIDIA drivers installed via the standard process in Windows. It is surprising but true that Linux containers running within WSL 2 will use the Windows NVIDIA drivers, not the Linux drivers.

The Windows Subsystem for Linux Version 2 (WSL 2) will run a real Linux kernel alongside Windows itself and will expose the Windows NVIDIA drivers to Linux distros running within WSL 2. Docker Desktop installed in Windows will use WSL 2 to run Linux containers with full kernel support. The containers can be launched from Windows or from a Linux distro running within WSL 2.

Finally, the setup includes NVIDIA's cuda-wsl-ubuntu package, which provides NVIDIA management tools but won't clobber the NVIDIA driver stubs that connect Linux to the Windows drivers.

Regular Linux

NVIDIA Docker setup for Linux might be hard to document in general. But the key requirements are to install:

If you are lucky, all of these might be available from your distribution's package manager. Here's one Medium post that gives a possible overview on Ubuntu.

Docker images

The main artifact produced from this repo is a Docker image called ninjaben/kilosort3. You should be able to pull this image onto a configured host and start running Kilosort3 (see example commands, below).

This image is built up from a few layers that add Kilosort dependencies:

ninjaben/matlab-parallel

This image starts from the offical mathworks/matlab:r2022b image. It uses Matlab Package Manager to install the Matlab toolkboxes required for Kilosort:

  • Parallel_Computing_Toolbox
  • Signal_Processing_Toolbox
  • Statistics_and_Machine_Learning_Toolbox

The ninjaben/matlab-parallel image is available on Docker Hub.

ninjaben/kilosort3-code

This image builds on ninjaben/matlab-parallel and adds Git, Kilosort3, and npy-matlab. It keeps Git installed as a way to check and report the commit hashes of cloned toolboxes.

It also adds a test script, testKilosortEMouse.m, to serve as an automated test of the whole environment (see example commands, below).

The ninjaben/kilosort3-code image is available on Docker Hub.

ninjaben/kilosort3

This is the final image produced from this repo. It builds on ninjaben/kilosort3-code and adds binaries for Kilosort's GPU-accelerated mex-functions. It also adds a binary for Matlab's mexGPUExample function, which is useful as a quick test.

You should be able to pull this image onto a configured host and start running Kilosort3 and/or test commands (see example commands, below).

The precompiled binaries are built during an intermediate build step that includes NVIDIA CUDA Toolkit version 11.2, which is the version of CUDA Toolkit required for Matlab r2022b. Once the binaries are built, the CUDA Toolkit is discarded and only the binaries themselves are carried forward into the final image. This makes the final image several GB smaller than it would be otherwise. Docker multi-stage builds let us do all of this with one Dockerfile.

The actual mex gpu build commands are scraped from the output of mexcuda -v ... in Matlab, and then run in the shell without Matlab during the Docker build. These commands use include the nvcc compiler from CUDA Toolkit and the system's g++ linker. Building from the plain-old-shell makes the entire build process automatable and auditable, and avoids running Matlab or configuring a license during the build.

The ninjaben/kilosort3 image is available on Docker Hub.

Example commands

Here are some example docker run commands that should help you run ninjaben/kilosort3 containers on a confiured host.

Quick test

You can run the Mathworks mexGPUExample to check if the host, Docker, CUDA, and Matlab are all working together.

This example uses a local Matlab license, specific to the host MAC address. There are also more ways to configure the license, documented in the Matlab readme on Docker Hub. You'll probably need to edit this command a bit to reflect your license situation.

LICENSE_MAC_ADDRESS=$(cat /sys/class/net/en*/address)
LICENSE_FILE="$(pwd)/license.lic"
docker run --gpus all --rm \
  --mac-address "$LICENSE_MAC_ADDRESS" \
  -v "$LICENSE_FILE":/licenses/license.lic \
  -e MLM_LICENSE_FILE=/licenses/license.lic \
  ninjaben/kilosort3:v0.0.11 \
  -batch "shouldBeTwos = mexGPUExample(ones(4,4,'gpuArray'))"

After a successful run, Matlab should print a 4x4 matrix of twos:

shouldBeTwos = 

    2    2    2    2
    2    2    2    2
    2    2    2    2
    2    2    2    2

Kilosort3 test

If the quick test above looks good, then a similar command should work for testing Kilosort3 itself with simulated neural data.

LICENSE_MAC_ADDRESS=$(cat /sys/class/net/en*/address)
LICENSE_FILE="$(pwd)/license.lic"
docker run --gpus all --rm \
  --mac-address "$LICENSE_MAC_ADDRESS" \
  -v "$LICENSE_FILE":/licenses/license.lic \
  -e MLM_LICENSE_FILE=/licenses/license.lic \
  ninjaben/kilosort3:v0.0.11 \
  -batch "success = testKilosortEMouse()"

A successful run may take several minutes and produce a lot of output. Then end should look something like this:

Success: found 128 clusters with 94 considered "good".
output filename: /home/matlab/eMouse/output_cluster_metrics.txt


--Results Summary--
median initial score: 0.75; median best score: 0.96
total merges required: 53
35 / 74 good cells, score > 0.80 (pre-merge)
51 / 74 good cells, score > 0.80 (post-merge)
Mean merges per good cell 0.80

success =

  logical

   1

The function testKilosortEMouse.m comes from this repo. It's based on Kilosort's eMouse example and modified so that it can run unattended, on Linux, and report sanity check assertions at the end. This is needed because as of 2022 Kilosort3 seems not to have an automated test suite we can run.

Kilosort3 spike sorting

If the Kilosort test above looks good, then you could try doing some actual spike sorting.

You might want to bring your own scripts and data for this, perhaps in dirs on the host called /my/kilosort/code and /my/kilosort/data. You can mount these dirs into the container's file system, then call your own Kilosort code and point it at your data.

LICENSE_MAC_ADDRESS=$(cat /sys/class/net/en*/address)
LICENSE_FILE="$(pwd)/license.lic"
docker run --gpus all --rm \
  --mac-address "$LICENSE_MAC_ADDRESS" \
  -v "$LICENSE_FILE":/licenses/license.lic \
  -e MLM_LICENSE_FILE=/licenses/license.lic \
  -v /my/kilosort/code:/my/kilosort/code \
  -v /my/kilosort/data:/my/kilosort/data \
  ninjaben/kilosort3:v0.0.11 \
  -batch "myKilosortFunction('/my/kilosort/data/a/b/c')"

I hope this is helpful and fun -- good luck!

A point about image sizes

Here are the rough, uncompressed sizes of images used and produced during the build process for this repo.

REPOSITORY                       TAG       SIZE
mathworks/matlab                 r2022b    5.85GB
ninjaben/matlab-parallel         v0.0.11   10.1GB
ninjaben/kilosort3-code          v0.0.11   10.3GB
(CUDA Toolkit w/ mex-build.sh)   (temp)    18.4GB   <--
ninjaben/kilosort3               v0.0.11   10.3GB

The Matlab base image brings in >5GB to start with. Adding the required toolboxes takes the image to >10GB. This is somewhat cumbersome, but normal for Matlab installs. So far this seems not to be a problem for Docker or Docker Hub.

Installing CUDA Toolkit nearly doubles the image size to >18GB! This seems like a lot to ask. That's why the final ninjaben/kilosort3 image omits CUDA Toolkit and only includes precompiled mex binaries.

Building the images

Local

You can build these Docker images locally like this:

git clone https://github.com/benjamin-heasly/kilosort3-docker.git

cd kilosort3-docker/matlab-parallel
./build.sh

cd ../kilosort3-code
./build.sh

cd ../kilosort3
./build.sh

Automatic

The images are also built automatically by GitHub Actions whenever a tag is pushed to this repo.

git clone https://github.com/benjamin-heasly/kilosort3-docker.git

cd kilosort3-docker
git tag -a v9.9.99 -m "This tag should trigger an image build."
git push --tags

After several minutes, new images with the same tag should appear at Docker Hub: ninjaben/matlab-parallel, ninjaben/kilosort3-code, and ninjaben/kilosort3.

kilosort3-docker's People

Contributors

benjamin-heasly avatar

Stargazers

XCY avatar Nate Dolensek avatar

Watchers

 avatar  avatar

kilosort3-docker's Issues

Can we make kilosort 3 deterministic?

From our own testing, it appears kilosort is not deterministic! As a anecdotal example, I re-ran sorting with the same code and input files, and got:

  • run 1: 2 units at depths 900 and 900
  • run 2: zero spikes or units
  • run 3: zero spikes or units
  • run 4: 2 units at depths 600 and 900

The most discussion of this I've found so far is here

It's unclear we can tackle this completely (!) but we could try add args to the runKilosort entrypoint that would allow us to set rng and gpurng at the outset.

Maybe Kilosort 4 with Pytorch will give us a different handle on rng stuff?

runKilosort explodes when displaying ops override for struct-valued field.

2023-03-17 13:22:32,786 [INFO] Step 'kilosort3': runKilosort Overriding ops fproc with value: '/data/Kilosort/temp_wh2.dat'

2023-03-17 13:22:32,794 [INFO] Step 'kilosort3': Error using mat2str

2023-03-17 13:22:32,794 [INFO] Step 'kilosort3': Input matrix must be a numeric array, character array, or string array.

2023-03-17 13:22:32,795 [INFO] Step 'kilosort3':

2023-03-17 13:22:32,795 [INFO] Step 'kilosort3': Error in runKilosort (line 81)

2023-03-17 13:22:32,796 [INFO] Step 'kilosort3':     fprintf('runKilosort Overriding ops %s with value: %s\n', fieldName, mat2str(customOps.(fieldName)));

The offending value was the chanMap object:

chanMap":{"Nchannels":16,"chanMap":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],"connected":[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],"xcoords":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"ycoords":[1050,900,750,600,450,300,150,0,2250,2100,1950,1800,1650,1500,1350,1200],"kcoords":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]},

This is a superficial print formatting problem, but it breaks the whole flow.

Break out versions as Docker build ARGs

In addition to the version of images produced, I think this should break out several build ARGs for things like:

  • Matlab version
  • CUDA Toolkit version
  • kilosort version / commit hash
  • etc

The versions would depend on each other, for example Matlab and CUDA Toolkit. Maybe the readme could include a few "known good" version sets.

Build mex binaries outside Matlab

It might be that we can avoid the awkward local run step by building the mexGPUExample and Kilosort mex gpu functions with nvcc directly from the shell, instead of using Matlab to run mexcuda and Kilosort's mexGPUall.

This must be possible. But would it be hard or easy to tease out the environment config and commands used by mexcuda?

If this works we could:

  • Avoid storing binaries in this repo.
  • Have a fully automated and auditable end-to-end build.
  • Continue to omit CUDA Toolkit from the final ninjaben/kilosort3 image by using a Docker multi-stage build.
  • Test that we got the builds right by running mexGPUExample and testKilosortEMouse.
  • Avoid dealing with Matlab licensing until actual spike sorting runtime.

Save result summary in JSON

For integrating with other tools, it will be handy to save some of the Kilosort results in a human- and machine-readable file in an interoperable format like JSON.

I'm thinking a subset "rez" data, similar to what's logged by Kilosort, including things like:

  • number of clusters found
  • number of "good" clusters
  • which clusters are "good"
  • etc

Refactor with "main" kilosort function in matlab

Refactor testKilosortEMouse to keep the eMoise stuff, but extract a more general Kilosort3 "main" function. Then testKilosortEMouse can just call the "main" function.

The main function should:

  • take a Kilosort "ops" struct or file to load
  • take a Kilosort "chan map" struct or file to load
  • take a bin dir name
  • take a bin file name
  • take a scratch dir name
  • take a scratch file name
  • merge the above into a Kilosort "ops" struct
  • initialize the gpu
  • call the 7 kilosort processing utils as in the current kilosort "main" example
  • call rezToPhy on the results
  • save the "rez" result to disk
  • save any figures created by Kilosort to disk as plain old image files
  • Log intention, progress, timing, and status for the steps above, as it goes

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.