Nanny7's picture
feat: initial commit for B Map AI backend and Gemma LLM service
2f86d9b
Raw History Blame Contribute Delete
6.6 kB
# Copyright 2026 DeepMind Technologies Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
r"""Evaluation binary for Hackable Diffusion adapter.
Runs AR sampling evaluation on a single checkpoint and reports task-specific
metrics (accuracy, BLEU, etc.) plus text sample summaries.
"""
from __future__ import annotations
from absl import app
from absl import flags
from absl import logging
from gemma.diffusion.hackable_diffusion_adapter.eval import ar_eval
import jax
from kauldron import kd
import tensorflow as tf
# pylint: disable=g-import-not-at-top
with kd.konfig.imports():
from kauldron import kd as kd_cfg # pylint: disable=reimported
from gemma.diffusion.hackable_diffusion_adapter.eval import sudoku_eval as sudoku_eval_cfg
from gemma.diffusion.hackable_diffusion_adapter.eval import pubmedqa_eval as pubmedqa_eval_cfg
# pylint: enable=g-import-not-at-top
################################################################################
# MARK: Flags
################################################################################
_CONFIG = kd.konfig.DEFINE_config_file(
"cfg",
None,
"Training configuration.",
lock_config=False,
)
_TASK = flags.DEFINE_enum(
"task",
None,
["sudoku", "pubmedqa"],
"Task to evaluate. Determines which metrics are reported.",
)
_EVAL_NAMES = flags.DEFINE_list(
"eval_names",
None,
"Evaluation(s) to run. If not set, runs all evaluators.",
)
_STEP = flags.DEFINE_integer(
"step",
None,
"The checkpoint step to evaluate. If not set, restores the latest"
" checkpoint.",
)
################################################################################
# MARK: Metrics
################################################################################
def _denoising_metrics():
"""Return metrics common to every task (denoising step counts)."""
return {
"processed_denoising_steps": kd_cfg.metrics.SingleDimension(
tensor="processed_denoising_steps", index=None
),
"processed_num_canvases": kd_cfg.metrics.SingleDimension(
tensor="processed_num_canvases", index=None
),
"average_denoising_steps_per_canvas": kd_cfg.metrics.SingleDimension(
tensor="average_denoising_steps_per_canvas", index=None
),
}
def _sudoku_metrics():
"""Return task-specific metrics for the Sudoku config."""
return {
"sudoku": sudoku_eval_cfg.SudokuAllMetrics(
tokens="samples",
ground_truth="batch.solution_tokens",
puzzle="batch.puzzle_tokens",
extraction_mode=sudoku_eval_cfg.ExtractionMode.SFT,
),
}
def _pubmedqa_metrics():
"""Return task-specific metrics for the PubMedQA config."""
return {
"pubmedqa_accuracy": pubmedqa_eval_cfg.PubMedQAAccuracy(
tokens="samples",
ground_truth="batch.short_answer_tokens",
),
"pubmedqa_bleu": pubmedqa_eval_cfg.BLEUScore(
tokens="samples",
ground_truth="batch.long_answer_tokens",
),
}
_TASK_METRICS = {
"sudoku": _sudoku_metrics,
"pubmedqa": _pubmedqa_metrics,
}
################################################################################
# MARK: Eval injection
################################################################################
def _inject_ar_evals(cfg, task):
"""Build AR evaluators with task-specific metrics and add them to ``cfg``.
Args:
cfg: The (unresolved) Kauldron trainer config.
task: Task name (``"sudoku"`` or ``"pubmedqa"``).
"""
eval_metrics = _denoising_metrics()
if task_metrics_fn := _TASK_METRICS.get(task):
eval_metrics.update(task_metrics_fn())
all_evals = ar_eval.make_ar_evals(
cfg,
gemma_network_ref=cfg.ref.model.gemma_network,
corruption_process_ref=cfg.ref.aux.corruption_process,
canvas_size_ref=cfg.ref.aux.canvas_size,
metrics=eval_metrics,
max_num_canvases=cfg.ref.aux.num_canvases,
use_early_stopping=False,
)
early_stopping_evals = ar_eval.make_ar_evals(
cfg,
gemma_network_ref=cfg.ref.model.gemma_network,
corruption_process_ref=cfg.ref.aux.corruption_process,
canvas_size_ref=cfg.ref.aux.canvas_size,
metrics=eval_metrics,
max_num_canvases=cfg.ref.aux.num_canvases,
use_early_stopping=True,
)
all_evals.update(early_stopping_evals)
cfg.evals.update(all_evals)
################################################################################
# MARK: Main
################################################################################
def main(_):
"""Run single-checkpoint evaluation."""
# Early JAX initialization to secure GPU contexts and prevent NCCL corruption.
jax.devices()
# Hide GPUs from TensorFlow to avoid memory conflicts with JAX.
tf.config.set_visible_devices([], "GPU")
cfg = _CONFIG.value
task = _TASK.value
eval_names = _EVAL_NAMES.value
step = _STEP.value
_inject_ar_evals(cfg, task)
if hasattr(cfg, "init_transform"):
cfg.init_transform = None # pyrefly: ignore[missing-attribute]
trainer: kd.train.Trainer = kd.konfig.resolve(cfg) # pyrefly: ignore[bad-assignment]
logging.info("Initializing state...")
state = trainer.init_state()
if step is None:
logging.info("Restoring latest checkpoint...")
state = trainer.checkpointer.restore(state)
step = int(state.step)
else:
logging.info("Restoring checkpoint at step %d...", step)
state = trainer.checkpointer.restore(state, step=step)
available_evals = [
name for name in trainer.evals.keys() if name != "gemma_checkpointer"
]
if not eval_names:
eval_names = available_evals
logging.info("Running evaluation(s) %s for step %d...", eval_names, step)
for name in eval_names:
if name not in trainer.evals:
raise ValueError(
f"Evaluator {name!r} not found. Available: {available_evals}"
)
evaluator = trainer.evals[name]
evaluator.evaluate(state, step=step)
logging.info("All evaluations done!")
if __name__ == "__main__":
jax.config.config_with_absl()
app.run(main)