You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# kr_lp_pgnet — 프로젝트 핸드오프
한국 자동차 번호판 검출 + OCR을 위한 PaddleOCR PGNet 학습 프로젝트.
---
## 30초 요약
- **목표**: PGNet 한 모델로 한국 LP 4종 (자가용/영업/전기/화물) 검출+인식 → ONNX export
- **현재 상태 (2026-05-08)**: Step1 pretrain **학습 중** (50 epoch, eta ~11시간, run id `l0eqqbrb`)
- **다음 단계**: 학습 완료 후 → Step2 fine-tune (실차 데이터) → ONNX export
- **운영 원칙**: 로컬 Mac은 코드 작성·git만, 모든 실행(학습·합성·검증)은 외부 GPU 서버에서
---
## 환경
### 1. 로컬 Mac (코드 작성 전용)
- 작업 디렉토리: `/Users/songhyeonsu/Documents/GIT/cuuva_AI/kr_lp_pgnet/`
- **금지사항** (메모리 `feedback_local_no_runtime.md`):
- Python 패키지 설치 (`pip install ...`)
- 외부 자산 git clone (qjadud 등)
- 합성기·학습·평가 실행
- **허용**: 코드/yaml/sh 작성·수정, 우리 repo git commit/push
### 2. 외부 GPU 서버
- **SSH**: `ssh cuuva@192.168.10.189` (사내망 전용, key 인증)
- **호스트**: Ubuntu 25.10, RTX 5090 32GB, NVIDIA driver 590.48.01, CUDA 13.1
- **레이아웃**:
```
/home/cuuva/workspace/
├── PaddleOCR/ # git clone release/2.7
├── kr_lp_pgnet/ # 이 repo (사내망 GitLab에서 clone)
├── train_data/
│ ├── kr_lp_synth/ # Step1 학습용 (50k, 본격)
│ ├── kr_lp_synth_v2/ # 400장 (dry-run용)
│ ├── kr_lp_synth_smoke/ # 40장 (smoke test)
│ ├── region_check_y/ # 영업용 region 16종 검증
│ └── region_check_g/ # 친환경 region 16종 검증
└── wheels/
└── paddlepaddle_gpu-3.3.0.dev20251209-cp310-...whl # sm_120 wheel
```
### 3. 학습 컨테이너 `kr_lp_pgnet`
- 베이스: `ubuntu:24.04`
- 옵션: `--gpus all --shm-size=8g --restart unless-stopped`
- bind mount: 호스트 `/home/cuuva/workspace` ↔ 컨테이너 `/workspace`
- 설치된 것: Python 3.10 (deadsnakes), paddlepaddle-gpu 3.3.0.dev (sm_120), cuDNN 9.17, numpy 1.26, opencv 4.10+, wandb 0.26, PaddleOCR + 의존성
- 재셋업: `bash scripts/recreate_container.sh` (한 줄로 전부)
### 4. 파일 서버 컨테이너 `kr_lp_http`
- 합성 결과 시각 확인용
- URL: **http://192.168.10.189:8889/**
- 마운트: `/home/cuuva/workspace/train_data` (read-only)
- 시작 명령:
```bash
docker run -d --name kr_lp_http -v /home/cuuva/workspace/train_data:/data:ro \
-p 8889:8889 --restart unless-stopped python:3.11-slim \
python3 -m http.server 8889 --bind 0.0.0.0 --directory /data
```
### 5. 다른 컨테이너 `my-vision-container` (우리 일과 무관, 그대로 두기)
- 4주 전 시작, 8888 포트로 Jupyter 노출
- 우리 paddle wheel 설치 중 cuda-bindings/nccl 충돌로 **torch import 깨진 상태**
- 복구는 사용자가 원할 때 본인 방식으로 `docker rm -f 983b0a026d7b && docker run ...` (`/workspace`는 bind mount라 데이터 안전)
---
## 저장소
- **Git remote**: `http://192.168.10.110/TTA/kr_lp_pgnet.git` (사내 GitLab/Gitea)
- **HTTP 인증**: 서버에서 평소 git push/pull 정상 (사용자 설정됨)
- **브랜치**: `main`만 사용
- **로컬 사용자 정보**: `hunsoo0823@naver.com` / `songhyeonsu`
## wandb
- **Entity**: `hssong_cuuva` (개인 계정)
- **Project**: `kr_lp_pgnet`
- **현재 본격 학습 run**: `step1-pretrain` (id `l0eqqbrb`)
- **dashboard**: https://wandb.ai/hssong_cuuva/kr_lp_pgnet
- **이 run 직접 URL**: https://wandb.ai/hssong_cuuva/kr_lp_pgnet/runs/l0eqqbrb
- **로그인**: 컨테이너 안 `/root/.netrc`에 저장됨 (`recreate_container.sh`가 자동 보존)
---
## 디렉토리 구조 (이 repo)
```
kr_lp_pgnet/
├── README.md
├── ONBOARDING.md # 이 문서
├── configs/
│ └── kr_lp_pgnet.yml # PGNet 학습 설정 (epoch 50, batch 16, pad_num 67)
├── dict/
│ └── kr_lp_dict.txt # 문자 사전 67자
├── data_gen/
│ ├── README.md # 자산 라이센스 / 사용법 / 알려진 제약
│ ├── setup_assets.sh # qjadud 자산 git clone
│ └── generate_synthetic.py # 합성기 (4 plate types, brightness, type weights)
├── scripts/
│ ├── recreate_container.sh # 컨테이너 재생성 (shm 8g, gpus all)
│ ├── setup_server.sh # 컨테이너 안 환경 셋업 (idempotent)
│ └── run_step1.sh # Step1 학습 실행
└── tools/
└── region_check.py # REGION_MAP 시각 검증용
```
---
## 진행 상태 (체크리스트)
### ✅ 완료
1. **환경 셋업** — repo, GitLab remote, 서버 컨테이너, paddle sm_120 wheel, cuDNN 9.17, PaddleOCR release/2.7
2. **dict + config** — 67자 (숫자 10 + 자가용 32 + 영업용 4 + 렌터카 3 + 배달 1 + 지역명 17), `pad_num=67`, `max_text_length=10`, `valid_set=partvgg`, `infer_visual_type=CN`
3. **합성기** — 4 plate type (520×110 / 355×155 / 336×170×2), 한영자판 매핑, REGION_MAP(추정), 도로 분포 가중치 (Type1 80%/Type2 5%/Type3 10%/Type4 5%), random_bright
4. **wandb 연동** — Global.use_wandb=True + project=kr_lp_pgnet
5. **50k 합성 완료** — train 47500 / test 2500, type 분포 도로 현실 일치
### 🔄 진행 중
- **Step1 pretrain 학습** — 50 epoch, batch 16, num_workers 8, 50k synthetic data
- 시작: 2026-05-08 07:58
- ips 58~59 samples/s
- 진행: epoch 1/50 ~step 2110 (확인 시점 기준)
- eta: ~11시간
- loss: 1234 → 63 (감소 추세 정상)
- 체크포인트 저장 경로: `/workspace/PaddleOCR/output/kr_lp_pgnet/{latest,best_accuracy}/`
### 📋 다음 단계
1. **Step1 완료 평가**`eval f_score_e2e` 확인, 추론 결과 시각 검증 (synth test set + 임의 LP 이미지)
2. **Step2 fine-tune** — 실제 한국 LP 사진 데이터 수집·라벨링·fine-tune (자산이 못 만든 글자 보충: 하, 호, 배, 세종)
3. **ONNX export**`paddle2onnx`로 변환 → 추론 검증
4. **(선택) 더 강한 augmentation** — config에 IaaAugment 추가 (rotate/perspective/blur)
5. **(선택) REGION_MAP 정확 검증** — region_check_y/g 시각 확인 후 매핑 정정
---
## 자주 쓰는 운영 명령
### 학습 모니터링
```bash
# 학습 프로세스 살아있는지
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet pgrep -af tools/train.py | wc -l'
# 학습 로그 (eval tqdm 줄 제외)
ssh cuuva@192.168.10.189 \
'docker exec kr_lp_pgnet bash -c "grep -v \"it/s\" /workspace/PaddleOCR/output/kr_lp_pgnet/run.log | tail -5"'
# GPU 사용량
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet nvidia-smi --query-gpu=memory.used,utilization.gpu --format=csv'
```
### 학습 끊김 대응 (NVML stale 등)
```bash
# 1. 컨테이너 재시작 (NVML 풀기)
ssh cuuva@192.168.10.189 'docker restart kr_lp_pgnet'
# 2. 이어서 학습 (latest 체크포인트에서 재개)
ssh cuuva@192.168.10.189 'docker exec -d kr_lp_pgnet bash -c "
cd /workspace/PaddleOCR
nohup python3.10 tools/train.py -c configs/e2e/kr_lp_pgnet.yml \
-o Global.checkpoints=./output/kr_lp_pgnet/latest \
> output/kr_lp_pgnet/run.log 2>&1 &
"'
```
### 학습 중단
```bash
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet pkill -f "tools/train.py"'
```
### 합성 추가 생성
```bash
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet python3.10 \
/workspace/kr_lp_pgnet/data_gen/generate_synthetic.py \
--out_dir /workspace/train_data/kr_lp_synth_extra \
--num 10000 --types 1,2,3,4 \
--dict /workspace/kr_lp_pgnet/dict/kr_lp_dict.txt'
```
### 컨테이너 완전 재셋업 (드물게)
```bash
ssh cuuva@192.168.10.189 'bash ~/workspace/kr_lp_pgnet/scripts/recreate_container.sh'
```
### 파일 서버 재시작
```bash
ssh cuuva@192.168.10.189 'docker restart kr_lp_http'
```
---
## 알려진 이슈 / 의사결정 기록
### 시스템
- **NVML stale 재발 가능성**: 컨테이너 오래 돌면 `nvidia-smi``Failed to initialize NVML` 에러. 호스트는 멀쩡, 컨테이너 재시작 한 번으로 풀림. 학습 시작 직전 한 번 재시작했으니 한동안은 안전할 가능성.
- **shm 부족 → DataLoader BUS error**: `--shm-size=8g` 필수 (해결됨).
- **OOM at batch 32**: PGNet 가변 input 사이즈가 peak에 32GB 초과. **batch 16 확정**.
- **cuDNN 9.17 강제**: paddle sm_120 wheel은 9.17로 빌드됐는데 paddle deps는 9.13 install. `pip install 'nvidia-cudnn-cu13>=9.17'`로 덮어쓰지 않으면 conv2d에서 `cublasLtCreate` 심볼 로드 실패 후 process abort. setup_server.sh에 반영됨.
- **paddle wheel 출처**: 비공식 [horhe-dvlp/paddlepaddle-sm120-wheels](https://github.com/horhe-dvlp/paddlepaddle-sm120-wheels) v3.3.0-dev (Python 3.10, CUDA 13.0). 공식은 sm_120 미지원.
### 데이터
- **자산 출처**: [qjadud1994/Korean-license-plate-Generator](https://github.com/qjadud1994/Korean-license-plate-Generator) (MIT). 폰트 대신 글자 PNG 사용 → 폰트 라이센스 회피.
- **자산이 만들 수 없는 글자 3개**: `하`, `호`, `배` — 합성 데이터에 안 등장. Step2 fine-tune의 실차 데이터로 보충 가정.
- **REGION_MAP 추정**: 자산 region PNG (A.jpg ~ P.jpg) → 한국 광역지자체 매핑은 일반 컨벤션 기반 추정값. `A='서울'` 한 개만 시각 검증됨. 나머지는 `tools/region_check.py` 실행 후 시각 확인하여 정정 필요.
- **세종 지역 빠짐**: 자산 region 16개라 17개 광역지자체 중 1개(추정 세종) 누락.
- **plate 배경 정확도**: 자가용은 정확, 영업용·전기차는 한국 표준과 약간 차이 (특히 전기차는 자산이 흰바탕+파란띠가 아니라 파란 두 줄). Step2 필수.
### 합성 분포 (한국 도로 추정)
| Type | 형태 | 비율 |
|---|---|---|
| 1 | 신형 가로 1줄 (자가용 흰) | 80% |
| 2 | 구형 가로 1줄 (흰, 작음) | 5% |
| 3 | 두 줄 노랑 (영업용 구형) | 10% |
| 4 | 두 줄 파/녹 (친환경 추정) | 5% |
---
## 학습 결과 평가 방법 (Step1 끝나면)
```bash
# 1. wandb dashboard에서 eval/f_score_e2e 추이 확인
# https://wandb.ai/hssong_cuuva/kr_lp_pgnet/runs/l0eqqbrb
# 2. best_accuracy 체크포인트로 평가 (paddle 명시 평가)
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet bash -c "
cd /workspace/PaddleOCR
python3.10 tools/eval.py -c configs/e2e/kr_lp_pgnet.yml \
-o Global.checkpoints=./output/kr_lp_pgnet/best_accuracy
"'
# 3. 임의 이미지 추론
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet bash -c "
cd /workspace/PaddleOCR
python3.10 tools/infer_e2e.py -c configs/e2e/kr_lp_pgnet.yml \
-o Global.infer_img=./train_data/kr_lp_synth/test/images/000000.jpg \
Global.pretrained_model=./output/kr_lp_pgnet/best_accuracy \
Global.load_static_weights=False
"'
```
## ONNX export (Step2 끝난 후)
```bash
# inference model export
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet bash -c "
cd /workspace/PaddleOCR
python3.10 tools/export_model.py -c configs/e2e/kr_lp_pgnet.yml \
-o Global.pretrained_model=./output/kr_lp_pgnet/best_accuracy \
Global.save_inference_dir=./inference/kr_lp_pgnet_infer
"'
# paddle2onnx
ssh cuuva@192.168.10.189 'docker exec kr_lp_pgnet bash -c "
python3.10 -m pip install paddle2onnx
paddle2onnx --model_dir /workspace/PaddleOCR/inference/kr_lp_pgnet_infer \
--model_filename inference.pdmodel --params_filename inference.pdiparams \
--save_file /workspace/kr_lp_pgnet/kr_lp_pgnet.onnx \
--opset_version 13
"'
```
---
## 메모리 (project + feedback)
이 프로젝트 관련 사용자 기억은 Claude Code memory에 저장돼 있음:
- `project_kr_lp_pgnet.md` — 프로젝트 개요·분업 구조·아키텍처
- `feedback_local_no_runtime.md` — 로컬 Mac은 코드 작성 전용, 실행 금지
이 두 메모리는 새 Claude Code 세션에서도 자동 로드됨 (메모리 디렉토리: `/Users/songhyeonsu/.claude/projects/-Users-songhyeonsu-Documents-GIT-cuuva-AI/memory/`).