refactor(actpred): 模型输入尺寸 image_size → image_width/image_height,默认 1920×1080
config/model/dataset/train/pretrain/predict/export 全链路适配非方形输入, hailo_infer/onnx_infer 从模型元数据动态推导宽高;旧 224 checkpoint 配置键 不兼容(重训后替换)。Pi 5 CPU 冒烟验证 1080p 训练可行(~4.75s/步 batch=2)。
This commit is contained in:
1 parent
a240377ba1
commit
91b30040c7
11 files changed
+73
-56
No files matched your search
+3
-2
@@ -9,7 +9,7 @@ Transformer(pre-LN)自注意力融合,取 [PRED] token 回归下一步动
|
||||
## 架构
|
||||
|
||||
```
|
||||
F 帧图像 (F×3×224×224) ─► 共享 CNN 编码器 ─► F 个 token ─► proj → d_model ┐
|
||||
F 帧图像 (F×3×H×W) ─► 共享 CNN 编码器 ─► F 个 token ─► proj → d_model ┐
|
||||
├─► [img×F, act×H, PRED] + 位置编码
|
||||
动作历史 (H×D) ─► Linear proj → d_model ─► H 个 token ────────┤ │
|
||||
可学习 [PRED] token ────────────────────────────────────────┘ ▼
|
||||
@@ -110,7 +110,8 @@ recorder.flush()
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `--image-size` | 224 | 图像缩放尺寸 |
|
||||
| `--image-width` | 1920 | 图像缩放宽度 |
|
||||
| `--image-height` | 1080 | 图像缩放高度 |
|
||||
| `--action-dim` | 18 | 动作向量维度(对齐 bot4cj 18 列:10 舵机 + 2 云台 + 扬声器频率 + 延时 + 4 预留)|
|
||||
| `--history-len` | 5 | 历史动作窗口长度 |
|
||||
| `--frame-len` | 3 | 输入图像帧数(含当前帧,旧帧在前)|
|
||||
|
||||
+8
-4
@@ -5,7 +5,8 @@ from typing import Optional
|
||||
|
||||
@dataclass
|
||||
class DataConfig:
|
||||
image_size: int = 224
|
||||
image_width: int = 1920
|
||||
image_height: int = 1080
|
||||
action_dim: int = 18
|
||||
history_len: int = 5
|
||||
frame_len: int = 3
|
||||
@@ -59,7 +60,8 @@ class Config:
|
||||
|
||||
def build_argparser(description: str = "") -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
parser.add_argument("--image-size", type=int, default=None)
|
||||
parser.add_argument("--image-width", type=int, default=None)
|
||||
parser.add_argument("--image-height", type=int, default=None)
|
||||
parser.add_argument("--action-dim", type=int, default=None)
|
||||
parser.add_argument("--history-len", type=int, default=None)
|
||||
parser.add_argument("--frame-len", type=int, default=None)
|
||||
@@ -99,7 +101,8 @@ def validate_config_values(data_cfg: DataConfig, model_cfg: ModelConfig,
|
||||
也防止训练 CLI 越界参数(如 --history-len 0 / --lr -1)静默进入训练。
|
||||
"""
|
||||
checks = [
|
||||
("image_size", data_cfg.image_size, 1, 1024, int),
|
||||
("image_width", data_cfg.image_width, 1, 4096, int),
|
||||
("image_height", data_cfg.image_height, 1, 4096, int),
|
||||
("history_len", data_cfg.history_len, 1, 1024, int),
|
||||
("frame_len", data_cfg.frame_len, 1, 1024, int),
|
||||
("action_dim", data_cfg.action_dim, 1, 1024, int),
|
||||
@@ -173,7 +176,8 @@ def parse_checkpoint_config(cfg_dict: dict) -> Config:
|
||||
|
||||
def apply_overrides(cfg: Config, args: argparse.Namespace) -> Config:
|
||||
mapping = {
|
||||
"image_size": ("data", "image_size"),
|
||||
"image_width": ("data", "image_width"),
|
||||
"image_height": ("data", "image_height"),
|
||||
"action_dim": ("data", "action_dim"),
|
||||
"history_len": ("data", "history_len"),
|
||||
"frame_len": ("data", "frame_len"),
|
||||
|
||||
+5
-3
@@ -16,16 +16,18 @@ def _natural_key(p):
|
||||
|
||||
class ActionDataset(Dataset):
|
||||
def __init__(self, data_dir: str, history_len: int, action_dim: int,
|
||||
image_size: int = 224, normalize_actions: bool = False,
|
||||
image_width: int = 1920, image_height: int = 1080,
|
||||
normalize_actions: bool = False,
|
||||
action_stats_path: str = None, episode_indices: list = None,
|
||||
frame_len: int = 3):
|
||||
self.history_len = history_len
|
||||
self.action_dim = action_dim
|
||||
self.image_size = image_size
|
||||
self.image_width = image_width
|
||||
self.image_height = image_height
|
||||
self.frame_len = frame_len
|
||||
|
||||
self.transform = transforms.Compose([
|
||||
transforms.Resize((image_size, image_size)),
|
||||
transforms.Resize((image_height, image_width)),
|
||||
transforms.ToTensor(),
|
||||
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
|
||||
])
|
||||
|
||||
@@ -21,7 +21,7 @@ def main():
|
||||
model.eval()
|
||||
|
||||
dummy_images = torch.randn(
|
||||
1, data_cfg.frame_len, 3, data_cfg.image_size, data_cfg.image_size)
|
||||
1, data_cfg.frame_len, 3, data_cfg.image_height, data_cfg.image_width)
|
||||
dummy_history = torch.randn(1, data_cfg.history_len, data_cfg.action_dim)
|
||||
|
||||
batch = Dim("batch")
|
||||
|
||||
+12
-12
@@ -5,8 +5,8 @@
|
||||
HEF 由 actpred ONNX 经 Hailo DFC 编译生成(量化校准后)。本封装不硬编码
|
||||
vstream 名称/形状/量化参数,全部从 HEF 的 input/output vstream info 动态推导:
|
||||
|
||||
图像输入: (1, F, 3, S, S) → NHWC uint8 (1, F, S, S, 3)
|
||||
或 (1, S, S, F*3) → 帧沿通道拼接
|
||||
图像输入: (1, F, 3, H, W) → NHWC uint8 (1, F, H, W, 3)
|
||||
或 (1, H, W, F*3) → 帧沿通道拼接
|
||||
动作输入: (1, H, D) float32,uint8 边缘时按 quant_info 量化
|
||||
动作输出: (1, D),uint8 边缘时按 quant_info 反量化
|
||||
|
||||
@@ -111,15 +111,15 @@ class HailoPredictor:
|
||||
def _derive_dims(self):
|
||||
shape = tuple(self._image_info.shape)
|
||||
if len(shape) == 5:
|
||||
_, self.frame_len, c, self.image_size, _ = shape
|
||||
_, self.frame_len, c, self.image_height, self.image_width = shape
|
||||
if c != 3:
|
||||
raise ValueError(f"图像输入通道维应为 3,实际形状 {shape}")
|
||||
self._image_layout = "ncfhw"
|
||||
else: # (1, S, S, F*3) NHWC 帧拼通道
|
||||
_, self.image_size, s2, c = shape
|
||||
if s2 != self.image_size or c % 3 != 0 or c == 3:
|
||||
else: # (1, H, W, F*3) NHWC 帧拼通道
|
||||
_, self.image_height, self.image_width, c = shape
|
||||
if c % 3 != 0 or c == 3:
|
||||
raise ValueError(
|
||||
f"无法从 4 维图像输入推导帧数(期望 (1,S,S,F*3)),"
|
||||
f"无法从 4 维图像输入推导帧数(期望 (1,H,W,F*3)),"
|
||||
f"实际形状 {shape}")
|
||||
self.frame_len = c // 3
|
||||
self._image_layout = "nhwc_fused"
|
||||
@@ -206,15 +206,15 @@ class HailoPredictor:
|
||||
def _preprocess(self, image) -> np.ndarray:
|
||||
img = Image.fromarray(image) if isinstance(image, np.ndarray) else image
|
||||
img = img.convert("RGB").resize(
|
||||
(self.image_size, self.image_size), Image.BILINEAR)
|
||||
(self.image_width, self.image_height), Image.BILINEAR)
|
||||
return np.asarray(img, dtype=np.uint8) # HWC uint8
|
||||
|
||||
def _image_buffer(self, frames: np.ndarray) -> np.ndarray:
|
||||
"""(F, S, S, 3) → HEF 图像输入缓冲区(按编译后布局)"""
|
||||
"""(F, H, W, 3) → HEF 图像输入缓冲区(按编译后布局)"""
|
||||
if self._image_layout == "ncfhw":
|
||||
return frames.transpose(0, 3, 1, 2)[np.newaxis] # (1,F,3,S,S)
|
||||
# nhwc_fused: 帧沿通道拼接 (1, S, S, F*3)
|
||||
return frames.reshape(1, self.image_size, self.image_size,
|
||||
return frames.transpose(0, 3, 1, 2)[np.newaxis] # (1,F,3,H,W)
|
||||
# nhwc_fused: 帧沿通道拼接 (1, H, W, F*3)
|
||||
return frames.reshape(1, self.image_height, self.image_width,
|
||||
self.frame_len * 3)
|
||||
|
||||
|
||||
|
||||
+4
-3
@@ -127,14 +127,15 @@ class ActionPredictor(nn.Module):
|
||||
self._frame_len = data_cfg.frame_len
|
||||
self._history_len = data_cfg.history_len
|
||||
self._action_dim = data_cfg.action_dim
|
||||
self._image_size = data_cfg.image_size
|
||||
self._image_width = data_cfg.image_width
|
||||
self._image_height = data_cfg.image_height
|
||||
self._cnn_feature_dim = model_cfg.cnn_feature_dim
|
||||
|
||||
def forward(self, images: torch.Tensor, action_history: torch.Tensor) -> torch.Tensor:
|
||||
# images: (B, F, 3, S, S) action_history: (B, H, D)
|
||||
# images: (B, F, 3, H, W) action_history: (B, H_len, D)
|
||||
b = images.size(0)
|
||||
frames = images.reshape(
|
||||
b * self._frame_len, 3, self._image_size, self._image_size)
|
||||
b * self._frame_len, 3, self._image_height, self._image_width)
|
||||
img_feat = self.image_encoder(frames).reshape(
|
||||
b, self._frame_len, self._cnn_feature_dim)
|
||||
img_tokens = self.img_proj(img_feat)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
接口对齐 predict.ActionPredictorInference:predict(images, action_history)。
|
||||
|
||||
模型维度从 ONNX session 输入元数据动态推导(images: [1,F,3,S,S],
|
||||
模型维度从 ONNX session 输入元数据动态推导(images: [1,F,3,H,W],
|
||||
action_history: [1,H,D]),无需 checkpoint。
|
||||
图像预处理复现训练时的 dataset.py 流水线:Resize → /255 → ImageNet 归一化。
|
||||
|
||||
@@ -55,7 +55,7 @@ class OnnxPredictor:
|
||||
inputs = {i.name: [d if isinstance(d, int) else -1
|
||||
for d in i.shape] for i in self._session.get_inputs()}
|
||||
img_shape, hist_shape = self._locate_inputs(inputs)
|
||||
_, self.frame_len, _, self.image_size, _ = img_shape
|
||||
_, self.frame_len, _, self.image_height, self.image_width = img_shape
|
||||
_, self.history_len, self.action_dim = hist_shape
|
||||
self._image_name = next(n for n, s in inputs.items() if len(s) == 5)
|
||||
self._history_name = next(n for n, s in inputs.items() if len(s) == 3)
|
||||
@@ -82,9 +82,9 @@ class OnnxPredictor:
|
||||
raise ValueError(
|
||||
"ONNX 输入应为 1 个 5 维图像 + 1 个 3 维动作历史,"
|
||||
f"实际: {inputs}")
|
||||
if img[0][2] != 3 or img[0][3] != img[0][4]:
|
||||
if img[0][2] != 3:
|
||||
raise ValueError(
|
||||
f"图像输入形状应为 [1,F,3,S,S],实际为 {img[0]}")
|
||||
f"图像输入形状应为 [1,F,3,H,W],实际为 {img[0]}")
|
||||
return img[0], hist[0]
|
||||
|
||||
# ---------------- 生命周期 ----------------
|
||||
@@ -134,10 +134,10 @@ class OnnxPredictor:
|
||||
return result
|
||||
|
||||
def _preprocess(self, image) -> np.ndarray:
|
||||
"""Resize → /255 → ImageNet 归一化 → (3, S, S) float32"""
|
||||
"""Resize → /255 → ImageNet 归一化 → (3, H, W) float32"""
|
||||
img = Image.fromarray(image) if isinstance(image, np.ndarray) else image
|
||||
img = img.convert("RGB").resize(
|
||||
(self.image_size, self.image_size), Image.BILINEAR)
|
||||
(self.image_width, self.image_height), Image.BILINEAR)
|
||||
x = np.asarray(img, dtype=np.float32) / 255.0 # HWC
|
||||
x = x.transpose(2, 0, 1) # CHW
|
||||
return (x - IMAGENET_MEAN[:, None, None]) / IMAGENET_STD[:, None, None]
|
||||
|
||||
+2
-1
@@ -31,7 +31,8 @@ class ActionPredictorInference:
|
||||
self.frame_len = self._data_cfg.frame_len
|
||||
|
||||
self._transform = transforms.Compose([
|
||||
transforms.Resize((self._data_cfg.image_size, self._data_cfg.image_size)),
|
||||
transforms.Resize((self._data_cfg.image_height,
|
||||
self._data_cfg.image_width)),
|
||||
transforms.ToTensor(),
|
||||
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
|
||||
])
|
||||
|
||||
@@ -76,7 +76,8 @@ class MTActionDataset(Dataset):
|
||||
}
|
||||
|
||||
|
||||
def pretrain_one_epoch(model, loader, optimizer, device, image_size, frame_len,
|
||||
def pretrain_one_epoch(model, loader, optimizer, device, image_width,
|
||||
image_height, frame_len,
|
||||
max_grad_norm=None, noise_std=0.0):
|
||||
model.train()
|
||||
total_loss = 0.0
|
||||
@@ -90,7 +91,7 @@ def pretrain_one_epoch(model, loader, optimizer, device, image_size, frame_len,
|
||||
target = target + torch.randn_like(target) * noise_std
|
||||
if zero_images is None or zero_images.size(0) != history.size(0):
|
||||
zero_images = torch.zeros(
|
||||
history.size(0), frame_len, 3, image_size, image_size,
|
||||
history.size(0), frame_len, 3, image_height, image_width,
|
||||
device=device,
|
||||
)
|
||||
optimizer.zero_grad()
|
||||
@@ -106,7 +107,7 @@ def pretrain_one_epoch(model, loader, optimizer, device, image_size, frame_len,
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
def validate(model, loader, device, image_size, frame_len):
|
||||
def validate(model, loader, device, image_width, image_height, frame_len):
|
||||
model.eval()
|
||||
total_loss = 0.0
|
||||
count = 0
|
||||
@@ -116,7 +117,7 @@ def validate(model, loader, device, image_size, frame_len):
|
||||
target = batch["target"].to(device)
|
||||
if zero_images is None or zero_images.size(0) != history.size(0):
|
||||
zero_images = torch.zeros(
|
||||
history.size(0), frame_len, 3, image_size, image_size,
|
||||
history.size(0), frame_len, 3, image_height, image_width,
|
||||
device=device,
|
||||
)
|
||||
pred = model(zero_images, history)
|
||||
@@ -239,11 +240,12 @@ def main():
|
||||
f"lr={optimizer.param_groups[0]['lr']:.6f}")
|
||||
train_loss = pretrain_one_epoch(
|
||||
model, train_loader, optimizer, device,
|
||||
cfg.data.image_size, cfg.data.frame_len,
|
||||
cfg.data.image_width, cfg.data.image_height, cfg.data.frame_len,
|
||||
cfg.train.max_grad_norm, args.noise_std,
|
||||
)
|
||||
val_loss = validate(model, val_loader, device,
|
||||
cfg.data.image_size, cfg.data.frame_len)
|
||||
cfg.data.image_width, cfg.data.image_height,
|
||||
cfg.data.frame_len)
|
||||
scheduler.step()
|
||||
print(f" train_loss={train_loss:.6f} val_loss={val_loss:.6f}")
|
||||
|
||||
|
||||
+22
-16
@@ -84,7 +84,7 @@ class TestActionPredictor(unittest.TestCase):
|
||||
"""测试多帧注意力模型前向传播"""
|
||||
|
||||
def test_forward_multi_frame(self):
|
||||
data_cfg = DataConfig(image_size=64, action_dim=18, history_len=5, frame_len=3)
|
||||
data_cfg = DataConfig(image_width=64, image_height=64, action_dim=18, history_len=5, frame_len=3)
|
||||
model_cfg = ModelConfig(cnn_backbone="simple")
|
||||
model = ActionPredictor(model_cfg, data_cfg)
|
||||
model.eval()
|
||||
@@ -97,7 +97,7 @@ class TestActionPredictor(unittest.TestCase):
|
||||
|
||||
def test_forward_single_frame_degenerate(self):
|
||||
"""frame_len=1 退化为单帧输入也应正常前向"""
|
||||
data_cfg = DataConfig(image_size=32, action_dim=4, history_len=3, frame_len=1)
|
||||
data_cfg = DataConfig(image_width=32, image_height=32, action_dim=4, history_len=3, frame_len=1)
|
||||
model_cfg = ModelConfig(cnn_backbone="simple")
|
||||
model = ActionPredictor(model_cfg, data_cfg)
|
||||
model.eval()
|
||||
@@ -109,7 +109,7 @@ class TestActionPredictor(unittest.TestCase):
|
||||
self.assertEqual(out.shape, (2, 4))
|
||||
|
||||
def test_forward_dynamic_batch(self):
|
||||
data_cfg = DataConfig(image_size=32, action_dim=4, history_len=3, frame_len=2)
|
||||
data_cfg = DataConfig(image_width=32, image_height=32, action_dim=4, history_len=3, frame_len=2)
|
||||
model_cfg = ModelConfig(cnn_backbone="simple")
|
||||
model = ActionPredictor(model_cfg, data_cfg)
|
||||
model.eval()
|
||||
@@ -123,7 +123,7 @@ class TestActionPredictor(unittest.TestCase):
|
||||
|
||||
def test_custom_attn_config(self):
|
||||
"""自定义 attn_dim/heads/layers 应可构建并前向"""
|
||||
data_cfg = DataConfig(image_size=32, action_dim=4, history_len=3, frame_len=2)
|
||||
data_cfg = DataConfig(image_width=32, image_height=32, action_dim=4, history_len=3, frame_len=2)
|
||||
model_cfg = ModelConfig(attn_dim=64, attn_heads=2, attn_layers=1)
|
||||
model = ActionPredictor(model_cfg, data_cfg)
|
||||
model.eval()
|
||||
@@ -183,7 +183,8 @@ class TestActionDataset(unittest.TestCase):
|
||||
def test_dataset_loading(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
self._create_dummy_episode(Path(tmpdir), n_frames=10, action_dim=4)
|
||||
ds = ActionDataset(tmpdir, history_len=3, action_dim=4, image_size=32,
|
||||
ds = ActionDataset(tmpdir, history_len=3, action_dim=4,
|
||||
image_width=32, image_height=32,
|
||||
frame_len=3)
|
||||
# 采样起点 max(history_len, frame_len-1) = 3 → 10 - 3 = 7 samples
|
||||
self.assertEqual(len(ds), 7)
|
||||
@@ -200,7 +201,8 @@ class TestActionDataset(unittest.TestCase):
|
||||
"""frame_len-1 > history_len 时采样起点由帧窗口决定"""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
self._create_dummy_episode(Path(tmpdir), n_frames=10, action_dim=4)
|
||||
ds = ActionDataset(tmpdir, history_len=3, action_dim=4, image_size=32,
|
||||
ds = ActionDataset(tmpdir, history_len=3, action_dim=4,
|
||||
image_width=32, image_height=32,
|
||||
frame_len=6)
|
||||
# 起点 max(3, 5) = 5 → 10 - 5 = 5 samples
|
||||
self.assertEqual(len(ds), 5)
|
||||
@@ -265,7 +267,8 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
def test_default_config(self):
|
||||
cfg = Config()
|
||||
self.assertEqual(cfg.data.image_size, 224)
|
||||
self.assertEqual(cfg.data.image_width, 1920)
|
||||
self.assertEqual(cfg.data.image_height, 1080)
|
||||
self.assertEqual(cfg.data.action_dim, 18)
|
||||
self.assertEqual(cfg.data.history_len, 5)
|
||||
self.assertEqual(cfg.data.frame_len, 3)
|
||||
@@ -480,7 +483,8 @@ class TestValidateConfigValues(unittest.TestCase):
|
||||
validate_config_values(cfg.data, cfg.model) # 不应抛异常
|
||||
|
||||
def test_out_of_range_or_non_int_raises(self):
|
||||
for field, value in [("image_size", 99999), ("image_size", 0),
|
||||
for field, value in [("image_width", 99999), ("image_width", 0),
|
||||
("image_height", 0),
|
||||
("history_len", -1), ("frame_len", 0),
|
||||
("frame_len", 99999), ("action_dim", "18")]:
|
||||
cfg = Config()
|
||||
@@ -601,10 +605,11 @@ class TestActionPredictorInference(unittest.TestCase):
|
||||
"""测试推理封装端到端:checkpoint 保存 → 加载 → 推理"""
|
||||
|
||||
@staticmethod
|
||||
def _make_checkpoint(tmpdir, normalize_actions=False, image_size=32,
|
||||
frame_len=3):
|
||||
def _make_checkpoint(tmpdir, normalize_actions=False, image_width=32,
|
||||
image_height=32, frame_len=3):
|
||||
cfg = Config()
|
||||
cfg.data.image_size = image_size
|
||||
cfg.data.image_width = image_width
|
||||
cfg.data.image_height = image_height
|
||||
cfg.data.action_dim = 4
|
||||
cfg.data.history_len = 3
|
||||
cfg.data.frame_len = frame_len
|
||||
@@ -707,11 +712,11 @@ class TestActionPredictorInference(unittest.TestCase):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
path, model, cfg = self._make_checkpoint(tmpdir)
|
||||
cfg_dict = cfg.to_dict()
|
||||
cfg_dict["data"]["image_size"] = 99999
|
||||
cfg_dict["data"]["image_width"] = 99999
|
||||
bad_path = os.path.join(tmpdir, "bad.pt")
|
||||
torch.save({"model_state_dict": model.state_dict(),
|
||||
"config": cfg_dict}, bad_path)
|
||||
with self.assertRaisesRegex(ValueError, "image_size"):
|
||||
with self.assertRaisesRegex(ValueError, "image_width"):
|
||||
ActionPredictorInference(bad_path, device="cpu")
|
||||
|
||||
def test_unknown_config_key_in_checkpoint_raises(self):
|
||||
@@ -820,7 +825,8 @@ class TestOnnxPredictor(unittest.TestCase):
|
||||
@staticmethod
|
||||
def _export_small_onnx(tmpdir):
|
||||
cfg = Config()
|
||||
cfg.data.image_size = 32
|
||||
cfg.data.image_width = 32
|
||||
cfg.data.image_height = 32
|
||||
cfg.data.action_dim = 4
|
||||
cfg.data.history_len = 3
|
||||
cfg.data.frame_len = 3
|
||||
@@ -847,7 +853,7 @@ class TestOnnxPredictor(unittest.TestCase):
|
||||
with OnnxPredictor(path) as p:
|
||||
self.assertEqual((p.frame_len, p.history_len, p.action_dim),
|
||||
(3, 3, 4))
|
||||
self.assertEqual(p.image_size, 32)
|
||||
self.assertEqual((p.image_width, p.image_height), (32, 32))
|
||||
|
||||
def test_matches_torch_forward(self):
|
||||
from onnx_infer import OnnxPredictor
|
||||
@@ -1043,7 +1049,7 @@ class TestHailoPredictor(unittest.TestCase):
|
||||
history = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
|
||||
with HailoPredictor("fake.hef") as p:
|
||||
self.assertEqual((p.frame_len, p.history_len, p.action_dim), (2, 2, 3))
|
||||
self.assertEqual(p.image_size, 4)
|
||||
self.assertEqual((p.image_width, p.image_height), (4, 4))
|
||||
result = p.predict(self._frames(2), history)
|
||||
np.testing.assert_allclose(result, [1, 2, 3])
|
||||
self.assertEqual(seen_shapes["image"], (1, 2, 3, 4, 4))
|
||||
|
||||
+2
-2
@@ -82,7 +82,7 @@ def main():
|
||||
|
||||
train_ds = ActionDataset(
|
||||
cfg.data.data_dir, cfg.data.history_len, cfg.data.action_dim,
|
||||
cfg.data.image_size, cfg.data.normalize_actions,
|
||||
cfg.data.image_width, cfg.data.image_height, cfg.data.normalize_actions,
|
||||
cfg.data.action_stats_path, train_indices, cfg.data.frame_len)
|
||||
if cfg.data.normalize_actions and not cfg.data.action_stats_path:
|
||||
# 归一化统计量必须只用训练集计算,再供验证集复用,否则 val loss 不可信
|
||||
@@ -92,7 +92,7 @@ def main():
|
||||
cfg.data.action_stats_path = stats_path
|
||||
val_ds = ActionDataset(
|
||||
cfg.data.data_dir, cfg.data.history_len, cfg.data.action_dim,
|
||||
cfg.data.image_size, cfg.data.normalize_actions,
|
||||
cfg.data.image_width, cfg.data.image_height, cfg.data.normalize_actions,
|
||||
cfg.data.action_stats_path, val_indices, cfg.data.frame_len)
|
||||
|
||||
print(f"Samples: {len(train_ds)} train, {len(val_ds)} val")
|
||||
|
||||
Reference in new issue
Block a user