Skip to content

Releases: KamitaniLab/bdpy

BdPy 0.26 Release

18 May 07:58

Choose a tag to compare

bdpy 0.26

Highlights

  • Supports Python 3.6 – 3.11.
  • This is the last release to support Python 3.6 – 3.9.
    Future releases will follow the upstream Python support schedule.
  • Starting with this version, we use uv for development, which ensures that the lock file generated from pyproject.toml is resolved as a universal lock file.
  • This release includes 4 breaking changes — see the Breaking Changes section for migration guidance.

Breaking Changes

AffineDomain removed in favor of StandardizedDomain / ScaledDomain (#100)

AffineDomain now raises RuntimeError immediately upon instantiation. Use StandardizedDomain and ScaledDomain from bdpy.dl.torch.domain.image_domain instead.

Note: The new classes have different semantics from AffineDomain. A direct parameter swap is not always correct. Refer to the example and BdPyVGGDomain in bdpy/dl/torch/domain/image_domain.py as a concrete migration reference.

Before:

from bdpy.dl.torch.domain.image_domain import AffineDomain

# AffineDomain.receive: images_in_domain = images_in_[0,1] * scale - center
domain = AffineDomain(center=mean_pixels, scale=255.)

After:

from bdpy.dl.torch.domain.image_domain import (
    ScaledDomain, StandardizedDomain, ComposedDomain,
)

# Equivalent: first scale to [0, 255], then subtract mean
domain = ComposedDomain([
    ScaledDomain(255.),
    StandardizedDomain(center=mean_pixels, scale=1.),
])

ImageDataset now returns CHW float64 arrays (#105)

ImageDataset.__getitem__ previously returned images in HWC (uint8) format. It now returns CHW (float64) arrays with pixel values normalized to [0, 1].

Additionally, when stimulus_names=None, names are now returned in alphabetically sorted (deterministic) order.

Before:

dataset = ImageDataset(root_path="images/")
img, name = dataset[0]
# img.shape == (H, W, 3), dtype=uint8, values in [0, 255]

# Typical downstream pre-processing:
img_chw = img.transpose(2, 0, 1).astype(float) / 255.0

After:

dataset = ImageDataset(root_path="images/")
img, name = dataset[0]
# img.shape == (3, H, W), dtype=float64, values in [0.0, 1.0]

# No manual transposition or normalization needed:
img_chw = img  # ready to use

If your downstream code was manually transposing / normalizing, remove those operations.


FeatureInversionTask takes optimizer/scheduler factories (#101)

The constructor arguments optimizer (a torch.optim.Optimizer instance) and scheduler (a LRScheduler instance) have been replaced by optimizer_factory and scheduler_factory (callables). The optimizer and scheduler are now recreated on every reset_states() call, fixing incorrect optimizer state accumulation across multiple task runs.

Before:

from bdpy.recon.torch.task import FeatureInversionTask

optimizer = torch.optim.Adam(
    list(generator.parameters()) + list(latent.parameters()), lr=1e-3
)
task = FeatureInversionTask(
    encoder, generator, latent, critic,
    optimizer=optimizer,
    num_iterations=200,
)

After:

from bdpy.recon.torch.task import FeatureInversionTask
from bdpy.recon.torch.modules import build_optimizer_factory

optimizer_factory = build_optimizer_factory(torch.optim.Adam, lr=1e-3)
task = FeatureInversionTask(
    encoder, generator, latent, critic,
    optimizer_factory=optimizer_factory,
    num_iterations=200,
)

For schedulers, use build_scheduler_factory in the same way:

from bdpy.recon.torch.modules import build_scheduler_factory
from torch.optim.lr_scheduler import StepLR

scheduler_factory = build_scheduler_factory(StepLR, step_size=100, gamma=0.1)
task = FeatureInversionTask(
    ..., optimizer_factory=optimizer_factory, scheduler_factory=scheduler_factory,
)

model_factory key renamed: "referencenet""reference_net" (#98)

Before:

model = model_factory("referencenet")

After:

model = model_factory("reference_net")

New Features

  • Added StandardizedDomain and ScaledDomain to bdpy.dl.torch.domain.image_domain
    as the recommended replacements for the removed AffineDomain. (#100)
  • Added build_optimizer_factory and build_scheduler_factory factory helpers to
    bdpy.recon.torch.modules.optimizer (importable from bdpy.recon.torch.modules). (#101)

Bug Fixes

  • Fixed missing typing_extensions import in the callback module. (#99)
  • ImageDataset.stimulus_names now returns names in alphabetically sorted, deterministic order. (#105)
  • bdpy/mri/roi.py: ROI file glob results are now sorted for deterministic ordering. (14a369d)
  • bdpy/ml/learning.py: Added typing_extensions fallback for TypedDict / Protocol
    on Python < 3.8. (#112)

CI / Build

  • Updated all GitHub Actions to latest versions; migrated from the archived
    chartboost/ruff-action to astral-sh/ruff-action@v4. (#118)
  • Migrated Ruff lint config to the new [tool.ruff.lint] format; enabled I (import sort)
    and NumPy docstring convention rules. (#109)
  • Separated Python 3.6 / 3.7 CI into dedicated jobs in test_old.yml on the
    maintenance/legacy branch. (#112)
  • Pinned pytest-github-actions-annotate-failures==0.2.0 to fix intermittent CI failures. (#103)
  • Migrated dev-dependency declarations from [tool.rye] to PEP 735 [dependency-groups]
    with [tool.uv]; Starting with this version, we use uv for development, which ensures that the lock file generated from pyproject.toml is resolved as a universal lock file. (#112)

Contributors

Thanks to everyone who contributed to this release!


Full Changelog: 0.25.1...0.26