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