ไปรษณีย์ไทย

คู่มือ & วิธีการทำงานของระบบ AI

Technical Guide

กำลังตรวจสอบโมเดล…

Technical Guide · ระยะที่ 2 · รถ EV

ระบบ AI ตรวจวัดพื้นที่ว่างในรถ EV ทำงานอย่างไร

ระบบรับ “ภาพถ่ายเดียว” จากกล้องภายในห้องสัมภาระของรถ EV แล้วใช้โมเดล Vision Transformer (DINOv3) จำแนกระดับพื้นที่ว่างออกเป็น 6 ระดับ เพื่อช่วยวางแผนการจัดส่งและใช้พื้นที่รถให้คุ้มค่าที่สุด · A single in-van camera image → DINOv3 ViT classifier → one of six empty-space levels.

1

ภาพรวมสถาปัตยกรรม

Model Architecture

แกนหลักคือ DINOv3 ViT-S/16+ ซึ่งเป็น Vision Transformer ที่ผ่านการเรียนรู้แบบ self-supervised มาก่อน (pretrained) ทำหน้าที่สกัดคุณลักษณะเชิงพื้นที่ของภาพ จากนั้นรวมเป็นเวกเตอร์เดียวด้วย Global Average Pooling แล้วส่งเข้าชั้น Linear ขนาดเล็กเพื่อจำแนกเป็น 6 คลาส

ภาพกล้อง

RGB · 224×224×3

→

DINOv3 ViT-S/16+

backbone (แช่แข็ง)

→

Spatial tokens

14×14×384

→

Dual Attention

ตัวเลือก (ปิดในโปรดักชัน)

→

Global Avg Pool

→ 384

→

Linear → LayerNorm

384 → 6 logits

→

Softmax + Argmax

6 คลาส

The backbone outputs a 14×14 grid of 384-dim tokens; these are pooled and passed through a single bias-free linear layer (384→6) with LayerNorm. An optional Dual Attention Module exists in the codebase but production inference runs with attention=None.

2

การเตรียมภาพก่อนเข้าโมเดล

Preprocessing

ทุกภาพผ่านขั้นตอนเดียวกันทั้งตอนเทรนและตอนใช้งานจริง เพื่อให้ผลตรงกัน:

transform = Compose([
  Resize((224, 224)),                 # ปรับขนาดเป็น 224×224
  ToTensor(),                         # → เทนเซอร์ค่า [0,1]
  Normalize(mean=[0.485,0.456,0.406], # ค่ามาตรฐาน ImageNet
            std =[0.229,0.224,0.225]),
])
image = Image.open(path).convert("RGB")  # บังคับเป็น 3 ช่องสี

ภาพจากกล้องรถ EV ในชุดข้อมูลเป็นภาพสีขนาด 640x360 px ทุกภาพจะถูกย่อเป็น 224×224 ก่อนเข้า backbone · หากกล้องสลับเป็นโหมดกลางคืน (ขาวดำ/อินฟราเรด) ภาพก็จะถูกแปลงเป็น RGB 3 ช่องด้วยขั้นตอนเดียวกัน

3

ความหมายของ 6 ระดับ (สำคัญ)

Class Semantics

ตัวเลขของระดับคือ เปอร์เซ็นต์พื้นที่ “ว่าง” ไม่ใช่ % บรรทุก ดังนั้น โฟลเดอร์ 0_ = ว่าง 0% = เต็มคัน และ 81-100_ = ว่าง 81–100% = เกือบว่าง

Native idxโฟลเดอร์ (ชุดรถ EV)% ว่างระดับแสดงผล (API)ความหมาย
00_0% (เต็ม)6ระดับ 6 · ใช้งานเกือบเต็ม หรือ เต็ม
11-20_1-20%5ระดับ 5 · ใช้งานมาก
221-40_21-40%4ระดับ 4 · ใช้งานปานกลาง
341-60_41-60%3ระดับ 3 · ใช้งานน้อย
461-80_61-80%2ระดับ 2 · ใช้งานน้อยมาก
581-100_81-100% (ว่าง)1ระดับ 1 · ว่าง

โมเดลทำนายดัชนีดิบ (native 0–5 ตามลำดับโฟลเดอร์) ส่วน API จะกลับเลขเป็นpredicted_class = 6 − pred เพื่อให้ “ระดับ 1 = ว่างมากสุด … ระดับ 6 = เต็ม” ตรงกับการแสดงผลบนพอร์ทัล · การวัดความแม่นยำใช้ดัชนีดิบเทียบกับเลขโฟลเดอร์โดยตรง (ไม่กลับเลข)

4

วิธีการเทรนโมเดล

Training Method

สูตรเทรนดั้งเดิม: ใช้ backbone DINOv3 ViT-S/16+ pretrained (LVD-1689M) เป็นตัวสกัดคุณลักษณะ แล้วเทรนหัวจำแนกด้วย CDB Loss (Class-Difficulty Balanced) ซึ่งปรับน้ำหนัก ความสูญเสียรายคลาสใหม่ทุก epoch ตามความแม่นยำของชุด validation เพื่อรับมือข้อมูลไม่สมดุล ร่วมกับ data augmentation (พลิกแนวนอน, หมุน, affine, ปรับสี และ SimulateNightVision จำลองภาพกลางคืน) · โมเดลปัจจุบันถูกเทรนจากภาพรถอีกประเภทหนึ่ง (รถบรรทุก ภาพอินฟราเรด) และยังไม่เคยเห็นภาพรถ EV มาก่อน

การเทรนใหม่สำหรับรถ EV: ขั้นแรกทดลอง เทรนเฉพาะชั้นจำแนก (head-only · 2,316 พารามิเตอร์ · Adam, full batch · 600 steps · 3 seeds) โดยแช่แข็ง backbone ไว้ เพื่อวัดว่าภาพรถ EV แยกระดับได้จริงหรือไม่ก่อนลงทุนเทรนเต็ม — ทำเสร็จแล้ว (ดูผลในข้อ 8) · ขั้นต่อไปคือ fine-tune ทั้งโมเดล บนชุดภาพรถ EV ที่ครอบคลุมหลายคัน หลายวัน ซึ่งอยู่ในแผน Roadmap

5

ขั้นตอนการอนุมาน (Inference)

Inference Pipeline

POST /predict  (multipart: file)
 1. เปิดภาพ → convert("RGB")
 2. transform → tensor (1, 3, 224, 224)
 3. logits = model(tensor)          # (1, 6)
 4. probs  = softmax(logits)
 5. pred   = argmax(probs)          # native 0..5
 6. predicted_class = 6 - pred      # → 1..6 (แสดงผล)
 7. map → empty_range / empty_percent

backbone ถูกโหลดจากไฟล์ในเครื่อง (local_files_only=True) ระบบจึงทำงานแบบออฟไลน์ได้ ทั้งหมด ไม่ต้องเรียก Hugging Face hub · วัดได้จริง ~132.9 ms/ภาพ บน CPU (จากการทดสอบภาพรถ EV 1,811 ภาพ)

6

การรวมผล 2 กล้อง (กล้องหน้า + กล้องหลัง)

Two-Camera Late Fusion

รถ EV ที่ใช้งานจริงติดตั้งกล้อง 2 ตัว (กล้องหน้า/กล้องหลัง) มองพื้นที่เดียวกันคนละมุม ส่วนชุดภาพตัวอย่างระยะที่ 2 ที่ได้รับมาเป็นภาพจากกล้องเดียว ระบบจึงออกแบบให้รองรับทั้ง ใช้กล้องเดียว และ รวมทั้ง 2 กล้อง ด้วยเทคนิค Late Fusion (Soft Voting)

  1. นำภาพแต่ละกล้องเข้าโมเดลตัวเดียวกันแยกกัน ได้เวกเตอร์ความน่าจะเป็น 6 ระดับของแต่ละกล้อง (pหน้า, pหลัง)
  2. เฉลี่ยความน่าจะเป็นรายระดับจากทุกกล้อง
  3. เลือกระดับที่มีค่าเฉลี่ยสูงสุด (argmax) เป็นคำตอบสุดท้าย
# ความน่าจะเป็นรวมของแต่ละระดับ k (1..6)
p_fused[k] = ( p_front[k] + p_rear[k] ) / 2

ระดับสุดท้าย = argmax(p_fused)         # ระดับ 1..6
ความเชื่อมั่น = max(p_fused)
# ใช้กล้องเดียว → p_fused = p ของกล้องนั้น (passthrough)

ทำไมช่วยได้: สองมุมมองช่วยลดความผิดพลาดจากการบดบัง (occlusion), มุมกล้อง และแสงเงาของภาพเดียว เพราะของในรถคือชุดเดียวกัน ทั้งสองกล้องจึงควรเห็นระดับใกล้กัน การเฉลี่ยความน่าจะเป็น จึงหักล้าง noise แบบสุ่มออก (เทียบเท่า ensemble แบบ soft-voting 2 สมาชิก) และไม่ต้องเทรนใหม่

ข้อจำกัดในตอนนี้: การจำลองการรวมผลบนหน้า ผลทดสอบล่าสุด (เฉลี่ยเฟรมติดกันแทนกล้องที่สอง) แสดงว่าการเฉลี่ยไม่สามารถแก้ความเอนเอียงทิศทางเดียวของโมเดลได้ก่อนการเทรนใหม่ — ทายตรงระดับ 25.7% (กล้องเดียว) เทียบ 25.4% (เฉลี่ย 2 เฟรม)· ทางเลือกอื่น เช่น ถ่วงน้ำหนักด้วยความเชื่อมั่น หรือ Early Fusion (ต้องเทรนใหม่) จะพิจารณาหลังมีภาพจากกล้องทั้งสองตัว

7

ชุดข้อมูลรถ EV (ระยะที่ 2)

EV Dataset

ภาพจากกล้องในรถ EV จัดเป็นโฟลเดอร์แบบแบน 6 โฟลเดอร์ตามระดับพื้นที่ว่าง รวม 1,811 ภาพ (ประเมินจริง 1,811 ภาพ · ขนาด 640x360 px · ถ่ายระหว่าง 04 ส.ค. – 06 ส.ค.)

โฟลเดอร์ระดับ (% ว่าง)ไฟล์ที่พบภาพที่ประเมิน
0_0% (เต็ม)300300
1-20_1-20%311311
21-40_21-40%300300
41-60_41-60%300300
61-80_61-80%300300
81-100_81-100% (ว่าง)300300
รวม1,8111,811

รอบการถ่ายภาพ (capture sessions)

วันที่ช่วงเวลาระดับ (% ว่าง)จำนวนภาพแหล่งที่มา
04 ส.ค.15:48–16:4581-10036ภาพจับหน้าจอ (screenshot)
05 ส.ค.09:11–11:2081-100264เฟรมจากกล้อง
05 ส.ค.11:21–15:3861-80300เฟรมจากกล้อง
05 ส.ค.15:42–17:1241-6079เฟรมจากกล้อง
06 ส.ค.09:03–11:1041-60221เฟรมจากกล้อง
06 ส.ค.11:13–14:5821-40300เฟรมจากกล้อง
06 ส.ค.15:01–18:101-20311เฟรมจากกล้อง
06 ส.ค.18:23–20:030%300เฟรมจากกล้อง

ข้อควรระวัง (confound): แต่ละระดับถูกถ่ายในรอบเดียวกันเกือบทั้งหมด (1 ระดับ ≈ 1 รอบการโหลดของ) ทำให้แสง โทนสี และเวลาที่พิมพ์อยู่บนภาพผูกติดกับระดับพื้นที่ว่างโดยไม่ตั้งใจ หากแบ่งชุดฝึก/ทดสอบแบบสุ่ม เฟรมติดกันจะไปอยู่ทั้งสองฝั่งและตัวเลขจะสูงเกินจริง การทดลองจึงแบ่งตามช่วงเวลา (time-block) และเว้นช่องว่าง 5 นาทีระหว่างชุด (ตัดออก 111 เฟรม) · ภาพซ้ำ 12 ภาพ และภาพจับหน้าจอ 36 ภาพ ถูกคัดออกจากชุดฝึก/ทดสอบ (ชุดฝึก 1,009 / ตรวจสอบ 182 / ทดสอบ 382 / ข้ามเซสชัน 79 ภาพ)

8

ผลทดสอบล่าสุด

Latest Results

โมเดลปัจจุบัน (ยังไม่เทรนใหม่) บนภาพรถ EV ทั้ง 1,811 ภาพ

26.1%

ทายตรงระดับ (exact)

62.4%

คลาดไม่เกิน ±1 ระดับ

24.9 จุด

MAE (โดยประมาณ)

การทดลองเทรนเฉพาะชั้นจำแนก (head-only) · ชุดทดสอบ time-block n=382 · ข้ามเซสชัน n=79

61.0%

ทายตรงระดับ (จาก 30.9%)

9.5 จุด

MAE (จาก 22.2 จุด)

39.2%

ข้ามเซสชัน 41–60% (จาก 38.0%)

ชุดทดสอบ time-block มาจากรอบถ่ายเดียวกับชุดฝึก (วันเดียวกัน แสงใกล้เคียง) ตัวเลขจึงสูงกว่าที่คาดว่าจะเจอกับรถคันใหม่หรือวันใหม่ ส่วนชุดข้ามเซสชัน (ระดับ 41–60% อีกวันหนึ่ง) ยังไม่เห็นการเปลี่ยนแปลงที่วัดได้ — จึงเป็นการทดลองความเป็นไปได้ ไม่ใช่โมเดลส่งมอบ · ระบบ deploy ด้วย FastAPI (โมเดล) + Next.js (หน้าเว็บ) · ดูผลแบบละเอียดที่ ผลทดสอบล่าสุด · รถ EV และแผนการเทรนใหม่ที่ Roadmap

9

API สำหรับระบบภายนอก (v1)

Integration API

ระบบของผู้ใช้งาน (เช่น ระบบที่ดึงภาพจากกล้อง/NVR ได้เอง) ส่งภาพมาให้ AI ประเมินได้โดยตรงผ่าน REST API ทุกคำขอต้องมี header X-API-Key · เอกสารฉบับเต็มพร้อมตัวอย่าง curl/Python อยู่ในไฟล์ docs/API.md และทดลองยิงได้จากหน้า Swagger ที่ /backend/docs

Endpointหน้าที่
GET /v1/health · GET /v1/modelสถานะและคิว · ข้อมูลโมเดล ตารางระดับ ขีดจำกัด และผลวัดล่าสุด
POST /v1/predict (multipart file)จำแนก 1 ภาพ + metadata (request_id, camera_id, vehicle_id, captured_at)
POST /v1/predict/json (image_base64)เหมือนด้านบน แต่ส่งเป็น JSON
POST /v1/predict/batchหลายภาพต่อคำขอ (≤ 8) ตอบ 200 พร้อมผล/ข้อผิดพลาดรายภาพ
curl -X POST "$BASE/v1/predict" -H "X-API-Key: $API_KEY" \
  -F "file=@frame.jpg" -F "camera_id=CAM-01" -F "vehicle_id=EV-001" \
  -F "captured_at=2026-08-05T09:35:10+07:00"

→ { "level": { "class": 1, "code": "ARE-01", "label_th": "ว่าง", "empty_range": {"min": 81, "max": 100} },
    "confidence": 0.66, "probabilities": { "1": 0.66, ... "6": 0.03 },
    "estimated_empty_percent": { "value": 78.3, "is_estimate": true }, "warnings": [...] }

คำตอบให้ระดับ 1–6 (รหัส ARE-01…06) ความน่าจะเป็นทั้ง 6 ระดับ และ ค่าประมาณ % ว่างที่ติดธง is_estimate — ไม่มีค่าสุ่ม · โมเดลที่ให้บริการยังเป็นตัวปัจจุบัน (ยังไม่ได้เทรนกับรถ EV) สัญญา API คงเดิมเมื่อเปลี่ยนโมเดล สังเกตได้จาก model_version · URL เดโมเป็น quick tunnel ที่เปลี่ยนเมื่อรีสตาร์ต ระบบจริงจะใช้ URL ถาวร