ScoNet_V1
This commit is contained in:
@@ -0,0 +1,101 @@
|
|||||||
|
data_cfg:
|
||||||
|
dataset_name: Scoliosis1K
|
||||||
|
dataset_root: your_path_of_Scoliosis1K-Released-pkl
|
||||||
|
dataset_partition: ./datasets/Scoliosis1K/Scoliosis1K_***.json
|
||||||
|
num_workers: 1
|
||||||
|
remove_no_gallery: false # Remove probe if no gallery for it
|
||||||
|
test_dataset_name: Scoliosis
|
||||||
|
|
||||||
|
evaluator_cfg:
|
||||||
|
enable_float16: true
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 20000
|
||||||
|
save_name: ScoNet
|
||||||
|
eval_func: evaluate_scoliosis
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: false
|
||||||
|
batch_size: 8
|
||||||
|
sample_type: all_ordered # all indicates whole sequence used to test, while ordered means input sequence by its natural order; Other options: fixed_unordered
|
||||||
|
frames_all_limit: 720 # limit the number of sampled frames to prevent out of memory
|
||||||
|
metric: euc # cos
|
||||||
|
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
|
||||||
|
channels: # Layers configuration for automatically model construction
|
||||||
|
- 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: # Learning Rate Reduction at each milestones
|
||||||
|
- 10000
|
||||||
|
- 14000
|
||||||
|
- 18000
|
||||||
|
scheduler: MultiStepLR
|
||||||
|
trainer_cfg:
|
||||||
|
enable_float16: true # half_percesion float for memory reduction and speedup
|
||||||
|
fix_BN: false
|
||||||
|
with_test: false
|
||||||
|
log_iter: 100
|
||||||
|
restore_ckpt_strict: true
|
||||||
|
restore_hint: 0
|
||||||
|
save_iter: 20000
|
||||||
|
save_name: ScoNet
|
||||||
|
sync_BN: true
|
||||||
|
total_iter: 20000
|
||||||
|
sampler:
|
||||||
|
batch_shuffle: true
|
||||||
|
batch_size:
|
||||||
|
- 8 # TripletSampler, batch_size[0] indicates Number of Identity
|
||||||
|
- 8 # batch_size[1] indicates Samples sequqnce for each Identity
|
||||||
|
frames_num_fixed: 30 # fixed frames number for training
|
||||||
|
sample_type: fixed_unordered # fixed control input frames number, unordered for controlling order of input tensor; Other options: unfixed_ordered or all_ordered
|
||||||
|
type: TripletSampler
|
||||||
|
transform:
|
||||||
|
- type: BaseSilCuttingTransform
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Tutorial for [Scoliosis1K](https://zhouzi180.github.io/Scoliosis1K)
|
||||||
|
|
||||||
|
## Download the Scoliosis1K dataset
|
||||||
|
Download the dataset from the [link](https://zhouzi180.github.io/Scoliosis1K).
|
||||||
|
decompress these two file by following command:
|
||||||
|
```shell
|
||||||
|
unzip -P password Scoliosis1K-pkl.zip | xargs -n1 tar xzvf
|
||||||
|
```
|
||||||
|
password should be obtained by signing [agreement](https://zhouzi180.github.io/Scoliosis1K/static/resources/Scoliosis1KAgreement.pdf) and sending to email (12331257@mail.sustech.edu.cn)
|
||||||
|
|
||||||
|
Then you will get Scoliosis1K formatted as:
|
||||||
|
```
|
||||||
|
DATASET_ROOT/
|
||||||
|
00000 (subject)/
|
||||||
|
positive (category)/
|
||||||
|
000-180 (view)/
|
||||||
|
000.pkl (contains all frames)
|
||||||
|
......
|
||||||
|
```
|
||||||
|
## Train the dataset
|
||||||
|
Modify the `dataset_root` in `configs/sconet/sconet_scoliosis1k.yaml`, and then run this command:
|
||||||
|
```shell
|
||||||
|
CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 opengait/main.py --cfgs configs/sconet/sconet_scoliosis1k.yaml --phase train
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Process from RAW dataset
|
||||||
|
|
||||||
|
### Preprocess the dataset (Optional)
|
||||||
|
Download the raw dataset from the [official link](https://zhouzi180.github.io/Scoliosis1K). You will get two compressed files, i.e. `Scoliosis1K-raw.zip`, and `Scoliosis1K-pkl.zip`.
|
||||||
|
We recommend using our provided pickle files for convenience, or process raw dataset into pickle by this command:
|
||||||
|
```shell
|
||||||
|
python datasets/pretreatment.py --input_path Scoliosis1K_raw --output_path Scoliosis1K-pkl
|
||||||
|
```
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ from utils import get_msg_mgr, mkdir
|
|||||||
|
|
||||||
from .metric import mean_iou, cuda_dist, compute_ACC_mAP, evaluate_rank, evaluate_many
|
from .metric import mean_iou, cuda_dist, compute_ACC_mAP, evaluate_rank, evaluate_many
|
||||||
from .re_rank import re_ranking
|
from .re_rank import re_ranking
|
||||||
|
from sklearn.metrics import confusion_matrix, accuracy_score
|
||||||
|
|
||||||
def de_diag(acc, each_angle=False):
|
def de_diag(acc, each_angle=False):
|
||||||
# Exclude identical-view cases
|
# Exclude identical-view cases
|
||||||
@@ -415,3 +415,45 @@ def evaluate_CCPG(data, dataset, metric='euc'):
|
|||||||
msg_mgr.log_info('DN: {}'.format(de_diag(acc[2, :, :, i], True)))
|
msg_mgr.log_info('DN: {}'.format(de_diag(acc[2, :, :, i], True)))
|
||||||
msg_mgr.log_info('BG: {}'.format(de_diag(acc[3, :, :, i], True)))
|
msg_mgr.log_info('BG: {}'.format(de_diag(acc[3, :, :, i], True)))
|
||||||
return result_dict
|
return result_dict
|
||||||
|
|
||||||
|
def evaluate_scoliosis(data, dataset, metric='euc'):
|
||||||
|
msg_mgr = get_msg_mgr()
|
||||||
|
|
||||||
|
feature, label, class_id, view = data['embeddings'], data['labels'], data['types'], data['views']
|
||||||
|
|
||||||
|
label = np.array(label)
|
||||||
|
class_id = np.array(class_id)
|
||||||
|
|
||||||
|
# Update class_id with integer labels based on status
|
||||||
|
class_id_int = np.array([1 if status == 'positive' else 2 if status == 'critical' else 0 for status in class_id])
|
||||||
|
print('class_id=', class_id_int)
|
||||||
|
|
||||||
|
features = np.array(feature)
|
||||||
|
c_id_int = np.argmax(features.mean(-1), axis=-1)
|
||||||
|
print('predicted_labels', c_id_int)
|
||||||
|
|
||||||
|
# Calculate sensitivity and specificity
|
||||||
|
cm = confusion_matrix(class_id_int, c_id_int, labels=[0, 1, 2])
|
||||||
|
FP = cm.sum(axis=0) - np.diag(cm)
|
||||||
|
FN = cm.sum(axis=1) - np.diag(cm)
|
||||||
|
TP = np.diag(cm)
|
||||||
|
TN = cm.sum() - (FP + FN + TP)
|
||||||
|
|
||||||
|
# Sensitivity, hit rate, recall, or true positive rate
|
||||||
|
TPR = TP / (TP + FN)
|
||||||
|
# Specificity or true negative rate
|
||||||
|
TNR = TN / (TN + FP)
|
||||||
|
accuracy = accuracy_score(class_id_int, c_id_int)
|
||||||
|
|
||||||
|
result_dict = {}
|
||||||
|
result_dict["scalar/test_accuracy/"] = accuracy
|
||||||
|
result_dict["scalar/test_sensitivity/"] = TPR
|
||||||
|
result_dict["scalar/test_specificity/"] = TNR
|
||||||
|
|
||||||
|
# Printing the sensitivity and specificity
|
||||||
|
for i, cls in enumerate(['Positive']):
|
||||||
|
print(f"{cls} Sensitivity (Recall): {TPR[i] * 100:.2f}%")
|
||||||
|
print(f"{cls} Specificity: {TNR[i] * 100:.2f}%")
|
||||||
|
print(f"Accuracy: {accuracy * 100:.2f}%")
|
||||||
|
|
||||||
|
return result_dict
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import torch
|
||||||
|
|
||||||
|
from ..base_model import BaseModel
|
||||||
|
from ..modules import SetBlockWrapper, HorizontalPoolingPyramid, PackSequenceWrapper, SeparateFCs, SeparateBNNecks
|
||||||
|
|
||||||
|
from einops import rearrange
|
||||||
|
import numpy as np
|
||||||
|
class ScoNet(BaseModel):
|
||||||
|
|
||||||
|
def build_network(self, model_cfg):
|
||||||
|
self.Backbone = self.get_backbone(model_cfg['backbone_cfg'])
|
||||||
|
self.Backbone = SetBlockWrapper(self.Backbone)
|
||||||
|
self.FCs = SeparateFCs(**model_cfg['SeparateFCs'])
|
||||||
|
self.BNNecks = SeparateBNNecks(**model_cfg['SeparateBNNecks'])
|
||||||
|
self.TP = PackSequenceWrapper(torch.max)
|
||||||
|
self.HPP = HorizontalPoolingPyramid(bin_num=model_cfg['bin_num'])
|
||||||
|
|
||||||
|
def forward(self, inputs):
|
||||||
|
ipts, labs, class_id, _, seqL = inputs
|
||||||
|
|
||||||
|
class_id_int = np.array([1 if status == 'positive' else 2 if status == 'critical' else 0 for status in class_id])
|
||||||
|
class_id = torch.tensor(class_id_int).cuda()
|
||||||
|
|
||||||
|
sils = ipts[0]
|
||||||
|
if len(sils.size()) == 4:
|
||||||
|
sils = sils.unsqueeze(1)
|
||||||
|
else:
|
||||||
|
sils = rearrange(sils, 'n s c h w -> n c s h w')
|
||||||
|
|
||||||
|
del ipts
|
||||||
|
outs = self.Backbone(sils) # [n, c, s, h, w]
|
||||||
|
|
||||||
|
# Temporal Pooling, TP
|
||||||
|
outs = self.TP(outs, seqL, options={"dim": 2})[0] # [n, c, h, w]
|
||||||
|
# Horizontal Pooling Matching, HPM
|
||||||
|
feat = self.HPP(outs) # [n, c, p]
|
||||||
|
|
||||||
|
embed_1 = self.FCs(feat) # [n, c, p]
|
||||||
|
embed_2, logits = self.BNNecks(embed_1) # [n, c, p]
|
||||||
|
embed = embed_1
|
||||||
|
retval = {
|
||||||
|
'training_feat': {
|
||||||
|
'triplet': {'embeddings': embed, 'labels': labs},
|
||||||
|
'softmax': {'logits': logits, 'labels': class_id},
|
||||||
|
},
|
||||||
|
'visual_summary': {
|
||||||
|
'image/sils': rearrange(sils,'n c s h w -> (n s) c h w')
|
||||||
|
},
|
||||||
|
'inference_feat': {
|
||||||
|
'embeddings': logits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval
|
||||||
Reference in New Issue
Block a user