AI入门:从零开始实现手写数字识别(1)
AI入门从零开始实现手写数字识别1前言技术要求声明机器学习Machine Learning简介机器学习的类型机器学习的基本流程KNN算法模型简介基本工作流程算法的优缺点补充基于KNN算法实现手写数字识别数据准备数据预处理与模型训练预测数据PCA降维与超参数优化问题与总结前言AI大模型已经渗透到我们生活的方方面面。就业市场上AI大模型开发工程师是各家企业争抢的人才。很多人想学却不知从何下手。一看到那堆术语就懵了——ML、DL、LLM、Agent、MCP、RAG……完全不知道该从哪开始。从今天起我打算开一个系列。我们从机器学习ML入手由易到难实现手写数字识别。最后搭一个交互式网站把不同算法的效果做可视化。技术要求开始之前需要具备以下基础编程语言基础具备基本的 python 语法基础。数学基础了解微积分线性代数概率论中的基本概念。AI辅助编程后期网站开发将使用 Code Agent 辅助项目开发。声明这个系列主要是记录个人学习过程。写下来是为了厘清思路顺便加深理解。内容来源包括但不限于网络搜索、AI 生成、视频学习、各大论坛等。如果发现内容有误恳请大佬在评论区指正我会及时修改。学习中有疑问也欢迎私信或评论区讨论。我们正式开始学习吧。机器学习Machine Learning简介机器学习Machine Learning简称 ML是人工智能AI的一个核心分支。简单来说它是一门让计算机从数据中自动学习规律并利用这些规律对未知数据进行预测或决策的科学而无需人类为它编写明确的、死板的规则代码。机器学习的类型根据训练数据和学习目标的不同机器学习主要分为以下三种类型监督学习 (Supervised Learning)定义监督学习是指使用带标签的数据进行训练模型通过学习输入数据与标签之间的关系来做出预测或分类。常见应用分类预测离散的类别识别猫狗图片、判断邮件是否为垃圾邮件、疾病诊断、回归预测连续的数值预测房价、预测明天的气温。常用算法线性回归、逻辑回归、决策树、随机森林、支持向量机SVM。无监督学习 (Unsupervised Learning)定义无监督学习使用没有标签的数据模型试图在数据中发现潜在的结构或模式。常见应用聚类将相似的数据分到同一组如用户画像分群、异常检测、降维在保留核心信息的前提下减少数据的维度便于可视化或计算如PCA 主成分分析。常用算法K-Means聚类、层次聚类、DBSCAN。强化学习 (Reinforcement Learning)定义强化学习通过与环境互动智能体在试错中学习最佳策略以最大化长期回报。每次行动后系统会收到奖励或惩罚来指导行为的改进。常见应用自动驾驶游戏AI。机器学习的基本流程数据收集数据是机器学习的燃料获取数据是机器学习必备的第一步。数据预处理对数据集中的缺失值异常值等脏数据进行清洗填补。并选择有助于模型学习的最相关特征。良好的数据决定模型效果的上限。模型选择与训练根据需求以及数据选择合适的机器学习模型模型通过优化算法如梯度下降等最小化损失函数拟合数据规律。模型评估使用测试集数据来检验模型的准确率召回率等指标。模型部署将训练完成的模型部署到实际应用中。KNN算法模型简介K 近邻算法K-Nearest Neighbors简称 KNN是机器学习中最基础和直观的算法之一可以用于分类或者回归。K 近邻算法属于监督学习的一种核心思想是通过计算待分类样本与训练集中各个样本的距离找到距离最近的K 个样本然后根据这 K 个样本的类别或值来预测待分类样本的类别或值。简单来说就是“物以类聚”。基本工作流程数据收集与其他机器学习算法一致数据收集是必备的第一步。数据预处理 在 KNN 算法中对数据进行归一化进行处理是非常重要的因为 KNN 算法的核心是计算距离如果某一特征的量级远大于其他特征会导致该特征对结果的影响非常显著因此在模型训练前需要对数据进行归一化处理确保每个特征对距离的贡献是相同的。模型训练KNN 是一种惰性学习的算法没有显式的训练阶段实际的训练只是把训练集的数据存起来真正的计算发生在预测阶段。预测在预测过程中模型会计算输入的样本与训练集中每一个样本之间的距离这里的距离有多种计算方式将所有计算出的距离进行升序排序再从中选取前 K 个样本进行决策根据分类还是回归有不同的决策方式。算法的优缺点优点简单直观KNN 算法原理简单符合直觉易于理解。无需训练KNN 是一种惰性学习的算法没有显式的训练阶段。对数据分布无要求KNN 不对数据的分布做任何假设适用于各种类型的数据。缺点预测速度慢KNN 算法每预测一个新样本都需要和训练集中的全部样本都计算一次距离计算复杂度高。对样本不平衡敏感如果某个类别的样本数量特别多它在 K 个邻居中占多数的概率就大容易主导预测结果。维度灾难当特征维度非常高比如几千维时所有样本之间的距离都会变得差不多导致 KNN 失效。补充距离判断两个样本到底有多近需要计算两个样本之间的距离常用的距离有欧氏距离 (Euclidean Distance)最常用即两点之间的直线距离。在二维平面上可以使用勾股定理进行计算并由此可以推广到高维空间。曼哈顿距离 (Manhattan Distance)街区距离就像在曼哈顿街道开车只能沿着网格线走绝对值距离之和。在二维平面上表示为两点之间横坐标差值的绝对值加上纵坐标差值的绝对值。2.决策方式根据分类任务还是回归任务选择不同的决策方式如果是分类任务采用多数表决原则。这 K 个邻居中哪个类别最多新样本就归为哪一类。如果是回归任务采用平均值原则。将这 K 个邻居的目标数值求平均作为新样本的预测值。基于KNN算法实现手写数字识别数据准备本项目数据集选用MNIST数据集该数据集于 1998 年由 Yann LeCun 等人发布可以说是机器学习领域中的Hello World。数据集中包括 70000 张 28 × 28 像素 (单通道灰度图像素值范围为0 - 2550 表示纯黑255 表示纯白)的图像可以分为 60000 张训练集与 10000 张测试集。首先获取数据集并保存到本地。fromsklearn.datasetsimportfetch_openmlfromsklearn.model_selectionimporttrain_test_splitfromsklearn.neighborsimportKNeighborsClassifierfromsklearn.metricsimportaccuracy_scoreimportjoblibimportpandasaspdimportnumpyasnpimportmatplotlib.pyplotasplt# 获取数据使用sklearn提供的fetch_openml方法# 下载 MNIST 数据集# (784个特征代表28x28的像素version1表示数据集版本号as_frameFalse表示返回的是NumPy数组)mnistfetch_openml(mnist_784,version1,as_frameFalse,parserauto)# 提取特征集与标签集X,ymnist.data,mnist.target# X 形状为 (70000, 784)y 形状为 (70000,)# 保存为 NumPy 的 .npz 格式是速度最快、体积最小的选择。它可以将 X 和 y 打包压缩进一个文件中。np.savez_compressed(mnist.npz,XX,yy)可以查看数据集中的前十张照片。fig,axesplt.subplots(2,5,figsize(10,5))fig.suptitle(MNIST数据集的前十张示例图片,fontsize16)fori,axinenumerate(axes.flat):# 将第i张图片X[i]reshape成28×28的矩阵imageX[i].reshape(28,28)ax.imshow(image,cmapgray)# 将图片对应的标签显示为标题ax.set_title(y[i])ax.axis(off)# 隐藏坐标轴# 绘制图片plt.tight_layout()plt.show()运行结果如下数据预处理与模型训练因为MNIST数据集的特征处理较为简单所以数据处理与模型训练合并在一起。# 定义训练并保存模型函数deftrain_model(x_data,y_target):# 数据归一化因为数据范围在0-255之内只需要归一化到0-1之间与数据的分布无关因此可以直接对整个数据集进行归一化x_datax_data/255.0# 切分训练集与测试集X_train,X_test,y_train,y_testtrain_test_split(x_data,y_target,test_size10000,train_size60000,random_state6,stratifyy_target)# 创建KNN分类器knn_estimatorKNeighborsClassifier(n_neighbors5)# 训练模型knn_estimator.fit(X_train,y_train)# 评估模型print(准确度: ,knn_estimator.score(X_test,y_test))# 保存模型joblib.dump(knn_estimator,./my_model/knn_model.pkl)print(训练完成模型已经保存)# 读取数据并训练datanp.load(mnist.npz,allow_pickleTrue)Xdata[X]ydata[y]train_model(X,y)运行结果如下准确度: 0.9725 训练完成模型已经保存预测数据使用已经训练好的模型对图片进行预测# 预测数据defpredict_data(path):# 读取模型knn_estimatorjoblib.load(./my_model/knn_model.pkl)# 读取图片imgplt.imread(path)# 显示图片plt.imshow(img,cmapgray)plt.axis(off)plt.show()# 预测图片ximg.reshape(1,-1)#如果图片格式为PNG则返回0-1之间的数值如果图片格式为其他格式则返回0-255之间的数值需要归一化。predknn_estimator.predict(x)returnpredprint(预测结果为,predict_data(./KNN_MNIST_TEST/demo.png))运行结果如下预测结果为 [2]PCA降维与超参数优化看到这里大家肯定会有疑问什么是PCA什么是超参数优化PCAPCAPrincipal Component Analysis主成分分析是统计学和机器学习中最常用的降维算法可以用于解决KNN的维度灾难以及计算开销问题。PCA 通过正交变换将原始高维数据投影到方差最大的少数主成分上实现降维的同时保留数据最主要的变异信息。简单来说PCA 就是通过某种算法把原始数据中众多相关指标浓缩成少数几个互不相干的核心指标在牺牲少量精度的前提下大幅降低数据复杂度。以MNIST数据集为例MNIST每张图像有28×28784维若训练集有60000个样本每次预测都要计算60000次784维向量的距离非常耗时。并且通过前面的实操大家可以观察到MNIST图像有很多像素的数据是重复且多余的比如图片的边缘部分有大量的黑色像素这些黑色像素并没有提供与数字预测相关的信息。超参数优化首先说明一下什么是超参数在机器学习中参数可以分为两类模型参数Parameters 和超参数Hyperparameters。模型参数是模型内部通过训练数据自动学习到的变量例如线性回归的权重。而超参数是在模型训练开始前人为设定的外部参数例如 KNN算法里的K值。超参数优化Hyperparameter Tuning 的目的就是寻找一组最佳的超参数组合使得模型在测试集上表现良好从而避免过拟合或欠拟合。寻找最佳超参数的标准方法是结合 交叉验证Cross-Validation 和 网格搜索Grid Search。交叉验证将训练集分成 N 份如 5 折轮流用 4 份训练1 份验证取平均成绩。这能有效防止模型在特定的验证集上过拟合。网格搜索预先设定好各个超参数的候选值列表算法会尝试每个超参数并通过交叉验证找出得分最高的那一组。由于相关内容较多我会单独写一个帖子来实现。问题与总结在本项目测试过程中最开始我使用了自己在ps中绘制的数字图片但是预测效果非常差我使用cursor进行问题排查cursor得出的结论如下MNIST 测试集上的高准确率并不代表模型在任意手写图片上都能有同样表现。测试集与训练集同源、分布一致而自定义 PNG 在写法风格、笔画粗细和数字位置上与 MNIST 存在明显偏差其中最关键的一点是MNIST 数字已做居中处理若预测时仅将图片 reshape 后直接输入像素位置偏移会显著拉大与训练样本的距离。KNN 依赖像素级欧氏距离找最近邻对位置和分布变化极为敏感不学习抽象特征因此在“分布外”数据上容易失效。因此高测试准确率更多反映模型在标准数据集上的拟合效果真实预测效果还取决于输入与训练数据的一致性以及 KNN 算法本身的局限。因此使用 KNN 算法本身并不是很适合用于实现通用的手写数字识别本项目仅仅是作为机器学习入门帮助大家熟悉机器学习的步骤掌握数据的处理了解 KNN 算法的原理以及实现过程。欢迎大家在评论区交流学习心得也欢迎大佬指出文章中的错误。下一篇我会分享决策树算法并基于该算法实现手写数字识别。