Download script/utils.py from OneScience-Group/Earthformer: direct link, hf CLI and curl.
- Browser
- Download file 3.79 kB
-
https://huggingface.co/OneScience-Group/Earthformer/resolve/main/script/utils.py
- Command line
-
hf download hf://OneScience-Group/Earthformer/script/utils.py
-
curl -L -o utils.py https://huggingface.co/OneScience-Group/Earthformer/resolve/main/script/utils.py
3.79 kB
| from __future__ import annotations | |
| import os | |
| from pathlib import Path | |
| from typing import Any | |
| import torch | |
| import yaml | |
| ROOT = Path(__file__).resolve().parents[1] | |
| DEFAULT_CONFIG = ROOT / "conf/config.yaml" | |
| def load_config(path: str | Path = DEFAULT_CONFIG) -> dict[str, Any]: | |
| config_path = Path(path).expanduser().resolve() | |
| with config_path.open("r", encoding="utf-8") as handle: | |
| config = yaml.safe_load(handle) | |
| if not isinstance(config, dict): | |
| raise ValueError("configuration must be a YAML mapping") | |
| for section in ("data", "model", "train", "dataloader", "distributed"): | |
| if section not in config: | |
| raise ValueError(f"missing configuration section: {section}") | |
| data, model = config["data"], config["model"] | |
| for key in ("input_length", "output_length", "height", "width", "channels"): | |
| if int(data.get(key, 0)) <= 0: | |
| raise ValueError(f"data.{key} must be positive") | |
| if int(data["height"]) % 4 or int(data["width"]) % 4: | |
| raise ValueError("data height and width must be divisible by four") | |
| dims, depths = model.get("dims"), model.get("depths") | |
| if not isinstance(dims, list) or len(dims) != 2 or int(dims[1]) != 2 * int(dims[0]): | |
| raise ValueError("model.dims must be [D, 2*D]") | |
| if not isinstance(depths, list) or len(depths) != 2 or min(int(x) for x in depths) < 1: | |
| raise ValueError("model.depths must contain two positive integers") | |
| heads = int(model.get("heads", 0)) | |
| if heads < 1 or any(int(dim) % heads for dim in dims): | |
| raise ValueError("model.heads must divide both hidden dimensions") | |
| normalization = data.get("normalization", "unit") | |
| if normalization not in ("unit", "uint8_255"): | |
| raise ValueError("data.normalization must be 'unit' or 'uint8_255'") | |
| for key in ("data_dir", "train_npz", "val_npz", "test_npz"): | |
| if data.get(key): | |
| value = Path(data[key]).expanduser() | |
| data[key] = str(value if value.is_absolute() else ROOT / value) | |
| output_dir = Path(config["train"]["output_dir"]).expanduser() | |
| config["train"]["output_dir"] = str(output_dir if output_dir.is_absolute() else ROOT / output_dir) | |
| return config | |
| def resolve_device(requested: str, local_rank: int = 0) -> torch.device: | |
| if requested not in ("auto", "cpu", "cuda"): | |
| raise ValueError("device must be auto, cpu, or cuda") | |
| use_accelerator = requested == "cuda" or (requested == "auto" and torch.cuda.is_available()) | |
| if use_accelerator: | |
| if not torch.cuda.is_available(): | |
| raise RuntimeError("CUDA/ROCm device requested but torch.cuda.is_available() is false") | |
| torch.cuda.set_device(local_rank) | |
| return torch.device("cuda", local_rank) | |
| return torch.device("cpu") | |
| def resolve_cli_path(value: str | None) -> str | None: | |
| if not value: | |
| return value | |
| path = Path(value).expanduser() | |
| return str(path if path.is_absolute() else ROOT / path) | |
| def load_checkpoint_payload(path: str | Path, device: torch.device) -> dict[str, Any]: | |
| payload = torch.load(path, map_location=device, weights_only=False) | |
| if not isinstance(payload, dict) or "model" not in payload or "config" not in payload: | |
| raise ValueError("checkpoint must contain model and config") | |
| return payload | |
| def clean_state_dict(state_dict: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: | |
| return {key.removeprefix("module."): value for key, value in state_dict.items()} | |
| def atomic_torch_save(payload: dict[str, Any], path: str | Path) -> Path: | |
| path = Path(path) | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| temporary = path.with_name(f".{path.name}.{os.getpid()}.tmp") | |
| torch.save(payload, temporary) | |
| os.replace(temporary, path) | |
| return path | |