딥러닝

MoveNet으로 수집한 데이터를 seq데이터로 변환하자

lhg010524 2024. 8. 30. 13:57

지난번에 이어, MoveNet으로 관절 Keypoint까지 인식하는 것에 성공했다. 우리의 목표를 다시 한번 상기해 보자면 더위, 추위를 인식하기. 사실 실효성이 있는 모델인지는 모르겠지만 모델을 학습하고 라이브러리 사용에 의의를 두자. 최종 목표는 4가지 동작을 인식하는 것이지만 데모 모델이기에 shivering과 fanning, 두 동작을 인식시키기로 결정했다. 

actions = ['cold_shiver', 'fanning'] # 학습할 두 가지 동작
seq_length = 30 # 시퀀스 길이


created_time = int(time.time())

def process_frame(frame):
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = tf.image.resize_with_pad(tf.expand_dims(img, axis=0), 256, 256)
input_img = tf.cast(img, dtype=tf.int32)

# MoveNet으로 포즈 추출
results = movenet(input_img)
keypoints_with_scores = results['output_0'].numpy() # (1, 1, 17, 3)
keypoints = keypoints_with_scores[0, 0] # (17, 3)

return keypoints, keypoints_with_scores

def compute_angles(keypoints):
"""
MoveNet 키포인트에서 관절 간 각도를 계산하는 함수.
"""
joint = keypoints[:, :3] # 17개의 키포인트 좌표만 사용
v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15], :] # Parent joint
v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], :] # Child joint
v = v2 - v1 # [16, 3]

# Normalize v
v = v / np.linalg.norm(v, axis=1)[:, np.newaxis]

# Get angle using arccos of dot product
angle = np.arccos(np.einsum('nt,nt->n', v[:-1], v[1:])) # [15,]

angle = np.degrees(angle) # Convert radian to degree
return angle

frame_display_interval = 100 # 프레임 간격을 설정하는 파라미터
frame_count = 0 # 프레임 카운터 초기화
 
 

이런 식으로 데이터를 수집하고 cap = cv2.VideoCapture(0으로 직접 촬영을 하든, 촬영 데이터를 불러와 학습을 시켜도 된다. 다양한 데이터를 수집하고자 직접 영상을 찍고 부탁하며 주변 지인들에게 좀 뭇매를 맞았다.

 

직접 영상 데이터를 수집해야 하는데, 정말 말 그대로 수집했다. 주변 가족 친구들에게 모션을 취해달라 부탁했고 30초 동안의 영상을 촬영, 이제 이 영상을 프레임마다 나누어 프레임 별 관절 위치와 각도를 수집한다. 전체 코드는 프로젝트가 완성되면 첨부할 텐데, 프레임별 촬영된 데이터를 결합해 학습시킨다 생각하면 된다. 일부 코드를 첨부한다

# 동작 목록 설정
actions = ['shiver', 'fanning']

# 데이터 로드 및 결합
data_shiver = np.load('/content/drive/MyDrive/dataset/seq_cold_shiver_1724408535.npy')
data_fanning = np.load('/content/drive/MyDrive/dataset/seq_fanning_1724413985.npy') # 실제 fanning 데이터 경로로 변경

# 데이터를 결합
data = np.concatenate([data_shiver, data_fanning], axis=0)

# 데이터 분리: 입력 데이터와 라벨
x_data = data[:, :, :-1]
labels = data[:, 0, -1]

그리고 라벨을 원-핫 인코딩으로 변환 후, 데이터셋을 훈련 세트와 검증 세트로 분리하면 된다. 

 

여기까지는 사실 크게 달라진 것이 없고, 우리의 프로젝트 중 가장 큰 변화는 훈련 모델에 있다. 원래 lstm 모델을 사용해 모델을 학습했는데, 물론 세계적 석학들이 수천억을 들이며 만들어낸 모델이지만

 

1. 시퀀스 길이가 길어지면 장기 의존성 문제를 해결하지 못한다는 점과

2. 순차적 데이터 처리를 하기 때문에, 즉 병렬화가 어려워 학습과 예측 속도에서 다소 느린 성능

 

을 고려하여 lstm에겐 미안하지만 좀 더 정확도를 높이고자 i3d모델과 mobilenetV2+3d cnn을 이용해 정확한 학습을 시도해 보았다.

.

.

.

시도는 좋았지만 두 개 모두 cnn기반 모델이다 보니 메모리가 부족해 사용하기 어려울 거 같다는 결론에 도달했다. 빠르게 모델 변경. 비디오 길이가 30초 정도면 transformer가 성능상 낫다는 연구 결과를 참고해 transformer 모델을 데모로 구현해 학습했고 기존 lstm모델을 사용할 때보다 높은 정확도를 보여주었다. 관련 코드는 이후 포스팅에 첨부하겠다. 

 

이제 우리가 해야할 것은 수집된 동작 npy 파일을 transformer 모델로 학습시키고 온도 조절 로직을 정교하게 세우는 것뿐이다.

 

잘 되겠지...