feat: improve training config UX and remove unused logging options
This commit is contained in:
parent
52cd860008
commit
53f7f4f158
3 changed files with 59 additions and 127 deletions
|
|
@ -2,13 +2,11 @@ import { SectionCard } from "@/components/section-card";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { ChartContainer } from "@/components/ui/chart";
|
||||
import type { ChartConfig } from "@/components/ui/chart";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import { Input } from "@/components/ui/input";
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import {
|
||||
parseYamlConfig,
|
||||
serializeConfigToYaml,
|
||||
|
|
@ -17,14 +15,13 @@ import {
|
|||
} from "@/features/training";
|
||||
import {
|
||||
Archive04Icon,
|
||||
ArrowDown01Icon,
|
||||
ChartAverageIcon,
|
||||
CleanIcon,
|
||||
CloudUploadIcon,
|
||||
Rocket01Icon,
|
||||
} from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import { useRef, useState } from "react";
|
||||
import { useRef } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts";
|
||||
|
||||
|
|
@ -44,7 +41,6 @@ const placeholderData = [
|
|||
export function TrainingSection() {
|
||||
const store = useTrainingConfigStore();
|
||||
const { isStarting, startError, startTrainingRun } = useTrainingActions();
|
||||
const [logOpen, setLogOpen] = useState(false);
|
||||
const isIncompatible =
|
||||
!store.isVisionModel && store.isDatasetMultimodal === true;
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
|
@ -79,7 +75,13 @@ export function TrainingSection() {
|
|||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "training-config.yaml";
|
||||
|
||||
const model = (store.selectedModel ?? "model").split("/").pop();
|
||||
const method = store.trainingMethod ?? "qlora";
|
||||
const dataset = (store.dataset ?? "dataset").split("/").pop();
|
||||
const timestamp = new Date().toISOString().replace(/[:T]/g, "-").slice(0, 19);
|
||||
a.download = `${model}_${method}_${dataset}_${timestamp}.yaml`;
|
||||
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
|
@ -163,36 +165,52 @@ export function TrainingSection() {
|
|||
)}
|
||||
|
||||
{/* Upload / Save / Reset */}
|
||||
<p className="text-xs text-muted-foreground">Training Config</p>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="cursor-pointer"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<HugeiconsIcon icon={CloudUploadIcon} className="size-3.5" />
|
||||
Upload
|
||||
</Button>
|
||||
<Button
|
||||
data-tour="studio-save"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="cursor-pointer"
|
||||
onClick={handleSaveConfig}
|
||||
>
|
||||
<HugeiconsIcon icon={Archive04Icon} className="size-3.5" />
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="cursor-pointer"
|
||||
onClick={handleResetConfig}
|
||||
disabled={!store.selectedModel}
|
||||
>
|
||||
<HugeiconsIcon icon={CleanIcon} className="size-3.5" />
|
||||
Reset
|
||||
</Button>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="cursor-pointer"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<HugeiconsIcon icon={CloudUploadIcon} className="size-3.5" />
|
||||
Upload
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Load a saved YAML config</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
data-tour="studio-save"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="cursor-pointer"
|
||||
onClick={handleSaveConfig}
|
||||
>
|
||||
<HugeiconsIcon icon={Archive04Icon} className="size-3.5" />
|
||||
Save
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Download current config as YAML</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="cursor-pointer"
|
||||
onClick={handleResetConfig}
|
||||
disabled={!store.selectedModel}
|
||||
>
|
||||
<HugeiconsIcon icon={CleanIcon} className="size-3.5" />
|
||||
Reset
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Reset to model defaults</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
|
|
@ -201,85 +219,6 @@ export function TrainingSection() {
|
|||
className="hidden"
|
||||
onChange={handleFileUpload}
|
||||
/>
|
||||
|
||||
{/* Logging */}
|
||||
<Collapsible open={logOpen} onOpenChange={setLogOpen}>
|
||||
<CollapsibleTrigger className="flex w-full cursor-pointer items-center gap-1.5 text-xs text-muted-foreground">
|
||||
<HugeiconsIcon
|
||||
icon={ArrowDown01Icon}
|
||||
className={`size-3.5 transition-transform ${logOpen ? "rotate-180" : ""}`}
|
||||
/>
|
||||
Logging
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="mt-3 flex flex-col gap-3">
|
||||
{/* W&B */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="wandb"
|
||||
checked={store.enableWandb}
|
||||
onCheckedChange={(v) => store.setEnableWandb(!!v)}
|
||||
/>
|
||||
<label
|
||||
htmlFor="wandb"
|
||||
className="text-xs cursor-pointer text-muted-foreground"
|
||||
>
|
||||
Weights & Biases
|
||||
</label>
|
||||
</div>
|
||||
{store.enableWandb && (
|
||||
<div className="flex flex-col gap-2 pl-6">
|
||||
<Input
|
||||
placeholder="W&B API Token"
|
||||
type="password"
|
||||
value={store.wandbToken}
|
||||
onChange={(e) => store.setWandbToken(e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
placeholder="Project name"
|
||||
value={store.wandbProject}
|
||||
onChange={(e) => store.setWandbProject(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* TensorBoard */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="tensorboard"
|
||||
checked={store.enableTensorboard}
|
||||
onCheckedChange={(v) => store.setEnableTensorboard(!!v)}
|
||||
/>
|
||||
<label
|
||||
htmlFor="tensorboard"
|
||||
className="text-xs cursor-pointer text-muted-foreground"
|
||||
>
|
||||
TensorBoard
|
||||
</label>
|
||||
</div>
|
||||
{store.enableTensorboard && (
|
||||
<div className="flex flex-col gap-2 pl-6">
|
||||
<Input
|
||||
placeholder="Log directory"
|
||||
value={store.tensorboardDir}
|
||||
onChange={(e) => store.setTensorboardDir(e.target.value)}
|
||||
/>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs font-medium text-muted-foreground">
|
||||
Log frequency
|
||||
</span>
|
||||
<Input
|
||||
type="number"
|
||||
value={store.logFrequency}
|
||||
onChange={(e) =>
|
||||
store.setLogFrequency(Number(e.target.value))
|
||||
}
|
||||
className="w-24"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</div>
|
||||
</SectionCard>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ export const studioSaveStep: TourStep = {
|
|||
title: "Save config",
|
||||
body: (
|
||||
<>
|
||||
Save configs that worked. Re-running the same baseline makes it obvious
|
||||
if a change helped (or if you just got lucky).
|
||||
Save your training config as a YAML file. Re-running the same baseline
|
||||
makes it obvious if a change helped (or if you just got lucky).
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -75,13 +75,6 @@ export function serializeConfigToYaml(
|
|||
lr_scheduler_type: state.lrSchedulerType,
|
||||
},
|
||||
lora,
|
||||
logging: {
|
||||
enable_wandb: state.enableWandb,
|
||||
wandb_project: state.wandbProject,
|
||||
enable_tensorboard: state.enableTensorboard,
|
||||
tensorboard_dir: state.tensorboardDir,
|
||||
log_frequency: state.logFrequency,
|
||||
},
|
||||
};
|
||||
|
||||
return yaml.dump(config, { lineWidth: -1, noRefs: true });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue