Add weighted CE proxy and fix loss imports
This commit is contained in:
+115
@@ -0,0 +1,115 @@
|
|||||||
|
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_weightedce_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: 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
|
||||||
|
class_weight:
|
||||||
|
- 1.0
|
||||||
|
- 4.0
|
||||||
|
- 4.0
|
||||||
|
|
||||||
|
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
|
||||||
|
solver: SGD
|
||||||
|
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_weightedce_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: BaseSilCuttingTransform
|
||||||
@@ -29,6 +29,7 @@ Use it for:
|
|||||||
| 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` | interrupted | superseded by proxy route before eval |
|
| 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` | interrupted | superseded by proxy route before eval |
|
||||||
| 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` | interrupted | superseded by geometry-fixed proxy before completion |
|
| 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` | interrupted | superseded by geometry-fixed proxy before completion |
|
||||||
| 2026-03-10 | `ScoNet_skeleton_118_sigma15_joint8_geomfix_proxy_1gpu` | ScoNet-MT-ske proxy | `Scoliosis1K-drf-pkl-118-sigma15-joint8-geomfix` | Geometry ablation: aspect-ratio-preserving crop+pad instead of square-warp resize; `AdamW`, `no-cut`, `8x8`, `total_iter=2000`, `eval_iter=500`, fixed test subset seed `118` | complete | proxy subset unstable: `500 24.22/8.07/33.33/13.00`, `1000 60.16/68.05/58.13/55.25`, `1500 26.56/58.33/35.64/17.68`, `2000 27.34/63.96/37.02/20.14` (Acc/Prec/Rec/F1) |
|
| 2026-03-10 | `ScoNet_skeleton_118_sigma15_joint8_geomfix_proxy_1gpu` | ScoNet-MT-ske proxy | `Scoliosis1K-drf-pkl-118-sigma15-joint8-geomfix` | Geometry ablation: aspect-ratio-preserving crop+pad instead of square-warp resize; `AdamW`, `no-cut`, `8x8`, `total_iter=2000`, `eval_iter=500`, fixed test subset seed `118` | complete | proxy subset unstable: `500 24.22/8.07/33.33/13.00`, `1000 60.16/68.05/58.13/55.25`, `1500 26.56/58.33/35.64/17.68`, `2000 27.34/63.96/37.02/20.14` (Acc/Prec/Rec/F1) |
|
||||||
|
| 2026-03-10 | `ScoNet_skeleton_118_sigma15_joint8_sharedalign_weightedce_proxy_1gpu` | ScoNet-MT-ske proxy | `Scoliosis1K-drf-pkl-118-sigma15-joint8-sharedalign` | Training-side imbalance ablation: kept the current best shared-align geometry, restored `SGD` baseline settings, and applied weighted CE with class weights `[1.0, 4.0, 4.0]`; `total_iter=2000`, `eval_iter=500`, fixed test subset seed `118` | training | no eval yet |
|
||||||
|
|
||||||
## Current best skeleton baseline
|
## Current best skeleton baseline
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,25 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
from ctypes import ArgumentError
|
from ctypes import ArgumentError
|
||||||
import torch.nn as nn
|
from typing import Any
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
|
|
||||||
from opengait.utils import Odict
|
from opengait.utils import Odict
|
||||||
import functools
|
import functools
|
||||||
from opengait.utils import ddp_all_gather
|
from opengait.utils import ddp_all_gather
|
||||||
|
|
||||||
|
|
||||||
def gather_and_scale_wrapper(func):
|
def gather_and_scale_wrapper(
|
||||||
|
func: Callable[..., tuple[torch.Tensor | float, Odict]],
|
||||||
|
) -> Callable[..., tuple[torch.Tensor | float, Odict]]:
|
||||||
"""Internal wrapper: gather the input from multple cards to one card, and scale the loss by the number of cards.
|
"""Internal wrapper: gather the input from multple cards to one card, and scale the loss by the number of cards.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def inner(*args, **kwds):
|
def inner(*args: Any, **kwds: Any) -> tuple[torch.Tensor | float, Odict]:
|
||||||
try:
|
try:
|
||||||
|
|
||||||
for k, v in kwds.items():
|
for k, v in kwds.items():
|
||||||
@@ -32,7 +40,7 @@ class BaseLoss(nn.Module):
|
|||||||
Your loss should also subclass this class.
|
Your loss should also subclass this class.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, loss_term_weight=1.0):
|
def __init__(self, loss_term_weight: float = 1.0) -> None:
|
||||||
"""
|
"""
|
||||||
Initialize the base class.
|
Initialize the base class.
|
||||||
|
|
||||||
@@ -43,7 +51,7 @@ class BaseLoss(nn.Module):
|
|||||||
self.loss_term_weight = loss_term_weight
|
self.loss_term_weight = loss_term_weight
|
||||||
self.info = Odict()
|
self.info = Odict()
|
||||||
|
|
||||||
def forward(self, logits, labels):
|
def forward(self, logits: torch.Tensor, labels: torch.Tensor) -> tuple[torch.Tensor, Odict]:
|
||||||
"""
|
"""
|
||||||
The default forward function.
|
The default forward function.
|
||||||
|
|
||||||
@@ -56,4 +64,4 @@ class BaseLoss(nn.Module):
|
|||||||
Returns:
|
Returns:
|
||||||
tuple of loss and info.
|
tuple of loss and info.
|
||||||
"""
|
"""
|
||||||
return .0, self.info
|
return torch.tensor(0.0, device=logits.device), self.info
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
|
from opengait.evaluation.metric import mean_iou
|
||||||
|
from opengait.utils.common import Odict
|
||||||
|
|
||||||
from .base import BaseLoss
|
from .base import BaseLoss
|
||||||
from evaluation import mean_iou
|
|
||||||
|
|
||||||
|
|
||||||
class BinaryCrossEntropyLoss(BaseLoss):
|
class BinaryCrossEntropyLoss(BaseLoss):
|
||||||
def __init__(self, loss_term_weight=1.0, eps=1.0e-9):
|
eps: float
|
||||||
|
|
||||||
|
def __init__(self, loss_term_weight: float = 1.0, eps: float = 1.0e-9) -> None:
|
||||||
super(BinaryCrossEntropyLoss, self).__init__(loss_term_weight)
|
super(BinaryCrossEntropyLoss, self).__init__(loss_term_weight)
|
||||||
self.eps = eps
|
self.eps = eps
|
||||||
|
|
||||||
def forward(self, logits, labels):
|
def forward(self, logits: torch.Tensor, labels: torch.Tensor) -> tuple[torch.Tensor, Odict]:
|
||||||
"""
|
"""
|
||||||
logits: [n, 1, h, w]
|
logits: [n, 1, h, w]
|
||||||
labels: [n, 1, h, w]
|
labels: [n, 1, h, w]
|
||||||
|
|||||||
@@ -1,29 +1,68 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
import torch
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
|
|
||||||
|
from opengait.utils.common import Odict
|
||||||
|
|
||||||
from .base import BaseLoss
|
from .base import BaseLoss
|
||||||
|
|
||||||
|
|
||||||
class CrossEntropyLoss(BaseLoss):
|
class CrossEntropyLoss(BaseLoss):
|
||||||
def __init__(self, scale=2**4, label_smooth=True, eps=0.1, loss_term_weight=1.0, log_accuracy=False):
|
scale: float
|
||||||
|
label_smooth: bool
|
||||||
|
eps: float
|
||||||
|
log_accuracy: bool
|
||||||
|
class_weight: torch.Tensor | None = None
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
scale: float = 2**4,
|
||||||
|
label_smooth: bool = True,
|
||||||
|
eps: float = 0.1,
|
||||||
|
loss_term_weight: float = 1.0,
|
||||||
|
log_accuracy: bool = False,
|
||||||
|
class_weight: Sequence[float] | None = None,
|
||||||
|
) -> None:
|
||||||
super(CrossEntropyLoss, self).__init__(loss_term_weight)
|
super(CrossEntropyLoss, self).__init__(loss_term_weight)
|
||||||
self.scale = scale
|
self.scale = scale
|
||||||
self.label_smooth = label_smooth
|
self.label_smooth = label_smooth
|
||||||
self.eps = eps
|
self.eps = eps
|
||||||
self.log_accuracy = log_accuracy
|
self.log_accuracy = log_accuracy
|
||||||
|
weight_tensor = (
|
||||||
|
None
|
||||||
|
if class_weight is None
|
||||||
|
else torch.as_tensor(class_weight, dtype=torch.float32)
|
||||||
|
)
|
||||||
|
if class_weight is None:
|
||||||
|
self.register_buffer("class_weight", weight_tensor)
|
||||||
|
else:
|
||||||
|
self.register_buffer("class_weight", weight_tensor)
|
||||||
|
|
||||||
def forward(self, logits, labels):
|
def forward(self, logits: torch.Tensor, labels: torch.Tensor) -> tuple[torch.Tensor, Odict]:
|
||||||
"""
|
"""
|
||||||
logits: [n, c, p]
|
logits: [n, c, p]
|
||||||
labels: [n]
|
labels: [n]
|
||||||
"""
|
"""
|
||||||
n, c, p = logits.size()
|
_n, _c, p = logits.size()
|
||||||
logits = logits.float()
|
logits = logits.float()
|
||||||
labels = labels.unsqueeze(1)
|
labels = labels.unsqueeze(1)
|
||||||
|
class_weight = self.class_weight if isinstance(self.class_weight, torch.Tensor) else None
|
||||||
if self.label_smooth:
|
if self.label_smooth:
|
||||||
loss = F.cross_entropy(
|
loss = F.cross_entropy(
|
||||||
logits*self.scale, labels.repeat(1, p), label_smoothing=self.eps)
|
logits * self.scale,
|
||||||
|
labels.repeat(1, p),
|
||||||
|
weight=class_weight,
|
||||||
|
label_smoothing=self.eps,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
loss = F.cross_entropy(logits*self.scale, labels.repeat(1, p))
|
loss = F.cross_entropy(
|
||||||
|
logits * self.scale,
|
||||||
|
labels.repeat(1, p),
|
||||||
|
weight=class_weight,
|
||||||
|
)
|
||||||
self.info.update({'loss': loss.detach().clone()})
|
self.info.update({'loss': loss.detach().clone()})
|
||||||
if self.log_accuracy:
|
if self.log_accuracy:
|
||||||
pred = logits.argmax(dim=1) # [n, p]
|
pred = logits.argmax(dim=1) # [n, p]
|
||||||
|
|||||||
Reference in New Issue
Block a user