2026-07-21 08:32:30 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import tempfile
|
|
|
|
|
import unittest
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
from airfrans_frontier.training.config import load_training_config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TrainingConfigTests(unittest.TestCase):
|
|
|
|
|
def test_config_loader_accepts_mlp_tiny(self) -> None:
|
|
|
|
|
config = load_training_config("configs/mlp_tiny.toml")
|
|
|
|
|
|
|
|
|
|
self.assertEqual(config.run.name, "mlp_tiny")
|
|
|
|
|
self.assertEqual(config.model.type, "mlp")
|
|
|
|
|
self.assertEqual(config.loss.type, "normalized_mse")
|
|
|
|
|
self.assertEqual(config.device.type, "cuda")
|
|
|
|
|
self.assertTrue(config.data.root.is_absolute())
|
2026-07-25 16:12:49 +00:00
|
|
|
self.assertEqual(config.data.source, "local")
|
|
|
|
|
self.assertIsNone(config.data.hf_repo_id)
|
|
|
|
|
self.assertIsNone(config.data.cache_dir)
|
|
|
|
|
|
|
|
|
|
def test_config_loader_accepts_huggingface_data_source(self) -> None:
|
|
|
|
|
config = load_training_config("configs/aggressive_smoke.toml")
|
|
|
|
|
|
|
|
|
|
self.assertEqual(config.data.source, "huggingface")
|
|
|
|
|
self.assertEqual(config.data.hf_repo_id, "zacheryasc/airfrans-processed")
|
|
|
|
|
self.assertEqual(config.data.hf_path_prefix, "processed/full")
|
|
|
|
|
self.assertTrue(config.data.cache_dir is not None)
|
2026-07-21 08:32:30 +00:00
|
|
|
|
2026-07-28 18:04:50 +00:00
|
|
|
def test_config_loader_parses_model_metadata_and_defaults_old_configs(self) -> None:
|
|
|
|
|
config = load_training_config("configs/mlp_tiny.toml")
|
|
|
|
|
self.assertEqual(config.model_metadata.reported_family, "mlp")
|
|
|
|
|
self.assertFalse(config.model_metadata.is_proxy)
|
|
|
|
|
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
|
|
|
config_path = Path(tmp) / "proxy.toml"
|
|
|
|
|
config_path.write_text(
|
|
|
|
|
f"""
|
|
|
|
|
[run]
|
|
|
|
|
name = "proxy"
|
|
|
|
|
seed = 0
|
|
|
|
|
artifact_dir = "{Path(tmp) / "runs"}"
|
|
|
|
|
|
|
|
|
|
[data]
|
|
|
|
|
root = "{Path(tmp) / "data"}"
|
|
|
|
|
train_cases = 1
|
|
|
|
|
val_cases = 0
|
|
|
|
|
test_cases = 0
|
|
|
|
|
points_per_case = 1
|
|
|
|
|
batch_size = 1
|
|
|
|
|
|
|
|
|
|
[model]
|
|
|
|
|
type = "raster_fno_unet"
|
|
|
|
|
hidden_width = 8
|
|
|
|
|
depth = 1
|
|
|
|
|
activation = "gelu"
|
|
|
|
|
|
|
|
|
|
[model_metadata]
|
|
|
|
|
requested_family = "raster_fno_unet"
|
|
|
|
|
implementation_family = "raster_fno_unet"
|
|
|
|
|
reported_family = "raster_fno_unet_proxy"
|
|
|
|
|
is_proxy = true
|
|
|
|
|
proxy_for = "fno_or_raster_field_model"
|
|
|
|
|
proxy_notes = "proxy"
|
|
|
|
|
coordinate_encoding_compatibility = "raw_only"
|
|
|
|
|
|
|
|
|
|
[optim]
|
|
|
|
|
lr = 0.001
|
|
|
|
|
weight_decay = 0.0
|
|
|
|
|
steps = 1
|
|
|
|
|
|
|
|
|
|
[device]
|
|
|
|
|
type = "cpu"
|
|
|
|
|
allow_cpu_fallback = false
|
|
|
|
|
benchmark_kernels = false
|
|
|
|
|
|
|
|
|
|
[loss]
|
|
|
|
|
type = "normalized_mse"
|
|
|
|
|
""".strip()
|
|
|
|
|
+ "\n"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
parsed = load_training_config(config_path)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(parsed.model_metadata.reported_family, "raster_fno_unet_proxy")
|
|
|
|
|
self.assertTrue(parsed.model_metadata.is_proxy)
|
|
|
|
|
self.assertEqual(parsed.model_metadata.coordinate_encoding_compatibility, "raw_only")
|
|
|
|
|
|
2026-07-29 09:42:52 +00:00
|
|
|
def test_config_loader_accepts_all_points_dead_curve_and_lightweight_checkpoint(self) -> None:
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
|
|
|
config_path = Path(tmp) / "all_points.toml"
|
|
|
|
|
config_path.write_text(
|
|
|
|
|
f"""
|
|
|
|
|
[run]
|
|
|
|
|
name = "all_points"
|
|
|
|
|
seed = 0
|
|
|
|
|
artifact_dir = "{Path(tmp) / "runs"}"
|
|
|
|
|
|
|
|
|
|
[data]
|
|
|
|
|
root = "{Path(tmp) / "data"}"
|
|
|
|
|
train_cases = 1
|
|
|
|
|
val_cases = 0
|
|
|
|
|
test_cases = 0
|
|
|
|
|
all_points_per_case = true
|
|
|
|
|
batch_size = 1
|
|
|
|
|
|
|
|
|
|
[coordinate_encoding]
|
|
|
|
|
type = "nerf_multires"
|
|
|
|
|
features = ["x", "y", "sdf"]
|
|
|
|
|
levels = 4
|
|
|
|
|
|
|
|
|
|
[model]
|
|
|
|
|
type = "mlp_encoded_baseline"
|
|
|
|
|
hidden_width = 8
|
|
|
|
|
depth = 1
|
|
|
|
|
activation = "gelu"
|
|
|
|
|
coordinate_features = ["x", "y", "sdf"]
|
|
|
|
|
|
|
|
|
|
[optim]
|
|
|
|
|
lr = 0.001
|
|
|
|
|
weight_decay = 0.0
|
|
|
|
|
steps = 1
|
|
|
|
|
|
|
|
|
|
[device]
|
|
|
|
|
type = "cpu"
|
|
|
|
|
allow_cpu_fallback = false
|
|
|
|
|
benchmark_kernels = false
|
|
|
|
|
|
|
|
|
|
[loss]
|
|
|
|
|
type = "normalized_mse"
|
|
|
|
|
|
|
|
|
|
[checkpoint]
|
|
|
|
|
policy = "lightweight_scaling_probe"
|
|
|
|
|
include_optimizer_state = false
|
|
|
|
|
include_rng_state = false
|
|
|
|
|
interval_seconds = 0
|
|
|
|
|
|
|
|
|
|
[stability]
|
|
|
|
|
dead_curve_patience_evals = 3
|
|
|
|
|
dead_curve_min_relative_improvement = 0.01
|
|
|
|
|
dead_curve_warmup_steps = 5
|
|
|
|
|
""".strip()
|
|
|
|
|
+ "\n"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
parsed = load_training_config(config_path)
|
|
|
|
|
|
|
|
|
|
self.assertTrue(parsed.data.all_points_per_case)
|
|
|
|
|
self.assertIsNone(parsed.data.points_per_case)
|
|
|
|
|
self.assertEqual(parsed.model.type, "mlp_encoded_baseline")
|
|
|
|
|
self.assertEqual(parsed.checkpoint.policy, "lightweight_scaling_probe")
|
|
|
|
|
self.assertFalse(parsed.checkpoint.include_optimizer_state)
|
|
|
|
|
self.assertEqual(parsed.stability.dead_curve_patience_evals, 3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_config_loader_accepts_huggingface_streaming_data_source(self) -> None:
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
|
|
|
config_path = Path(tmp) / "hf_streaming.toml"
|
|
|
|
|
config_path.write_text(
|
|
|
|
|
f"""
|
|
|
|
|
[run]
|
|
|
|
|
name = "hf_streaming"
|
|
|
|
|
seed = 0
|
|
|
|
|
artifact_dir = "{Path(tmp) / "runs"}"
|
|
|
|
|
|
|
|
|
|
[data]
|
|
|
|
|
root = "{Path(tmp) / "cache" / "processed" / "full"}"
|
|
|
|
|
source = "huggingface_streaming"
|
|
|
|
|
hf_repo_id = "zacheryasc/airfrans-processed"
|
|
|
|
|
hf_repo_type = "dataset"
|
|
|
|
|
hf_path_prefix = "processed/full"
|
|
|
|
|
cache_dir = "{Path(tmp) / "cache"}"
|
|
|
|
|
train_cases = 1
|
|
|
|
|
val_cases = 0
|
|
|
|
|
test_cases = 0
|
|
|
|
|
all_points_per_case = true
|
|
|
|
|
batch_size = 1
|
|
|
|
|
streaming_queue_max_cases = 8
|
|
|
|
|
streaming_normalization_cases = 1
|
|
|
|
|
|
|
|
|
|
[model]
|
|
|
|
|
type = "mlp"
|
|
|
|
|
hidden_width = 8
|
|
|
|
|
depth = 1
|
|
|
|
|
activation = "gelu"
|
|
|
|
|
|
|
|
|
|
[optim]
|
|
|
|
|
lr = 0.001
|
|
|
|
|
weight_decay = 0.0
|
|
|
|
|
steps = 1
|
|
|
|
|
|
|
|
|
|
[device]
|
|
|
|
|
type = "cpu"
|
|
|
|
|
allow_cpu_fallback = false
|
|
|
|
|
benchmark_kernels = false
|
|
|
|
|
|
|
|
|
|
[loss]
|
|
|
|
|
type = "normalized_mse"
|
|
|
|
|
|
|
|
|
|
[checkpoint]
|
|
|
|
|
interval_seconds = 0
|
|
|
|
|
""".strip()
|
|
|
|
|
+ "\n"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
parsed = load_training_config(config_path)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(parsed.data.source, "huggingface_streaming")
|
|
|
|
|
self.assertEqual(parsed.data.hf_repo_id, "zacheryasc/airfrans-processed")
|
|
|
|
|
self.assertTrue(parsed.data.all_points_per_case)
|
|
|
|
|
|
2026-07-21 08:32:30 +00:00
|
|
|
def test_config_loader_rejects_missing_section(self) -> None:
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
|
|
|
config_path = Path(tmp) / "bad.toml"
|
|
|
|
|
config_path.write_text("[run]\nname = 'bad'\n")
|
|
|
|
|
|
|
|
|
|
with self.assertRaisesRegex(ValueError, r"missing \[data\] section"):
|
|
|
|
|
load_training_config(config_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
unittest.main()
|