diff --git a/CHANGELOG.md b/CHANGELOG.md index a0aa703..86a0842 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) convention. +## [0.2.9] - 2023-10-18 + ++ Update - DLC project directory (named v2) of example data ++ Update - The mounting strategy to update the environment variables ++ Update - Add a new tutorial notebook ++ Fix - Rename pipeline link in README + ## [0.2.8] - 2023-08-07 + Update - GitHub Actions with new reusable workflows diff --git a/element_deeplabcut/model.py b/element_deeplabcut/model.py index 3a17253..c31ac82 100644 --- a/element_deeplabcut/model.py +++ b/element_deeplabcut/model.py @@ -229,7 +229,7 @@ def extract_new_body_parts(cls, dlc_config: dict, verbose: bool = True): """Returns list of body parts present in dlc config, but not BodyPart table. Args: - dlc_config (str or dict): path to a config.y*ml, or dict of such contents. + dlc_config ( varchar(255) ): Path to a config.y*ml. verbose (bool): Default True. Print both existing and new items to console. """ if not isinstance(dlc_config, dict): @@ -257,7 +257,7 @@ def insert_from_config( """Insert all body parts from a config file. Args: - dlc_config (str or dict): path to a config.y*ml, or dict of such contents. + dlc_config ( varchar(255) ): Path to a config.y*ml. descriptions (list): Optional. List of strings describing new body parts. prompt (bool): Optional, default True. Prompt for confirmation before insert. """ @@ -365,8 +365,8 @@ def insert_new_model( Args: model_name (str): User-friendly name for this model. - dlc_config (str or dict): path to a config.y*ml, or dict of such contents. - shuffle (int): Shuffled or not as 1 or 0. + dlc_config ( varchar(255) ): Path to a config.y*ml. + shuffle (int): Which shuffle of the training dataset. trainingsetindex (int): Index of training fraction list in config.yaml. model_description (str): Optional. Description of this model. model_prefix (str): Optional. Filename prefix used across DLC project @@ -377,21 +377,18 @@ def insert_new_model( from deeplabcut.utils.auxiliaryfunctions import GetScorerName # isort:skip # handle dlc_config being a yaml file - if not isinstance(dlc_config, dict): - dlc_config_fp = find_full_path(get_dlc_root_data_dir(), Path(dlc_config)) - assert dlc_config_fp.exists(), ( - "dlc_config is neither dict nor filepath" + f"\n Check: {dlc_config_fp}" - ) - if dlc_config_fp.suffix in (".yml", ".yaml"): - with open(dlc_config_fp, "rb") as f: - dlc_config = yaml.safe_load(f) - if isinstance(params, dict): - dlc_config.update(params) + dlc_config_fp = find_full_path(get_dlc_root_data_dir(), Path(dlc_config)) + assert dlc_config_fp.exists(), ( + "dlc_config is not a filepath" + f"\n Check: {dlc_config_fp}" + ) + if dlc_config_fp.suffix in (".yml", ".yaml"): + with open(dlc_config_fp, "rb") as f: + dlc_config = yaml.safe_load(f) + if isinstance(params, dict): + dlc_config.update(params) # ---- Get and resolve project path ---- - project_path = find_full_path( - get_dlc_root_data_dir(), dlc_config.get("project_path", project_path) - ) + project_path = dlc_config_fp.parent dlc_config["project_path"] = project_path.as_posix() # update if different root_dir = find_root_directory(get_dlc_root_data_dir(), project_path) @@ -452,11 +449,7 @@ def insert_new_model( ): print("Canceled insert.") return - # ---- Save DJ-managed config ---- - try: - _ = dlc_reader.save_yaml(project_path, dlc_config) - except PermissionError: - pass + # ____ Insert into table ---- with cls.connection.transaction: cls.insert1(model_dict) diff --git a/element_deeplabcut/version.py b/element_deeplabcut/version.py index d28c47d..dde2c05 100644 --- a/element_deeplabcut/version.py +++ b/element_deeplabcut/version.py @@ -1,4 +1,4 @@ """ Package metadata """ -__version__ = "0.2.8" +__version__ = "0.2.9" diff --git a/notebooks/tutorial.ipynb b/notebooks/tutorial.ipynb index 5a6b16e..825c12e 100644 --- a/notebooks/tutorial.ipynb +++ b/notebooks/tutorial.ipynb @@ -11,7 +11,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Open-source Data Pipeline for Markerless Pose Estimation in Neurophysiology**\n", + "### **Open-source Data Pipeline for Markerless Pose Estimation in Neurophysiology**\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", "This tutorial aims to provide a comprehensive understanding of the open-source data pipeline by `Element-DeepLabCut`." ] @@ -27,7 +33,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The package is designed to simplify pose estimation analyses and streamline data organization using `DataJoint`. " + "The package is designed to integrate the **model training** and **pose estimation analyses** into a data pipeline and streamline model and video management using DataJoint. " ] }, { @@ -41,69 +47,70 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "By the end of this tutorial, participants will have a clear grasp of how to set up and apply the `Element DeepLabCut` for their specific pose estimation projects. " + "By the end of this tutorial, you will have a clear grasp of how to set up and integrate the `Element DeepLabCut` into your specific research projects and your lab. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "**Key Components and Objectives**\n", - "\n", - "**- Setup**\n", - "\n", - "**- Designing the DataJoint Pipeline**\n", - "\n", - "**- Step 1: Register an Existing Model in the DataJoint Pipeline**\n", - "\n", - "**- Step 2: Insert Subject, Session, and Behavior Videos**\n", - "\n", - "**- Step 3: DeepLabCut Inference Task**\n", - "\n", - "**- Step 4: Visualization of Results**" + "#### **Key Components and Objectives**\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For detailed documentation and tutorials on general DataJoint principles that support collaboration, automation, reproducibility, and visualizations:\n", "\n", - "[`DataJoint for Python - Interactive Tutorials`](https://github.com/datajoint/datajoint-tutorials) covers fundamentals, including table tiers, query operations, fetch operations, automated computations with the make function, and more.\n", + "**- Setup**\n", + "\n", + "**- Designing the DataJoint Pipeline**\n", "\n", - "[`DataJoint for Python - Documentation`](https://datajoint.com/docs/core/datajoint-python/0.14/)\n", + "**- Step 1: Register an Existing Model in the DataJoint Pipeline**\n", + "\n", + "**- Step 2: Insert Example Data into Subject and Session tables**\n", "\n", - "[`DataJoint Element for DeepLabCut - Documentation`](https://datajoint.com/docs/elements/element-deeplabcut/0.2/)" + "**- Step 3: Run the DeepLabCut Inference Task**\n", + "\n", + "**- Step 4: Visualize the Results**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Setup" + "### **Setup**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This tutorial examines the **behavior of a freely moving mouse** in an open-field environment. \n", + "This tutorial examines the **behavior of a freely moving mouse** in an open-field environment.\n", "\n", "The goal is to extract pose estimations of the animal's **head and tail base** from video footage. \n", "\n", - "This information offers valuable insights into the **animal's movements, postures, and interactions** within the environment. \n", + "The **resulting x and y coordinates** offer valuable insights into the **animal's movements, postures, and interactions** within the environment. \n", "\n", - "The results of this Element example can be **combined with other modalities** to create a complete data pipeline for your specific lab or study.\n", + "The results of this Element example can be **combined with other modalities** to create a complete customizable data pipeline for your specific lab or study. For instance, you can combine `element-deeplabcut` with `element-calcium-imaging` and `element-array-ephys` to characterize the neural activity.\n", "\n", "#### Steps to Run the Element-DeepLabCut\n", "\n", - "To run the Element, ensure that you have:\n", + "The input data for this data pipeline is as follows:\n", + "\n", + "- A DeepLabCut (DLC) project folder.\n", "\n", - "- A DeepLabCut (DLC) project folder on your machine.\n", + "- The labeled training data in your DLC project folder.\n", "\n", - "- Labeled data in your DLC project folder.\n", "\n", - "This tutorial includes a DLC project folder with example data and its results in `example_data`. " + "This tutorial includes this DLC project folder with example data and the results as well in `example_data` directory. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start this tutorial by importing the packages necessary to run the data pipeline." ] }, { @@ -118,13 +125,6 @@ " + \"element directory\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First start by importing the packages necessary to run this pipeline." - ] - }, { "cell_type": "code", "execution_count": 2, @@ -152,8 +152,8 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2023-10-17 15:33:12,400][INFO]: Connecting root@fakeservices.datajoint.io:3306\n", - "[2023-10-17 15:33:12,407][INFO]: Connected root@fakeservices.datajoint.io:3306\n" + "[2023-10-19 19:26:24,608][INFO]: Connecting root@fakeservices.datajoint.io:3306\n", + "[2023-10-19 19:26:24,616][INFO]: Connected root@fakeservices.datajoint.io:3306\n" ] }, { @@ -175,14 +175,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Design the DataJoint Pipeline" + "### **Design the DataJoint Pipeline**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This tutorial assumes that `element-deeplabcut` is already configured and instantiated, with the database connected downstream from existing subject and session tables. Import schemas for subject, session, train, model, etc.:" + "This tutorial presumes that the `element-deeplabcut` has been pre-configured and instantiated, with the database linked downstream to pre-existing `subject` and `session` tables. \n", + "\n", + "Now, we will proceed to import the essential schemas required to construct this data pipeline, with particular attention to the primary components: `train` and `model`." ] }, { @@ -194,7 +196,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[2023-10-17 15:33:14,915][WARNING]: lab.Project and related tables will be removed in a future version of Element Lab. Please use the project schema.\n" + "[2023-10-19 19:26:26,055][WARNING]: lab.Project and related tables will be removed in a future version of Element Lab. Please use the project schema.\n" ] } ], @@ -202,6 +204,13 @@ "from tutorial_pipeline import lab, subject, session, train, model " ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can represent a diagram of some of the upstream and downstream dependencies connected to these `model` and `train` schemas:" + ] + }, { "cell_type": "code", "execution_count": 5, @@ -210,768 +219,768 @@ { "data": { "image/svg+xml": [ - "\n", + "\n", "\n", "%3\n", - "\n", - "\n", + "\n", + "\n", "\n", - "lab.UserRole\n", - "\n", - "\n", - "lab.UserRole\n", + "subject.Line\n", + "\n", + "\n", + "subject.Line\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.LabMembership\n", - "\n", - "\n", - "lab.LabMembership\n", + "\n", + "\n", + "subject.Subject.Line\n", + "\n", + "\n", + "subject.Subject.Line\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "lab.UserRole->lab.LabMembership\n", - "\n", + "subject.Line->subject.Subject.Line\n", + "\n", "\n", - "\n", + "\n", + "\n", + "subject.Line.Allele\n", + "\n", + "\n", + "subject.Line.Allele\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "subject.Line->subject.Line.Allele\n", + "\n", + "\n", + "\n", "\n", - "session.SessionDirectory\n", - "\n", - "\n", - "session.SessionDirectory\n", + "subject.Subject.Source\n", + "\n", + "\n", + "subject.Subject.Source\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "model.VideoRecording.File\n", - "\n", - "\n", - "model.VideoRecording.File\n", + "lab.Project\n", + "\n", + "\n", + "lab.Project\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "subject.Strain\n", - "\n", - "\n", - "subject.Strain\n", + "session.ProjectSession\n", + "\n", + "\n", + "session.ProjectSession\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.Subject.Strain\n", - "\n", - "\n", - "subject.Subject.Strain\n", + "\n", + "\n", + "lab.Project->session.ProjectSession\n", + "\n", + "\n", + "\n", + "\n", + "lab.ProjectPublication\n", + "\n", + "\n", + "lab.ProjectPublication\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.Strain->subject.Subject.Strain\n", - "\n", + "\n", + "\n", + "lab.Project->lab.ProjectPublication\n", + "\n", "\n", - "\n", - "\n", - "lab.ProtocolType\n", - "\n", - "\n", - "lab.ProtocolType\n", + "\n", + "\n", + "lab.ProjectSourceCode\n", + "\n", + "\n", + "lab.ProjectSourceCode\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.Protocol\n", - "\n", - "\n", - "lab.Protocol\n", + "\n", + "\n", + "lab.Project->lab.ProjectSourceCode\n", + "\n", + "\n", + "\n", + "\n", + "lab.ProjectKeywords\n", + "\n", + "\n", + "lab.ProjectKeywords\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.ProtocolType->lab.Protocol\n", - "\n", + "\n", + "\n", + "lab.Project->lab.ProjectKeywords\n", + "\n", "\n", - "\n", - "\n", - "lab.ProjectPublication\n", - "\n", - "\n", - "lab.ProjectPublication\n", + "\n", + "\n", + "lab.ProjectUser\n", + "\n", + "\n", + "lab.ProjectUser\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.SubjectDeath\n", - "\n", - "\n", - "subject.SubjectDeath\n", + "\n", + "\n", + "lab.Project->lab.ProjectUser\n", + "\n", + "\n", + "\n", + "\n", + "model.Model.BodyPart\n", + "\n", + "\n", + "model.Model.BodyPart\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.SubjectCull\n", - "\n", - "\n", - "subject.SubjectCull\n", + "\n", + "\n", + "model.PoseEstimation.BodyPartPosition\n", + "\n", + "\n", + "model.PoseEstimation.BodyPartPosition\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.SubjectDeath->subject.SubjectCull\n", - "\n", + "\n", + "\n", + "model.Model.BodyPart->model.PoseEstimation.BodyPartPosition\n", + "\n", "\n", - "\n", - "\n", - "subject.Subject.Protocol\n", - "\n", - "\n", - "subject.Subject.Protocol\n", + "\n", + "\n", + "model.PoseEstimationTask\n", + "\n", + "\n", + "model.PoseEstimationTask\n", "\n", "\n", "\n", - "\n", - "\n", - "train.TrainingParamSet\n", - "\n", - "\n", - "train.TrainingParamSet\n", + "\n", + "\n", + "model.PoseEstimation\n", + "\n", + "\n", + "model.PoseEstimation\n", "\n", "\n", "\n", - "\n", - "\n", - "train.TrainingTask\n", - "\n", - "\n", - "train.TrainingTask\n", - "\n", + "\n", + "\n", + "model.PoseEstimationTask->model.PoseEstimation\n", + "\n", "\n", + "\n", + "\n", + "session.SessionDirectory\n", + "\n", + "\n", + "session.SessionDirectory\n", + "\n", "\n", - "\n", - "\n", - "train.TrainingParamSet->train.TrainingTask\n", - "\n", "\n", - "\n", - "\n", - "model.Model\n", - "\n", - "\n", - "model.Model\n", + "\n", + "\n", + "lab.Lab.Organization\n", + "\n", + "\n", + "lab.Lab.Organization\n", "\n", "\n", "\n", - "\n", - "\n", - "train.TrainingParamSet->model.Model\n", - "\n", + "\n", + "\n", + "lab.LabMembership\n", + "\n", + "\n", + "lab.LabMembership\n", + "\n", "\n", - "\n", + "\n", + "\n", "\n", - "subject.Allele.Source\n", - "\n", - "\n", - "subject.Allele.Source\n", + "session.Session.Attribute\n", + "\n", + "\n", + "session.Session.Attribute\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "lab.Device\n", - "\n", - "\n", - "lab.Device\n", + "lab.User\n", + "\n", + "\n", + "lab.User\n", "\n", "\n", "\n", - "\n", - "\n", - "model.VideoRecording\n", - "\n", - "\n", - "model.VideoRecording\n", + "\n", + "\n", + "lab.User->lab.LabMembership\n", + "\n", + "\n", + "\n", + "\n", + "session.SessionExperimenter\n", + "\n", + "\n", + "session.SessionExperimenter\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.Device->model.VideoRecording\n", - "\n", + "\n", + "\n", + "lab.User->session.SessionExperimenter\n", + "\n", "\n", - "\n", - "\n", - "session.ProjectSession\n", - "\n", - "\n", - "session.ProjectSession\n", + "\n", + "\n", + "subject.Subject.User\n", + "\n", + "\n", + "subject.Subject.User\n", "\n", "\n", "\n", - "\n", + "\n", + "\n", + "lab.User->subject.Subject.User\n", + "\n", + "\n", + "\n", + "\n", + "lab.User->lab.ProjectUser\n", + "\n", + "\n", + "\n", + "\n", + "model.PoseEstimation->model.PoseEstimation.BodyPartPosition\n", + "\n", + "\n", + "\n", "\n", - "subject.Line.Allele\n", - "\n", - "\n", - "subject.Line.Allele\n", + "model.VideoRecording.File\n", + "\n", + "\n", + "model.VideoRecording.File\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "train.VideoSet.File\n", - "\n", - "\n", - "train.VideoSet.File\n", + "lab.Device\n", + "\n", + "\n", + "lab.Device\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.Allele\n", - "\n", - "\n", - "subject.Allele\n", + "\n", + "\n", + "model.VideoRecording\n", + "\n", + "\n", + "model.VideoRecording\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.Allele->subject.Allele.Source\n", - "\n", - "\n", - "\n", - "\n", - "subject.Allele->subject.Line.Allele\n", - "\n", + "\n", + "\n", + "lab.Device->model.VideoRecording\n", + "\n", "\n", - "\n", - "\n", - "subject.Zygosity\n", - "\n", - "\n", - "subject.Zygosity\n", + "\n", + "\n", + "train.TrainingParamSet\n", + "\n", + "\n", + "train.TrainingParamSet\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.Allele->subject.Zygosity\n", - "\n", - "\n", - "\n", - "\n", - "model.PoseEstimationTask\n", - "\n", - "\n", - "model.PoseEstimationTask\n", + "\n", + "\n", + "model.Model\n", + "\n", + "\n", + "model.Model\n", "\n", "\n", "\n", - "\n", - "\n", - "model.PoseEstimation\n", - "\n", - "\n", - "model.PoseEstimation\n", + "\n", + "\n", + "train.TrainingParamSet->model.Model\n", + "\n", + "\n", + "\n", + "\n", + "train.TrainingTask\n", + "\n", + "\n", + "train.TrainingTask\n", "\n", "\n", "\n", - "\n", - "\n", - "model.PoseEstimationTask->model.PoseEstimation\n", - "\n", + "\n", + "\n", + "train.TrainingParamSet->train.TrainingTask\n", + "\n", "\n", - "\n", - "\n", - "subject.Subject\n", - "\n", - "\n", - "subject.Subject\n", + "\n", + "\n", + "subject.Subject.Protocol\n", + "\n", + "\n", + "subject.Subject.Protocol\n", "\n", "\n", "\n", - "\n", - "\n", - "subject.Subject->subject.SubjectDeath\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject->subject.Subject.Protocol\n", - "\n", - "\n", "\n", - "\n", + "\n", "session.Session\n", - "\n", - "\n", - "session.Session\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject->session.Session\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject.Source\n", - "\n", - "\n", - "subject.Subject.Source\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject->subject.Subject.Source\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject->subject.Zygosity\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject->subject.Subject.Strain\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject.Line\n", - "\n", - "\n", - "subject.Subject.Line\n", + "\n", + "\n", + "session.Session\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "subject.Subject->subject.Subject.Line\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject.User\n", - "\n", - "\n", - "subject.Subject.User\n", - "\n", - "\n", + "session.Session->session.ProjectSession\n", + "\n", "\n", - "\n", + "\n", "\n", - "subject.Subject->subject.Subject.User\n", - "\n", - "\n", - "\n", - "\n", - "subject.Subject.Lab\n", - "\n", - "\n", - "subject.Subject.Lab\n", - "\n", - "\n", + "session.Session->session.SessionDirectory\n", + "\n", "\n", - "\n", + "\n", "\n", - "subject.Subject->subject.Subject.Lab\n", - "\n", - "\n", - "\n", - "\n", - "train.ModelTraining\n", - "\n", - "\n", - "train.ModelTraining\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "lab.ProjectSourceCode\n", - "\n", - "\n", - "lab.ProjectSourceCode\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "model.ModelEvaluation\n", - "\n", - "\n", - "model.ModelEvaluation\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "model.RecordingInfo\n", - "\n", - "\n", - "model.RecordingInfo\n", - "\n", - "\n", + "session.Session->session.Session.Attribute\n", + "\n", "\n", - "\n", + "\n", "\n", - "session.Session->session.SessionDirectory\n", - "\n", - "\n", - "\n", - "\n", - "session.Session->session.ProjectSession\n", - "\n", + "session.Session->session.SessionExperimenter\n", + "\n", "\n", "\n", - "\n", + "\n", "session.SessionNote\n", - "\n", - "\n", - "session.SessionNote\n", + "\n", + "\n", + "session.SessionNote\n", "\n", "\n", "\n", "\n", - "\n", + "\n", "session.Session->session.SessionNote\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "session.Session->model.VideoRecording\n", - "\n", + "\n", "\n", - "\n", - "\n", - "session.Session.Attribute\n", - "\n", - "\n", - "session.Session.Attribute\n", + "\n", + "\n", + "subject.Subject\n", + "\n", + "\n", + "subject.Subject\n", "\n", "\n", "\n", - "\n", - "\n", - "session.Session->session.Session.Attribute\n", - "\n", - "\n", - "\n", - "\n", - "session.SessionExperimenter\n", - "\n", - "\n", - "session.SessionExperimenter\n", - "\n", + "\n", + "\n", + "subject.Subject->subject.Subject.Source\n", + "\n", "\n", + "\n", + "\n", + "subject.Subject->subject.Subject.Protocol\n", + "\n", "\n", - "\n", + "\n", "\n", - "session.Session->session.SessionExperimenter\n", - "\n", + "subject.Subject->session.Session\n", + "\n", "\n", - "\n", + "\n", "\n", - "train.TrainingTask->train.ModelTraining\n", - "\n", + "subject.Subject->subject.Subject.Line\n", + "\n", "\n", - "\n", - "\n", - "lab.Project\n", - "\n", - "\n", - "lab.Project\n", + "\n", + "\n", + "subject.Subject.Lab\n", + "\n", + "\n", + "subject.Subject.Lab\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "lab.Project->lab.ProjectPublication\n", - "\n", + "subject.Subject->subject.Subject.Lab\n", + "\n", "\n", - "\n", + "\n", "\n", - "lab.Project->session.ProjectSession\n", - "\n", + "subject.Subject->subject.Subject.User\n", + "\n", "\n", - "\n", + "\n", + "\n", + "subject.Subject.Strain\n", + "\n", + "\n", + "subject.Subject.Strain\n", + "\n", + "\n", + "\n", + "\n", "\n", - "lab.Project->lab.ProjectSourceCode\n", - "\n", + "subject.Subject->subject.Subject.Strain\n", + "\n", "\n", - "\n", - "\n", - "lab.ProjectKeywords\n", - "\n", - "\n", - "lab.ProjectKeywords\n", + "\n", + "\n", + "subject.SubjectDeath\n", + "\n", + "\n", + "subject.SubjectDeath\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "lab.Project->lab.ProjectKeywords\n", - "\n", + "subject.Subject->subject.SubjectDeath\n", + "\n", "\n", - "\n", - "\n", - "lab.ProjectUser\n", - "\n", - "\n", - "lab.ProjectUser\n", + "\n", + "\n", + "subject.Zygosity\n", + "\n", + "\n", + "subject.Zygosity\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "lab.Project->lab.ProjectUser\n", - "\n", + "subject.Subject->subject.Zygosity\n", + "\n", + "\n", + "\n", + "\n", + "lab.Lab\n", + "\n", + "\n", + "lab.Lab\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "lab.Lab->lab.Lab.Organization\n", + "\n", + "\n", + "\n", + "\n", + "lab.Lab->lab.LabMembership\n", + "\n", + "\n", + "\n", + "\n", + "lab.Lab->subject.Subject.Lab\n", + "\n", "\n", "\n", - "\n", + "\n", "lab.Location\n", - "\n", - "\n", - "lab.Location\n", + "\n", + "\n", + "lab.Location\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.Source\n", - "\n", - "\n", - "lab.Source\n", + "\n", + "\n", + "lab.Lab->lab.Location\n", + "\n", + "\n", + "\n", + "\n", + "lab.UserRole\n", + "\n", + "\n", + "lab.UserRole\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.Source->subject.Allele.Source\n", - "\n", + "\n", + "\n", + "lab.UserRole->lab.LabMembership\n", + "\n", "\n", - "\n", - "\n", - "lab.Source->subject.Subject.Source\n", - "\n", + "\n", + "\n", + "subject.Strain\n", + "\n", + "\n", + "subject.Strain\n", + "\n", "\n", - "\n", - "\n", - "model.PoseEstimation.BodyPartPosition\n", - "\n", - "\n", - "model.PoseEstimation.BodyPartPosition\n", + "\n", + "\n", + "\n", + "subject.Strain->subject.Subject.Strain\n", + "\n", + "\n", + "\n", + "\n", + "lab.Organization\n", + "\n", + "\n", + "lab.Organization\n", "\n", "\n", "\n", - "\n", - "\n", - "model.PoseEstimation->model.PoseEstimation.BodyPartPosition\n", - "\n", + "\n", + "\n", + "lab.Organization->lab.Lab.Organization\n", + "\n", + "\n", + "\n", + "\n", + "model.RecordingInfo\n", + "\n", + "\n", + "model.RecordingInfo\n", + "\n", + "\n", "\n", - "\n", - "\n", - "lab.Lab.Organization\n", - "\n", - "\n", - "lab.Lab.Organization\n", + "\n", + "\n", + "subject.Allele.Source\n", + "\n", + "\n", + "subject.Allele.Source\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.Protocol->subject.Subject.Protocol\n", - "\n", - "\n", - "\n", - "\n", - "lab.User\n", - "\n", - "\n", - "lab.User\n", + "\n", + "\n", + "lab.ProtocolType\n", + "\n", + "\n", + "lab.ProtocolType\n", "\n", "\n", "\n", - "\n", - "\n", - "lab.User->lab.ProjectUser\n", - "\n", - "\n", - "\n", - "\n", - "lab.User->lab.LabMembership\n", - "\n", + "\n", + "\n", + "lab.Protocol\n", + "\n", + "\n", + "lab.Protocol\n", + "\n", "\n", - "\n", - "\n", - "lab.User->subject.Subject.User\n", - "\n", "\n", - "\n", + "\n", "\n", - "lab.User->session.SessionExperimenter\n", - "\n", + "lab.ProtocolType->lab.Protocol\n", + "\n", "\n", - "\n", + "\n", + "\n", + "model.BodyPart\n", + "\n", + "\n", + "model.BodyPart\n", + "\n", + "\n", + "\n", + "\n", "\n", - "model.VideoRecording->model.VideoRecording.File\n", - "\n", + "model.BodyPart->model.Model.BodyPart\n", + "\n", "\n", - "\n", - "\n", - "model.VideoRecording->model.PoseEstimationTask\n", - "\n", + "\n", + "\n", + "train.VideoSet.File\n", + "\n", + "\n", + "train.VideoSet.File\n", + "\n", "\n", - "\n", - "\n", - "model.VideoRecording->model.RecordingInfo\n", - "\n", + "\n", + "\n", + "\n", + "model.Model->model.Model.BodyPart\n", + "\n", "\n", "\n", - "\n", + "\n", "model.Model->model.PoseEstimationTask\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "model.ModelEvaluation\n", + "\n", + "\n", + "model.ModelEvaluation\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "model.Model->model.ModelEvaluation\n", - "\n", + "\n", "\n", - "\n", - "\n", - "model.Model.BodyPart\n", - "\n", - "\n", - "model.Model.BodyPart\n", + "\n", + "\n", + "train.VideoSet\n", + "\n", + "\n", + "train.VideoSet\n", "\n", "\n", "\n", - "\n", + "\n", + "\n", + "train.VideoSet->train.VideoSet.File\n", + "\n", + "\n", + "\n", "\n", - "model.Model->model.Model.BodyPart\n", - "\n", + "train.VideoSet->train.TrainingTask\n", + "\n", "\n", - "\n", - "\n", - "subject.Line\n", - "\n", - "\n", - "subject.Line\n", + "\n", + "\n", + "lab.Source\n", + "\n", + "\n", + "lab.Source\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "subject.Line->subject.Line.Allele\n", - "\n", + "lab.Source->subject.Subject.Source\n", + "\n", "\n", - "\n", + "\n", "\n", - "subject.Line->subject.Subject.Line\n", - "\n", + "lab.Source->subject.Allele.Source\n", + "\n", "\n", - "\n", - "\n", - "model.BodyPart\n", - "\n", - "\n", - "model.BodyPart\n", + "\n", + "\n", + "subject.Allele\n", + "\n", + "\n", + "subject.Allele\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "model.BodyPart->model.Model.BodyPart\n", - "\n", - "\n", - "\n", - "\n", - "lab.Lab\n", - "\n", - "\n", - "lab.Lab\n", - "\n", - "\n", + "subject.Allele->subject.Line.Allele\n", + "\n", "\n", - "\n", + "\n", "\n", - "lab.Lab->lab.Location\n", - "\n", + "subject.Allele->subject.Allele.Source\n", + "\n", "\n", - "\n", + "\n", "\n", - "lab.Lab->lab.Lab.Organization\n", - "\n", + "subject.Allele->subject.Zygosity\n", + "\n", "\n", - "\n", + "\n", "\n", - "lab.Lab->lab.LabMembership\n", - "\n", + "model.VideoRecording->model.PoseEstimationTask\n", + "\n", "\n", - "\n", + "\n", "\n", - "lab.Lab->subject.Subject.Lab\n", - "\n", + "model.VideoRecording->model.VideoRecording.File\n", + "\n", "\n", - "\n", - "\n", - "train.VideoSet\n", - "\n", - "\n", - "train.VideoSet\n", - "\n", + "\n", + "\n", + "model.VideoRecording->model.RecordingInfo\n", + "\n", "\n", + "\n", + "\n", + "train.ModelTraining\n", + "\n", + "\n", + "train.ModelTraining\n", + "\n", "\n", - "\n", - "\n", - "train.VideoSet->train.VideoSet.File\n", - "\n", "\n", - "\n", + "\n", "\n", - "train.VideoSet->train.TrainingTask\n", - "\n", + "train.TrainingTask->train.ModelTraining\n", + "\n", "\n", - "\n", - "\n", - "lab.Organization\n", - "\n", - "\n", - "lab.Organization\n", + "\n", + "\n", + "subject.SubjectCull\n", + "\n", + "\n", + "subject.SubjectCull\n", "\n", "\n", "\n", - "\n", + "\n", "\n", - "lab.Organization->lab.Lab.Organization\n", - "\n", + "subject.SubjectDeath->subject.SubjectCull\n", + "\n", "\n", - "\n", + "\n", "\n", - "model.Model.BodyPart->model.PoseEstimation.BodyPartPosition\n", - "\n", + "lab.Protocol->subject.Subject.Protocol\n", + "\n", "\n", "\n", "" ], "text/plain": [ - "" + "" ] }, "execution_count": 5, @@ -993,12 +1002,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As you can see, this data pipeline is quite extensive, with various tables related to other components like models, training, and evaluation in DLC. Some, such as the `Subject` table, are not relevant to this tutorial and are upstream." + "As evident, this data pipeline is fairly comprehensive, encompassing several tables associated with different DeepLabCut components like model, train, and evaluation. A few tables, such as `Subject` or `Lab`, while integral to the pipeline, fall outside the scope of the scope of element-deeplabcut tutorial as they are upstream. \n", + "\n", + "Our focus in this tutorial will be primarily on the two core schemas:" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -1008,224 +1019,224 @@ "\n", "%3\n", "\n", - "\n", + "\n", "\n", - "train.VideoSet.File\n", - "\n", - "\n", - "train.VideoSet.File\n", + "train.TrainingParamSet\n", + "\n", + "\n", + "train.TrainingParamSet\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "train.TrainingTask\n", + "\n", + "\n", + "train.TrainingTask\n", "\n", "\n", "\n", + "\n", + "\n", + "train.TrainingParamSet->train.TrainingTask\n", + "\n", + "\n", "\n", - "\n", + "\n", "model.Model\n", - "\n", + "\n", "\n", "model.Model\n", "\n", "\n", "\n", + "\n", + "\n", + "train.TrainingParamSet->model.Model\n", + "\n", + "\n", + "\n", + "\n", + "model.VideoRecording\n", + "\n", + "\n", + "model.VideoRecording\n", + "\n", + "\n", + "\n", "\n", - "\n", + "\n", "model.PoseEstimationTask\n", - "\n", + "\n", "\n", "model.PoseEstimationTask\n", "\n", "\n", "\n", - "\n", - "\n", - "model.Model->model.PoseEstimationTask\n", - "\n", + "\n", + "\n", + "model.VideoRecording->model.PoseEstimationTask\n", + "\n", "\n", - "\n", - "\n", - "model.ModelEvaluation\n", - "\n", - "\n", - "model.ModelEvaluation\n", + "\n", + "\n", + "model.VideoRecording.File\n", + "\n", + "\n", + "model.VideoRecording.File\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "model.VideoRecording->model.VideoRecording.File\n", + "\n", + "\n", + "\n", + "\n", + "model.RecordingInfo\n", + "\n", + "\n", + "model.RecordingInfo\n", "\n", "\n", "\n", - "\n", - "\n", - "model.Model->model.ModelEvaluation\n", - "\n", + "\n", + "\n", + "model.VideoRecording->model.RecordingInfo\n", + "\n", "\n", "\n", - "\n", + "\n", "model.Model.BodyPart\n", - "\n", + "\n", "\n", "model.Model.BodyPart\n", "\n", "\n", "\n", - "\n", - "\n", - "model.Model->model.Model.BodyPart\n", - "\n", - "\n", - "\n", - "\n", - "model.VideoRecording.File\n", - "\n", - "\n", - "model.VideoRecording.File\n", + "\n", + "\n", + "model.PoseEstimation.BodyPartPosition\n", + "\n", + "\n", + "model.PoseEstimation.BodyPartPosition\n", "\n", "\n", "\n", + "\n", + "\n", + "model.Model.BodyPart->model.PoseEstimation.BodyPartPosition\n", + "\n", + "\n", "\n", - "\n", + "\n", "model.PoseEstimation\n", - "\n", + "\n", "\n", "model.PoseEstimation\n", "\n", "\n", "\n", - "\n", - "\n", - "model.PoseEstimation.BodyPartPosition\n", - "\n", - "\n", - "model.PoseEstimation.BodyPartPosition\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "model.PoseEstimation->model.PoseEstimation.BodyPartPosition\n", - "\n", - "\n", "\n", - "\n", + "\n", "model.PoseEstimationTask->model.PoseEstimation\n", "\n", "\n", - "\n", - "\n", - "train.ModelTraining\n", - "\n", - "\n", - "train.ModelTraining\n", - "\n", - "\n", - "\n", "\n", - "\n", + "\n", "model.BodyPart\n", - "\n", + "\n", "\n", "model.BodyPart\n", "\n", "\n", "\n", "\n", - "\n", + "\n", "model.BodyPart->model.Model.BodyPart\n", "\n", "\n", - "\n", - "\n", - "train.VideoSet\n", - "\n", - "\n", - "train.VideoSet\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "train.VideoSet->train.VideoSet.File\n", - "\n", - "\n", - "\n", + "\n", "\n", - "train.TrainingTask\n", - "\n", - "\n", - "train.TrainingTask\n", + "train.ModelTraining\n", + "\n", + "\n", + "train.ModelTraining\n", "\n", "\n", "\n", - "\n", - "\n", - "train.VideoSet->train.TrainingTask\n", - "\n", - "\n", - "\n", - "\n", - "model.RecordingInfo\n", - "\n", - "\n", - "model.RecordingInfo\n", - "\n", - "\n", + "\n", + "\n", + "train.TrainingTask->train.ModelTraining\n", + "\n", "\n", - "\n", - "\n", - "model.VideoRecording\n", - "\n", - "\n", - "model.VideoRecording\n", + "\n", + "\n", + "train.VideoSet.File\n", + "\n", + "\n", + "train.VideoSet.File\n", "\n", "\n", "\n", - "\n", - "\n", - "model.VideoRecording->model.VideoRecording.File\n", - "\n", - "\n", - "\n", + "\n", "\n", - "model.VideoRecording->model.PoseEstimationTask\n", - "\n", + "model.Model->model.Model.BodyPart\n", + "\n", "\n", - "\n", + "\n", "\n", - "model.VideoRecording->model.RecordingInfo\n", - "\n", - "\n", - "\n", - "\n", - "train.TrainingTask->train.ModelTraining\n", - "\n", + "model.Model->model.PoseEstimationTask\n", + "\n", "\n", - "\n", + "\n", "\n", - "train.TrainingParamSet\n", - "\n", - "\n", - "train.TrainingParamSet\n", + "model.ModelEvaluation\n", + "\n", + "\n", + "model.ModelEvaluation\n", "\n", "\n", "\n", - "\n", + "\n", + "\n", + "model.Model->model.ModelEvaluation\n", + "\n", + "\n", + "\n", "\n", - "train.TrainingParamSet->model.Model\n", - "\n", + "model.PoseEstimation->model.PoseEstimation.BodyPartPosition\n", + "\n", "\n", - "\n", + "\n", + "\n", + "train.VideoSet\n", + "\n", + "\n", + "train.VideoSet\n", + "\n", + "\n", + "\n", + "\n", "\n", - "train.TrainingParamSet->train.TrainingTask\n", - "\n", + "train.VideoSet->train.TrainingTask\n", + "\n", "\n", - "\n", + "\n", "\n", - "model.Model.BodyPart->model.PoseEstimation.BodyPartPosition\n", - "\n", + "train.VideoSet->train.VideoSet.File\n", + "\n", "\n", "\n", "" ], "text/plain": [ - "" + "" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -1238,26 +1249,28 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This diagram represents the `element-deeplabcut` pipeline." + "This diagram represents an example of the `element-deeplabcut` pipeline." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 1 - Register an Existing Model in the DataJoint Pipeline" + "### **Step 1 - Register an Existing Model in the DataJoint Pipeline**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "A DeepLabCut model is defined in a specific folder structure with a `config.yaml` file that contains the model's specifications (see folder `example_data/inbox`). To \"register\" this DLC model with DataJoint, you can specify this config file:" + "A DeepLabCut project adheres to a specific folder structure, featuring a `config.yaml` file that outlines the model's specifications (located within the `example_data/inbox` directory). \n", + "\n", + "To \"register\" this DLC model into the pipeline, the initial step is to define the path to the configuration file. Subsequently, this path should be provided as an input to the function responsible for executing the model registration process." ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -1268,30 +1281,28 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `insert_new_model` function is a helper function provided in `element-deeplacut` for convenient model registration.\n", + "The `insert_new_model` function serves as a convenient function within the `element-deeplacut` for simplifying the model registration process.\n", "\n", - "This function prints out the essential information, like the `model_name` and the `model_description`, together with other relevant information from the config file. \n", - "\n", - "If all the information is correct, you can confirm the insertion by typing 'yes,' which will insert the new model and its two body parts, `head` and `tailbase`:" + "Upon execution, this function generates a printout featuring vital details such as the `model_name` and `model_description`, along with pertinent information extracted from the configuration file. If all the information is accurate and in order, you can initiate the insertion process by typing 'yes', which will result in the registration of the new model, including its two associated body parts, `head` and `tailbase`." ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2023-10-17 15:35:14.274368: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\n", + "2023-10-19 19:26:49.961931: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\n", "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2023-10-17 15:35:18.481329: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib/python3.9/site-packages/cv2/../../lib64:/lib:/opt/conda/lib\n", - "2023-10-17 15:35:18.481376: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n", - "2023-10-17 15:35:18.859072: E tensorflow/stream_executor/cuda/cuda_blas.cc:2981] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", - "2023-10-17 15:35:24.333497: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib/python3.9/site-packages/cv2/../../lib64:/lib:/opt/conda/lib\n", - "2023-10-17 15:35:24.333709: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib/python3.9/site-packages/cv2/../../lib64:/lib:/opt/conda/lib\n", - "2023-10-17 15:35:24.333725: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" + "2023-10-19 19:26:50.069069: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib/python3.9/site-packages/cv2/../../lib64:/lib:/opt/conda/lib\n", + "2023-10-19 19:26:50.069107: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.\n", + "2023-10-19 19:26:50.091643: E tensorflow/stream_executor/cuda/cuda_blas.cc:2981] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2023-10-19 19:26:51.042839: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib/python3.9/site-packages/cv2/../../lib64:/lib:/opt/conda/lib\n", + "2023-10-19 19:26:51.043018: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory; LD_LIBRARY_PATH: /usr/local/lib/python3.9/site-packages/cv2/../../lib64:/lib:/opt/conda/lib\n", + "2023-10-19 19:26:51.043033: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] }, { @@ -1358,12 +1369,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "You can check the `Model` table to confirm that the new model has been added:" + "You can check the `Model` table to confirm that the new model has been registered:" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -1487,7 +1498,7 @@ " (Total: 1)" ] }, - "execution_count": 10, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -1500,28 +1511,28 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Much of this information is directly sourced from the `config` file. However, it's worth noting that this model is currently distinct and singular. \n", + "A significant portion of this data is directly extracted from the `config` file. \n", "\n", - "If you wish to incorporate another model, you must specify a new `model_name`; duplication of an existing model is not permitted—it must be an entirely new model." + "It's important to highlight that every model added to the `model` table is unique and singular. When introducing a new model, it is mandatory to define a new `model_name`. Replicating an existing model is not permitted; the new model must be entirely distinct. Even if you attempt to employ a different `model_name` for a previously registered model, `DataJoint` will identify this duplication and trigger an error. This model management protocol is crucial for maintining data integrity." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 2 - Insert Subject, Session, and Behavior Videos" + "### **Step 2 - Insert Subject, Session, and Behavior Videos**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Confirm the availability of data in the `Subject` and `Session` tables:" + "Now, let's delve into the `Subject` and `Session` tables and include some example data." ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -1609,7 +1620,7 @@ " (Total: 0)" ] }, - "execution_count": 11, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -1622,12 +1633,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Insert a subject into the `Subject` table:" + "Add a new entry for a subject in the `Subject` table:" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -1647,13 +1658,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Define session keys and insert them into the `Session` table:\n", + "Create session keys and input them into the `Session` table: \n", "\n" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -1676,7 +1687,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -1758,7 +1769,7 @@ " (Total: 2)" ] }, - "execution_count": 14, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -1771,12 +1782,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Insert data into the `VideoRecording` table:" + "Insert data into the `VideoRecording` table as well:" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -1795,7 +1806,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -1811,12 +1822,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Populate the `RecordingInfo` table:" + "Now, populate the `RecordingInfo` table will extract the metadata from the video sets and storing it in the table. \n", + "\n", + "This metadata will serve as a valuable resource for subsequent analyses reliant on video characteristics and as a `lookup` table for accessing this video data whenever necessary." ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -1924,7 +1937,7 @@ " (Total: 1)" ] }, - "execution_count": 17, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -1938,26 +1951,26 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Recording info extracts metadata from the video and validates the number of frames (n_frames), which will correspond to the number of entries for each body part in the pose estimation results." + "We can confirm the accuracy of the inference analysis by cross-referencing it with the number of frames extracted (`nframes`). This count of frames should align with the number of entries for each body part in the pose estimation results." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 3 - DeepLabCut Inference Task" + "### **Step 3 - DeepLabCut Inference Task**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The `PoseEstimationTask` table is used for defining an inference task. Let's explore the table description:" + "The `PoseEstimationTask` table serves the purpose of specifying an inference task. Let's delve into the table description:" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -1979,7 +1992,7 @@ "'-> model.VideoRecording\\n-> model.Model\\n---\\ntask_mode=\"load\" : enum(\\'load\\',\\'trigger\\') # load results or trigger computation\\npose_estimation_output_dir=\"\" : varchar(255) # output dir relative to the root dir\\npose_estimation_params=null : longblob # analyze_videos params, if not default\\n'" ] }, - "execution_count": 18, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -1992,30 +2005,30 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To define and insert a task, you need to:\n", + "Defining and inserting a pose estimation task requires:\n", "\n", "1. Define a video recording.\n", - "2. Select a model.\n", - "3. Choose the task mode (load or trigger).\n", - "4. Specify the output directory and optional parameters.\n", + "2. Choose a model.\n", + "3. Select a task mode (\"load\" or \"trigger\").\n", + "4. Specify the output directory and any optional parameters.\n", "\n", - "When the task mode is \"trigger,\" DataJoint triggers the inference, running the DeepLabCut model. This might take a long time, depending on the hardware. If the hardware lacks GPU support, it's not recommended.\n", + "When utilizing the \"trigger\" task mode, DataJoint initiates the inference process, running the DeepLabCut model. The duration of this process can vary, depending on the available hardware. If your hardware lacks GPU support, it's advisable to avoid this mode for this tutorial.\n", "\n", - "For this exercise, we are choosing the **\"load\" task** mode because the server does not have the necessary GPU for inference. The results have already been prepared. The results of this inference are generated in `example_data\\outbox`. \n", + "For this particular exercise, we have opted for the **\"load\" task** mode since the server lacks the necessary GPU resources for inference. The inference results have already been prepared and can be found in the `example_data\\outbox` directory. \n", "\n", - "If you select the **\"trigger\" task**, DataJoint will perform the entire inference process and generate these file sets." + "If you choose the **\"trigger\" task** mode, DataJoint will handle the entire inference process and produce these sets of files." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's define the keys for recording and task:" + "Now, let's establish the keys for the pose estimation task: the recording identifiers, and the chosen model." ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -2026,7 +2039,7 @@ " 'recording_id': '1'}" ] }, - "execution_count": 19, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -2037,7 +2050,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -2048,12 +2061,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The results are located in the `pose_estimation_output_dir` location." + "The results can be found at the `pose_estimation_output_dir` location." ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -2068,12 +2081,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Display the `PoseEstimationTask` table:" + "Show the contents of the `PoseEstimationTask` table." ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -2173,7 +2186,7 @@ " (Total: 1)" ] }, - "execution_count": 22, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -2184,7 +2197,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -2195,12 +2208,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's look into the `PoseEstimation` table." + "Now, let's examine the contents of the `PoseEstimation` table." ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -2292,7 +2305,7 @@ " (Total: 1)" ] }, - "execution_count": 24, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -2305,12 +2318,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The most critical table is the `PoseEstimation.BodyPartPosition` because it will contain the results of the inference. " + "One of the most crucial table is `PoseEstimation.BodyPartPosition` as it will store the results of the inference: x and y coordinates, and likelihood of the pose estimation." ] }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -2432,7 +2445,7 @@ " (Total: 2)" ] }, - "execution_count": 25, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -2445,16 +2458,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "After pose estimation, entries related to the task include: `subject`, `session`, `recording_id`, `model name`, and each detected `body_part` (two entries in this case).\n", + "Following the pose estimation process, the task-related entries encompass: `subject`, `session`, `recording_id`, `model name`, and each detected `body_part` (in this case, two entries).\n", "\n", - "Entries also contain `frame_index`, `x_pos` and `y_pos` positions, and `likelihood` (`z_pos` is zero). This structure is familiar to DeepLabCut users.\n", + "Each entry includes `frame_index`, `x_pos` and `y_pos` positions, along with a `likelihood` value (`z_pos` is `None`). \n", "\n", - "Finally, these results can be fetched in a Pandas DataFrame structure: " + "These results can be retrieved in the form of a Pandas DataFrame." ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -2463,7 +2476,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -2552,7 +2565,7 @@ "1 [0.9999996423721313, 0.9999996423721313, 0.999... " ] }, - "execution_count": 27, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -2565,19 +2578,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "`frame_index` is an array of frame numbers, `x_pos` is a NumPy array of x positions, and `likelihood` is also a NumPy array.\n" + "`frame_index` consists of an array of frame numbers, `x_pos` is a NumPy array of x positions, and `likelihood` is a NumPy array as well.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Use DataJoint `fetch` as a Pandas DataFrame and utilize the `explode` function to expand `x` and `y` positions." + "Retrieve the data using the `fetch` method, store it as a Pandas DataFrame, and apply the `explode` function to expand the x and y positions." ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -2817,7 +2830,7 @@ "[120000 rows x 11 columns]" ] }, - "execution_count": 28, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -2831,14 +2844,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As mentioned earlier, you can confirm these results by the number of entries. There are 60000 frames for each body part, matching the `nframes` from the `RecordingInfo` table." + "As mentioned earlier, a validation step for these results involves verifying the number of entries. Each body part should have 60,000 frames, aligning with the `nframes` value stored in the `RecordingInfo` table." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 4 - Visualization of results" + "### **Step 4 - Visualization of results**" ] }, { @@ -2847,12 +2860,12 @@ "source": [ "First, separate the data for the head and tailbase. \n", "\n", - "Then plot (1) the head pose estimation, and (2) the tailbase pose estimation." + "Following this, create two plots: (1) for the head pose estimation, and (2) for the tail base pose estimation." ] }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -2864,7 +2877,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -2899,7 +2912,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -2935,12 +2948,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, let's plot the head and tailbase positions on the same graph." + "Lastly, let's generate a plot that displays the head and tailbase positions on the same graph." ] }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 31, "metadata": {}, "outputs": [ { @@ -2977,13 +2990,54 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, we can plot the spatial mapping of both body parts, head and tail base." + "We have generated the spatial mapping plot for both body parts, head and tail base." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Summary" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Following this tutorial, we've efficiently:\n", + "- covered the essential functionality of `element-deeplabcut`\n", + "- acquired the skills to integrate an existing DLC model into the pipeline\n", + "- insert data into tables\n", + "- execute the pose estimation procedure\n", + "- visualize the outcomes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Documentation and DataJoint tutorials" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For detailed documentation on `element-deeplabcut`:\n", + "\n", + "[`DataJoint Element for DeepLabCut - Documentation`](https://datajoint.com/docs/elements/element-deeplabcut/0.2/)\n" ] }, { "cell_type": "markdown", "metadata": {}, - "source": [] + "source": [ + "For detailed documentation and tutorials on general DataJoint principles that support collaboration, automation, reproducibility, and visualizations:\n", + "\n", + "[`DataJoint for Python - Interactive Tutorials`](https://github.com/datajoint/datajoint-tutorials) covers fundamentals, including table tiers, query operations, fetch operations, automated computations with the make function, and more.\n", + "\n", + "[`DataJoint for Python - Documentation`](https://datajoint.com/docs/core/datajoint-python/0.14/)" + ] } ], "metadata": {