Presentation Summary

Sprint 1 요약

Sprint Goal 결과물, 원래 계획과 달라진 점, 추가 성과, 개발 중 발견한 이슈를 한 페이지에 정리한 공유 문서다.

5/5핵심 US 충족
3실행 모드 (PyTorch/ONNX/INT8)
3NPU 디바이스 측정
10이슈 추적 (해결 5 / 진단 1 / 미해결 4)

1. Sprint Goal 결과물 — User Story별

Sprint Goal: "사용자가 랜드마크 이미지를 입력했을 때, 온디바이스 상에서 해당 이미지가 어떤 랜드마크인지 구별하여 결과를 출력하는 핵심 프로세스(스켈레톤 앱)를 시연할 수 있도록 구축한다."

각 User Story마다 원래 요구 → 구현 → 검증을 같은 카드 프레임으로 정리했다.

US-01 · T1-T5 ✅ 충족

사진 입력 + 전처리

이미지 업로드, RGB/resize, 포맷·크기 검증, 흐림/어두움 거부.

원래 요구 (AC)

이미지 업로드, RGB/resize 정규화, 포맷·크기·EXIF 등 입력 검증, 너무 어둡거나 흐릿한 이미지 거부.

구현
  • UI: Streamlit st.file_uploader (jpg/jpeg/png/webp). PIL.Image.open으로 RGB 변환.
  • 입력 검증: validate_image_file()가 확장자 + 헤더(MIME sniffing) + 최대 24 MB.
  • 품질 평가: assess_image_quality()가 Laplacian variance 기반 blur score, 평균 luminance brightness score, 224×224 해상도 하한으로 quality_flags(blurry/dark/too_small) 생성.
  • 전처리: 224×224 center-crop + ImageNet mean/std 정규화. PyTorch/ONNX 모두 같은 numpy tensor.
검증

pytest tests/test_quality.py 정상/blur/dark fixture 통과. 실측 시연 카메라 캡처 정상 처리.

US-02 + US-06 · T6-T10 ✅ 충족

Top-3 후보 + 유사 구분

cosine 유사도 기반 Top-3, 점수 표시, 로그, 상세 페이지 링크, 유사 외관 분리.

원래 요구 (AC)

cosine 유사도 기반 Top-3, 점수 표시, 검색 로그, 상세 페이지 링크, 유사한 외관(궁궐/문 등) 명확 구분.

구현
  • search_by_image: image embedding × 13 클래스 prototype index, 같은 클래스 max-pool로 1점수 응축.
  • search_by_text: text embedding × landmark_text_index.json + keyword/alias fusion (text 0.6, keyword 0.4).
  • ConfidencePolicy 4-way: matched / ambiguous(마진 부족) / out_of_scope(임계값 미만) / low_quality(품질 플래그 우선).
  • UI render_top3: 카드 3개 + "자세히 보기" 버튼. cosine은 0~100 스케일.
  • 로그: logs/demo.jsonltop1, top2, margin, reason_codes, thresholds, model_version, quality_flags, mode, runtime.
검증

demo_regression_v1.json 양성 13 + OOS 2 fixture로 image 18/18, text 10/10 통과. FP32↔INT8 회귀 cos 0.999, top-1 100%, decision 100% 일치.

US-03 · T11-T14 ✅ 충족

상세 정보 조회

landmark 정보 데이터, 상세 페이지 UI, 한·영 이름·설명·좌표.

원래 요구 (AC)

landmark 정보 데이터베이스, 상세 페이지 UI, 한국어/영어 이름·설명·좌표 노출.

구현
  • 데이터: assets/landmark_info.json에 13 클래스 × {id, name_ko, name_en, description_ko, description_en, lat, lng, address, hero_image}.
  • 화면 전환: st.session_state["page"]로 home ↔ landmark. "자세히 보기" → page="landmark" + selected_landmark_id 세팅 + st.rerun().
  • render_landmark_page: hero 이미지, 이름 ko/en, 설명, Google Maps 임베딩, "← 검색으로 돌아가기" 버튼.
검증

13 클래스 모두 직접 클릭해 페이지 진입 확인. 텍스트 검색 ↔ 상세 이동도 이슈 #8 수정 후 정상.

US-04 · T15-T17 ⚠️ 부분 충족

저신뢰 입력 예외 처리

흐림/어두움 거부, 저신뢰 안내, 지원 범위 밖 입력 처리.

원래 요구 (AC)

흐릿/어두운 이미지 거부, 신뢰도 낮은 결과 안내, 지원 범위 밖 입력 처리.

구현
  • 품질 게이트: quality_flagsConfidencePolicy가 가장 먼저 보고 low_quality로 분기. "후보 참고용으로 보기" 토글로 강제 열람.
  • OOS 처리: 화면 캡처/uniform noise/관계없는 이미지는 cosine 미만으로 out_of_scope. 회귀 fixture에 OOS 2건 포함.
  • 애매한 입력 처리: Top-1 점수와 Top-2 마진이 충분하지 않으면 ambiguous로 안내하고 후보를 참고용으로 보여준다.
검증

화면 캡처와 uniform noise는 out_of_scope, 심한 blur/dark 입력은 low_quality로 처리됨을 확인했다. 결정과 reason_codes는 jsonl 로그에 기록된다.

아직 부족한 점

강한 노이즈, 압축 깨짐, 저해상도 재확대가 섞인 복합 손상 이미지는 사람이 보기 어려워도 현재 품질 휴리스틱이 항상 low_quality로 분리하지는 못한다. 예를 들어 실제 광화문 이미지를 심하게 망가뜨린 경우 낮은 점수의 ambiguous 후보가 나올 수 있다.

Sprint 2 구현 방향
  • 실제 랜드마크 이미지에 blur, dark, noise, low-resolution, JPEG artifact를 입힌 quality regression set을 만든다.
  • assess_image_quality()noise_score, artifact 감지 지표, 복합 손상 기준을 추가한다.
  • 복합 손상 지표가 높으면 모델 후보 점수보다 low_quality를 우선 적용해 재촬영 안내로 분기한다.
US-07 · T18-T22 ✅ 초과 충족

경량 모델 + 추론

ONNX export, 로딩, embedding 생성, 추론 상태. Sprint 1에서 NPU 실측·text encoder ONNX까지 확장.

원래 요구 (AC)

경량(ONNX) 모델 준비, 로딩, embedding 생성, 추론 상태 반환.

구현
  • 학습 가중치: MobileCLIP2-S4 fine-tuned best.pt (1.7 GB).
  • Image encoder ONNX: scripts/export_mobile_onnx.py (opset 18, dynamo). FP32 1.23 GB external data + INT8 weight-only 약 320 MB.
  • Text encoder ONNX 추가: scripts/export_text_encoder_onnx.py 신규. FP32 473 MB / INT8 229 MB. OnnxTextEncoder로 PyTorch와 인터페이스 통일 (변경 7).
  • 실행 모드: run.py / --onnx / --int8. 모드별 InferenceBundle이 image+text encoder 쌍 로드.
  • NPU 검증: AI Hub Snapdragon S23/S24/S25에 ONNX 직접 컴파일. 1014/1014 layer 100% Hexagon NPU 탑재, fallback 0. warm latency 518 / 390 / 374 ms.
검증

PyTorch ↔ ONNX top-3 exact match 4/4. INT8 회귀 cos 0.999. text encoder PyTorch ↔ ONNX cosine 1.00000 (5/5).

API로 구현될 내부 함수

Sprint 1 데모앱은 별도 REST API 서버 없이 내부 함수를 직접 호출한다. Backlog의 /images/validation, /searches, /landmarks/{landmark_id}, /image-embeddings가 현재 어떤 함수로 대응되는지는 별도 문서에 정리했다.

내부 함수 매핑 문서 열기

2. 원래 Sprint Backlog와 다른 점

핵심 메시지는 목표를 바꾼 것이 아니라, Sprint 1에서 검증 가능한 방식으로 구현 경로를 조정했다는 것이다. 아래는 변경을 원인과 결과 중심으로 재배치한 버전이다.

핵심 해석

원래 Backlog는 Flutter 앱과 DB/API 구성을 포함했지만, Sprint 1의 실제 평가 대상은 온디바이스 모델 준비와 핵심 검색 흐름 시연이었다. 그래서 프레임워크보다 모델, artifact, confidence policy, 회귀 검증을 먼저 고정했다.

유지한 것: 이미지 입력, Top-3, 상세보기, 저신뢰 안내, 경량 모델 준비 바꾼 것: Flutter/SQLite/REST를 Sprint 2 통합 과제로 이동 추가한 것: NPU 실측, INT8 회귀, text encoder ONNX, 이슈 트래킹
01

시연 속도 우선

Flutter 네이티브 빌드 대신 Streamlit으로 검색 흐름을 빠르게 관찰했다.

앱 프레임워크보다 모델 동작 증명이 먼저
02

모바일 검증 분리

폰 직접 탑재는 Sprint 2로 넘기고, AI Hub로 NPU 탑재 가능성을 먼저 측정했다.

1014/1014 layer NPU, fallback 0
03

정적 데이터는 JSON

13개 클래스의 메타데이터와 검색 catalog는 DB보다 diff 가능한 JSON이 적합했다.

라벨링, catalog, prototype을 리뷰 가능하게 관리
04

검색 UX 단순화

이름 검색은 자연어 검색의 alias/keyword 처리로 흡수했다.

사용자는 이미지 또는 자연어만 선택

Task 추적용 요약

1번 User Story별 결과물을 Sprint Backlog의 Task 번호와 대조하기 위한 색인이다. 구현 상세는 위 카드에 두고, 여기서는 완료 상태와 변경/이월 판단을 중심으로 남긴다.

01 Backlog의 계획 출발점 02 현재 구현 결과물 03 바꾼 이유 판단 근거 04 포인트 해석
Flutter 앱
Android/iOS 네이티브 빌드
Streamlit 데모
노트북 호스팅 + 폰 브라우저 접속
빌드 환경보다 모델 검색 흐름을 먼저 검증해야 했다. 핵심 로직은 Python 모듈과 ONNX artifact라 Sprint 2 Flutter 래퍼로 이전 가능.
폰 직접 추론
ONNX Runtime Mobile에서 latency 측정
PC 시연 + AI Hub NPU 실측
S23/S24/S25 proxy 측정
QNN delegate 통합과 UI 빌드를 분리해야 실패 지점을 좁힐 수 있었다. 데모는 안정적으로 유지하고, 모바일 가능성은 NPU layer와 latency로 별도 증명.
SQLite DB
Landmark, SearchLog, UserSession 테이블
JSON assets
info, text catalog, text index, prototype, jsonl log
13개 정적 클래스에는 SQL보다 Git diff 가능한 파일이 더 운영하기 쉽다. 데이터 보강과 검색 표현 개선을 팀원이 직접 리뷰할 수 있다.
REST API 분리
Flutter client와 FastAPI server
단일 프로세스
Streamlit 내부에서 search 함수 직접 호출
이미지 직렬화, 네트워크 hop, 모델 중복 로딩을 줄였다. 함수 경계는 유지되어 Sprint 2에서 FastAPI 라우터로 감쌀 수 있다.
이름 검색 탭
이미지, 자연어, 이름 3탭
자연어 탭에 통합
alias/keyword/catalog로 장소명 처리
사용자가 입력 종류를 먼저 고르는 부담을 줄였다. 이름 검색 의도는 유지하면서 UI는 2탭으로 단순화했다.
저신뢰 입력 예외 처리
품질/범위/마진 기준 판단
Confidence policy
low_quality, ambiguous, out_of_scope로 처리
별도 필터를 늘리기보다 검색 결과를 확정 답처럼 보이지 않게 만드는 것이 Sprint 1 범위에 맞았다. 사용자는 실패 원인을 이해하고, 애매한 후보는 참고용으로 확인할 수 있다.
Image encoder export
자연어는 PyTorch 모드 중심
Text encoder ONNX 추가
ONNX/INT8에서도 semantic 검색
자연어 검색 품질을 실행 모드마다 다르게 둘 수 없었다. 계획 외 추가지만 Sprint 1 핵심 기능의 일관성을 높였다.
Backlog Task 상태 현재 구현 변경/이월 판단
T1-T5
US-01 이미지 입력 및 전처리
완료 1번 US-01 카드 참조: 이미지 업로드, 전처리, 입력 검증, 품질 평가. /images/validation HTTP API는 만들지 않고 validate_image_file(), assess_image_quality() 내부 함수로 구현.
T6-T10
US-02/06 Top-3 후보와 상세 연결
완료 1번 US-02/06 카드 참조: Top-3, 점수, 상세 이동, 검색 로그. /searches, /landmarks/{landmark_id} endpoint 대신 search_by_image(), search_by_text(), local metadata lookup으로 대체.
T11-T14
US-03 상세 정보 조회
완료 1번 US-03 카드 참조: 상세 정보 asset과 상세 화면 표시. SQLite 테이블과 LandmarkRepository 대신 정적 JSON asset과 bundle.info_by_id lookup 사용. DB화는 Sprint 2 선택 과제.
T15-T17
US-04 저신뢰 예외 처리
부분 충족 1번 US-04 카드 참조: 저품질/저신뢰 상태 판단과 안내 UI. blur, dark, too_small, OOS, ambiguous 처리는 구현. 강한 노이즈/압축 깨짐/복합 손상 감지는 Sprint 2에서 noise_score와 quality regression set으로 보강한다.
T18-T22
US-07 경량 모델 탑재 및 추론
확장 완료 1번 US-07 카드 참조: 모델 artifact, ONNX/INT8, image/text encoder 실행 모드. /image-embeddings endpoint는 만들지 않고 내부 encoder 단계로 유지. Flutter 앱 내부 asset 탑재와 Dart/native preprocessing parity 검증은 Sprint 2로 이동.
T23
DoD에만 등장한 smoke test
완료 1번 검증 항목과 회귀 fixture 참조. Task Breakdown에는 없었지만 DoD 검증 항목으로 수행. 이후 Sprint에서는 Task ID를 별도 부여하는 것이 좋음.
평가 관점

Planning과 구현 결과의 차이는 구현 축이 바뀐 것이 아니라 검증 우선순위가 바뀐 결과로 해석한다. Sprint 1은 완성 앱보다 모델 준비와 핵심 기능 토대가 평가 기준이었다.

Sprint 2 연결

Flutter, REST API, DB, 실제 폰 런타임은 버린 것이 아니라 모델 artifact와 검색 계약이 고정된 뒤 붙일 통합 과제로 남긴다.

3. 추가 성과

Sprint Backlog에 없었지만 Sprint 1에서 함께 만들어낸 것들이다.

NPU

모바일 NPU 실측 트랙

Qualcomm AI Hub에 모델을 올려 Galaxy S23 / S24 / S25 proxy에서 latency 측정. 1014/1014 layer 100% Hexagon NPU 탑재 (fallback 0), warm 518 / 390 / 374 ms.

Quantization

INT8 양자화 4 경로 + 한계 진단

ORT dynamic, ORT static QDQ, AI Hub w8a16 (calibration 15 / 260장)을 모두 시도. AI Hub 경로 임베딩 붕괴는 calibration 17배 늘려도 동일 → PTQ 알고리즘과 ViT-S4 분포 적합도 문제로 결정 진단. AI Hub FP32 inference cos 0.9995로 그래프 변환 무손실 확인.

ONNX

Text Encoder ONNX Export 추가

Sprint Backlog에 없던 text encoder도 ONNX로 export (FP32 473 MB / INT8 229 MB, PyTorch와 cosine 1.00000 parity). 세 모드 모두 자연어 검색이 의미 기반으로 동작.

Dataset

데이터셋 v3 정규화

4,719 records / 4,464 confirmed in-scope. class id 정규화, status 통일, hard_case_tags / scope_status / contrast_with caption / 한·영 user_query 추가. MMCA catalog 위치 설명 오염 정제 (이슈 #1 수정).

Regression

회귀 fixture 동결 + Smoke 테스트

양성 13건 + OOS 2건 fixture 동결 + 자동 재생성 스크립트. 세 모드(PyTorch / FP32 ONNX / INT8 ONNX) 모두 image 18/18, text 10/10 통과. PC FP32 ↔ INT8 cos 0.999, top-1 100%, decision 100%.

Process

이슈 트래커 시스템

개발/시연 중 발견된 트러블 기록·추적 문서 체계 구축. 현재 10건 (해결 5 / 진단 1 / 미해결 4) 추적. 흥미로운 케이스는 별도 분석 문서로 분리해 깊이 다룸.

DX

3 모드 실행 분리 + Vercel 문서

python run.py (PyTorch) / --onnx (FP32) / --int8 (INT8) 세 모드 분리로 팀원이 한 명령으로 원하는 환경 실행. 모든 결정 근거·운영 문서는 Vercel 자동 배포.

4. 개발하며 찾은 이슈들

Sprint 1에서 발견한 트러블과 깊이 분석한 케이스는 별도 문서로 관리한다. 각 링크에서 증상, 원인, 수정 또는 Sprint 2 방향을 확인할 수 있다.

Issues

Known Issues Tracker

이슈 10건의 목록과 해결 상태. 카테고리별 (텍스트 검색, 이미지 검색, ONNX 모드, 양자화, 인프라, UI)로 정리.

이슈 트래커 열기 →
Analysis

텍스트 검색 케이스 분석

"경복궁" → mmca 검색 오염, 한국어 vs 영어 점수 분포 비교, text encoder 변별력 한계 깊이 분석.

분석 열기 →

대표 이슈 미리보기

#제목상태한 줄 요약
#1 "경복궁" 검색 → mmca 1위 ✅ 해결 mmca catalog의 "경복궁 옆 미술관" 위치 설명이 검색 오염을 일으킴. 위치 설명 제거.
#2 "한복 입고 사진 찍는 곳" → mmca ⚠️ 미해결 영어 중심 CLIP이 한국어 "사진"을 "picture/painting"(그림)으로 해석. Sprint 2 한국어 caption 보강.
#3 ONNX 모드 자연어 검색 keyword만 사용 ✅ 해결 Sprint 1 추가 작업으로 text encoder ONNX export, ONNX/INT8 모드도 semantic 검색 살림.
#4 광화문 wide shot → cheongwadae 혼동 ⚠️ 미해결 광화문 학습 데이터 52장 부족. Sprint 2 데이터 보강 + view_type별 prototype 분할 + parent landmark 계층.
#5 AI Hub w8a16 INT8 임베딩 공간 붕괴 ✅ 진단 calibration 17배 늘려도 동일. PTQ 알고리즘과 ViT-S4 분포 적합도 문제로 결정적 진단.
#6 지원 범위 밖/화면 캡처가 확정 답처럼 보임 ✅ 해결 confidence policy와 OOS fixture로 out_of_scope, ambiguous 안내를 분리.
#7 팀원 PC에서 ONNX/INT8 config가 개인 D: 경로를 참조 ✅ 해결 config.onnx.toml, config.int8.toml을 repo 내부 상대경로로 수정.
#8 텍스트 검색 후 "자세히 보기" 안 넘어감 ✅ 해결 session_state 재렌더에 더해 ?landmark_id=... query param 라우팅을 추가해 탭 rerun에서도 상세 페이지 진입 유지.
#9 근정문 검색 시 최대 40% ⚠️ 미해결 text 변별력 약함. Sprint 2에서 catalog 한국어 query 보강.
#10 text encoder 한국어/영어 변별 폭 좁음 ⚠️ 미해결 한국어와 영어 모두 약 0.05 좁은 폭. 차이는 폭이 아닌 방향. keyword 매칭이 안전장치 역할.

※ 본 표에는 검색·UI·양자화 등 주 기능과 직결된 이슈만 포함했다. 디스크 공간, 호스트 RAM 압박 같은 로컬 환경 이슈는 트래커에서만 별도 추적한다.

관련 문서