File size: 4,601 Bytes
3b18ebd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# -*- coding: utf-8 -*-
"""全域設定:訓練與即時推論共用,改這裡就好。"""
from pathlib import Path

# ---------------------------------------------------------------- 路徑
PROJECT_DIR = Path(__file__).resolve().parent
# 把 Google Drive 的 NPY_Dataset 下載到本機後,放在這個路徑
DATA_ROOT = PROJECT_DIR / "data" / "NPY_Dataset"
OUT_DIR = PROJECT_DIR / "runs"

# ---------------------------------------------------------------- 關鍵點佈局
# 每個 .npy 形狀為 (T, 55, 3)。55 = 12 上半身 pose + 21 左手 + 21 右手 + 1 虛擬頸點。
# ✓ 已與組員的 extract_features.py 核對過,完全一致。
NUM_POINTS = 55
POSE_SLICE = slice(0, 12)      # 上半身 pose
LHAND_SLICE = slice(12, 33)    # 左手 21 點
RHAND_SLICE = slice(33, 54)    # 右手 21 點
CENTER_IDX = 54                # 虛擬頸點=雙肩中點(正規化原點)
LSHOULDER_IDX = 0
RSHOULDER_IDX = 1

# 從 MediaPipe Pose 的 33 點裡挑的 12 點(= extract_features.py 的 POSE_INDICES)。
POSE_MP_INDICES = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

# ---------------------------------------------------------------- 前處理
# 實際資料:影格數 min=55 / median=150 / max=179,所以重採樣到 64 格
# (約 2.3 倍下採樣,保留足夠的手部動作細節,又不會讓訓練太慢)
SEQ_LEN = 64
MIN_FRAMES = 8        # 少於這個影格數的樣本會先補到這個長度
USE_XY_ONLY = True    # MediaPipe 的 z 噪音大,預設只用 x,y(設 False 則保留全部維度)
ADD_VELOCITY = True   # 加入相鄰影格差分(動作速度),對手語很有幫助
ADD_MASK = True       # 加入「這一點這一格有沒有被偵測到」的 0/1 通道

# --- 跨人泛化用的特徵(骨向量與關節角度對體型差異較不敏感)
ADD_BONE = True       # 每個節點指向父節點的向量(長度隱含肢段比例)
ADD_ANGLE = True      # 該節點在骨架樹上與父、祖父形成的夾角(純角度,與體型無關)

# ---------------------------------------------------------------- 訓練
SEED = 42
VAL_RATIO = 0.2
BATCH_SIZE = 32
EPOCHS = 120
LR = 1e-3
WEIGHT_DECAY = 1e-4
LABEL_SMOOTHING = 0.05
EARLY_STOP_PATIENCE = 25

# ---------------------------------------------------------------- 模型
ARCH = "stgcn"
DROPOUT = 0.3

# ST-GCN
GRAPH_STRATEGY = "spatial"      # "spatial"(三組分割)或 "uniform"
STGCN_CHANNELS = (64, 64, 128, 128)
STGCN_STRIDES = (1, 1, 2, 1)    # 2 代表時間軸下採樣一半
STGCN_EDGE_IMPORTANCE = True    # 讓模型自己學每條骨架邊的重要性

# ---------------------------------------------------------------- 資料增強
# 目標不只是防過擬合,而是 domain randomization ——
# 用單一拍攝者的資料合成出「各種體型、各種取景、各種偵測品質」的假樣本,
# 讓模型不要依賴那些會隨人改變的線索。
AUG_SCALE = 0.20       # 隨機縮放 ±20%
AUG_ROTATE_DEG = 18.0  # 隨機旋轉 ±18 度
AUG_SHIFT = 0.10       # 隨機平移
AUG_NOISE = 0.015      # 高斯雜訊
AUG_TIME_WARP = 0.3    # 隨機加減速 ±30%
AUG_FRAME_DROP = 0.08  # 隨機丟影格比例
AUG_MIRROR = False     # 左右鏡像:手語中左右手分工有意義,預設關閉

# --- 模擬跨人/跨環境的差異
AUG_LIMB_SCALE = 0.15     # 各肢段長度獨立隨機縮放 ±15%,模擬不同體型
AUG_JOINT_DROP = 0.15     # 隨機關節在隨機時段「偵測失敗」,模擬 MediaPipe 掉點
AUG_HAND_DROP = 0.15      # 整隻手短暫消失的機率(實測即時環境常發生)
AUG_TEMPORAL_CROP = 0.25  # 隨機裁掉頭尾最多 25%,模擬滑動視窗沒對齊完整動作

# ---------------------------------------------------------------- 即時推論
# ★ 關鍵:訓練時每支影片不管多長都被時間正規化成 SEQ_LEN 格,
#   所以模型學到的是「一個完整手語詞從頭到尾」的樣子。
#   即時推論的 sliding window 必須涵蓋**同樣長度的時間**(而不是同樣的影格數),
#   否則模型會看到一個被快轉 3 倍的動作,準確率直接崩掉。
#
# 訓練影片中位數 150 格。若原始影片是 30 fps → 一個詞約 5.0 秒。
# ★ 請跟組員確認原始 mp4 的 fps,再改這個數字:PRED_WINDOW_SECONDS = 150 / fps
PRED_WINDOW_SECONDS = 5.0
PRED_STRIDE = 4            # 每幾格推論一次
PRED_THRESHOLD = 0.75      # 信心門檻,低於此不輸出
PRED_SMOOTH = 3            # 連續幾次相同預測才確認