Safemotion Lib
Loading...
Searching...
No Matches
action_dataset_loader.py
Go to the documentation of this file.
2import torch
3import torch.nn as nn
4from smutils.utils_os import search_file
5from smutils.utils_data import load_pkl_data
6import random
7
8import copy
9import numpy as np
10import os
12
13#피클 데이터의 구조
14# dict 구조
15# keys 필수 -> 'label'
16# 행동 인식을 위한 key 예시 -> 'keypoints'
17
18class ActionDatasetLoader(torch.utils.data.Dataset):
19 """
20 세이프모션의 학습용 데이터를 기반으로하는 데이터로더
21 학습용 데이터는 '.pkl'파일로 구성됨
22 TODO: 사용하지 않을 가능성이 커보임, 삭제 요망
23 args:
24 mode (str): 데이터로더의 셋팅 모드, 학습용일 경우 'train', 평가일 경우 'val'
25 train_data_folder (str): 학습용 데이터가 저장된 폴더 또는 파일
26 test_data_folder (str): 평가용 데이터가 저장된 폴더 또는 파일
27 clip_len (int): 샘플링할 프레임 수
28 """
29 def __init__(self, mode, train_data_folder, test_data_folder, clip_len):
30 self.mode = mode
31 self.train_data_folder = train_data_folder
32 self.test_data_folder = test_data_folder
33 self.clip_len = clip_len
34
35 self.load_data()
36
37 def load_data(self):
38 """
39 데이터를 로드하는 기능
40 """
41
42 #모드에 따른 데이터 경로 설정
43 data_folder = self.train_data_folder if self.mode == 'train' else self.test_data_folder
44 if os.path.isdir(data_folder): #데이터 경로가 폴더일 경우
45 #폴더 내부의 .pkl 파일을 모두 검색
46 name_list, path_list = search_file(data_folder, '.pkl')
47
48 #데이터 로드
49 self.dataset = []
50 for name, path in zip(name_list, path_list):
51 pkl = load_pkl_data(path)
52 self.dataset.append(pkl)
53 else:
54 #데이터 로드
55 self.dataset = load_pkl_data(data_folder)
56
57 def preprocessing(self, sample):
58 """
59 모델의 입력을 위한 데이터 전처리 기능
60 스켈레톤의 히트맵을 생성하는게 메인 기능임, 데이터 증강(data augmentation) 포함됨
61 TODO: 데이터 증강은 학습 모드일 경우만 진행되도록 코드 변경 필요
62 args:
63 sample (dict): 모델의 입력을 생성하기 위한 데이터
64 return (dict): 모델의 입력이 포함된 데이터
65 """
66
67 sample = pose_sampling(sample, clip_len=self.clip_len) #샘플링
68 sample = pose_shift(sample, shift_ratio=0.05) #스켈레톤 이동, 데이터 증강
69 sample = pose_compact(sample) #스켈레톤 범위 셋팅
70 sample = pose_resize(sample, scale=(64, 64)) #리사이즈
71 sample = pose_random_crop(sample, area_range=(0.56, 1.0), aspect_ratio_range=(3 / 4, 4 / 3)) #랜덤 크롭, 데이터 증강
72 sample = pose_resize(sample, scale=(56, 56)) #리사이즈, 크롭을 진행했기 때문에 다시 리사이즈 해줌
73 sample = pose_flip(sample, flip_ratio=0.5) #좌우반전, 데이터 증강
74 sample = make_pose_heatmap(sample) #히트맵 생성
75
76 return sample
77
78 def __len__(self):
79 return len(self.dataset)
80
81 def __getitem__(self, index):
82 sample = self.dataset[index]
83 if isinstance(sample, list): #샘플이 리스트일 경우 랜덤으로 한개 선택함
84 size_data = len(sample) #리스트 크기
85
86 #랜덤으로 선택
87 rand_idx = random.randint(0, size_data-1)
88 sample = sample[rand_idx]
89
90 return self.preprocessing(sample)
91
92class ActionDatasetLoader_v22(torch.utils.data.Dataset):
93 """
94 세이프모션의 데이터셋을 기반으로 단일 경로 모델을 학습하기 위한 데이터로더
95 args:
96 mode (str): 데이터로더의 셋팅 모드, 학습용일 경우 'train', 평가일 경우 'val'
97 data_folder (str): 학습용 데이터셋이 저장된 폴더, 해당 폴더 안에는 mode 폴더가 포함되어 있어야함
98 category_info (dict): 학습 데이터의 카테고리별 클래스 수
99 TODO: category_info는 제거해도 동작가능할 것으로 보여짐, 코드 수정 필요
100 clip_len (int): 샘플링할 프레임 수
101 """
102 def __init__(self, mode, data_folder, category_info, clip_len):
103 self.mode = mode
104 self.data_folder = data_folder
105 self.category_info = category_info
106 self.clip_len = clip_len
107
108 self.load_data()
109
110 def load_data(self):
111 """
112 데이터를 로드하는 기능
113 """
114 self.dataset = []
115 for category, num in self.category_info.items(): #카테고리, 클래스 수
116 folder = os.path.join(self.data_folder, self.mode, category) #카테고리-클래스의 데이터 폴더
117 name_list, path_list = search_file(folder, '.pkl') #해당 폴더의 모든 pkl파일 검색
118
119 #데이터 로드
120 data_num = len(path_list)
121 for i, (name, path) in enumerate(zip(name_list, path_list)):
122 print(f'{self.mode} : {category} [{i+1}/{data_num}] -> {name}', end='\r')
123 pkl = load_pkl_data(path)
124 self.dataset.append(pkl)
125
126 def preprocessing(self, sample):
127 """
128 모델의 입력을 위한 데이터 전처리 기능
129 스켈레톤의 히트맵을 생성하는게 메인 기능임, 데이터 증강(data augmentation) 포함됨
130 TODO: 데이터 증강은 학습 모드일 경우만 진행되도록 코드 변경 필요
131 args:
132 sample (dict): 모델의 입력을 생성하기 위한 데이터
133 return (dict): 모델의 입력이 포함된 데이터
134 """
135 sample = pose_sampling(sample, clip_len=self.clip_len) #샘플링
136 sample = pose_shift(sample, shift_ratio=0.05) #스켈레톤 이동, 데이터 증강
137 sample = pose_compact(sample) #스켈레톤 범위 셋팅
138 sample = pose_resize(sample, scale=(64, 64)) #리사이즈
139 sample = pose_random_crop(sample, area_range=(0.56, 1.0), aspect_ratio_range=(3 / 4, 4 / 3)) #랜덤 크롭, 데이터 증강
140 sample = pose_resize(sample, scale=(56, 56)) #리사이즈, 크롭을 진행했기 때문에 다시 리사이즈 해줌
141 sample = pose_flip(sample, flip_ratio=0.5) #좌우 반전, 데이터 증강
142 sample = make_pose_heatmap(sample) #히트맵 생성
143
144 return sample
145
146 def __len__(self):
147 return len(self.dataset)
148
149 def __getitem__(self, index):
150 sample = self.dataset[index]
151 if isinstance(sample, list): #샘플이 리스트일 경우 한개 선택함
152 size_data = len(sample)
153
154 #인덱스 설정
155 if self.mode == 'train': #학습 모드일 경우 랜덤으로 선택
156 rand_idx = random.randint(0, size_data-1)
157 else: #평가모드일 경우 중심에서 한개 선택
158 rand_idx = size_data//2
159
160 sample = sample[rand_idx]
161
162 return self.preprocessing(sample)
163
164
165
166class ActionDatasetLoader_mtml(torch.utils.data.Dataset):
167 """
168 세이프모션의 데이터셋을 기반으로 2-스트림 경로 모델을 학습하기 위한 데이터로더
169 args:
170 mode (str): 데이터로더의 셋팅 모드, 학습용일 경우 'train', 평가일 경우 'val'
171 data_folder (str): 학습용 데이터셋이 저장된 폴더, 해당 폴더 안에는 mode 폴더가 포함되어 있어야함
172 category_info (dict): 학습 데이터의 카테고리별 클래스 수
173 TODO: category_info는 제거해도 동작가능할 것으로 보여짐, 코드 수정 필요
174 clip_len_action (int): 행동 경로에 사용되는 프레임 수
175 clip_len_pose (int): 포즈 경로에 사용되는 프레임 수
176 """
177 def __init__(self, mode, data_folder, category_info, clip_len_action=20, clip_len_pose=8):
178 self.mode = mode
179 self.data_folder = data_folder
180 self.category_info = category_info
181 self.clip_len_action = clip_len_action
182 self.clip_len_pose = clip_len_pose
183
184 self.load_data()
185
186 def load_data(self):
187 """
188 데이터를 로드하는 기능
189 """
190 self.dataset = []
191 for category, num in self.category_info.items(): #카테고리, 클래스 수
192 folder = os.path.join(self.data_folder, self.mode, category) #카테고리-클래스의 데이터 폴더
193 name_list, path_list = search_file(folder, '.pkl') #해당 폴더의 모든 pkl파일 검색
194
195 #데이터 로드
196 data_num = len(path_list)
197 for i, (name, path) in enumerate(zip(name_list, path_list)):
198 print(f'{self.mode}/{category}/{num:02d} [{i+1}/{data_num}] -> {name}', end='\r')
199 pkl = load_pkl_data(path)
200 self.dataset.append(pkl)
201
202 def preprocessing(self, sample):
203 """
204 모델의 입력을 위한 데이터 전처리 기능
205 스켈레톤의 히트맵을 생성하는게 메인 기능임, 데이터 증강(data augmentation) 포함됨
206 TODO: 데이터 증강은 학습 모드일 경우만 진행되도록 코드 변경 필요
207 args:
208 sample (dict): 모델의 입력을 생성하기 위한 데이터
209 return (dict): 모델의 입력이 포함된 데이터
210 """
211
212 sample = pose_sampling(sample, clip_len=self.clip_len_action) #샘플링
213 sample = pose_shift(sample, shift_ratio=0.01) #스켈레톤 이동, 데이터 증강
214 sample = pose_compact(sample) #스켈레톤 범위 셋팅
215 sample = pose_resize(sample, scale=(64, 64)) #리사이즈
216 sample = pose_random_crop(sample, area_range=(0.56, 1.0), aspect_ratio_range=(3 / 4, 4 / 3)) #랜덤 크롭, 데이터 증강
217 sample = pose_resize(sample, scale=(56, 56)) #리사이즈, 크롭을 진행했기 때문에 다시 리사이즈 해줌
218 sample = pose_flip(sample, flip_ratio=0.5) #좌우 반전, 데이터 증강
219
220 sample_pose = copy.deepcopy(sample) #포즈 경로의 입력 데이터 생성을 위해 복사
221
222 #포즈 경로의 입력 범위 샘플링
223 frames = sample_pose['keypoint'].shape[1]
224 start = (frames - self.clip_len_pose)//2
225 end = start+self.clip_len_pose
226 sample_pose['keypoint'] = sample_pose['keypoint'][:,start:end, :, : ]
227 sample_pose['keypoint_score'] = sample_pose['keypoint_score'][:,start:end, : ]
228
229 #포즈 경로의 입력 데이터 생성을위한 스켈레톤 좌표 조정
230 sample_pose = pose_compact(sample_pose) #스켈레톤 범위 셋팅
231 sample_pose = pose_resize(sample_pose, scale=(56, 56)) #리사이즈
232
233 #히트맵 생성
234 sample = make_pose_heatmap(sample)
235 sample_pose = make_pose_heatmap(sample_pose)
236 sample['pose_heatmap_for_action'] = sample['pose_heatmap']
237 sample['pose_heatmap_for_pose'] = sample_pose['pose_heatmap']
238
239 return sample
240
241 def __len__(self):
242 return len(self.dataset)
243
244 def __getitem__(self, index):
245 sample = self.dataset[index]
246 if isinstance(sample, list): #샘플이 리스트일 경우 한개 선택함
247 size_data = len(sample)
248
249 #인덱스 설정
250 if self.mode == 'train': #학습 모드일 경우 랜덤으로 선택
251 rand_idx = random.randint(0, size_data-1)
252 else: #평가모드일 경우 중심에서 한개 선택
253 rand_idx = size_data//2
254
255 sample = sample[rand_idx]
256
257 return self.preprocessing(sample)
__init__(self, mode, data_folder, category_info, clip_len_action=20, clip_len_pose=8)
__init__(self, mode, data_folder, category_info, clip_len)
__init__(self, mode, train_data_folder, test_data_folder, clip_len)