ScoNet_V1

This commit is contained in:
Zzier
2024-06-28 17:34:32 +08:00
parent 01daf44061
commit dc2616c0e0
8 changed files with 6227 additions and 1 deletions
+101
View File
@@ -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
+34
View File
@@ -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
+43 -1
View File
@@ -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 .re_rank import re_ranking
from sklearn.metrics import confusion_matrix, accuracy_score
def de_diag(acc, each_angle=False):
# 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('BG: {}'.format(de_diag(acc[3, :, :, i], True)))
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
+53
View File
@@ -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