3D Volumetric Analysis and Processing
Module: Healthcare AI | Difficulty: Advanced
Volumetric Measurement
where .
3D Convolution
Dice Score for Volumetric Segmentation
Volume Overlap Measures
| Metric | Formula | Range | Sensitivity | |--------|---------|-------|-------------| | Dice | | 0-1 | High | | Jaccard | | 0-1 | High | | Hausdorff | | 0-infty | Medium | | ASSD | | 0-infty | Medium | | Volume Diff | | 0-infty | Low |
import torch
import torch.nn as nn
class ResBlock3D(nn.Module):
def __init__(self, channels):
super().__init__()
self.conv = nn.Sequential(
nn.Conv3d(channels, channels, 3, padding=1),
nn.InstanceNorm3d(channels),
nn.LeakyReLU(0.1, inplace=True),
nn.Conv3d(channels, channels, 3, padding=1),
nn.InstanceNorm3d(channels)
)
self.act = nn.LeakyReLU(0.1, inplace=True)
def forward(self, x):
return self.act(x + self.conv(x))
class VNet3D(nn.Module):
def __init__(self, in_channels=1, num_classes=1):
super().__init__()
self.enc1 = nn.Sequential(
nn.Conv3d(in_channels, 32, 3, padding=1), ResBlock3D(32))
self.enc2 = nn.Sequential(
nn.Conv3d(32, 64, 3, padding=1), ResBlock3D(64))
self.enc3 = nn.Sequential(
nn.Conv3d(64, 128, 3, padding=1), ResBlock3D(128))
self.pool = nn.MaxPool3d(2)
self.bottleneck = nn.Sequential(
nn.Conv3d(128, 256, 3, padding=1), ResBlock3D(256))
self.up3 = nn.ConvTranspose3d(256, 128, 2, stride=2)
self.dec3 = nn.Sequential(
nn.Conv3d(256, 128, 3, padding=1), ResBlock3D(128))
self.up2 = nn.ConvTranspose3d(128, 64, 2, stride=2)
self.dec2 = nn.Sequential(
nn.Conv3d(128, 64, 3, padding=1), ResBlock3D(64))
self.up1 = nn.ConvTranspose3d(64, 32, 2, stride=2)
self.dec1 = nn.Sequential(
nn.Conv3d(64, 32, 3, padding=1), ResBlock3D(32))
self.out_conv = nn.Conv3d(32, num_classes, 1)
def forward(self, x):
e1 = self.enc1(x)
e2 = self.enc2(self.pool(e1))
e3 = self.enc3(self.pool(e2))
b = self.bottleneck(self.pool(e3))
d3 = self.dec3(torch.cat([self.up3(b), e3], dim=1))
d2 = self.dec2(torch.cat([self.up2(d3), e2], dim=1))
d1 = self.dec1(torch.cat([self.up1(d2), e1], dim=1))
return self.out_conv(d1)
model = VNet3D(in_channels=1, num_classes=1)
x = torch.randn(1, 1, 64, 64, 64)
output = model(x)
print(f'Input: {x.shape}, Output: {output.shape}')
param_count = sum(p.numel() for p in model.parameters())
print(f'Parameters: {param_count:,}')
Research Insight: Patch-based training with random patch sampling is critical for 3D medical image segmentation due to GPU memory constraints. Sliding window inference with overlap-add prevents boundary artifacts between patches. The optimal patch size depends on the target organ: larger patches (96x96x96) for whole-organ segmentation, smaller patches (48x48x48) for small lesion detection.