Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
4729ef3
Added inference code for incoming super models
yeshaokai Oct 14, 2022
ea9efc8
handled empty prediction in multiple scale prediction. Formatting
yeshaokai Oct 15, 2022
d638d70
Update deeplabcut/pose_estimation_tensorflow/predict_supermodel.py
MMathisLab Oct 20, 2022
636fbce
Update deeplabcut/pose_estimation_tensorflow/predict_supermodel.py
MMathisLab Oct 20, 2022
eb70f2f
Update deeplabcut/pose_estimation_tensorflow/predict_supermodel.py
yeshaokai Oct 21, 2022
020cfce
Update deeplabcut/pose_estimation_tensorflow/predict_supermodel.py
yeshaokai Oct 21, 2022
da2bb80
fixed DLCscorer in make_label_video for suffix
yeshaokai Oct 21, 2022
6bc0593
Added example document. Added top down inference
yeshaokai Oct 21, 2022
f8a5385
Fixed previous commit
yeshaokai Oct 21, 2022
45763fc
Made the scorer convetion include DLC_
yeshaokai Oct 31, 2022
329ae73
handled the case where one of topdown prediction gives empty prediction
yeshaokai Oct 31, 2022
ff2f6db
first docs started
MMathisLab Nov 6, 2022
f26f6fd
Update _toc.yml
MMathisLab Nov 6, 2022
28aa5cf
Merge pull request #1 from DeepLabCut/master
yeshaokai Nov 7, 2022
fe8b694
change scale_list nonoptional
yeshaokai Nov 7, 2022
e33b6c5
Added functional test script and api docs
yeshaokai Nov 7, 2022
227ad23
Fixed a formatting
yeshaokai Nov 7, 2022
bc57bd9
safer way to parse num_kpts
yeshaokai Nov 10, 2022
dc62f36
Made the superanimal inference simpler
yeshaokai Nov 11, 2022
e76c5af
Simplify the API and added more docs
yeshaokai Nov 11, 2022
7277182
changed the relative path in the rst file
yeshaokai Nov 11, 2022
1625057
Fixed circular import
yeshaokai Nov 11, 2022
136572a
Fixed known issue
yeshaokai Nov 15, 2022
dacbf37
Merge branch 'super_model_inference' of github.com:yeshaokai/DeepLabC…
yeshaokai Nov 15, 2022
7d7a023
Further getting rid of the dependency on config for inference
yeshaokai Nov 29, 2022
87ce73c
make_labeled_video takes superanimal_name now
yeshaokai Nov 29, 2022
9f17361
Update docs/ModelZoo.md
yeshaokai Nov 30, 2022
455c3f4
Merge branch 'DeepLabCut:main' into super_model_inference
yeshaokai Nov 30, 2022
c42e2e0
Cleanup and removal of bbox file
jeylau Dec 1, 2022
f88e460
Minor fixes
jeylau Dec 2, 2022
fb276b9
Run black and isort
jeylau Dec 2, 2022
0d55fb6
Remove unused variables
jeylau Dec 2, 2022
b116d61
Get rid of the additional VideoWriter
jeylau Dec 2, 2022
a8b6d7f
Fix test
jeylau Dec 2, 2022
c008b8b
Hide _video_inference from high-level API
jeylau Dec 2, 2022
a52709d
Add test_get_multi_scale_frames
jeylau Dec 2, 2022
794b875
Clean configs
jeylau Dec 7, 2022
500b90b
Accelerate pandas's code
jeylau Dec 7, 2022
7b978dd
Test projection back to original image size
jeylau Dec 7, 2022
0ef2224
Merge pull request #2014 from yeshaokai/super_model_inference
jeylau Dec 7, 2022
b57f638
Faster DataFrame creation
jeylau Dec 12, 2022
11c9214
Remove tools folder
jeylau Dec 14, 2022
69dd13a
Add dlclibrary for model download from zoo
jeylau Dec 14, 2022
a61aca8
also remove old weight download function
AlexEMG Dec 14, 2022
8de3260
Add dlclibrary to setup.py
jeylau Dec 15, 2022
3387f37
Merge remote-tracking branch 'official/add_dlclib_in' into develop
yeshaokai Dec 20, 2022
660a772
Added modelzoo folder
yeshaokai Nov 29, 2022
ed8867d
removed domain matcher for now
yeshaokai Nov 29, 2022
d77a9b3
fix last commit
yeshaokai Nov 29, 2022
c247499
Users define threshold and pcutoff for adaptation api
yeshaokai Nov 29, 2022
1d09dec
Added documentation. Only keep the without project way of using the api
yeshaokai Nov 29, 2022
c8a0eb6
Now video adaptation code uses video reader for training
yeshaokai Dec 7, 2022
b445057
reformatting
yeshaokai Dec 12, 2022
4697459
Update deeplabcut/modelzoo/apis/spatiotemporal_adapt.py
yeshaokai Dec 12, 2022
4030a9d
Update deeplabcut/modelzoo/apis/spatiotemporal_adapt.py
yeshaokai Dec 12, 2022
f135132
Update deeplabcut/modelzoo/apis/spatiotemporal_adapt.py
yeshaokai Dec 12, 2022
bec4bf8
Remove unused imports
jeylau Dec 13, 2022
3d08cfe
Remove duplicate code
jeylau Dec 13, 2022
8a7ce5e
Fixed unused threshold
yeshaokai Dec 13, 2022
69fb761
Avoid hardcoding supermodel names
jeylau Dec 13, 2022
9ceecf5
Add missing `vid` attribute
jeylau Dec 13, 2022
946c663
Delay import
jeylau Dec 13, 2022
5bd8c73
Add missing attribute
jeylau Dec 13, 2022
2a0d1cc
Add video adaptation to GUI
jeylau Dec 13, 2022
782c8a6
Update branch name to "main" in GitHub's CI workflow (#2089)
jeylau Dec 15, 2022
ca2d86a
inference api and adaptation api work with hugging face weights
yeshaokai Dec 20, 2022
5a20224
minor update
yeshaokai Dec 20, 2022
f525621
trying to avoid circular import
yeshaokai Dec 20, 2022
ddcd6e5
WIP fixing previous commit
yeshaokai Dec 20, 2022
de14948
fixed logic for getting image shape for video adaptation
yeshaokai Dec 20, 2022
f41fc04
smaller batch sizes in train configs
yeshaokai Dec 20, 2022
09e8b37
fix the path after enforcing abs path
yeshaokai Dec 21, 2022
4877e77
Added colab example
yeshaokai Dec 21, 2022
b4b3356
adaptation api takes kwargs
yeshaokai Dec 21, 2022
b30797f
updated docstring for inference code
yeshaokai Dec 22, 2022
7edc5c2
Update ModelZoo.md
MMathisLab Dec 23, 2022
d45da22
Add dlclibrary for model download from zoo (#2088)
jeylau Dec 22, 2022
6694719
Backwards comp
jeylau Dec 23, 2022
dc88466
Add some multi-animal defaults
jeylau Dec 23, 2022
6d26f4b
Add a missing parameter
jeylau Dec 23, 2022
d05e95c
Add empty paf graph
jeylau Dec 23, 2022
62e3179
Change dataset_type to single-animal
jeylau Dec 23, 2022
456b5e2
Merge branch 'develop' into data-and-api
jeylau Dec 23, 2022
f8ea42d
Merge pull request #2078 from yeshaokai/data-and-api
jeylau Dec 23, 2022
e3a5735
Update ModelZoo.md
MMathisLab Jan 3, 2023
60ef6b1
Merge branch 'main' into develop
jeylau Jan 9, 2023
19ee928
Minor fixes
jeylau Jan 9, 2023
c56b396
Video adaptation api (up to date) (#2116)
yeshaokai Jan 19, 2023
f8ba071
Fix imports
jeylau Jan 20, 2023
61d7942
Fix multiprocessing RuntimeError
jeylau Jan 20, 2023
5755f74
Fix model zoo GUI tab
jeylau Jan 20, 2023
15eec56
Fix typo
jeylau Jan 20, 2023
25e6ffd
Fix custom config path
jeylau Jan 20, 2023
a67631b
Test video adaptation on a shorter video
jeylau Jan 20, 2023
d68274d
Avoid empty folder creation if not adapting
jeylau Jan 20, 2023
a4a6318
Remove unused apply_filter flag
jeylau Jan 20, 2023
9c77988
Avoid multiprocessing when started with spawn
jeylau Jan 20, 2023
139caf9
Fix hardcoded paths
jeylau Jan 20, 2023
d1599e1
Option to pass in display and saveiters
jeylau Jan 20, 2023
5ad8a94
Merge branch 'main' into develop
jeylau Jan 20, 2023
f28425c
Append video analysis success
jeylau Jan 24, 2023
bd6fdee
Silence numpy RuntimeWarnings
jeylau Jan 24, 2023
0badf69
Add Colab example and form fields
jeylau Jan 24, 2023
9ea54ab
30x speedup of averaging over multiple scales
jeylau Jan 24, 2023
eed366e
Add Open in Colab badge
jeylau Jan 25, 2023
0eef655
Minor change
jeylau Jan 25, 2023
41ad473
Use newer API in modelzoo's GUI tab
jeylau Jan 25, 2023
e9ed866
Add trajectory plotting to superanimal inference
jeylau Jan 27, 2023
fe0d077
Update spatiotemporal_adapt.py
jeylau Jan 27, 2023
3b58aac
Rename variable
jeylau Jan 27, 2023
64979bc
Add tools directory back in
jeylau Mar 7, 2023
259db76
Merge branch 'main' into develop
jeylau Mar 7, 2023
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
1 change: 1 addition & 0 deletions deeplabcut/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
visualize_paf,
extract_save_all_maps,
export_model,
video_inference_superanimal
)


Expand Down
1 change: 1 addition & 0 deletions deeplabcut/gui/tabs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from deeplabcut.gui.tabs.extract_outlier_frames import ExtractOutlierFrames
from deeplabcut.gui.tabs.label_frames import LabelFrames
from deeplabcut.gui.tabs.manage_project import ManageProject
from deeplabcut.gui.tabs.modelzoo import ModelZoo
from deeplabcut.gui.tabs.open_project import OpenProject
from deeplabcut.gui.tabs.refine_tracklets import RefineTracklets
from deeplabcut.gui.tabs.train_network import TrainNetwork
Expand Down
103 changes: 103 additions & 0 deletions deeplabcut/gui/tabs/modelzoo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import deeplabcut
from PySide6 import QtWidgets
from PySide6.QtCore import Qt, Signal, QTimer
from PySide6.QtGui import QRegularExpressionValidator
from deeplabcut.gui.components import (
DefaultTab,
VideoSelectionWidget,
_create_label_widget,
_create_grid_layout,
)
from deeplabcut.modelzoo.utils import parse_available_supermodels


class RegExpValidator(QRegularExpressionValidator):
validationChanged = Signal(QRegularExpressionValidator.State)

def validate(self, input_, pos):
state, input_, pos = super().validate(input_, pos)
self.validationChanged.emit(state)
return state, input_, pos


class ModelZoo(DefaultTab):
def __init__(self, root, parent, h1_description):
super().__init__(root, parent, h1_description)
self._val_pattern = "(\d{3,5},\s*)+\d{3,5}"
self._set_page()

@property
def files(self):
return self.video_selection_widget.files

def _set_page(self):
self.main_layout.addWidget(_create_label_widget("Video Selection", "font:bold"))
self.video_selection_widget = VideoSelectionWidget(self.root, self)
self.main_layout.addWidget(self.video_selection_widget)

model_settings_layout = _create_grid_layout(margins=(20, 0, 0, 0))

section_title = _create_label_widget(
"Supermodel Settings", "font:bold", (0, 50, 0, 0)
)

model_combo_text = QtWidgets.QLabel("Supermodel name")
self.model_combo = QtWidgets.QComboBox()
supermodels = parse_available_supermodels()
self.model_combo.addItems(supermodels.keys())

scales_label = QtWidgets.QLabel('Scale list')
self.scales_line = QtWidgets.QLineEdit("", parent=self)
self.scales_line.setPlaceholderText("Optionally input a list of integer sizes separated by commas...")
validator = RegExpValidator(self._val_pattern, self)
validator.validationChanged.connect(self._handle_validation_change)
self.scales_line.setValidator(validator)

model_settings_layout.addWidget(section_title, 0, 0)
model_settings_layout.addWidget(model_combo_text, 1, 0)
model_settings_layout.addWidget(self.model_combo, 1, 1)
model_settings_layout.addWidget(scales_label, 2, 0)
model_settings_layout.addWidget(self.scales_line, 2, 1)
self.main_layout.addLayout(model_settings_layout)

self.run_button = QtWidgets.QPushButton("Run")
self.run_button.clicked.connect(self.run_video_adaptation)
self.main_layout.addWidget(self.run_button, alignment=Qt.AlignRight)

def _handle_validation_change(self, state):
if state == RegExpValidator.Invalid:
color = 'red'
elif state == RegExpValidator.Intermediate:
color = 'gold'
elif state == RegExpValidator.Acceptable:
color = 'lime'
self.scales_line.setStyleSheet(f'border: 1px solid {color}')
QTimer.singleShot(500, lambda: self.scales_line.setStyleSheet(''))

def run_video_adaptation(self):
videos = list(self.files)
if not videos:
msg = QtWidgets.QMessageBox()
msg.setIcon(QtWidgets.QMessageBox.Critical)
msg.setText("You must select a video file")
msg.setWindowTitle("Error")
msg.setMinimumWidth(400)
msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
msg.exec_()
return

scales = []
scales_ = self.scales_line.text()
if scales_:
if (self.scales_line.validator().validate(scales_, 0)[0] == RegExpValidator.Acceptable):
scales = list(map(int, scales_.split(",")))
supermodel_name = self.model_combo.currentText()
videotype = self.video_selection_widget.videotype_widget.currentText()

deeplabcut.video_inference_superanimal(
videos,
supermodel_name,
videotype=videotype,
video_adapt=True,
scale_list=scales,
)
4 changes: 4 additions & 0 deletions deeplabcut/gui/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@ def add_tabs(self):
self.refine_tracklets = RefineTracklets(
root=self, parent=None, h1_description="DeepLabCut - Refine labels"
)
self.modelzoo = ModelZoo(
root=self, parent=None, h1_description="DeepLabCut - Model Zoo"
)
self.video_editor = VideoEditor(
root=self, parent=None, h1_description="DeepLabCut - Optional Video Editor"
)
Expand All @@ -490,6 +493,7 @@ def add_tabs(self):
self.extract_outlier_frames, "Extract outlier frames (*)"
)
self.tab_widget.addTab(self.refine_tracklets, "Refine tracklets (*)")
self.tab_widget.addTab(self.modelzoo, "Model Zoo")
self.tab_widget.addTab(self.video_editor, "Video editor (*)")

if not self.is_multianimal:
Expand Down
Empty file added deeplabcut/modelzoo/__init__.py
Empty file.
1 change: 1 addition & 0 deletions deeplabcut/modelzoo/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .spatiotemporal_adapt import SpatiotemporalAdaptation
199 changes: 199 additions & 0 deletions deeplabcut/modelzoo/api/spatiotemporal_adapt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import deeplabcut
import glob
import os
from deeplabcut.modelzoo.utils import parse_available_supermodels
from deeplabcut.modelzoo.api import superanimal_inference
from deeplabcut.utils.plotting import _plot_trajectories
from pathlib import Path


class SpatiotemporalAdaptation:
def __init__(
self,
video_path,
supermodel_name,
scale_list=[],
videotype="mp4",
adapt_iterations=1000,
modelfolder="",
customized_pose_config="",
init_weights="",
):

"""
This class supports video adaptation to a super model.

Parameters
----------
video_path: string
The string to the path of the video
init_weights: string
The path to a superanimal model's checkpoint
supermodel_name: string
Currently we support supertopview(LabMice) and superquadruped (quadruped side-view animals)
scale_list: list
A list of different resolutions for the spatial pyramid
videotype: string
Checks for the extension of the video in case the input to the video is a directory.\n Only videos with this extension are analyzed. The default is ``.avi``
adapt_iterations: int
Number of iterations for adaptation training. Empirically 1000 is sufficient. Training longer can cause worse performance depending whether there is occlusion in the video
modelfolder: string, optional
Because the API does not need a dlc project, the checkpoint and logs go to this temporary model folder, and otherwise model is saved to the current work place
customized_pose_config: string, optional
For future support of non modelzoo model

Examples
--------

from deeplabcut.modelzoo.apis import SpatiotemporalAdaptation
video_path = '/mnt/md0/shaokai/openfield_video/m3v1mp4.mp4'
superanimal_name = 'superanimal_topviewmouse'
videotype = 'mp4'
>>> adapter = SpatiotemporalAdaptation(video_path,
superanimal_name,
modelfolder = "temp_topview",
videotype = videotype)

adapter.before_adapt_inference()
adapter.adaptation_training()
adapter.after_adapt_inference()


"""
supermodels = parse_available_supermodels()
if supermodel_name not in supermodels:
raise ValueError(f"`supermodel_name` should be one of: {', '.join(supermodels)}.")

self.video_path = video_path
self.supermodel_name = supermodel_name
self.scale_list = scale_list
self.videotype = videotype
vname = str(Path(self.video_path).stem)
self.adapt_modelprefix = vname + "_video_adaptation"
self.adapt_iterations = adapt_iterations
self.modelfolder = modelfolder
self.init_weights = init_weights

if not customized_pose_config:
dlc_root_path = os.sep.join(deeplabcut.__file__.split(os.sep)[:-1])
self.customized_pose_config = os.path.join(
dlc_root_path,
"pose_estimation_tensorflow",
"superanimal_configs",
supermodels[self.supermodel_name],
)
else:
self.customized_pose_config = customized_pose_config

def before_adapt_inference(self,
make_video=False,
**kwargs):
if self.init_weights != "":
_ = superanimal_inference.video_inference(
[self.video_path],
self.supermodel_name,
videotype=self.videotype,
scale_list=self.scale_list,
init_weights=self.init_weights,
customized_test_config=self.customized_pose_config,
)
else:
self.init_weights, _ = superanimal_inference.video_inference(
[self.video_path],
self.supermodel_name,
videotype=self.videotype,
scale_list=self.scale_list,
customized_test_config=self.customized_pose_config,
)
if make_video:
deeplabcut.create_labeled_video(
"",
[self.video_path],
videotype=self.videotype,
filtered=False,
init_weights=self.init_weights,
draw_skeleton=True,
superanimal_name=self.supermodel_name,
**kwargs
)

def train_without_project(self, pseudo_label_path, **kwargs):
from deeplabcut.pose_estimation_tensorflow.core.train_multianimal import train

displayiters = kwargs.pop("displayiters", 500)
saveiters = kwargs.pop("saveiters", 1000)
train(
self.customized_pose_config,
displayiters=displayiters,
saveiters=saveiters,
maxiters=self.adapt_iterations,
modelfolder=self.modelfolder,
init_weights=self.init_weights,
pseudo_labels=pseudo_label_path,
video_path=self.video_path,
**kwargs
)

def adaptation_training(self, displayiters=500, saveiters=1000, **kwargs):
"""
There should be two choices, either taking a config, with is then assuming there is a DLC project.
Or we make up a fake one, then we use a light way convention to do adaptation
"""

# looking for the pseudo label path
DLCscorer = "DLC_" + Path(self.init_weights).stem
vname = str(Path(self.video_path).stem)
video_root = Path(self.video_path).parent

_, pseudo_label_path, _, _ = deeplabcut.auxiliaryfunctions.load_analyzed_data(
video_root, vname, DLCscorer, False, ""
)
if self.modelfolder != "":
os.makedirs(self.modelfolder, exist_ok=True)

self.train_without_project(
pseudo_label_path,
displayiters=displayiters,
saveiters=saveiters,
**kwargs,
)

def after_adapt_inference(self, **kwargs):

pattern = os.path.join(
self.modelfolder, f"snapshot-{self.adapt_iterations}.index"
)
ref_proj_config_path = ""

files = glob.glob(pattern)

if not len(files):
raise ValueError("Weights were not found.")

adapt_weights = files[0].replace(".index", "")

# spatial pyramid is not for adapted model

scale_list = kwargs.pop('scale_list', [])
_, datafiles = superanimal_inference.video_inference(
[self.video_path],
self.supermodel_name,
videotype=self.videotype,
init_weights=adapt_weights,
scale_list=scale_list,
customized_test_config=self.customized_pose_config,
)

if kwargs.pop('plot_trajectories', True):
_plot_trajectories(datafiles[0])

deeplabcut.create_labeled_video(
ref_proj_config_path,
[self.video_path],
videotype=self.videotype,
filtered=False,
init_weights=adapt_weights,
draw_skeleton=True,
superanimal_name=self.supermodel_name,
**kwargs
)
Loading