--- base_model: unsloth/Qwen3.5-9B library_name: peft language: - ko pipeline_tag: image-text-to-text tags: - agriculture - image-classification - korean - lora - peft - pest-detection - qwen - qwen3 - vision-language datasets: - Himedia-AI-01/kor-pest-detection-webp metrics: - accuracy - f1 - precision - recall model-index: - name: kor-pest-detector results: - task: type: image-text-to-text name: Korean Pest Classification dataset: name: Himedia-AI-01/kor-pest-detection-webp type: image-classification metrics: - type: accuracy value: 0.9948 name: Accuracy - type: f1 value: 0.9891 name: F1 (macro) - type: f1 value: 0.9948 name: F1 (weighted) - type: precision value: 0.9907 name: Precision (macro) - type: recall value: 0.9879 name: Recall (macro) --- # 해충 탐지 VLM - Qwen3.5-9B LoRA [unsloth/Qwen3.5-9B](https://huggingface.co/unsloth/Qwen3.5-9B)를 파인튜닝한 비전-언어 PEFT 기반 LoRA 어댑터입니다. 작물 사진에서 한국 농작물 해충 19종을 식별합니다. 제공된 잎, 과실, 식물 전체 사진에 감지된 해충이 있을 시 해충의 한국어 이름을 출력하고, 해충이 감지되지 않으면 `정상`을 출력합니다. * 19개 클래스 분류기: 해충 18종 + '정상' (해충 없음) * 베이스 모델: `unsloth/Qwen3.5-9B` (비전-언어, 하이브리드 Linear + Self Attention) * 어댑터 유형: LoRA (PEFT), Rank 64, Alpha 128 * 언어: 한국어 * 크기: 어댑터 가중치 693MB 클래스 목록 - 정상 - 검거세미밤나방 - 꽃노랑총채벌레 - 담배가루이 - 담배거세미나방 - 담배나방 - 도둑나방 - 먹노린재 - 목화바둑명나방 - 무잎벌 - 배추좀나방 - 배추흰나비 - 벼룩잎벌레 - 복숭아혹진딧물 - 홍비단노린재 - 썩덩나무노린재 - 열대거세미나방 - 큰28점박이무당벌레 - 톱다리개미허리노린재 - 파밤나방 ## ⚠ 배포 전에 반드시 읽어야 할 단 한 가지 **이 LoRA는 GGUF / llama.cpp / Ollama 경로로 배포할 수 없습니다.** 현재 어댑터의 `adapter_config.json`에서 `target_modules`에 `in_proj_qkv`, `in_proj_z`, `in_proj_a`, `in_proj_b`, `out_proj`가 포함되어 있습니다. 이는 Qwen3.5 하이브리드 아키텍처의 `linear_attn` 계열 투영에 해당하며, GGUF 변환 경로(`convert_hf_to_gguf.py`의 `_reorder_v_heads`)에서 LoRA 델타가 보존되지 않아 출력 붕괴가 발생할 수 있습니다. 요약: - `merge_and_unload` 또는 `save_pretrained_merged` 후 GGUF 변환: 고위험 - `FastVisionModel + PeftModel.from_pretrained` 런타임 LoRA: 권장 - 배포는 HF Transformers/Unsloth 기반 서버로 유지 권장 ## 학습 설정 열기/접기 | 하이퍼파라미터 | 값 | |---|---| | LoRA Rank | 64 | | LoRA Alpha | 128 | | rsLoRA 사용 | True | | 비전 레이어 파인튜닝 | False | | 학습률 | 0.000116 | | 웜업 비율 | 0.03 | | 가중치 감쇠 | 0.013802 | | LR 스케줄러 | linear | | 옵티마이저 | adamw_torch | | 디바이스당 배치 | 1 | | 그래디언트 누적 | 8 | | 유효 배치 | 8 | | 최대 시퀀스 길이 | 1024 | | Epoch 수 | 1 | | Tight Crop 확률 | 0.4561 | | 정밀도 형식 | bf16 | | 그래디언트 체크포인팅 | True | | 학습 시간 | 1115분 | * 학습 하드웨어: RTX A40 48G 학습 코드와 하이퍼-파라미터 탐색 코드는 [WizWix/model-finetuner](https://github.com/WizWix/model-finetuner)에 있습니다. ## 평가 결과 [Himedia-AI-01/kor-pest-detection-webp](https://huggingface.co/datasets/Himedia-AI-01/kor-pest-detection-webp)의 검증 세트 샘플 (전체 1,535개)로 평가한 결과입니다. | 지표 | 값 | |---|---| | 정확도 (Accuracy) | 99.48% | | 정밀도 (Precision, Macro) | 99.07% | | 정밀도 (Precision, Weighted) | 99.49% | | 재현율 (Recall, Macro) | 98.79% | | 재현율 (Recall, Weighted) | 99.48% | | F1 (Macro) | 98.91% | | F1 (Weighted) | 99.48% | | 검증 샘플 수 | 1,535 | [W&B Report](https://wandb.ai/wizwix36-none/kor-pest-detector-train) ## 혼동 행렬   ## 클래스별 성능 | 클래스 | 정밀도 (Precision) | 재현율 (Recall) | F1 | 샘플 수 | | ---------- | --------------: | -----------: | -----: | ---: | | 검거세미밤나방 | 0.9286 | 0.9286 | 0.9286 | 14 | | 꽃노랑총채벌레 | 1.0000 | 1.0000 | 1.0000 | 44 | | 담배가루이 | 1.0000 | 1.0000 | 1.0000 | 41 | | 담배거세미나방 | 1.0000 | 1.0000 | 1.0000 | 46 | | 담배나방 | 1.0000 | 1.0000 | 1.0000 | 69 | | 도둑나방 | 1.0000 | 0.9231 | 0.9600 | 13 | | 먹노린재 | 0.9894 | 1.0000 | 0.9947 | 93 | | 목화바둑명나방 | 1.0000 | 1.0000 | 1.0000 | 34 | | 무잎벌 | 1.0000 | 1.0000 | 1.0000 | 22 | | 배추좀나방 | 0.9733 | 1.0000 | 0.9865 | 73 | | 배추흰나비 | 1.0000 | 1.0000 | 1.0000 | 116 | | 벼룩잎벌레 | 1.0000 | 1.0000 | 1.0000 | 203 | | 복숭아혹진딧물 | 1.0000 | 1.0000 | 1.0000 | 35 | | 썩덩나무노린재 | 1.0000 | 0.9917 | 0.9958 | 120 | | 열대거세미나방 | 0.9423 | 0.9800 | 0.9608 | 50 | | 정상 | 1.0000 | 0.9932 | 0.9966 | 147 | | 큰28점박이무당벌레 | 1.0000 | 1.0000 | 1.0000 | 133 | | 톱다리개미허리노린재 | 1.0000 | 1.0000 | 1.0000 | 75 | | 파밤나방 | 0.9796 | 0.9412 | 0.9600 | 51 | | 홍비단노린재 | 1.0000 | 1.0000 | 1.0000 | 156 | ### LoRA 어댑터 유무에 따른 차이 [유사한 데이터셋의 실험 결과](https://huggingface.co/pfox1995/pest-detector-final/blob/main/README.md#%F0%9F%93%88-%EB%B2%A0%EC%9D%B4%EC%8A%A4%EB%9D%BC%EC%9D%B8-%EB%B9%84%EA%B5%90-lora-%EC%96%B4%EB%8C%91%ED%84%B0-%EC%9C%A0%EB%AC%B4%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%B0%A8%EC%9D%B4)를 참조하세요. ## 사용 예시 ### 빠른 시작 (권장 추론 경로: Unsloth + Runtime PEFT) ```python import torch from unsloth import FastVisionModel from peft import PeftModel from PIL import Image BASE = "unsloth/Qwen3.5-9B" ADAPTER = "WizWix/kor-pest-detector" # 학습 시 사용한 시스템 프롬프트를 그대로 사용 SYSTEM_MSG = ( "당신은 작물 해충 식별 전문가입니다. " "사진을 보고 해충의 이름만 한국어로 답하세요. " '해충이 없으면 "정상"이라고만 답하세요. ' "부가 설명 없이 이름만 출력하세요." ) # 베이스 모델 로드 + 어댑터 연결 model, tokenizer = FastVisionModel.from_pretrained(BASE, load_in_4bit=False) model = PeftModel.from_pretrained(model, ADAPTER) FastVisionModel.for_inference(model) model.eval() # 이미지 준비 image = Image.open("pest.jpg").convert("RGB") messages = [ {"role": "system", "content": [{"type": "text", "text": SYSTEM_MSG}]}, { "role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": "이 사진에 있는 해충의 이름을 알려주세요."}, ], }, ] text = tokenizer.apply_chat_template( messages, add_generation_prompt=True, enable_thinking=False, ) inputs = tokenizer(image, text, add_special_tokens=False, return_tensors="pt").to("cuda") with torch.inference_mode(): out = model.generate( **inputs, max_new_tokens=10, use_cache=True, stop_strings=["\n"], tokenizer=tokenizer.tokenizer, ) prediction = tokenizer.decode(out[0][inputs["input_ids"].shape[1] :], skip_special_tokens=True).strip() print(prediction) # 예: "배추흰나비" ``` ### 주의: 병합/GGUF 변환 경로 비권장 아래 경로는 현재 어댑터 타깃 모듈 구성(`in_proj_qkv/z/a/b/out_proj`)과 충돌 가능성이 높아 권장하지 않습니다. ```python # 비권장 예시 (실행하지 마세요) # model = model.merge_and_unload() # model.save_pretrained("./merged") # 이후 GGUF 변환 및 llama.cpp/Ollama 배포 ``` ## 라이선스 베이스 모델 및 데이터셋의 라이선스를 따릅니다. 자세한 약관은 [unsloth/Qwen3.5-9B](https://huggingface.co/unsloth/Qwen3.5-9B) 및 [Himedia-AI-01/kor-pest-detection-webp](https://huggingface.co/datasets/Himedia-AI-01/kor-pest-detection-webp)를 확인하세요.