bioimageio.core.sample
1from __future__ import annotations 2 3from dataclasses import dataclass 4from math import ceil, floor 5from typing import ( 6 Callable, 7 Dict, 8 Generic, 9 Iterable, 10 Optional, 11 Tuple, 12 TypeVar, 13 Union, 14) 15 16import numpy as np 17from typing_extensions import Self 18 19from .axis import AxisId, PerAxis 20from .block import Block 21from .block_meta import ( 22 BlockMeta, 23 LinearAxisTransform, 24 split_multiple_shapes_into_blocks, 25) 26from .common import ( 27 BlockIndex, 28 Halo, 29 HaloLike, 30 MemberId, 31 PadMode, 32 PerMember, 33 SampleId, 34 SliceInfo, 35 TotalNumberOfBlocks, 36) 37from .stat_measures import Stat 38from .tensor import Tensor 39 40# TODO: allow for lazy samples to read/write to disk 41 42 43@dataclass 44class Sample: 45 """A dataset sample""" 46 47 members: Dict[MemberId, Tensor] 48 """the sample's tensors""" 49 50 stat: Stat 51 """sample and dataset statistics""" 52 53 id: SampleId 54 """identifier within the sample's dataset""" 55 56 @property 57 def shape(self) -> PerMember[PerAxis[int]]: 58 return {tid: t.sizes for tid, t in self.members.items()} 59 60 def split_into_blocks( 61 self, 62 block_shapes: PerMember[PerAxis[int]], 63 halo: PerMember[PerAxis[HaloLike]], 64 pad_mode: PadMode, 65 broadcast: bool = False, 66 ) -> Tuple[TotalNumberOfBlocks, Iterable[SampleBlockWithOrigin]]: 67 assert not ( 68 missing := [m for m in block_shapes if m not in self.members] 69 ), f"`block_shapes` specified for unknown members: {missing}" 70 assert not ( 71 missing := [m for m in halo if m not in block_shapes] 72 ), f"`halo` specified for members without `block_shape`: {missing}" 73 74 n_blocks, blocks = split_multiple_shapes_into_blocks( 75 shapes=self.shape, 76 block_shapes=block_shapes, 77 halo=halo, 78 broadcast=broadcast, 79 ) 80 return n_blocks, sample_block_generator(blocks, origin=self, pad_mode=pad_mode) 81 82 def as_single_block(self, halo: Optional[PerMember[PerAxis[Halo]]] = None): 83 if halo is None: 84 halo = {} 85 return SampleBlockWithOrigin( 86 sample_shape=self.shape, 87 sample_id=self.id, 88 blocks={ 89 m: Block( 90 sample_shape=self.shape[m], 91 data=data, 92 inner_slice={ 93 a: SliceInfo(0, s) for a, s in data.tagged_shape.items() 94 }, 95 halo=halo.get(m, {}), 96 block_index=0, 97 blocks_in_sample=1, 98 ) 99 for m, data in self.members.items() 100 }, 101 stat=self.stat, 102 origin=self, 103 block_index=0, 104 blocks_in_sample=1, 105 ) 106 107 @classmethod 108 def from_blocks( 109 cls, 110 sample_blocks: Iterable[SampleBlock], 111 *, 112 fill_value: float = float("nan"), 113 ) -> Self: 114 members: PerMember[Tensor] = {} 115 stat: Stat = {} 116 sample_id = None 117 for sample_block in sample_blocks: 118 assert sample_id is None or sample_id == sample_block.sample_id 119 sample_id = sample_block.sample_id 120 stat = sample_block.stat 121 for m, block in sample_block.blocks.items(): 122 if m not in members: 123 if -1 in block.sample_shape.values(): 124 raise NotImplementedError( 125 "merging blocks with data dependent axis not yet implemented" 126 ) 127 128 members[m] = Tensor( 129 np.full( 130 tuple(block.sample_shape[a] for a in block.data.dims), 131 fill_value, 132 dtype=block.data.dtype, 133 ), 134 dims=block.data.dims, 135 ) 136 137 members[m][block.inner_slice] = block.inner_data 138 139 return cls(members=members, stat=stat, id=sample_id) 140 141 142BlockT = TypeVar("BlockT", Block, BlockMeta) 143 144 145@dataclass 146class SampleBlockBase(Generic[BlockT]): 147 """base class for `SampleBlockMeta` and `SampleBlock`""" 148 149 sample_shape: PerMember[PerAxis[int]] 150 """the sample shape this block represents a part of""" 151 152 sample_id: SampleId 153 """identifier for the sample within its dataset""" 154 155 blocks: Dict[MemberId, BlockT] 156 """Individual tensor blocks comprising this sample block""" 157 158 block_index: BlockIndex 159 """the n-th block of the sample""" 160 161 blocks_in_sample: TotalNumberOfBlocks 162 """total number of blocks in the sample""" 163 164 @property 165 def shape(self) -> PerMember[PerAxis[int]]: 166 return {mid: b.shape for mid, b in self.blocks.items()} 167 168 @property 169 def inner_shape(self) -> PerMember[PerAxis[int]]: 170 return {mid: b.inner_shape for mid, b in self.blocks.items()} 171 172 173@dataclass 174class LinearSampleAxisTransform(LinearAxisTransform): 175 member: MemberId 176 177 178@dataclass 179class SampleBlockMeta(SampleBlockBase[BlockMeta]): 180 """Meta data of a dataset sample block""" 181 182 def get_transformed( 183 self, new_axes: PerMember[PerAxis[Union[LinearSampleAxisTransform, int]]] 184 ) -> Self: 185 sample_shape = { 186 m: { 187 a: ( 188 trf 189 if isinstance(trf, int) 190 else trf.compute(self.sample_shape[trf.member][trf.axis]) 191 ) 192 for a, trf in new_axes[m].items() 193 } 194 for m in new_axes 195 } 196 197 def get_member_halo(m: MemberId, round: Callable[[float], int]): 198 return { 199 a: ( 200 Halo(0, 0) 201 if isinstance(trf, int) 202 or trf.axis not in self.blocks[trf.member].halo 203 else Halo( 204 round(self.blocks[trf.member].halo[trf.axis].left * trf.scale), 205 round(self.blocks[trf.member].halo[trf.axis].right * trf.scale), 206 ) 207 ) 208 for a, trf in new_axes[m].items() 209 } 210 211 halo: Dict[MemberId, Dict[AxisId, Halo]] = {} 212 for m in new_axes: 213 halo[m] = get_member_halo(m, floor) 214 if halo[m] != get_member_halo(m, ceil): 215 raise ValueError( 216 f"failed to unambiguously scale halo {halo[m]} with {new_axes[m]}" 217 + f" for {m}." 218 ) 219 220 inner_slice = { 221 m: { 222 a: ( 223 SliceInfo(0, trf) 224 if isinstance(trf, int) 225 else SliceInfo( 226 trf.compute( 227 self.blocks[trf.member].inner_slice[trf.axis].start 228 ), 229 trf.compute(self.blocks[trf.member].inner_slice[trf.axis].stop), 230 ) 231 ) 232 for a, trf in new_axes[m].items() 233 } 234 for m in new_axes 235 } 236 return self.__class__( 237 blocks={ 238 m: BlockMeta( 239 sample_shape=sample_shape[m], 240 inner_slice=inner_slice[m], 241 halo=halo[m], 242 block_index=self.block_index, 243 blocks_in_sample=self.blocks_in_sample, 244 ) 245 for m in new_axes 246 }, 247 sample_shape=sample_shape, 248 sample_id=self.sample_id, 249 block_index=self.block_index, 250 blocks_in_sample=self.blocks_in_sample, 251 ) 252 253 def with_data(self, data: PerMember[Tensor], *, stat: Stat) -> SampleBlock: 254 return SampleBlock( 255 sample_shape={ 256 m: { 257 a: data[m].tagged_shape[a] if s == -1 else s 258 for a, s in member_shape.items() 259 } 260 for m, member_shape in self.sample_shape.items() 261 }, 262 sample_id=self.sample_id, 263 blocks={ 264 m: Block.from_meta(b, data=data[m]) for m, b in self.blocks.items() 265 }, 266 stat=stat, 267 block_index=self.block_index, 268 blocks_in_sample=self.blocks_in_sample, 269 ) 270 271 272@dataclass 273class SampleBlock(SampleBlockBase[Block]): 274 """A block of a dataset sample""" 275 276 stat: Stat 277 """computed statistics""" 278 279 @property 280 def members(self) -> PerMember[Tensor]: 281 """the sample block's tensors""" 282 return {m: b.data for m, b in self.blocks.items()} 283 284 def get_transformed_meta( 285 self, new_axes: PerMember[PerAxis[Union[LinearSampleAxisTransform, int]]] 286 ) -> SampleBlockMeta: 287 return SampleBlockMeta( 288 sample_id=self.sample_id, 289 blocks=dict(self.blocks), 290 sample_shape=self.sample_shape, 291 block_index=self.block_index, 292 blocks_in_sample=self.blocks_in_sample, 293 ).get_transformed(new_axes) 294 295 296@dataclass 297class SampleBlockWithOrigin(SampleBlock): 298 """A `SampleBlock` with a reference (`origin`) to the whole `Sample`""" 299 300 origin: Sample 301 """the sample this sample block was taken from""" 302 303 304class _ConsolidatedMemberBlocks: 305 def __init__(self, blocks: PerMember[BlockMeta]): 306 super().__init__() 307 block_indices = {b.block_index for b in blocks.values()} 308 assert len(block_indices) == 1 309 self.block_index = block_indices.pop() 310 blocks_in_samples = {b.blocks_in_sample for b in blocks.values()} 311 assert len(blocks_in_samples) == 1 312 self.blocks_in_sample = blocks_in_samples.pop() 313 314 315def sample_block_meta_generator( 316 blocks: Iterable[PerMember[BlockMeta]], 317 *, 318 sample_shape: PerMember[PerAxis[int]], 319 sample_id: SampleId, 320): 321 for member_blocks in blocks: 322 cons = _ConsolidatedMemberBlocks(member_blocks) 323 yield SampleBlockMeta( 324 blocks=dict(member_blocks), 325 sample_shape=sample_shape, 326 sample_id=sample_id, 327 block_index=cons.block_index, 328 blocks_in_sample=cons.blocks_in_sample, 329 ) 330 331 332def sample_block_generator( 333 blocks: Iterable[PerMember[BlockMeta]], 334 *, 335 origin: Sample, 336 pad_mode: PadMode, 337) -> Iterable[SampleBlockWithOrigin]: 338 for member_blocks in blocks: 339 cons = _ConsolidatedMemberBlocks(member_blocks) 340 yield SampleBlockWithOrigin( 341 blocks={ 342 m: Block.from_sample_member( 343 origin.members[m], block=member_blocks[m], pad_mode=pad_mode 344 ) 345 for m in origin.members 346 }, 347 sample_shape=origin.shape, 348 origin=origin, 349 stat=origin.stat, 350 sample_id=origin.id, 351 block_index=cons.block_index, 352 blocks_in_sample=cons.blocks_in_sample, 353 )
@dataclass
class
Sample:
44@dataclass 45class Sample: 46 """A dataset sample""" 47 48 members: Dict[MemberId, Tensor] 49 """the sample's tensors""" 50 51 stat: Stat 52 """sample and dataset statistics""" 53 54 id: SampleId 55 """identifier within the sample's dataset""" 56 57 @property 58 def shape(self) -> PerMember[PerAxis[int]]: 59 return {tid: t.sizes for tid, t in self.members.items()} 60 61 def split_into_blocks( 62 self, 63 block_shapes: PerMember[PerAxis[int]], 64 halo: PerMember[PerAxis[HaloLike]], 65 pad_mode: PadMode, 66 broadcast: bool = False, 67 ) -> Tuple[TotalNumberOfBlocks, Iterable[SampleBlockWithOrigin]]: 68 assert not ( 69 missing := [m for m in block_shapes if m not in self.members] 70 ), f"`block_shapes` specified for unknown members: {missing}" 71 assert not ( 72 missing := [m for m in halo if m not in block_shapes] 73 ), f"`halo` specified for members without `block_shape`: {missing}" 74 75 n_blocks, blocks = split_multiple_shapes_into_blocks( 76 shapes=self.shape, 77 block_shapes=block_shapes, 78 halo=halo, 79 broadcast=broadcast, 80 ) 81 return n_blocks, sample_block_generator(blocks, origin=self, pad_mode=pad_mode) 82 83 def as_single_block(self, halo: Optional[PerMember[PerAxis[Halo]]] = None): 84 if halo is None: 85 halo = {} 86 return SampleBlockWithOrigin( 87 sample_shape=self.shape, 88 sample_id=self.id, 89 blocks={ 90 m: Block( 91 sample_shape=self.shape[m], 92 data=data, 93 inner_slice={ 94 a: SliceInfo(0, s) for a, s in data.tagged_shape.items() 95 }, 96 halo=halo.get(m, {}), 97 block_index=0, 98 blocks_in_sample=1, 99 ) 100 for m, data in self.members.items() 101 }, 102 stat=self.stat, 103 origin=self, 104 block_index=0, 105 blocks_in_sample=1, 106 ) 107 108 @classmethod 109 def from_blocks( 110 cls, 111 sample_blocks: Iterable[SampleBlock], 112 *, 113 fill_value: float = float("nan"), 114 ) -> Self: 115 members: PerMember[Tensor] = {} 116 stat: Stat = {} 117 sample_id = None 118 for sample_block in sample_blocks: 119 assert sample_id is None or sample_id == sample_block.sample_id 120 sample_id = sample_block.sample_id 121 stat = sample_block.stat 122 for m, block in sample_block.blocks.items(): 123 if m not in members: 124 if -1 in block.sample_shape.values(): 125 raise NotImplementedError( 126 "merging blocks with data dependent axis not yet implemented" 127 ) 128 129 members[m] = Tensor( 130 np.full( 131 tuple(block.sample_shape[a] for a in block.data.dims), 132 fill_value, 133 dtype=block.data.dtype, 134 ), 135 dims=block.data.dims, 136 ) 137 138 members[m][block.inner_slice] = block.inner_data 139 140 return cls(members=members, stat=stat, id=sample_id)
A dataset sample
Sample( members: Dict[bioimageio.spec.model.v0_5.TensorId, bioimageio.core.Tensor], stat: Dict[Annotated[Union[Annotated[Union[bioimageio.core.stat_measures.SampleMean, bioimageio.core.stat_measures.SampleStd, bioimageio.core.stat_measures.SampleVar, bioimageio.core.stat_measures.SampleQuantile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.core.stat_measures.DatasetMean, bioimageio.core.stat_measures.DatasetStd, bioimageio.core.stat_measures.DatasetVar, bioimageio.core.stat_measures.DatasetPercentile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='scope', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Union[float, Annotated[bioimageio.core.Tensor, BeforeValidator(func=<function tensor_custom_before_validator>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function tensor_custom_serializer>, return_type=PydanticUndefined, when_used='always')]]], id: Hashable)
stat: Dict[Annotated[Union[Annotated[Union[bioimageio.core.stat_measures.SampleMean, bioimageio.core.stat_measures.SampleStd, bioimageio.core.stat_measures.SampleVar, bioimageio.core.stat_measures.SampleQuantile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.core.stat_measures.DatasetMean, bioimageio.core.stat_measures.DatasetStd, bioimageio.core.stat_measures.DatasetVar, bioimageio.core.stat_measures.DatasetPercentile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='scope', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Union[float, Annotated[bioimageio.core.Tensor, BeforeValidator(func=<function tensor_custom_before_validator at 0x7f9a7099e840>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function tensor_custom_serializer at 0x7f9a7099ea20>, return_type=PydanticUndefined, when_used='always')]]]
sample and dataset statistics
shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]]
def
split_into_blocks( self, block_shapes: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]], halo: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, Union[int, Tuple[int, int], bioimageio.core.common.Halo]]], pad_mode: Literal['edge', 'reflect', 'symmetric'], broadcast: bool = False) -> Tuple[int, Iterable[SampleBlockWithOrigin]]:
61 def split_into_blocks( 62 self, 63 block_shapes: PerMember[PerAxis[int]], 64 halo: PerMember[PerAxis[HaloLike]], 65 pad_mode: PadMode, 66 broadcast: bool = False, 67 ) -> Tuple[TotalNumberOfBlocks, Iterable[SampleBlockWithOrigin]]: 68 assert not ( 69 missing := [m for m in block_shapes if m not in self.members] 70 ), f"`block_shapes` specified for unknown members: {missing}" 71 assert not ( 72 missing := [m for m in halo if m not in block_shapes] 73 ), f"`halo` specified for members without `block_shape`: {missing}" 74 75 n_blocks, blocks = split_multiple_shapes_into_blocks( 76 shapes=self.shape, 77 block_shapes=block_shapes, 78 halo=halo, 79 broadcast=broadcast, 80 ) 81 return n_blocks, sample_block_generator(blocks, origin=self, pad_mode=pad_mode)
def
as_single_block( self, halo: Optional[Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, bioimageio.core.common.Halo]]] = None):
83 def as_single_block(self, halo: Optional[PerMember[PerAxis[Halo]]] = None): 84 if halo is None: 85 halo = {} 86 return SampleBlockWithOrigin( 87 sample_shape=self.shape, 88 sample_id=self.id, 89 blocks={ 90 m: Block( 91 sample_shape=self.shape[m], 92 data=data, 93 inner_slice={ 94 a: SliceInfo(0, s) for a, s in data.tagged_shape.items() 95 }, 96 halo=halo.get(m, {}), 97 block_index=0, 98 blocks_in_sample=1, 99 ) 100 for m, data in self.members.items() 101 }, 102 stat=self.stat, 103 origin=self, 104 block_index=0, 105 blocks_in_sample=1, 106 )
@classmethod
def
from_blocks( cls, sample_blocks: Iterable[SampleBlock], *, fill_value: float = nan) -> Self:
108 @classmethod 109 def from_blocks( 110 cls, 111 sample_blocks: Iterable[SampleBlock], 112 *, 113 fill_value: float = float("nan"), 114 ) -> Self: 115 members: PerMember[Tensor] = {} 116 stat: Stat = {} 117 sample_id = None 118 for sample_block in sample_blocks: 119 assert sample_id is None or sample_id == sample_block.sample_id 120 sample_id = sample_block.sample_id 121 stat = sample_block.stat 122 for m, block in sample_block.blocks.items(): 123 if m not in members: 124 if -1 in block.sample_shape.values(): 125 raise NotImplementedError( 126 "merging blocks with data dependent axis not yet implemented" 127 ) 128 129 members[m] = Tensor( 130 np.full( 131 tuple(block.sample_shape[a] for a in block.data.dims), 132 fill_value, 133 dtype=block.data.dtype, 134 ), 135 dims=block.data.dims, 136 ) 137 138 members[m][block.inner_slice] = block.inner_data 139 140 return cls(members=members, stat=stat, id=sample_id)
@dataclass
class
SampleBlockBase146@dataclass 147class SampleBlockBase(Generic[BlockT]): 148 """base class for `SampleBlockMeta` and `SampleBlock`""" 149 150 sample_shape: PerMember[PerAxis[int]] 151 """the sample shape this block represents a part of""" 152 153 sample_id: SampleId 154 """identifier for the sample within its dataset""" 155 156 blocks: Dict[MemberId, BlockT] 157 """Individual tensor blocks comprising this sample block""" 158 159 block_index: BlockIndex 160 """the n-th block of the sample""" 161 162 blocks_in_sample: TotalNumberOfBlocks 163 """total number of blocks in the sample""" 164 165 @property 166 def shape(self) -> PerMember[PerAxis[int]]: 167 return {mid: b.shape for mid, b in self.blocks.items()} 168 169 @property 170 def inner_shape(self) -> PerMember[PerAxis[int]]: 171 return {mid: b.inner_shape for mid, b in self.blocks.items()}
base class for SampleBlockMeta
and SampleBlock
SampleBlockBase( sample_shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]], sample_id: Hashable, blocks: Dict[bioimageio.spec.model.v0_5.TensorId, ~BlockT], block_index: int, blocks_in_sample: int)
sample_shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]]
the sample shape this block represents a part of
blocks: Dict[bioimageio.spec.model.v0_5.TensorId, ~BlockT]
Individual tensor blocks comprising this sample block
shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]]
inner_shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]]
LinearSampleAxisTransform( axis: bioimageio.spec.model.v0_5.AxisId, scale: float, offset: int, member: bioimageio.spec.model.v0_5.TensorId)
Inherited Members
@dataclass
class
SampleBlockMeta179@dataclass 180class SampleBlockMeta(SampleBlockBase[BlockMeta]): 181 """Meta data of a dataset sample block""" 182 183 def get_transformed( 184 self, new_axes: PerMember[PerAxis[Union[LinearSampleAxisTransform, int]]] 185 ) -> Self: 186 sample_shape = { 187 m: { 188 a: ( 189 trf 190 if isinstance(trf, int) 191 else trf.compute(self.sample_shape[trf.member][trf.axis]) 192 ) 193 for a, trf in new_axes[m].items() 194 } 195 for m in new_axes 196 } 197 198 def get_member_halo(m: MemberId, round: Callable[[float], int]): 199 return { 200 a: ( 201 Halo(0, 0) 202 if isinstance(trf, int) 203 or trf.axis not in self.blocks[trf.member].halo 204 else Halo( 205 round(self.blocks[trf.member].halo[trf.axis].left * trf.scale), 206 round(self.blocks[trf.member].halo[trf.axis].right * trf.scale), 207 ) 208 ) 209 for a, trf in new_axes[m].items() 210 } 211 212 halo: Dict[MemberId, Dict[AxisId, Halo]] = {} 213 for m in new_axes: 214 halo[m] = get_member_halo(m, floor) 215 if halo[m] != get_member_halo(m, ceil): 216 raise ValueError( 217 f"failed to unambiguously scale halo {halo[m]} with {new_axes[m]}" 218 + f" for {m}." 219 ) 220 221 inner_slice = { 222 m: { 223 a: ( 224 SliceInfo(0, trf) 225 if isinstance(trf, int) 226 else SliceInfo( 227 trf.compute( 228 self.blocks[trf.member].inner_slice[trf.axis].start 229 ), 230 trf.compute(self.blocks[trf.member].inner_slice[trf.axis].stop), 231 ) 232 ) 233 for a, trf in new_axes[m].items() 234 } 235 for m in new_axes 236 } 237 return self.__class__( 238 blocks={ 239 m: BlockMeta( 240 sample_shape=sample_shape[m], 241 inner_slice=inner_slice[m], 242 halo=halo[m], 243 block_index=self.block_index, 244 blocks_in_sample=self.blocks_in_sample, 245 ) 246 for m in new_axes 247 }, 248 sample_shape=sample_shape, 249 sample_id=self.sample_id, 250 block_index=self.block_index, 251 blocks_in_sample=self.blocks_in_sample, 252 ) 253 254 def with_data(self, data: PerMember[Tensor], *, stat: Stat) -> SampleBlock: 255 return SampleBlock( 256 sample_shape={ 257 m: { 258 a: data[m].tagged_shape[a] if s == -1 else s 259 for a, s in member_shape.items() 260 } 261 for m, member_shape in self.sample_shape.items() 262 }, 263 sample_id=self.sample_id, 264 blocks={ 265 m: Block.from_meta(b, data=data[m]) for m, b in self.blocks.items() 266 }, 267 stat=stat, 268 block_index=self.block_index, 269 blocks_in_sample=self.blocks_in_sample, 270 )
Meta data of a dataset sample block
SampleBlockMeta( sample_shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]], sample_id: Hashable, blocks: Dict[bioimageio.spec.model.v0_5.TensorId, ~BlockT], block_index: int, blocks_in_sample: int)
def
get_transformed( self, new_axes: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, Union[LinearSampleAxisTransform, int]]]) -> Self:
183 def get_transformed( 184 self, new_axes: PerMember[PerAxis[Union[LinearSampleAxisTransform, int]]] 185 ) -> Self: 186 sample_shape = { 187 m: { 188 a: ( 189 trf 190 if isinstance(trf, int) 191 else trf.compute(self.sample_shape[trf.member][trf.axis]) 192 ) 193 for a, trf in new_axes[m].items() 194 } 195 for m in new_axes 196 } 197 198 def get_member_halo(m: MemberId, round: Callable[[float], int]): 199 return { 200 a: ( 201 Halo(0, 0) 202 if isinstance(trf, int) 203 or trf.axis not in self.blocks[trf.member].halo 204 else Halo( 205 round(self.blocks[trf.member].halo[trf.axis].left * trf.scale), 206 round(self.blocks[trf.member].halo[trf.axis].right * trf.scale), 207 ) 208 ) 209 for a, trf in new_axes[m].items() 210 } 211 212 halo: Dict[MemberId, Dict[AxisId, Halo]] = {} 213 for m in new_axes: 214 halo[m] = get_member_halo(m, floor) 215 if halo[m] != get_member_halo(m, ceil): 216 raise ValueError( 217 f"failed to unambiguously scale halo {halo[m]} with {new_axes[m]}" 218 + f" for {m}." 219 ) 220 221 inner_slice = { 222 m: { 223 a: ( 224 SliceInfo(0, trf) 225 if isinstance(trf, int) 226 else SliceInfo( 227 trf.compute( 228 self.blocks[trf.member].inner_slice[trf.axis].start 229 ), 230 trf.compute(self.blocks[trf.member].inner_slice[trf.axis].stop), 231 ) 232 ) 233 for a, trf in new_axes[m].items() 234 } 235 for m in new_axes 236 } 237 return self.__class__( 238 blocks={ 239 m: BlockMeta( 240 sample_shape=sample_shape[m], 241 inner_slice=inner_slice[m], 242 halo=halo[m], 243 block_index=self.block_index, 244 blocks_in_sample=self.blocks_in_sample, 245 ) 246 for m in new_axes 247 }, 248 sample_shape=sample_shape, 249 sample_id=self.sample_id, 250 block_index=self.block_index, 251 blocks_in_sample=self.blocks_in_sample, 252 )
def
with_data( self, data: Mapping[bioimageio.spec.model.v0_5.TensorId, bioimageio.core.Tensor], *, stat: Dict[Annotated[Union[Annotated[Union[bioimageio.core.stat_measures.SampleMean, bioimageio.core.stat_measures.SampleStd, bioimageio.core.stat_measures.SampleVar, bioimageio.core.stat_measures.SampleQuantile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.core.stat_measures.DatasetMean, bioimageio.core.stat_measures.DatasetStd, bioimageio.core.stat_measures.DatasetVar, bioimageio.core.stat_measures.DatasetPercentile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='scope', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Union[float, Annotated[bioimageio.core.Tensor, BeforeValidator(func=<function tensor_custom_before_validator>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function tensor_custom_serializer>, return_type=PydanticUndefined, when_used='always')]]]) -> SampleBlock:
254 def with_data(self, data: PerMember[Tensor], *, stat: Stat) -> SampleBlock: 255 return SampleBlock( 256 sample_shape={ 257 m: { 258 a: data[m].tagged_shape[a] if s == -1 else s 259 for a, s in member_shape.items() 260 } 261 for m, member_shape in self.sample_shape.items() 262 }, 263 sample_id=self.sample_id, 264 blocks={ 265 m: Block.from_meta(b, data=data[m]) for m, b in self.blocks.items() 266 }, 267 stat=stat, 268 block_index=self.block_index, 269 blocks_in_sample=self.blocks_in_sample, 270 )
Inherited Members
273@dataclass 274class SampleBlock(SampleBlockBase[Block]): 275 """A block of a dataset sample""" 276 277 stat: Stat 278 """computed statistics""" 279 280 @property 281 def members(self) -> PerMember[Tensor]: 282 """the sample block's tensors""" 283 return {m: b.data for m, b in self.blocks.items()} 284 285 def get_transformed_meta( 286 self, new_axes: PerMember[PerAxis[Union[LinearSampleAxisTransform, int]]] 287 ) -> SampleBlockMeta: 288 return SampleBlockMeta( 289 sample_id=self.sample_id, 290 blocks=dict(self.blocks), 291 sample_shape=self.sample_shape, 292 block_index=self.block_index, 293 blocks_in_sample=self.blocks_in_sample, 294 ).get_transformed(new_axes)
A block of a dataset sample
SampleBlock( sample_shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]], sample_id: Hashable, blocks: Dict[bioimageio.spec.model.v0_5.TensorId, ~BlockT], block_index: int, blocks_in_sample: int, stat: Dict[Annotated[Union[Annotated[Union[bioimageio.core.stat_measures.SampleMean, bioimageio.core.stat_measures.SampleStd, bioimageio.core.stat_measures.SampleVar, bioimageio.core.stat_measures.SampleQuantile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.core.stat_measures.DatasetMean, bioimageio.core.stat_measures.DatasetStd, bioimageio.core.stat_measures.DatasetVar, bioimageio.core.stat_measures.DatasetPercentile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='scope', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Union[float, Annotated[bioimageio.core.Tensor, BeforeValidator(func=<function tensor_custom_before_validator>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function tensor_custom_serializer>, return_type=PydanticUndefined, when_used='always')]]])
stat: Dict[Annotated[Union[Annotated[Union[bioimageio.core.stat_measures.SampleMean, bioimageio.core.stat_measures.SampleStd, bioimageio.core.stat_measures.SampleVar, bioimageio.core.stat_measures.SampleQuantile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.core.stat_measures.DatasetMean, bioimageio.core.stat_measures.DatasetStd, bioimageio.core.stat_measures.DatasetVar, bioimageio.core.stat_measures.DatasetPercentile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='scope', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Union[float, Annotated[bioimageio.core.Tensor, BeforeValidator(func=<function tensor_custom_before_validator at 0x7f9a7099e840>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function tensor_custom_serializer at 0x7f9a7099ea20>, return_type=PydanticUndefined, when_used='always')]]]
computed statistics
members: Mapping[bioimageio.spec.model.v0_5.TensorId, bioimageio.core.Tensor]
280 @property 281 def members(self) -> PerMember[Tensor]: 282 """the sample block's tensors""" 283 return {m: b.data for m, b in self.blocks.items()}
the sample block's tensors
def
get_transformed_meta( self, new_axes: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, Union[LinearSampleAxisTransform, int]]]) -> SampleBlockMeta:
285 def get_transformed_meta( 286 self, new_axes: PerMember[PerAxis[Union[LinearSampleAxisTransform, int]]] 287 ) -> SampleBlockMeta: 288 return SampleBlockMeta( 289 sample_id=self.sample_id, 290 blocks=dict(self.blocks), 291 sample_shape=self.sample_shape, 292 block_index=self.block_index, 293 blocks_in_sample=self.blocks_in_sample, 294 ).get_transformed(new_axes)
Inherited Members
@dataclass
class
SampleBlockWithOrigin297@dataclass 298class SampleBlockWithOrigin(SampleBlock): 299 """A `SampleBlock` with a reference (`origin`) to the whole `Sample`""" 300 301 origin: Sample 302 """the sample this sample block was taken from"""
A SampleBlock
with a reference (origin
) to the whole Sample
SampleBlockWithOrigin( sample_shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]], sample_id: Hashable, blocks: Dict[bioimageio.spec.model.v0_5.TensorId, ~BlockT], block_index: int, blocks_in_sample: int, stat: Dict[Annotated[Union[Annotated[Union[bioimageio.core.stat_measures.SampleMean, bioimageio.core.stat_measures.SampleStd, bioimageio.core.stat_measures.SampleVar, bioimageio.core.stat_measures.SampleQuantile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.core.stat_measures.DatasetMean, bioimageio.core.stat_measures.DatasetStd, bioimageio.core.stat_measures.DatasetVar, bioimageio.core.stat_measures.DatasetPercentile], Discriminator(discriminator='name', custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='scope', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Union[float, Annotated[bioimageio.core.Tensor, BeforeValidator(func=<function tensor_custom_before_validator>, json_schema_input_type=PydanticUndefined), PlainSerializer(func=<function tensor_custom_serializer>, return_type=PydanticUndefined, when_used='always')]]], origin: Sample)
def
sample_block_meta_generator( blocks: Iterable[Mapping[bioimageio.spec.model.v0_5.TensorId, bioimageio.core.BlockMeta]], *, sample_shape: Mapping[bioimageio.spec.model.v0_5.TensorId, Mapping[bioimageio.spec.model.v0_5.AxisId, int]], sample_id: Hashable):
316def sample_block_meta_generator( 317 blocks: Iterable[PerMember[BlockMeta]], 318 *, 319 sample_shape: PerMember[PerAxis[int]], 320 sample_id: SampleId, 321): 322 for member_blocks in blocks: 323 cons = _ConsolidatedMemberBlocks(member_blocks) 324 yield SampleBlockMeta( 325 blocks=dict(member_blocks), 326 sample_shape=sample_shape, 327 sample_id=sample_id, 328 block_index=cons.block_index, 329 blocks_in_sample=cons.blocks_in_sample, 330 )
def
sample_block_generator( blocks: Iterable[Mapping[bioimageio.spec.model.v0_5.TensorId, bioimageio.core.BlockMeta]], *, origin: Sample, pad_mode: Literal['edge', 'reflect', 'symmetric']) -> Iterable[SampleBlockWithOrigin]:
333def sample_block_generator( 334 blocks: Iterable[PerMember[BlockMeta]], 335 *, 336 origin: Sample, 337 pad_mode: PadMode, 338) -> Iterable[SampleBlockWithOrigin]: 339 for member_blocks in blocks: 340 cons = _ConsolidatedMemberBlocks(member_blocks) 341 yield SampleBlockWithOrigin( 342 blocks={ 343 m: Block.from_sample_member( 344 origin.members[m], block=member_blocks[m], pad_mode=pad_mode 345 ) 346 for m in origin.members 347 }, 348 sample_shape=origin.shape, 349 origin=origin, 350 stat=origin.stat, 351 sample_id=origin.id, 352 block_index=cons.block_index, 353 blocks_in_sample=cons.blocks_in_sample, 354 )