Skip to content

Feature/1d data support#672

Draft
tmuird wants to merge 23 commits intoCAREamics:mainfrom
tmuird:feature/1d-data-support
Draft

Feature/1d data support#672
tmuird wants to merge 23 commits intoCAREamics:mainfrom
tmuird:feature/1d-data-support

Conversation

@tmuird
Copy link
Copy Markdown

@tmuird tmuird commented Jan 4, 2026

Description

Note

tldr: Adds support for 1D data (spectroscopy, time series, sensor data) in CAREamics N2V, including 1D UNet architecture, patching, tiling, and multichannel processing.

Background - why do we need this PR?

CAREamics previously only supported 2D and 3D image data. However, many scientific applications require denoising of 1D data:

  • Raman/IR spectroscopy measurements
  • Time series sensor data
  • Single-line scans
  • 1D signal processing

Without 1D support, users had to artificially pad their data to 2D or use external tools. This PR enables native 1D data processing through N2V.

Overview - what changed?

  • Architecture: UNet now supports conv_dim=1 for 1D convolutions
  • Validation: Axes validators accept single spatial dimension (X, SX, TX, CX)
  • Patching: Sequential and random patching handle 1D arrays
  • Tiling: Tiling logic supports 1D coordinates for prediction
  • Layers: MaxBlurPool supports 1D for StructN2V
  • Multichannel: Per-channel N2V models with arbitrary channel indices
  • Random patching: Configurable random patch extraction per sample

Implementation - how did you implement the changes?

1D UNet Architecture:

config = create_n2v_configuration(
    axes="SX",           # S=samples, X=spatial
    patch_size=[64],     # 1D patch size
    ...
)

The UNet automatically uses 1D convolutions (nn.Conv1d) when conv_dims=1, with linear upsampling instead of bilinear.

Axes Validation:
Modified validators to detect single spatial dimensions and route to 1D-specific validation. Axes like "X", "SX", "TX", "CX" are now valid.

Patching Logic:

  • _extract_patches_1d() handles 1D array shapes (S, C, X) or (S, X)
  • Overlap computation works with 1D dimensions
  • Random patching supports configurable num_patches_per_sample

Multichannel Processing:
Enhanced N2V to support per-channel models where input/output channels can differ:

# Train separate model for channel 2 only
config.n_channels = 4
config.data_channel_indices = [2]  # Train on channel 2
# Model: 1 input channel → 1 output channel

Normalisation properly handles channel mismatches using target_channel_indices.

Changes Made

New features or files

  • check_axes_validity_1d() in src/careamics/config/validators/axes_validators.py
  • _extract_patches_1d() in src/careamics/dataset/patching/sequential_patching.py
  • MaxBlurPool 1D mode (dim=1) in src/careamics/models/layers.py
  • target_channel_indices parameter in Denormalize transform
  • num_patches_per_sample configuration for random patching
  • patching_seed for reproducible random patching
  • Test files: test_layers_1d.py, test_unet_1d.py, test_careamist_1d.py

Modified features or files

Core Architecture:

  • src/careamics/models/unet.py: Added 1D upsampling (linear mode), 1D skip connections
  • src/careamics/config/architectures/unet_config.py: Accepts conv_dims=1, validation warnings

Configuration:

  • src/careamics/config/validators/axes_validators.py: Routes 1D axes to new validator
  • src/careamics/config/data/data_config.py: Validates patch size matches spatial dims
  • src/careamics/config/configuration_factories.py: Added 1D Raman example in docstring

Patching & Tiling:

  • src/careamics/dataset/patching/sequential_patching.py: Routes to 1D/2D/3D based on axes
  • src/careamics/dataset/patching/validate_patch_dimension.py: Validates 1D patch dimensions
  • src/careamics/dataset/tiling/tiled_patching.py: Already had _compute_crop_and_stitch_coords_1d()

Transforms:

  • src/careamics/transforms/normalize.py: Handles channel mismatch (N input → M output)
  • src/careamics/transforms/denormalize.py: Added target_channel_indices for per-channel stats

Lightning Module:

  • src/careamics/lightning/lightning_module.py: Passes target_channel_indices to denormalise

Algorithm Config:

  • src/careamics/config/algorithms/n2v_algorithm_config.py: Disabled model_matching_in_out_channels validator

Removed features or files

None. All changes maintain backward compatibility.

How has this been tested?

Unit Tests Added:

  1. Axes Validation (test_axes_validators.py):

    • Tests 1D axes: X, SX, TX, CX, SCX, STX
    • Verifies invalid combinations are rejected
  2. MaxBlurPool1D (test_layers_1d.py):

    • Output shape correctness
    • Forward pass functionality
    • dtype and device compatibility
    • ceil_mode parameter behavior
  3. 1D UNet (test_unet_1d.py):

    • Model creation with depths 2-4
    • Forward pass with various input lengths
    • Multichannel: 1→1, 3→3, 1→2 (pixel embedding)
    • N2V2 mode with blur pooling
    • Gradient flow verification
    • dtype/device compatibility
  4. End-to-End N2V (test_careamist_1d.py):

    • Training with synthetic 1D signals
    • Prediction on unseen data
    • Multichannel 1D data (4 channels)
    • Validation split
    • Different axes configurations
    • N2V2 mode
    • Model save/load
    • Variable patch sizes
  5. Multichannel Tests (test_n2v_algorithm_config.py, test_denormalize_perchannel.py):

    • Mismatching input/output channels
    • Per-channel normalization stats
    • Channel index mapping

Manual Testing:
Tested on real Raman spectroscopy data with successful denoising results. Also using auxiliary channels lead to an improvement.

Related Issues

Breaking changes

None. All changes are backward compatible

Additional Notes and Examples

Example 1D Usage:

from careamics import CAREamist
from careamics.config import create_n2v_configuration
import numpy as np

# 1D spectroscopy data: (samples, length)
spectra = np.random.randn(100, 512).astype(np.float32)

# Configure for 1D
config = create_n2v_configuration(
    experiment_name="raman_denoising",
    data_type="array",
    axes="SX",
    patch_size=[64],
    batch_size=8,
    num_epochs=50,
)

# Train
careamist = CAREamist(source=config, work_dir="./checkpoints")
careamist.train(train_source=spectra[:80], val_source=spectra[80:])

# Predict
denoised = careamist.predict(source=spectra, data_type="array")

Multichannel Example:

# Train separate models per channel
multichannel_data = np.random.randn(100, 4, 512)  # 4 channels

config = create_n2v_configuration(
    axes="SCX",
    patch_size=[64],
    ...
)

careamist = CAREamist(source=config)
careamist.train(train_source=multichannel_data)

Random Patching Example:

config = create_n2v_configuration(
    axes="SX",
    patch_size=[64],
    patching_strategy="random",
    num_patches_per_sample=10,  # Extract 10 patches per sample
    patching_seed=42,            # Reproducible
    ...
)

Please ensure your PR meets the following requirements:

  • Code builds and passes tests locally, including doctests - a few unrelated tests need to be updated to make validation consistent with the new support for 1D
  • New tests have been added (for bug fixes/features)
  • Pre-commit passes
  • PR to the documentation exists (for bug fixes / features)

tmuird added 23 commits January 3, 2026 22:16
…ctly for arbitrary data channels. Improve batching logic and handling of 1D Manipulations
- Fix test_axes_validators.py to allow 1D axes (X, SX, TX, CX, SCX, STX)
- Add MaxBlurPool1D layer tests
- Add 1D UNet architecture tests
- Add end-to-end 1D N2V training tests

Covers: axes validation, MaxBlurPool1D, 1D UNet, N2V training/prediction
…tests. Remove redundant dropout and attention code. Type checking
@tmuird
Copy link
Copy Markdown
Author

tmuird commented Jan 5, 2026

Just to introduce myself, I'm Tom, a first year PhD student at the University of Birmingham working under the supervision of Alexander Krull. I've been working on the application of his N2V algorithm to Raman Spectroscopy and other types of data.

@jdeschamps jdeschamps requested a review from a team January 7, 2026 15:09
@jdeschamps
Copy link
Copy Markdown
Member

jdeschamps commented Jan 8, 2026

Just to introduce myself, I'm Tom, a first year PhD student at the University of Birmingham working under the supervision of Alexander Krull. I've been working on the application of his N2V algorithm to Raman Spectroscopy and other types of data.

Hi Tom!

Thanks for your PRs, we are happy CAREamics might be of use to your projects and hi to Alex!

The PRs are touching on many aspects of the code base and we are in the middle of a major refactoring, therefore we will need a few days to review and assess the various changes. We will come back to you with detailed feedback!

@jdeschamps
Copy link
Copy Markdown
Member

Hi Tom,

I tried to get in touch with Alex because I could not find your contact details. Given the depth of the changes necessary to accommodate your needs, I think it would be good to have a discussion first.

Do you mind getting in touch with me by emails? You can find it on the HT website!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants