feat: add eval_enabled flag and format-first-then-split for eval dataset

This commit is contained in:
Roland Tannous 2026-02-16 14:13:55 +00:00
commit 5df3a0b250
7 changed files with 23 additions and 4 deletions

View file

@ -30,6 +30,7 @@ class TrainingBackend:
self.step_history = []
self.eval_loss_history = []
self.eval_step_history = []
self.eval_enabled = False
self.current_theme = "light"
self.trainer.add_progress_callback(self._on_progress_update)
@ -144,6 +145,7 @@ class TrainingBackend:
self.step_history = []
self.eval_loss_history = []
self.eval_step_history = []
self.eval_enabled = False
import time
output_dir = f"./outputs/{model_name.replace('/', '_')}_{int(time.time())}"
@ -215,6 +217,13 @@ class TrainingBackend:
dataset = dataset_result
eval_dataset = None
# If user set eval_steps to 0, disable evaluation entirely
if eval_steps is not None and float(eval_steps) <= 0:
eval_dataset = None
# Track whether eval is enabled for status reporting
self.eval_enabled = eval_dataset is not None
if dataset is None or self.trainer.should_stop:
logger.error("Failed to load dataset or stopped by user")
return False

View file

@ -96,6 +96,7 @@ class TrainingStatus(BaseModel):
"stopped"
] = Field(..., description="Current phase of training pipeline")
is_training_running: bool = Field(..., description="True if training loop is actively running")
eval_enabled: bool = Field(False, description="True if evaluation dataset is configured for this training run")
message: str = Field(..., description="Human-readable status message")
error: Optional[str] = Field(None, description="Error details if phase is 'error'")
details: Optional[dict] = Field(None, description="Phase-specific info, e.g. {'model_size': '8B'}")

View file

@ -415,6 +415,7 @@ async def get_training_status(
job_id=job_id,
phase=phase,
is_training_running=is_active,
eval_enabled=backend.eval_enabled,
message=status_message,
error=error_message,
details=details,

View file

@ -148,7 +148,9 @@ function ema(data: LossHistoryItem[], alpha: number): SmoothedLossItem[] {
export function ChartsContent({
metrics,
}: { metrics: TrainingChartSeries }): ReactElement {
isTraining,
evalEnabled,
}: { metrics: TrainingChartSeries; isTraining: boolean; evalEnabled: boolean }): ReactElement {
const [smoothing, setSmoothing] = useState(0.75);
const [showRaw, setShowRaw] = useState(true);
const [showSmoothed, setShowSmoothed] = useState(true);
@ -674,10 +676,10 @@ export function ChartsContent({
className="size-5 text-muted-foreground/50"
/>
<p className="text-sm font-medium text-muted-foreground">
Evaluation not configured
{isTraining && evalEnabled ? "Waiting for first evaluation step…" : "Evaluation not configured"}
</p>
<p className="text-xs text-muted-foreground/60">
Set eval dataset & eval_steps to track eval loss
{isTraining && evalEnabled ? "Chart will appear once eval_steps is reached" : "Set eval dataset & eval_steps to track eval loss"}
</p>
</div>
</div>

View file

@ -16,6 +16,8 @@ const SKELETON_KEYS = [
export function ChartsSection(): ReactElement | null {
const currentStep = useTrainingRuntimeStore((state) => state.currentStep);
const totalSteps = useTrainingRuntimeStore((state) => state.totalSteps);
const isTraining = useTrainingRuntimeStore((state) => state.isTrainingRunning);
const evalEnabled = useTrainingRuntimeStore((state) => state.evalEnabled);
const lossHistoryRaw = useTrainingRuntimeStore((state) => state.lossHistory);
const lrHistoryRaw = useTrainingRuntimeStore((state) => state.lrHistory);
const gradNormHistoryRaw = useTrainingRuntimeStore(
@ -70,7 +72,7 @@ export function ChartsSection(): ReactElement | null {
</div>
}
>
<ChartsContent metrics={series} />
<ChartsContent metrics={series} isTraining={isTraining} evalEnabled={evalEnabled} />
</Suspense>
);
}

View file

@ -12,6 +12,7 @@ const initialState: TrainingRuntimeState = {
jobId: null,
phase: "idle",
isTrainingRunning: false,
evalEnabled: false,
message: "Ready to train",
error: null,
isHydrating: false,
@ -144,6 +145,7 @@ export const useTrainingRuntimeStore = create<TrainingRuntimeStore>()((set) => (
jobId: payload.job_id || state.jobId,
phase: payload.phase,
isTrainingRunning: payload.is_training_running,
evalEnabled: payload.eval_enabled ?? state.evalEnabled,
message: payload.message,
error: payload.error,
startError: null,

View file

@ -12,6 +12,7 @@ export interface TrainingStatusResponse {
job_id: string;
phase: TrainingPhase;
is_training_running: boolean;
eval_enabled: boolean;
message: string;
error: string | null;
details?: {
@ -63,6 +64,7 @@ export interface TrainingRuntimeState {
jobId: string | null;
phase: TrainingPhase;
isTrainingRunning: boolean;
evalEnabled: boolean;
message: string;
error: string | null;
isHydrating: boolean;