Skip to content
Merged
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
44 changes: 29 additions & 15 deletions deeplabcut/pose_estimation_pytorch/apis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,7 @@ def list_videos_in_folder(
else:
video_suffixes = [video_type]

suffixes = [
s if s.startswith(".") else "." + s for s in video_suffixes
]
suffixes = [s if s.startswith(".") else "." + s for s in video_suffixes]
videos_in_dir = [file for file in path.iterdir() if file.suffix in suffixes]
if shuffle:
random.shuffle(videos_in_dir)
Expand Down Expand Up @@ -365,15 +363,28 @@ def build_predictions_dataframe(
image_name_to_index: Callable[[str], tuple[str, ...]] | None = None,
) -> pd.DataFrame:
"""
Builds a pandas DataFrame from pose prediction data. The resulting DataFrame
includes properly formatted indices and column names for compatibility with
DeepLabCut workflows.

Args:
scorer:
predictions
parameters:
image_name_to_index:
scorer: The name of the scorer used to generate the predictions.
predictions: A dictionary where each key is an image name and its value is
another dictionary. The inner dictionary contains prediction data for
"bodyparts" and optionally "unique_bodyparts". The "bodyparts" and
"unique_bodyparts" data arrays are expected to be 3-dimensional, containing
pose predictions in format (num_predicted_individuals, num_bodyparts, 3).
parameters: Dataset-specific parameters required for constructing DataFrame
columns.
image_name_to_index: A callable function that takes an image name and returns
a tuple representing the DataFrame index. If None, indices will be
generated without transformation.

Returns:

A pandas DataFrame containing the processed prediction data for all provided
images. The DataFrame index corresponds to the image names or their
transformed values (if `image_name_to_index` is provided). The DataFrame
columns are constructed using the provided scorer and parameters.
"""
image_names = []
prediction_data = []
Expand Down Expand Up @@ -405,17 +416,19 @@ def build_bboxes_dict_for_dataframe(
) -> dict:
"""
Creates a dictionary with bounding boxes from predictions.
The keys of the dictionary are the same as the index of the dataframe created by build_predictions_dataframe.
Therefore, the structures returned by build_predictions_dataframe and by build_bboxes_dict_for_dataframe
can be accessed with the same keys.

The keys of the dictionary are the same as the index of the dataframe created by
build_predictions_dataframe. Therefore, the structures returned by
build_predictions_dataframe and by build_bboxes_dict_for_dataframe can be accessed
with the same keys.

Args:
predictions: Dictionary containing the evaluation results
image_name_to_index, optional: a transform to apply on each image_name
image_name_to_index: a transform to apply on each image_name

Returns:
Dictionary with sames keys as in the dataframe returned by build_predictions_dataframe,
and respective bounding boxes and scores, if any.
Dictionary with sames keys as in the dataframe returned by
build_predictions_dataframe, and respective bounding boxes and scores, if any.
"""

image_names = []
Expand Down Expand Up @@ -549,7 +562,8 @@ def get_inference_runners(
max_individuals=max_individuals,
),
load_weights_only=model_config["detector"]["runner"].get(
"load_weights_only", None,
"load_weights_only",
None,
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ runner:
optimizer:
type: AdamW
params:
lr: 0.0005
lr: 0.001
scheduler:
type: LRListScheduler
params:
lr_list: [ [ 1e-4 ], [ 1e-5 ] ]
milestones: [ 90, 190 ]
milestones: [ 90, 120 ]
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ runner:
optimizer:
type: AdamW
params:
lr: 0.0005
lr: 0.001
scheduler:
type: LRListScheduler
params:
lr_list: [ [ 1e-4 ], [ 1e-5 ] ]
milestones: [ 90, 190 ]
milestones: [ 90, 120 ]
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ runner:
optimizer:
type: AdamW
params:
lr: 0.0005
lr: 0.001
scheduler:
type: LRListScheduler
params:
lr_list: [ [ 1e-4 ], [ 1e-5 ] ]
milestones: [ 90, 190 ]
milestones: [ 90, 120 ]
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ model:
type: ResNet
model_name: resnet101
output_stride: 16
freeze_bn_stats: true
freeze_bn_stats: false
freeze_bn_weights: false
backbone_output_channels: 2048
runner:
optimizer:
type: AdamW
params:
lr: 0.0001
lr: 0.001
scheduler:
type: LRListScheduler
params:
lr_list: [ [ 1e-5 ], [ 1e-6 ] ]
milestones: [ 160, 190 ]
lr_list: [ [ 1e-4 ], [ 1e-5 ] ]
milestones: [ 90, 120 ]
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ model:
type: ResNet
model_name: resnet50_gn
output_stride: 16
freeze_bn_stats: true
freeze_bn_stats: false
freeze_bn_weights: false
backbone_output_channels: 2048
runner:
optimizer:
type: AdamW
params:
lr: 0.0001
lr: 0.001
scheduler:
type: LRListScheduler
params:
lr_list: [ [ 1e-5 ], [ 1e-6 ] ]
milestones: [ 160, 190 ]
lr_list: [ [ 1e-4 ], [ 1e-5 ] ]
milestones: [ 90, 120 ]
15 changes: 6 additions & 9 deletions deeplabcut/pose_estimation_pytorch/config/base/aug_default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ train:
affine:
p: 0.5
rotation: 30
scaling: [1.0, 1.0]
scaling: [0.5, 1.25]
translation: 0
collate:
type: ResizeFromDataSizeCollate
min_scale: 0.4
max_scale: 1.0
min_short_side: 128
max_short_side: 1152
multiple_of: 32
to_square: false
covering: false
crop_sampling:
width: 400
height: 400
max_shift: 0.1
method: hybrid
gaussian_noise: 12.75
hist_eq: false
motion_blur: false
Expand Down
2 changes: 1 addition & 1 deletion deeplabcut/pose_estimation_pytorch/runners/train.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ def _compute_epoch_metrics(self) -> dict[str, float]:
scores = metrics.compute_metrics(
ground_truth=self._epoch_ground_truth["bodyparts"],
predictions=self._epoch_predictions["bodyparts"],
single_animal=False, # FIXME(niels): Get this value from the dataset
single_animal=True,
unique_bodypart_gt=self._epoch_ground_truth.get("unique_bodyparts"),
unique_bodypart_poses=self._epoch_predictions.get("unique_bodyparts"),
pcutoff=0.6,
Expand Down