新闻详情

新闻详情

首页 / 资讯中心 / 详情

MNIST手写识别实战:基于Python的CNN工程全解析

发布时间:2026/10/2 2:12:34来源:尧图网络
MNIST手写识别实战:基于Python的CNN工程全解析
简介面向计算机、电子信息、数学等专业学生这款资源提供基于Python深度学习实现MNIST手写数字识别的完整源码与原始数据可直接用于课程设计、期末大作业或毕业设计的参考与实践。压缩包共18个文件结构清晰5个Python源文件对应主程序、卷积网络、层与函数实现、数据加载等核心模块5个pyc编译文件便于快速加载3个JSON配置文件提供VSCode任务与调试参数1个pkl归档及2组idx3/idx1格式的训练测试图像与标签构成了完整的数据集整体仅19.77MB传输与使用都很便捷。目前已有511人学习下载。源码设计模块化main.py可一键启动训练ConvNet.py、layers.py、functions.py等内容适合逐步拆解卷积、池化、全连接和反向传播细节既能帮助初学者理解深度学习整体流程也方便有基础者在此基础上修改网络结构或超参数进行二次开发。1. 一份自带IDX数据的MNIST识别工程为什么我建议先把它跑通再谈理论很多人的第一份深度学习作业都卡在“数据下不下来”这一步。我最近拆了一份基于Python深度学习实现mnist手写数据集识别的源码包里面不仅有完整的CNN代码还把train-images-idx3-ubyte、train-labels-idx1-ubyte、t10k系列原始IDX数据一并打进了rar解压就能跑不用等网络、不用忍受torchvision返回404的尴尬。工程的模块划分很典型layers.py管网络层、functions.py管激活与损失、ConvNet.py定义卷积网络、mnist.py负责数据加载最后main.py统一训练入口。它适合做课程设计、期末大作业也适合刚看完理论想亲手把CNN跑通的人对熟手来说这套结构也是一份不错的调参参考。2. 工程结构与运行准备从.vscode到mnist.py先让训练跑起来先别急着看训练代码把工程结构摸清楚能少走很多弯路。这个压缩包解压后其实分成四类东西源码、原始数据、中间缓存、编辑器配置。第一次打开工程就被一堆文件吓住很正常但真正需要关心的只有main.py、layers.py、functions.py、ConvNet.py、mnist.py这五个Python文件以及四个idx开头的原始数据文件。2.1 文件清单哪些是代码、哪些是数据、哪些可以放心删文件/目录作用处理建议main.py训练入口加载数据、构建网络、执行训练循环核心代码保留layers.pyAffine/ReLU/Conv/Pool等网络层的类实现核心代码保留functions.pysoftmax、交叉熵等激活与损失函数核心代码保留ConvNet.py卷积网络结构定义与梯度计算核心代码保留mnist.py读取IDX数据、归一化、one-hot、生成pkl核心代码保留mnist.pklmnist.py生成的预处理数据缓存可删运行后自动重建train-images-idx3-ubyte等4个数据文件MNIST原始训练集与测试集保留是项目的数据本体.vscodeVSCode的调试与任务配置参考路径需按本机调整pycache/*.pycPython字节码缓存可删不影响功能先说数据文件。MNIST训练集有60000张图测试集10000张输入是28x28的灰度图每个像素是一个0到255的uint8整数。这4个文件就是最原始的IDX格式很多在线教程还要额外下载这份资源直接替你把这一步省了。mnist.pkl是mnist.py把IDX数据解析并做归一化、one-hot之后序列化出来的缓存第二次训练时直接从pkl加载可以少解析一遍二进制文件启动更快。如果pkl丢了mnist.py会在首次运行时重新生成所以它属于“可删但建议保留”的文件。.vscode目录里有settings.json、tasks.json、launch.json说明作者用VSCode调试工程。这个目录不是必须的里面保存的解释器路径是作者机器的绝对路径到你的电脑上大概率失效直接删掉也不影响任何训练功能。__pycache__里的pyc文件同理属于运行缓存删掉后Python会在下次import时自动重新生成。解压后建议先看一眼数据文件的大小。图像文件按60000×28×28计算约为45MB测试图像约7.5MB两个标签文件各几十KB整个数据集加起来五十多MB。如果解压后远小于这个量级大概率是压缩包传输过程中出了问题先重新解压再跑训练不要在这种事情上浪费时间。2.2 环境准备Python 3.7、numpy与launch.json的调整从__pycache__里的simpleConvNet.cpython-37.pyc可以判断作者用的是Python 3.7。虽然Python 3.8到3.12也能兼容这类纯NumPy工程但为了避免依赖的坑我建议本地装一个3.7或3.8的解释器。别用系统自带的全局环境单独拉一个虚拟环境最省心。# 创建虚拟环境并安装依赖 python -m venv .venv source .venv/bin/activate # Windows 下用 .venv\Scripts\activate pip install numpy matplotlib第一条命令在当前目录创建名为.venv的虚拟环境第二条激活它第三条安装numpy和matplotlib。numpy是网络计算的基础matplotlib用于画loss曲线和可视化预测结果如果不想画图matplotlib可以不装但建议留着后面验证模型时用得上。安装完成后直接在命令行跑python main.py如果训练日志开始输出说明工程跑通了。这里有一个容易忽略的点main.py里如果写了读取mnist.pkl的逻辑第一次跑会先走“解析IDX→预处理→生成pkl”这条路耗时比后续运行多几十秒这是正常现象不是死循环。耐心等它把pkl写出来之后每次启动都会快很多。我处理这类带.vscode的工程时第一件事就是先把配置看一遍。launch.json是F5调试的入口里面通常写着pythonPath这样的字段。你本机解释器路径如果和作者不一致调试根本起不来。改法有两种一是把launch.json里的pythonPath改成你venv里python的绝对路径二是干脆删掉.vscode全程用命令行跑。对课程设计来说第二种更省事调试断点可以用Python自带的breakpoint()函数代替效果一样。{ version: 0.2.0, configurations: [ { name: Python: main.py, type: python, request: launch, program: ${workspaceFolder}/main.py, console: integratedTerminal, pythonPath: ${workspaceFolder}/.venv/bin/python } ] }这个配置里${workspaceFolder}代表工程根目录pythonPath指向虚拟环境里的python解释器。实际使用时把pythonPath改成你自己的路径即可。还有一种更现代的做法是去掉pythonPath字段在VSCode左下角点击解释器选择按钮直接选当前venv环境这样launch.json不需要写死路径换机器也不容易出问题。还有一个小提醒安装numpy时如果提示pip版本太老先执行pip install --upgrade pip再装。Python 3.7对应numpy的版本不要盲目上最新版老解释器配老numpy更稳一般pip install numpy2.0能避开大部分兼容问题。等环境全部就绪、训练跑通再回头研究每一个模块的实现细节你会发现那些概念突然变得好理解多了。3. 核心模块拆解layers.py、functions.py与ConvNet.py如何搭起一个CNN整个资源里最有价值的部分就是源码模块的划分。很多同学跑得通main.py但问起“反向传播到底是怎么传的”就说不清了。其实把这几个模块的职责分清楚CNN的黑匣子就没那么玄了。3.1 layers.py把层写成类的经典套路基于NumPy手写深度学习时最常见的组织方式是把每一层定义成一个类。这个类通常有初始化参数、前向传播forward和反向传播backward三个部分。以全连接层Affine为例它在MNIST工程里是最基本的组件。下面这段代码就是典型的实现模板import numpy as np class Affine: def __init__(self, W, b): self.W W # 权重形状 (输入维度, 输出维度) self.b b # 偏置形状 (输出维度,) self.x None # 记住输入供反向传播使用 self.dW None # 权重梯度 self.db None # 偏置梯度 def forward(self, x): self.x x return np.dot(x, self.W) self.b def backward(self, dout): dx np.dot(dout, self.W.T) self.dW np.dot(self.x.T, dout) self.db np.sum(dout, axis0) return dxforward只有一句话输入x与权重W做矩阵乘法再加偏置b。反向传播则是三条赋值语句。为什么要保存self.x因为计算dW时需要用到前向时的输入。dW x.T dot dout 这个式子是从矩阵求导链式法则推出来的不是拍脑袋写的。db要对批量维度求和因为偏置对每个样本共享梯度需要累加。整个Affine类写完再把其他层也定义成类就能像搭积木一样串起来构建网络。层写成类还有一个好处调试时可以在forward里临时加print看某个中间层输出的形状排查维度对不上的问题。我在实际调试时经常这么干比在损失函数里干瞪眼快得多。如果不想从头手写也可以直接用PyTorch的nn.Linear但如果目的是搞懂原理跟着这份资源自己写一遍Affine的forward和backward收获会比调框架大得多。再看另一个必有的层ReLUclass ReLU: def __init__(self): self.mask None def forward(self, x): self.mask (x 0) out x.copy() out[self.mask] 0 return out def backward(self, dout): dout[self.mask] 0 return doutmask记录的是输入中所有小于等于0的位置。前向时把这些位置置0反向时把梯度也置0因为ReLU在负数区域的导数是0。至于为什么用ReLU而不是sigmoid一句话就能说明白sigmoid在深层网络中梯度会越传越小最后消失ReLU在正数区域导数是1能缓解梯度消失所以现在的卷积网络几乎默认用ReLU。在MNIST这种浅层小网络上ReLU和sigmoid差异没那么大但养成用ReLU的习惯没坏处。3.2 functions.py激活函数与损失函数的数值稳定写法functions.py里通常放着两种东西激活函数和损失函数。激活函数已经见过ReLU损失函数里最核心的是softmax和交叉熵。MNIST是10分类输出层的softmax把10个得分转成概率分布交叉熵损失度量预测分布与真实标签的距离。很多初学者以为这两个是分开的函数其实在反向传播里它们经常组合在一起梯度公式会简化成“预测值减真实值”非常漂亮。def softmax(x): m np.max(x, axis1, keepdimsTrue) exp_x np.exp(x - m) return exp_x / np.sum(exp_x, axis1, keepdimsTrue) def cross_entropy_error(y, t): batch_size y.shape[0] return -np.sum(t * np.log(y 1e-7)) / batch_sizesoftmax里那个m是关键。exp函数在输入稍大时会指数爆炸比如exp(1000)直接变成inf再除以总和就得到nan。先减去每行的最大值指数部分的最大值变成0其余都小于0指数算出来一定是一个有限的小数数值稳定性一下就上来了。交叉熵里的1e-7则是防log(0)的保险丝。y是softmax的输出理论上概率值大于0但浮点运算可能得到极小值如果恰好是0log(0)就是-inf整个loss变成inf或nan。加一个极小正数就把这个风险堵住了。参数说明x的shape一般是(批大小, 10)t的shape要么是(批大小, 10)的one-hot要么是(批大小,)的整数标签。上面这段交叉熵是按one-hot写的如果t是整数标签可以改成-np.log(y[np.arange(batch_size), t])效果完全一样还省内存。手写工程里两种写法都有我倾向后一种因为省去one-hot转换的步骤。损失函数层在反向传播里会输出一个特殊的梯度如果网络最后一层是softmax和交叉熵的组合那么回传给前一层的梯度就是(y - t) / batch_size。这个结论不用死记但调试时可以拿它对照验证梯度实现是否正确。万一自己写的梯度和数值梯度对不上先检查是不是这个表达式算错了。3.3 ConvNet.py从SimpleNet到可训练的卷积网络ConvNet.py是网络装配的地方。从__pycache__里simpleConvNet.cpython-37.pyc这个文件名看作者定义了一个SimpleConvNet类。这类网络的结构通常很直接卷积层提取局部特征池化层压缩尺寸最后接两个全连接层输出10个类别的得分。结构示意如下class SimpleConvNet: def __init__(self, input_dim(1, 28, 28), hidden_size50, output_size10): self.layers [ Conv(input_dim, 16, filter_size5, stride1, pad0), ReLU(), Pool(pool_h2, pool_w2, stride2), Affine(16 * 12 * 12, hidden_size), ReLU(), Affine(hidden_size, output_size) ] self.last_layer SoftmaxWithLoss() def predict(self, x): for layer in self.layers: x layer.forward(x) return x def loss(self, x, t): y self.predict(x) return self.last_layer.forward(y, t) def gradient(self, x, t): # 前向记录各层中间结果反向按层逆序回传 self.loss(x, t) dout 1 dout self.last_layer.backward(dout) # softmax交叉熵的梯度简化为 y-t for layer in reversed(self.layers): dout layer.backward(dout) # 各层内部的 dW、db 已经在这轮反向传播中被更新这段结构里有一个需要自己算清楚的地方161212是怎么来的。输入是1x28x28的灰度图5x5卷积核不填充pad、步长1输出尺寸是(28-5)/1124所以卷积后变成16x24x242x2池化步长2尺寸减半变成16x12x12展平后就是1612122304维刚好接第一层全连接。如果修改了卷积核大小或池化步长这个数字必须跟着改否则维度对不上会直接报错。forward的写法极简一个循环把每层依次过一遍最后拿到10个得分。这种顺序层结构是手写CNN最通用的设计理解成本低也好改。反向传播的原理是链式法则backward从loss开始往前传每一层把上游传来的梯度继续回传并顺势计算本层的参数梯度。读者改网络时只需要遵守一条规则forward怎么定义backward就按相反顺序传。训练时超参数的选择比网络深度更能决定成败。MNIST在视觉入门数据集里算最简单的一类几十万参数的小网络已经足够。与其追求网络深不如先把lr、batch、epoch这几个基础参数调明白。4. 数据从IDX到pklmnist.py的加载流程与train/test划分MNIST的手写识别任务本身不难但这个数据集在工程落地上有几个反直觉的坑。mnist.py的作用就是把原始二进制文件解析成网络认识的NumPy数组并顺手把预处理做完。4.1 IDX格式解析idx3-ubyte到底是什么train-images-idx3-ubyte不是一个普通图片文件而是IDX格式的二进制数据。它的头部用一个4字节的magic number标识类型数据内容按大端序存储。图像文件的magic是2051十六进制0x0801标签文件的magic是20490x0803。解析时先用struct模块把这些头部信息读出来剩下的大块数据才是真正的图像或标签。import struct import numpy as np def load_idx(path): with open(path, rb) as f: magic, n struct.unpack(II, f.read(8)) if magic 2051: # 图像维度是 n x rows x cols rows, cols struct.unpack(II, f.read(8)) data np.frombuffer(f.read(), dtypenp.uint8) data data.reshape(n, rows, cols) return data elif magic 2049: # 标签一维数组 data np.frombuffer(f.read(), dtypenp.uint8) return data else: raise ValueError(f未知magic number: {magic})代码里的II需要解释一下。表示大端序II表示连续读两个无符号整型。IDX格式规定所有头部字段都是大端字节序这和x86机器默认的小端相反漏掉读出来的数字就会错乱得离谱。图像和标签走不同分支因为图像除了样本数还需要读行数、列数两个维度标签则是一维标量没有额外的shape信息。用np.frombuffer直接读整段字节效率比逐字节读取高好几个数量级MNIST有六万张图这个习惯很重要。为什么不直接用深度学习框架的加载接口因为这份资源走的是“纯NumPy手写网络”路线从数据读取到网络训练都不依赖PyTorch/TensorFlow。如果只是交作业直接用框架内置的MNIST接口当然更省事但想把数据格式、预处理、训练全链路都弄明白手动解析IDX是绕不开的一环。4.2 归一化与one-hot一份可复用的预处理原始图像数据是0到255的灰度值训练前必须除以255归一化到[0,1]区间。原因很简单网络初始权重下输入范围过大会让加权求和的结果方差变大经过softmax后某些样本的梯度可能一开始就非常大训练不稳定。归一化是最廉价也最有效的预处理手段。同样重要的是标签的one-hot转换。MNIST标签是0到9的整数如果交叉熵按t * np.log(y)的方式计算t必须是one-hot向量也就是每行只有一个位置是1、其余是0。转换函数一般长这样def _change_one_hot_label(X): T np.zeros((X.size, 10)) for idx, row in enumerate(X): T[idx, row] 1 return TX.size是样本总数列数10对应10个数字类别。循环里把每个样本的整数标签row映射到one-hot矩阵T的对应列。这段代码在60000个样本上跑大概需要几秒不算慢。如果追求效率也可以用T[np.arange(X.size), X] 1这种向量化写法一行搞定效果完全相同。mnist.py完成的数据处理包括解析IDX、归一化、one-hot、划分训练集和测试集最后把这四组数据打包成字典用pickle写进mnist.pkl。这样做之后第二次运行的启动时间会明显缩短。但这里有一个隐患如果修改了mnist.py的预处理逻辑而pkl还在加载的仍然是旧缓存代码更新了但行为没变这是个很难察觉的黑匣子。注意mnist.pkl只是缓存mnist.py的预处理逻辑一旦改动记得先删掉再重跑。我用这类缓存文件时的习惯是只要动了数据加载相关代码就手动把pkl删掉绝不依赖“自动重建”这个兜底逻辑。因为自动重建只在文件不存在时触发不会检查文件是否过期。4.3 训练入口main.py超参数设置与Loss曲线main.py把前面所有模块串起来。典型的训练循环是加载数据、初始化网络、随机抽样一批样本、算loss、反向传播、更新参数、重复若干轮。从工程结构看这份源码的main.py承担的就是这个职责。下面是这套工程里最常见也最能复现结果的骨架import numpy as np from mnist import load_mnist from ConvNet import SimpleConvNet lr 0.01 # 学习率SGD的常用起点 hidden_size 50 # 全连接层神经元数量 epochs 10 # 训练轮数 batch_size 100 # 每次采样100个样本 (x_train, t_train), (x_test, t_test) load_mnist( normalizeTrue, one_hot_labelTrue) net SimpleConvNet() for epoch in range(epochs): idx np.random.choice(x_train.shape[0], batch_size) x_batch x_train[idx] t_batch t_train[idx] loss net.loss(x_batch, t_batch) grads net.gradient(x_batch, t_batch) for key in net.params: net.params[key] - lr * grads[key] print(fepoch {epoch1}, loss{loss:.4f})参数说明lr0.01是SGD在MNIST上的常用起点太小收敛慢太大会在loss曲线上看到明显震荡甚至发散batch_size100是折中太大梯度方向更稳但每轮要跑更久太小梯度噪声大100对这个数据集来说比较合适epochs设10到20都能有不错的收敛效果。关键是每个epoch从训练集里随机抽100个样本而不是把全部60000张图都喂进去这种mini-batch方式既省内存又引入随机性能帮助跳出局部极小。loss曲线是最直观的健康指标。正常训练时loss应该先快速下降然后慢慢趋于平缓。如果loss不是下降而是频繁跳动优先调学习率如果loss一开始就nan回到前面检查softmax有没有减max、数据有没有归一化。不要急着加BN、Dropout之类的花活MNIST这种规模的任务把基础参数调对就够用了。训练结束后把测试集数据也走一遍网络算一算准确率才算真正闭环。5. 排查手册环境、数据与训练三个层面的常见坑代码能跑是一回事跑得顺利是另一回事。这一章把我实际遇到过的、以及从工程结构能推断出的高频坑位整理出来按现象、原因、解决三步写方便直接对照排查。5.1 数据获取torchvision下载MNIST返回404现象有同学收到这份资源后并不用mnist.py而是顺手写了一段torchvision代码下载MNIST结果长时间停在Downloading最后报urllib.error.HTTPError: HTTP Error 404或者文件校验失败。原因torchvision.datasets.MNIST默认下载地址不在国内文件又大下载过程容易中断或校验失败。更坑的是torchvision对文件名和响应有严格校验即使文件下了一半也可能被判定为下载失败重试也不会续传。解决这份资源本身已经把IDX原始数据打包好了根本不需要联网下载。直接用mnist.py的load_mnist函数解析本地文件即可。如果非要用torchvision的接口也可以把download设为False并把root指向包含原始数据的目录。但IDX文件和torchvision期望的目录结构不一定一致最保险的做法还是走本地mnist.py。我拿到任何和MNIST相关的工程第一反应都是先看有没有原始数据文件有就绝不下载。这算是我踩过一次404之后总结出来的血泪经验。5.2 数据解析读出来的形状与预期不符现象load_mnist返回的训练集shape是(60000,)而不是预期的(60000, 1, 28, 28)训练时矩阵乘法直接报维度错误或者图像打印出来是乱的。原因解析IDX时magic number判断写反或者没有按大端序读取。图像文件magic是2051标签文件magic是2049两者shape逻辑完全不同。如果没区分magic直接统一按图像逻辑解析标签数据会少读两个字段导致后续整个张量错位。解决先单独写个脚本只解析一个文件把magic、n、rows、cols全打印出来确认。读到magic2051时按图像处理等于2049时按标签处理。读取时用struct.unpack(II, ...)大端序不能漏。reshape时顺序是(n, rows, cols)其中像素按行优先存储颠倒顺序会得到一张错乱的图。还有一个很实用的小技巧把解析出来的第一条数据用matplotlib画出来看一眼如果能清晰看到一个数字再继续往下训练。这一步十秒钟能省下后面白跑半小时的后悔药。5.3 工程环境launch.json里的pythonPath失效现象用VSCode打开工程后按F5提示“无法启动调试”或者解释器路径不存在也有人启动后提示找不到numpy。原因.vscode/launch.json里保存的是作者机器上的绝对路径换一台电脑基本都会失效。这类配置文件天生不跨机器属于个人环境产物不是工程本身的一部分。解决最简单的办法是删掉.vscode目录直接在命令行里python main.py。如果习惯在VSCode里调试就手动把launch.json里的pythonPath改成当前venv的python路径。更稳妥的做法是在VSCode左下角点解释器选择你创建好的.venv环境launch.json里的python属性留空让VSCode自动使用当前选中的解释器。环境相关的问题绝大多数都能靠这个办法解决不用怀疑源码有问题。5.4 训练异常loss输出为nan现象训练刚开始正常loss在下降到某个epoch突然变成nan后面一直nan模型输出也全部变成nan或0。原因最常遇到的是softmax溢出输入值过大时exp算成inf除以inf得到nan。其次是数据没有归一化uint8的0到255像素直接喂进网络初始梯度量级过大再次是学习率设得太大比如直接抄了0.5或1.0SGD一步跨出去就把参数更新到数值爆炸的地方。解决按顺序检查三件事softmax里有没有减max训练数据有没有除以255归一化学习率是不是从0.01附近起步。还有一个隐蔽来源标签没有转one-hot导致交叉熵里t * np.log(y)作用在错误形状上出现负数和nan。把loss打印语句保留着前几个epoch如果loss在2.3附近然后快速下降说明网络状态正常。如果loss一开始就是nan不用犹豫直接回数据预处理里找问题。数值稳定性问题在MNIST这种小网络上很容易被忽略但它恰恰是手写网络最容易翻车的地方。5.5 工程认知__pycache__里的pyc文件可以随便删现象压缩包里有一个__pycache__目录里面放着simpleConvNet.cpython-37.pyc、mnist.cpython-37.pyc等文件。有些同学以为这是额外的源码或者删了怕工程跑不了。原因.pyc是Python解释器在import模块时生成的字节码缓存目的是加速下次启动。文件名里的cpython-37表示这个缓存对应CPython 3.7版本如果换用其他Python版本缓存会失效并重新生成。解决放心删完全不影响功能。下次运行main.py时Python会自动生成新的pyc。判断一个工程完整性的依据永远是.py源文件和数据集文件而不是.pyc。同理mnist.pkl也不是必须的文件它只是预处理数据的快照删掉后mnist.py会自动重建。但要注意删pkl之后第一次运行会重新解析全部IDX数据耗时几十秒这是预期行为。6. 最后一步走查用验证集精度和可视化确认模型真的学到了训练完模型很多人看一眼loss下降了就觉得大功告成其实还差一步验证模型在没见过的测试集上到底表现如何。MNIST的测试集正好用来做这件事。先写一段最朴素的验证代码acc_cnt 0 for i in range(len(x_test)): y net.predict(x_test[i:i1]) if np.argmax(y, axis1)[0] np.argmax(t_test[i:i1], axis1)[0]: acc_cnt 1 print(ftest acc {acc_cnt / len(x_test):.4f})逻辑很简单把测试集每张图逐张送进网络的predict方法得到10个类别的得分argmax取最大得分对应的数字和真实标签比较。注意预测时只取一个样本x_test[i:i1]而不是x_test[i]因为全连接层通常期望二维输入(1, 784)。用mini-batch的方式一次多取几百张也可以效果一样速度更快。对MNIST来说把简单CNN跑出97%以上的测试准确率是比较正常的低于95%就要怀疑数据预处理或者训练循环写错了。我还有一个固定的检查步骤比看准确率更早能暴露问题冒烟测试。就是只取一个batch比如100张图先跑一个epoch看loss有没有从约2.310分类随机猜测的交叉熵往下降。如果loss在降说明网络、数据、梯度整套链路是通的如果loss原地不动或者直接nan就别浪费时间跑全量训练先回头查数据形状、归一化、softmax这几处。如果把可视化也补上验证会更直观随机从测试集取10张图预测出数字用matplotlib画成一行图像旁边标注真实值和预测值一眼就能看出模型错在哪类数字上。这个操作不复杂但对课程设计答辩非常加分。训练一小时发现数据加载错了那种挫败感我经历过不止一次。从那以后我每次训练新模型都强制先跑完单batch冒烟测试再放开全量确认loss确实在动才开始调参数加结构。这套习惯帮我避开了很多数据预处理的黑匣子。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

CTF红包题MISC实战:文件隐写、伪加密与编码链层层拆解 2026/10/2 3:07:02

CTF红包题MISC实战:文件隐写、伪加密与编码链层层拆解

“红包题”这个词,常逛技术社区的朋友应该不陌生。像吾爱破解论坛这类性质的技术交流平台,隔一段时间就会组织一次趣味小活动,用几道CTF风格的题目充当闯关环节,参与者解出题目里藏着的答案,就能领到一份小彩蛋。题目本…

阅读更多 →
两阶段鲁棒优化在微电网经济调度中的应用与CCG求解 2026/10/2 3:06:49

两阶段鲁棒优化在微电网经济调度中的应用与CCG求解

1. 微电网经济调度到底在解决什么问题做微电网调度的人,几乎都绕不开同一个痛点:光伏和风电的出力今天看着很准,明天就可能偏差百分之二三十,负荷曲线更是难伺候。你要是按确定性模型设计好一天的调度计划,实际运行的时…

阅读更多 →
微电网两阶段鲁棒优化经济调度:原理与CCG算法实践 2026/10/2 3:06:49

微电网两阶段鲁棒优化经济调度:原理与CCG算法实践

1. 微电网经济调度难在哪:不确定性才是真正的对手做过微电网调度的人都有同感:最难缠的不是机组约束、不是潮流计算,而是“明天到底来多少光、刮多大风、负荷涨多少”这种谁都说不好事。传统做法是把光伏出力、负荷当成一组确定数值塞进模型&…

阅读更多 →
Spring Boot集成Druid连接池:配置、监控与踩坑实战 2026/10/2 3:06:49

Spring Boot集成Druid连接池:配置、监控与踩坑实战

1. 从连接池到Druid:为什么要在Spring Boot里选它先亮个结论:如果你在Spring Boot项目里用JDBC、MyBatis或者JPA,连接池基本是绕不开的一环。而Druid在国内Java圈子里属于“老牌且能打”的选手,配合druid-spring-boot-starter这种…

阅读更多 →
LiteLLM生产部署实战:用统一API网关管理多模型接入 2026/10/2 3:06:49

LiteLLM生产部署实战:用统一API网关管理多模型接入

手头同时接了OpenAI、DeepSeek、本地Ollama,还有个用vLLM拉起来的开源模型,第一反应是很爽,第二反应就是头大:每家API格式不一样、鉴权方式不一样、限流策略也不一样,前端同事催着要上线,总不能每个模型都写…

阅读更多 →
Altium Designer画板全流程:原理图页+PCB板框+跨域协同 2026/10/2 3:06:49

Altium Designer画板全流程:原理图页+PCB板框+跨域协同

1. AD画板流程和快捷键:一个十年PCB工程师的日常操作手册Altium Designer(AD)里的“画板”,不是美术课上的水彩纸,而是工程师每天打交道的原理图页(Schematic Sheet)和PCB板框(Board…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉