Parse single epoch training curves
This commit is contained in:
@@ -183,7 +183,7 @@ def parse_training_curve(path: Path, max_points: int = 300) -> dict | None:
|
|||||||
y = _as_float(row.get(name))
|
y = _as_float(row.get(name))
|
||||||
if y is not None:
|
if y is not None:
|
||||||
points.append({"x": x, "y": y})
|
points.append({"x": x, "y": y})
|
||||||
if len(points) >= 2:
|
if points:
|
||||||
values = [point["y"] for point in points]
|
values = [point["y"] for point in points]
|
||||||
series.append({"name": name, "points": points, "last": values[-1], "min": min(values), "max": max(values)})
|
series.append({"name": name, "points": points, "last": values[-1], "min": min(values), "max": max(values)})
|
||||||
if not series:
|
if not series:
|
||||||
|
|||||||
@@ -28,6 +28,26 @@ def test_parse_yolo_results_curve(tmp_path: Path):
|
|||||||
assert all("lr/" not in name for name in names)
|
assert all("lr/" not in name for name in names)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_single_epoch_yolo_results_curve(tmp_path: Path):
|
||||||
|
csv_path = tmp_path / "results.csv"
|
||||||
|
csv_path.write_text(
|
||||||
|
"\n".join(
|
||||||
|
[
|
||||||
|
"epoch,time,train/box_loss,train/seg_loss,metrics/mAP50(M),lr/pg0",
|
||||||
|
"1,1.0,1.5,3.0,0.12,0.001",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
curve = parse_training_curve(csv_path)
|
||||||
|
|
||||||
|
assert curve is not None
|
||||||
|
assert curve["row_count"] == 1
|
||||||
|
seg_loss = next(item for item in curve["series"] if item["name"] == "train/seg_loss")
|
||||||
|
assert seg_loss["points"] == [{"x": 1.0, "y": 3.0}]
|
||||||
|
|
||||||
|
|
||||||
def test_results_api_honors_limit(monkeypatch):
|
def test_results_api_honors_limit(monkeypatch):
|
||||||
calls = {}
|
calls = {}
|
||||||
|
|
||||||
|
|||||||
@@ -1764,17 +1764,24 @@ function MiniCurvePlot({ series }: { series: CurveSeries[] }) {
|
|||||||
{[0.25, 0.5, 0.75].map((tick) => (
|
{[0.25, 0.5, 0.75].map((tick) => (
|
||||||
<path key={tick} d={`M ${pad} ${pad + tick * (height - pad * 2)} H ${width - pad}`} className="gridLine" />
|
<path key={tick} d={`M ${pad} ${pad + tick * (height - pad * 2)} H ${width - pad}`} className="gridLine" />
|
||||||
))}
|
))}
|
||||||
{series.map((item, index) => (
|
{series.map((item, index) => {
|
||||||
<polyline
|
const color = curveColor(index);
|
||||||
key={item.name}
|
const scaled = item.points.map((point) => ({ x: scaleX(point.x), y: scaleY(point.y) }));
|
||||||
points={item.points.map((point) => `${scaleX(point.x).toFixed(2)},${scaleY(point.y).toFixed(2)}`).join(" ")}
|
if (scaled.length === 1) {
|
||||||
fill="none"
|
return <circle key={item.name} cx={scaled[0].x} cy={scaled[0].y} r="4" fill={color} />;
|
||||||
stroke={curveColor(index)}
|
}
|
||||||
strokeWidth="2.4"
|
return (
|
||||||
strokeLinejoin="round"
|
<polyline
|
||||||
strokeLinecap="round"
|
key={item.name}
|
||||||
/>
|
points={scaled.map((point) => `${point.x.toFixed(2)},${point.y.toFixed(2)}`).join(" ")}
|
||||||
))}
|
fill="none"
|
||||||
|
stroke={color}
|
||||||
|
strokeWidth="2.4"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeLinecap="round"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user