프로젝트/캡스톤 졸프

[졸프스타트] "HandDoc" AI

rngPwns 2025. 5. 14. 12:38

1. AI 기술 조사

📌 수어 청각장애인이 사용하는 독립적인 언어 체계 단순한 손동작이 아니라, 문법과 규칙이 있는 언어라는 점 !

한국어 수어에서 사용되는 방식에는 “지문자” 와 “문장 수어” 2가지가 존재함 !

  1. 지문자 : 손가락 모양을 사용하여 ‘한글자씩’ 표현하는 방식 한 글자씩 표현하는 방식이라서 실제 대화에서는 비효율적임. ai 모델을 만들 때, 지문자만 학습하면 자연스러운 문장 대화가 불가능함 !
  2. 일반적인 수어 : 손의 움직임과 얼굴 표정을 포함하는 ‘자연스러운 문장 단위 표현’ 일반적인 대화에서 사용되며 빠르고 직관적인 의사소통이 가능함 실제 수어 사용자들이 사용하는 방식임

환자 입장에서의 수어만 인식하는 AI모델을 착안하면 됨. 의료진 수어까지 포함하면 문장이 복잡해지고 단어도 어려운 단어가 많을 것이지만, 환자의 수어만 처리하면 필요한 데이터셋 규모가 줄어들 수도 있을 것 같음.

📌 데이터셋은 단어와 짧은 문장 중심으로 구성

📌 각 단어 & 문장은 다양한 각도에서 촬영하여 AI 모델의 일반화 성능을 높임

 

Mediapipe 란 ?

Mediapipe는 Google 에서 제공하는 ‘컴퓨터 비전 라이브러리’ 딥러닝을 사용해서 영상이나 이미지에서 ‘손, 얼굴, 몸의 랜드마크(관절 좌표)를 감지’ 하는 기능을 제공 딥러닝 모델이 내장되어 있어서, 별도로 모델을 학습하지 않고도 ‘손의 움직임, 얼굴의 표정, 몸의 자세’ 등을 분석할 수 있음

 

MediaPipe 프레임 좌표 문제

  • 보통 MediaPipe로 추출한 좌표는 왼손 21개, 오른손 21개, 전신 33개 포인트로 구성되며, 각 포인트는 x, y, z(그리고 visibility 포함) 좌표를 갖기 때문에 총 258개의 수치로 1프레임을 표현하게 됨.
  • but 수화는 대부분 손, 팔, 어깨, 얼굴, 상반신 중심이기 때문에 MediaPipe Pose의 33개 중 다 쓰는 것은 비효율적, 정확도와 속도 낮춤
  • 상반신 관절만 추출한다면?부위 좌표 수
    왼손 21 × 3 = 63
    오른손 21 × 3 = 63
    상반신 Pose 약 64
    총합 190개 내외
    👉 즉, 전체 258개 → 약 190개로 축소 가능
  • 이는 속도 향상, 노이즈 감소에 도움됨
  •  

2. 데이터셋 구축

 

[촬영 가이드]

  • 총 11개의 단어
  • 1인당 하나의 단어를 10번씩 촬영하기 !
  • 얼굴 + 손 + 상반신이 나오도록 !
  • 정면 4번 / 왼쪽 측면 3번 / 오른쪽 측면 3번
  • 한 장소에서 하나의 단어에 대해서 정면, 왼쪽, 오른쪽에 대해서 촬영하는 것을 한 묶음으로 가정한다면, 한 장소에서 11묶음 촬영 가능
  • 장소를 바꿀 때는 옷이나 배경 조명을 변경하면 됨
  • 촬영시간 길게 가져가지 않기

 

3. 데이터 전처리

우리가 사용한 설정

상반신 Pose + 좌우 손 키포인트를 사용하는 방식으로 진행함

  • 얼굴 좌표는 일단 적용시키면 무거워져서 속도가 느려진다고 해서 일단 제외하고 진행 !

Pose Index 구조

  • 0 : 코
  • 11-16 : 어깨, 팔꿈치, 손목
  • 23-24 : 골반
  • 27 - 32 : 무릎, 발목, 발

→ 일단 0, 11-16 을 적용

# 상반신 pose 인덱스
upper_body_landmarks = [0, 11, 12, 13, 14, 15, 16]

데이터 전처리 흐름

  1. mp4 수어 영상을 가지고 최대 30프레임 추출
  2. Mediapipe Holistic 처리
  3. key point 벡터 추출
  4. 프레임 별로 .npy 저장

왜 30프레임만 추출하나 ?

  1. 모델 입력의 길이를 고정하기 위해서
    • 딥러닝 모델은 입력 시퀀스의 길이가 동일해야 학습이 가능하다고 한다 !
    • 수어 영상마다 길이가 다르기 때문에 → 동일하게 30프레임으로 잘라서 사용
  2. 1초 기준 정보로도 충분하다
    • 일반적으로 영상은 초당 30프레임에 해당한다.
    • 수어 역시 움직이는 부분은 굉장히 짧음 (우리 영상 최대 길이가 한 2-3초 되는 것 같음)
    • 지금은 영상의 앞 30프레임 방식으로 진행함 !

 

4. 라벨링 및 데이터셋 정의

모델 학습 (Training)

입력/출력 형식

  • 입력: (30, 154) 시퀀스 (Batch 형태는 (N, 30, 154))
  • 출력: 분류할 수어 단어 수만큼의 클래스 (예: 10개 단어 → output shape: (N, 10))

목표 요약

  • 입력: (30, 154) 크기의 NumPy 배열 (각 샘플은 30프레임, 각 프레임은 154개의 좌표)
  • 출력: 수어 단어 클래스 (예: 감기, 기침 등)
  • 모델: PyTorch 기반 1D-CNN
  • 향후: 경량화된 모델 생성 → ONNX 변환 후 실시간 예측에 활용

📌 입력 데이터 구조

  • 하나의 수어 영상은 30프레임 기준으로 처리됨
  • 각 프레임은 손 + 상반신 포즈 좌표 총 154차원
  • → 영상 하나 = (30, 154) 형태의 벡터 (학습 1샘플)

📌 전체 단계

단계 내용

1단계(데이터전처리-끝!) .mp4 영상 → 프레임 추출 → MediaPipe로 keypoint 좌표화 (.npy)
2단계(labeling) 30개의 .npy = 1샘플 → X 데이터로 구성폴더 이름으로 클래스 매핑해 Y (정답) 라벨 부여
3단계 PyTorch Dataset/Dataloader 정의
4단계 1D-CNN 모델 정의 및 학습
5단계 모델 저장 및 추후 ONNX 변환 등

2단계 : labeling

AI 모델이 제대로 학습하려면 라벨링이 반드시 필요함 AI가 입력된 데이터가 어떤 의미인지 학습할 수 있도록 정답을 달아줘야함 (label)

구성

  1. 입력 데이터 (X) : Mediapipe pose로 변환된 랜드마크 데이터 (벡터)
  2. 정답 데이터 (Y, 라벨) : 해당 수어가 의미하는 ‘단어 or 문장’

📌 AI 가 학습할 데이터는 X(입력) → Y (출력) 형태로 저장되어야함.

AI 학습에 사용할 데이터셋 저장 형식

  • Numpy 배열로 저장 → 추천 ! : 딥러닝 모델에 바로 사용할 수 있음 ! </aside>

주요 설명

항목 내용

X (샘플 수, 30, 154) 크기의 좌표 시퀀스
Y 문자 클래스명 리스트 → 숫자로 인코딩
LabelEncoder 문자열 라벨을 숫자로 변환
저장 파일 X.npy, Y.npy, classes.npy
  • "기침"라는 뜻을 갖는 수어 데이터가 "cough"라는 폴더에 저장되어 있다면, 라벨링은 폴더 이름(cough)이 곧 그 단어의 의미로 쓰이는 구조.

그 라벨을 Y.npy로 저장하고, 이걸 LabelEncoder로 숫자 라벨로 바꾸는 것 ! 그러나 우리는 영문 → 한글을 원하기에 추가적으로 딕셔너리 파일로 만들어야 함! - 이거는 나중에 FastAPI 서버에 통합하여 FastAPI 결과 반환

3단계 : PyTorch Dataset/Dataloader 정의

모델에 데이터를 효과적으로 넣기 위한 준비 과정. 우리가 앞서 만든 (샘플 수, 30, 154) 형태의 X.npy, Y.npy 파일을 불러와서, PyTorch에서 학습에 쓸 수 있도록 Dataset 클래스를 만들어주는 것!

📌 데이터 모델링 vs Dataset/Dataloader

항목 Dataset/Dataloader 정의 데이터 모델링

언제? 학습 전에 데이터를 불러와서 처리할 때 학습을 위한 신경망 구조를 설계하고 학습시킬 때
무엇을? X.npy, Y.npy를 PyTorch가 이해할 수 있는 형식으로 변환 (30, 154) 데이터를 받아서 예측하는 1D CNN 모델을 만들고 학습
포인트 torch.tensor로 변환, __getitem__ 구현, DataLoader로 배치 처리 nn.Module 상속해서 CNN 구조 정의, loss, optimizer 설정, 학습 loop
예시 Dataset, DataLoader, train_test_split model = My1DCNN(), optimizer.step(), loss.backward()
  • X.npy, Y.npy 파일 로드 → Numpy
  • → SignLanguageDataset으로 PyTorch가 이해할 수 있게 변환
  • → DataLoader로 배치(batch) 단위로 모델에 넣을 준비 완료
  • 이걸 이제 model()에 넣고 학습하는 게 모델링 단계

 

5. 1D-CNN 모델 정의, 구축, 학습, 검증

5단계 : 모델 저장

  1. 모델 저장: 학습 완료 후 모델 저장

수어 인식 시스템에서는 모델을 학습한 후, 실시간 예측을 위해 모델을 저장해야 함. 다음과 같은 방식으로 모델을 저장할 수 있다!

  • PyTorch 모델 저장 (.pt or .pth):
    • 학습 완료 후 가장 성능이 좋은 모델을 저장.
    • PyTorch에서는 torch.save()를 사용하여 모델 상태를 저장.
  1. 모델 평가: 테스트 데이터로 성능 평가

모델 저장 후에는 검증 데이터로 모델 성능을 평가해야 함. 평가 방식은 다음과 같다.

(1) 검증 데이터 활용:

  • 학습 과정에서 사용하지 않은 데이터로 평가하여 과적합 여부 확인.
  • 성능 지표로는 정확도(Accuracy), F1-Score, Recall, Precision 등을 사용.

(2) Confusion Matrix로 성능 시각화:

  • 실제 라벨과 예측 라벨 간 비교를 통해 모델 성능 파악.

(onnx는 상대적으로 간단한? 우리 기술에서는 굳이 변환 안 해도 될듯.. 만약 속도가 너무 느리면 시도해보자!)

Tip: 모델 선택 기준

  1. 성능 최적화: F1-Score와 Accuracy를 기준으로 가장 높은 모델 선택.
  2. 실시간성 고려: ONNX 모델로 변환 후 속도와 정확성 비교.
  3. 모델 경량화: FastAPI 서버에서 실시간으로 예측하기 위해 모델 파일 크기와 로딩 시간을 고려.

 

6. FastAPI 연결

👊 목표 : PyTorch 모델을 FastAPI와 연결하여 실시간 예측을 구현 - 로컬 Python에서!

<aside>

  • 프론트: 좌표 데이터를 JSON으로 변환하여 FastAPI 서버로 전송
  • FastAPI: JSON을 받아서 Numpy로 변환 후 모델에 입력
  • 응답: 모델 예측 결과를 JSON으로 변환하여 프론트로 전송 </aside>
  • FastAPI는 백엔드 중심의 데이터 변환을 담당하며,
  • 프론트에서는 JSON으로 전송만 담당
  • 모델 입력 형식 때문에 JSON -> Numpy 변환이 필요하며, 이 과정을 FastAPI에서 처리