Views
No views yet
pip install huggingface-hub torch torchvision pydicom1from huggingface_hub import snapshot_download
2import sys
3import os
4
5# Download model
6model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
7sys.path.append(model_path)
8
9# Import model
10from modeling_sybil_hf import SybilHFWrapper
11from configuration_sybil import SybilConfig
12
13# Initialize
14config = SybilConfig()
15model = SybilHFWrapper(config)
16
17dicom_dir = "path/to/volume"
18dicom_paths = [os.path.join(dicom_dir, f) for f in os.listdir(dicom_dir) if f.endswith('.dcm')]
19
20print(f"Found {len(dicom_paths)} DICOM files for prediction.")
21
22# Get predictions
23output = model(dicom_paths=dicom_paths)
24risk_scores = output.risk_scores.numpy()
25
26# Display results
27print("\nLung Cancer Risk Predictions:")
28print(f"Risk scores shape: {risk_scores.shape}")
29
30# Handle both single and batch predictions
31if risk_scores.ndim == 2:
32 # Batch predictions - take first sample
33 risk_scores = risk_scores[0]
34
35for i, score in enumerate(risk_scores):
36 print(f"Year {i+1}: {float(score)}")
371import requests
2import zipfile
3from io import BytesIO
4import os
5
6# Download demo DICOM files
7def get_demo_data():
8 cache_dir = os.path.expanduser("~/.sybil_demo")
9 demo_dir = os.path.join(cache_dir, "sybil_demo_data")
10
11 if not os.path.exists(demo_dir):
12 print("Downloading demo data...")
13 url = "https://www.dropbox.com/scl/fi/covbvo6f547kak4em3cjd/sybil_example.zip?rlkey=7a13nhlc9uwga9x7pmtk1cf1c&dl=1"
14 response = requests.get(url)
15
16 os.makedirs(cache_dir, exist_ok=True)
17 with zipfile.ZipFile(BytesIO(response.content)) as zf:
18 zf.extractall(cache_dir)
19
20 # Find DICOM files
21 dicom_files = []
22 for root, dirs, files in os.walk(cache_dir):
23 for file in files:
24 if file.endswith('.dcm'):
25 dicom_files.append(os.path.join(root, file))
26
27 return sorted(dicom_files)
28
29# Run demo
30from huggingface_hub import snapshot_download
31import sys
32
33# Load model
34model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
35sys.path.append(model_path)
36
37from modeling_sybil_wrapper import SybilHFWrapper
38from configuration_sybil import SybilConfig
39
40# Initialize and predict
41config = SybilConfig()
42model = SybilHFWrapper(config)
43
44dicom_files = get_demo_data()
45output = model(dicom_paths=dicom_files)
46
47# Show results
48for i, score in enumerate(output.risk_scores.numpy()):
49 print(f"Year {i+1}: {float(score)}")1from huggingface_hub import snapshot_download
2import sys
3import os
4import torch
5import numpy as np
6
7# Download and setup model
8model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
9sys.path.append(model_path)
10
11from modeling_sybil_hf import SybilHFWrapper
12from configuration_sybil import SybilConfig
13
14def extract_embeddings(dicom_paths):
15 """
16 Extract embeddings from the layer after ReLU, before Dropout.
17
18 Args:
19 dicom_paths: List of DICOM file paths
20
21 Returns:
22 numpy array of shape (512,) - averaged embeddings across ensemble
23 """
24 # Initialize model
25 config = SybilConfig()
26 model = SybilHFWrapper(config)
27
28 # Set each model in ensemble to eval mode
29 for m in model.models:
30 m.eval()
31
32 # Storage for embeddings from each model in ensemble
33 all_embeddings = []
34
35 # Register hooks on each model in the ensemble
36 for model_idx, ensemble_model in enumerate(model.models):
37 embeddings_buffer = []
38
39 def create_hook(buffer):
40 def hook(module, input, output):
41 # Capture the output of ReLU layer (before dropout)
42 buffer.append(output.detach().cpu())
43 return hook
44
45 # Register hook on the ReLU layer
46 hook_handle = ensemble_model.relu.register_forward_hook(create_hook(embeddings_buffer))
47
48 # Run forward pass
49 with torch.no_grad():
50 _ = model(dicom_paths=dicom_paths)
51
52 # Remove hook
53 hook_handle.remove()
54
55 # Get the embeddings (should be shape [1, 512])
56 if embeddings_buffer:
57 embedding = embeddings_buffer[0].numpy().squeeze()
58 all_embeddings.append(embedding)
59 print(f"Model {model_idx + 1}: Embedding shape = {embedding.shape}")
60
61 # Average embeddings across ensemble
62 averaged_embedding = np.mean(all_embeddings, axis=0)
63 return averaged_embedding
64
65# Usage
66dicom_dir = "path/to/volume"
67dicom_paths = [os.path.join(dicom_dir, f) for f in os.listdir(dicom_dir) if f.endswith('.dcm')]
68
69embeddings = extract_embeddings(dicom_paths)
70print(f"\nEmbedding vector shape: {embeddings.shape}")
71print(f"Embedding statistics:")
72print(f" Mean: {np.mean(embeddings):.6f}")
73print(f" Std: {np.std(embeddings):.6f}")
74print(f" Min: {np.min(embeddings):.6f}")
75print(f" Max: {np.max(embeddings):.6f}")1import torch
2from huggingface_hub import snapshot_download
3import sys
4
5model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
6sys.path.append(model_path)
7
8from modeling_sybil_hf import SybilHFWrapper
9from configuration_sybil import SybilConfig
10
11config = SybilConfig()
12model = SybilHFWrapper(config)
13
14# Get first model from ensemble for demonstration
15first_model = model.models[0]
16
17# Model architecture flow:
18# Input → image_encoder → pool → relu → dropout → prob_of_failure_layer → Output
19
20def extract_layer_output(model, layer_name, dicom_paths):
21 """
22 Extract output from any layer in the model.
23
24 Args:
25 model: SybilHFWrapper model
26 layer_name: Name of the layer to extract from
27 dicom_paths: List of DICOM file paths
28
29 Returns:
30 Extracted features from the specified layer
31 """
32 features = []
33
34 def hook_fn(module, input, output):
35 features.append(output.detach().cpu())
36
37 # Register hook on the specified layer
38 for m in model.models:
39 layer = dict(m.named_modules())[layer_name]
40 hook_handle = layer.register_forward_hook(hook_fn)
41
42 # Run forward pass
43 with torch.no_grad():
44 _ = model(dicom_paths=dicom_paths)
45
46 # Remove hook
47 hook_handle.remove()
48
49 return features
50
51# Example 1: Extract from image encoder (3D feature maps)
52# Shape: (batch, 512, time, height, width)
53encoder_features = extract_layer_output(model, 'image_encoder', dicom_paths)
54print(f"Image encoder output shape: {encoder_features[0].shape}")
55
56# Example 2: Extract from pooling layer (before ReLU)
57# Shape: (batch, 512)
58pool_features = extract_layer_output(model, 'pool', dicom_paths)
59print(f"Pool layer output shape: {pool_features[0].shape}")
60
61# Example 3: Extract from ReLU layer (before dropout) - RECOMMENDED
62# Shape: (batch, 512)
63relu_features = extract_layer_output(model, 'relu', dicom_paths)
64print(f"ReLU layer output shape: {relu_features[0].shape}")
65
66# Example 4: Extract from dropout layer (before final prediction)
67# Shape: (batch, 512)
68dropout_features = extract_layer_output(model, 'dropout', dicom_paths)
69print(f"Dropout layer output shape: {dropout_features[0].shape}")1def extract_custom_layer(dicom_paths, target_layer_name):
2 """
3 Template for extracting features from any layer.
4
5 Args:
6 dicom_paths: List of DICOM file paths
7 target_layer_name: Name of target layer (e.g., 'relu', 'pool', 'image_encoder')
8
9 Returns:
10 Extracted features averaged across ensemble
11 """
12 from huggingface_hub import snapshot_download
13 import sys
14 import torch
15 import numpy as np
16
17 model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
18 sys.path.append(model_path)
19
20 from modeling_sybil_hf import SybilHFWrapper
21 from configuration_sybil import SybilConfig
22
23 config = SybilConfig()
24 model = SybilHFWrapper(config)
25
26 all_features = []
27
28 for ensemble_model in model.models:
29 ensemble_model.eval()
30 features_buffer = []
31
32 # Get the target layer
33 target_layer = dict(ensemble_model.named_modules())[target_layer_name]
34
35 # Register hook
36 def hook(module, input, output):
37 features_buffer.append(output.detach().cpu())
38
39 hook_handle = target_layer.register_forward_hook(hook)
40
41 # Forward pass
42 with torch.no_grad():
43 _ = model(dicom_paths=dicom_paths)
44
45 hook_handle.remove()
46
47 if features_buffer:
48 all_features.append(features_buffer[0])
49
50 # Average across ensemble
51 averaged_features = torch.stack(all_features).mean(dim=0)
52 return averaged_features.numpy()1from huggingface_hub import snapshot_download
2import sys
3
4model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
5sys.path.append(model_path)
6
7from modeling_sybil_hf import SybilHFWrapper
8from configuration_sybil import SybilConfig
9
10config = SybilConfig()
11model = SybilHFWrapper(config)
12
13# Print configuration
14print("=" * 80)
15print("MODEL CONFIGURATION:")
16print("=" * 80)
17print(config)
18
19# Print ensemble information
20print("\n" + "=" * 80)
21print("ENSEMBLE INFORMATION:")
22print("=" * 80)
23print(f"Number of models in ensemble: {len(model.models)}")
24print(f"Device: {model.device}")
25
26# Print architecture of first model
27print("\n" + "=" * 80)
28print("MODEL ARCHITECTURE (First model in ensemble):")
29print("=" * 80)
30first_model = model.models[0]
31print(first_model)1from huggingface_hub import snapshot_download
2import sys
3
4model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
5sys.path.append(model_path)
6
7from modeling_sybil_hf import SybilHFWrapper
8from configuration_sybil import SybilConfig
9
10config = SybilConfig()
11model = SybilHFWrapper(config)
12
13print("=" * 80)
14print("MODEL PARAMETERS:")
15print("=" * 80)
16
17# Parameters per model in ensemble
18for i, ensemble_model in enumerate(model.models):
19 total_params = sum(p.numel() for p in ensemble_model.parameters())
20 trainable_params = sum(p.numel() for p in ensemble_model.parameters() if p.requires_grad)
21
22 print(f"\nModel {i+1}:")
23 print(f" Total parameters: {total_params:,}")
24 print(f" Trainable parameters: {trainable_params:,}")
25 print(f" Non-trainable parameters: {total_params - trainable_params:,}")
26
27# Total ensemble parameters
28total_ensemble = sum(
29 sum(p.numel() for p in m.parameters())
30 for m in model.models
31)
32print(f"\nTotal ensemble parameters: {total_ensemble:,}")1from huggingface_hub import snapshot_download
2import sys
3
4model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
5sys.path.append(model_path)
6
7from modeling_sybil_hf import SybilHFWrapper
8from configuration_sybil import SybilConfig
9
10config = SybilConfig()
11model = SybilHFWrapper(config)
12first_model = model.models[0]
13
14print("=" * 80)
15print("MODEL COMPONENTS:")
16print("=" * 80)
17
18# Print each component with parameter count
19for name, module in first_model.named_children():
20 num_params = sum(p.numel() for p in module.parameters())
21 print(f"{name}: {module.__class__.__name__} ({num_params:,} parameters)")
22
23print("\n" + "=" * 80)
24print("DETAILED LAYER NAMES:")
25print("=" * 80)
26
27# Print all named modules (including nested layers)
28for name, module in first_model.named_modules():
29 if name: # Skip the root module
30 print(f" {name}: {module.__class__.__name__}")Input (3D CT Volume)
↓
image_encoder (R3D-18 backbone)
- 3D convolutional neural network
- Pretrained on Kinetics-400
- Output: (batch, 512, time, height, width)
↓
pool (MultiAttentionPool)
- Attention-based pooling mechanisms
- Combines multiple pooling strategies
- Output: (batch, 512)
↓
relu (ReLU activation)
- Non-linear activation
- Output: (batch, 512) ← EMBEDDING EXTRACTION POINT
↓
dropout (Dropout layer)
- Regularization (p=0.0 in inference)
- Output: (batch, 512)
↓
prob_of_failure_layer (CumulativeProbabilityLayer)
- Hazard function prediction
- Output: (batch, 6) - one score per year
↓
sigmoid (applied post-forward)
↓
Risk Scores (final output)1def print_model_summary(model):
2 """Print a detailed summary of the model architecture."""
3 from huggingface_hub import snapshot_download
4 import sys
5
6 model_path = snapshot_download(repo_id="Lab-Rasool/sybil")
7 sys.path.append(model_path)
8
9 from modeling_sybil_hf import SybilHFWrapper
10 from configuration_sybil import SybilConfig
11
12 config = SybilConfig()
13 model = SybilHFWrapper(config)
14 first_model = model.models[0]
15
16 print(f"{'Layer Name':<40} {'Type':<30} {'Parameters':>15}")
17 print("=" * 85)
18
19 total_params = 0
20 for name, module in first_model.named_modules():
21 if name: # Skip root
22 num_params = sum(p.numel() for p in module.parameters())
23 if num_params > 0:
24 print(f"{name:<40} {module.__class__.__name__:<30} {num_params:>15,}")
25 total_params += num_params
26
27 print("=" * 85)
28 print(f"{'TOTAL':<40} {'':<30} {total_params:>15,}")
29
30# Usage
31print_model_summary(model)| Dataset | 1-Year AUC | 6-Year AUC | Sample Size |
|---|---|---|---|
| NLST Test | 0.94 | 0.86 | ~15,000 |
| MGH | 0.86 | 0.75 | ~12,000 |
| CGMH Taiwan | 0.94 | 0.80 | ~8,000 |
1@article{mikhael2023sybil,
2 title={Sybil: a validated deep learning model to predict future lung cancer risk from a single low-dose chest computed tomography},
3 author={Mikhael, Peter G and Wohlwend, Jeremy and Yala, Adam and others},
4 journal={Journal of Clinical Oncology},
5 volume={41},
6 number={12},
7 pages={2191--2200},
8 year={2023},
9 publisher={American Society of Clinical Oncology}
10}sys.path.append(model_path)pip install torch torchvision pydicom sybil huggingface-hub1import pydicom
2dcm = pydicom.dcmread("your_file.dcm") # Test single file1import torch
2device = 'cuda' if torch.cuda.is_available() else 'cpu'