Skip to content

Latest commit

 

History

45 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Image

Mirri 링크

🔗 Mirri


목차

  1. Why?
  2. 주요 기능
  3. AI Pipeline & Strategy
  4. Gemini
  5. 설치 및 실행
  6. 기술 스택

Why?

취업 준비생의 가장 큰 고민 중 하나는 "내가 면접에서 어떻게 보이는가" 를 스스로 알기 어렵다는 점입니다.

답변 내용을 준비하는 것만큼 중요한 것이 비언어적 태도입니다. 시선이 흔들리거나, 고개가 기울거나, 표정이 어색하면 아무리 좋은 답변도 설득력을 잃습니다. 하지만 혼자 연습할 때 이런 부분을 인지하고 교정하기 쉽지 않습니다.

Mirri는 이 문제를 해결합니다.

  • 실시간으로 시선·표정·자세를 측정해 면접 중 나의 태도를 수치로 보여줍니다.
  • 답변이 끝나면 AI가 내용의 논리성·전달력·면접 맥락 적합성을 분석합니다.
  • 연습할수록 쌓이는 기록으로 나의 성장을 확인할 수 있습니다.

주요 기능

Image Image Image Image Mirri (6)_page-0001 Image Image Image

AI Pipeline & Strategy

Mirri는 네 가지 AI 파이프라인을 결합하여 면접 태도를 분석합니다.

1. Gaze Zone CNN (시선 구역 분류)

브라우저에서 400ms마다 웹캠 프레임을 캡처하여 백엔드 서버로 전송하면, ResNet-18 기반 커스텀 CNN이 시선 구역을 실시간 분류합니다.

1-1. Dataset & Performance

기존 공개 데이터셋은 실제 웹캠 면접 환경과 거리가 있어, Columbia Gaze Dataset을 기반으로 파인튜닝 데이터를 구성하였습니다.

처음 고려했던 class 분류는 다음과 같은 문제점이 있어 개선하였습니다.

이를 통해 Camera 정확도가 62.5%에서 80.4%로 대폭 향상되었으며, 학습 그래프 또한 훨씬 안정적인 수렴을 보이는 결과를 얻었습니다.

1-2. Model Architecture

ResNet-18 (ImageNet pretrained)
  └── fc: Sequential(
        Dropout(p=0.3),
        Linear(512 → 4)
      )

1-3. Training Configuration

항목
Base Model resnet18 (ImageNet pretrained)
Input Size 224 × 224
Optimizer Adam (lr=1e-4, weight_decay=1e-4)
Scheduler StepLR (step_size=7, gamma=0.5)
Epochs 20
Loss CrossEntropyLoss (class weight 적용)
Augmentation ColorJitter (brightness=0.3, contrast=0.3)
Preprocessing Resize → ToTensor → ImageNet Normalize

클래스 가중치 (불균형 보정)

클래스 샘플 수 가중치
Camera 1,680 0.88
Left 1,120 1.31
Right 1,120 1.31
Down 1,960 0.75

2. Expression Recognition CNN (표정 인식)

2-1. Why?

초기에는 @vladmandic/human의 내장 감정 모델을 사용해 브라우저에서 별도 서버 요청 없이 실행하는 방식을 사용하였지만, 다음과 같은 한계가 있어 모델을 직접 설계하였습니다.

1. 면접 맥락 부재

@vladmandic/human은 FER2013 기반 범용 모델로, happy와 neutral만 "안정"으로 집계하는 단순 이진 분류 외에 감정별 가중 점수를 산출한다거나, 긴장/불안 요소 코칭 등 면접에 특화된 해석이 불가능했습니다.

2. 낮은 실측 정확도

동일한 RAF-DB test set에서 FER 기반 모델을 실측한 결과, 전체 정확도 68.58%로 매우 낮은 정확도를 보였습니다.

Class FER 기반 (기존) EfficientNet-B2 (개선)
surprise 26.7% 84%
fear 67.6% 61%
disgust 26.9% 44%
happiness 83.7% 93%
sadness 85.1% 84%
anger 81.5% 83%
neutral 57.6% 83%
전체 68.58% 84.71%

이에 따라 RAF-DB 기반 커스텀 CNN을 직접 설계하기로 결정했습니다.

2-2. 초기 모델 설계와 한계

초기 모델은 EfficientNet-B0 기반으로 학습을 진행하였습니다.

초기 결과 및 한계

항목
Test Accuracy 80.74%
주요 문제 train/val gap 17%p (과적합)
취약 클래스 fear recall 65%, disgust recall 59%

과적합의 주요 원인은 fear(281장)/disgust(717장)이 상대적으로 매우 적다는 클래스 불균형 문제와, 모델 도메인에 맞는 적절한 Augmentation을 적용하지 못했다고 판단하였습니다.

2-3. 개선사항 및 최종 결과

1. Baseline → B2 + Augmentation (+3.42%p)

항목 변경 근거
B0 → B2 파라미터 5.3M → 7.7M compound scaling으로 정확도/효율 최적화
CenterCrop 제거 Resize(256,256) 직접 적용 RAF-DB는 이미 face-crop — 추가 crop이 턱/이마 손실 초래
GaussianBlur 추가 RandomApply(p=0.1) 웹캠 저화질/초점 불량 환경 강건성
RandomGrayscale 제거 웹캠은 항상 RGB — 불필요한 도메인 shift
Epoch 25 → 35 학습 곡선상 미수렴 확인

2. Oversampling (+0.55%p)

항목 변경 근거
Fear ×3 225 → 675장 면접 긴장도의 핵심 지표이나 train 내 최소 클래스
Disgust ×2 574 → 1,148장 샘플 수 대비 recall이 낮아 보강 필요
drop_path_rate=0.2 Stochastic Depth backbone 내부 정규화로 과적합 갭 17%p → 7%p 감소
Dropout 0.3 → 0.5 head 정규화 강화

2-4. 실시간 추론 파이프라인

RAF-DB는 얼굴 크롭 이미지로 학습된 모델이므로, 전체 프레임을 그대로 입력하면 배경·몸통 정보가 혼입되어 성능이 크게 저하됩니다.

이를 해결하기 위해 프론트엔드에서 얼굴 영역을 먼저 크롭한 뒤 표정 모델에 전달합니다.

Face Crop (프론트엔드)

@vladmandic/human이 감지한 얼굴 바운딩 박스(face.box)를 캔버스 해상도(320×240)에 맞게 스케일링한 뒤, 이마 25% / 좌우 20% 패딩을 추가해 얼굴 영역만 크롭합니다.

[원본 프레임 320×240]
        ↓ face.box → 스케일 보정
[얼굴 bbox + 패딩 크롭]
        ↓ base64 JPEG (face_frame)
[백엔드 /vision/frame]

시선 모델(ResNet-18)은 전체 프레임을, 표정 모델(EfficientNet-B2)은 얼굴 크롭 이미지를 각각 입력받아 단일 API 호출로 두 결과를 동시에 반환합니다.

표정 점수 (0~100점)

100점에서 부정 감정 확률에 비례해 패널티를 차감합니다. happiness·neutral은 패널티가 없으므로 자연히 높은 점수로 이어집니다.

score = 100
score -= P(fear)    × 60
score -= P(anger)   × 30
score -= P(sadness) × 40
score -= P(disgust) × 30

표정 상태 레이블 (실시간 패널)

점수와 별개로, 실시간 분석 패널에는 상태 레이블만 표시합니다.

happiness 또는 neutral이 임계값을 넘으면 안정으로 판정하고, 그렇지 않으면 가장 높은 확률의 감정으로 판단합니다.

P(happiness) > 0.2 또는 P(neutral) > 0.3  →  안정
그 외: top 감정 매핑
  fear    →  긴장
  anger   →  경직
  sadness →  위축
  disgust →  위축
  surprise → 당황

2-5. Architecture

Input (256×256 RGB)
    ↓
EfficientNet-B2 backbone
  - Compound scaling (width × depth × resolution)
  - MBConv + SE block (채널 어텐션)
  - drop_path_rate=0.2 (Stochastic Depth)
    ↓
Global Average Pooling → 1408-dim feature
    ↓
Dropout(0.5)
    ↓
Linear(1408 → 7)
    ↓
Softmax → 7개 감정 확률

2-6. Training

항목
Optimizer AdamW (weight_decay=1e-4)
Loss CrossEntropyLoss + class weights + label_smoothing=0.1
Scheduler CosineAnnealingLR
Phase 1 backbone frozen, head only, lr=1e-3, 5 epochs
Phase 2 full fine-tuning, lr=1e-4, 35 epochs
Augmentation RandomHorizontalFlip, RandomRotation(15°), ColorJitter, GaussianBlur, RandomErasing
MixUp α=0.2, Phase 2에서만 적용
Train split 80/20 (train/val)

3. Browser-side CV (@vladmandic/human)

네트워크 요청 없이 브라우저 내에서 직접 실행되는 멀티태스크 CV 파이프라인입니다.

매 프레임(requestAnimationFrame)마다 추론이 실행되며, 결과는 React state로 실시간 반영됩니다.

고개 안정도 (Head Stable)

코(nose)와 양쪽 어깨 중점을 잇는 벡터의 기울기를 각도로 환산합니다.

neckAngle = atan2(nose.x − shoulder_mid.x,  shoulder_mid.y − nose.y)
조건 판정
│neckAngle│ ≤ 8° 안정
│neckAngle│ > 8° 불안정

자세 안정도 (Body Stable)

카메라 기준 왼쪽/오른쪽 어깨 좌표의 높이 차이를 각도로 환산합니다.

shoulderTilt = atan2(camRight.y − camLeft.y,  camRight.x − camLeft.x)
조건 판정
│shoulderTilt│ ≤ 5° 또는 ≥ 175° 안정 (수평 또는 완전 반전)
그 외 불안정

눈 깜빡임 (Blink Count)

@vladmandic/human은 face mesh 랜드마크를 기반으로 EAR(Eye Aspect Ratio) 를 계산하여 깜빡임을 감지합니다.

EAR 공식

눈 주변 6개 랜드마크를 기준으로 눈의 세로 길이 / 가로 길이 비율을 계산합니다.

        p2  p3
   p1 ●      ● p4
        p6  p5
EAR = (‖p2−p6‖ + ‖p3−p5‖) / (2 × ‖p1−p4‖)
상태 EAR 값
눈 열림 ≈ 0.25 ~ 0.30
눈 감김 (깜빡임) < 0.20

EAR이 임계값 아래로 떨어지면 "blink" 제스처로 판정됩니다.

쿨다운 300ms를 적용하여 한 번의 깜빡임이 중복 집계되지 않도록 합니다.

if (gesture.includes("blink") && 눈_열림_상태 && now − lastBlink > 300ms)
  → 카운트 +1, 쿨다운 시작

4. Gemini

세션 종료 후 녹음된 오디오와 CV 집계 데이터를 서버로 전송하면, Gemini 3.1 Flash Lite가 STT 변환 및 면접 피드백을 생성합니다.

오디오 (webm) + CV 집계 지표 + 질문 목록
        ↓
  Gemini STT — 음성 전체를 한국어 텍스트로 전사
        ↓
  프롬프트 구성 (답변 내용 + 비언어 지표 수치)
        ↓
  Gemini 분석 — JSON 형식으로 결과 반환

채점 기준

모든 점수(0~100)는 Gemini가 아래 입력을 종합적으로 판단하여 부여합니다.

카테고리 점수 — 답변 내용 기반

카테고리 평가 요소
전달력 발화 명확성, 표현의 간결함
적극성 답변 의지, 자신감 있는 어조
안정감 일관된 태도, 침착함
논리성 구조적 답변 구성, 근거 제시

CV 점수 — 비언어 지표 수치 기반

지표 Gemini에 전달되는 수치
시선 정면 응시율 (%)
표정 패널티 차감 점수 평균 (0~100) + 안정·긴장·위축 등 상태 분포 (%)
고개 고개 안정 프레임 비율 (%)
자세 어깨 수평 프레임 비율 (%)
눈깜빡임 분당 횟수 (정상 기준: 15~20회/분)

질문별 점수 — 질문 답변 내용 기반

avgScore = 질문별 score의 산술 평균


Directory Structure

Mirri/
├── backend/
│   ├── routers/
│   │   ├── vision.py        # Gaze CNN + Expression CNN 추론 엔드포인트
│   │   ├── feedback.py      # Gemini STT + 면접 분석 피드백
│   │   └── chat.py          # AI 질문 추천 챗봇
│   ├── main.py
│   └── requirements.txt
│
├── frontend/
│   └── src/
│       ├── components/
│       │   ├── Header.jsx
│       │   └── Layout.jsx
│       ├── hooks/
│       │   ├── useHuman.js  # @vladmandic/human 브라우저 CV
│       │   └── useAudioRecorder.js
│       ├── pages/
│       │   ├── Landing.jsx
│       │   ├── InterviewSetup.jsx
│       │   ├── InterviewPractice.jsx
│       │   ├── AnalysisResult.jsx
│       │   └── Records.jsx
│       ├── services/
│       │   ├── apiService.js
│       │   └── storageService.js
│       └── data/
│           └── mockData.js
│
└── model/
    ├── Gaze_Zone.ipynb      # 시선 모델 학습
    ├── gaze_zone_best.pt    # ResNet-18 체크포인트
    ├── expression.ipynb     # 표정 모델 학습
    └── expression.pt        # EfficientNet-B2 체크포인트

설치 및 실행

사전 요구사항

  • Node.js 18+
  • Python 3.11+
  • Google Gemini API Key

Backend

cd backend
python -m venv venv
# Windows
venv\Scripts\activate
# macOS/Linux
source venv/bin/activate
pip install -r requirements.txt
# .env 파일 생성
echo "GEMINI_API_KEY=your_key_here" > .env
uvicorn main:app --reload --port 8000

Frontend

cd frontend
npm install
npm run dev

http://localhost:5173 에서 확인

환경 변수

Backend (backend/.env)

변수 설명
GEMINI_API_KEY Google Gemini API 키

Frontend

파일 변수
.env.local VITE_API_URL http://localhost:8000
.env.production VITE_API_URL HuggingFace Space URL

기술 스택

stack
Category Technology
Frontend React 19, Vite 8, Tailwind CSS v4
Backend FastAPI, Uvicorn
AI — Gaze PyTorch, ResNet-18, Columbia Gaze Dataset
AI — Expression PyTorch, EfficientNet-B2, RAF-DB
AI — CV @vladmandic/human
AI — Feedback Google Gemini 3.1 Flash Lite API
Hosting Vercel (Frontend), HuggingFace (Backend)
Model Training Kaggle (Tesla T4 GPU)
AI Assistant Claude

About

AI-powered online interview coach that analyzes your gaze, posture, expression, and answers.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages