Download examples/infer_tensor.py from simon-donike/SR-GAN: direct link, hf CLI and curl.
- Browser
- Download file 4.83 kB
-
https://huggingface.co/simon-donike/SR-GAN/resolve/main/examples/infer_tensor.py
- Command line
-
hf download hf://simon-donike/SR-GAN/examples/infer_tensor.py
-
curl -L -o infer_tensor.py https://huggingface.co/simon-donike/SR-GAN/resolve/main/examples/infer_tensor.py
4.83 kB
| # SPDX-License-Identifier: MIT | |
| """Run an SR-GAN preset on one small BCHW tensor saved with ``torch.save``.""" | |
| from __future__ import annotations | |
| import argparse | |
| from collections.abc import Mapping, Sequence | |
| from pathlib import Path | |
| from typing import Any | |
| import torch | |
| from opensr_srgan import load_inference_model | |
| def _tensor_from_payload(payload: Any, *, source: str) -> torch.Tensor: | |
| """Extract an LR tensor from common dataset serialization layouts.""" | |
| if isinstance(payload, torch.Tensor): | |
| return payload | |
| if isinstance(payload, Mapping): | |
| for key in ("lr", "lr_imgs", "input", "image", "x"): | |
| if key in payload: | |
| return _tensor_from_payload(payload[key], source=f"{source}[{key!r}]") | |
| tensors = [value for value in payload.values() if isinstance(value, torch.Tensor)] | |
| if len(tensors) == 1: | |
| return tensors[0] | |
| raise ValueError( | |
| f"{source} is a dictionary without a recognized LR key. " | |
| "Use one of: lr, lr_imgs, input, image, x." | |
| ) | |
| if isinstance(payload, Sequence) and not isinstance(payload, (str, bytes)): | |
| for index, value in enumerate(payload): | |
| if isinstance(value, torch.Tensor): | |
| return value | |
| raise ValueError(f"{source} contains no tensor; expected an LR tensor or (lr, hr).") | |
| raise TypeError(f"{source} must contain a torch.Tensor, got {type(payload).__name__}.") | |
| def _load_input(path: Path) -> torch.Tensor: | |
| try: | |
| payload = torch.load(path, map_location="cpu", weights_only=True) | |
| except TypeError: # PyTorch versions before ``weights_only`` accepted this argument. | |
| payload = torch.load(path, map_location="cpu") | |
| return _tensor_from_payload(payload, source=str(path)) | |
| def _as_bchw(tensor: torch.Tensor, *, channels: int) -> torch.Tensor: | |
| if tensor.dtype == torch.bool or tensor.is_complex(): | |
| raise TypeError(f"Expected real-valued input, got dtype {tensor.dtype}.") | |
| if tensor.ndim == 3: | |
| tensor = tensor.unsqueeze(0) | |
| if tensor.ndim != 4: | |
| raise ValueError(f"Expected CHW or BCHW input, got shape {tuple(tensor.shape)}.") | |
| if tensor.shape[1] != channels: | |
| raise ValueError(f"Preset expects {channels} channels, got shape {tuple(tensor.shape)}.") | |
| tensor = tensor.float() | |
| if not torch.isfinite(tensor).all(): | |
| raise ValueError("Input contains NaN or infinite values.") | |
| return tensor.contiguous() | |
| def _parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--preset", choices=("SEN2-SR", "RGB-NIR", "SWIR"), default="SEN2-SR") | |
| parser.add_argument("--device", default="cpu", help="Torch device, for example cpu or cuda.") | |
| parser.add_argument("--input", type=Path, help="A torch.save tensor, (lr, hr), or supported mapping.") | |
| parser.add_argument("--output", type=Path, default=Path("sr.pt"), help="Destination BCHW tensor.") | |
| parser.add_argument("--revision", help="Optional Hugging Face commit, tag, or branch to resolve.") | |
| parser.add_argument( | |
| "--raw", | |
| action="store_true", | |
| help="Use forward on an already normalized 0..1 tensor; skip predict_step handling.", | |
| ) | |
| parser.add_argument( | |
| "--smoke", | |
| action="store_true", | |
| help="Use a generated zero tensor only to verify installation and output shape.", | |
| ) | |
| args = parser.parse_args() | |
| if args.smoke == (args.input is not None): | |
| parser.error("provide exactly one of --input or --smoke") | |
| return args | |
| def main() -> None: | |
| args = _parse_args() | |
| device = torch.device(args.device) | |
| model = load_inference_model( | |
| args.preset, map_location=device, revision=args.revision | |
| ).to(device) | |
| model.eval() | |
| channels = int(model.config.Model.in_bands) | |
| scale = int(model.config.Generator.scaling_factor) | |
| input_tensor = ( | |
| torch.zeros((1, channels, 16, 16), dtype=torch.float32) | |
| if args.smoke | |
| else _load_input(args.input) | |
| ) | |
| input_tensor = _as_bchw(input_tensor, channels=channels) | |
| with torch.inference_mode(): | |
| if args.raw: | |
| output = model(input_tensor.to(device)).detach().cpu() | |
| convention = "normalized network output (forward; no post-processing)" | |
| else: | |
| output = model.predict_step(input_tensor) | |
| convention = "raw DN/reflectance output (predict_step)" | |
| args.output.parent.mkdir(parents=True, exist_ok=True) | |
| torch.save(output, args.output) | |
| source = "generated smoke tensor" if args.smoke else str(args.input) | |
| print( | |
| f"Saved {tuple(output.shape)} to {args.output} from {source}; " | |
| f"preset={args.preset}, scale={scale}, convention={convention}." | |
| ) | |
| if __name__ == "__main__": | |
| main() | |