7 Revolutionary Breakthroughs in AI Medical Imaging: The Good, the Bad, and the Future of RIIR

Illustration showing a futuristic AI-powered medical imaging analyzing a brain MRI, with digital neural network pathways glowing in blue, symbolizing the Recurrent Inference Image Registration (RIIR) process.

In the rapidly evolving world of medical imaging, a groundbreaking new technology is emerging that promises to redefine how doctors align and analyze patient scans. Meet the Recurrent Inference Image Registration (RIIR) network—a revolutionary deep learning framework that’s not only faster and more accurate than traditional methods but also works with dramatically less data. This innovation, detailed in a recent Medical Image Analysis journal publication, could be the missing link between cutting-edge AI and practical, real-world clinical use.

But is it too good to be true? While the benefits are profound, there are still challenges to overcome. In this article, we’ll explore 7 key breakthroughs powered by RIIR—highlighting both the positive advancements and the negative limitations—so you can understand what this means for the future of healthcare, diagnostics, and artificial intelligence.


1. The Problem: Why Traditional Image Registration Falls Short

Medical image registration is the process of aligning two or more images—such as MRI or CT scans—taken at different times, from different angles, or using different modalities. It’s essential for:

  • Tracking tumor growth
  • Planning surgery
  • Comparing brain changes in neurodegenerative diseases
  • Quantifying heart function over time

Traditionally, this task has been solved using optimization-based methods like Elastix. These approaches iteratively adjust a transformation until images match, guided by similarity metrics and regularization constraints.

However, they come with major drawbacks:

  • Extremely slow—can take minutes to hours per scan
  • Computationally heavy, especially for high-resolution 3D images
  • ❌ Not ideal for real-time applications like image-guided surgery

On the flip side, deep learning-based one-step methods (like VoxelMorph) predict the full transformation in a single forward pass—making them fast. But they often lack accuracy, especially with large deformations, and require massive training datasets to generalize well.

This is where RIIR steps in—with a powerful hybrid approach that combines the best of both worlds.


2. The Solution: How RIIR Redefines Medical Image Registration

The Recurrent Inference Image Registration (RIIR) network, developed by researchers from Delft University of Technology and NIH, introduces a novel meta-learning framework inspired by the Recurrent Inference Machine (RIM).

Unlike traditional deep learning models that predict a transformation all at once, RIIR iteratively refines the registration over multiple steps—just like an optimization algorithm—but learns how to optimize from data.

✅ Key Innovation: Learning the Update Rule

Instead of hard-coding optimization steps, RIIR learns the update rule itself. At each iteration t , it computes a small incremental update Δϕt​ to the current transformation ϕt :

\[ \phi_{t+1} = \phi_t + \Delta \phi_t \]

This update is calculated by a recurrent neural network (specifically, a Convolutional GRU) that takes as input:

  • Current transformation ϕt
  • Gradient of the similarity loss ∇ϕt​​Linner​
  • Warped moving image Imov​∘ϕt
  • Fixed image Ifix​

This rich input allows RIIR to make data-efficient, context-aware corrections at each step—leading to higher accuracy with far less training data.


3. Breakthrough #1: Unmatched Data Efficiency (The Good)

One of the biggest hurdles in medical AI is data scarcity. Unlike consumer tech, hospitals can’t collect millions of labeled scans due to privacy, cost, and variability.

RIIR shines here.

In experiments across brain MRI (OASIS), lung CT (NLST), and cardiac MRI (mSASHA) datasets, RIIR outperformed all deep learning baselines—even when trained on just 5% of the available data.

METHODDICE SCORE (OASIS, 5% DATA)TRE (NLST, 5% DATA)
VoxelMorph0.621 ± 0.0434.12 ± 2.87 mm
LapIRN0.643 ± 0.0383.45 ± 2.11 mm
GraDIRN0.658 ± 0.0353.01 ± 2.33 mm
RIIR0.689 ± 0.0312.48 ± 1.89 mm

Source: Zhang et al., Medical Image Analysis (2025)

This data efficiency is a game-changer. It means RIIR can be trained and deployed in smaller hospitals or rare disease clinics where large datasets don’t exist.


4. Breakthrough #2: Hidden States Boost Performance (The Good)

Most iterative deep learning methods (like RCVM or GraDIRN) lack memory—each step operates independently. RIIR, however, uses hidden states ht​ in its ConvGRU layers to retain information across iterations.

Think of it like a doctor remembering what they’ve already adjusted in a scan—so they don’t repeat mistakes.

The ablation study confirmed: including hidden states improves accuracy, especially in complex cases like lung CT with large respiratory motion.

“Our findings reveal that the presence of hidden states… contributes positively to the performance of our model.” – Zhang et al.

Despite this, the memory overhead is minimal—only ~800 MB more VRAM on average—making it practical for clinical GPUs.


5. Breakthrough #3: Gradient Input = Smarter Learning (The Good)

RIIR uniquely incorporates the gradient of the inner lossϕt​​ Lsim​ as direct input to the network.

This is a subtle but powerful difference from methods like GraDIRN, where the gradient is added outside the network.

By feeding the gradient into the neural network, RIIR can learn how to respond to optimization signals—making it more adaptive and robust.

As the paper states:

“RIIR uses the gradient of inner loss as the neural network input to calculate the incremental update.”

This design leads to faster convergence and better generalization, especially when training data is limited.


6. The Challenge: High VRAM Usage (The Negative)

Despite its brilliance, RIIR isn’t perfect.

Because it’s recurrent, it must store intermediate states for each iteration during training. This causes VRAM usage to grow linearly with the number of inference steps T .

INFERENCE STEPS (T)VRAM USAGEINFERENCE TIME
4~8 GB0.40 s
6~12 GB0.55 s
12~24 GB1.12 s

While accuracy improves with more steps, not all clinics have access to high-end GPUs like the NVIDIA RTX 4090 used in the study.

This is a real-world limitation that could slow adoption in resource-limited settings.


7. Breakthrough #4: Superior Accuracy Across Modalities (The Good)

RIIR wasn’t tested on just one type of scan—it was validated across three diverse medical imaging tasks:

  1. Brain MRI (OASIS): Inter-subject registration for neuroimaging studies
  2. Lung CT (NLST): Intra-subject registration for respiratory motion correction
  3. Cardiac MRI (mSASHA): Quantitative mapping with contrast variation

In all cases, RIIR matched or exceeded state-of-the-art methods.

Brain MRI Results (OASIS, 100% Data)

  • Dice Score: 0.756 (vs. 0.753 for RCVM)
  • Hausdorff Distance: 3.48 mm (on par with best)
  • Smoothness: Low folding rate (0.011% negative Jacobian)

Lung CT Results (NLST, 100% Data)

  • TRE (Target Registration Error): 2.21 mm (best among all)
  • Dice (Lung Lobe): 0.966
  • Robustness: Handles large deformations from breathing

Cardiac MRI Results (mSASHA)

  • PCA-based Metric DPCA1​ : 0.36 (close to RCVM’s 0.32)
  • Stability: Consistent alignment across time series

These results prove RIIR is not a niche solution—it’s a generalizable framework for medical image registration.


How RIIR Works: The Math Behind the Magic

Let’s dive into the core equations that power RIIR.

The registration problem is formulated as:

\[ \hat{\phi} = \arg_{\phi} \min \; \mathcal{L}_{\text{sim}}\big(I_{\text{mov}} \circ \phi, I_{\text{fix}}\big) + \lambda \, \mathcal{L}_{\text{reg}}(\phi) \]

RIIR solves this iteratively. At each step t , it computes:

\[ \Delta \phi_{t, h_{t+1}} = g_{\theta}\big( \phi_t, \nabla_{\phi_t} L_{\text{inner}}, I_{\text{mov}} \circ \phi_t, I_{\text{fix}}, h_t \big) \] \[ \phi_{t+1} = \phi_t + \Delta \phi_t \]

The network gθ​ is trained using an outer loss that combines performance across all steps:

\[ L_{\text{outer}}(\theta) = \sum_{t=1}^{T} w_t \Big( L_{\text{sim}}\big( I_{\text{mov}} \circ \phi_t, \; I_{\text{fix}} \big) + \lambda \, L_{\text{reg}}(\phi_t) \Big) \]

This multi-step loss ensures early iterations contribute to learning—unlike methods that only use the final output.


🆚 RIIR vs. The Competition: A Quick Comparison

METHODSPEEDACCURACYDATA-EFFICIENCYMULTI-STEPHIDDEN-STATES
RIIRFast⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
VoxelMorph⚡ Fastest⭐⭐⭐⭐⭐
LapIRNFast⭐⭐⭐⭐⭐⭐⭐
GraDIRNFast⭐⭐⭐⭐⭐⭐⭐
RCVMSlow⭐⭐⭐⭐⭐⭐⭐⭐
Elastix❌ Slow⭐⭐⭐N/A (no training)

RIIR stands out by combining high accuracy, data efficiency, and smart iterative refinement.


Limitations and Future Work (The Negative)

While RIIR is a major leap forward, the authors acknowledge its current limitations:

  • No multi-resolution design (unlike LapIRN), which could improve large deformation handling
  • High VRAM usage due to recurrent steps
  • Fixed architecture—could benefit from attention mechanisms or dilated convolutions

Future versions may include:

  • Adaptive step scheduling
  • Semi-supervised learning
  • Physics-informed regularization

Why This Matters: The Bigger Picture

RIIR isn’t just another AI model—it’s a paradigm shift in how we think about medical image analysis.

By combining meta-learning, recurrent inference, and gradient-aware updates, it bridges the gap between traditional optimization and deep learning.

This means:

  • Faster, more accurate diagnoses
  • Better treatment planning
  • Feasible AI deployment in data-scarce environments
  • Potential extension to other high-dimensional optimization problems

Call to Action: Join the AI Medical Revolution

The future of medicine is intelligent, adaptive, and data-efficient. RIIR is a shining example of how AI can be both powerful and practical.

👉 Want to explore RIIR yourself? The authors have made their code publicly available on GitLab:
https://gitlab.tudelft.nl/ai4medicalimaging/riir-public

Whether you’re a researcher, clinician, or developer, now is the time to get involved. Download the code, run the experiments, and see how RIIR can transform your work.

Read the complete Paper: Recurrent inference machine for medical image registration

Share this article with your team, comment below with your thoughts on AI in healthcare, and subscribe for more deep dives into cutting-edge medical AI.

Together, we can build a future where every patient benefits from smarter, faster, and more accurate imaging.

Here is the end-to-end Python code for the Recurrent Inference Image Registration model proposed in the paper.

# Recurrent Inference Machine for Medical Image Registration (RIIR)
# Implementation based on the paper by Zhang, Y., et al. (2025)
# "Recurrent inference machine for medical image registration"
# Medical Image Analysis, 106, 103748.

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

# -----------------------------------------------------------------------------
# 1. Convolutional GRU (ConvGRU) Cell
# -----------------------------------------------------------------------------
# This is a key component of the RIIR Cell, allowing it to maintain a spatial
# memory (hidden state) across iterations.
class ConvGRU(nn.Module):
    """
    Convolutional GRU cell.
    
    Args:
        input_dim (int): Number of channels in the input tensor.
        hidden_dim (int): Number of channels in the hidden state.
        kernel_size (int): Size of the convolutional kernel.
    """
    def __init__(self, input_dim, hidden_dim, kernel_size):
        super(ConvGRU, self).__init__()
        self.hidden_dim = hidden_dim
        padding = kernel_size // 2
        
        # Convolution for reset and update gates
        self.conv_gates = nn.Conv2d(input_dim + hidden_dim, 2 * hidden_dim, kernel_size, padding=padding)
        # Convolution for the candidate hidden state
        self.conv_candidate = nn.Conv2d(input_dim + hidden_dim, hidden_dim, kernel_size, padding=padding)

    def forward(self, x, h):
        """
        Forward pass of the ConvGRU.
        
        Args:
            x (torch.Tensor): Input tensor of shape (B, C_in, H, W).
            h (torch.Tensor): Hidden state from previous time step of shape (B, C_hid, H, W).
            
        Returns:
            torch.Tensor: New hidden state of shape (B, C_hid, H, W).
        """
        if h is None:
            h = torch.zeros(x.size(0), self.hidden_dim, x.size(2), x.size(3), device=x.device)
            
        # Concatenate input and hidden state
        combined = torch.cat([x, h], dim=1)
        
        # Calculate reset and update gates
        gates = self.conv_gates(combined)
        reset_gate, update_gate = torch.chunk(gates, 2, dim=1)
        
        reset_gate = torch.sigmoid(reset_gate)
        update_gate = torch.sigmoid(update_gate)
        
        # Calculate candidate hidden state
        reset_hidden = torch.cat([x, reset_gate * h], dim=1)
        candidate = torch.tanh(self.conv_candidate(reset_hidden))
        
        # Calculate new hidden state
        new_h = (1 - update_gate) * h + update_gate * candidate
        
        return new_h

# -----------------------------------------------------------------------------
# 2. RIIR Cell (The Core Recurrent Update Network g_theta)
# -----------------------------------------------------------------------------
# This is the main network component that predicts the incremental deformation
# field at each step. It has a U-Net like architecture with ConvGRU units.
# Corresponds to the "RIIR Cell" in Figure 1 of the paper.
class RIIR_Cell(nn.Module):
    """
    The recurrent update network g_theta, implemented as a U-Net like
    architecture with ConvGRU units.
    
    Args:
        input_channels (int): Number of input channels.
        hidden_channels (int): Number of channels for the ConvGRU hidden states.
    """
    def __init__(self, input_channels=6, hidden_channels=32):
        super(RIIR_Cell, self).__init__()

        # --- Encoder ---
        self.enc1 = self.conv_block(input_channels, 16)
        self.enc2 = self.conv_block(16, 32)
        self.pool = nn.MaxPool2d(2)

        # --- ConvGRU Layers ---
        # As per the paper, two ConvGRU layers are used to maintain hidden states.
        self.conv_gru1 = ConvGRU(32, hidden_channels, 3)
        self.conv_gru2 = ConvGRU(hidden_channels, hidden_channels, 3)

        # --- Decoder ---
        self.up1 = nn.ConvTranspose2d(hidden_channels, 16, 2, stride=2)
        self.dec1 = self.conv_block(32, 16) # Skip connection from enc1
        
        # --- Output Layer ---
        # Predicts the incremental displacement field (delta_phi)
        self.output_conv = nn.Conv2d(16, 2, kernel_size=3, padding=1)
        # Initialize the output layer weights to a small value for stability
        self.output_conv.weight.data.fill_(0)
        self.output_conv.bias.data.fill_(0)

    def conv_block(self, in_channels, out_channels):
        return nn.Sequential(
            nn.Conv2d(in_channels, out_channels, 3, padding=1),
            nn.LeakyReLU(0.2, inplace=True)
        )

    def forward(self, x, h1, h2):
        """
        Forward pass of the RIIR Cell.
        
        Args:
            x (torch.Tensor): Concatenated input tensor.
            h1 (torch.Tensor): Hidden state for the first ConvGRU layer.
            h2 (torch.Tensor): Hidden state for the second ConvGRU layer.
            
        Returns:
            Tuple[torch.Tensor, torch.Tensor, torch.Tensor]: 
                - delta_phi: The predicted incremental displacement field.
                - new_h1: The updated hidden state for the first ConvGRU.
                - new_h2: The updated hidden state for the second ConvGRU.
        """
        # Encoder
        e1 = self.enc1(x)
        e2 = self.pool(e1)
        e2 = self.enc2(e2)

        # Recurrent block
        new_h1 = self.conv_gru1(e2, h1)
        new_h2 = self.conv_gru2(new_h1, h2)

        # Decoder with skip connection
        d1 = self.up1(new_h2)
        d1 = torch.cat([d1, e1], dim=1)
        d1 = self.dec1(d1)
        
        # Output
        delta_phi = self.output_conv(d1)
        
        return delta_phi, new_h1, new_h2

# -----------------------------------------------------------------------------
# 3. Spatial Transformer Network (STN)
# -----------------------------------------------------------------------------
# This function applies the deformation field to an image.
class SpatialTransformer(nn.Module):
    """
    2D Spatial Transformer Network to warp images.
    """
    def __init__(self, size):
        super(SpatialTransformer, self).__init__()
        self.size = size
        # Create a sampling grid
        vectors = [torch.arange(0, s) for s in size]
        grids = torch.meshgrid(vectors)
        grid = torch.stack(grids)
        grid = torch.unsqueeze(grid, 0)
        grid = grid.type(torch.FloatTensor)
        self.register_buffer('grid', grid)

    def forward(self, src, flow):
        """
        Applies a displacement field (flow) to a source image.
        
        Args:
            src (torch.Tensor): The source image to be warped.
            flow (torch.Tensor): The displacement field.
            
        Returns:
            torch.Tensor: The warped image.
        """
        new_locs = self.grid + flow
        shape = flow.shape[2:]

        # Need to normalize grid values to [-1, 1] for grid_sample
        for i in range(len(shape)):
            new_locs[:, i, ...] = 2 * (new_locs[:, i, ...] / (shape[i] - 1) - 0.5)

        new_locs = new_locs.permute(0, 2, 3, 1)
        new_locs = new_locs[..., [1, 0]] # Swap x and y for grid_sample

        return F.grid_sample(src, new_locs, align_corners=True, padding_mode="border")


# -----------------------------------------------------------------------------
# 4. The Main RIIR Model
# -----------------------------------------------------------------------------
# This class wraps the RIIR_Cell and handles the iterative registration process.
class RIIR(nn.Module):
    """
    The main RIIR model that performs iterative image registration.
    
    Args:
        img_size (tuple): The size of the input images (H, W).
        n_steps (int): The number of recurrent steps (T).
        cell_hidden_channels (int): Number of hidden channels in the RIIR_Cell.
    """
    def __init__(self, img_size=(128, 128), n_steps=6, cell_hidden_channels=32):
        super(RIIR, self).__init__()
        self.n_steps = n_steps
        self.img_size = img_size
        
        # Input channels: phi (2), grad_L_inner (2), I_mov_warped (1), I_fix (1)
        input_channels = 2 + 2 + 1 + 1 
        
        self.riir_cell = RIIR_Cell(input_channels=input_channels, hidden_channels=cell_hidden_channels)
        self.stn = SpatialTransformer(img_size)

    def forward(self, I_mov, I_fix):
        """
        Performs end-to-end registration.
        
        Args:
            I_mov (torch.Tensor): The moving image.
            I_fix (torch.Tensor): The fixed image.
            
        Returns:
            Tuple[list, list]:
                - phi_list: List of total deformation fields at each step.
                - warped_list: List of warped moving images at each step.
        """
        batch_size = I_mov.size(0)
        
        # Initialize deformation field (phi) and hidden states
        phi = torch.zeros(batch_size, 2, self.img_size[0], self.img_size[1], device=I_mov.device)
        h1, h2 = None, None
        
        phi_list = []
        warped_list = []
        
        for t in range(self.n_steps):
            # Warp the moving image with the current deformation field
            I_mov_warped = self.stn(I_mov, phi)
            
            # --- Calculate Inner Loss Gradient (as per Eq. 10) ---
            # We use MSE as the similarity metric for this example (L_inner)
            I_mov_warped.requires_grad_(True)
            inner_loss = F.mse_loss(I_mov_warped, I_fix)
            
            # The gradient of the inner loss w.r.t. the warped image
            # This is part of the input to the RIIR cell.
            # We need to calculate the gradient w.r.t phi, not I_mov_warped.
            # For simplicity, let's approximate this by gradient w.r.t. warped image.
            # A more accurate implementation would require a custom autograd function
            # to backprop through the STN to get the gradient w.r.t. phi.
            
            # Let's compute gradient w.r.t. phi directly
            phi.requires_grad_(True)
            # Re-warp to build computation graph from phi
            I_mov_warped_for_grad = self.stn(I_mov, phi)
            inner_loss_for_grad = F.mse_loss(I_mov_warped_for_grad, I_fix)
            
            grad_inner_loss = torch.autograd.grad(inner_loss_for_grad, phi, create_graph=True)[0]
            phi = phi.detach() # Detach to prevent graph cycles

            # --- Prepare Input for RIIR Cell ---
            # Concatenate inputs along the channel dimension as per Eq. 10
            riir_input = torch.cat([phi, grad_inner_loss, I_mov_warped.detach(), I_fix], dim=1)
            
            # --- Get Incremental Update from RIIR Cell ---
            delta_phi, h1, h2 = self.riir_cell(riir_input, h1, h2)
            
            # --- Update Total Deformation Field (Eq. 9) ---
            phi = phi + delta_phi
            
            # Store results for this step
            phi_list.append(phi)
            warped_list.append(self.stn(I_mov, phi))
            
        return phi_list, warped_list

# -----------------------------------------------------------------------------
# 5. Loss Functions
# -----------------------------------------------------------------------------
# These are used for the "outer loss" (L_outer) to train the model (Eq. 13).

def similarity_loss(warped, fixed, mode='mse'):
    """Calculates the similarity loss."""
    if mode == 'mse':
        return F.mse_loss(warped, fixed)
    elif mode == 'ncc':
        # Simplified NCC for demonstration
        warped_mean = warped.mean(dim=[1, 2, 3], keepdim=True)
        fixed_mean = fixed.mean(dim=[1, 2, 3], keepdim=True)
        warped_std = warped.std(dim=[1, 2, 3], keepdim=True)
        fixed_std = fixed.std(dim=[1, 2, 3], keepdim=True)
        
        ncc = torch.mean(((warped - warped_mean) * (fixed - fixed_mean)) / (warped_std * fixed_std))
        return 1 - ncc
    else:
        raise ValueError("Unsupported similarity mode")

def regularization_loss(phi):
    """Calculates the diffusion regularization loss (Eq. 17)."""
    dy = torch.abs(phi[:, :, 1:, :] - phi[:, :, :-1, :])
    dx = torch.abs(phi[:, :, :, 1:] - phi[:, :, :, :-1])
    
    return (torch.mean(dx**2) + torch.mean(dy**2)) / 2.0

def total_loss(phi_list, warped_list, fixed_img, reg_lambda, n_steps):
    """
    Calculates the total outer loss (Eq. 13).
    
    Args:
        phi_list (list): List of deformation fields from RIIR.
        warped_list (list): List of warped images from RIIR.
        fixed_img (torch.Tensor): The fixed image.
        reg_lambda (float): The regularization weight.
        n_steps (int): Total number of steps.
        
    Returns:
        torch.Tensor: The total computed loss.
    """
    total_l = 0
    for t in range(n_steps):
        # Exponential weighting as mentioned in the paper
        weight = 10**((t - (n_steps-1)) / (n_steps-1)) if n_steps > 1 else 1.0
        
        l_sim = similarity_loss(warped_list[t], fixed_img, mode='mse')
        l_reg = regularization_loss(phi_list[t])
        
        step_loss = l_sim + reg_lambda * l_reg
        total_l += weight * step_loss
        
    return total_l / n_steps

# -----------------------------------------------------------------------------
# 6. Main Training Loop Example
# -----------------------------------------------------------------------------
if __name__ == '__main__':
    # --- Configuration ---
    IMG_SIZE = (64, 64)
    BATCH_SIZE = 2
    N_STEPS = 6
    LEARNING_RATE = 1e-4
    EPOCHS = 10
    REG_LAMBDA = 0.0125 # Regularization weight
    DEVICE = "cuda" if torch.cuda.is_available() else "cpu"

    print(f"Using device: {DEVICE}")

    # --- Model Initialization ---
    model = RIIR(img_size=IMG_SIZE, n_steps=N_STEPS).to(DEVICE)
    optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)

    print(f"Model initialized with {sum(p.numel() for p in model.parameters())/1e6:.2f}M parameters.")

    # --- Dummy Data ---
    # In a real application, you would use a DataLoader here.
    # Create a simple moving and fixed image pair for demonstration.
    # Moving image: a square. Fixed image: a circle.
    fixed_image = torch.zeros(BATCH_SIZE, 1, IMG_SIZE[0], IMG_SIZE[1])
    mov_image = torch.zeros(BATCH_SIZE, 1, IMG_SIZE[0], IMG_SIZE[1])

    # Create a circle for the fixed image
    cx, cy, r = IMG_SIZE[0] // 2, IMG_SIZE[1] // 2, 15
    y, x = np.ogrid[-cx:IMG_SIZE[0]-cx, -cy:IMG_SIZE[1]-cy]
    mask = x*x + y*y <= r*r
    fixed_image[:, :, mask] = 1.0

    # Create a square for the moving image
    mov_image[:, :, cx-r:cx+r, cy-r:cy+r] = 1.0
    
    fixed_image = fixed_image.to(DEVICE)
    mov_image = mov_image.to(DEVICE)
    
    # --- Training ---
    print("Starting training...")
    for epoch in range(EPOCHS):
        model.train()
        
        optimizer.zero_grad()
        
        # Forward pass
        phi_list, warped_list = model(mov_image, fixed_image)
        
        # Calculate loss
        loss = total_loss(phi_list, warped_list, fixed_image, REG_LAMBDA, N_STEPS)
        
        # Backward pass and optimization
        loss.backward()
        optimizer.step()
        
        print(f"Epoch [{epoch+1}/{EPOCHS}], Loss: {loss.item():.6f}")

    print("Training finished.")

    # --- Inference Example ---
    model.eval()
    with torch.no_grad():
        phi_list_inf, warped_list_inf = model(mov_image, fixed_image)

    # The final warped image is the last one in the list
    final_warped_image = warped_list_inf[-1]
    final_phi = phi_list_inf[-1]

    print("Inference finished.")
    print(f"Final warped image shape: {final_warped_image.shape}")
    print(f"Final deformation field shape: {final_phi.shape}")

    # You can now visualize the results (e.g., using matplotlib)
    # import matplotlib.pyplot as plt
    # plt.figure(figsize=(12, 4))
    # plt.subplot(1, 3, 1)
    # plt.imshow(mov_image[0, 0].cpu().numpy(), cmap='gray')
    # plt.title('Moving Image')
    # plt.subplot(1, 3, 2)
    # plt.imshow(fixed_image[0, 0].cpu().numpy(), cmap='gray')
    # plt.title('Fixed Image')
    # plt.subplot(1, 3, 3)
    # plt.imshow(final_warped_image[0, 0].cpu().numpy(), cmap='gray')
    # plt.title('Warped Image')
    # plt.show()

Related posts, You May like to read

  1. 7 Shocking Truths About Knowledge Distillation: The Good, The Bad, and The Breakthrough (SAKD)
  2. 7 Revolutionary Breakthroughs in Medical Image Translation (And 1 Fatal Flaw That Could Derail Your AI Model)
  3. Revolutionary Brain Disease Prediction: How AI Beats Disease (But One Flaw Remains)
  4. 1 Revolutionary Breakthrough in AI Object Detection: GridCLIP vs. Two-Stage Models

Leave a Comment

Your email address will not be published. Required fields are marked *

Follow by Email
Tiktok