| |
| |
| import sys |
| import argparse |
| import yaml |
| import numpy as np |
| from tqdm import tqdm |
| |
| import torch |
| import torch.nn as nn |
| import torch.optim as optim |
| import time |
| import torch.nn.functional as F |
| |
| import torchlight.torchlight as torchlight |
| from torchlight.torchlight import str2bool |
| from torchlight.torchlight import DictAction |
| from torchlight.torchlight import import_class |
| from .evaluate_metrics import * |
| from .processor import Processor |
|
|
|
|
| def weights_init(m): |
| classname = m.__class__.__name__ |
| if classname.find('Conv1d') != -1: |
| m.weight.data.normal_(0.0, 0.02) |
| if m.bias is not None: |
| m.bias.data.fill_(0) |
| elif classname.find('Conv2d') != -1: |
| m.weight.data.normal_(0.0, 0.02) |
| if m.bias is not None: |
| m.bias.data.fill_(0) |
| elif classname.find('BatchNorm') != -1: |
| m.weight.data.normal_(1.0, 0.02) |
| m.bias.data.fill_(0) |
| def sliding_window_crop(input_data,label,window_size=32): |
| ''' |
| window_size=32 ~ 1second for pkummd dataset |
| ''' |
| N,T,V,C,M = input_data.shape |
| assert N==1 |
| |
| new_data = [] |
| new_label = [] |
| for i in range(N): |
| label_mask = (label!=255) |
| length = label_mask.float().sum() |
| for t in range(int(length)): |
| sample_s = t |
| if sample_s<window_size//2: |
| sample_s = 0 |
| sample_e = window_size |
| elif sample_s>length-(window_size//2): |
| sample_s = length-window_size |
| sample_e = length |
| else: |
| sample_s = sample_s - (window_size//2) |
| sample_e = sample_s + window_size |
| sample_s = int(sample_s) |
| sample_e = int(sample_e) |
| new_data.append(input_data[i][sample_s:sample_e]) |
| new_label.append(label[i][t]) |
| new_data = torch.stack(new_data,dim=0) |
| new_label = torch.stack(new_label,dim=0) |
|
|
| for i in range(5): |
| assert new_data.shape[i] == (N*length, window_size, V,C,M)[i] |
|
|
| return new_data, new_label |
|
|
| def sliding_window_crop_downsample(input_data,label,window_size=32, downsample=1): |
| ''' |
| window_size=32 ~ 1second for pkummd dataset |
| ''' |
| N,T,V,C,M = input_data.shape |
| window_size = window_size * downsample |
| assert N==1 |
| |
| new_data = [] |
| new_label = [] |
| for i in range(N): |
| label_mask = (label!=255) |
| length = label_mask.float().sum() |
| for t in range(int(length)): |
| sample_s = t |
| if sample_s<window_size//2: |
| sample_s = 0 |
| sample_e = window_size |
| elif sample_s>length-(window_size//2): |
| sample_s = length-window_size |
| sample_e = length |
| else: |
| sample_s = sample_s - (window_size//2) |
| sample_e = sample_s + window_size |
| sample_s = int(sample_s) |
| sample_e = int(sample_e) |
| new_data.append(input_data[i][sample_s:sample_e:downsample]) |
| new_label.append(label[i][t]) |
| new_data = torch.stack(new_data,dim=0) |
| new_label = torch.stack(new_label,dim=0) |
|
|
| for i in range(5): |
| assert new_data.shape[i] == (N*length, window_size//downsample, V,C,M)[i] |
|
|
| return new_data, new_label |
|
|
| class DT_Processor(Processor): |
| """ |
| Processor for Skeleton-based Action Recgnition |
| """ |
|
|
| def load_model(self): |
| self.model = self.io.load_model(self.arg.model, |
| **(self.arg.model_args)) |
| self.model.apply(weights_init) |
|
|
| for name, param in self.model.encoder_q.named_parameters(): |
| if name not in ['fc.weight', 'fc.bias', 'encoder_q.fc.weight', 'encoder_q.fc.bias']: |
| param.requires_grad = False |
| self.num_grad_layers = 2 |
|
|
| self.loss = nn.CrossEntropyLoss() |
| |
| def load_optimizer(self): |
| parameters = list(filter(lambda p: p.requires_grad, self.model.parameters())) |
| |
| assert len(parameters) == self.num_grad_layers |
| if self.arg.optimizer == 'SGD': |
| self.optimizer = optim.SGD( |
| parameters, |
| lr=self.arg.base_lr, |
| momentum=0.9, |
| nesterov=self.arg.nesterov, |
| weight_decay=self.arg.weight_decay) |
| elif self.arg.optimizer == 'Adam': |
| self.optimizer = optim.Adam( |
| parameters, |
| lr=self.arg.base_lr, |
| weight_decay=self.arg.weight_decay) |
| else: |
| raise ValueError() |
| |
| def show_best(self, k): |
| rank = self.result.argsort() |
| hit_top_k = [l in rank[i, -k:] for i, l in enumerate(self.label)] |
| accuracy = 100 * sum(hit_top_k) * 1.0 / len(hit_top_k) |
| accuracy = round(accuracy, 5) |
| self.current_result = accuracy |
| if self.best_result <= accuracy: |
| self.best_result = accuracy |
| self.io.print_log('\tBest Top{}: {:.2f}%'.format(k, self.best_result)) |
|
|
| def adjust_lr(self): |
| if self.arg.optimizer == 'SGD' and self.arg.step: |
| if self.meta_info['epoch'] < self.arg.warm_up_epoch: |
| lr = self.arg.base_lr * (self.meta_info['epoch']) / self.arg.warm_up_epoch |
| else: |
| lr = self.arg.base_lr * ( |
| 0.1**np.sum(self.meta_info['epoch']>= np.array(self.arg.step))) |
| for param_group in self.optimizer.param_groups: |
| param_group['lr'] = lr |
| self.lr = lr |
| else: |
| self.lr = self.arg.base_lr |
|
|
| def show_topk(self, k): |
| rank = self.result.argsort() |
| hit_top_k = [l in rank[i, -k:] for i, l in enumerate(self.label)] |
| accuracy = sum(hit_top_k) * 1.0 / len(hit_top_k) |
| if k==1: |
| self.test_acc = int(accuracy*100000) |
| self.io.print_log('\tTop{}: {:.2f}%'.format(k, 100 * accuracy)) |
| |
| def train(self,epoch): |
| |
| self.model.train() |
| |
| self.adjust_lr() |
| loader = self.data_loader['train'] |
| loss_value = [] |
| process = tqdm(loader) |
| for data, label, start_pos, video_name in process: |
| |
| |
| |
| data = data.float().to(self.dev) |
| label = label.long().to(self.dev) |
| |
| |
| output = self.model(data) |
| output = output[:,-1,:] |
| loss = self.loss(output, label) |
|
|
| |
| self.optimizer.zero_grad() |
| loss.backward() |
| self.optimizer.step() |
|
|
| |
| self.iter_info['loss'] = loss.data.item() |
| self.iter_info['lr'] = '{:.6f}'.format(self.lr) |
| loss_value.append(self.iter_info['loss']) |
| self.show_iter_info() |
| self.meta_info['iter'] += 1 |
|
|
| self.epoch_info['mean_loss']= np.mean(loss_value) |
| self.show_epoch_info() |
| self.io.print_timer() |
|
|
| def merge_list(self, vid_list): |
| group_list = [] |
| idx_per = [] |
| vid_list_uqk = [] |
| for idx, name in enumerate(vid_list): |
| if idx == len(vid_list)-1: |
| last_name = '' |
| else: |
| last_name = vid_list[idx+1] |
| if name != last_name: |
| idx_per.append(idx) |
| group_list.append(np.asarray(idx_per).astype(int) ) |
| vid_list_uqk.append(name) |
| idx_per = [] |
| else: |
| idx_per.append(idx) |
| return group_list, vid_list_uqk |
|
|
| def test(self, epoch): |
| |
| |
| |
| self.model.eval() |
| loader = self.data_loader['test'] |
| loss_value = [] |
| result_frag = [] |
| label_frag = [] |
| start_frag = [] |
| video_name_frag = [] |
| process = tqdm(loader) |
| sfm = nn.Softmax(dim=-1) |
| count = 0 |
| for data, label,start_pos,video_name in process: |
| with open ('1.txt','w') as f: |
| l = label[0].shape[0] |
| for i in range(l): |
| f.write(str(int(label[0][i].cpu().numpy()))+'\n') |
| |
| |
| N,T,V,C,M = data.shape |
| data = data.float().to(self.dev) |
| label = label.long().to(self.dev) |
| assert data.shape[0] == 1 |
| data, label = sliding_window_crop_downsample(data,label,window_size=16,downsample=4) |
| length = data.shape[0]//N |
|
|
| |
| with torch.no_grad(): |
| output = self.model(data) |
| output = output[:,-1,:] |
| output = output.reshape(N,length,-1) |
| label = label.reshape(N,length) |
| |
| |
| output = sfm(output) |
| padd_output = torch.zeros(N,9000,output.shape[2]) |
| padd_output[:,:length,:] = output |
| padd_output[:,length:,0] = 1.0 |
| |
| pre_o = get_interval_frm_frame_predict(padd_output[0].cpu().numpy()) |
| |
| |
| with open ('2.txt','w') as f: |
| |
| |
| |
| for i in pre_o: |
| f.write(str(i)+'\n') |
|
|
| |
| |
| |
| result_frag.append(padd_output.clone()) |
| label_frag.append(label) |
| start_frag = start_frag + start_pos.cpu().numpy().tolist() |
| |
| video_name_frag = video_name_frag + list(video_name) |
| |
| |
| prob_seq = torch.cat(result_frag,dim=0) |
| |
| gt_dict = {} |
| res_dict = {} |
|
|
| gt_video_dict = [] |
| res_video_dict = [] |
|
|
| |
| filtered = False |
| for idx in range(len(video_name_frag)): |
| prob_val = prob_seq[idx].cpu().numpy() |
| prob_smooth = smoothing(prob_val[:,:label_frag[idx].shape[1]],10) |
| |
| |
| |
|
|
| |
| pred_labels = get_segments(prob_smooth, activity_threshold=0.4) |
| pred_label_filted = [] |
| if filtered: |
| for i in range(pred_labels.shape[0]): |
| s,e = pred_labels[i][1:3] |
| if e-s>=15: |
| pred_label_filted.append(pred_labels[i]) |
| pred_labels = np.array(pred_label_filted) |
| |
| |
| vid_name = video_name_frag[idx] |
|
|
| label_path = '/mnt/netdisk/Datasets/088-PKUMMD/PKUMMDv1/Train_Label_PKU_final/' |
| labels = np.loadtxt(os.path.join(label_path, vid_name+'.txt'),delimiter=',').astype(int) |
| |
| labels[:,0] = labels[:,0] + 1 |
|
|
| gt_dict[vid_name] = labels |
| res_dict[vid_name] = pred_labels |
| |
| gt_per_video_dict = [] |
| res_per_video_dict = [] |
| for lab in labels: |
| gt_per_video_dict.append([lab[0],lab[1],lab[2],lab[3],vid_name]) |
| |
| for pred_lab in pred_labels: |
| res_per_video_dict.append([pred_lab[0],pred_lab[1],pred_lab[2],pred_lab[3],vid_name]) |
|
|
| gt_video_dict.append(gt_per_video_dict) |
| res_video_dict.append(res_per_video_dict) |
|
|
| mapv = sum([ap(res_video_dict[x], 0.5, gt_video_dict[x]) for x in range(len(res_video_dict))])/len(res_video_dict) |
|
|
| for thresh in [0.1, 0.3, 0.5]: |
| metrics = eval_detect_mAP(gt_dict, res_dict, minoverlap=thresh) |
| print('thresh: ',thresh, metrics['map']) |
| a = metrics['map'] |
| self.io.print_log(f'thresh: {thresh}, {a}') |
| self.current_result = metrics['map']*100 |
| self.best_result = max(self.best_result,self.current_result) |
| print ('mapa', metrics['map']) |
| print('mapv', mapv) |
|
|
|
|
| |
| |
| @staticmethod |
| def get_parser(add_help=False): |
|
|
| |
| parent_parser = Processor.get_parser(add_help=False) |
| parser = argparse.ArgumentParser( |
| add_help=add_help, |
| parents=[parent_parser], |
| description='Spatial Temporal Graph Convolution Network') |
|
|
| |
| |
| parser.add_argument('--show_topk', type=int, default=[1, 5], nargs='+', help='which Top K accuracy will be shown') |
| parser.add_argument('--warm_up_epoch', type=int, default=0, help='which Top K accuracy will be shown') |
| |
| parser.add_argument('--base_lr', type=float, default=0.01, help='initial learning rate') |
| parser.add_argument('--step', type=int, default=[], nargs='+', help='the epoch where optimizer reduce the learning rate') |
| parser.add_argument('--optimizer', default='SGD', help='type of optimizer') |
| parser.add_argument('--nesterov', type=str2bool, default=True, help='use nesterov or not') |
| parser.add_argument('--weight_decay', type=float, default=0.0001, help='weight decay for optimizer') |
| |
|
|
| return parser |
|
|