#!/usr/bin/env python # coding: utf-8 # # 2D Single Person Human Pose Estimation # # Megh Shukla: work.meghshukla@gmail.com # In[1]: # Ignore syntax warning related to HRNet syntax import warnings warnings.filterwarnings('ignore') # Python imports import os import cv2 import copy import logging # External package imports import numpy as np import pandas as pd from tqdm import tqdm import matplotlib from matplotlib import pyplot as plt # PyTorch imports import torch import torch.utils.data from torch.utils.tensorboard import SummaryWriter from torch.optim.lr_scheduler import ReduceLROnPlateau as ReduceLROnPlateau # Imports from supporting files from config import ParseConfig from dataloader import load_hp_dataset from dataloader import HumanPoseDataLoader from activelearning import ActiveLearning from evaluation import PercentageCorrectKeypoint from utils import fast_argmax from utils import visualize_image from utils import heatmap_loss from utils import count_parameters from utils import get_pairwise_joint_distances from train_test import Train from train_test import Metric from train_test import load_models from train_test import define_hyperparams from models.auxiliary.AuxiliaryNet import AuxNet from models.hrnet.pose_hrnet import PoseHighResolutionNet as HRNet from models.stacked_hourglass.StackedHourglass import PoseNet as Hourglass logging.getLogger().setLevel(logging.INFO) # ### Initializing configurations: # # Model: Hourglass / HRNet
# Dataset: MPII / Leeds Sports Pose
# Load and Save paths
# ... and much more! # # Have a look at ```configuration.yml``` # # In[2]: conf = ParseConfig() # ### Load datasets: # # Based on our choice of dataset in ```configuration.yml```, we will load our selection into memory.
# Quick recall, different datasets have different data formats!
# ```load_hp_dataset``` is located in ```dataloader.py``` # In[3]: dataset_dict = load_hp_dataset(dataset_conf=conf.dataset, model_conf=conf.model) # ### Initialize (...and load) model architecture: # # We initialize and load the model based on the choice of architecture specified in ```configuration.yml```.
# ```load_models``` is located in ```train_test.py``` # In[4]: pose_model, aux_net = load_models(conf=conf, load_pose=conf.model['load'], load_aux=conf.model['aux_net']['load'], model_dir=conf.model['load_path']) # ### Define the active learning library: # # Although we won't be doing active learning, the library will allow us to draw samples randomly for training the model.
# The class ```ActiveLearning``` is located in ```activelearning.py```. # In[5]: activelearning = ActiveLearning(conf=conf, pose_net=pose_model, aux_net=aux_net) # ### Creating an object that inherits from torch.utils.data.Dataset() # # Writing code in PyTorch is fairly simple, and PyTorch requires two objects that need to be explicitly coded: _model_ and _dataset_.
# For our scenario, we create an object of type ```HumanPoseDataLoader``` for handling our dataset.
# # ```datasets``` standardizes ```mpii``` and ```lsp``` into a common format, defines augmentation routines, calls ```activelearning``` to sample from this data, and also controls preprocessing at batch level. # # ```HumanPoseDataLoader``` is located in ```dataloader.py``` # In[6]: datasets = HumanPoseDataLoader(dataset_dict=dataset_dict, activelearning=activelearning, conf=conf) # Once we initialize our dataloader, we delete a few objects that we won't need any longer to clear memory.
# Deleting the models gets rid of any computational graphs computed during ```ActiveLearning``` which we don't require any longer. # In[7]: get_ipython().run_line_magic('matplotlib', 'inline') matplotlib.rc("figure", dpi=250) def visualize_heatmaps(data_obj): ''' Small code snippet to visualize heatmaps :return: ''' data_obj.input_dataset(validate=True) for i in range(0, 5): image, hm, _, _, _, _, _, _, _, _, _ = data_obj.__getitem__(i) plt.subplot(4, 4, 1) plt.imshow(image.numpy()) plt.axis('off') plt.show() for j in range(hm.shape[0]): plt.subplot(4, 4, j+1) plt.imshow(image.numpy()) plt.subplot(4, 4, j+1) plt.imshow(cv2.resize(hm[j].numpy(), dsize=(256, 256), interpolation=cv2.INTER_CUBIC), alpha=.5) plt.title('{}'.format(data_obj.ind_to_jnt[j]), fontdict = {'fontsize' : 6}) plt.axis('off') plt.show() plt.close() # Deepcopy prevents any altering to the internal state of datasets visualize_heatmaps(copy.deepcopy(datasets)) # In[8]: del activelearning del pose_model, aux_net torch.cuda.empty_cache() logging.info('Re-Initializing (and loading) human pose network and auxiliary network.\n') pose_model, aux_net = load_models(conf=conf, load_pose=conf.model['load'], load_aux=conf.model['aux_net']['load'], model_dir=conf.model['load_path']) # ### Declaring experiment settings: # # We create an object (loosely called ```hyperparameters```) which contains hyperparameters and optimizer configuration required for training our models. # # Optional: We also initialize TensorBoard based on our configurations. # In[9]: logging.info('Initializing experiment settings.') hyperparameters = define_hyperparams(conf=conf, pose_model=pose_model, aux_net=aux_net) if conf.tensorboard: writer = SummaryWriter(log_dir=os.path.join(conf.model['save_path'], 'tensorboard')) else: writer = None # ### It's time to run the training loop! # In[10]: if conf.train: train_obj = Train(pose_model=pose_model, aux_net=aux_net, hyperparameters=hyperparameters, dataset_obj=datasets, conf=conf, tb_writer=writer) train_obj.train_model() del train_obj # Reload the best model for metric evaluation conf.resume_training = False pose_model, _ = load_models(conf=conf, load_pose=True, load_aux=False, model_dir=conf.model['save_path']) # ### It's time to run the evaluation loop! # In[ ]: get_ipython().run_line_magic('matplotlib', 'inline') matplotlib.rc("figure", dpi=250) if conf.metric: metric_obj = Metric(network=pose_model, dataset_obj=datasets, conf=conf) metric_obj.eval()