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>
浙公网安备 33010602011771号