Add proxy eval and skeleton experiment tooling
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
coco18tococo17_args:
|
||||||
|
transfer_to_coco17: False
|
||||||
|
|
||||||
|
padkeypoints_args:
|
||||||
|
pad_method: knn
|
||||||
|
use_conf: True
|
||||||
|
|
||||||
|
norm_args:
|
||||||
|
pose_format: coco
|
||||||
|
use_conf: ${padkeypoints_args.use_conf}
|
||||||
|
heatmap_image_height: 128
|
||||||
|
|
||||||
|
heatmap_generator_args:
|
||||||
|
sigma: 1.5
|
||||||
|
use_score: ${padkeypoints_args.use_conf}
|
||||||
|
img_h: ${norm_args.heatmap_image_height}
|
||||||
|
img_w: ${norm_args.heatmap_image_height}
|
||||||
|
with_limb: null
|
||||||
|
with_kp: null
|
||||||
|
|
||||||
|
sigma_limb: 1.5
|
||||||
|
sigma_joint: 8.0
|
||||||
|
|
||||||
|
align_args:
|
||||||
|
align: True
|
||||||
|
final_img_size: 64
|
||||||
|
offset: 0
|
||||||
|
heatmap_image_size: ${norm_args.heatmap_image_height}
|
||||||
|
crop_mode: bbox_pad
|
||||||
|
preserve_aspect_ratio: True
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
coco18tococo17_args:
|
||||||
|
transfer_to_coco17: False
|
||||||
|
|
||||||
|
padkeypoints_args:
|
||||||
|
pad_method: knn
|
||||||
|
use_conf: True
|
||||||
|
|
||||||
|
norm_args:
|
||||||
|
pose_format: coco
|
||||||
|
use_conf: ${padkeypoints_args.use_conf}
|
||||||
|
heatmap_image_height: 128
|
||||||
|
|
||||||
|
heatmap_generator_args:
|
||||||
|
sigma: 1.5
|
||||||
|
use_score: ${padkeypoints_args.use_conf}
|
||||||
|
img_h: ${norm_args.heatmap_image_height}
|
||||||
|
img_w: ${norm_args.heatmap_image_height}
|
||||||
|
with_limb: null
|
||||||
|
with_kp: null
|
||||||
|
|
||||||
|
sigma_limb: 1.5
|
||||||
|
sigma_joint: 8.0
|
||||||
|
channel_gain_limb: 4.0
|
||||||
|
channel_gain_joint: 1.0
|
||||||
|
|
||||||
|
align_args:
|
||||||
|
align: True
|
||||||
|
final_img_size: 64
|
||||||
|
offset: 0
|
||||||
|
heatmap_image_size: ${norm_args.heatmap_image_height}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
coco18tococo17_args:
|
||||||
|
transfer_to_coco17: False
|
||||||
|
|
||||||
|
padkeypoints_args:
|
||||||
|
pad_method: knn
|
||||||
|
use_conf: True
|
||||||
|
|
||||||
|
norm_args:
|
||||||
|
pose_format: coco
|
||||||
|
use_conf: ${padkeypoints_args.use_conf}
|
||||||
|
heatmap_image_height: 128
|
||||||
|
|
||||||
|
heatmap_generator_args:
|
||||||
|
sigma: 1.5
|
||||||
|
use_score: ${padkeypoints_args.use_conf}
|
||||||
|
img_h: ${norm_args.heatmap_image_height}
|
||||||
|
img_w: ${norm_args.heatmap_image_height}
|
||||||
|
with_limb: null
|
||||||
|
with_kp: null
|
||||||
|
|
||||||
|
sigma_limb: 1.5
|
||||||
|
sigma_joint: 8.0
|
||||||
|
|
||||||
|
align_args:
|
||||||
|
align: True
|
||||||
|
final_img_size: 64
|
||||||
|
offset: 0
|
||||||
|
heatmap_image_size: ${norm_args.heatmap_image_height}
|
||||||
|
scope: sequence
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
data_cfg:
|
||||||
|
dataset_name: Scoliosis1K
|
||||||
|
dataset_root: /mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-geomfix
|
||||||
|
dataset_partition: ./datasets/Scoliosis1K/Scoliosis1K_118.json
|
||||||
|
data_in_use:
|
||||||
|
- true
|
||||||
|
- false
|
||||||
|
num_workers: 1
|
||||||
|
remove_no_gallery: false
|
||||||
|
test_dataset_name: Scoliosis1K
|
||||||
|
test_seq_subset_size: 128
|
||||||
|
test_seq_subset_seed: 118
|
||||||
|
|
||||||
|
evaluator_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 2000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_geomfix_proxy_1gpu
|
||||||
|
eval_func: evaluate_scoliosis
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: false
|
||||||
|
batch_size: 1
|
||||||
|
sample_type: all_ordered
|
||||||
|
type: InferenceSampler
|
||||||
|
frames_all_limit: 720
|
||||||
|
metric: euc
|
||||||
|
transform:
|
||||||
|
- type: BaseSilTransform
|
||||||
|
|
||||||
|
loss_cfg:
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
margin: 0.2
|
||||||
|
type: TripletLoss
|
||||||
|
log_prefix: triplet
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
scale: 16
|
||||||
|
type: CrossEntropyLoss
|
||||||
|
log_prefix: softmax
|
||||||
|
log_accuracy: true
|
||||||
|
|
||||||
|
model_cfg:
|
||||||
|
model: ScoNet
|
||||||
|
backbone_cfg:
|
||||||
|
type: ResNet9
|
||||||
|
block: BasicBlock
|
||||||
|
in_channel: 2
|
||||||
|
channels:
|
||||||
|
- 64
|
||||||
|
- 128
|
||||||
|
- 256
|
||||||
|
- 512
|
||||||
|
layers:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
strides:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 2
|
||||||
|
- 1
|
||||||
|
maxpool: false
|
||||||
|
SeparateFCs:
|
||||||
|
in_channels: 512
|
||||||
|
out_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
SeparateBNNecks:
|
||||||
|
class_num: 3
|
||||||
|
in_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
bin_num:
|
||||||
|
- 16
|
||||||
|
|
||||||
|
optimizer_cfg:
|
||||||
|
lr: 0.001
|
||||||
|
solver: AdamW
|
||||||
|
weight_decay: 0.0005
|
||||||
|
|
||||||
|
scheduler_cfg:
|
||||||
|
gamma: 0.1
|
||||||
|
milestones:
|
||||||
|
- 1000
|
||||||
|
- 1500
|
||||||
|
- 1800
|
||||||
|
scheduler: MultiStepLR
|
||||||
|
|
||||||
|
trainer_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
fix_BN: false
|
||||||
|
with_test: true
|
||||||
|
log_iter: 100
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 0
|
||||||
|
auto_resume_latest: true
|
||||||
|
resume_every_iter: 500
|
||||||
|
resume_keep: 3
|
||||||
|
eval_iter: 500
|
||||||
|
save_iter: 2000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_geomfix_proxy_1gpu
|
||||||
|
sync_BN: true
|
||||||
|
total_iter: 2000
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: true
|
||||||
|
batch_size:
|
||||||
|
- 8
|
||||||
|
- 8
|
||||||
|
frames_num_fixed: 30
|
||||||
|
sample_type: fixed_unordered
|
||||||
|
type: TripletSampler
|
||||||
|
transform:
|
||||||
|
- type: BaseSilTransform
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
data_cfg:
|
||||||
|
dataset_name: Scoliosis1K
|
||||||
|
dataset_root: /mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign-limb4
|
||||||
|
dataset_partition: ./datasets/Scoliosis1K/Scoliosis1K_118.json
|
||||||
|
num_workers: 1
|
||||||
|
remove_no_gallery: false
|
||||||
|
cache: false
|
||||||
|
test_dataset_name: Scoliosis1K
|
||||||
|
data_in_use:
|
||||||
|
- true
|
||||||
|
- false
|
||||||
|
|
||||||
|
evaluator_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 20000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_limb4_adamw_2gpu_bs12x8
|
||||||
|
eval_func: evaluate_scoliosis
|
||||||
|
sampler:
|
||||||
|
type: InferenceSampler
|
||||||
|
batch_size: 1
|
||||||
|
sample_type: all_ordered
|
||||||
|
batch_shuffle: false
|
||||||
|
frames_all_limit: 720
|
||||||
|
transform:
|
||||||
|
- type: BaseSilCuttingTransform
|
||||||
|
metric: euc
|
||||||
|
cross_view_gallery: false
|
||||||
|
|
||||||
|
loss_cfg:
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
margin: 0.3
|
||||||
|
type: TripletLoss
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
scale: 16
|
||||||
|
type: CrossEntropyLoss
|
||||||
|
|
||||||
|
model_cfg:
|
||||||
|
model: ScoNet
|
||||||
|
backbone_cfg:
|
||||||
|
type: ResNet9
|
||||||
|
block: BasicBlock
|
||||||
|
in_channel: 2
|
||||||
|
channels:
|
||||||
|
- 64
|
||||||
|
- 128
|
||||||
|
- 256
|
||||||
|
- 512
|
||||||
|
layers:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
strides:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 2
|
||||||
|
- 1
|
||||||
|
maxpool: false
|
||||||
|
SeparateFCs:
|
||||||
|
in_channels: 512
|
||||||
|
out_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
SeparateBNNecks:
|
||||||
|
class_num: 3
|
||||||
|
in_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
bin_num:
|
||||||
|
- 16
|
||||||
|
|
||||||
|
optimizer_cfg:
|
||||||
|
solver: AdamW
|
||||||
|
lr: 0.001
|
||||||
|
weight_decay: 0.0005
|
||||||
|
|
||||||
|
scheduler_cfg:
|
||||||
|
scheduler: MultiStepLR
|
||||||
|
milestones:
|
||||||
|
- 10000
|
||||||
|
- 15000
|
||||||
|
gamma: 0.1
|
||||||
|
|
||||||
|
trainer_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
save_iter: 20000
|
||||||
|
sync_BN: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 0
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_limb4_adamw_2gpu_bs12x8
|
||||||
|
with_test: false
|
||||||
|
log_iter: 100
|
||||||
|
fix_BN: false
|
||||||
|
find_unused_parameters: false
|
||||||
|
sample_type: fixed_unordered
|
||||||
|
sampler:
|
||||||
|
type: TripletSampler
|
||||||
|
batch_shuffle: true
|
||||||
|
batch_size:
|
||||||
|
- 12
|
||||||
|
- 8
|
||||||
|
frames_num_fixed: 30
|
||||||
|
transform:
|
||||||
|
- type: BaseSilCuttingTransform
|
||||||
|
optim_reset: false
|
||||||
|
scheduler_reset: false
|
||||||
|
resume_every_iter: 1000
|
||||||
|
resume_keep: 3
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
data_cfg:
|
||||||
|
dataset_name: Scoliosis1K
|
||||||
|
dataset_root: /mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign-limb4
|
||||||
|
dataset_partition: ./datasets/Scoliosis1K/Scoliosis1K_118.json
|
||||||
|
data_in_use:
|
||||||
|
- true
|
||||||
|
- false
|
||||||
|
num_workers: 1
|
||||||
|
remove_no_gallery: false
|
||||||
|
test_dataset_name: Scoliosis1K
|
||||||
|
|
||||||
|
evaluator_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 20000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_limb4_adamw_2gpu_bs12x8
|
||||||
|
eval_func: evaluate_scoliosis
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: false
|
||||||
|
batch_size: 2
|
||||||
|
sample_type: all_ordered
|
||||||
|
frames_all_limit: 720
|
||||||
|
metric: euc
|
||||||
|
transform:
|
||||||
|
- type: BaseSilCuttingTransform
|
||||||
|
|
||||||
|
loss_cfg:
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
margin: 0.2
|
||||||
|
type: TripletLoss
|
||||||
|
log_prefix: triplet
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
scale: 16
|
||||||
|
type: CrossEntropyLoss
|
||||||
|
log_prefix: softmax
|
||||||
|
log_accuracy: true
|
||||||
|
|
||||||
|
model_cfg:
|
||||||
|
model: ScoNet
|
||||||
|
backbone_cfg:
|
||||||
|
type: ResNet9
|
||||||
|
block: BasicBlock
|
||||||
|
in_channel: 2
|
||||||
|
channels:
|
||||||
|
- 64
|
||||||
|
- 128
|
||||||
|
- 256
|
||||||
|
- 512
|
||||||
|
layers:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
strides:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 2
|
||||||
|
- 1
|
||||||
|
maxpool: false
|
||||||
|
SeparateFCs:
|
||||||
|
in_channels: 512
|
||||||
|
out_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
SeparateBNNecks:
|
||||||
|
class_num: 3
|
||||||
|
in_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
bin_num:
|
||||||
|
- 16
|
||||||
|
|
||||||
|
optimizer_cfg:
|
||||||
|
lr: 0.001
|
||||||
|
solver: AdamW
|
||||||
|
weight_decay: 0.0005
|
||||||
|
|
||||||
|
scheduler_cfg:
|
||||||
|
gamma: 0.1
|
||||||
|
milestones:
|
||||||
|
- 10000
|
||||||
|
- 14000
|
||||||
|
- 18000
|
||||||
|
scheduler: MultiStepLR
|
||||||
|
|
||||||
|
trainer_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
fix_BN: false
|
||||||
|
with_test: false
|
||||||
|
log_iter: 100
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 0
|
||||||
|
auto_resume_latest: true
|
||||||
|
resume_every_iter: 500
|
||||||
|
resume_keep: 3
|
||||||
|
save_iter: 20000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_limb4_adamw_2gpu_bs12x8
|
||||||
|
sync_BN: true
|
||||||
|
total_iter: 20000
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: true
|
||||||
|
batch_size:
|
||||||
|
- 12
|
||||||
|
- 8
|
||||||
|
frames_num_fixed: 30
|
||||||
|
sample_type: fixed_unordered
|
||||||
|
type: TripletSampler
|
||||||
|
transform:
|
||||||
|
- type: BaseSilCuttingTransform
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
data_cfg:
|
||||||
|
dataset_name: Scoliosis1K
|
||||||
|
dataset_root: /mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign
|
||||||
|
dataset_partition: ./datasets/Scoliosis1K/Scoliosis1K_118.json
|
||||||
|
data_in_use:
|
||||||
|
- true
|
||||||
|
- false
|
||||||
|
num_workers: 1
|
||||||
|
remove_no_gallery: false
|
||||||
|
test_dataset_name: Scoliosis1K
|
||||||
|
|
||||||
|
evaluator_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 20000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_sharedalign_nocut_adamw_1gpu_bs8x8
|
||||||
|
eval_func: evaluate_scoliosis
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: false
|
||||||
|
batch_size: 1
|
||||||
|
sample_type: all_ordered
|
||||||
|
type: InferenceSampler
|
||||||
|
frames_all_limit: 720
|
||||||
|
metric: euc
|
||||||
|
transform:
|
||||||
|
- type: BaseSilTransform
|
||||||
|
|
||||||
|
loss_cfg:
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
margin: 0.2
|
||||||
|
type: TripletLoss
|
||||||
|
log_prefix: triplet
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
scale: 16
|
||||||
|
type: CrossEntropyLoss
|
||||||
|
log_prefix: softmax
|
||||||
|
log_accuracy: true
|
||||||
|
|
||||||
|
model_cfg:
|
||||||
|
model: ScoNet
|
||||||
|
backbone_cfg:
|
||||||
|
type: ResNet9
|
||||||
|
block: BasicBlock
|
||||||
|
in_channel: 2
|
||||||
|
channels:
|
||||||
|
- 64
|
||||||
|
- 128
|
||||||
|
- 256
|
||||||
|
- 512
|
||||||
|
layers:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
strides:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 2
|
||||||
|
- 1
|
||||||
|
maxpool: false
|
||||||
|
SeparateFCs:
|
||||||
|
in_channels: 512
|
||||||
|
out_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
SeparateBNNecks:
|
||||||
|
class_num: 3
|
||||||
|
in_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
bin_num:
|
||||||
|
- 16
|
||||||
|
|
||||||
|
optimizer_cfg:
|
||||||
|
lr: 0.001
|
||||||
|
solver: AdamW
|
||||||
|
weight_decay: 0.0005
|
||||||
|
|
||||||
|
scheduler_cfg:
|
||||||
|
gamma: 0.1
|
||||||
|
milestones:
|
||||||
|
- 10000
|
||||||
|
- 14000
|
||||||
|
- 18000
|
||||||
|
scheduler: MultiStepLR
|
||||||
|
|
||||||
|
trainer_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
fix_BN: false
|
||||||
|
with_test: false
|
||||||
|
log_iter: 100
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 0
|
||||||
|
auto_resume_latest: true
|
||||||
|
resume_every_iter: 1000
|
||||||
|
resume_keep: 3
|
||||||
|
save_iter: 20000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_sharedalign_nocut_adamw_1gpu_bs8x8
|
||||||
|
sync_BN: true
|
||||||
|
total_iter: 20000
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: true
|
||||||
|
batch_size:
|
||||||
|
- 8
|
||||||
|
- 8
|
||||||
|
frames_num_fixed: 30
|
||||||
|
sample_type: fixed_unordered
|
||||||
|
type: TripletSampler
|
||||||
|
transform:
|
||||||
|
- type: BaseSilTransform
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
data_cfg:
|
||||||
|
dataset_name: Scoliosis1K
|
||||||
|
dataset_root: /mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign
|
||||||
|
dataset_partition: ./datasets/Scoliosis1K/Scoliosis1K_118.json
|
||||||
|
data_in_use:
|
||||||
|
- true
|
||||||
|
- false
|
||||||
|
num_workers: 1
|
||||||
|
remove_no_gallery: false
|
||||||
|
test_dataset_name: Scoliosis1K
|
||||||
|
test_seq_subset_size: 128
|
||||||
|
test_seq_subset_seed: 118
|
||||||
|
|
||||||
|
evaluator_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 2000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_sharedalign_nocut_adamw_proxy_1gpu
|
||||||
|
eval_func: evaluate_scoliosis
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: false
|
||||||
|
batch_size: 1
|
||||||
|
sample_type: all_ordered
|
||||||
|
type: InferenceSampler
|
||||||
|
frames_all_limit: 720
|
||||||
|
metric: euc
|
||||||
|
transform:
|
||||||
|
- type: BaseSilTransform
|
||||||
|
|
||||||
|
loss_cfg:
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
margin: 0.2
|
||||||
|
type: TripletLoss
|
||||||
|
log_prefix: triplet
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
scale: 16
|
||||||
|
type: CrossEntropyLoss
|
||||||
|
log_prefix: softmax
|
||||||
|
log_accuracy: true
|
||||||
|
|
||||||
|
model_cfg:
|
||||||
|
model: ScoNet
|
||||||
|
backbone_cfg:
|
||||||
|
type: ResNet9
|
||||||
|
block: BasicBlock
|
||||||
|
in_channel: 2
|
||||||
|
channels:
|
||||||
|
- 64
|
||||||
|
- 128
|
||||||
|
- 256
|
||||||
|
- 512
|
||||||
|
layers:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
strides:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 2
|
||||||
|
- 1
|
||||||
|
maxpool: false
|
||||||
|
SeparateFCs:
|
||||||
|
in_channels: 512
|
||||||
|
out_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
SeparateBNNecks:
|
||||||
|
class_num: 3
|
||||||
|
in_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
bin_num:
|
||||||
|
- 16
|
||||||
|
|
||||||
|
optimizer_cfg:
|
||||||
|
lr: 0.001
|
||||||
|
solver: AdamW
|
||||||
|
weight_decay: 0.0005
|
||||||
|
|
||||||
|
scheduler_cfg:
|
||||||
|
gamma: 0.1
|
||||||
|
milestones:
|
||||||
|
- 1000
|
||||||
|
- 1500
|
||||||
|
- 1800
|
||||||
|
scheduler: MultiStepLR
|
||||||
|
|
||||||
|
trainer_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
fix_BN: false
|
||||||
|
with_test: true
|
||||||
|
log_iter: 100
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 0
|
||||||
|
auto_resume_latest: true
|
||||||
|
resume_every_iter: 500
|
||||||
|
resume_keep: 3
|
||||||
|
eval_iter: 500
|
||||||
|
save_iter: 2000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_sharedalign_nocut_adamw_proxy_1gpu
|
||||||
|
sync_BN: true
|
||||||
|
total_iter: 2000
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: true
|
||||||
|
batch_size:
|
||||||
|
- 8
|
||||||
|
- 8
|
||||||
|
frames_num_fixed: 30
|
||||||
|
sample_type: fixed_unordered
|
||||||
|
type: TripletSampler
|
||||||
|
transform:
|
||||||
|
- type: BaseSilTransform
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
data_cfg:
|
||||||
|
dataset_name: Scoliosis1K
|
||||||
|
dataset_root: /mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-seqalign
|
||||||
|
dataset_partition: ./datasets/Scoliosis1K/Scoliosis1K_118.json
|
||||||
|
data_in_use:
|
||||||
|
- true
|
||||||
|
- false
|
||||||
|
num_workers: 1
|
||||||
|
remove_no_gallery: false
|
||||||
|
test_dataset_name: Scoliosis1K
|
||||||
|
|
||||||
|
evaluator_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 20000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_seqalign_2gpu_bs12x8
|
||||||
|
eval_func: evaluate_scoliosis
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: false
|
||||||
|
batch_size: 2
|
||||||
|
sample_type: all_ordered
|
||||||
|
frames_all_limit: 720
|
||||||
|
metric: euc
|
||||||
|
transform:
|
||||||
|
- type: BaseSilCuttingTransform
|
||||||
|
|
||||||
|
loss_cfg:
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
margin: 0.2
|
||||||
|
type: TripletLoss
|
||||||
|
log_prefix: triplet
|
||||||
|
- loss_term_weight: 1.0
|
||||||
|
scale: 16
|
||||||
|
type: CrossEntropyLoss
|
||||||
|
log_prefix: softmax
|
||||||
|
log_accuracy: true
|
||||||
|
|
||||||
|
model_cfg:
|
||||||
|
model: ScoNet
|
||||||
|
backbone_cfg:
|
||||||
|
type: ResNet9
|
||||||
|
block: BasicBlock
|
||||||
|
in_channel: 2
|
||||||
|
channels:
|
||||||
|
- 64
|
||||||
|
- 128
|
||||||
|
- 256
|
||||||
|
- 512
|
||||||
|
layers:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
strides:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 2
|
||||||
|
- 1
|
||||||
|
maxpool: false
|
||||||
|
SeparateFCs:
|
||||||
|
in_channels: 512
|
||||||
|
out_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
SeparateBNNecks:
|
||||||
|
class_num: 3
|
||||||
|
in_channels: 256
|
||||||
|
parts_num: 16
|
||||||
|
bin_num:
|
||||||
|
- 16
|
||||||
|
|
||||||
|
optimizer_cfg:
|
||||||
|
lr: 0.1
|
||||||
|
momentum: 0.9
|
||||||
|
solver: SGD
|
||||||
|
weight_decay: 0.0005
|
||||||
|
|
||||||
|
scheduler_cfg:
|
||||||
|
gamma: 0.1
|
||||||
|
milestones:
|
||||||
|
- 10000
|
||||||
|
- 14000
|
||||||
|
- 18000
|
||||||
|
scheduler: MultiStepLR
|
||||||
|
|
||||||
|
trainer_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
fix_BN: false
|
||||||
|
with_test: false
|
||||||
|
log_iter: 100
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 0
|
||||||
|
auto_resume_latest: true
|
||||||
|
resume_every_iter: 1000
|
||||||
|
resume_keep: 3
|
||||||
|
save_iter: 20000
|
||||||
|
save_name: ScoNet_skeleton_118_sigma15_joint8_seqalign_2gpu_bs12x8
|
||||||
|
sync_BN: true
|
||||||
|
total_iter: 20000
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: true
|
||||||
|
batch_size:
|
||||||
|
- 12
|
||||||
|
- 8
|
||||||
|
frames_num_fixed: 30
|
||||||
|
sample_type: fixed_unordered
|
||||||
|
type: TripletSampler
|
||||||
|
transform:
|
||||||
|
- type: BaseSilCuttingTransform
|
||||||
@@ -167,6 +167,8 @@ Current confirmed findings from local debugging:
|
|||||||
* a larger heatmap sigma can materially blur away the articulated structure; `sigma=8` was much broader than the silhouette geometry, while smaller sigma values recovered more structure
|
* a larger heatmap sigma can materially blur away the articulated structure; `sigma=8` was much broader than the silhouette geometry, while smaller sigma values recovered more structure
|
||||||
* an earlier bug aligned the limb and joint channels separately; that made the two channels of `0_heatmap.pkl` slightly misregistered
|
* an earlier bug aligned the limb and joint channels separately; that made the two channels of `0_heatmap.pkl` slightly misregistered
|
||||||
* the heatmap path is now patched so limb and joint channels share one alignment crop
|
* the heatmap path is now patched so limb and joint channels share one alignment crop
|
||||||
|
* the heatmap aligner now also supports `align_args.scope: sequence`, which applies one shared crop box to the whole sequence instead of recomputing it frame by frame
|
||||||
|
* the heatmap config can also rebalance the two channels after alignment with `channel_gain_limb` / `channel_gain_joint`; this keeps the crop geometry fixed while changing limb-vs-joint strength
|
||||||
|
|
||||||
Remaining caution:
|
Remaining caution:
|
||||||
|
|
||||||
|
|||||||
@@ -517,7 +517,15 @@ class GatherTransform(object):
|
|||||||
"""
|
"""
|
||||||
Gather the different transforms.
|
Gather the different transforms.
|
||||||
"""
|
"""
|
||||||
def __init__(self, base_transform, transform_bone, transform_joint, align_transform=None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
base_transform,
|
||||||
|
transform_bone,
|
||||||
|
transform_joint,
|
||||||
|
align_transform=None,
|
||||||
|
limb_gain: float = 1.0,
|
||||||
|
joint_gain: float = 1.0,
|
||||||
|
) -> None:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
base_transform: Some common transform, e.g., COCO18toCOCO17, PadKeypoints, CenterAndScale
|
base_transform: Some common transform, e.g., COCO18toCOCO17, PadKeypoints, CenterAndScale
|
||||||
@@ -528,6 +536,22 @@ class GatherTransform(object):
|
|||||||
self.transform_bone = transform_bone
|
self.transform_bone = transform_bone
|
||||||
self.transform_joint = transform_joint
|
self.transform_joint = transform_joint
|
||||||
self.align_transform = align_transform
|
self.align_transform = align_transform
|
||||||
|
self.limb_gain = limb_gain
|
||||||
|
self.joint_gain = joint_gain
|
||||||
|
|
||||||
|
def _apply_channel_gains(self, heatmap: np.ndarray) -> np.ndarray:
|
||||||
|
if self.limb_gain == 1.0 and self.joint_gain == 1.0:
|
||||||
|
return heatmap
|
||||||
|
|
||||||
|
original_dtype = heatmap.dtype
|
||||||
|
scaled = heatmap.astype(np.float32, copy=True)
|
||||||
|
scaled[:, 0] *= self.limb_gain
|
||||||
|
scaled[:, 1] *= self.joint_gain
|
||||||
|
scaled = np.clip(scaled, 0.0, 255.0)
|
||||||
|
|
||||||
|
if np.issubdtype(original_dtype, np.integer):
|
||||||
|
return scaled.astype(original_dtype)
|
||||||
|
return scaled.astype(original_dtype)
|
||||||
|
|
||||||
def __call__(self, pose_data):
|
def __call__(self, pose_data):
|
||||||
x = self.base_transform(pose_data)
|
x = self.base_transform(pose_data)
|
||||||
@@ -536,38 +560,109 @@ class GatherTransform(object):
|
|||||||
heatmap = np.concatenate([heatmap_bone, heatmap_joint], axis=1)
|
heatmap = np.concatenate([heatmap_bone, heatmap_joint], axis=1)
|
||||||
if self.align_transform is not None:
|
if self.align_transform is not None:
|
||||||
heatmap = self.align_transform(heatmap)
|
heatmap = self.align_transform(heatmap)
|
||||||
return heatmap
|
return self._apply_channel_gains(heatmap)
|
||||||
|
|
||||||
|
AlignmentScope = Literal["frame", "sequence"]
|
||||||
|
AlignmentCropMode = Literal["square_center", "bbox_pad"]
|
||||||
|
|
||||||
|
|
||||||
class HeatmapAlignment():
|
class HeatmapAlignment():
|
||||||
def __init__(self, align=True, final_img_size=64, offset=0, heatmap_image_size=128) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
align: bool = True,
|
||||||
|
final_img_size: int = 64,
|
||||||
|
offset: int = 0,
|
||||||
|
heatmap_image_size: int = 128,
|
||||||
|
scope: AlignmentScope = "frame",
|
||||||
|
crop_mode: AlignmentCropMode = "square_center",
|
||||||
|
preserve_aspect_ratio: bool = False,
|
||||||
|
) -> None:
|
||||||
self.align = align
|
self.align = align
|
||||||
self.final_img_size = final_img_size
|
self.final_img_size = final_img_size
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.heatmap_image_size = heatmap_image_size
|
self.heatmap_image_size = heatmap_image_size
|
||||||
|
self.scope = scope
|
||||||
|
self.crop_mode = crop_mode
|
||||||
|
self.preserve_aspect_ratio = preserve_aspect_ratio
|
||||||
|
|
||||||
|
def _compute_crop_bounds(
|
||||||
|
self,
|
||||||
|
heatmap: np.ndarray,
|
||||||
|
) -> tuple[int, int, int, int] | None:
|
||||||
|
support_map = heatmap.max(axis=0)
|
||||||
|
y_sum = support_map.sum(axis=1)
|
||||||
|
x_sum = support_map.sum(axis=0)
|
||||||
|
nonzero_rows = np.flatnonzero(y_sum != 0)
|
||||||
|
nonzero_cols = np.flatnonzero(x_sum != 0)
|
||||||
|
if nonzero_rows.size == 0:
|
||||||
|
return None
|
||||||
|
if nonzero_cols.size == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
y_top = max(int(nonzero_rows[0]) - self.offset, 0)
|
||||||
|
y_btm = min(int(nonzero_rows[-1]) + self.offset, self.heatmap_image_size - 1)
|
||||||
|
|
||||||
|
if self.crop_mode == "bbox_pad":
|
||||||
|
x_left = max(int(nonzero_cols[0]) - self.offset, 0)
|
||||||
|
x_right = min(int(nonzero_cols[-1]) + self.offset + 1, self.heatmap_image_size)
|
||||||
|
return y_top, y_btm, x_left, x_right
|
||||||
|
|
||||||
|
height = y_btm - y_top + 1
|
||||||
|
x_center = self.heatmap_image_size // 2
|
||||||
|
x_left = max(x_center - (height // 2), 0)
|
||||||
|
x_right = min(x_center + (height // 2) + 1, self.heatmap_image_size)
|
||||||
|
return y_top, y_btm, x_left, x_right
|
||||||
|
|
||||||
|
def _resize_and_pad(self, cropped_heatmap: np.ndarray) -> np.ndarray:
|
||||||
|
_, src_h, src_w = cropped_heatmap.shape
|
||||||
|
if src_h <= 0 or src_w <= 0:
|
||||||
|
return np.zeros(
|
||||||
|
(cropped_heatmap.shape[0], self.final_img_size, self.final_img_size),
|
||||||
|
dtype=np.float32,
|
||||||
|
)
|
||||||
|
|
||||||
|
scale = float(self.final_img_size) / float(max(src_h, src_w))
|
||||||
|
resized_h = max(1, int(round(src_h * scale)))
|
||||||
|
resized_w = max(1, int(round(src_w * scale)))
|
||||||
|
|
||||||
|
resized = np.stack([
|
||||||
|
cv2.resize(channel, (resized_w, resized_h), interpolation=cv2.INTER_AREA)
|
||||||
|
for channel in cropped_heatmap
|
||||||
|
], axis=0)
|
||||||
|
|
||||||
|
canvas = np.zeros(
|
||||||
|
(cropped_heatmap.shape[0], self.final_img_size, self.final_img_size),
|
||||||
|
dtype=np.float32,
|
||||||
|
)
|
||||||
|
y_offset = (self.final_img_size - resized_h) // 2
|
||||||
|
x_offset = (self.final_img_size - resized_w) // 2
|
||||||
|
canvas[:, y_offset:y_offset + resized_h, x_offset:x_offset + resized_w] = resized
|
||||||
|
return canvas
|
||||||
|
|
||||||
|
def _crop_and_resize(
|
||||||
|
self,
|
||||||
|
heatmap: np.ndarray,
|
||||||
|
crop_bounds: tuple[int, int, int, int] | None,
|
||||||
|
) -> np.ndarray:
|
||||||
|
raw_heatmap = heatmap
|
||||||
|
if crop_bounds is not None:
|
||||||
|
y_top, y_btm, x_left, x_right = crop_bounds
|
||||||
|
raw_heatmap = raw_heatmap[:, y_top:y_btm + 1, x_left:x_right]
|
||||||
|
if self.preserve_aspect_ratio:
|
||||||
|
return self._resize_and_pad(raw_heatmap)
|
||||||
|
|
||||||
|
return np.stack([
|
||||||
|
cv2.resize(channel, (self.final_img_size, self.final_img_size), interpolation=cv2.INTER_AREA)
|
||||||
|
for channel in raw_heatmap
|
||||||
|
], axis=0)
|
||||||
|
|
||||||
def center_crop(self, heatmap):
|
def center_crop(self, heatmap):
|
||||||
"""
|
"""
|
||||||
Input: [C, heatmap_image_size, heatmap_image_size]
|
Input: [C, heatmap_image_size, heatmap_image_size]
|
||||||
Output: [C, final_img_size, final_img_size]
|
Output: [C, final_img_size, final_img_size]
|
||||||
"""
|
"""
|
||||||
raw_heatmap = heatmap
|
crop_bounds = self._compute_crop_bounds(heatmap) if self.align else None
|
||||||
if self.align:
|
return self._crop_and_resize(heatmap, crop_bounds) # [C, final_img_size, final_img_size]
|
||||||
support_map = raw_heatmap.max(axis=0)
|
|
||||||
y_sum = support_map.sum(axis=1)
|
|
||||||
nonzero_rows = np.flatnonzero(y_sum != 0)
|
|
||||||
if nonzero_rows.size != 0:
|
|
||||||
y_top = max(int(nonzero_rows[0]) - self.offset, 0)
|
|
||||||
y_btm = min(int(nonzero_rows[-1]) + self.offset, self.heatmap_image_size - 1)
|
|
||||||
height = y_btm - y_top + 1
|
|
||||||
x_center = self.heatmap_image_size // 2
|
|
||||||
x_left = max(x_center - (height // 2), 0)
|
|
||||||
x_right = min(x_center + (height // 2) + 1, self.heatmap_image_size)
|
|
||||||
raw_heatmap = raw_heatmap[:, y_top:y_btm + 1, x_left:x_right]
|
|
||||||
resized = np.stack([
|
|
||||||
cv2.resize(channel, (self.final_img_size, self.final_img_size), interpolation=cv2.INTER_AREA)
|
|
||||||
for channel in raw_heatmap
|
|
||||||
], axis=0)
|
|
||||||
return resized # [C, final_img_size, final_img_size]
|
|
||||||
|
|
||||||
def __call__(self, heatmap_imgs):
|
def __call__(self, heatmap_imgs):
|
||||||
"""
|
"""
|
||||||
@@ -576,6 +671,13 @@ class HeatmapAlignment():
|
|||||||
"""
|
"""
|
||||||
original_dtype = heatmap_imgs.dtype
|
original_dtype = heatmap_imgs.dtype
|
||||||
heatmap_imgs = heatmap_imgs.astype(np.float32) / 255.0
|
heatmap_imgs = heatmap_imgs.astype(np.float32) / 255.0
|
||||||
|
if self.align and self.scope == "sequence":
|
||||||
|
sequence_crop_bounds = self._compute_crop_bounds(heatmap_imgs.max(axis=0))
|
||||||
|
heatmap_imgs = np.array(
|
||||||
|
[self._crop_and_resize(heatmap_img, sequence_crop_bounds) for heatmap_img in heatmap_imgs],
|
||||||
|
dtype=np.float32,
|
||||||
|
)
|
||||||
|
else:
|
||||||
heatmap_imgs = np.array([self.center_crop(heatmap_img) for heatmap_img in heatmap_imgs], dtype=np.float32)
|
heatmap_imgs = np.array([self.center_crop(heatmap_img) for heatmap_img in heatmap_imgs], dtype=np.float32)
|
||||||
heatmap_imgs = heatmap_imgs * 255.0
|
heatmap_imgs = heatmap_imgs * 255.0
|
||||||
if np.issubdtype(original_dtype, np.integer):
|
if np.issubdtype(original_dtype, np.integer):
|
||||||
@@ -591,6 +693,8 @@ def GenerateHeatmapTransform(
|
|||||||
reduction: Literal["upstream", "max", "sum"] = "upstream",
|
reduction: Literal["upstream", "max", "sum"] = "upstream",
|
||||||
sigma_limb: float | None = None,
|
sigma_limb: float | None = None,
|
||||||
sigma_joint: float | None = None,
|
sigma_joint: float | None = None,
|
||||||
|
channel_gain_limb: float | None = None,
|
||||||
|
channel_gain_joint: float | None = None,
|
||||||
):
|
):
|
||||||
|
|
||||||
base_transform = T.Compose([
|
base_transform = T.Compose([
|
||||||
@@ -636,6 +740,8 @@ def GenerateHeatmapTransform(
|
|||||||
transform_bone,
|
transform_bone,
|
||||||
transform_joint,
|
transform_joint,
|
||||||
HeatmapAlignment(**align_args),
|
HeatmapAlignment(**align_args),
|
||||||
|
limb_gain=1.0 if channel_gain_limb is None else channel_gain_limb,
|
||||||
|
joint_gain=1.0 if channel_gain_joint is None else channel_gain_joint,
|
||||||
) # [T, 2, H, W]
|
) # [T, 2, H, W]
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|||||||
@@ -203,6 +203,8 @@ def main() -> None:
|
|||||||
reduction=cast(HeatmapReduction, args.heatmap_reduction),
|
reduction=cast(HeatmapReduction, args.heatmap_reduction),
|
||||||
sigma_limb=optional_cfg_float(heatmap_cfg, "sigma_limb"),
|
sigma_limb=optional_cfg_float(heatmap_cfg, "sigma_limb"),
|
||||||
sigma_joint=optional_cfg_float(heatmap_cfg, "sigma_joint"),
|
sigma_joint=optional_cfg_float(heatmap_cfg, "sigma_joint"),
|
||||||
|
channel_gain_limb=optional_cfg_float(heatmap_cfg, "channel_gain_limb"),
|
||||||
|
channel_gain_joint=optional_cfg_float(heatmap_cfg, "channel_gain_joint"),
|
||||||
)
|
)
|
||||||
|
|
||||||
pose_paths = iter_pose_paths(args.pose_data_path)
|
pose_paths = iter_pose_paths(args.pose_data_path)
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Scoliosis Training Change Log
|
||||||
|
|
||||||
|
This file is the single run-by-run changelog for Scoliosis1K training and evaluation in this repo.
|
||||||
|
|
||||||
|
Use it for:
|
||||||
|
- what changed between runs
|
||||||
|
- which dataset/config/checkpoint was used
|
||||||
|
- what the resulting metrics were
|
||||||
|
- whether a run is still in progress
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Add one entry before launching a new training run.
|
||||||
|
- Update the same entry after training/eval completes.
|
||||||
|
- Record only the delta from the previous relevant run, not a full config dump.
|
||||||
|
- For skeleton-map control runs, use plain-text `ScoNet-MT-ske` naming in the notes even though the code class is `ScoNet`.
|
||||||
|
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
| Date | Run | Model | Dataset | Main change vs previous relevant run | Status | Eval result |
|
||||||
|
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||||
|
| 2026-03-07 | `DRF` | DRF | `Scoliosis1K-drf-pkl-118` | First OpenGait DRF integration on paper `1:1:8` split using shared OpenGait skeleton/PAV path | complete | `58.08 Acc / 78.80 Prec / 60.22 Rec / 56.99 F1` |
|
||||||
|
| 2026-03-08 | `DRF_paper` | DRF | `Scoliosis1K-drf-pkl-118-paper` | More paper-literal preprocessing: summed/sparser heatmap path, dataset-level PAV normalization, body-prior path refinement | complete | `51.67 Acc / 72.37 Prec / 56.22 Rec / 50.92 F1` |
|
||||||
|
| 2026-03-08 | `ScoNet_skeleton_118` | ScoNet-MT-ske control | `Scoliosis1K-drf-pkl-118-paper` | Plain skeleton-map baseline on the paper-literal export to isolate DRF vs skeleton-path failure | complete | `38.85 Acc / 61.23 Prec / 46.75 Rec / 35.96 F1` |
|
||||||
|
| 2026-03-08 | `ScoNet_skeleton_118_sigma8` | ScoNet-MT-ske control | `Scoliosis1K_sigma_8.0/pkl` | Reused upstream/default sigma-8 heatmap export instead of the DRF paper-literal export | complete | `36.45 Acc / 69.17 Prec / 43.82 Rec / 32.78 F1` |
|
||||||
|
| 2026-03-08 | `ScoNet_skeleton_118_sigma15_bs12x8` | ScoNet-MT-ske control | `Scoliosis1K-drf-pkl-118-sigma15` | Lowered skeleton-map sigma from `8.0` to `1.5` to tighten the pose rasterization | complete | `46.33 Acc / 68.09 Prec / 51.92 Rec / 44.69 F1` |
|
||||||
|
| 2026-03-09 | `ScoNet_skeleton_118_sigma15_joint8_sharedalign_2gpu_bs12x8` | ScoNet-MT-ske control | `Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign` | Fixed limb/joint channel misalignment, used mixed sigma `limb=1.5 / joint=8.0`, kept SGD | complete | `50.47 Acc / 69.31 Prec / 54.58 Rec / 48.63 F1` |
|
||||||
|
| 2026-03-09 | `ScoNet_skeleton_118_sigma15_joint8_limb4_adamw_2gpu_bs12x8` | ScoNet-MT-ske control | `Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign-limb4` | Rebalanced channel intensity with `limb_gain=4.0`; switched optimizer from `SGD` to `AdamW` | complete | `48.60 Acc / 65.97 Prec / 53.19 Rec / 46.41 F1` |
|
||||||
|
| 2026-03-09 | `ScoNet_skeleton_118_sigma15_joint8_sharedalign_nocut_adamw_1gpu_bs8x8` | ScoNet-MT-ske control | `Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign` | Switched runtime transform from `BaseSilCuttingTransform` to `BaseSilTransform` (`no-cut`), kept `AdamW`, reduced `8x8` due to 5070 Ti OOM at `12x8` | training | no eval yet |
|
||||||
|
| 2026-03-09 | `ScoNet_skeleton_118_sigma15_joint8_sharedalign_nocut_adamw_proxy_1gpu` | ScoNet-MT-ske proxy | `Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign` | Fast proxy route: `no-cut`, `AdamW`, `8x8`, `total_iter=2000`, `eval_iter=500`, `test_seq_subset_size=128` | training | no eval yet |
|
||||||
|
|
||||||
|
## Current best skeleton baseline
|
||||||
|
|
||||||
|
Current best `ScoNet-MT-ske`-style result:
|
||||||
|
- `ScoNet_skeleton_118_sigma15_joint8_sharedalign_2gpu_bs12x8`
|
||||||
|
- `50.47 Acc / 69.31 Prec / 54.58 Rec / 48.63 F1`
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `ckpt/ScoNet-20000-better.pt` is intentionally not listed here because it is a silhouette checkpoint, not a skeleton-map run.
|
||||||
|
- `DRF` runs are included because they are part of the same reproduction/debugging loop, but this log should stay focused on train/eval changes, not broader code refactors.
|
||||||
|
- The long `ScoNet_skeleton_118_sigma15_joint8_sharedalign_nocut_adamw_1gpu_bs8x8` run was intentionally interrupted and superseded by the shorter proxy run once fast-iteration support was added.
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
import os
|
|
||||||
import pickle
|
|
||||||
import os.path as osp
|
|
||||||
import torch.utils.data as tordata
|
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
import os.path as osp
|
||||||
|
import pickle
|
||||||
|
import random
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
|
import torch.utils.data as tordata
|
||||||
from opengait.utils import get_msg_mgr
|
from opengait.utils import get_msg_mgr
|
||||||
|
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
class DataSet(tordata.Dataset):
|
class DataSet(tordata.Dataset):
|
||||||
def __init__(self, data_cfg, training):
|
def __init__(self, data_cfg, training):
|
||||||
@@ -66,6 +71,33 @@ class DataSet(tordata.Dataset):
|
|||||||
for idx in range(len(self)):
|
for idx in range(len(self)):
|
||||||
self.__getitem__(idx)
|
self.__getitem__(idx)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _sample_items(
|
||||||
|
items: list[T],
|
||||||
|
subset_size: int | None,
|
||||||
|
subset_seed: int,
|
||||||
|
subset_name: str,
|
||||||
|
msg_mgr=None,
|
||||||
|
) -> list[T]:
|
||||||
|
if subset_size is None:
|
||||||
|
return items
|
||||||
|
if subset_size <= 0:
|
||||||
|
raise ValueError(f"{subset_name} must be positive, got {subset_size}")
|
||||||
|
if subset_size >= len(items):
|
||||||
|
return items
|
||||||
|
|
||||||
|
sampled_items = random.Random(subset_seed).sample(items, subset_size)
|
||||||
|
sampled_items.sort()
|
||||||
|
if msg_mgr is not None:
|
||||||
|
msg_mgr.log_info(
|
||||||
|
"Using %s subset: %d / %d items (seed=%d)",
|
||||||
|
subset_name,
|
||||||
|
len(sampled_items),
|
||||||
|
len(items),
|
||||||
|
subset_seed,
|
||||||
|
)
|
||||||
|
return sampled_items
|
||||||
|
|
||||||
def __dataset_parser(self, data_config, training):
|
def __dataset_parser(self, data_config, training):
|
||||||
dataset_root = data_config['dataset_root']
|
dataset_root = data_config['dataset_root']
|
||||||
try:
|
try:
|
||||||
@@ -80,9 +112,16 @@ class DataSet(tordata.Dataset):
|
|||||||
label_list = os.listdir(dataset_root)
|
label_list = os.listdir(dataset_root)
|
||||||
train_set = [label for label in train_set if label in label_list]
|
train_set = [label for label in train_set if label in label_list]
|
||||||
test_set = [label for label in test_set if label in label_list]
|
test_set = [label for label in test_set if label in label_list]
|
||||||
|
msg_mgr = get_msg_mgr()
|
||||||
|
train_set = self._sample_items(
|
||||||
|
train_set,
|
||||||
|
data_config.get("train_pid_subset_size"),
|
||||||
|
int(data_config.get("train_pid_subset_seed", 0)),
|
||||||
|
"train pid",
|
||||||
|
msg_mgr,
|
||||||
|
)
|
||||||
miss_pids = [label for label in label_list if label not in (
|
miss_pids = [label for label in label_list if label not in (
|
||||||
train_set + test_set)]
|
train_set + test_set)]
|
||||||
msg_mgr = get_msg_mgr()
|
|
||||||
|
|
||||||
def log_pid_list(pid_list):
|
def log_pid_list(pid_list):
|
||||||
if len(pid_list) >= 3:
|
if len(pid_list) >= 3:
|
||||||
@@ -121,5 +160,14 @@ class DataSet(tordata.Dataset):
|
|||||||
'Find no .pkl file in %s-%s-%s.' % (lab, typ, vie))
|
'Find no .pkl file in %s-%s-%s.' % (lab, typ, vie))
|
||||||
return seqs_info_list
|
return seqs_info_list
|
||||||
|
|
||||||
self.seqs_info = get_seqs_info_list(
|
if training:
|
||||||
train_set) if training else get_seqs_info_list(test_set)
|
self.seqs_info = get_seqs_info_list(train_set)
|
||||||
|
else:
|
||||||
|
self.seqs_info = get_seqs_info_list(test_set)
|
||||||
|
self.seqs_info = self._sample_items(
|
||||||
|
self.seqs_info,
|
||||||
|
data_config.get("test_seq_subset_size"),
|
||||||
|
int(data_config.get("test_seq_subset_seed", 0)),
|
||||||
|
"test sequence",
|
||||||
|
msg_mgr,
|
||||||
|
)
|
||||||
|
|||||||
@@ -553,12 +553,21 @@ class BaseModel(MetaModel, nn.Module):
|
|||||||
resume_every_iter = int(model.engine_cfg.get('resume_every_iter', 0))
|
resume_every_iter = int(model.engine_cfg.get('resume_every_iter', 0))
|
||||||
if resume_every_iter > 0 and model.iteration % resume_every_iter == 0:
|
if resume_every_iter > 0 and model.iteration % resume_every_iter == 0:
|
||||||
model.save_resume_ckpt(model.iteration)
|
model.save_resume_ckpt(model.iteration)
|
||||||
if model.iteration % model.engine_cfg['save_iter'] == 0:
|
save_iter = int(model.engine_cfg['save_iter'])
|
||||||
|
eval_iter = int(model.engine_cfg.get('eval_iter', 0))
|
||||||
|
should_save = save_iter > 0 and model.iteration % save_iter == 0
|
||||||
|
should_eval = False
|
||||||
|
if model.engine_cfg['with_test']:
|
||||||
|
if eval_iter > 0:
|
||||||
|
should_eval = model.iteration % eval_iter == 0
|
||||||
|
else:
|
||||||
|
should_eval = should_save
|
||||||
|
|
||||||
|
if should_save:
|
||||||
# save the checkpoint
|
# save the checkpoint
|
||||||
model.save_ckpt(model.iteration)
|
model.save_ckpt(model.iteration)
|
||||||
|
|
||||||
# run test if with_test = true
|
if should_eval:
|
||||||
if model.engine_cfg['with_test']:
|
|
||||||
model.msg_mgr.log_info("Running test...")
|
model.msg_mgr.log_info("Running test...")
|
||||||
model.eval()
|
model.eval()
|
||||||
result_dict = BaseModel.run_test(model)
|
result_dict = BaseModel.run_test(model)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from dataclasses import dataclass
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
|
import click
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from jaxtyping import Float
|
from jaxtyping import Float
|
||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
@@ -18,12 +19,12 @@ if str(REPO_ROOT) not in sys.path:
|
|||||||
|
|
||||||
from datasets import pretreatment_scoliosis_drf as drf_prep
|
from datasets import pretreatment_scoliosis_drf as drf_prep
|
||||||
|
|
||||||
POSE_ROOT = Path("/mnt/public/data/Scoliosis1K/Scoliosis1K-pose-pkl")
|
DEFAULT_POSE_ROOT = Path("/mnt/public/data/Scoliosis1K/Scoliosis1K-pose-pkl")
|
||||||
HEATMAP_ROOT = Path("/mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign")
|
DEFAULT_HEATMAP_ROOT = Path("/mnt/public/data/Scoliosis1K/Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign")
|
||||||
PARTITION_PATH = REPO_ROOT / "datasets/Scoliosis1K/Scoliosis1K_118.json"
|
DEFAULT_PARTITION_PATH = REPO_ROOT / "datasets/Scoliosis1K/Scoliosis1K_118.json"
|
||||||
HEATMAP_CFG_PATH = REPO_ROOT / "configs/drf/pretreatment_heatmap_drf_sigma15_joint8.yaml"
|
DEFAULT_HEATMAP_CFG_PATH = REPO_ROOT / "configs/drf/pretreatment_heatmap_drf_sigma15_joint8.yaml"
|
||||||
REPORT_PATH = REPO_ROOT / "research/scoliosis_dataset_analysis_118_sharedalign.md"
|
DEFAULT_REPORT_PATH = REPO_ROOT / "research/scoliosis_dataset_analysis_118_sharedalign.md"
|
||||||
JSON_PATH = REPO_ROOT / "research/scoliosis_dataset_analysis_118_sharedalign.json"
|
DEFAULT_JSON_PATH = REPO_ROOT / "research/scoliosis_dataset_analysis_118_sharedalign.json"
|
||||||
|
|
||||||
EPS = 1e-6
|
EPS = 1e-6
|
||||||
THRESHOLD = 13.0
|
THRESHOLD = 13.0
|
||||||
@@ -53,8 +54,19 @@ class RunningStats:
|
|||||||
return self.total / max(self.count, 1)
|
return self.total / max(self.count, 1)
|
||||||
|
|
||||||
|
|
||||||
def load_partition_ids() -> tuple[set[str], set[str]]:
|
@dataclass(frozen=True)
|
||||||
with PARTITION_PATH.open("r", encoding="utf-8") as handle:
|
class AnalysisArgs:
|
||||||
|
pose_root: Path
|
||||||
|
heatmap_root: Path
|
||||||
|
partition_path: Path
|
||||||
|
heatmap_cfg_path: Path
|
||||||
|
report_path: Path
|
||||||
|
json_path: Path
|
||||||
|
report_title: str
|
||||||
|
|
||||||
|
|
||||||
|
def load_partition_ids(partition_path: Path) -> tuple[set[str], set[str]]:
|
||||||
|
with partition_path.open("r", encoding="utf-8") as handle:
|
||||||
partition = json.load(handle)
|
partition = json.load(handle)
|
||||||
return set(partition["TRAIN_SET"]), set(partition["TEST_SET"])
|
return set(partition["TRAIN_SET"]), set(partition["TEST_SET"])
|
||||||
|
|
||||||
@@ -64,12 +76,12 @@ def sequence_key_from_path(path: Path) -> SequenceKey:
|
|||||||
return SequenceKey(pid=parts[-4], label=parts[-3], seq=parts[-2])
|
return SequenceKey(pid=parts[-4], label=parts[-3], seq=parts[-2])
|
||||||
|
|
||||||
|
|
||||||
def iter_pose_paths() -> list[Path]:
|
def iter_pose_paths(pose_root: Path) -> list[Path]:
|
||||||
return sorted(POSE_ROOT.glob("*/*/*/*.pkl"))
|
return sorted(pose_root.glob("*/*/*/*.pkl"))
|
||||||
|
|
||||||
|
|
||||||
def iter_heatmap_paths() -> list[Path]:
|
def iter_heatmap_paths(heatmap_root: Path) -> list[Path]:
|
||||||
return sorted(HEATMAP_ROOT.glob("*/*/*/0_heatmap.pkl"))
|
return sorted(heatmap_root.glob("*/*/*/0_heatmap.pkl"))
|
||||||
|
|
||||||
|
|
||||||
def read_pickle(path: Path) -> object:
|
def read_pickle(path: Path) -> object:
|
||||||
@@ -214,10 +226,10 @@ def evaluate_predictions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def analyze() -> dict[str, object]:
|
def analyze(args: AnalysisArgs) -> dict[str, object]:
|
||||||
train_ids, test_ids = load_partition_ids()
|
train_ids, test_ids = load_partition_ids(args.partition_path)
|
||||||
|
|
||||||
heatmap_cfg = drf_prep.load_heatmap_cfg(str(HEATMAP_CFG_PATH))
|
heatmap_cfg = drf_prep.load_heatmap_cfg(str(args.heatmap_cfg_path))
|
||||||
pose_transform = drf_prep.build_pose_transform(heatmap_cfg)
|
pose_transform = drf_prep.build_pose_transform(heatmap_cfg)
|
||||||
|
|
||||||
split_label_counts: dict[str, dict[str, int]] = {
|
split_label_counts: dict[str, dict[str, int]] = {
|
||||||
@@ -233,7 +245,7 @@ def analyze() -> dict[str, object]:
|
|||||||
"test": defaultdict(RunningStats),
|
"test": defaultdict(RunningStats),
|
||||||
}
|
}
|
||||||
|
|
||||||
for pose_path in iter_pose_paths():
|
for pose_path in iter_pose_paths(args.pose_root):
|
||||||
key = sequence_key_from_path(pose_path)
|
key = sequence_key_from_path(pose_path)
|
||||||
split = "train" if key.pid in train_ids else "test"
|
split = "train" if key.pid in train_ids else "test"
|
||||||
split_label_counts[split][key.label] += 1
|
split_label_counts[split][key.label] += 1
|
||||||
@@ -250,7 +262,7 @@ def analyze() -> dict[str, object]:
|
|||||||
labels_test: list[int] = []
|
labels_test: list[int] = []
|
||||||
pav_means: dict[str, list[float]] = defaultdict(list)
|
pav_means: dict[str, list[float]] = defaultdict(list)
|
||||||
|
|
||||||
for heatmap_path in iter_heatmap_paths():
|
for heatmap_path in iter_heatmap_paths(args.heatmap_root):
|
||||||
key = sequence_key_from_path(heatmap_path)
|
key = sequence_key_from_path(heatmap_path)
|
||||||
split = "train" if key.pid in train_ids else "test"
|
split = "train" if key.pid in train_ids else "test"
|
||||||
heatmap = np.asarray(read_pickle(heatmap_path), dtype=np.float32)
|
heatmap = np.asarray(read_pickle(heatmap_path), dtype=np.float32)
|
||||||
@@ -284,6 +296,11 @@ def analyze() -> dict[str, object]:
|
|||||||
pav_classifier = evaluate_predictions(y_test, y_pred, num_classes=3)
|
pav_classifier = evaluate_predictions(y_test, y_pred, num_classes=3)
|
||||||
|
|
||||||
results: dict[str, object] = {
|
results: dict[str, object] = {
|
||||||
|
"report_title": args.report_title,
|
||||||
|
"pose_root": str(args.pose_root),
|
||||||
|
"heatmap_root": str(args.heatmap_root),
|
||||||
|
"partition_path": str(args.partition_path),
|
||||||
|
"heatmap_cfg_path": str(args.heatmap_cfg_path),
|
||||||
"split_label_counts": split_label_counts,
|
"split_label_counts": split_label_counts,
|
||||||
"pose_confidence_mean": {
|
"pose_confidence_mean": {
|
||||||
split: {label: stats.mean for label, stats in per_label.items()}
|
split: {label: stats.mean for label, stats in per_label.items()}
|
||||||
@@ -310,6 +327,11 @@ def analyze() -> dict[str, object]:
|
|||||||
|
|
||||||
|
|
||||||
def format_report(results: dict[str, object]) -> str:
|
def format_report(results: dict[str, object]) -> str:
|
||||||
|
report_title = str(results["report_title"])
|
||||||
|
pose_root = str(results["pose_root"])
|
||||||
|
heatmap_root = str(results["heatmap_root"])
|
||||||
|
partition_path = str(results["partition_path"])
|
||||||
|
heatmap_cfg_path = str(results["heatmap_cfg_path"])
|
||||||
split_counts = results["split_label_counts"]
|
split_counts = results["split_label_counts"]
|
||||||
pose_conf = results["pose_confidence_mean"]
|
pose_conf = results["pose_confidence_mean"]
|
||||||
pose_valid = results["pose_valid_ratio_mean"]
|
pose_valid = results["pose_valid_ratio_mean"]
|
||||||
@@ -332,7 +354,13 @@ def format_report(results: dict[str, object]) -> str:
|
|||||||
height_mean, height_p95 = heat_stat("height_mean")
|
height_mean, height_p95 = heat_stat("height_mean")
|
||||||
active_fraction_mean, active_fraction_p95 = heat_stat("active_fraction_mean")
|
active_fraction_mean, active_fraction_p95 = heat_stat("active_fraction_mean")
|
||||||
|
|
||||||
return f"""# Scoliosis1K Dataset Analysis (1:1:8, shared-align skeleton maps)
|
return f"""# {report_title}
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
- pose root: `{pose_root}`
|
||||||
|
- heatmap root: `{heatmap_root}`
|
||||||
|
- partition: `{partition_path}`
|
||||||
|
- heatmap cfg: `{heatmap_cfg_path}`
|
||||||
|
|
||||||
## Split
|
## Split
|
||||||
|
|
||||||
@@ -377,7 +405,7 @@ Train-on-train / test-on-test linear softmax probe over sequence-level PAV:
|
|||||||
- macro recall: {pav_probe["macro_recall"]:.2f}%
|
- macro recall: {pav_probe["macro_recall"]:.2f}%
|
||||||
- macro F1: {pav_probe["macro_f1"]:.2f}%
|
- macro F1: {pav_probe["macro_f1"]:.2f}%
|
||||||
|
|
||||||
## Shared-align heatmap geometry
|
## Heatmap geometry
|
||||||
|
|
||||||
Combined support bbox stats over all sequences:
|
Combined support bbox stats over all sequences:
|
||||||
- width mean / p95: {width_mean:.2f} / {width_p95:.2f}
|
- width mean / p95: {width_mean:.2f} / {width_p95:.2f}
|
||||||
@@ -402,19 +430,79 @@ Estimated intensity mass in the columns removed by `BaseSilCuttingTransform`:
|
|||||||
|
|
||||||
- The raw pose data does not look broken. Confidence and valid-joint ratios are high and similar across classes.
|
- The raw pose data does not look broken. Confidence and valid-joint ratios are high and similar across classes.
|
||||||
- The sequence-level PAV still carries useful label signal, so the dataset is not devoid of scoliosis information.
|
- The sequence-level PAV still carries useful label signal, so the dataset is not devoid of scoliosis information.
|
||||||
- Shared alignment removed the old limb-vs-joint registration bug; residual channel-center mismatch is now small.
|
- The limb/joint alignment fix removed the old registration bug; residual channel-center mismatch is now small.
|
||||||
- The remaining suspicious area is the visual branch: the skeleton map still has frame-to-frame bbox jitter, and the support bbox is almost full-height (`~61.5 / 64`) and fairly dense (`~36%` active pixels), which may be washing out subtle asymmetry cues.
|
- The remaining suspicious area is the visual branch: the skeleton map still has frame-to-frame bbox jitter, and the support bbox is almost full-height (`~61.5 / 64`) and fairly dense (`~36%` active pixels), which may be washing out subtle asymmetry cues.
|
||||||
- `BaseSilCuttingTransform` does not appear to be the main failure source for this shared-align export; the measured mass in the removed side margins is near zero.
|
- `BaseSilCuttingTransform` does not appear to be the main failure source for this export; the measured mass in the removed side margins is near zero.
|
||||||
- The dataset itself looks usable; the bigger issue still appears to be how the current skeleton-map preprocessing/runtime path presents that data to ScoNet.
|
- The dataset itself looks usable; the bigger issue still appears to be how the current skeleton-map preprocessing/runtime path presents that data to ScoNet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
@click.command()
|
||||||
results = analyze()
|
@click.option(
|
||||||
REPORT_PATH.write_text(format_report(results), encoding="utf-8")
|
"--pose-root",
|
||||||
JSON_PATH.write_text(json.dumps(results, indent=2, sort_keys=True), encoding="utf-8")
|
type=click.Path(path_type=Path, file_okay=False),
|
||||||
print(f"Wrote {REPORT_PATH}")
|
default=DEFAULT_POSE_ROOT,
|
||||||
print(f"Wrote {JSON_PATH}")
|
show_default=True,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--heatmap-root",
|
||||||
|
type=click.Path(path_type=Path, file_okay=False),
|
||||||
|
default=DEFAULT_HEATMAP_ROOT,
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--partition-path",
|
||||||
|
type=click.Path(path_type=Path, dir_okay=False),
|
||||||
|
default=DEFAULT_PARTITION_PATH,
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--heatmap-cfg-path",
|
||||||
|
type=click.Path(path_type=Path, dir_okay=False),
|
||||||
|
default=DEFAULT_HEATMAP_CFG_PATH,
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--report-path",
|
||||||
|
type=click.Path(path_type=Path, dir_okay=False),
|
||||||
|
default=DEFAULT_REPORT_PATH,
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--json-path",
|
||||||
|
type=click.Path(path_type=Path, dir_okay=False),
|
||||||
|
default=DEFAULT_JSON_PATH,
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--report-title",
|
||||||
|
type=str,
|
||||||
|
default="Scoliosis1K Dataset Analysis (1:1:8, shared-align skeleton maps)",
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
|
def main(
|
||||||
|
pose_root: Path,
|
||||||
|
heatmap_root: Path,
|
||||||
|
partition_path: Path,
|
||||||
|
heatmap_cfg_path: Path,
|
||||||
|
report_path: Path,
|
||||||
|
json_path: Path,
|
||||||
|
report_title: str,
|
||||||
|
) -> None:
|
||||||
|
args = AnalysisArgs(
|
||||||
|
pose_root=pose_root,
|
||||||
|
heatmap_root=heatmap_root,
|
||||||
|
partition_path=partition_path,
|
||||||
|
heatmap_cfg_path=heatmap_cfg_path,
|
||||||
|
report_path=report_path,
|
||||||
|
json_path=json_path,
|
||||||
|
report_title=report_title,
|
||||||
|
)
|
||||||
|
results = analyze(args)
|
||||||
|
args.report_path.write_text(format_report(results), encoding="utf-8")
|
||||||
|
args.json_path.write_text(json.dumps(results, indent=2, sort_keys=True), encoding="utf-8")
|
||||||
|
print(f"Wrote {args.report_path}")
|
||||||
|
print(f"Wrote {args.json_path}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
Reference in New Issue
Block a user