Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

분실물-습득물 자동 매칭 시스템

TF-IDF 코사인 유사도 + 나이브베이즈

습득물을 등록하고, 분실물을 설명하면 벡터 유사도로 자동 매칭해 주는 시스템입니다.

[등록 프로세스]                              [찾기 프로세스]

  사진 ─┐                                  자연어 "까만 가죽 지갑"  ─┐
        ├→ 표현 표준화 → 사람 확인 → DB              또는              ├→ 표준화
  설명 ─┘   (색 대조)                      특징별 입력 (종류/재질/     ┘
              │                            색/생김새/글씨/수량)         │
        구조화 필드 저장                                                │
        + 설명문 자동 생성                    ① 종류를 알면 카테고리 확정
              │                                 모르면 나이브베이즈 추정
              └──────────→ SQLite ←──────────── ② 필드 가중 코사인 유사도
                                              ③ 임계값 판정 → 결과 + 근거

필수 의존성이 없습니다. TF-IDF, 코사인 유사도, 나이브베이즈, 편집 거리, 색공간 변환, k-평균 군집화, PNG 디코더, 웹 서버, 평가 지표, 교차검증까지 모두 표준 라이브러리만으로 직접 구현했습니다. 파이썬 3.9 이상이면 설치 과정 없이 바로 실행됩니다.

Pillow는 선택 사항입니다. 스마트폰 사진(JPEG/HEIC)을 그대로 읽고 싶을 때만 설치하면 되고(pip install pillow), 없으면 PNG/PPM을 내장 디코더로 읽습니다. 어느 쪽이든 색 판정 수학(HSV 거리, k-평균)은 직접 구현한 코드가 담당합니다.


빠른 실행

# 준비 (한 번만)
python3 tools/make_images.py     # 합성 사진 135장 생성
python3 tools/seed_db.py         # CSV → SQLite 적재 (180건)

# 웹에서 쓰기 (권장)
python3 web/app.py               # http://localhost:8000
python3 web/app.py --host 0.0.0.0   # 같은 와이파이의 다른 기기에서도 접속

# 터미널에서 쓰기 — 등록 프로세스
python3 register.py "까만 소가죽 반지갑 학생증 들어있어요" --image data/images/F001.png
python3 register.py -i                                    # 대화형

# 찾기 프로세스
python3 find.py "까만 가죽 지갑 잃어버렸어요"                 # 자연어
python3 find.py --kind 지갑 --color 까만 --material 가죽     # 특징별
python3 find.py -f                                        # 항목별 입력
python3 find.py -i                                        # 대화형

# 검증
python3 evaluate.py              # 실험 11종 (약 1분 40초)
python3 tests/test_all.py        # 단위 테스트 67개

# 실제 데이터 수집·검증 (docs/실데이터실험.md 참고)
python3 web/app.py --host 0.0.0.0   # 같은 와이파이에서 접속 가능하게
python3 tools/analyze_collected.py  # 사전에 넣을 표현 뽑기
python3 tools/eval_real.py          # 실제 신고로 시스템 시험
python3 tools/eval_real.py --sheet 판정지.csv   # 사람이 채점할 표

웹 화면

python3 web/app.py 를 실행하면 브라우저에서 네 가지를 할 수 있습니다.

하는 일
찾기 자연어 또는 특징별 검색. 필드별 점수 막대와 공통 단어까지 표시
등록 설명 + 사진 업로드 → 표준화 과정을 보여 주고 확인 후 저장
보관 목록 등록된 물품 훑어보기
데이터 수집 실제 사용자 표현 모으기 (사전 보강용)

화면은 http.server + HTML 한 장으로만 만들었습니다. 웹 프레임워크를 쓰지 않아 설치 없이 바로 실행되는 성질이 그대로입니다.

온라인 배포

무료로 인터넷에 올릴 수 있습니다. 등록한 물건은 계속 남고, 코드를 고치면 git pull + Reload 로 반영됩니다. 절차와 호스팅 비교는 docs/배포.md 에 있습니다.

gunicorn wsgi:application        # 또는 Dockerfile 그대로 사용
환경변수
LOSTFOUND_DATA_DIR DB·업로드를 둘 폴더 (호스팅의 영구 볼륨 경로)
LOSTFOUND_ADMIN_KEY 등록할 때 요구할 열쇠말 (장난 등록 방지)
LOSTFOUND_READONLY 1 이면 등록·수집을 막고 찾기만 열기

무료 요금제는 대개 파일이 안 남거나 잠듭니다. 실측·확인한 내용은 배포 문서의 비교표에 정리했고, 결론은 PythonAnywhere 무료(파일 유지·잠들지 않음)입니다. 검색 1건에 CPU 0.003초라 하루 100초 한도로도 3만 건 넘게 처리됩니다.

등록 예시

[입력] 까만 소가죽 반지갑 학생증 들어있어요   (글씨: 김민수)
  표준화 과정:
    까만       [color]    -> 검정
    소가죽      [material] -> 가죽
    반지갑      [kind]     그대로
    학생증      [features] 그대로
  사진 분석: 주색=검정 보조색=남색 형태=네모난 [검정 73%, 남색 14%, 갈색 5%]
  -> 입력한 색 '검정'과 사진이 일치합니다.
  -> 형태 '네모난'을 사진에서 채웠습니다.

  종류=반지갑  분류=지갑  색=검정  재질=가죽  형태=네모난  글씨=김민수  특징=학생증
  생성된 설명문: 검정 가죽 네모난 반지갑 김민수 학생증
  등록 완료: F181

찾기 예시

[질의] 까만 가죽 지갑 잃어버렸어요 학생증 들어있음
  해석: 종류=지갑  분류=지갑  색=검정  재질=가죽  특징=학생증/들어있음
  ① 카테고리: 지갑  (표준 어휘 사전이 '지갑'를 확정)
  ② 탐색 대상: 지갑 → 습득물 20건과 비교
     사용한 필드: 종류, 색상, 재질, 특징, 문장전체

  *1위  점수 0.794  [F001] 검정 가죽 반지갑 학생증과 카드
        지갑 / 2026-06-01 / 중앙도서관 2층 열람실   사진: data/images/F001.png
        필드별: 재질 1.00, 색상 1.00, 특징 0.84, 문장전체 0.60, 종류 0.27
        공통 단어: 학생증(0.139), 가죽(0.068)

"까만"으로 검색해도 "검정"으로 등록된 물건이 나옵니다. 표준화가 두 표현을 같은 축으로 모으기 때문입니다. 필드별 점수와 공통 단어가 함께 표시되어 왜 이 후보가 나왔는지 설명할 수 있습니다.


수학적 원리

주 원리 2개는 그대로 두고, 실제 프로세스를 돌리는 데 필요한 보조 수식 3개를 얹었습니다.

원리 쓰이는 곳
주1 TF-IDF + 코사인 유사도 설명 매칭
주2 나이브베이즈 카테고리 추정
보조1 편집 거리 + 한글 자모 분해 오타 교정, 글씨 대조
보조2 HSV 색공간 + 최근접 중심 사진에서 색 읽기
보조3 필드 가중 결합 + 좌표상승 구조화 검색, 가중치 탐색
보조4 k-평균 군집화 (Lloyd + k-means++) 사진에서 물체와 배경 분리

주1. TF-IDF + 코사인 유사도

TF(t,d)  = 1 + log f(t,d)                     빈도 (로그로 완만하게)
IDF(t)   = log((1+N) / (1+df(t))) + 1         희소할수록 큰 값
v_d      = TF·IDF / ||TF·IDF||₂               L2 정규화 (길이 편향 제거)

                 a · b
cos(a,b) = ─────────────────    두 문서가 이루는 각도의 코사인
             ||a|| · ||b||

검정은 거의 모든 습득물에 나오므로 IDF가 작아 점수에 거의 기여하지 않고, 에어팟은 몇 건에만 나오므로 IDF가 커서 겹치면 점수가 크게 오릅니다. L2 정규화를 미리 해 두면 코사인 유사도가 내적 한 번으로 끝납니다.

주2. 나이브베이즈

P(c|d) = P(d|c)P(c) / P(d)               베이즈 정리
P(d|c) ≈ ∏ P(tᵢ|c)                       "나이브" 독립 가정
score(c,d) = log P(c) + Σ count(tᵢ,d)·log P(tᵢ|c)      언더플로 방지
P(t|c) = (count(t,c) + α) / (Σcount + α|V|)            라플라스 스무딩

보조1. 편집 거리 + 자모 분해

lev(a,b)  동적 계획법으로 최소 편집 횟수
sim = 1 − lev(a,b) / max(|a|,|b|)

한글 음절 분해:  code = 0xAC00 + (초성×21 + 중성)×28 + 종성

민수 vs 민서는 음절로 재면 0.5지만, 자모로 풀면 ㅁㅣㄴㅅㅜ vs ㅁㅣㄴㅅㅓ모음 하나만 달라 0.8입니다. 사람이 이름을 잘못 기억하는 방식이 정확히 이렇습니다.

보조2. HSV 색공간 + 최근접 중심

d_H = min(|h₁−h₂|, 1−|h₁−h₂|) × 2        색상환은 원형
d   = √((w_H·d_H)² + (w_S·d_S)² + (w_V·d_V)²)
      단, 채도가 낮으면(무채색) H 항을 뺀다
color(p) = argmin_c d(p, center_c)        최근접 중심

h=0.02h=0.98은 둘 다 빨강인데 그냥 빼면 0.96이 나와 정반대 색으로 오판합니다. 원형 거리로는 0.08입니다.

보조3. 필드 가중 결합

                Σ_f  w_f · sim_f(q_f, d_f)
score(q,d) = ─────────────────────────────     f ∈ (질의에 값이 있는 필드)
                       Σ_f  w_f

분모를 질의에 값이 있는 필드로만 잡는 것이 요점입니다. 사용자가 재질만 기억해도 그 필드만으로 정상 점수가 나옵니다.

보조4. k-평균 군집화

J = Σ_i ||x_i − μ_{c(i)}||²            군집 내 분산의 합

배정  c(i) = argmin_j ||x_i − μ_j||²
갱신  μ_j  = (1/|C_j|) Σ_{i∈C_j} x_i

배정과 갱신을 번갈아 반복하면 J가 줄어들기만 하므로 반드시 수렴합니다 (전역 최적은 아니라서 k-means++로 초기 중심을 멀찍이 잡습니다).

처음에는 "테두리 색과 다르면 전경"이라는 규칙을 썼는데, 그건 촬영대 같은 단색 배경에서만 통했습니다. 실제 사진은 책상 무늬·그림자·손이 섞여 있어 색으로 덩어리를 나눈 뒤 "가장자리를 많이 차지하고 가운데엔 적은" 덩어리를 배경으로 고르는 편이 훨씬 잘 버팁니다.

전체 유도와 손계산 예시는 docs/수학원리.md 에 있습니다.


성능 검증 결과

python3 evaluate.py로 재현할 수 있습니다. 데이터는 습득물 180건, 분실 신고 90건(정답 있음 75 / 없음 15), 9개 카테고리.

1부 — 텍스트 매칭의 기초

실험 1·2 나이브베이즈 카테고리 분류

조건 정확도
5-fold 교차검증 78.89% (표준편차 6.48%)
습득물로 학습 → 분실 신고로 테스트 94.44%

교차검증이 더 낮고 더 보수적인 수치입니다. 둘 다 보고합니다.

실험 3 카테고리로 후보 좁히기 (핵심 결과)

방식 Top-1 MRR 신고당 비교 건수
코사인만 (베이스라인) 98.67% 0.990 180.0
NB 확률 가중 (soft) 98.67% 0.991 180.0
NB 상위확률 필터 (top-p) 98.67% 0.991 21.1
NB 1등 필터 (hard) 97.33% 0.978 20.0

여기서 가설을 한 번 수정했습니다. 처음에는 "카테고리로 좁히면 정확도가 오른다"고 예상했지만, 1등 카테고리만 남기는 hard 방식은 오히려 정확도를 떨어뜨렸습니다(98.67% → 97.33%). 분류가 틀리는 순간 정답이 후보에서 통째로 사라지기 때문입니다.

그래서 누적확률이 p=0.9를 넘을 때까지만 남기는 top-p 필터를 도입했습니다. 확신하면 1개, 헷갈리면 3~4개를 남겨 정확도를 그대로 유지하면서 비교 건수를 8.5배 줄였습니다.

즉 나이브베이즈의 실제 역할은 정확도 향상이 아니라 정확도를 잃지 않으면서 계산량을 줄이는 것입니다.

실험 5 절제 실험 — 음절 2-gram이 가장 크게 기여합니다(빼면 3어절 조건에서 88.00% → 84.00%). 3-gram으로 키우면 조각이 길어져 오히려 77.33%로 나빠집니다.

실험 6 임계값 — 1위 점수 평균이 정답 있는 신고 0.856, 없는 신고 0.433으로 갈립니다. τ = 0.53에서 오탐 0건, 재현율 98.67%.

3부 — 수학적 원리의 검증

실험 12 "나이브" 독립 가정은 얼마나 틀렸는가

나이브베이즈는 P(d|c) = ∏P(tᵢ|c), 즉 클래스가 정해지면 단어가 서로 독립이라고 가정합니다. 그 가정을 데이터로 검사했습니다.

lift = P(a,b|c) / ( P(a|c)·P(b|c) )      독립이면 1
분류 단어 쌍 lift
도서문구 볼펜 + 자루 6.67
지갑 카드 + 검정 5.00
액세서리 뿔테 + 안경 4.44

단어 쌍 62개의 평균 lift 2.70, 2배 이상 어긋난 쌍이 **65%**입니다. 독립 가정은 명백히 틀렸습니다.

그런데도 분류 정확도는 100%입니다. 이유는 필요한 것이 정확한 확률값이 아니라 순위이기 때문입니다. 다만 대가가 있습니다 — 1등 확률이 0.99를 넘는 문서가 **87%**로, 확률값 자체는 과신(overconfident)입니다. 독립 가정이 같은 증거를 여러 번 센 탓입니다.

분류기로는 써도 되지만, 확률값을 그대로 쓰는 곳(임계값)에서는 조심해야 한다 — 이것이 실험 6·10의 임계값이 데이터가 바뀌면 무너지는 이유이기도 합니다.

실험 13 top-p는 엔트로피 적응형 계산이다

분류기가 얼마나 헷갈리는지를 사후확률의 엔트로피로 쟀습니다. H(P) = −ΣP(c|q)log₂P(c|q), 카테고리 9개이므로 최대 log₂9 = 3.17비트.

엔트로피 건수 탐색 카테고리 비교 건수
확신 (0~0.5) 29 1.0 20
보통 (0.5~1.5) 30 1.7 34
혼란 (1.5~) 31 4.4 87

상관계수 r = 0.716.

top-p는 "확률 큰 것부터 누적합이 0.9를 넘을 때까지"라는 단순한 규칙인데, 결과적으로 엔트로피가 낮으면 좁게, 높으면 넓게 탐색합니다. 모를수록 계산을 더 씁니다. 실험 3의 "정확도를 잃지 않고 계산량만 줄인다"가 실제로는 이것이었습니다.

실험 14 로그를 쓰는 이유와 라플라스 α

확률을 그대로 곱하면 162개 단어에서 0이 됩니다(float64). 그 뒤로는 어느 클래스든 0이라 비교 자체가 불가능합니다. 로그를 취하면 log(0.01¹⁶²) = −746으로 여유롭습니다.

α를 바꿔 가며 교차검증한 결과 α=1.0에서 78.89%로 최고였습니다. 너무 작으면(0.001 → 75.0%) 못 본 단어 하나에 휘둘리고, 너무 크면(20 → 73.3%) 관측을 덮습니다. 라플라스 스무딩의 기본값이 우연이 아니라는 것이 수치로 확인됩니다.

2부 — 등록/찾기 프로세스

실험 7 표현 표준화 (핵심 결과)

대상 결과
습득물 180건 — 종류 추출 성공 180/180 (100%)
습득물 180건 — 사전만으로 카테고리 정확 180/180 (100%)
분실 신고 90건 — 사전만으로 카테고리 정확 87/90 (96.7%)

실패한 3건은 캐리어·드론·색연필로, 사전에 아예 없는 물건입니다. 이 구간을 나이브베이즈가 넘겨받습니다. 규칙(사전)과 확률(NB)의 역할 분담이 명확합니다 — 아는 건 규칙이 100% 확실하게, 모르는 건 확률 모델이.

같은 물건을 다른 말로 적었을 때의 성능:

원문 : 까만 가죽 반지갑 안에 학생증이랑 카드 몇 장 있어요
변형 : 검은 소가죽 반짜리지갑 안에 학생증이랑 카드 여러개 장 있어요

원문 : 회색 천 지갑 찍찍이로 여닫고 학생증 들어 있음
변형 : 잿빛 패브릭 월렛 찍찍이로 여닫고 학생증 들어 있음
방식 Top-1 R@3 MRR
표준화 없음 (통짜 TF-IDF) 84.00% 93.33% 0.893
표준화 + 필드 가중 100.00% 100.00% 1.000

이것이 초판 README에 한계로 적어 두었던 "까만검정이 겹치지 않는다"는 문제를 정면으로 해결한 결과입니다.

실험 8 필드 가중 검색 vs 통짜 설명문

어절 수 통짜 (기존) 필드 가중 (신규)
2개 65.33% 77.33%
3개 88.00% 96.00%
4개 96.00% 100.00%
전체 98.67% 100.00%

설명이 짧을수록 격차가 벌어집니다. 정보가 적을 때 어느 필드를 믿을지 정해 두는 것이 통짜로 섞는 것보다 유리하기 때문입니다.

실험 9 가중치 좌표상승 탐색

필드 손으로 정함 탐색 후
kind (종류) 0.280 0.068
color (색상) 0.150 0.194
material (재질) 0.090 0.117
fulltext (문장전체) 0.140 0.180

5-fold 교차검증 held-out MRR 0.9750 → 0.9822. 학습에 쓰지 않은 질의에서도 개선이 유지되므로 과적합이 아닙니다.

종류 가중치가 0.28에서 0.068로 내려앉은 것이 흥미롭습니다. 상식과 반대인데 이유가 있습니다. 종류는 이미 카테고리 필터로 후보를 거르는 데 쓰였고 fulltext 필드에도 들어 있어 신호가 중복됩니다. 게다가 대표 종류를 잘못 고르면(볼펜 세 자루와 형광펜 필통에서 볼펜) 그 필드가 정답을 밀어냅니다.

제약 없이 탐색하면 kind를 0까지 내립니다. 수치상으로는 맞지만 그러면 "종류만 입력한 검색"이 전부 0점이 되어 기능이 죽습니다. 지표가 아니라 기능이 걸린 문제라 가중치 하한 0.02를 두고 탐색했습니다.

실험 10 최종 임계값 — 1위 점수 평균이 정답 있는 신고 0.900, 없는 신고 0.459. τ = 0.57에서 오탐 0건, 재현율 100%. 이 값을 find.py 기본값으로 씁니다.

실험 11 사진 색 추출의 견고성

합성 사진입니다. 분류에 쓰는 표준 RGB 중심값 그대로 그리면 정확도 100%가 나오는 게 당연하므로(순환 논리), 물체 색을 HSV 축에서 흔들어 놓고 세기 p를 키우며 언제 무너지는지 쟀습니다.

색 교란 p 주색 정확도 대표 오판
0.00 100.0% — (순환 논리 구간)
0.20 97.8% 흰색→베이지
0.35 94.8% 흰색→베이지, 노랑→주황
0.50 91.9% 흰색→회색, 빨강→갈색
0.70 82.2% 흰색→회색, 검정→남색
1.00 59.3% 검정→남색(17건)

무너지는 방식이 색 이론과 맞아떨어집니다. 흰색↔베이지/회색은 채도가 낮아 색상 축이 무의미해진 경우이고, 검정↔남색은 명도가 낮아 세 축이 모두 붙어 버린 경우입니다. 어두운 색과 무채색이 원래 어렵습니다.

그래서 사진은 색을 보조로 확인하는 용도로만 쓰고, 입력과 불일치하면 경고만 띄우고 사람이 정하도록 설계했습니다.


프로젝트 구조

lostandfound/
├── README.md              이 문서
├── register.py            등록 프로세스 CLI
├── find.py                찾기 프로세스 CLI
├── web/
│   ├── app.py             웹 앱 (개발용 http.server + 배포용 WSGI 공용)
│   └── index.html         화면 (CSS/JS 인라인, 외부 요청 없음)
├── wsgi.py                배포용 진입점
├── Dockerfile             도커를 받는 호스팅용
├── demo.py                초판 매칭 데모 (통짜 설명문 방식)
├── evaluate.py            성능 검증 실험 11종
├── data/
│   ├── found_items.csv    습득물 180건 (씨앗 데이터)
│   ├── lost_reports.csv   분실 신고 90건 (정답 75 / 정답없음 15)
│   ├── images/            합성 사진 135장 + labels.csv
│   └── lostfound.db       SQLite 운영 저장소 (생성됨)
├── src/
│   ├── tokenizer.py       한국어 간이 토크나이저 (조사 제거 + 음절 2-gram)
│   ├── tfidf.py           TF-IDF 벡터화 + 코사인 유사도
│   ├── naive_bayes.py     다항 나이브베이즈 (로그공간 + 라플라스 스무딩)
│   ├── editdist.py        편집 거리 + 한글 자모 분해
│   ├── lexicon.py         표준 어휘 사전 (색/재질/종류/무늬/형태/수량)
│   ├── normalize.py       표현 표준화 엔진 (3단계 매칭)
│   ├── schema.py          구조화 레코드
│   ├── search.py          필드 가중 검색
│   ├── tuning.py          가중치 좌표상승 탐색
│   ├── image.py           PNG 디코더 + HSV 색 추출 (JPEG는 Pillow 있을 때)
│   ├── palette.py         k-평균 군집화 (물체/배경 분리)
│   ├── synth.py           합성 사진 생성
│   ├── db.py              SQLite 저장소
│   ├── matcher.py         초판 파이프라인 (비교 기준선)
│   ├── metrics.py         분류/랭킹 지표, 층화 k-fold
│   └── data.py            CSV 적재
├── tools/
│   ├── make_images.py     합성 사진 생성 스크립트
│   ├── seed_db.py         CSV → SQLite 적재
│   ├── analyze_collected.py  수집 데이터 분석 + 사전 보강 후보 추출
│   ├── eval_real.py       실제 신고로 시스템 시험 (임계값 검증·채점표)
│   ├── import_photos.py   실제 사진 적재·색 라벨링·검증
│   └── photo_prompts.py   이미지 생성 AI용 촬영 목록·명령문 생성
├── tests/test_all.py      단위 테스트 67개
└── docs/
    ├── 수학원리.md          수식 유도와 손계산 예시 (발표용)
    ├── 데이터수집.md        실제 표현 수집 방법과 주의사항
    ├── 실데이터실험.md      실제 신고문으로 성능을 다시 재는 3단계 계획
    ├── 실사진교체.md        합성 도형을 실제 사진으로 바꾸는 계획
    ├── 사진목록.md          생성 AI에게 줄 명령문과 180장 목록 (생성물)
    └── 배포.md              무료 호스팅 비교와 배포·갱신 절차

표준화가 다루는 필드

필드 표준어 개수
종류(kind) 반지갑, 장우산, 백팩, 이어폰 70여 개 → 9개 대분류
색상(color) 검정 ← 까만/까망/블랙/흑색 19
재질(material) 가죽 ← 레더/소가죽/인조가죽 12
무늬(pattern) 체크 ← 격자/타탄 6
생김새(shape) 작은 ← 소형/미니/자그마한 7
수량(quantity) 2개 ← 두/둘/한쌍 11
글씨(marking) 각인된 이름·번호 (편집 거리로 대조) 자유

팀 역할 (2인)

담당 작업 산출물
A 데이터 구축, 표현 표준화, 이미지/색공간 data/, lexicon.py, normalize.py, editdist.py, image.py, synth.py
B 검색 수학, 가중치 탐색, 성능검증, 발표 tfidf.py, naive_bayes.py, search.py, tuning.py, metrics.py, evaluate.py, docs/
공동 DB 설계, 등록/찾기 파이프라인, 테스트 db.py, schema.py, register.py, find.py, tests/

한계와 개선 방향

정직하게 적어 둡니다.

  1. 데이터가 합성입니다. 실제 분실물 센터 데이터가 아니라 직접 작성한 180건이고, 사진도 코드로 만든 도형입니다. 실험 4·8에서 어절을 잘라, 실험 11에서 색을 흔들어 난이도를 올렸지만 실물의 대체는 아닙니다. 이 한계를 직접 재는 도구를 만들어 두었습니다 — 웹 UI의 '데이터 수집' 탭으로 실제 문장을 모으고 tools/analyze_collected.py 로 분석하면, 합성 데이터 대비 어휘 커버리지가 얼마나 떨어지는지가 그대로 나옵니다. 그 격차가 곧 "합성 데이터로 잰 성능이 얼마나 부풀려져 있는가"입니다. (자세한 방법은 docs/데이터수집.md)
  2. 사진으로 종류를 판정하지 않습니다. 색과 형태만으로 지갑과 가방을 가르는 건 원리적으로 불가능해 시도하지 않았습니다. 실제 종류 인식에는 CNN 계열 모델이 필요하고, 그건 이 보고서의 "손으로 계산할 수 있는 수학" 범위를 벗어납니다.
  3. OCR을 구현하지 않았습니다. 각인된 글씨는 등록자가 직접 입력하는 필드로 두었습니다. 밑바닥 OCR은 이 규모에서 현실적이지 않고, 억지로 흉내 내면 보고서 신뢰도만 깎입니다. 대신 입력된 글씨를 편집 거리로 대조하는 부분은 제대로 구현했습니다.
  4. 사전은 사람이 채워야 합니다. 표준화 성능은 lexicon.py의 품질에 직결됩니다. 사전에 없는 새 물건(캐리어·드론)은 종류를 못 잡고 나이브베이즈로 넘어갑니다. tools/analyze_collected.py 가 미등록 표현을 빈도순으로 뽑아 주지만, 어느 표준어에 붙일지는 사람이 정해야 합니다.
  5. 수량이 어느 명사에 걸리는지 모릅니다. "카드 여러 장"에서 뽑은 여러개가 지갑의 수량인지 카드의 수량인지 구분하지 못합니다. 그래서 검색 필드로는 쓰되 생성 문장에는 넣지 않았습니다. 구문 분석이 필요합니다.
  6. 장소·시간을 점수에 반영하지 않습니다. 날짜 필터는 옵션으로만 구현했습니다(date_window_days). 실제 운영에서는 "같은 건물에서 같은 주에 습득"이 강한 신호가 될 수 있습니다.
  7. 실제 사진은 아직 검증하지 못했습니다. JPEG 읽기와 k-평균 배경 분리를 넣었지만, 가진 사진이 합성 도형뿐이라 잡배경·그림자에서 얼마나 버티는지는 미지수입니다. 바꾸는 계획과 도구는 준비해 두었습니다 (docs/실사진교체.md, tools/import_photos.py). 실제 사진으로 바꾸면 실험 11의 순환 논리 꼬리표가 떨어지고, 지금 판정 불가로 빼 둔 은색·금색도 시험해 볼 수 있습니다.
  8. 가방·의류 분류가 약합니다 (실험 1에서 각각 40%, 60%). 카테고리당 20건은 어휘가 다양한 카테고리에 부족합니다. 단 실제 파이프라인에서는 사전이 종류를 먼저 잡으므로 이 약점이 최종 성능에 잘 드러나지 않습니다.

참고

  • 순수 파이썬이라 pip install 과정이 없습니다. 파이썬 3.9 이상이면 동작합니다.
  • 데이터를 바꿔도 코드 수정 없이 돌아갑니다. data/*.csv의 열 이름만 맞추면 됩니다.
  • 새 물건 종류를 추가하려면 src/lexicon.pyKINDS에 한 줄 넣으면 됩니다.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages