Coverage for src/bioimageio/spec/_hf_card.py: 81%
303 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-15 15:08 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-15 15:08 +0000
1import collections.abc
2import warnings
3from functools import partial
4from pathlib import PurePosixPath
5from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
7import numpy as np
8from imageio.v3 import imwrite # pyright: ignore[reportUnknownVariableType]
9from loguru import logger
10from numpy.typing import NDArray
11from typing_extensions import assert_never
13from bioimageio.spec._internal.validation_context import get_validation_context
14from bioimageio.spec.model.v0_5 import (
15 FileDescr,
16 IntervalOrRatioDataDescr,
17 KerasHdf5WeightsDescr,
18 KerasV3WeightsDescr,
19 NominalOrOrdinalDataDescr,
20 OnnxWeightsDescr,
21 PytorchStateDictWeightsDescr,
22 TensorflowJsWeightsDescr,
23 TensorflowSavedModelBundleWeightsDescr,
24 TensorId,
25 TorchscriptWeightsDescr,
26)
28from ._internal.io import RelativeFilePath, get_reader
29from ._internal.io_utils import load_array
30from ._version import VERSION
31from .model import ModelDescr
32from .utils import get_spdx_licenses, load_image
34HF_KNOWN_LICENSES = (
35 "apache-2.0",
36 "mit",
37 "openrail",
38 "bigscience-openrail-m",
39 "creativeml-openrail-m",
40 "bigscience-bloom-rail-1.0",
41 "bigcode-openrail-m",
42 "afl-3.0",
43 "artistic-2.0",
44 "bsl-1.0",
45 "bsd",
46 "bsd-2-clause",
47 "bsd-3-clause",
48 "bsd-3-clause-clear",
49 "c-uda",
50 "cc",
51 "cc0-1.0",
52 "cc-by-2.0",
53 "cc-by-2.5",
54 "cc-by-3.0",
55 "cc-by-4.0",
56 "cc-by-sa-3.0",
57 "cc-by-sa-4.0",
58 "cc-by-nc-2.0",
59 "cc-by-nc-3.0",
60 "cc-by-nc-4.0",
61 "cc-by-nd-4.0",
62 "cc-by-nc-nd-3.0",
63 "cc-by-nc-nd-4.0",
64 "cc-by-nc-sa-2.0",
65 "cc-by-nc-sa-3.0",
66 "cc-by-nc-sa-4.0",
67 "cdla-sharing-1.0",
68 "cdla-permissive-1.0",
69 "cdla-permissive-2.0",
70 "wtfpl",
71 "ecl-2.0",
72 "epl-1.0",
73 "epl-2.0",
74 "etalab-2.0",
75 "eupl-1.1",
76 "eupl-1.2",
77 "agpl-3.0",
78 "gfdl",
79 "gpl",
80 "gpl-2.0",
81 "gpl-3.0",
82 "lgpl",
83 "lgpl-2.1",
84 "lgpl-3.0",
85 "isc",
86 "h-research",
87 "intel-research",
88 "lppl-1.3c",
89 "ms-pl",
90 "apple-ascl",
91 "apple-amlr",
92 "mpl-2.0",
93 "odc-by",
94 "odbl",
95 "openmdw-1.0",
96 "openrail++",
97 "osl-3.0",
98 "postgresql",
99 "ofl-1.1",
100 "ncsa",
101 "unlicense",
102 "zlib",
103 "pddl",
104 "lgpl-lr",
105 "deepfloyd-if-license",
106 "fair-noncommercial-research-license",
107 "llama2",
108 "llama3",
109 "llama3.1",
110 "llama3.2",
111 "llama3.3",
112 "llama4",
113 "grok2-community",
114 "gemma",
115)
118def _generate_png_from_tensor(tensor: NDArray[np.generic]) -> Optional[bytes]:
119 """Generate PNG bytes from a sample tensor.
121 Prefers 2D slices from multi-dimensional arrays.
122 Returns PNG bytes or None if generation fails.
123 """
124 try:
125 # Squeeze out singleton dimensions
126 arr = np.squeeze(tensor)
128 # Handle different dimensionalities
129 if arr.ndim == 2:
130 img_data = arr
131 elif arr.ndim == 3:
132 # Could be (H, W, C) or (Z, H, W)
133 if arr.shape[-1] in [1, 3, 4]: # Likely channels last
134 img_data = arr
135 else: # Take middle slice
136 img_data = arr[arr.shape[0] // 2]
137 elif arr.ndim == 4:
138 # Take middle slices (e.g., batch, z, y, x)
139 img_data = (
140 arr[0, arr.shape[1] // 2]
141 if arr.shape[0] == 1
142 else arr[arr.shape[0] // 2, arr.shape[1] // 2]
143 )
144 elif arr.ndim > 4:
145 # Take middle slices of all extra dimensions
146 slices = tuple(s // 2 for s in arr.shape[:-2])
147 img_data = arr[slices]
148 else:
149 return None
151 # Normalize to 0-255 uint8
152 img_data = np.squeeze(img_data)
153 if img_data.dtype != np.uint8:
154 img_min, img_max = img_data.min(), img_data.max()
155 if img_max > img_min:
156 img_data: NDArray[Any] = (img_data - img_min) / (img_max - img_min)
157 else:
158 img_data = np.zeros_like(img_data)
159 img_data = (img_data * 255).astype(np.uint8)
160 return imwrite("<bytes>", img_data, extension=".png")
161 except Exception:
162 return None
165def _get_io_description(
166 model: ModelDescr,
167) -> Tuple[str, Dict[str, bytes], List[TensorId], List[TensorId]]:
168 """Generate a description of model inputs and outputs with sample images.
170 Returns:
171 A tuple of (markdown_string, referenced_files_dict, input_ids, output_ids) where referenced_files_dict maps
172 filenames to file bytes.
173 """
174 markdown_string = ""
175 referenced_files: dict[str, bytes] = {}
176 input_ids: List[TensorId] = []
177 output_ids: List[TensorId] = []
179 def format_data_descr(
180 d: Union[
181 NominalOrOrdinalDataDescr,
182 IntervalOrRatioDataDescr,
183 Sequence[Union[NominalOrOrdinalDataDescr, IntervalOrRatioDataDescr]],
184 ],
185 ) -> str:
186 ret = ""
187 if isinstance(d, NominalOrOrdinalDataDescr):
188 ret += f" - Values: {d.values}\n"
189 elif isinstance(d, IntervalOrRatioDataDescr):
190 ret += f" - Value unit: {d.unit}\n"
191 ret += f" - Value scale factor: {d.scale}\n"
192 if d.offset is not None:
193 ret += f" - Value offset: {d.offset}\n"
194 elif d.range[0] is not None:
195 ret += f" - Value minimum: {d.range[0]}\n"
196 elif d.range[1] is not None:
197 ret += f" - Value maximum: {d.range[1]}\n"
198 elif isinstance(d, collections.abc.Sequence):
199 for dd in d:
200 ret += format_data_descr(dd)
201 else:
202 assert_never(d)
204 return ret
206 # Input descriptions
207 if model.inputs:
208 markdown_string += "\n- **Input specifications:**\n"
210 for inp in model.inputs:
211 input_ids.append(inp.id)
212 axes_str = ", ".join(str(a.id) for a in inp.axes)
213 shape_str = " × ".join(
214 str(a.size) if isinstance(a.size, int) else str(a.size)
215 for a in inp.axes
216 )
218 markdown_string += f" `{inp.id}`: {inp.description or ''}\n\n"
219 markdown_string += f" - Axes: `{axes_str}`\n"
220 markdown_string += f" - Shape: `{shape_str}`\n"
221 markdown_string += f" - Data type: `{inp.dtype}`\n"
222 markdown_string += format_data_descr(inp.data)
224 # Try to load and display sample_tensor (preferred) or test_tensor
225 img_bytes = None
226 if inp.sample_tensor is not None:
227 try:
228 arr = load_image(inp.sample_tensor)
229 img_bytes = _generate_png_from_tensor(arr)
230 except Exception as e:
231 logger.error("failed to generate input sample image: {}", e)
233 if img_bytes is None and inp.test_tensor is not None:
234 try:
235 arr = load_array(inp.test_tensor)
236 img_bytes = _generate_png_from_tensor(arr)
237 except Exception as e:
238 logger.error(
239 "failed to generate input sample image from test data: {}", e
240 )
242 if img_bytes:
243 filename = f"images/input_{inp.id}_sample.png"
244 referenced_files[filename] = img_bytes
245 markdown_string += f" - example\n \n"
247 # Output descriptions
248 if model.outputs:
249 markdown_string += "\n- **Output specifications:**\n"
250 for out in model.outputs:
251 output_ids.append(out.id)
252 axes_str = ", ".join(str(a.id) for a in out.axes)
253 shape_str = " × ".join(
254 str(a.size) if isinstance(a.size, int) else str(a.size)
255 for a in out.axes
256 )
258 markdown_string += f" `{out.id}`: {out.description or ''}\n"
259 markdown_string += f" - Axes: `{axes_str}`\n"
260 markdown_string += f" - Shape: `{shape_str}`\n"
261 markdown_string += f" - Data type: `{out.dtype}`\n"
262 markdown_string += format_data_descr(out.data)
264 # Try to load and display sample_tensor (preferred) or test_tensor
265 img_bytes = None
266 if out.sample_tensor is not None:
267 try:
268 arr = load_image(out.sample_tensor)
269 img_bytes = _generate_png_from_tensor(arr)
270 except Exception as e:
271 logger.error("failed to generate output sample image: {}", e)
273 if img_bytes is None and out.test_tensor is not None:
274 try:
275 arr = load_array(out.test_tensor)
276 img_bytes = _generate_png_from_tensor(arr)
277 except Exception as e:
278 logger.error(
279 "failed to generate output sample image from test data: {}", e
280 )
282 if img_bytes:
283 filename = f"images/output_{out.id}_sample.png"
284 referenced_files[filename] = img_bytes
285 markdown_string += f" - example\n {out.id} sample]({filename})\n"
287 return markdown_string, referenced_files, input_ids, output_ids
290def create_huggingface_model_card(
291 model: ModelDescr, *, repo_id: str
292) -> Tuple[str, Dict[str, bytes]]:
293 """Create a Hugging Face model card for a BioImage.IO model.
295 Returns:
296 A tuple of (markdown_string, images_dict) where images_dict maps
297 filenames to PNG bytes that should be saved alongside the markdown.
298 """
299 model = model.model_copy()
301 if model.version is None:
302 model_version = ""
303 else:
304 model_version = f"\n- **model version:** {model.version}"
306 if model.documentation is None:
307 additional_model_doc = ""
308 else:
309 doc_reader = get_reader(model.documentation)
310 local_doc_path = f"package/{doc_reader.original_file_name}"
311 with get_validation_context().replace(perform_io_checks=False):
312 model.documentation = FileDescr(
313 source=RelativeFilePath(PurePosixPath(local_doc_path))
314 )
316 additional_model_doc = f"\n- **Additional model documentation:** [{local_doc_path}]({local_doc_path})"
318 if model.cite:
319 developed_by = "\n- **Developed by:** " + (
320 "".join(
321 (
322 f"\n - {c.text}: "
323 + (f"https://www.doi.org/{c.doi}" if c.doi else str(c.url))
324 )
325 for c in model.cite
326 )
327 )
328 else:
329 developed_by = ""
331 if model.config.bioimageio.funded_by:
332 funded_by = f"\n- **Funded by:** {model.config.bioimageio.funded_by}"
333 else:
334 funded_by = ""
336 if model.authors:
337 shared_by = "\n- **Shared by:** " + (
338 "".join(
339 (
340 f"\n - {a.name}"
341 + (f", {a.affiliation}" if a.affiliation else "")
342 + (
343 f", [https://orcid.org/{a.orcid}](https://orcid.org/{a.orcid})"
344 if a.orcid
345 else ""
346 )
347 + (
348 f", [https://github.com/{a.github_user}](https://github.com/{a.github_user})"
349 if a.github_user
350 else ""
351 )
352 for a in model.authors
353 )
354 )
355 )
356 else:
357 shared_by = ""
359 if model.config.bioimageio.architecture_type:
360 model_type = f"\n- **Model type:** {model.config.bioimageio.architecture_type}"
361 else:
362 model_type = ""
364 if model.config.bioimageio.modality:
365 model_modality = f"\n- **Modality:** {model.config.bioimageio.modality}"
366 else:
367 model_modality = ""
369 if model.config.bioimageio.target_structure:
370 target_structures = "\n- **Target structures:** " + ", ".join(
371 model.config.bioimageio.target_structure
372 )
373 else:
374 target_structures = ""
376 if model.config.bioimageio.task:
377 task_type = f"\n- **Task type:** {model.config.bioimageio.task}"
378 else:
379 task_type = ""
381 if model.parent:
382 finetuned_from = f"\n- **Finetuned from model:** {model.parent.id}"
383 else:
384 finetuned_from = ""
386 repository = (
387 f"[{model.git_repo}]({model.git_repo})" if model.git_repo else "missing"
388 )
390 dl_framework_parts: List[str] = []
391 training_frameworks: List[str] = []
392 model_size: Optional[str] = None
393 for weights in model.weights.available_formats.values():
394 if isinstance(weights, (PytorchStateDictWeightsDescr, TorchscriptWeightsDescr)):
395 dl_framework_version = weights.pytorch_version
396 elif isinstance(
397 weights,
398 (
399 TensorflowSavedModelBundleWeightsDescr,
400 TensorflowJsWeightsDescr,
401 KerasHdf5WeightsDescr,
402 ),
403 ):
404 dl_framework_version = weights.tensorflow_version
405 elif isinstance(weights, KerasV3WeightsDescr):
406 dl_framework_version = weights.keras_version
407 elif isinstance(weights, OnnxWeightsDescr):
408 dl_framework_version = f"opset version: {weights.opset_version}"
409 else:
410 assert_never(weights)
412 if weights.parent is None:
413 training_frameworks.append(weights.weights_format_name)
415 dl_framework_parts.append(
416 f"\n - {weights.weights_format_name}: {dl_framework_version}"
417 )
419 if model_size is None:
420 s = 0
421 r = weights.get_reader()
422 for chunk in iter(partial(r.read, 128 * 1024), b""):
423 s += len(chunk)
425 if model.config.bioimageio.model_parameter_count is not None:
426 if model.config.bioimageio.model_parameter_count < 1e9:
427 model_size = f"{model.config.bioimageio.model_parameter_count / 1e6:.2f} million parameters, "
428 else:
429 model_size = f"{model.config.bioimageio.model_parameter_count / 1e9:.2f} billion parameters, "
430 else:
431 model_size = ""
433 if s < 1e9:
434 model_size += f"{s / 1e6:.2f} MB"
435 else:
436 model_size += f"{s / 1e9:.2f} GB"
438 dl_frameworks = "".join(dl_framework_parts)
439 if len(training_frameworks) > 1:
440 warnings.warn(
441 "Multiple training frameworks detected. (Some weight formats are probably missing a `parent` reference.)"
442 )
444 if (
445 model.weights.pytorch_state_dict is not None
446 and model.weights.pytorch_state_dict.dependencies is not None
447 ):
448 env_reader = model.weights.pytorch_state_dict.dependencies.get_reader()
449 dependencies = f"Dependencies for Pytorch State dict weights are listed in [{env_reader.original_file_name}](package/{env_reader.original_file_name})."
450 else:
451 dependencies = "None beyond the respective framework library."
453 out_of_scope_use = (
454 model.config.bioimageio.out_of_scope_use
455 if model.config.bioimageio.out_of_scope_use
456 else """missing; therefore these typical limitations should be considered:
458- *Likely not suitable for diagnostic purposes.*
459- *Likely not validated for different imaging modalities than present in the training data.*
460- *Should not be used without proper validation on user's specific datasets.*
462"""
463 )
465 environmental_impact = model.config.bioimageio.environmental_impact.format_md()
466 if environmental_impact:
467 environmental_impact_toc_entry = (
468 "\n- [Environmental Impact](#environmental-impact)"
469 )
470 else:
471 environmental_impact_toc_entry = ""
473 evaluation_parts: List[str] = []
474 n_evals = 0
475 for e in model.config.bioimageio.evaluations:
476 if e.dataset_role == "independent":
477 continue # treated separately below
479 n_evals += 1
480 n_evals_str = "" if n_evals == 1 else f" {n_evals}"
481 evaluation_parts.append(f"\n# Evaluation{n_evals_str}\n")
482 evaluation_parts.append(e.format_md())
484 n_evals = 0
485 for e in model.config.bioimageio.evaluations:
486 if e.dataset_role != "independent":
487 continue # treated separately above
489 n_evals += 1
490 n_evals_str = "" if n_evals == 1 else f" {n_evals}"
492 evaluation_parts.append(f"### Validation on External Data{n_evals_str}\n")
493 evaluation_parts.append(e.format_md())
495 if evaluation_parts:
496 evaluation = "\n".join(evaluation_parts)
497 evaluation_toc_entry = "\n- [Evaluation](#evaluation)"
498 else:
499 evaluation = ""
500 evaluation_toc_entry = ""
502 training_details = ""
503 if model.config.bioimageio.training.training_preprocessing:
504 training_details += f"### Preprocessing\n\n{model.config.bioimageio.training.training_preprocessing}\n\n"
506 training_details += "### Training Hyperparameters\n\n"
507 training_details += f"- **Framework:** {' / '.join(training_frameworks)}"
508 if model.config.bioimageio.training.training_epochs is not None:
509 training_details += (
510 f"- **Epochs:** {model.config.bioimageio.training.training_epochs}\n"
511 )
513 if model.config.bioimageio.training.training_batch_size is not None:
514 training_details += f"- **Batch size:** {model.config.bioimageio.training.training_batch_size}\n"
516 if model.config.bioimageio.training.initial_learning_rate is not None:
517 training_details += f"- **Initial learning rate:** {model.config.bioimageio.training.initial_learning_rate}\n"
519 if model.config.bioimageio.training.learning_rate_schedule is not None:
520 training_details += f"- **Learning rate schedule:** {model.config.bioimageio.training.learning_rate_schedule}\n"
522 if model.config.bioimageio.training.loss_function is not None:
523 training_details += (
524 f"- **Loss function:** {model.config.bioimageio.training.loss_function}"
525 )
526 if model.config.bioimageio.training.loss_function_kwargs:
527 training_details += (
528 f" with {model.config.bioimageio.training.loss_function_kwargs}"
529 )
530 training_details += "\n"
532 if model.config.bioimageio.training.optimizer is not None:
533 training_details += (
534 f"- **Optimizer:** {model.config.bioimageio.training.optimizer}"
535 )
536 if model.config.bioimageio.training.optimizer_kwargs:
537 training_details += (
538 f" with {model.config.bioimageio.training.optimizer_kwargs}"
539 )
540 training_details += "\n"
542 if model.config.bioimageio.training.regularization is not None:
543 training_details += (
544 f"- **Regularization:** {model.config.bioimageio.training.regularization}\n"
545 )
547 speeds_sizes_times = "### Speeds, Sizes, Times\n\n"
548 if model.config.bioimageio.training.training_duration is not None:
549 speeds_sizes_times += f"- **Training time:** {'{:.2f}'.format(model.config.bioimageio.training.training_duration)}\n"
551 speeds_sizes_times += f"- **Model size:** {model_size}\n"
552 if model.config.bioimageio.inference_time:
553 speeds_sizes_times += (
554 f"- **Inference time:** {model.config.bioimageio.inference_time}\n"
555 )
557 if model.config.bioimageio.memory_requirements_inference:
558 speeds_sizes_times += f"- **Memory requirements:** {model.config.bioimageio.memory_requirements_inference}\n"
560 model_arch_and_objective = "## Model Architecture and Objective\n\n"
561 if (
562 model.config.bioimageio.architecture_type
563 or model.config.bioimageio.architecture_description
564 ):
565 model_arch_and_objective += (
566 f"- **Architecture:** {model.config.bioimageio.architecture_type or ''}"
567 + (
568 " --- "
569 if model.config.bioimageio.architecture_type
570 and model.config.bioimageio.architecture_description
571 else ""
572 )
573 + (
574 model.config.bioimageio.architecture_description
575 if model.config.bioimageio.architecture_description is not None
576 else ""
577 )
578 + "\n"
579 )
581 io_desc, referenced_files, input_ids, output_ids = _get_io_description(model)
582 predict_snippet_inputs = str(
583 {input_id: "<path or tensor>" for input_id in input_ids}
584 )
585 model_arch_and_objective += io_desc
587 hardware_requirements = "\n### Hardware Requirements\n"
588 if model.config.bioimageio.memory_requirements_training is not None:
589 hardware_requirements += f"- **Training:** GPU memory: {model.config.bioimageio.memory_requirements_training}\n"
591 if model.config.bioimageio.memory_requirements_inference is not None:
592 hardware_requirements += f"- **Inference:** GPU memory: {model.config.bioimageio.memory_requirements_inference}\n"
594 hardware_requirements += f"- **Storage:** Model size: {model_size}\n"
596 if model.license is None:
597 license = "unknown"
598 license_meta = "unknown"
599 elif isinstance(model.license, FileDescr):
600 license_reader = get_reader(model.license)
601 local_license_path = f"package/{license_reader.original_file_name}"
602 with get_validation_context().replace(perform_io_checks=False):
603 model.license.source = RelativeFilePath(PurePosixPath(local_license_path))
605 license = f"[{local_license_path}]({local_license_path})"
606 license_meta = "unknown"
607 else:
608 spdx_licenses = get_spdx_licenses()
609 matches = [
610 (entry["name"], entry["reference"])
611 for entry in spdx_licenses["licenses"]
612 if entry["licenseId"].lower() == model.license.lower()
613 ]
614 if matches:
615 if len(matches) > 1:
616 logger.warning(
617 "Multiple SPDX license matches found for '{}', using the first one.",
618 model.license,
619 )
620 name, reference = matches[0]
621 license = f"[{name}]({reference})"
622 if model.license.lower() in HF_KNOWN_LICENSES:
623 license_meta = model.license.lower()
624 else:
625 license_meta = f"other\nlicense_name: {model.license.lower()}\nlicense_link: {reference}"
626 else:
627 if model.license.lower() in HF_KNOWN_LICENSES:
628 license_meta = model.license.lower()
629 else:
630 license_meta = "unknown"
632 license = model.license.lower()
634 base_model = (
635 f"\nbase_model: {model.parent.id[len('huggingface/') :]}"
636 if model.parent is not None and model.parent.id.startswith("huggingface/")
637 else ""
638 )
639 dataset_meta = (
640 f"\ndataset: {model.training_data.id[len('huggingface/') :]}"
641 if model.training_data is not None
642 and model.training_data.id is not None
643 and model.training_data.id.startswith("huggingface/")
644 else ""
645 )
646 if model.covers:
647 cover_image_reader = get_reader(model.covers[0])
648 cover_image_bytes = cover_image_reader.read()
649 cover_image_filename = f"images/{cover_image_reader.original_file_name}"
650 referenced_files[cover_image_filename] = cover_image_bytes
651 cover_image_md = f"\n\n\n"
652 thumbnail_meta = (
653 f"\nthumbnail: {cover_image_filename}" # TODO: fix this to be a proper URL
654 )
656 else:
657 cover_image_md = ""
658 thumbnail_meta = ""
660 # TODO: add pipeline_tag to metadata
661 readme = f"""---
662license: {license_meta}{thumbnail_meta}
663tags: {list({"biology"}.union(set(model.tags)))}
664language: [en]
665library_name: bioimageio{base_model}{dataset_meta}
666---
667# {model.name}{cover_image_md}
669{model.description or ""}
672# Table of Contents
674- [Model Details](#model-details)
675- [Uses](#uses)
676- [Bias, Risks, and Limitations](#bias-risks-and-limitations)
677- [How to Get Started with the Model](#how-to-get-started-with-the-model)
678- [Training Details](#training-details){evaluation_toc_entry}{
679 environmental_impact_toc_entry
680 }
681- [Technical Specifications](#technical-specifications)
684# Model Details
686## Model Description
687{model_version}{additional_model_doc}{developed_by}{funded_by}{shared_by}{model_type}{
688 model_modality
689 }{target_structures}{task_type}
690- **License:** {license}{finetuned_from}
692## Model Sources
694- **Repository:** {repository}
695- **Paper:** see [**Developed by**](#model-description)
697# Uses
699## Direct Use
701This model is compatible with the bioimageio.spec Python package (version >= {
702 VERSION
703 }) and the bioimageio.core Python package supporting model inference in Python code or via the `bioimageio` CLI.
705```python
706from bioimageio.core import predict
708output_sample = predict(
709 "huggingface/{repo_id}/{model.version or "draft"}",
710 inputs={predict_snippet_inputs},
711)
713output_tensor = output_sample.members["{
714 output_ids[0] if output_ids else "<output_id>"
715 }"]
716xarray_dataarray = output_tensor.data
717numpy_ndarray = output_tensor.data.to_numpy()
718```
720## Downstream Use
722Specific bioimage.io partner tool compatibilities may be reported at [Compatibility Reports](https://bioimage-io.github.io/collection/latest/compatibility/#compatibility-by-resource).
723{
724 "Training (and fine-tuning) code may be available at " + model.git_repo + "."
725 if model.git_repo
726 else ""
727 }
729## Out-of-Scope Use
731{out_of_scope_use}
734{model.config.bioimageio.bias_risks_limitations.format_md()}
736# How to Get Started with the Model
738You can use "huggingface/{repo_id}/{
739 model.version or "draft"
740 }" as the resource identifier to load this model directly from the Hugging Face Hub using bioimageio.spec or bioimageio.core.
742See [bioimageio.core documentation: Get started](https://bioimage-io.github.io/core-bioimage-io-python/latest/get-started) for instructions on how to load and run this model using the `bioimageio.core` Python package or the bioimageio CLI.
744# Training Details
746## Training Data
748{
749 "This model was trained on `" + str(model.training_data.id) + "`."
750 if model.training_data is not None
751 else "missing"
752 }
754## Training Procedure
756{training_details}
758{speeds_sizes_times}
759{evaluation}
760{environmental_impact}
762# Technical Specifications
764{model_arch_and_objective}
766## Compute Infrastructure
768{hardware_requirements}
770### Software
772- **Framework:** {dl_frameworks}
773- **Libraries:** {dependencies}
774- **BioImage.IO partner compatibility:** [Compatibility Reports](https://bioimage-io.github.io/collection/latest/compatibility/#compatibility-by-resource)
776---
778*This model card was created using the template of the bioimageio.spec Python Package, which intern is based on the BioImage Model Zoo template, incorporating best practices from the Hugging Face Model Card Template. For more information on contributing models, visit [bioimage.io](https://bioimage.io).*
780---
782**References:**
784- [Hugging Face Model Card Template](https://huggingface.co/docs/hub/en/model-card-annotated)
785- [Hugging Face modelcard_template.md](https://github.com/huggingface/huggingface_hub/blob/b9decfdf9b9a162012bc52f260fd64fc37db660e/src/huggingface_hub/templates/modelcard_template.md)
786- [BioImage Model Zoo Documentation](https://bioimage.io/docs/)
787- [Model Cards for Model Reporting](https://arxiv.org/abs/1810.03993)
788- [bioimageio.spec Python Package](https://bioimage-io.github.io/spec-bioimage-io)
789"""
791 return readme, referenced_files