26-8-12:反向传播(BP算法),请用两层神经网络解释一下,并通过html展示一下
title:title
date:2026.8月份


下面是HTML代码
点击查看代码
</details><!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>两层神经网络 · 完整复合函数 + BP 数学全解</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
background: radial-gradient(circle at 20% 30%, #141428, #080812);
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
display: flex;
justify-content: center;
padding: 20px;
}
.container {
max-width: 1400px;
width: 100%;
background: rgba(16, 16, 32, 0.85);
backdrop-filter: blur(12px);
border-radius: 40px;
padding: 30px 35px;
border: 1px solid rgba(255, 255, 255, 0.06);
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.9);
}
h1 {
color: #eee;
font-weight: 300;
letter-spacing: 2px;
margin-top: 0;
margin-bottom: 4px;
font-size: 28px;
display: flex;
align-items: center;
gap: 14px;
flex-wrap: wrap;
}
h1 small {
font-size: 16px;
color: #88aadd;
font-weight: 400;
background: #222244;
padding: 2px 18px;
border-radius: 40px;
}
.sub {
color: #99aabb;
border-bottom: 1px solid #2a2a4a;
padding-bottom: 12px;
margin-bottom: 25px;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
gap: 10px;
}
/* 复合函数展示条 */
.composite-box {
background: #0a0a18;
border-radius: 16px;
padding: 16px 22px;
margin-bottom: 25px;
border: 1px solid #ffaa4455;
border-left: 6px solid #ffaa44;
font-family: 'Courier New', monospace;
font-size: 15px;
color: #d0d8e0;
line-height: 1.9;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
}
.composite-box .fn {
color: #ffaa44;
font-weight: 700;
}
.composite-box .layer1 {
color: #66ddff;
}
.composite-box .layer2 {
color: #ff66aa;
}
.composite-box .sigma {
color: #88dd88;
}
.dashboard {
display: grid;
grid-template-columns: 1.1fr 0.9fr;
gap: 30px;
}
@media (max-width: 900px) {
.dashboard {
grid-template-columns: 1fr;
}
}
.card {
background: rgba(8, 8, 20, 0.6);
border-radius: 24px;
border: 1px solid #2a2a4a;
padding: 20px 22px;
backdrop-filter: blur(4px);
box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.02);
}
.card h3 {
color: #ccd;
font-weight: 400;
letter-spacing: 1px;
margin-top: 0;
margin-bottom: 18px;
border-bottom: 1px solid #2a2a4a;
padding-bottom: 10px;
display: flex;
align-items: center;
gap: 10px;
}
.card h3 span {
background: #2a2a5a;
padding: 0 12px;
border-radius: 20px;
font-size: 12px;
color: #88aaff;
}
.param-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px 18px;
font-size: 15px;
}
.param-item {
display: flex;
justify-content: space-between;
border-bottom: 1px dashed #1a1a30;
padding: 4px 0;
}
.param-item .label {
color: #8899bb;
}
.param-item .val {
color: #eee;
font-weight: 600;
font-family: 'Courier New', monospace;
}
.math-box {
background: #0a0a18;
border-radius: 16px;
padding: 12px 16px;
margin-top: 12px;
border-left: 4px solid #ffaa44;
font-family: 'Courier New', monospace;
font-size: 14px;
color: #d0d8e0;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
line-height: 1.7;
}
.math-box .highlight {
color: #ffaa44;
}
.math-box .highlight2 {
color: #66ddff;
}
.math-box .highlight3 {
color: #ff66aa;
}
.slider-group {
display: flex;
gap: 20px;
flex-wrap: wrap;
margin: 15px 0 10px 0;
}
.slider-group label {
color: #bbc;
font-size: 14px;
display: flex;
align-items: center;
gap: 12px;
flex: 1;
min-width: 140px;
}
.slider-group input[type="range"] {
flex: 1;
min-width: 80px;
-webkit-appearance: none;
background: #2a2a44;
height: 4px;
border-radius: 4px;
outline: none;
}
.slider-group input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
border-radius: 50%;
background: #ffaa44;
border: 2px solid #fff;
cursor: pointer;
}
.slider-group .val {
color: #fff;
font-weight: 600;
min-width: 30px;
text-align: center;
}
.btn-group {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-top: 16px;
}
.btn {
background: #2a2a5a;
border: none;
color: #fff;
padding: 10px 28px;
border-radius: 40px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
border: 1px solid transparent;
letter-spacing: 0.5px;
flex: 1;
min-width: 100px;
}
.btn:hover {
background: #3a3a7a;
border-color: #88aaff;
box-shadow: 0 0 30px rgba(80, 120, 255, 0.15);
transform: translateY(-2px);
}
.btn:active {
transform: scale(0.96);
}
.btn.primary {
background: #cc8833;
color: #0a0a12;
}
.btn.primary:hover {
background: #ffaa44;
box-shadow: 0 0 40px rgba(255, 170, 68, 0.3);
}
.btn.danger {
background: #442a2a;
}
.btn.danger:hover {
background: #663a3a;
border-color: #ff8866;
}
.status-badge {
display: inline-block;
padding: 4px 16px;
border-radius: 40px;
font-weight: 600;
font-size: 13px;
}
.status-badge.running {
background: #33cc88;
color: #0a0a12;
}
.status-badge.stopped {
background: #556;
color: #ccc;
}
.loss-display {
font-size: 24px;
font-weight: 700;
color: #ffaa44;
font-family: 'Courier New', monospace;
}
.footnote {
margin-top: 25px;
color: #556;
font-size: 13px;
text-align: center;
border-top: 1px solid #1a1a30;
padding-top: 18px;
}
.layer-tag {
display: inline-block;
background: #1a2a3a;
padding: 0 10px;
border-radius: 12px;
font-size: 12px;
color: #88aadd;
}
</style>
</head>
<body>
<div class="container">
<h1>
🧠 两层神经网络 · 完整复合函数
<small>2 输入 → 隐藏层(2神经元, σ) → 输出(1神经元, σ)</small>
</h1>
<div class="sub">
<span>🔬 数学公式 + 实时数值代入</span>
<span><span class="status-badge stopped" id="statusBadge">⏸ 待命</span></span>
</div>
<!-- ★★★ 核心:完整复合函数展示 ★★★ -->
<div class="composite-box" id="compositeDisplay">
<div style="color:#8899bb; font-size:13px; margin-bottom:6px;">📐 两层网络的完整复合映射 (输入 x₁, x₂ → 输出 ŷ)</div>
<span class="fn">f(x₁, x₂) = σ(</span>
<span class="layer2">v₁</span>·<span class="layer1">σ(</span><span class="layer2">w₁₁</span>x₁ + <span class="layer2">w₁₂</span>x₂ + <span class="layer2">b₁</span><span class="layer1">)</span> +
<span class="layer2">v₂</span>·<span class="layer1">σ(</span><span class="layer2">w₂₁</span>x₁ + <span class="layer2">w₂₂</span>x₂ + <span class="layer2">b₂</span><span class="layer1">)</span> +
<span class="layer2">b_out</span>
<span class="fn">)</span>
<div style="margin-top:8px; font-size:13px; color:#667; border-top:1px solid #1a1a30; padding-top:8px;">
⚡ 其中 σ(z) = 1/(1+e<sup>-z</sup>) |
<span class="layer1">■ 隐藏层 (蓝色)</span>
<span class="layer2">■ 输出层 (粉色)</span>
</div>
</div>
<div class="dashboard">
<!-- 左栏 -->
<div>
<div class="card">
<h3>⚙️ 网络参数 (9个可训练权重)</h3>
<div class="param-grid" id="paramGrid">
<!-- JS 填充 -->
</div>
<div style="margin-top:16px; display:flex; gap:10px; flex-wrap:wrap; justify-content:space-between;">
<div><span style="color:#8899bb;">学习率 η = </span><span id="lrDisplay" style="color:#ffaa44;font-weight:700;">0.5</span></div>
<div><span style="color:#8899bb;">损失 L = </span><span id="lossDisplay" class="loss-display">0.2500</span></div>
<div><span style="color:#8899bb;">轮次 </span><span id="epochDisplay" style="color:#eee;font-weight:700;">0</span></div>
</div>
</div>
<div class="card" style="margin-top:16px;">
<h3>🎮 控制器</h3>
<div class="slider-group">
<label>x₁ <input type="range" id="x1Slider" min="0" max="1" step="0.05" value="0.5"> <span class="val" id="x1Val">0.5</span></label>
<label>x₂ <input type="range" id="x2Slider" min="0" max="1" step="0.05" value="0.8"> <span class="val" id="x2Val">0.8</span></label>
<label>目标 y <input type="range" id="ySlider" min="0" max="1" step="0.05" value="1.0"> <span class="val" id="yVal">1.0</span></label>
</div>
<div class="btn-group">
<button class="btn primary" id="trainBtn">▶ 开始训练</button>
<button class="btn" id="stepBtn">⏭ 单步 BP</button>
<button class="btn danger" id="resetBtn">↺ 重置</button>
</div>
<div style="margin-top:12px; color:#667; font-size:13px;">
💡 点击“单步BP”观察链式求导的每一步具体数值。
</div>
</div>
<div class="card" style="margin-top:16px;">
<h3>📐 当前梯度 (反向传播结果)</h3>
<div id="gradientDisplay" style="font-family:'Courier New',monospace; font-size:13px; color:#ccd; line-height:1.8;">
尚未计算...
</div>
</div>
</div>
<!-- 右栏:逐层数学推导 -->
<div>
<div class="card" style="height:100%;">
<h3>🧮 第1层 (隐藏层) · 子函数 <span class="layer-tag">h₁, h₂</span></h3>
<div id="layer1Math" class="math-box" style="border-left-color:#66ddff;">
<span style="color:#667;">点击“单步BP”查看 h₁、h₂ 的 z 和 a 计算...</span>
</div>
<h3 style="margin-top:20px;">🧮 第2层 (输出层) · 子函数 <span class="layer-tag">ŷ</span></h3>
<div id="layer2Math" class="math-box" style="border-left-color:#ff66aa;">
<span style="color:#667;">输出层加权求和 + Sigmoid 激活...</span>
</div>
<h3 style="margin-top:20px;">⬇️ 反向传播 · 链式求导 (δ 误差项)</h3>
<div id="backwardMath" class="math-box" style="border-left-color:#ff8844;">
<span style="color:#667;">∂L/∂z 逐层回传...</span>
</div>
<h3 style="margin-top:20px;">🔄 权重更新 (梯度下降)</h3>
<div id="updateMath" class="math-box" style="border-left-color:#33ff88;">
<span style="color:#667;">新权重 = 旧权重 - η × 梯度</span>
</div>
</div>
</div>
</div>
<div class="footnote">
⚡ 网络 = 2层 (隐藏层 + 输出层) · 损失函数 MSE = ½(ŷ - y)² · 激活函数 σ(z) = 1/(1+e<sup>-z</sup>)
</div>
</div>
<script>
// ============================================================
// 1. 参数 (两层: W1(2x2), b1(2), W2(1x2), b2(1))
// ============================================================
let w11 = 0.15,
w12 = 0.20,
w21 = 0.25,
w22 = 0.30;
let b1 = 0.35,
b2 = 0.35;
let v1 = 0.40,
v2 = 0.45;
let b_out = 0.60;
let lr = 0.5;
let epoch = 0;
let isTraining = false;
let trainInterval = null;
let x1 = 0.5,
x2 = 0.8,
y_true = 1.0;
let cache = {};
// ============================================================
// 2. 数学函数
// ============================================================
function sigmoid(z) { return 1 / (1 + Math.exp(-z)); }
function sigmoidDeriv(a) { return a * (1 - a); }
function forward(x1, x2) {
const z_h1 = w11 * x1 + w12 * x2 + b1;
const z_h2 = w21 * x1 + w22 * x2 + b2;
const a_h1 = sigmoid(z_h1);
const a_h2 = sigmoid(z_h2);
const z_out = v1 * a_h1 + v2 * a_h2 + b_out;
const a_out = sigmoid(z_out);
return { z_h1, z_h2, a_h1, a_h2, z_out, a_out };
}
function computeLoss(y_pred, y_true) { return 0.5 * (y_pred - y_true) ** 2; }
function backward(x1, x2, y_true) {
const f = forward(x1, x2);
const y_pred = f.a_out;
const loss = computeLoss(y_pred, y_true);
// 输出层
const dL_da_out = y_pred - y_true;
const da_out_dz_out = sigmoidDeriv(y_pred);
const delta_out = dL_da_out * da_out_dz_out;
const grad_v1 = delta_out * f.a_h1;
const grad_v2 = delta_out * f.a_h2;
const grad_b_out = delta_out;
// 隐藏层
const da_h1_dz_h1 = sigmoidDeriv(f.a_h1);
const da_h2_dz_h2 = sigmoidDeriv(f.a_h2);
const delta_h1 = delta_out * v1 * da_h1_dz_h1;
const delta_h2 = delta_out * v2 * da_h2_dz_h2;
const grad_w11 = delta_h1 * x1;
const grad_w12 = delta_h1 * x2;
const grad_w21 = delta_h2 * x1;
const grad_w22 = delta_h2 * x2;
const grad_b1 = delta_h1;
const grad_b2 = delta_h2;
cache = { ...f, y_pred, loss, dL_da_out, da_out_dz_out, delta_out, delta_h1, delta_h2,
grad_w11, grad_w12, grad_w21, grad_w22, grad_b1, grad_b2, grad_v1, grad_v2, grad_b_out,
da_h1_dz_h1, da_h2_dz_h2
};
return {
grads: { grad_w11, grad_w12, grad_w21, grad_w22, grad_b1, grad_b2, grad_v1, grad_v2, grad_b_out },
loss, cache
};
}
function updateWeights(grads) {
w11 -= lr * grads.grad_w11;
w12 -= lr * grads.grad_w12;
w21 -= lr * grads.grad_w21;
w22 -= lr * grads.grad_w22;
b1 -= lr * grads.grad_b1;
b2 -= lr * grads.grad_b2;
v1 -= lr * grads.grad_v1;
v2 -= lr * grads.grad_v2;
b_out -= lr * grads.grad_b_out;
}
// ============================================================
// 3. UI 渲染
// ============================================================
function renderParams() {
const grid = document.getElementById('paramGrid');
const items = [
['w₁₁', w11], ['w₁₂', w12],
['w₂₁', w21], ['w₂₂', w22],
['b₁', b1], ['b₂', b2],
['v₁', v1], ['v₂', v2],
['b_out', b_out]
];
grid.innerHTML = items.map(([name, val]) =>
`<div class="param-item"><span class="label">${name}</span><span class="val">${val.toFixed(4)}</span></div>`
).join('');
}
function renderGradients(grads) {
if (!grads) { document.getElementById('gradientDisplay').innerHTML = '<span style="color:#667;">尚未计算...</span>'; return; }
const items = [
['∂L/∂w₁₁', grads.grad_w11], ['∂L/∂w₁₂', grads.grad_w12],
['∂L/∂w₂₁', grads.grad_w21], ['∂L/∂w₂₂', grads.grad_w22],
['∂L/∂b₁', grads.grad_b1], ['∂L/∂b₂', grads.grad_b2],
['∂L/∂v₁', grads.grad_v1], ['∂L/∂v₂', grads.grad_v2],
['∂L/∂b_out', grads.grad_b_out]
];
document.getElementById('gradientDisplay').innerHTML = items.map(([name, val]) =>
`<div><span style="color:#8899bb;">${name}</span> = <span style="color:#ff8844;font-weight:700;">${val.toFixed(6)}</span></div>`
).join('');
}
function renderMath(cache, grads) {
if (!cache) {
document.getElementById('layer1Math').innerHTML = '<span style="color:#667;">等待计算...</span>';
document.getElementById('layer2Math').innerHTML = '<span style="color:#667;">等待计算...</span>';
document.getElementById('backwardMath').innerHTML = '<span style="color:#667;">等待计算...</span>';
document.getElementById('updateMath').innerHTML = '<span style="color:#667;">等待计算...</span>';
return;
}
const f = cache;
// ---- 第1层 ----
document.getElementById('layer1Math').innerHTML = `
<span style="color:#66ddff;">h₁ = σ(z₁)</span> , z₁ = ${w11.toFixed(4)}·${x1.toFixed(2)} + ${w12.toFixed(4)}·${x2.toFixed(2)} + ${b1.toFixed(4)} = ${f.z_h1.toFixed(6)}
a₁ = σ(${f.z_h1.toFixed(4)}) = <span class="highlight">${f.a_h1.toFixed(6)}</span>
<span style="color:#66ddff;">h₂ = σ(z₂)</span> , z₂ = ${w21.toFixed(4)}·${x1.toFixed(2)} + ${w22.toFixed(4)}·${x2.toFixed(2)} + ${b2.toFixed(4)} = ${f.z_h2.toFixed(6)}
a₂ = σ(${f.z_h2.toFixed(4)}) = <span class="highlight">${f.a_h2.toFixed(6)}</span>
`;
// ---- 第2层 ----
document.getElementById('layer2Math').innerHTML = `
<span style="color:#ff66aa;">ŷ = σ(z_out)</span> , z_out = ${v1.toFixed(4)}·${f.a_h1.toFixed(4)} + ${v2.toFixed(4)}·${f.a_h2.toFixed(4)} + ${b_out.toFixed(4)} = ${f.z_out.toFixed(6)}
ŷ = σ(${f.z_out.toFixed(4)}) = <span class="highlight2">${f.y_pred.toFixed(6)}</span>
🔹 损失 L = ½·(${f.y_pred.toFixed(4)} - ${y_true.toFixed(2)})² = <span class="highlight3">${f.loss.toFixed(6)}</span>
`;
// ---- 反向传播 ----
document.getElementById('backwardMath').innerHTML = `
🔸 输出层增量 δ_out = (ŷ - y)·σ'(z_out) = (${f.y_pred.toFixed(4)} - ${y_true.toFixed(2)}) · ${f.da_out_dz_out.toFixed(6)} = <span class="highlight3">${f.delta_out.toFixed(6)}</span>
🔸 隐藏层增量 δ₁ = δ_out·v₁·σ'(a₁) = ${f.delta_out.toFixed(6)} · ${v1.toFixed(4)} · ${f.da_h1_dz_h1.toFixed(6)} = <span class="highlight3">${f.delta_h1.toFixed(6)}</span>
δ₂ = δ_out·v₂·σ'(a₂) = ${f.delta_out.toFixed(6)} · ${v2.toFixed(4)} · ${f.da_h2_dz_h2.toFixed(6)} = <span class="highlight3">${f.delta_h2.toFixed(6)}</span>
🔸 梯度示例: ∂L/∂w₁₁ = δ₁·x₁ = ${f.delta_h1.toFixed(6)} · ${x1.toFixed(2)} = <span class="highlight">${f.grad_w11.toFixed(6)}</span>
`;
// ---- 更新 ----
if (grads) {
document.getElementById('updateMath').innerHTML = `
w₁₁(新) = ${w11.toFixed(4)} - ${lr.toFixed(2)}·(${grads.grad_w11.toFixed(6)}) = <span style="color:#33ff88;">${(w11 - lr*grads.grad_w11).toFixed(6)}</span>
w₁₂(新) = ${w12.toFixed(4)} - ${lr.toFixed(2)}·(${grads.grad_w12.toFixed(6)}) = <span style="color:#33ff88;">${(w12 - lr*grads.grad_w12).toFixed(6)}</span>
... (其余权重同理)
`;
} else {
document.getElementById('updateMath').innerHTML = '<span style="color:#667;">执行单步BP后显示更新...</span>';
}
}
function fullUpdateUI() {
const f = forward(x1, x2);
const loss = computeLoss(f.a_out, y_true);
document.getElementById('lossDisplay').textContent = loss.toFixed(6);
document.getElementById('epochDisplay').textContent = epoch;
renderParams();
if (cache && cache.delta_out !== undefined) {
const grads = {
grad_w11: cache.grad_w11, grad_w12: cache.grad_w12,
grad_w21: cache.grad_w21, grad_w22: cache.grad_w22,
grad_b1: cache.grad_b1, grad_b2: cache.grad_b2,
grad_v1: cache.grad_v1, grad_v2: cache.grad_v2,
grad_b_out: cache.grad_b_out
};
renderGradients(grads);
renderMath(cache, grads);
} else {
const tempCache = { ...f, y_pred: f.a_out, loss: computeLoss(f.a_out, y_true) };
renderMath(tempCache, null);
document.getElementById('gradientDisplay').innerHTML = '<span style="color:#667;">点击“单步BP”计算梯度...</span>';
}
}
// ============================================================
// 4. 动作
// ============================================================
function doBackpropStep() {
const result = backward(x1, x2, y_true);
updateWeights(result.grads);
epoch++;
renderGradients(result.grads);
renderMath(cache, result.grads);
fullUpdateUI();
return result.loss;
}
function resetNetwork() {
if (trainInterval) { clearInterval(trainInterval);
trainInterval = null; }
isTraining = false;
document.getElementById('trainBtn').textContent = '▶ 开始训练';
document.getElementById('statusBadge').textContent = '⏸ 待命';
document.getElementById('statusBadge').className = 'status-badge stopped';
w11 = 0.15;
w12 = 0.20;
w21 = 0.25;
w22 = 0.30;
b1 = 0.35;
b2 = 0.35;
v1 = 0.40;
v2 = 0.45;
b_out = 0.60;
epoch = 0;
cache = {};
document.getElementById('gradientDisplay').innerHTML = '<span style="color:#667;">尚未计算...</span>';
fullUpdateUI();
document.getElementById('layer1Math').innerHTML = '<span style="color:#667;">点击“单步BP”查看...</span>';
document.getElementById('layer2Math').innerHTML = '<span style="color:#667;">点击“单步BP”查看...</span>';
document.getElementById('backwardMath').innerHTML = '<span style="color:#667;">点击“单步BP”查看...</span>';
document.getElementById('updateMath').innerHTML = '<span style="color:#667;">点击“单步BP”查看...</span>';
}
function toggleTraining() {
if (isTraining) {
if (trainInterval) { clearInterval(trainInterval);
trainInterval = null; }
isTraining = false;
document.getElementById('trainBtn').textContent = '▶ 继续训练';
document.getElementById('statusBadge').textContent = '⏸ 已暂停';
document.getElementById('statusBadge').className = 'status-badge stopped';
} else {
isTraining = true;
document.getElementById('trainBtn').textContent = '⏹ 停止';
document.getElementById('statusBadge').textContent = '▶ 训练中...';
document.getElementById('statusBadge').className = 'status-badge running';
if (trainInterval) clearInterval(trainInterval);
trainInterval = setInterval(() => {
const loss = doBackpropStep();
if (loss < 0.00001) {
clearInterval(trainInterval);
trainInterval = null;
isTraining = false;
document.getElementById('trainBtn').textContent = '✅ 已收敛';
document.getElementById('statusBadge').textContent = '✅ 收敛';
document.getElementById('statusBadge').className = 'status-badge running';
}
}, 80);
}
}
// ============================================================
// 5. 绑定
// ============================================================
document.getElementById('x1Slider').addEventListener('input', (e) => {
x1 = parseFloat(e.target.value);
document.getElementById('x1Val').textContent = x1.toFixed(2);
if (!isTraining) { cache = {};
fullUpdateUI(); }
});
document.getElementById('x2Slider').addEventListener('input', (e) => {
x2 = parseFloat(e.target.value);
document.getElementById('x2Val').textContent = x2.toFixed(2);
if (!isTraining) { cache = {};
fullUpdateUI(); }
});
document.getElementById('ySlider').addEventListener('input', (e) => {
y_true = parseFloat(e.target.value);
document.getElementById('yVal').textContent = y_true.toFixed(2);
if (!isTraining) { cache = {};
fullUpdateUI(); }
});
document.getElementById('stepBtn').addEventListener('click', () => { if (!isTraining) doBackpropStep(); });
document.getElementById('trainBtn').addEventListener('click', toggleTraining);
document.getElementById('resetBtn').addEventListener('click', resetNetwork);
resetNetwork();
</script>
</body>
</html>
浙公网安备 33010602011771号