10.11日志____基础batch,分批次的具体过程

1、nn.BatchNorm2d函数讲解,李哥考研图片分类的代码

点击查看代码
 # 3*224*224 -> 52*7*7 ->拉直->全连接
 #卷积 归一化 激活 池化,是一套服务
        self.conv1 =nn.Conv2d(3,64,3,1,1) #64*224*224 ;Conv2d(二维卷积)名字的由来:卷积核在 H×W 两个方向上滑动,不管通道有多少。
        self.bn1 = nn.BatchNorm2d(64)   #Batch(批次),Normalization(归一化、标准化),2D(二维);64表示通道数
        self.relu = nn.ReLU()
        self.pool1 = nn.MaxPool2d(2)
图片

2、BatchNorm2d(64), 这个不是批次归一化吗,怎么分的批次,是程序员自己分的吗

批次(batch)不是程序员手动去“分”的,而是数据加载时自动按 batch_size 切出来的。

📦 批次是怎么来的

在 PyTorch 里,你用 DataLoader 加载数据时,会指定一个 batch_size:
train_loader = DataLoader(dataset, batch_size=32, shuffle=True)

3、训练阶段、推理阶段和训练集、验证集、推理集的关联

图片

3、批次只在训练时分吗?推理也分吗?

训练和推理都会分批次,但目的和影响不同。训练:分批是必须的,且批次大小会影响效果。推理:分批只是工程手段,batch_size 设 1 或 64,单张图输出应该一致。

3.1 5000 张图分类,分批次动态过程

假设: 5000 张图、 batch_size = 32、 训练 1 个 epoch

流程: 1、打乱索引:5000 个索引随机排列。 2、切分 batch:5000 ÷ 32 = 156 个完整 batch,最后剩 8 张作为第 157 个 batch。 3、 逐个 batch 前向 + 反向:每个 batch 更新一次参数。 4、1 个 epoch 结束:所有 5000 张图都被看过一次,参数更新了 157 次。

为什么分批次训练有效果? 1、梯度更稳:32 张图的平均梯度比 1 张图的梯度噪声小,比 5000 张的梯度更易计算。2、显存可行:一次只放 32 张图进 GPU。 3、BN 可用:batch 内统计量才有意义。 4、收敛更快:一个 epoch 内多次更新,比全量梯度下降快得多。

批次大小的影响: 太小(如 1、2):梯度噪声大,BN 统计不稳,训练震荡。 太大(如 512):显存爆,梯度太“平均”,泛化可能变差。常用 32、64、128,需要根据显存和任务调。

3.2 不是 157 次更新都“同样有用”,但它们整体上是有效的,而且这种“看似有噪声”的更新反而常常比全量更新更好

图片

3.3下面这个 HTML 文件用动画展示了 5000 张图被切成 batch、逐个送入模型训练的过程。你可以直接保存为 .html 文件,用浏览器打开。

点击查看代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>批次训练动态演示</title>
<style>
  body {
    font-family: "Microsoft YaHei", sans-serif;
    background: #0f172a;
    color: #e2e8f0;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 30px;
  }
  h1 { font-size: 22px; margin-bottom: 10px; color: #38bdf8; }
  .info { font-size: 14px; color: #94a3b8; margin-bottom: 20px; }
  .container {
    display: flex;
    gap: 40px;
    align-items: flex-start;
  }
  .pool {
    display: grid;
    grid-template-columns: repeat(20, 14px);
    gap: 3px;
    padding: 12px;
    background: #1e293b;
    border-radius: 10px;
    border: 1px solid #334155;
  }
  .img {
    width: 14px;
    height: 14px;
    border-radius: 3px;
    background: #475569;
    transition: all 0.2s;
  }
  .img.used { background: #22c55e; }
  .img.current { background: #f59e0b; transform: scale(1.4); }
  .img.remaining { background: #475569; }

  .right-panel {
    display: flex;
    flex-direction: column;
    gap: 20px;
    min-width: 320px;
  }
  .batch-box {
    background: #1e293b;
    border: 1px solid #334155;
    border-radius: 10px;
    padding: 16px;
  }
  .batch-title { font-size: 14px; color: #94a3b8; margin-bottom: 10px; }
  .batch-grid {
    display: grid;
    grid-template-columns: repeat(8, 22px);
    gap: 4px;
    min-height: 60px;
  }
  .batch-img {
    width: 22px;
    height: 22px;
    border-radius: 4px;
    background: #f59e0b;
    opacity: 0;
    transform: scale(0.3);
    transition: all 0.25s;
  }
  .batch-img.show { opacity: 1; transform: scale(1); }

  .model {
    background: #1e293b;
    border: 1px solid #334155;
    border-radius: 10px;
    padding: 16px;
    text-align: center;
  }
  .model-title { font-size: 14px; color: #94a3b8; }
  .model-box {
    margin-top: 10px;
    padding: 14px;
    border-radius: 8px;
    background: #0ea5e9;
    color: white;
    font-weight: bold;
    transition: all 0.3s;
  }
  .model-box.active {
    background: #22c55e;
    box-shadow: 0 0 20px #22c55e;
  }

  .stats {
    background: #1e293b;
    border: 1px solid #334155;
    border-radius: 10px;
    padding: 16px;
    font-size: 14px;
    line-height: 1.9;
  }
  .stats span { color: #38bdf8; font-weight: bold; }

  button {
    margin-top: 20px;
    padding: 10px 28px;
    font-size: 15px;
    border: none;
    border-radius: 8px;
    background: #0ea5e9;
    color: white;
    cursor: pointer;
    transition: background 0.2s;
  }
  button:hover { background: #0284c7; }
  button:disabled { background: #475569; cursor: not-allowed; }
</style>
</head>
<body>

<h1>🧠 5000 张图分批次训练演示</h1>
<div class="info">batch_size = 32 | 总 batch 数 = 157 | 训练 1 个 epoch</div>

<div class="container">
  <!-- 左:数据池 -->
  <div>
    <div class="info" style="text-align:center">数据池(5000 张,只显示前 400 个)</div>
    <div class="pool" id="pool"></div>
  </div>

  <!-- 右:当前 batch + 模型 + 统计 -->
  <div class="right-panel">
    <div class="batch-box">
      <div class="batch-title">当前送入模型的 Batch</div>
      <div class="batch-grid" id="batchGrid"></div>
    </div>

    <div class="model">
      <div class="model-title">模型(参数更新)</div>
      <div class="model-box" id="modelBox">等待中…</div>
    </div>

    <div class="stats">
      <div>当前 Batch:<span id="curBatch">0</span> / 157</div>
      <div>已训练图片:<span id="trained">0</span> / 5000</div>
      <div>参数更新次数:<span id="updates">0</span></div>
    </div>
  </div>
</div>

<button id="startBtn" onclick="startTraining()">▶ 开始训练</button>

<script>
const TOTAL = 5000;
const BATCH_SIZE = 32;
const VISIBLE = 400; // 数据池只显示前 400 个
const TOTAL_BATCHES = Math.ceil(TOTAL / BATCH_SIZE);

// 生成数据池
const pool = document.getElementById('pool');
const imgEls = [];
for (let i = 0; i < VISIBLE; i++) {
  const d = document.createElement('div');
  d.className = 'img remaining';
  pool.appendChild(d);
  imgEls.push(d);
}

const batchGrid = document.getElementById('batchGrid');
const modelBox = document.getElementById('modelBox');
const curBatchEl = document.getElementById('curBatch');
const trainedEl = document.getElementById('trained');
const updatesEl = document.getElementById('updates');

// 打乱索引
function shuffle(arr) {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

let indices = shuffle([...Array(TOTAL).keys()]);

async function startTraining() {
  const btn = document.getElementById('startBtn');
  btn.disabled = true;
  btn.textContent = '训练中…';

  let trained = 0;
  let updates = 0;

  for (let b = 0; b < TOTAL_BATCHES; b++) {
    const start = b * BATCH_SIZE;
    const batchIdx = indices.slice(start, start + BATCH_SIZE);

    // 1. 展示当前 batch 里的图片
    batchGrid.innerHTML = '';
    for (let k = 0; k < batchIdx.length; k++) {
      const d = document.createElement('div');
      d.className = 'batch-img';
      batchGrid.appendChild(d);
      setTimeout(() => d.classList.add('show'), k * 8);
    }

    // 2. 数据池里标记当前 batch(只标记可见部分)
    batchIdx.forEach(idx => {
      if (idx < VISIBLE) {
        imgEls[idx].className = 'img current';
      }
    });

    curBatchEl.textContent = b + 1;

    // 3. 模型更新
    await sleep(120);
    modelBox.classList.add('active');
    modelBox.textContent = `第 ${b + 1} 次参数更新 ✅`;

    // 4. 标记为已训练
    batchIdx.forEach(idx => {
      if (idx < VISIBLE) {
        imgEls[idx].className = 'img used';
      }
    });

    trained += batchIdx.length;
    updates++;
    trainedEl.textContent = trained;
    updatesEl.textContent = updates;

    await sleep(80);
    modelBox.classList.remove('active');
  }

  modelBox.textContent = '🎉 1 个 epoch 完成!';
  btn.textContent = '✅ 训练完成';
}

function sleep(ms) {
  return new Promise(r => setTimeout(r, ms));
}
</script>
</body>
</html>
posted @ 2026-10-11 22:05  小小冰&碎冰冰  阅读(3)  评论(0)    收藏  举报