tianma commited on
Commit ·
3482727
1
Parent(s): bed503a
Support optional fixed eval_size and update detection configs.
Browse filesAdd Resize(eval_size) for TAIC eval with correct COCO box scale_factor; sync README and local detection train/eval settings.
- README.md +9 -13
- configs/eval/taic_detection.yaml +3 -1
- configs/taic/detection.yaml +4 -4
- flexicm/data/datasets.py +10 -2
- flexicm/tasks/metric_eval.py +7 -0
- flexicm/tasks/metric_runners.py +7 -2
- scripts/eval_taic.py +13 -3
- scripts/train_taic.py +1 -1
README.md
CHANGED
|
@@ -363,11 +363,7 @@ For C-TAIC, reported `bpp` is **extension-layer only** (base-layer rate is exclu
|
|
| 363 |
|
| 364 |
```bash
|
| 365 |
python scripts/eval_taic.py -c configs/eval/taic_detection.yaml
|
| 366 |
-
python scripts/eval_taic.py -c configs/eval/taic_detection.yaml --actual-bpp
|
| 367 |
-
python scripts/eval_taic.py -c configs/eval/taic_detection.yaml --max-batches 10
|
| 368 |
-
|
| 369 |
python scripts/eval_ctaic.py -c configs/eval/ctaic_s1.yaml
|
| 370 |
-
python scripts/eval_ctaic.py -c configs/eval/ctaic_s1.yaml --no-condition
|
| 371 |
```
|
| 372 |
|
| 373 |
---
|
|
@@ -431,15 +427,15 @@ ann_file: "annotations/instances_val2017.json"
|
|
| 431 |
### Run codec + metrics
|
| 432 |
|
| 433 |
```bash
|
| 434 |
-
python scripts/eval_taic.py -c configs/eval/taic_detection.yaml
|
| 435 |
-
python scripts/eval_taic.py -c configs/eval/taic_instance.yaml
|
| 436 |
-
python scripts/eval_taic.py -c configs/eval/taic_semantic.yaml
|
| 437 |
-
python scripts/eval_taic.py -c configs/eval/taic_panoptic.yaml
|
| 438 |
-
python scripts/eval_taic.py -c configs/eval/taic_pose.yaml
|
| 439 |
-
|
| 440 |
-
python scripts/eval_ctaic.py -c configs/eval/ctaic_s1.yaml
|
| 441 |
-
python scripts/eval_ctaic.py -c configs/eval/ctaic_s2.yaml
|
| 442 |
-
python scripts/eval_ctaic.py -c configs/eval/ctaic_s3.yaml
|
| 443 |
```
|
| 444 |
|
| 445 |
JSON results (codec + task metrics) are written under `logs/eval_taic/` or `logs/eval_ctaic/`.
|
|
|
|
| 363 |
|
| 364 |
```bash
|
| 365 |
python scripts/eval_taic.py -c configs/eval/taic_detection.yaml
|
|
|
|
|
|
|
|
|
|
| 366 |
python scripts/eval_ctaic.py -c configs/eval/ctaic_s1.yaml
|
|
|
|
| 367 |
```
|
| 368 |
|
| 369 |
---
|
|
|
|
| 427 |
### Run codec + metrics
|
| 428 |
|
| 429 |
```bash
|
| 430 |
+
python scripts/eval_taic.py -c configs/eval/taic_detection.yaml
|
| 431 |
+
python scripts/eval_taic.py -c configs/eval/taic_instance.yaml
|
| 432 |
+
python scripts/eval_taic.py -c configs/eval/taic_semantic.yaml
|
| 433 |
+
python scripts/eval_taic.py -c configs/eval/taic_panoptic.yaml
|
| 434 |
+
python scripts/eval_taic.py -c configs/eval/taic_pose.yaml
|
| 435 |
+
|
| 436 |
+
python scripts/eval_ctaic.py -c configs/eval/ctaic_s1.yaml
|
| 437 |
+
python scripts/eval_ctaic.py -c configs/eval/ctaic_s2.yaml
|
| 438 |
+
python scripts/eval_ctaic.py -c configs/eval/ctaic_s3.yaml
|
| 439 |
```
|
| 440 |
|
| 441 |
JSON results (codec + task metrics) are written under `logs/eval_taic/` or `logs/eval_ctaic/`.
|
configs/eval/taic_detection.yaml
CHANGED
|
@@ -5,8 +5,10 @@ split: "val2017"
|
|
| 5 |
ann_file: "annotations/instances_val2017.json"
|
| 6 |
quality_level: 1
|
| 7 |
lmbda: 0.0035
|
| 8 |
-
checkpoint: "./logs/taic_detection/1/checkpoint_0.
|
| 9 |
base_codec: "./checkpoints/base_codec/base_codec_1.pth.tar"
|
|
|
|
|
|
|
| 10 |
# official task network (required for --with-metrics)
|
| 11 |
gpu_id: 0
|
| 12 |
cuda: true
|
|
|
|
| 5 |
ann_file: "annotations/instances_val2017.json"
|
| 6 |
quality_level: 1
|
| 7 |
lmbda: 0.0035
|
| 8 |
+
checkpoint: "./logs/taic_detection/1/checkpoint_0.1334.pth.tar"
|
| 9 |
base_codec: "./checkpoints/base_codec/base_codec_1.pth.tar"
|
| 10 |
+
# null = original COCO resolution; 256 = force 256x256 (aspect stretched)
|
| 11 |
+
eval_size: null
|
| 12 |
# official task network (required for --with-metrics)
|
| 13 |
gpu_id: 0
|
| 14 |
cuda: true
|
configs/taic/detection.yaml
CHANGED
|
@@ -4,18 +4,18 @@ exp_name: "taic_detection"
|
|
| 4 |
task: "detection"
|
| 5 |
dataset_path: "/data/Dataset/coco2017"
|
| 6 |
base_codec: "./checkpoints/base_codec/base_codec_1.pth.tar" # quality matches lmbda mapping
|
| 7 |
-
checkpoint:
|
| 8 |
freeze_base_codec: false # false = fine-tune the entire TIC + SFMA + Task Connector
|
| 9 |
epochs: 999
|
| 10 |
learning_rate: 1.0e-4
|
| 11 |
gpu_id: 0
|
| 12 |
quality_level: 1
|
| 13 |
-
# paper lambda set: {0.0035, 0.0067, 0.0130, 0.0250}
|
| 14 |
lmbda: 0.2050
|
| 15 |
num_workers: 8
|
| 16 |
-
batch_size:
|
| 17 |
test_batch_size: 1
|
| 18 |
-
patch_size:
|
| 19 |
cuda: true
|
| 20 |
save: true
|
| 21 |
seed: 42
|
|
|
|
| 4 |
task: "detection"
|
| 5 |
dataset_path: "/data/Dataset/coco2017"
|
| 6 |
base_codec: "./checkpoints/base_codec/base_codec_1.pth.tar" # quality matches lmbda mapping
|
| 7 |
+
checkpoint: "/data/Dataset/FlexICM/logs/taic_detection/1/checkpoint_best_loss.pth.tar"
|
| 8 |
freeze_base_codec: false # false = fine-tune the entire TIC + SFMA + Task Connector
|
| 9 |
epochs: 999
|
| 10 |
learning_rate: 1.0e-4
|
| 11 |
gpu_id: 0
|
| 12 |
quality_level: 1
|
| 13 |
+
# paper lambda set: {0.0035, 0.0067, 0.0130, 0.0250, 0.2050}
|
| 14 |
lmbda: 0.2050
|
| 15 |
num_workers: 8
|
| 16 |
+
batch_size: 8
|
| 17 |
test_batch_size: 1
|
| 18 |
+
patch_size: 512
|
| 19 |
cuda: true
|
| 20 |
save: true
|
| 21 |
seed: 42
|
flexicm/data/datasets.py
CHANGED
|
@@ -28,8 +28,16 @@ def build_train_transform(patch_size: int = 256) -> Callable:
|
|
| 28 |
)
|
| 29 |
|
| 30 |
|
| 31 |
-
def build_test_transform() -> Callable:
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
|
| 35 |
class ImageFolderDataset(Dataset):
|
|
|
|
| 28 |
)
|
| 29 |
|
| 30 |
|
| 31 |
+
def build_test_transform(eval_size: Optional[int] = None) -> Callable:
|
| 32 |
+
"""Eval preprocess. If ``eval_size`` is set (e.g. 256), force HxW = size×size."""
|
| 33 |
+
if eval_size is None:
|
| 34 |
+
return transforms.ToTensor()
|
| 35 |
+
return transforms.Compose(
|
| 36 |
+
[
|
| 37 |
+
transforms.Resize((int(eval_size), int(eval_size))),
|
| 38 |
+
transforms.ToTensor(),
|
| 39 |
+
]
|
| 40 |
+
)
|
| 41 |
|
| 42 |
|
| 43 |
class ImageFolderDataset(Dataset):
|
flexicm/tasks/metric_eval.py
CHANGED
|
@@ -55,6 +55,12 @@ def run_task_metric_eval(
|
|
| 55 |
for image, meta in zip(images_list, metas):
|
| 56 |
image = image.unsqueeze(0).to(device)
|
| 57 |
_, _, H, W = image.shape
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
x, _ = pad_for_codec(image, divisor=align_divisor, device=device)
|
| 59 |
|
| 60 |
y_b = None
|
|
@@ -77,6 +83,7 @@ def run_task_metric_eval(
|
|
| 77 |
meta = dict(meta)
|
| 78 |
meta["pad_height"] = int(x.shape[-2])
|
| 79 |
meta["pad_width"] = int(x.shape[-1])
|
|
|
|
| 80 |
pred = runner.predict_from_h(h, meta)
|
| 81 |
predictions.append(pred)
|
| 82 |
|
|
|
|
| 55 |
for image, meta in zip(images_list, metas):
|
| 56 |
image = image.unsqueeze(0).to(device)
|
| 57 |
_, _, H, W = image.shape
|
| 58 |
+
ori_h = int(meta["height"])
|
| 59 |
+
ori_w = int(meta["width"])
|
| 60 |
+
# If the image was resized (e.g. eval_size=256), boxes must be
|
| 61 |
+
# mapped back with the correct scale_factor for COCO mAP.
|
| 62 |
+
scale_w = float(W) / float(ori_w) if ori_w > 0 else 1.0
|
| 63 |
+
scale_h = float(H) / float(ori_h) if ori_h > 0 else 1.0
|
| 64 |
x, _ = pad_for_codec(image, divisor=align_divisor, device=device)
|
| 65 |
|
| 66 |
y_b = None
|
|
|
|
| 83 |
meta = dict(meta)
|
| 84 |
meta["pad_height"] = int(x.shape[-2])
|
| 85 |
meta["pad_width"] = int(x.shape[-1])
|
| 86 |
+
meta["scale_factor"] = (scale_w, scale_h)
|
| 87 |
pred = runner.predict_from_h(h, meta)
|
| 88 |
predictions.append(pred)
|
| 89 |
|
flexicm/tasks/metric_runners.py
CHANGED
|
@@ -204,6 +204,11 @@ class DetectionMetricRunner(TaskMetricRunner):
|
|
| 204 |
# FPN strides line up; boxes are rescaled back to ori_shape.
|
| 205 |
pad_h = int(img_meta.get("pad_height", h.shape[-2] * 4))
|
| 206 |
pad_w = int(img_meta.get("pad_width", h.shape[-1] * 4))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
try:
|
| 208 |
# MMDet 3.x style
|
| 209 |
from mmdet.structures import DetDataSample
|
|
@@ -214,7 +219,7 @@ class DetectionMetricRunner(TaskMetricRunner):
|
|
| 214 |
img_shape=(pad_h, pad_w),
|
| 215 |
ori_shape=(ori_h, ori_w),
|
| 216 |
pad_shape=(pad_h, pad_w),
|
| 217 |
-
scale_factor=
|
| 218 |
img_id=img_meta.get("image_id"),
|
| 219 |
)
|
| 220 |
)
|
|
@@ -241,7 +246,7 @@ class DetectionMetricRunner(TaskMetricRunner):
|
|
| 241 |
img_shape=(pad_h, pad_w, 3),
|
| 242 |
ori_shape=(ori_h, ori_w, 3),
|
| 243 |
pad_shape=(pad_h, pad_w, 3),
|
| 244 |
-
scale_factor=
|
| 245 |
flip=False,
|
| 246 |
)
|
| 247 |
]
|
|
|
|
| 204 |
# FPN strides line up; boxes are rescaled back to ori_shape.
|
| 205 |
pad_h = int(img_meta.get("pad_height", h.shape[-2] * 4))
|
| 206 |
pad_w = int(img_meta.get("pad_width", h.shape[-1] * 4))
|
| 207 |
+
sf = img_meta.get("scale_factor", (1.0, 1.0))
|
| 208 |
+
if isinstance(sf, (int, float)):
|
| 209 |
+
scale_factor = (float(sf), float(sf))
|
| 210 |
+
else:
|
| 211 |
+
scale_factor = (float(sf[0]), float(sf[1]))
|
| 212 |
try:
|
| 213 |
# MMDet 3.x style
|
| 214 |
from mmdet.structures import DetDataSample
|
|
|
|
| 219 |
img_shape=(pad_h, pad_w),
|
| 220 |
ori_shape=(ori_h, ori_w),
|
| 221 |
pad_shape=(pad_h, pad_w),
|
| 222 |
+
scale_factor=scale_factor,
|
| 223 |
img_id=img_meta.get("image_id"),
|
| 224 |
)
|
| 225 |
)
|
|
|
|
| 246 |
img_shape=(pad_h, pad_w, 3),
|
| 247 |
ori_shape=(ori_h, ori_w, 3),
|
| 248 |
pad_shape=(pad_h, pad_w, 3),
|
| 249 |
+
scale_factor=scale_factor,
|
| 250 |
flip=False,
|
| 251 |
)
|
| 252 |
]
|
scripts/eval_taic.py
CHANGED
|
@@ -65,6 +65,12 @@ def parse_args(argv):
|
|
| 65 |
parser.add_argument("--with-metrics", action="store_true", help="Run full task-network metrics")
|
| 66 |
parser.add_argument("--max-batches", type=int, default=None)
|
| 67 |
parser.add_argument("--split", type=str, default=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
args = parser.parse_args(remaining)
|
| 69 |
args.config = cfg_path
|
| 70 |
if "--actual-bpp" in argv:
|
|
@@ -76,7 +82,8 @@ def parse_args(argv):
|
|
| 76 |
|
| 77 |
def build_codec_loader(args, device):
|
| 78 |
split = args.split or getattr(args, "split", None) or "val2017"
|
| 79 |
-
|
|
|
|
| 80 |
root = args.dataset_path
|
| 81 |
split_dir = os.path.join(root, split)
|
| 82 |
if os.path.isdir(split_dir):
|
|
@@ -101,11 +108,12 @@ def build_metric_loader(args, device):
|
|
| 101 |
if ann_rel is None:
|
| 102 |
raise ValueError(f"No ann_file for task={args.task}")
|
| 103 |
ann_file = ann_rel if os.path.isabs(ann_rel) else os.path.join(args.dataset_path, ann_rel)
|
|
|
|
| 104 |
dataset = COCOEvalDataset(
|
| 105 |
args.dataset_path,
|
| 106 |
ann_file=ann_file,
|
| 107 |
image_prefix=split,
|
| 108 |
-
transform=build_test_transform(),
|
| 109 |
)
|
| 110 |
loader = DataLoader(
|
| 111 |
dataset,
|
|
@@ -152,7 +160,9 @@ def main(argv):
|
|
| 152 |
teacher = teacher.to(device).eval()
|
| 153 |
criterion = TAICCriterion(lmbda=lmbda, align_mode=align_mode)
|
| 154 |
codec_loader = build_codec_loader(args, device)
|
| 155 |
-
|
|
|
|
|
|
|
| 156 |
|
| 157 |
codec_result = test_taic_loader(
|
| 158 |
net,
|
|
|
|
| 65 |
parser.add_argument("--with-metrics", action="store_true", help="Run full task-network metrics")
|
| 66 |
parser.add_argument("--max-batches", type=int, default=None)
|
| 67 |
parser.add_argument("--split", type=str, default=None)
|
| 68 |
+
parser.add_argument(
|
| 69 |
+
"--eval-size",
|
| 70 |
+
type=int,
|
| 71 |
+
default=cfg.get("eval_size", None),
|
| 72 |
+
help="If set (e.g. 256), resize eval images to eval_size×eval_size",
|
| 73 |
+
)
|
| 74 |
args = parser.parse_args(remaining)
|
| 75 |
args.config = cfg_path
|
| 76 |
if "--actual-bpp" in argv:
|
|
|
|
| 82 |
|
| 83 |
def build_codec_loader(args, device):
|
| 84 |
split = args.split or getattr(args, "split", None) or "val2017"
|
| 85 |
+
eval_size = getattr(args, "eval_size", None)
|
| 86 |
+
tf = build_test_transform(eval_size=eval_size)
|
| 87 |
root = args.dataset_path
|
| 88 |
split_dir = os.path.join(root, split)
|
| 89 |
if os.path.isdir(split_dir):
|
|
|
|
| 108 |
if ann_rel is None:
|
| 109 |
raise ValueError(f"No ann_file for task={args.task}")
|
| 110 |
ann_file = ann_rel if os.path.isabs(ann_rel) else os.path.join(args.dataset_path, ann_rel)
|
| 111 |
+
eval_size = getattr(args, "eval_size", None)
|
| 112 |
dataset = COCOEvalDataset(
|
| 113 |
args.dataset_path,
|
| 114 |
ann_file=ann_file,
|
| 115 |
image_prefix=split,
|
| 116 |
+
transform=build_test_transform(eval_size=eval_size),
|
| 117 |
)
|
| 118 |
loader = DataLoader(
|
| 119 |
dataset,
|
|
|
|
| 160 |
teacher = teacher.to(device).eval()
|
| 161 |
criterion = TAICCriterion(lmbda=lmbda, align_mode=align_mode)
|
| 162 |
codec_loader = build_codec_loader(args, device)
|
| 163 |
+
eval_size = getattr(args, "eval_size", None)
|
| 164 |
+
size_msg = f"{eval_size}x{eval_size}" if eval_size else "original"
|
| 165 |
+
print(f"[codec] test set size: {len(codec_loader.dataset)} device={device} task={task} input={size_msg}")
|
| 166 |
|
| 167 |
codec_result = test_taic_loader(
|
| 168 |
net,
|
scripts/train_taic.py
CHANGED
|
@@ -210,7 +210,7 @@ def main(argv):
|
|
| 210 |
for epoch in range(args.epochs):
|
| 211 |
logging.info(f"===== Epoch {epoch}/{args.epochs} =====")
|
| 212 |
train_stats = train_one_epoch(net, teacher, train_loader, optimizer, criterion, device)
|
| 213 |
-
if epoch %
|
| 214 |
val_stats = validate(net, teacher, val_loader, criterion, device)
|
| 215 |
logging.info(f"train={train_stats} val={val_stats}")
|
| 216 |
is_best = val_stats["loss"] < best
|
|
|
|
| 210 |
for epoch in range(args.epochs):
|
| 211 |
logging.info(f"===== Epoch {epoch}/{args.epochs} =====")
|
| 212 |
train_stats = train_one_epoch(net, teacher, train_loader, optimizer, criterion, device)
|
| 213 |
+
if epoch % 2 == 0:
|
| 214 |
val_stats = validate(net, teacher, val_loader, criterion, device)
|
| 215 |
logging.info(f"train={train_stats} val={val_stats}")
|
| 216 |
is_best = val_stats["loss"] < best
|