手写数字识别系统实战:从KNN基线到CNN模型部署

发布时间:2026/10/1 19:47:14

手写数字识别系统实战:从KNN基线到CNN模型部署 简介基于Python与神经网络的手写数字识别系统是面向计算机、电子信息等专业毕业设计或课程设计场景的高分项目资源。项目利用MNIST数据集训练深度神经网络模型实现对0-9手写数字的自动识别与预测完整覆盖数据预处理、模型搭建、训练评估与推理演示等关键环节适合需要从零掌握神经网络图像分类原理、快速搭建可演示识别系统的开发者参考。压缩包共包含18个文件整体大小约11.11MB。除model.py、demo.py、登录注册代码实现.py等Python源码外还提供RAR格式压缩的MNIST训练与测试数据集、需求分析规格说明书与登录模块测试用例docx文档、SQL登录注册界面脚本以及requirements.txt、README等环境说明文件涵盖项目开发所需的代码、数据、文档与配置方便直接复现和二次开发。目前已有96人学习下载。依托这套资料读者可以对照源码理解神经网络在数字识别中的实际应用也能借助需求分析和测试文档完善自己的毕设材料还可通过自带登录模块扩展为完整系统用于毕设答辩或课程项目展示。1. 数字识别系统毕设选题里性价比最高的那个方向答辩前一周导师问了一句“你的系统能不能识别我随手写出来的数字”这个问题其实是整个基于Python的数字识别系统最核心的验收标准——模型在公开数据集上的准确率再漂亮也得接得住真实输入还得能做成一个能演示、能交互的成品。数字识别本质上是图像分类任务输入一张 28×28 的灰度图输出 09 的类别标签常见的技术路线是 PyTorch 或 scikit-learn 训练 MNIST 数据集再配上 GUI 画板或 OpenCV 预处理。它适合做毕设的理由很直接数据公开、模型规模适中、效果能量化而且天然留好了“交互界面”这个加分位。新手能顺着 MNIST 跑通全流程熟手可以在模型结构和部署形态上继续做深后文按我自己的实操顺序展开。2. 环境与数据集准备把 Python、PyTorch 和 MNIST 一次装到位这一章解决的是“代码没写一行先被环境卡死”的常见开局。很多同学第一次跑数字识别项目不是死在模型上而是死在 Python 解释器选错、torch 装不上、数据集下载失败这些环节。把这些前置工作理顺后面所有代码才能跑得动。2.1 Python 环境conda 虚拟环境与 VSCode 解释器选择如果是从零开始先装 Python 本身。Windows 下从 python 官网下载安装包时务必勾选“Add Python to PATH”否则后续命令行里敲python会提示找不到命令。装完在终端里输入python --version验证版本3.9 或 3.10 都可以不建议直接用 3.13 这类过新版本部分库的预编译包可能还没跟上。我一般会用 conda 建一个独立环境避免把系统 Python 搞乱conda create -n digit_rec python3.10 -y conda activate digit_rec pip install torch torchvision scikit-learn matplotlib opencv-python参数说明-n digit_rec指定环境名python3.10指定环境内的解释器版本-y跳过确认提示。pip install后面的包按用途分torch和torchvision负责模型训练与数据集加载scikit-learn提供 KNN 这类传统分类器matplotlib用来画训练曲线和数据预览opencv-python给后续真实手写数字预处理用。CPU 版 PyTorch 对 MNIST 这种 28×28 小图完全够用没必要为一万张测试图去折腾 GPU 环境。提示如果你用的是 VSCode装完后按CtrlShiftP输入 “Python: Select Interpreter”选digit_rec环境。这一步漏了后面import torch会报 ModuleNotFoundError这是环境问题里最常见的翻车点不是代码问题。2.2 获取 MNIST 数据torchvision 一行代码加载数字识别最常用的公开数据集是 MNIST包含 60000 张训练图和 10000 张测试图。torchvision 把它封装成了一行调用不需要自己写下载脚本from torchvision import datasets, transforms transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_set datasets.MNIST(root./data, trainTrue, downloadTrue, transformtransform) test_set datasets.MNIST(root./data, trainFalse, downloadTrue, transformtransform)这里Compose把两个预处理操作串起来ToTensor()把 PIL 图像转成张量并把像素值从 0255 缩放到 01Normalize用 MNIST 全量数据的均值 0.1307 和标准差 0.3081 做标准化。标准化不是可选项后面 CNN 训练时梯度更新会更平稳。root./data表示数据集存到当前目录下的 data 文件夹trainTrue/False区分训练集和测试集第一次运行downloadTrue会自动下载下载完再跑可以把download改为False避免每次启动都检查网络。下载完成后./data/MNIST/raw下会有四个.gz文件./data/MNIST/processed下是 torchvision 预处理好的缓存。验证一下形状print(train_set.data.shape) # torch.Size([60000, 28, 28]) print(test_set.data.shape) # torch.Size([10000, 28, 28]) print(train_set.targets.shape) # torch.Size([60000])2.3 数据预览训练前先看一遍图很多同学拿到数据集直接开训最后自己手写数字识别不准回头才发现训练集里根本没有“黑字白底”或者“倾斜笔画”的样本。训练前花一分钟把数据画出来能省掉后面大量无效调试import matplotlib.pyplot as plt fig, axes plt.subplots(1, 10, figsize(12, 3)) for i in range(10): idx (train_set.targets i).nonzero()[0][0] axes[i].imshow(train_set.data[idx], cmapgray) axes[i].set_title(flabel:{i}) axes[i].axis(off) plt.show()这段代码对每个数字类别取第一张样本画出来确认图是白字黑底、数字基本居中。MNIST 本身做过尺寸归一化但真实场景里自己手写的数字大小、位置、笔画粗细都不同这就是为什么后面必须加预处理步骤。数据这一关过了环境问题基本就清零了。3. 先用 KNN 跑通基线拿到第一个可答辩的准确率模型选型上我不建议一上来就写 CNN。先跑一个传统机器学习基线是数字识别项目里最容易被低估但收益极高的一步它给你一个参照系也能在答辩时讲清楚“为什么需要深度学习”。3.1 为什么要先做 KNN传统分类器的价值K 近邻KNN的思路很直白把 28×28 的图像拉平成 784 维向量测试样本和训练样本算欧氏距离取最近的 K 个邻居投票决定类别。它没有训练过程不需要调学习率也不会遇到梯度消失。MNIST 上 KNN 在完整训练集上能达到 96%97% 的准确率这个数字意味着一个刚接触机器学习的人用不到 50 行代码就能拿到一个能用的识别系统。这个基线的意义在于对照如果后面 CNN 准确率只有 95%那说明模型有问题而不是数据有问题如果 CNN 到了 99%你可以用 KNN 的 96.5% 做衬托解释卷积为什么更强。答辩时这类对比非常加分它证明你不是只会调包。3.2 用 scikit-learn 跑通 KNN 最小实现import numpy as np from sklearn.neighbors import KNeighborsClassifier train_images train_set.data.numpy().reshape(-1, 28 * 28) / 255.0 test_images test_set.data.numpy().reshape(-1, 28 * 28) / 255.0 train_labels train_set.targets.numpy() knn KNeighborsClassifier(n_neighbors3, weightsdistance, n_jobs-1) knn.fit(train_images[:20000], train_labels[:20000]) pred knn.predict(test_images[:2000]) acc (pred test_set.targets.numpy()[:2000]).mean() print(fKNN accuracy on 2000 test samples: {acc:.4f})reshape(-1, 28 * 28)把每张二维图展平成 784 维向量-1表示自动推断样本数除以 255 把像素值压到 01避免距离计算时像素值差异被放大。n_neighbors3是投票邻居数weightsdistance让距离近的样本投票权重更高n_jobs-1表示用满 CPU 多核加速。我故意只取 20000 张训练图和 2000 张测试图是因为 KNN 的预测阶段要实时计算距离样本量太大时内存和时间开销都容易失控这点在第 5 章会展开讲。先在小规模上验证代码通顺再根据机器配置逐步加样本。3.3 调参方向K 值与距离权重的选择K 值直接决定模型的偏置和方差。K1 时决策边界最细碎容易过拟合K 太大时会把相距很远的样本也拉进来投票边界过于平滑欠拟合。weights选uniform还是distance也会影响结果——用distance时离测试样本更近的训练样本话语权更大在有噪声的数据集上通常更稳。可以用网格搜索快速找一组好参数from sklearn.model_selection import GridSearchCV param_grid { n_neighbors: [1, 3, 5, 7], weights: [uniform, distance] } grid GridSearchCV(KNeighborsClassifier(), param_grid, cv3) grid.fit(train_images[:10000], train_labels[:10000]) print(grid.best_params_)在 MNIST 这类数据上n_neighbors3搭配weightsdistance通常是个稳妥的起点。跑完这步你已经有一个能工作的数字识别模型了。但别急着优化 KNN它的天花板摆在那里接下来的重头戏是 CNN这才是数字识别系统真正拉开分数差距的地方。4. 用 PyTorch 写 CNN 模型从 LeNet-5 出发训练与验证全流程KNN 只能停在 97% 附近因为全连接的距离度量很难捕捉笔画局部的结构特征。CNN 通过卷积核在图像上滑动把边缘、端点、弧线这些局部模式逐层组合成高阶特征这也是图像分类任务的主流做法。4.1 网络结构选型为什么 LeNet-5 的后续版本依然能打数字识别任务输入只有 28×28 单通道灰度图类别只有 10 个不需要 ResNet 这种百层模型。经典的 LeNet-5 结构经过小幅改动后在这个任务上就能跑到 99% 左右训练时间在 CPU 上也就几分钟。我常用的结构如下本质是“卷积 池化 × 2再接全连接”层输出尺寸参数数量作用Conv2d(1, 32, 3, padding1)28×28×32320提取低层边缘特征ReLU MaxPool2d(2)14×14×320下采样保留主要响应Conv2d(32, 64, 3, padding1)14×14×6418496组合形成局部纹理特征ReLU MaxPool2d(2)7×7×640进一步压缩空间维度Linear(64×7×7, 128)128401024全连接做高阶组合Linear(128, 10)101290输出 10 个类别的得分第一层卷积用 3×3 卷积核加 padding1保证输出尺寸仍为 28×28这样空间信息不会被卷积核迅速削掉。池化用 2×2 最大池化每经过一次尺寸减半28→14→7最后全连接层的输入维度是 64×7×7。4.2 定义模型PyTorch 代码与维度推导import torch import torch.nn as nn class DigitCNN(nn.Module): def __init__(self): super().__init__() self.features nn.Sequential( nn.Conv2d(1, 32, kernel_size3, padding1), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, kernel_size3, padding1), nn.ReLU(), nn.MaxPool2d(2) ) self.classifier nn.Sequential( nn.Flatten(), nn.Linear(64 * 7 * 7, 128), nn.ReLU(), nn.Linear(128, 10) ) def forward(self, x): return self.classifier(self.features(x))features里两个卷积层分别输出 32 通道和 64 通道的特征图池化后空间尺寸从 28 变成 7。Flatten()把三维特征图拉平成 64×7×73136 维向量Linear(3136, 128)负责把局部特征组合成全局表示最后一层Linear(128, 10)输出每个类别的原始得分。整个过程不做 Softmax因为后面CrossEntropyLoss内部已经包含了 Softmax 计算提前做反而会带来数值不稳定性。4.3 数据加载与训练循环核心超参数怎么设数据加载用 DataLoader 分批次喂给模型from torch.utils.data import DataLoader train_loader DataLoader(train_set, batch_size64, shuffleTrue) test_loader DataLoader(test_set, batch_size256, shuffleFalse)batch_size64表示每轮迭代处理 64 张图这是 MNIST 上稳定且训练速度合理的常见取值shuffleTrue打乱训练顺序避免模型学到样本顺序的假规律测试集不需要打乱shuffleFalse即可。训练阶段的核心代码device torch.device(cuda if torch.cuda.is_available() else cpu) model DigitCNN().to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr0.001) for epoch in range(10): model.train() running_loss 0.0 for images, labels in train_loader: images, labels images.to(device), labels.to(device) optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() print(fEpoch {epoch 1}, loss: {running_loss / len(train_loader):.4f})关键在三个调用optimizer.zero_grad()清空上一轮的梯度loss.backward()反向传播计算梯度optimizer.step()用梯度更新权重。这三个顺序反了或漏了训练要么不收敛要么参数原地不动。优化器选 Adam 而不是 SGD因为 Adam 自带学习率自适应lr0.001是它的默认建议值基本不需要额外调整。epoch 设为 10 轮每轮训练完后 loss 应该持续下降如果 loss 在第 5 轮后不降反升通常不是模型问题而是学习率过大把lr降到 0.0005 再试。4.4 测试集评估准确率到底有多少训练完必须在没参与训练的测试集上验证才有说服力model.eval() correct, total 0, 0 with torch.no_grad(): for images, labels in test_loader: images, labels images.to(device), labels.to(device) outputs model(images) preds outputs.argmax(dim1) correct (preds labels).sum().item() total labels.size(0) print(fTest accuracy: {correct / total:.4f})model.eval()切换模型到评估模式它会关闭 Dropout 等训练专用行为——这个调用漏掉是测试准确率玄学波动的最常见原因之一。torch.no_grad()告诉 PyTorch 关闭梯度记录推理阶段不需要梯度能省内存、提速。argmax(dim1)取模型输出得分最高的类别作为预测结果(preds labels).sum().item()统计预测正确的数量。按这组超参数训练测试准确率通常在 98.5%99.2% 区间。如果没到这个范围优先检查数据预处理是否漏了标准化以及model.eval()是否忘写。这个版本的 CNN 已经是能拿去答辩的水平但距离“高分毕设”还差最后一步——让它能识别真实手写数字而不只是 MNIST 压平的数组。5. 常见问题与避坑数字识别开发里最容易翻车的 5 个环节从环境到模型再到真实场景这一路踩过的坑比任何教程都有参考价值。我按现象、原因、解决的顺序梳理了下面几个高频问题基本覆盖绝大多数数字识别项目的报错现场。5.1 MNIST 下载失败或卡在 Downloading 不动现象第一次运行datasets.MNIST(downloadTrue)进度条长时间不走或直接报连接超时。原因MNIST 原始数据托管在国外服务器国内网络环境下直连经常不稳定或超时。解决最快的路是手动下载四个.gz原始文件——train-images-idx3-ubyte.gz、train-labels-idx1-ubyte.gz、t10k-images-idx3-ubyte.gz、t10k-labels-idx1-ubyte.gz放到./data/MNIST/raw/目录下然后把download参数改成False。torchvision 检测到 raw 目录下文件齐全就不会再触发下载。这个坑几乎每个跑 MNIST 的人都遇到过提前把文件备好后面就一劳永逸。5.2 像素没有正确归一化loss 不降或降得极慢现象模型训练几十轮准确率还在 90% 附近晃loss 曲线下不去。原因图像像素值如果没有被ToTensor()缩放到 01或者只做了缩放但没做标准化数值范围过大会让梯度更新不稳定。 解决检查 transform 里Normalize((0.1307,), (0.3081,))是否生效。如果只是import torchvision.datasets后没传 transform拿到的是 0255 的原始像素务必加上前面的Compose配置。训练前用一行确认数据范围print(train_set.data[0].float().min().item(), train_set.data[0].float().max().item())最小值应为 0、最大值应为 1否则就是预处理没接上。5.3 测试准确率忽高忽低Dropout 一直在干扰现象同一个模型连续跑两次测试准确率相差 23 个百分点很不稳定。原因模型定义里如果用了 Dropout训练结束后未切换到model.eval()Dropout 在推理阶段仍然随机屏蔽神经元导致每次输出不同。 解决推理前显式调用model.eval()并记住训练时用model.train()切回来。这个问题的隐蔽之处在于 pytorch 官方示例里通常会写但自己写代码时一紧张就漏了。配套检查手段是在测试阶段打印model.training输出 True 说明还在训练模式。5.4 自己手写的数字识别不准预处理是最大变量现象MNIST 测试准确率 99%但打开画板用鼠标写一个“7”模型识别成“2”。原因MNIST 的样本是白字黑底、数字居中、大小占满画面而且笔画粗细相对统一鼠标写的数字可能是黑字白底、位置偏移、笔画极细或断断续续。这是典型的数据分布不一致问题不是模型本身坏了。 解决写一个统一的预处理函数把任意输入转成 MNIST 风格import cv2 import numpy as np def preprocess_digit(img): gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, th cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV) contours, _ cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) x, y, w, h cv2.boundingRect(contours[0]) digit th[y:y h, x:x w] digit cv2.resize(digit, (20, 20), interpolationcv2.INTER_AREA) canvas np.zeros((28, 28), dtypenp.uint8) canvas[4:24, 4:24] digit return canvasTHRESH_BINARY_INV做二值化并把前景变白适配 MNIST 白字黑底findContours找到数字所在的最小外接矩形resize缩放到 20×20 再贴到 28×28 中心位置留出 4 像素边距。这样处理后的输入和 MNIST 训练样本的分布基本一致识别率会立刻恢复正常。很多人不写这步直接用原图喂模型效果差是必然的。5.5 KNN 预测时内存飙升或卡死现象用完整 60000 张训练集拟合 KNN然后直接predict全部 10000 张测试图进程卡死或内存被吃满。原因KNN 的预测阶段要计算测试样本与所有训练样本的距离6 万×1 万的浮点距离矩阵会占用大量内存和 CPU 时间。 解决减少训练样本量或者分批预测pred_chunks [] for i in range(0, len(test_images), 2000): pred_chunks.extend(knn.predict(test_images[i:i 2000]))每批预测 2000 张逐一拼结果内存占用会明显下降。这个坑也提醒一点KNN 在 MNIST 上只能当基线真要上线识别系统还得靠 CNN。6. 模型保存、GUI 落地与答辩演示把准确率变成能看见的东西模型在测试集上跑到 99%实时画板却识别不出来等于白做。最后一步是把训练好的 CNN 变成一个能打开就用的系统同时准备一套能打动评委的演示流程。先保存模型权重别每次都重新训练torch.save(model.state_dict(), digit_cnn.pt)推理时加载权重注意map_locationcpu是为了避免 GPU 上训练、CPU 上加载时出现设备不匹配model DigitCNN() model.load_state_dict(torch.load(digit_cnn.pt, map_locationcpu)) model.eval()GUI 层面Tkinter 是 Python 自带库不需要额外安装用 Canvas 组件做一个可鼠标绘制的画板是最快的方案。关键交互是鼠标按下时画线抬起后把 Canvas 内容转成图片调用preprocess_digit处理再喂给模型。Canvas 的坐标范围通常是 200×200转成 28×28 前需要先缩放注意保持数字长宽比否则会变形。对鼠标写的数字预处理脚本比模型本身更值得反复调这是真实的血泪经验。答辩演示我建议准备三个场景按顺序展示用 GUI 画板写一个数字立刻识别用手机或白板笔写一个数字拍照喂进去对比同一张图在 KNN 和 CNN 下的识别结果与置信度。这个顺序能自然带出项目的完整链路——数据、预处理、传统基线、深度模型、交互系统。一个容易被忽略的加分项是置信度展示model(images)的输出经过softmax后取最大值能说明模型是“确定地识别”还是“蒙对的”这个细节在答辩里很显专业。我现在接到识别类任务仍然习惯先跑一版 KNN 摸清数据底细再写 CNN 出正式结果最后才做交互层。这个顺序帮我省掉过无数次返工也让我在答辩时能把每个模块为什么存在讲得很笃定。按这条路径把最后一步做完祝你能把 99% 的准确率真正握在手里希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/1 19:42:14

东南大学编译课设:LLVM前端实践闭环与错误恢复实现

简介:本资源是东南大学网络安全学院《编译方法》课程的配套实践包,面向计算机专业本科生及编译原理初学者,聚焦词法分析、语法解析、语义处理与代码生成等核心环节的动手实现。资源共260个文件,以55份Markdown实验文档为学习主线&…

2026/10/1 19:42:14

OpenClaw云端部署实战:腾讯云Lighthouse从零搭建AI助手

1. 为什么要把 OpenClaw 搬到云端而不是留在本机很多人第一次接触 OpenClaw,都是在自己电脑上跑起来的。下载 Node.js、克隆仓库、装依赖、配模型,折腾一两个小时,看到终端里跳出对话界面,那种成就感确实不错。但用不了几天&#…

2026/10/1 19:42:14

EasyExcel导出合计行的正确实现方案

1. 为什么“合计行”是 EasyExcel 导出中最容易被低估的硬伤你有没有遇到过这样的场景:业务方发来一份 Excel 模板,最后一行写着“合计”,字体加粗、背景色浅灰、数字右对齐,还带千分位分隔符;你吭哧吭哧用 EasyExcel …

2026/10/2 0:07:57

根域名与www域名301重定向:5种服务器/CDN/代码配置方案

很多站长在建站初期,都会有这样一个疑问:用户访问example.com和www.example.com到底该不该统一?要不要做301重定向?怎么做才最稳妥?这个问题从我做运维第一天起就一直有人问,前前后后帮朋友和自己处理过不下…

2026/10/2 0:07:57

openrig实战:从硬件选型到本地AI推理工作站部署完整指南

把“openrig”这个标题拆开看,open是开源,rig在玩硬件的圈子里通常指一套完整的机器,尤其是那种为了特定任务拼起来的工作站或矿机。放到现在这个语境下,我理解的openrig就是一整套“本地AI推理工作站”的搭建方案:自己…

2026/10/2 0:07:57

MySQL数据类型选型指南:避开索引失效与精度陷阱

“MySQL 数据类型”五个字,看着像基础课里最平平无奇的一节,但我在生产环境翻过太多因为类型选错而埋雷的表了:金额字段用 FLOAT 存,对账对到怀疑人生;status 字段用 VARCHAR(50) 存“0”“1”“2”,索引等…

2026/10/2 0:07:57

彻底搞懂第二类曲线积分与曲面积分:从做功通量到格林高斯公式

第二类曲线积分和第二类曲面积分,大概是高等数学里最容易让人“课后感觉会了,做题全废”的一块。我做助教那几年,每到期末复习,来问问题的学生十个里有八个卡在这一章。不是公式背不下来,而是根本不知道自己在算什么&a…

2026/10/2 0:07:57

CentOS 6.10 换阿里源全攻略:从 yum 卡死到镜像配置实操

前阵子翻出一台快吃灰的 CentOS 6.10 服务器,准备把上面的旧系统数据导出来,结果刚敲下yum install就开始卡在 0%,进度条死活不动,最后直接超时报错。一开始我以为是网络波动,试了几次都一样,后来才反应过来…

2026/10/2 0:02:57

智能家居开源项目怎么找?四大渠道与复刻实操指南

这几年帮不少朋友带路入坑智能家居硬件,被问得最多的一个问题不是“怎么画板子”,也不是“用哪块开发板”,而是“我到底该去哪儿找真正能跑起来的开源项目”。在GitHub上搜“smart home”能出来几十万条结果,但原理图、PCB、固件、…

2026/10/1 5:21:14

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/10/1 17:09:46

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 10:48:55

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/2 0:02:57

PWN入门:从栈溢出原理到ROP链实战

1. 这不是“学PWN”,是重新理解你每天敲的每一行C代码我第一次在CTF赛场上写出能控制程序流的exp时,手抖得连gdb的c命令都输错三次。那道题只有23行C代码,一个gets()调用,一个printf(),一个return——它甚至没开NX&…

2026/10/2 0:02:57

Windows下cudaMallocHost显存占用之谜:WDDM与TCC模式差异及优化方案

1. 一个反直觉的显存占用现象第一次在 Windows 上看到cudaMallocHost把显存吃掉的时候,我的反应是打开任务管理器反复确认了三遍。明明调用的是主机端锁页内存分配,按 CUDA 文档的说法,这块内存应该落在系统 RAM 里,跟 GPU 的显存…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑