Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
70a0155
spatial pyramid for video adaptation by default, with a small range o…
yeshaokai Apr 6, 2023
8441909
Update test_crossvalutils.py
yeshaokai Apr 20, 2023
0e20e8d
Merge branch 'DeepLabCut:main' into master
yeshaokai Apr 25, 2023
d5febb1
Handled empty prediction
yeshaokai Apr 25, 2023
f32d317
Removed unused parameter. Updated config to use superanimal instead o…
n-poulsen May 23, 2023
7949045
Merge branch 'DeepLabCut:main' into master
yeshaokai May 31, 2023
d531e80
Merge branch 'DeepLabCut:main' into master
yeshaokai Jul 30, 2023
768296c
Merge branch 'DeepLabCut:main' into master
yeshaokai Jun 20, 2024
882f920
Added notebook for superanimal pytorch
yeshaokai Jun 20, 2024
4be4a70
Update COLAB_Pytorch_SuperAnimal.ipynb
MMathisLab Jun 20, 2024
ed8a979
Update COLAB_Pytorch_SuperAnimal.ipynb
MMathisLab Jun 20, 2024
624134b
Update COLAB_Pytorch_SuperAnimal.ipynb
MMathisLab Jun 20, 2024
7c123b3
Merge branch 'pytorch_dlc' into shaokai/educational_superanimal_notebook
n-poulsen Jun 26, 2024
d68a137
cleaned notebook and added bbox_threshold to analyze_superanimal_images
n-poulsen Jun 26, 2024
830f4ac
worked on superanimal notebook
n-poulsen Jul 2, 2024
66acb3d
fixed symlink creation for keypoint matching
n-poulsen Jul 4, 2024
ba39fd5
renamed COLAB to YOURDATA
n-poulsen Jul 4, 2024
24cc195
fixed some bugs and cleaned the notebook. added more print statements…
n-poulsen Jul 4, 2024
c99a199
installed latest version of DeepLabCut instead of from pypi
n-poulsen Jul 4, 2024
f59dc69
changed default training parameters
n-poulsen Jul 4, 2024
3877be3
added option to not have use symlinks for keypoint matching
n-poulsen Jul 4, 2024
97bb2a1
no symlinks for keypoint matching in COLAB
n-poulsen Jul 4, 2024
67903f0
set default eval interval to 10, add superanimal_analyze_images to init
n-poulsen Jul 4, 2024
faba3ac
do not copy images or create symlinks for memory replay
n-poulsen Jul 4, 2024
27a58af
fixed memory replay to only run once
n-poulsen Jul 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions deeplabcut/modelzoo/generalized_data_converter/datasets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,28 @@ def populate_generic(self):
raise NotImplementedError("Must implement this function")

def materialize(
self, proj_root, framework="coco", deepcopy=False, append_image_id=True
self,
proj_root,
framework="coco",
deepcopy=False,
append_image_id=True,
no_image_copy=False,
):
mat_func = mat_func_factory(framework)
self.meta["mat_datasets"] = {self.meta["dataset_name"]: self}
self.meta["imageid2datasetname"] = self.imageid2datasetname
kwargs = dict(deepcopy=deepcopy, append_image_id=append_image_id)
if framework == "coco":
kwargs["no_image_copy"] = no_image_copy

mat_func(
proj_root,
self.generic_train_images,
self.generic_test_images,
self.generic_train_annotations,
self.generic_test_annotations,
self.meta,
deepcopy=deepcopy,
append_image_id=append_image_id,
**kwargs,
)

def whether_anno_image_match(self, images, annotations):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import os
import pickle
import shutil
from pathlib import Path

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -660,9 +661,10 @@ def _generic2coco(
train_annotations,
test_annotations,
meta,
deepcopy=False,
full_image_path=True,
append_image_id=True,
deepcopy: bool = False,
full_image_path: bool = True,
append_image_id: bool = True,
no_image_copy: bool = False,
):
"""
Take generic data and create coco structure
Expand All @@ -672,6 +674,17 @@ def _generic2coco(
annotations
- train.json
- test.json

Args:
deepcopy: Only when no_image_copy=False. If False, images are not copied from
their original location and symlinks are created instead.
full_image_path: Only when no_image_copy=False. If True, the ``file_name`` for
the images in the annotation files contain the resolved path to the images.
Otherwise, a relative path is used.
append_image_id: Only when no_image_copy=False. Appends the image IDs in the
dataset to the image names.
no_image_copy: Instead of copying images to the COCO dataset, the full paths to
the images in the original dataset are used in the annotations.
"""

os.makedirs(os.path.join(proj_root, "images"), exist_ok=True)
Expand All @@ -693,54 +706,46 @@ def _generic2coco(
broken_links = []
# copying images via symbolic link
for image in train_images + test_images:
src = image["file_name"]
# important to resolve the filepath! Otherwise, errors can occur when running
# this code from Jupyter Notebooks
src = Path(image["file_name"]).resolve()
image_id = image["id"]

if not os.path.exists(src):
if not src.exists():
print("problem comes from", image["source_dataset"])
print(src)
broken_links.append(image_id)
continue
else:
pass
# print ('success comes from', image['source_dataset'])
# print (src)

# in dlc, some images have same name but under different folder
# we used to use a parent folder to distinguish them, but it's only applicable to DLC
# so here it's easier to just append a id into the filename

image_name = src.split(os.sep)[-1]
file_name = str(src)
dest = src
if not no_image_copy:
# in dlc, some images have same name but under different folder
# we used to use a parent folder to distinguish them, but it's only
# applicable to DLC so here it's easier to append an id into the filename

if image_name.count(".") > 1:
sep = image_name.rfind(".")
pre, suffix = image_name[:sep], image_name[sep + 1 :]
else:
# this does not work for image file that looks like image9.5.jpg..
pre, suffix = image_name.split(".")

# not to repeatedly add image id in memory replay training
if append_image_id:
dest_image_name = f"{pre}_{image_id}.{suffix}"
else:
dest_image_name = image_name
dest = os.path.join(proj_root, "images", dest_image_name)
# not to repeatedly add image id in memory replay training
dest_image_name = src.name
if append_image_id:
dest_image_name = f"{src.stem}_{image_id}{src.suffix}"

# now, we will also need to update the path in the config files
dest = Path(proj_root) / "images" / dest_image_name
dest = dest.resolve()

if full_image_path:
image["file_name"] = dest
else:
image["file_name"] = os.path.join("images", dest_image_name)
file_name = str(Path(*dest.parts[-2:]))
if full_image_path:
file_name = str(dest)

if deepcopy:
shutil.copy(src, dest)
else:
try:
os.symlink(src, dest)
except:
pass
if deepcopy:
shutil.copy(src, dest)
else:
try:
os.symlink(src, dest)
except Exception as err:
print(f"Could not create a symlink from {src} to {dest}: {err}")
pass

image["file_name"] = file_name
lookuptable[dest] = src

train_annotations = [
Expand Down
5 changes: 4 additions & 1 deletion deeplabcut/pose_estimation_pytorch/apis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
# Licensed under GNU Lesser General Public License v3.0
#

from deeplabcut.pose_estimation_pytorch.apis.analyze_images import analyze_images
from deeplabcut.pose_estimation_pytorch.apis.analyze_images import (
analyze_images,
superanimal_analyze_images,
)
from deeplabcut.pose_estimation_pytorch.apis.analyze_videos import analyze_videos
from deeplabcut.pose_estimation_pytorch.apis.convert_detections_to_tracklets import (
convert_detections2tracklets,
Expand Down
50 changes: 28 additions & 22 deletions deeplabcut/pose_estimation_pytorch/apis/analyze_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,33 +47,37 @@ def superanimal_analyze_images(
images: str | Path | list[str] | list[Path],
max_individuals: int,
out_folder: str,
bbox_threshold: float = 0.6,
progress_bar: bool = True,
device: str | None = None,
customized_pose_checkpoint: str | None = None,
customized_detector_checkpoint: str | None = None,
customized_model_config: str | None = None,
):
"""
This funciton inferences a superanimal model on a set of images and saves the results as labeled images.
This funciton inferences a superanimal model on a set of images and saves the
results as labeled images.

Parameters
----------
superanimal_name: str
The name of the superanimal to analyze.
supported list:
superanimal_topviewmouse
superanimal_quadruped
The name of the superanimal to analyze. Supported list:
- "superanimal_topviewmouse"
- "superanimal_quadruped"
model_name: str
The name of the model to use for inference.
supported list:
hrnetw32
The name of the model to use for inference. Supported list:
- "hrnetw32"
images: str | Path | list[str] | list[Path]
The images to analyze. Can either be a directory containing images, or
a list of paths of images.
max_individuals: int
The maximum number of individuals to detect in each image.
out_folder: str
The directory where the labeled images will be saved.
bbox_threshold: float, default=0.1
The minimum confidence score to keep bounding box detections. Must be in (0, 1).
Only used when `customized_model_config=None` (otherwise, edit your
`customized_model_config` with the desired bbox_threshold).
progress_bar: bool
Whether to display a progress bar when running inference.
device: str | None
Expand All @@ -95,17 +99,19 @@ def superanimal_analyze_images(
--------
>>> import deeplabcut
>>> from deeplabcut.pose_estimation_pytorch.apis.analyze_images import superanimal_analyze_images
>>> superanimal_name = 'superanimal_quadruped'
>>> model_name = 'hrnetw32'
>>> device = 'cuda'
>>> superanimal_name = "superanimal_quadruped"
>>> model_name = "hrnetw32"
>>> device = "cuda"
>>> max_individuals = 3
>>> test_images_folder = 'test_rodent_images'
>>> out_images_folder = 'vis_test_rodent_images'
>>> ret = superanimal_analyze_images(superanimal_name,
model_name,
test_images_folder,
max_individuals,
out_images_folder)
>>> test_images_folder = "test_rodent_images"
>>> out_images_folder = "vis_test_rodent_images"
>>> ret = superanimal_analyze_images(
>>> superanimal_name,
>>> model_name,
>>> test_images_folder,
>>> max_individuals,
>>> out_images_folder
>>> )
"""

os.makedirs(out_folder, exist_ok=True)
Expand All @@ -119,6 +125,10 @@ def superanimal_analyze_images(
snapshot_path,
detector_path,
) = get_config_model_paths(superanimal_name, model_name)

if "detector" in model_cfg:
model_cfg["detector"]["model"]["box_score_thresh"] = bbox_threshold

config = {**project_config, **model_cfg}
config = update_config(config, max_individuals, device)
else:
Expand Down Expand Up @@ -146,9 +156,7 @@ def superanimal_analyze_images(

superanimal_colormaps = get_superanimal_colormaps()
colormap = superanimal_colormaps[superanimal_name]

create_labeled_images_from_predictions(predictions, out_folder, colormap)

return predictions


Expand All @@ -164,8 +172,6 @@ def analyze_images(
device: str | None = None,
max_individuals: int | None = None,
progress_bar: bool = True,
superanimal_name=None,
model_name=None,
) -> dict[str, dict]:
"""Runs analysis on images using a pose model.

Expand Down
5 changes: 4 additions & 1 deletion deeplabcut/pose_estimation_pytorch/apis/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,10 @@ def train_network(
dataset_params = loader.get_dataset_parameters()
backbone_name = loader.model_cfg["model"]["backbone"]["model_name"]
model_name = modelzoo_utils.get_pose_model_type(backbone_name)
# at some point train_network should support a different train_file passing so memory replay can also take the same train file
# at some point train_network should support a different train_file passing
# so memory replay can also take the same train file

print("Preparing data for memory replay (this can take some time)")
prepare_memory_replay(
loader.project_path,
shuffle,
Expand All @@ -271,6 +273,7 @@ def train_network(
customized_pose_checkpoint=weight_init.customized_pose_checkpoint,
)

print("Loading memory replay data")
loader = COCOLoader(
project_root=Path(loader.model_folder).parent / "memory_replay",
model_config_path=loader.model_config_path,
Expand Down
2 changes: 1 addition & 1 deletion deeplabcut/pose_estimation_pytorch/config/base/base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ runner:
gpus: null
key_metric: "test.mAP"
key_metric_asc: true
eval_interval: 1
eval_interval: 10
optimizer:
type: AdamW
params:
Expand Down
Loading