Meta SAM3 (facebook/sam3) 모델로 학습 없이(Zero-Shot) 이미지 속 결함을
검출하고, 확정한 결과를 모아 LoRA 파인튜닝으로 모델을 점점 업그레이드하는
데스크탑 도구입니다. 산업현장 적용을 목표로 합니다.
- Prompt_Detect(원클릭 검출): 현재 프롬프트(
"scratch","crack"같은 텍스트 개념) + 지금까지 확정한 라벨을 합쳐 SAM3 Zero-Shot 검출을 한 번에 실행 (Bounding Box + Mask) - 박스 검출(Box Detect): 이미지에서 결함을 마우스로 드래그하면 그 박스를 시각적 예시(exemplar)로 삼아, 드래그한 영역 안의 같은 종류 결함을 분할
- LoRA 자가학습: 확정한 결함(+정상 이미지)으로 SAM3 를 파인튜닝해 검출 능력 향상
SAM3 의 HuggingFace 구현은 point 클릭 대신 box exemplar(시각적 예시) 방식을 씁니다. 그래서 검출하려는 결함을 박스로 드래그해 입력합니다.
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124CPU만 쓸 경우:
pip install torch torchvision이 환경의 GPU에서는 CUDA 빌드 버전을 실제 드라이버에 맞춰야 합니다 (transformers 5 / torch 조합에 따라 cu124가 아닌 빌드가 필요할 수 있음).
pip install -r requirements.txt
transformers는 5.0 이상이어야 SAM3 를 지원합니다. LoRA 학습에는peft(선택으로scipy)가 필요하며, base 모델만 쓸 거면 없어도 됩니다.
모델 경로는 sam3_defect.py 상단 DEFAULT_MODEL_ID 한 곳에서 정합니다.
기본값은 로컬 폴더 경로(D:\SAM3\models\sam3)로 되어 있습니다.
한 번만 내려받아 두고 그 경로를 지정합니다.
pip install -U huggingface_hub
hf auth login # 다운로드 시 1회만 필요
huggingface-cli download facebook/sam3 --local-dir C:\models\sam3그런 다음 sam3_defect.py 의 DEFAULT_MODEL_ID 를 받은 폴더로 바꿉니다.
DEFAULT_MODEL_ID = "facebook/sam3" 로 바꾸면 됩니다. 단 facebook/sam3 는
게이트(gated) 모델이라 접근 승인 + 로그인이 되어 있어야 합니다.
- https://huggingface.co/facebook/sam3 → 약관 동의 후 Request access
- 승인되면
hf auth login으로 로그인 (토큰은 read 권한이면 충분)
python check_env.py모델 소스(로컬/HuggingFace)를 자동 감지해 필요한 항목만 필수로 검사합니다. 로컬 폴더를 쓰면 HuggingFace 로그인 항목은 상태만 표시하고 통과 여부에서 제외합니다.
python AutoLabellingTool.py첫 화면(런처)이 모니터 크기에 맞춰 최대화된 채로 뜹니다. 위에 툴바 하나, 가운데에 이미지 뷰, 오른쪽에 이미지 목록이 있습니다(최대화를 풀면 화면의 90% 크기로 돌아갑니다).
| 툴바 | 하는 일 |
|---|---|
| New Project | 프로젝트 이름과 저장 위치를 입력하는 창이 열립니다. 만들어질 경로를 입력하는 동안 미리 보여 주고, 이미 있는 폴더나 쓸 수 없는 이름이면 이유를 알려 줍니다. [Create] 를 누르면 작업 폴더(images · dataset · results)가 생기고 현재 프로젝트로 잡혀, 이후 화면들의 경로가 자동으로 채워집니다. |
Open Project (Ctrl+O) |
이미지를 골라 가운데 화면에 띄웁니다. 그 이미지가 프로젝트 폴더 안에 있으면 프로젝트도 함께 잡힙니다. |
| Labelling | 라벨링 앱(Model_Development.py)을 띄웁니다. 프로젝트가 잡혀 있으면 그 프로젝트의 dataset/ 에 확정 결과가 쌓이고, 화면에 이미지가 떠 있으면 그 이미지로 바로 시작합니다. |
| Infer | 배치 추론 창을 엽니다 — Image Folder · LoRA Adapter · Output Folder · Output Type · Save Result Images · Resolution · Threshold · Prompt Batch · Image Batch · fp32 · Target Classes · JSON 저장을 화면에서 지정하고 실행합니다. 진행률과 로그가 그대로 보이고 [Stop] 으로 끊을 수 있습니다. |
| Compare | 내가 라벨링한 결과(왼쪽) 와 결과 폴더의 모델 결과 이미지(오른쪽) 를 나란히 봅니다. 좌우 제목에 건수가 함께 표시됩니다(왼쪽=확정 라벨 수, 오른쪽=결과 JSON 의 검출 수). 짝은 파일명으로 맞추고(part_01.png ↔ part_01_seg.png / part_01_det.png, 하위 폴더까지 찾습니다), 같은 이름의 결과가 없으면 오른쪽은 검은 화면에 "No Result" 라고 표시합니다. 런처에서 이미지를 넘기면 비교 창도 따라오고, 비교 창에서는 ← → 로 넘기고(런처는 ↑↓), 넘기면 런처도 따라옵니다. 펜·형광펜·지우개로 양쪽 화면에 각각 표시를 남길 수 있고, 도구를 끈 상태에서 드래그하면 화면이 움직입니다(휠 확대/축소와 함께 좌우가 같이 움직여 같은 자리를 비교합니다). |
Labels (L) |
확정한 라벨링을 이미지 위에 겹쳐 보여 줍니다. 시작할 때는 꺼져 있고 첫 이미지를 열면 자동으로 켜집니다(그 뒤로는 직접 끄고 켠 상태를 그대로 둡니다). |
Pen (P) · Marker (H) · Eraser (E) · 색 · Clear Notes |
이미지 위에 손으로 표시를 남깁니다. 이미지별로 기억하지만 데이터셋에는 저장되지 않습니다(검토용 메모지 — 프로그램을 끄면 사라집니다). |
- 오른쪽 이미지 목록 — 이미지를 열면 그 폴더의 이미지 전체가 파일명으로
나열됩니다(프로젝트를 잡으면
images/를 미리 채웁니다). 클릭하면 그 이미지가 화면에 뜹니다. ↑ ↓ ← → 키로도 넘길 수 있고, 이때 목록을 먼저 클릭할 필요는 없습니다(빠르게 훑을 때는 잠깐 모았다가 멈춘 자리의 이미지를 엽니다). 파일명 옆에 그 이미지의 확정 라벨 건수가, 정상(OK)으로 확정한 이미지는OK가 표시됩니다. 파일명이 길면 패널 폭에 맞춰 여러 줄로 접혀 끝까지 다 보입니다(패널 폭을 바꾸면 다시 접힙니다). - ↑ ↓ — 키보드로 폴더의 이전/다음 이미지로 넘깁니다(화면의 화살표 버튼은 없앴습니다).
- 프로그램을 켜면 목록은 비어 있습니다. 지난번에 쓰던 프로젝트는 경로 기본값으로만 되살아나고(상태바와 목록 위에 이름이 표시됩니다), 이미지를 열어야 그 폴더의 목록이 채워집니다.
- 오른쪽 아래 Class 범례 — 지금 이미지에 있는 Class 를 색과 건수로 보여 줍니다. 클릭하면 그 Class 의 표시 색을 바꿀 수 있고, 바뀐 색은 라벨링 앱에서도 그대로 쓰입니다.
- 라벨은 읽기만 합니다 — 이 화면에서는 아무것도 저장되지 않습니다. 라벨링 앱에서 저장하고 이 창으로 돌아오면 자동으로 다시 읽어 반영합니다. 보기 전용 화면이라 마우스로 박스를 그리거나 옮길 수 없습니다(휠 확대/축소는 됩니다). 라벨을 고치려면 [Labelling] 으로 여세요.
- 이미지를 확대/축소한 뒤
F를 누르면 화면에 다시 맞춥니다.
프로젝트는 선택 사항입니다 — 만들지 않아도 두 기능 모두 그대로 씁니다
(경로를 직접 지정하면 됩니다). 현재 프로젝트와 Inference 입력값은
~/.auto_labelling_tool.json 에 기억해 다음 실행 때 복원합니다.
라벨링 앱만 따로 띄우려면:
python Model_Development.py앱은 빈 화면으로 뜹니다. 좌측 상단 [Open Image](또는 Ctrl+O)로
검사할 이미지를 엽니다. 이미지가 든 폴더를 열면 뷰 좌우의 ◀ ▶ 화살표로
같은 폴더의 다른 이미지로 넘길 수 있습니다.
실행 옵션은 터미널 인자가 아니라 코드로 지정합니다. 이 도구의 스크립트들은
--image같은 명령줄 인자를 받지 않습니다. 시작 이미지·추론 해상도·LoRA 어댑터 등은Model_Development.py파일 맨 아래main(...)호출 값을 직접 고쳐서 지정하세요:main( image=r"C:\path\to\image.png", # None이면 빈 화면 image_size=768, # None=모델 기본 1008. VRAM 부족 시 768/560 lora_dir=None, # r"dataset\lora_adapter\best" 등 fp32=False, # fp16이 느린 카드면 True )
확정한 결함으로 SAM3 를 LoRA 파인튜닝해 zero-shot 인식 능력 자체를 넓혀 갑니다.
- [Prompt_Detect] 한 번 → 현재 프롬프트 + 지금까지 확정한 라벨을 합쳐 SAM3 Zero-Shot 검출을 실행합니다.
- 결과를 보고 틀린 건 우클릭 삭제 / 박스 드래그로 수정 (필요하면 툴바 [Polygon] 로 세그멘테이션 폴리곤까지 다듬기).
- [Confirm & Save](단축키
Ctrl+S) → 지금 결과를 정답으로 확정해 원본 이미지째 데이터셋(dataset/) 에 저장하고Dataset v{N}으로 갱신합니다. 결함이 하나도 없는 이미지는 [Confirm as Normal (OK)] 로 저장하면 학습 시 과검출을 줄여 줍니다.Ctrl+S는 화면을 보고 알아서 갈라집니다 — 라벨링이 있으면 확정 저장, 화면이 비어 있으면 그 이미지를 정상(OK)으로 확정합니다.- 같은 이미지를 다시 저장하면 이전 확정은 지워지고 지금 화면 그대로 저장됩니다. 다른 이미지를 보다가 돌아와 라벨을 고치거나 지운 뒤 저장하면, 옛 라벨이 남지 않습니다.
- 이미 결함을 확정해 둔 이미지를 정상(OK)으로 바꾸면 그 확정 기록이 지워지므로, 확인 창이 한 번 뜹니다.
- 툴바 [Train] 창에서 COCO 내보내기 + LoRA 학습을 한 번에 실행합니다.
경로(COCO/어댑터/이어서 학습) · 프리셋 · 에폭 · 학습률 · 누적 스텝 · 학습 해상도 ·
폴리곤 학습 · bf16 · negative 개수/비율 · cosine 스케줄러까지 화면에서 지정하고,
진행률과 로그를 그대로 보며 [Stop] 으로 끊을 수 있습니다. 결과는
dataset/lora_adapter/{best,last,checkpoint-epochN}/에 저장되고training_history.csv에 에폭별 지표가 쌓입니다. (터미널로 하려면 예전처럼python coco_export.py→python lora_train.py.) - 툴바 [Model] 로 학습 결과 폴더(
.../best등)를 선택하면 검출기에 즉시 반영됩니다 — 다음 검출부터 파인튜닝된 가중치로 동작. 어댑터가 적용돼 있으면 버튼 이름이Model *로 바뀌고, 툴팁에 현재 경로가 표시됩니다.
동작 원리: 확정 데이터로 SAM3 가중치에 LoRA(전체의 약 0.2~2%) 보정을 학습시켜 모델의 개념 이해 자체를 넓힙니다. 폴리곤(세그멘테이션)이 있으면 마스크까지 학습합니다. 자세한 파이프라인은
CLAUDE.md의lora-finetuning-flow를 참고하세요.
- 툴바 순서 —
Open Image · Train · Model · Pan · Fit · Clear · Polygon · Export COCO. 메뉴바(File/View)는 없고, 단축키는Ctrl+O이미지 열기 ·F화면 맞춤 ·Ctrl+S확정 & 저장 입니다. - 이미지 드래그(박스) → 그 박스를 예시로, 드래그 영역 안의 같은 종류 결함 검출 (하늘색)
- Prompts 입력창 / 프리셋 칩 → 쉼표로 여러 개 입력 (예:
scratch, crack, stain) - Sensitivity(THRESHOLD) 슬라이더 → 낮출수록 더 많이(민감하게) 검출
- Prompt Batch(1~8) → 프롬프트를 몇 개씩 묶어 한 번에 검출할지. 1이 기본이며 안전합니다. 클래스가 많고 VRAM 여유가 있을 때만 2~4 로 올려 보세요 — 호출 횟수는 줄지만 vision feature 를 그만큼 복제해 VRAM/연산이 늘어납니다.
- 검출 결과 표(Inspector) → 행 우클릭=삭제, LABEL 셀 클릭=Class명 변경
- Class 별 색 → 검출 박스·마스크·라벨은 Class 마다 다른 색으로 그려집니다. 색은 처음 보는 Class 에 자동으로 배정되고, Dataset 패널의 Class 표를 클릭하면 원하는 색으로 바꿀 수 있습니다(데이터셋에 저장되어 Auto Labelling Tool 에서도 같은 색).
- 박스 모서리·내부 드래그 → 좌표 수정
- [Polygon] 토글 → 세그멘테이션 결과를 폴리곤 꼭짓점으로 표시. 좌클릭 점 추가, 우클릭(3점↑) 폴리곤 닫기/새 클래스 라벨링, 완성 폴리곤 우클릭 삭제, 좌드래그 이동. [Confirm & Save] 시 폴리곤이 있으면 세그멘테이션(COCO polygon)까지 함께 저장됩니다.
- 학습 데이터셋(Dataset) → Total / Defect Image / Normal Image 3칸으로 현황을 보여 줍니다. Total 은 학습에 들어가는 전체 이미지 장수(결함 이미지 + 정상 이미지) 라, 정상(OK)으로만 확정해도 함께 올라갑니다. 그 아래 Class 표에서 확정된 결함이 클래스별로 몇 건인지(건수 많은 순) 확인할 수 있습니다.
- 측정·판정(Stats) → 결함 수/면적 비율/평균 점수를 집계하고, 허용 개수·면적비% 규칙으로 PASS / FAIL 을 판정합니다.
- 배치 검사(Batch) → [Open Folder] 로 이미지 폴더를 불러와 썸네일로 보고, [Detect All] 로 폴더 전체를 일괄 검사합니다.
- [Clear View] / [Clear] → 표시된 결과 제거
- 휠 → 마우스 위치 기준 확대/축소 · [Pan] Pan 모드 · [Fit]/
F
기본 추론 해상도는 1008px 입니다. Model_Development.py 의 main(image_size=...)
값을 낮추세요 (768, 더 부족하면 560). 학습은 lora_train.py 의 image_size /
bf16=True / grad_accum_steps 로 조절합니다.
SAM3 는 자연 이미지 개념으로 학습되어 "결함"이라는 추상 개념은 종종 약하게 반응합니다.
- 구체적 명사구 사용:
"black spot","surface scratch","metal crack","rust stain","missing part"등 - 임계값을 0.2~0.3 으로 낮춰 후보를 늘린 뒤 눈으로 선별
- 박스 검출 활용: 결함 하나를 드래그하면 box exemplar 로 유사 결함을 함께 찾습니다
- 잘 안 잡히면 LoRA 학습: 확정 데이터로 파인튜닝하면 애초에 인식 못하던 개념도 살아납니다
학습한 LoRA 모델로 폴더 전체를 검사해 결과 이미지 + JSON 을 저장합니다. 같은 일을 화면에서 하려면 런처의 [Infer] 를 쓰세요 — 아래 값들을 전부 위젯으로 지정하고 진행률/로그까지 보여 줍니다.
터미널로 돌리려면 batch_infer.py 하단 main(...) 의 image_dir,
lora_dir(필수) 등을 고쳐 실행:
python batch_infer.py검사 클래스는 어댑터의 labels.json(= 실제 학습한 카테고리)에서 읽습니다.
속도: 결과 이미지를 끄면(
save_images=False, UI 의 [Save Result Images] 체크 해제) 가장 크게 빨라집니다 — 2560×2560 실측으로 장당 1.85초 → 0.29초(저장이 전체의 84% 였습니다). 로그에열기 / 검출 / 저장이 따로 찍히니 직접 확인하실 수 있습니다.
image_batch_size를 2~4 로 올리면 여러 장을 한 번의 forward 로 묶어 처리해 장당 시간이 줄어듭니다(실측 RTX 2070 Max-Q · 560px · 프롬프트 2개: 322ms → 198ms). VRAM 을 장수만큼 더 쓰므로CUDA out of memory가 나면 낮추거나 해상도를 줄이세요. 결과를 외부 검사 툴 XML 로 반영하려면Revert2InspectionTool.py를 씁니다.
| 파일 | 설명 |
|---|---|
AutoLabellingTool.py |
첫 화면(런처) — 프로젝트 생성 / 프로젝트 열기 / Labelling / Infer / 비교 |
project.py |
프로젝트(작업 폴더) 생성·열기, 런처 설정(~/.auto_labelling_tool.json) |
Model_Development.py |
라벨링 앱(PySide6 데스크탑) 진입점 |
ui/ |
PySide6 화면, 도크 패널(Controls/Layers/Inspector/Dataset/Stats/Batch), 런처·추론 창, 오버레이, 백그라운드 |
features/ |
스마트(원클릭) · 자동(Auto) · 박스(Box) 검출 기능 모듈 |
sam3_defect.py |
SAM3 검출 엔진 (텍스트/박스 검출 API, LoRA 어댑터 로드) |
defect_dataset.py |
LoRA 학습용 확정 데이터셋 (원본 이미지 + 박스/폴리곤 + 라벨, 정상 이미지) |
coco_export.py · lora_train.py · merge_lora.py |
dataset → COCO → LoRA 파인튜닝 → (선택) 병합 |
batch_infer.py · Revert2InspectionTool.py |
폴더 일괄 추론 → 결과 이미지/JSON → 검사툴 XML 반영 |
check_env.py |
실행 전 환경/권한 점검 |
log_utils.py |
파일 로그/stdout tee/faulthandler |
requirements.txt |
의존성 목록 |
모든 스크립트(단,
check_env.py·AutoLabellingTool.py제외)는 터미널 인자를 받지 않습니다 — 각 파일 맨 아래if __name__ == "__main__":블록의main(...)값을 고쳐 실행합니다. 런처(AutoLabellingTool.py)는 고칠 값이 없습니다 — 경로·옵션을 화면에서 지정합니다.
from PIL import Image
from sam3_defect import Sam3DefectDetector
det = Sam3DefectDetector(image_size=768) # VRAM 여유 없으면 768
det.load()
det.set_image(Image.open("sample.png"))
# 텍스트 자동 검출
for d in det.detect_text("scratch", threshold=0.3):
print(d.label, d.score, d.box)
# 박스(시각적 예시) 검출 — box 는 (x1, y1, x2, y2) 절대 픽셀
for d in det.detect_box((296, 186, 344, 234), threshold=0.3):
print(d.score, d.box)
# 학습한 LoRA 어댑터를 얹어 검출 (base 위에 즉시 적용)
det.load_lora(r"dataset\lora_adapter\best")
det.set_image(Image.open("sample.png")) # 어댑터 반영 위해 재등록