Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 12 additions & 8 deletions _toc.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
format: jb-book
root: README

parts:
- caption: Getting Started
chapters:
- file: docs/UseOverviewGuide
- file: docs/course

- caption: Installation
chapters:
- file: docs/installation
Expand All @@ -31,40 +33,41 @@ parts:
- file: docs/pytorch/user_guide.md
- file: docs/pytorch/pytorch_config.md
- file: docs/pytorch/architectures.md

- caption: Quick Start Tutorials
chapters:
- file: docs/quick-start/single_animal_quick_guide
- file: docs/quick-start/tutorial_maDLC
- caption: 🚀 Beginner's Guide to DeepLabCut

- caption: "🚀 Beginner's Guide to DeepLabCut"
chapters:
- file: docs/beginner-guides/beginners-guide
- file: docs/beginner-guides/manage-project
- file: docs/beginner-guides/labeling
- file: docs/beginner-guides/Training-Evaluation
- file: docs/beginner-guides/video-analysis
- caption: 🚀 Main Demo Notebooks

- caption: "🚀 Main Demo Notebooks"
chapters:
- file: examples/COLAB/COLAB_DEMO_SuperAnimal
- file: examples/COLAB/COLAB_DEMO_mouse_openfield
- file: examples/COLAB/COLAB_3miceDemo
- file: examples/COLAB/COLAB_HumanPose_with_RTMPose



- caption: 🚀 Notebooks For Your Data
- caption: "🚀 Notebooks For Your Data"
chapters:
- file: examples/COLAB/COLAB_YOURDATA_SuperAnimal
- file: examples/COLAB/COLAB_YOURDATA_TrainNetwork_VideoAnalysis
- file: examples/COLAB/COLAB_YOURDATA_maDLC_TrainNetwork_VideoAnalysis

- caption: 🚀 Special Feature Demos
- caption: "🚀 Special Feature Demos"
chapters:
- file: examples/COLAB/COLAB_transformer_reID
- file: examples/COLAB/COLAB_BUCTD_and_CTD_tracking
- file: examples/JUPYTER/Demo_3D_DeepLabCut
- file: examples/COLAB/COLAB_DLC_ModelZoo

- caption: 🧑‍🍳 Cookbook (detailed helper guides)
- caption: "🧑‍🍳 Cookbook (detailed helper guides)"
chapters:
- file: docs/convert_maDLC
- file: docs/recipes/OtherData
Expand All @@ -82,6 +85,7 @@ parts:
- caption: Hardware Tips
chapters:
- file: docs/recipes/TechHardware

- caption: DeepLabCut-Live!
chapters:
- file: docs/dlc-live/deeplabcutlive
Expand Down Expand Up @@ -110,7 +114,7 @@ parts:
- file: docs/benchmark
- file: docs/pytorch/Benchmarking_shuffle_guide

- caption: Mission & Contribute
- caption: "Mission & Contribute"
chapters:
- file: docs/MISSION_AND_VALUES
- file: docs/roadmap
Expand Down
8 changes: 7 additions & 1 deletion deeplabcut/core/config/base_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class DLCBaseConfig(BaseModel):
- Field aliases from `json_schema_extra`.
"""

model_config = ConfigDict(extra="forbid", validate_assignment=True)
model_config = ConfigDict(extra="forbid", validate_assignment=True, arbitrary_types_allowed=True)

# ------------------------------------------------------------------
# Validation (before pydantic field validation)
Expand Down Expand Up @@ -392,10 +392,16 @@ def record_change_note(
include_caller: bool = False,
_stack_depth: int = 1,
) -> None:
field_name = self._resolve_alias(field_name)

if field_name not in type(self).model_fields:
raise KeyError(f"'{type(self).__name__}' has no field '{field_name}'")

if include_caller:
frame = sys._getframe(_stack_depth)
filename = frame.f_code.co_filename.rsplit("/", 1)[-1]
message = f"{message} [{filename}:{frame.f_lineno}]"

self._change_notes[field_name] = message

def log_changes(self) -> None:
Expand Down
4 changes: 2 additions & 2 deletions deeplabcut/core/weight_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ def from_dict(data: dict) -> WeightInitialization:
if "snapshot_path" not in data:
return WeightInitialization.from_dict_legacy(data)

snapshot_path = data['snapshot_path']
if data['snapshot_path'] is not None:
snapshot_path = data["snapshot_path"]
if data["snapshot_path"] is not None:
snapshot_path = Path(snapshot_path)

detector_snapshot_path = data.get("detector_snapshot_path")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,6 @@ def _generic2coco(
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
Expand Down
2 changes: 1 addition & 1 deletion deeplabcut/pose_estimation_3d/camera_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ def check_undistortion(config, cbrow=8, cbcol=6, plot=True):
f2.suptitle("Undistorted corner points on camera-1 and camera-2", fontsize=25)
ax1.imshow(cv2.cvtColor(im_remapped1, cv2.COLOR_BGR2RGB))
ax2.imshow(cv2.cvtColor(im_remapped2, cv2.COLOR_BGR2RGB))
for i in range(0, cam1_undistort.shape[1]):
for i in range(cam1_undistort.shape[1]):
ax1.scatter(
[cam1_undistort[-1][i, 0, 0]],
[cam1_undistort[-1][i, 0, 1]],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from deeplabcut.core.config import read_config_as_dict, write_config
from deeplabcut.core.weight_init import WeightInitialization
from deeplabcut.pose_estimation_pytorch.config.pose import PoseConfig
from deeplabcut.pose_estimation_pytorch.config.utils import (
get_config_folder_path,
load_backbones,
Expand Down
26 changes: 15 additions & 11 deletions deeplabcut/pose_estimation_pytorch/data/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
#
from __future__ import annotations

import warnings
from abc import ABC, abstractmethod
from pathlib import Path
import warnings

import albumentations as A
import numpy as np

from deeplabcut.pose_estimation_pytorch.config.pose import PoseConfig
import deeplabcut.core.config as config_utils
import deeplabcut.pose_estimation_pytorch.config as config
from deeplabcut.core.types import DEPRECATED_ARGUMENT
from deeplabcut.pose_estimation_pytorch.config.pose import PoseConfig
from deeplabcut.pose_estimation_pytorch.data.dataset import (
PoseDataset,
PoseDatasetParameters,
Expand All @@ -34,7 +34,6 @@
map_id_to_annotations,
)
from deeplabcut.pose_estimation_pytorch.task import Task
from deeplabcut.core.types import DEPRECATED_ARGUMENT


class Loader(ABC):
Expand Down Expand Up @@ -66,18 +65,20 @@ def __init__(
Args:
project_root: The root directory of the project.
image_root: The root directory of the images.
model_config (Path | str | PoseConfig | dict):
model_config (Path | str | PoseConfig | dict):
The pose model configuration. Can be a path to a YAML file, a PoseConfig object, or a dictionary.
(model_config_path: The path to the pose model configuration. Deprecated, use `model_config` instead.)
"""

def _resolve_legacy_args(model_config, model_config_path):
"""Support for legacy argument `model_config_path`. returns new model_config arg"""
if model_config_path:
warnings.warn(
"argument `model_config_path` in Loader.__init__ is deprecated, use `model_config` instead",
DeprecationWarning,
stacklevel=2,
)
if model_config is not None:
if model_config is not None:
raise ValueError(
"`model_config_path` and `model_config` arguments cannot be provided together! "
"Please provide only `model_config`."
Expand All @@ -86,21 +87,24 @@ def _resolve_legacy_args(model_config, model_config_path):
model_config_path = Path(model_config_path) / "pytorch_config.yaml"
model_config = model_config_path
elif model_config is None:
raise ValueError(
"`model_config` argument must be provided."
)
raise ValueError("`model_config` argument must be provided.")
return model_config
model_config = _resolve_legacy_args(model_config, model_config_path)

model_config = _resolve_legacy_args(model_config, model_config_path)
self.model_cfg: PoseConfig = PoseConfig.from_any(model_config)

def _infer_model_config_path(model_config: PoseConfig | dict | Path | str) -> Path:
"""Resolve the pose config path. Either the input is a path, or it is specified in `metadata.pose_config_path` field."""
"""
Resolve the pose config path.
Either the input is a path, or it is specified in `metadata.pose_config_path` field.
"""
provided_path = Path(model_config) if isinstance(model_config, (Path, str)) else None
specified_path = self.model_cfg.select("metadata.pose_config_path")
model_config_path = provided_path or specified_path
if model_config_path is None:
raise ValueError("`model_config` must contain a `metadata.pose_config_path` field.")
return Path(model_config_path)

self.model_config_path = _infer_model_config_path(model_config)

self.project_root = Path(project_root)
Expand Down
7 changes: 3 additions & 4 deletions deeplabcut/pose_estimation_pytorch/data/dlcloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
import numpy as np
import pandas as pd
import scipy.io as sio
from deeplabcut.core.config.project_config import ProjectConfig

import deeplabcut.utils.auxiliaryfunctions as af
from deeplabcut.core.config.project_config import ProjectConfig
from deeplabcut.core.engine import Engine
from deeplabcut.generate_training_dataset.trainingsetmanipulation import drop_likelihood_columns
from deeplabcut.pose_estimation_pytorch.data.base import Loader
Expand Down Expand Up @@ -51,9 +52,7 @@ def __init__(
self._project_config: ProjectConfig = ProjectConfig.from_any(config)
self._project_root = provided_root_dir or self._project_config.project_path
if self._project_root is None:
raise ValueError(
"`config` must contain a `project_path` field."
)
raise ValueError("`config` must contain a `project_path` field.")

self._shuffle = shuffle
self._trainset_index = trainset_index
Expand Down
1 change: 0 additions & 1 deletion deeplabcut/pose_estimation_pytorch/data/postprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ def __call__(self, predictions: Any, context: Context) -> Any:
Returns:
a single post-processed prediction
"""
pass


def build_bottom_up_postprocessor(
Expand Down
1 change: 0 additions & 1 deletion deeplabcut/pose_estimation_pytorch/data/preprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ def __call__(self, image: Image, context: Context) -> tuple[Image, Context]:
Returns:
the pre-processed image (or batch of images) and their context
"""
pass


def build_bottom_up_preprocessor(color_mode: str, transform: A.BaseCompose) -> Preprocessor:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def forward(self, x: torch.Tensor) -> torch.Tensor:
Returns:
a feature map for the input, of shape (batch_size, c', h', w')
"""
pass

def freeze_batch_norm_layers(self) -> None:
"""Freezes batch norm layers.
Expand Down
2 changes: 0 additions & 2 deletions deeplabcut/pose_estimation_pytorch/models/detectors/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ def forward(
losses: {'loss_name': loss_value}
detections: for each of the b images, {"boxes": bounding_boxes}
"""
pass

@abstractmethod
def get_target(self, labels: dict) -> list[dict]:
Expand All @@ -97,7 +96,6 @@ def get_target(self, labels: dict) -> list[dict]:
Returns:
list of dictionaries, each representing target information for a single annotation.
"""
pass

def freeze_batch_norm_layers(self) -> None:
"""Freezes batch norm layers.
Expand Down
2 changes: 0 additions & 2 deletions deeplabcut/pose_estimation_pytorch/models/heads/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ def forward(self, x: torch.Tensor) -> dict[str, torch.Tensor]:
Returns:
the head outputs (e.g. "heatmap", "locref")
"""
pass

def get_loss(
self,
Expand Down Expand Up @@ -172,4 +171,3 @@ def convert_weights(
)
``
"""
pass
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ def forward(self, x: torch.Tensor):
Returns:
Output tensor.
"""
pass

def _init_weights(self, pretrained: str | None):
"""Method for initializing block weights from pretrained models.
Expand Down
1 change: 0 additions & 1 deletion deeplabcut/pose_estimation_pytorch/models/necks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def forward(self, x: torch.Tensor):
Returns:
Output tensor.
"""
pass

def _init_weights(self, pretrained: str):
"""Initialize the Neck with pretrained weights.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,3 @@ def forward(self, stride: float, outputs: dict[str, torch.Tensor]) -> dict[str,
Raises:
NotImplementedError: This method must be implemented in subclasses.
"""
pass
8 changes: 6 additions & 2 deletions deeplabcut/pose_estimation_pytorch/runners/inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def __init__(
self.inference_cfg = InferenceConfig.from_dict(inference_cfg)
elif inference_cfg is None:
self.inference_cfg = InferenceConfig()
else:
else:
raise ValueError(f"Invalid inference config: {inference_cfg}")

if self.snapshot_path is not None and self.snapshot_path != "":
Expand Down Expand Up @@ -539,7 +539,11 @@ def _safe_get(self) -> Any:
return item
except Empty:
# check if producer is still running
if self._stop_event.is_set() or self._preprocessing_thread is None or not self._preprocessing_thread.is_alive():
if (
self._stop_event.is_set()
or self._preprocessing_thread is None
or not self._preprocessing_thread.is_alive()
):
return None
continue

Expand Down
2 changes: 0 additions & 2 deletions deeplabcut/pose_estimation_pytorch/runners/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ def log_images(
targets: the targets for each model head
step: the current step
"""
pass

def select_images_to_log(self, train: DataLoader, valid: DataLoader) -> None:
"""Selects the train and test images to log.
Expand Down Expand Up @@ -448,7 +447,6 @@ def log_config(self, config: dict = None) -> None:
Args:
config: Experiment config file.
"""
pass

def _load_existing_data(self) -> None:
"""Loads existing CSV data if the log file exists."""
Expand Down
4 changes: 0 additions & 4 deletions deeplabcut/pose_estimation_pytorch/runners/schedulers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from typing import Any

import torch
from omegaconf import DictConfig, ListConfig, OmegaConf
from torch.optim.lr_scheduler import _LRScheduler


Expand Down Expand Up @@ -87,9 +86,6 @@ def build_scheduler(
# unpicklable omegaconf objects with _parent references.
# TODO @deruyter92: decide on typed / plain list / dict in upstream code
# Then this check can be removed.
if isinstance(param, (ListConfig, DictConfig)):
param = OmegaConf.to_container(param, resolve=True)

if isinstance(param, list):
param = [_parse_scheduler_param(p, optimizer) for p in param]
else:
Expand Down
2 changes: 0 additions & 2 deletions deeplabcut/pose_estimation_tensorflow/nnets/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,3 @@ def drop_connect(inputs, is_training, drop_connect_rate):

class DepthwiseConv2D(tf.keras.layers.DepthwiseConv2D, tf.compat.v1.layers.Layer):
"""Wrap keras DepthwiseConv2D to tf.layers."""

pass
2 changes: 1 addition & 1 deletion deeplabcut/refine_training_dataset/outlier_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,7 @@ def merge_datasets(config, forceiterate=None):
else:
print("The following folder was not manually refined,...", folder)
flagged = True
pass # this folder does not contain a MachineLabelsRefine file (not updated...)
# this folder does not contain a MachineLabelsRefine file (not updated...)

if not flagged:
# updates iteration by 1
Expand Down
2 changes: 1 addition & 1 deletion deeplabcut/refine_training_dataset/tracklets.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def get_frame_ind(s):

# Map a tracklet # to the animal ID it belongs to or the bodypart # it corresponds to.
self.individuals = self.cfg["individuals"] + (["single"] if len(self.cfg["uniquebodyparts"]) else [])
self.tracklet2id = [i for i in range(0, self.nindividuals) for _ in bodyparts_multi] + [
self.tracklet2id = [i for i in range(self.nindividuals) for _ in bodyparts_multi] + [
self.nindividuals
] * len(bodyparts_single)
bps = bodyparts_multi + bodyparts_single
Expand Down
Loading