Instructions to use phi-lab-rice/GRADE with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use phi-lab-rice/GRADE with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("phi-lab-rice/GRADE", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
Download evaluation/utils/common.py from phi-lab-rice/GRADE: direct link, hf CLI and curl.
- Browser
- Download file 9.63 kB
-
https://huggingface.co/phi-lab-rice/GRADE/resolve/main/evaluation/utils/common.py
- Command line
-
hf download hf://phi-lab-rice/GRADE/evaluation/utils/common.py
-
curl -L -o common.py https://huggingface.co/phi-lab-rice/GRADE/resolve/main/evaluation/utils/common.py
9.63 kB
| from __future__ import annotations | |
| import os | |
| from pathlib import Path | |
| from typing import Iterable | |
| import numpy as np | |
| import pandas as pd | |
| from PIL import Image | |
| from model_registry import canonical_model_name | |
| ROOT = Path(__file__).resolve().parent | |
| EVALUATION_DIR = ROOT.parent | |
| REFERENCE_RESULTS_DIR = EVALUATION_DIR / "reference_results" | |
| # Fixed paper inputs are deliberately separate from fresh evaluator output. A | |
| # reproduction run can override only MERGED_DIR to consume newly computed CSVs; | |
| # it never needs to mutate the golden source material. | |
| REFERENCE_DATA_DIR = REFERENCE_RESULTS_DIR / "pre_eval_results" | |
| DATA_DIR = Path(os.environ.get("GRADE_REFERENCE_DATA_DIR", str(REFERENCE_DATA_DIR))) | |
| REFERENCE_MERGED_DIR = REFERENCE_DATA_DIR / "csv" | |
| GENERATED_MERGED_DIR = EVALUATION_DIR / "metric_results" / "merged_csv" | |
| MERGED_DIR = Path(os.environ.get("GRADE_MERGED_DIR", str(REFERENCE_MERGED_DIR))) | |
| OUTPUT_DIR = EVALUATION_DIR / "reproduced_results" | |
| METRICS = ["MAE", "SSIM", "LPIPS", "CD", "MHD"] | |
| GRADIENT_ERROR = "GradientError" | |
| ERROR_METRICS = {"MAE", "LPIPS", "CD", "MHD", GRADIENT_ERROR} | |
| # GradientError sits around 2.5e-3, so 3 decimals collapses the variants together. | |
| DEFAULT_PRECISION = 3 | |
| METRIC_PRECISION = {GRADIENT_ERROR: 4} | |
| def load_merged(name: str) -> pd.DataFrame: | |
| path = MERGED_DIR / f"{canonical_model_name(name)}.csv" | |
| if not path.is_file(): | |
| raise FileNotFoundError(f"Missing evaluation CSV: {path}") | |
| frame = pd.read_csv(path) | |
| required = {"sequences", "frame_idx", "R", "IR", *METRICS} | |
| missing = required.difference(frame.columns) | |
| if missing: | |
| raise ValueError(f"{path} is missing columns: {sorted(missing)}") | |
| return frame | |
| def available_methods(methods: list[tuple[str, str]]) -> list[tuple[str, str]]: | |
| """Keep only computed model rows in local mode; require all rows in saved mode.""" | |
| if os.environ.get("GRADE_REPRODUCTION_MODE") != "local": | |
| return methods | |
| available = [ | |
| (label, variant) for label, variant in methods | |
| if (MERGED_DIR / f"{canonical_model_name(variant)}.csv").is_file() | |
| ] | |
| if not available: | |
| raise FileNotFoundError(f"No model CSVs for this table in {MERGED_DIR}") | |
| return available | |
| def load_aligned_merged(names: Iterable[str]) -> dict[str, pd.DataFrame]: | |
| """Load variants on their shared (sequence, frame) evaluation support. | |
| RadarCam-Depth omits frames without a valid radar point cloud. Figures | |
| comparing empirical distributions must therefore use the intersection of | |
| frame keys rather than silently giving each method a different sample set. | |
| """ | |
| names = list(names) | |
| if not names: | |
| return {} | |
| frames = {name: load_merged(name) for name in names} | |
| keys: pd.MultiIndex | None = None | |
| for name, frame in frames.items(): | |
| if frame.duplicated(["sequences", "frame_idx"]).any(): | |
| raise ValueError(f"{name} has duplicate (sequences, frame_idx) rows") | |
| current = pd.MultiIndex.from_frame(frame[["sequences", "frame_idx"]]) | |
| keys = current if keys is None else keys.intersection(current, sort=False) | |
| if keys is None: | |
| raise RuntimeError("No frame keys were available to align merged results.") | |
| key_frame = keys.to_frame(index=False) | |
| key_frame.columns = ["sequences", "frame_idx"] | |
| aligned = { | |
| name: key_frame.merge( | |
| frame, | |
| on=["sequences", "frame_idx"], | |
| how="left", | |
| validate="one_to_one", | |
| ) | |
| for name, frame in frames.items() | |
| } | |
| return aligned | |
| def clear_mask(frame: pd.DataFrame) -> pd.Series: | |
| return frame["sequences"].astype(str).str.endswith("-0") | |
| def overall_split(frame: pd.DataFrame) -> dict[str, pd.DataFrame]: | |
| """Paper split: clear sequences and smoke frames with IR >= 2000.""" | |
| is_clear = clear_mask(frame) | |
| return { | |
| "Clear": frame.loc[is_clear].copy(), | |
| "Smoke": frame.loc[(~is_clear) & (frame["IR"] >= 2000)].copy(), | |
| } | |
| def add_smoke_class(frame: pd.DataFrame) -> pd.DataFrame: | |
| """Paper density split using the MAX30105 infrared reading. | |
| Light smoke has IR < 2000, medium smoke has 2000 <= IR < 4000, and heavy | |
| smoke has IR >= 4000. | |
| """ | |
| frame = frame.copy() | |
| is_clear = clear_mask(frame) | |
| readings = frame["IR"].to_numpy(dtype=float) | |
| smoke_class = np.select( | |
| [readings < 2000, (readings >= 2000) & (readings < 4000), readings >= 4000], | |
| ["light", "medium", "heavy"], | |
| default="unclassified", | |
| ) | |
| frame["Smoke class"] = np.where( | |
| is_clear, | |
| "clear", | |
| smoke_class, | |
| ) | |
| return frame | |
| def metric_medians(frame: pd.DataFrame, metrics: list[str] | None = None) -> dict[str, float]: | |
| return {metric: float(frame[metric].median()) for metric in metrics or METRICS} | |
| def format_metrics(values: dict[str, float], metrics: list[str] | None = None) -> list[str]: | |
| return [ | |
| f"{values[metric]:.{METRIC_PRECISION.get(metric, DEFAULT_PRECISION)}f}" | |
| for metric in metrics or METRICS | |
| ] | |
| def print_metric_table( | |
| title: str, | |
| groups: dict[str, list[tuple[str, list[str]]]], | |
| label_header: str = "Method", | |
| metrics: list[str] | None = None, | |
| headers: list[str] | None = None, | |
| highlight: bool = False, | |
| ) -> None: | |
| """Print grouped metric rows as an aligned plain-text table. | |
| When ``highlight`` is true, ``[1]``/``[2]`` marks the best and second-best | |
| displayed value in each metric column. Ties share a rank. | |
| """ | |
| metrics = metrics or METRICS | |
| headers = headers or metrics | |
| if len(headers) != len(metrics): | |
| raise ValueError("headers and metrics must have the same length") | |
| ranks_by_group = { | |
| group: compute_ranks(dict(rows), metrics) if highlight else {} | |
| for group, rows in groups.items() | |
| } | |
| def render(group: str, label: str, values: list[str]) -> list[str]: | |
| ranks = ranks_by_group[group].get(label, [0] * len(values)) | |
| suffix = {1: "[1]", 2: "[2]"} | |
| return [f"{value}{suffix.get(rank, '')}" for value, rank in zip(values, ranks)] | |
| labels = [label for rows in groups.values() for label, _ in rows] | |
| width = max(len(label_header), *(len(label) for label in labels)) | |
| rendered = { | |
| group: [(label, render(group, label, values)) for label, values in rows] | |
| for group, rows in groups.items() | |
| } | |
| columns = [ | |
| max( | |
| 7, | |
| len(header), | |
| *( | |
| len(values[index]) | |
| for rows in rendered.values() | |
| for _, values in rows | |
| ), | |
| ) | |
| for index, header in enumerate(headers) | |
| ] | |
| header = f"{label_header:<{width}} " + " ".join( | |
| f"{name:>{size}}" for name, size in zip(headers, columns) | |
| ) | |
| print(f"\n{title}") | |
| print("=" * len(header)) | |
| for group, rows in rendered.items(): | |
| print(f"\n{group}") | |
| print("-" * len(header)) | |
| print(header) | |
| for label, values in rows: | |
| cells = " ".join(f"{value:>{size}}" for value, size in zip(values, columns)) | |
| print(f"{label:<{width}} {cells}") | |
| if highlight: | |
| print("\n[1] best; [2] second-best (ties share rank at displayed precision)") | |
| print() | |
| def compute_ranks( | |
| rows: dict[str, list[str]], metrics: list[str] | None = None | |
| ) -> dict[str, list[int]]: | |
| """Rank 1 = best, 2 = second best, per metric column, at displayed precision. | |
| Ties share a rank, so two methods printing the same rounded value are both | |
| highlighted rather than one arbitrarily winning. | |
| """ | |
| metrics = metrics or METRICS | |
| ranks = {label: [0] * len(metrics) for label in rows} | |
| for index, metric in enumerate(metrics): | |
| column = {label: float(values[index]) for label, values in rows.items()} | |
| ordered = sorted(set(column.values()), reverse=metric not in ERROR_METRICS) | |
| for label, value in column.items(): | |
| position = ordered.index(value) | |
| if position < 2: | |
| ranks[label][index] = position + 1 | |
| return ranks | |
| def tex_cell(value: str, rank: int = 0) -> str: | |
| if rank == 1: | |
| return rf"\cellcolor{{blue!18}}\textbf{{{value}}}" | |
| if rank == 2: | |
| return rf"\cellcolor{{blue!8}}{value}" | |
| return value | |
| def tex_row(label: str, values: Iterable[str], ranks: Iterable[int] | None = None) -> str: | |
| values = list(values) | |
| ranks = list(ranks) if ranks is not None else [0] * len(values) | |
| cells = [tex_cell(value, rank) for value, rank in zip(values, ranks)] | |
| return f"{label} & " + " & ".join(cells) + r" \\" | |
| def write_output(path: Path, content: str) -> None: | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| path.write_text(content.rstrip() + "\n", encoding="utf-8") | |
| print(f"Saved {path}") | |
| def normalize_canvas(path: Path, target_width: int, target_height: int) -> None: | |
| """Center-crop/pad tight-bbox output to the camera-ready raster dimensions.""" | |
| with Image.open(path) as source: | |
| source = source.convert("RGBA") | |
| left = max(0, (source.width - target_width) // 2) | |
| top = max(0, (source.height - target_height) // 2) | |
| cropped = source.crop( | |
| ( | |
| left, | |
| top, | |
| min(source.width, left + target_width), | |
| min(source.height, top + target_height), | |
| ) | |
| ) | |
| canvas = Image.new("RGBA", (target_width, target_height), "white") | |
| canvas.paste( | |
| cropped, | |
| ((target_width - cropped.width) // 2, (target_height - cropped.height) // 2), | |
| ) | |
| canvas.save(path) | |