机器学习笔记
机器学习概念理解
多种神经网络
神经网络
是一种模仿人脑结构的算法,由很多 “节点”(像神经元)层层连接组成。输入数据后,每个节点会处理信息、传递给下一层,最后输出结果(比如判断一张图是不是猫)。核心就是通过大量数据 “训练”,让这些节点学会找规律
全连接神经网络
每一层的每个节点都和下一层所有节点全连接
理解:最 “实在” 的神经网络,就像握手问题,两个相邻的层的所有节点都会握手(全连接)
缺点:参数太多,容易算得慢,适合处理简单数据(如图像像素少的情况)
CNN卷积神经网络
是处理图像的主流网络架构
不像全连接那样瞎连,它用 “卷积核”(类似滤镜)扫描图像,提取局部特征(比如边缘、颜色块),再层层叠加特征(从线条到眼睛、再到猫的整体)。
优点:能减少参数,还能保留图像的空间关系,
应用:专门对付图像。游戏、自动驾驶里的图像识别
核心层及其功能
- 卷积层:通过卷积核(过滤器)与输入图像进行滑动窗口计算,提取局部特征(如边缘、纹理等)
权值共享:同一卷积核在图像不同位置共享参数,减少计算量
局部连接:每个神经元仅连接输入的局部区域,符合图像局部相关性 - 池化层:对特征图进行下采样,减少参数数量,同时保留主要特征
最大池化:取窗口内最大值,保留显著特征
平均池化:取窗口内平均值,平滑特征 - 激活层:对卷积层输出引入非线性变换(激活函数)
- 批量归一化层:对每层输入进行归一化(标准化均值和方差),加速训练收敛,缓解梯度消失问题
- 全连接层:连接所有特征,将提取的局部特征整合为全局特征,常用于分类任务的最后一层,输出类别概率
- 输出层:根据任务类型输出结果
RNN循环神经网络
它的节点会 “记住” 之前的输入信息,就像读句子会根据前文理解后文。
缺点:传统 RNN 记性不好,长句子后面的信息容易忘,后来进化出LSTM
应用:处理 “有顺序” 的数据(比如句子、股票走势)
处理图片的神经网络模型
VGG16
适合理解基础特征提取
理解:用 “叠叠乐” 提取图片细节,就像用放大镜一层一层看图片,先找边缘线条,再组合成耳朵、眼睛等局部特征,最后拼出完整物体
用很多个 3×3 的小 “窗口”(卷积核)反复扫描图片,每次只关注一小块区域,比如先找直线(边缘),再找曲线(耳朵轮廓),最后认整体(猫的样子)。
网络有 16 层,靠 “堆层数” 让特征提取更细致
缺点:参数多、计算量大,像搬一摞厚厚的书,有点笨重
ResNet
常用在复杂任务里(比如自动驾驶认路标)
理解:给神经网络加 “电梯” ,传统深层网络像爬高楼,层数太多容易 “缺氧”(梯度消失,学不动),ResNet 加了 “电梯”(残差连接)解决这个问题
让信息能跳过中间层直接传递,比如学习第 100 层时,不光学新东西,还能直接拿到第 1 层的 “基础信息”,避免深层学偏。
可以搭非常深的网络(比如 152 层),像用望远镜看远处,既能看清细节又能把握整体,准确率更高。
激活函数
理解:像炒菜时的调料,同样的食材(数字)加不同调料(激活函数),味道(输出)完全不同
作用是为模型引入非线性能力,让网络能学习复杂模式
若没有激活函数,多层神经网络会退化成线性模型,只能拟合线性关系,无法处理图像、语言等复杂非线性问题
Sigmoid:老派温和,输出像概率,但容易 “摸鱼”(梯度消失),计算慢
Sigmoid:适合当二分类的最后一层(输出 0 或 1 的概率),比如垃圾邮件分类
ReLU:直爽暴躁,计算快不消失,但可能 “摆烂”(神经元死亡),现在主流
ReLU:适合藏在中间层提取特征,比如 CNN 里每层卷积后接 ReLU,让网络学出复杂图案(猫狗的耳朵、尾巴)
常见类型——ReLU(修正线性单元)
最常用,公式为 f(x)=max(0, x),x>0 时直接输出 x,x≤0 时输出 0
优点是计算效率高、缓解梯度消失,缺点是神经元可能 “死亡”(输入负数时始终输出 0)
没有复杂运算,只判断 x 是不是正数,效率高
常见类型——Sigmoid
公式:f (x)=1/(1+e^-x),输出永远在 0 到 1 之间,像把数字 “挤” 进窄门
将输入映射到 (0,1) 区间,常用于二分类输出层,但存在梯度消失问题,且输出非零中心化,可能导致训练不稳定
图像:S 型曲线,中间陡两边平
过拟合
- 模型在训练集上正确率超高,但在新数据(测试集)上表现拉垮,因为它记住了训练数据的特殊细节,没抓住普遍规律
- 理解:过拟合就像 “死记硬背” 却没学懂
模型把训练数据里的 “噪音”(无关细节)也当成了规律
比如例题都是 “红苹果”,只死板记住了 “红色 = 苹果”,但遇到绿苹果就认不出了 - 过拟合的本质是模型 “太聪明” 但没 “理解本质”,防止方法都是在让模型 “学精而不是学杂”,平衡 “拟合训练数据” 和 “泛化到新数据” 的能力
- 过拟合的后果:浪费资源,模型没用(无法进行预测)
如何防止过拟合:
- 正则化——简化内容,给模型减负(在损失函数里加 “惩罚项”,让模型参数尽量小)
- Dropout——掐断依赖(训练时随机让一部分神经元不工作,防止模型过度依赖某几个特征)
- 增加训练数据——收集更多数据,或用数据增强(比如图像旋转、翻转)扩充数据集,让模型看到更多例外情况
- 解决关键:激活函数选对、权重初始化合理、加残差或梯度裁剪,让网络 “情绪稳定” 地学习
梯度消失恶化梯度爆炸
神经网络训练时,需要根据误差调整参数(比如权重),而梯度就是告诉参数 “该往哪调、调多少” 的方向标,梯度大,参数更新快(学得猛);梯度小,参数更新慢(学得慢)
梯度消失 “越学越没劲”
深层网络训练时,梯度从最后一层往前传,越传越弱,到前面层时几乎没了,参数几乎不更新,模型 “学不动”
原因:激活函数选得不合适(如 Sigmoid 导数最大值只有 0.25),多层连乘后梯度越乘越小,像滚雪球越滚越小
梯度爆炸 “越学越暴躁”“发疯乱学”
梯度更新时数值变得极大,参数疯狂乱跳,模型输出全是 NaN(无效值),训练崩溃
神经网络中,若权重初始值太大,或多层梯度连乘时数值爆炸(如权重 > 1 时连乘越来越大)
原因:权重初始化不合理,或网络结构太深,梯度连乘时数值呈指数级增长,像利滚利突然欠了一屁股债
解决办法:
梯度消失对策:
换激活函数:用 ReLU(导数在正数区恒为 1,不压缩梯度)
加残差连接(ResNet 的做法):让梯度能 “抄近道” 直接往前传,跳过中间层,避免层层衰减
梯度爆炸对策:
权重初始化选合适方法(如 Xavier、Kaiming 初始化),让初始值别太大。、
梯度裁剪:设置阈值,当梯度超过一定值时强行 “刹车”,比如把梯度限制在 [-10, 10] 之间
梯度消失 / 爆炸在 CNN 和 RNN
CNN 靠多层卷积提取特征,梯度消失 / 爆炸主要来自激活函数选择(如老用 Sigmoid)或网络太深
用 ReLU 激活 + 残差连接(ResNet)就能大幅缓解
RNN 处理序列数据(如句子),信息要按时间步一步步传,梯度消失 / 爆炸来自链式求导连乘。比 CNN 更难搞,因为序列长度不固定,链式求导天然容易出问题
CNN 和 RNN 都可能遇到梯度消失 / 爆炸,但 RNN 更严重(因为序列链式传递);
LSTM 是 RNN 的 “加强版”,用三个 “门” 控制记忆流动,让梯度稳定传递,能记住长序列信息,比如翻译整段话时不忘开头的词
LSTM解决RNN的遗忘(梯度消失)
LSTM 的 “三件套” 设计:
遗忘门:决定 “扔掉哪些旧记忆”,比如读句子时,发现 “昨天” 对理解当前词不重要,就删掉。
输入门:决定 “存哪些新记忆”,比如遇到关键动词 “吃”,就把它存进 “保险箱”。
输出门:决定 “用哪些记忆来输出”,比如回答问题时,只把相关的 “吃饭”“昨天” 信息拿出来。
通过这三个门控机制,LSTM 让梯度能稳定流动,避免消失,能记住长序列的信息
学习率
学习率是机器学习优化过程中的关键参数,它决定了模型参数更新的步长
简单类比:学习率就像走路的步幅 —— 大步走(高学习率)可能走得快但容易错过目标,小步走(低学习率)走得慢但更稳,合适的步幅(学习率)才能高效到达目的地(模型最优解)
增加学习率
让参数更新的步长变大,模型在损失函数的梯度方向上尝试更快地 “迈步” 靠近最优解
优点:可能加速模型收敛,减少训练时间。
缺点:如果学习率过大,容易跳过最优解,导致损失函数震荡甚至发散(模型不收敛,准确率下降)
降低学习率
使参数更新的步长变小,模型以更 “谨慎” 的方式调整参数
优点:有助于模型在接近最优解时更精准地 “微调”,可能找到更优的参数组合,提升最终收敛的稳定性。
缺点:训练速度变慢,若学习率过小,模型可能陷入局部最优解而无法进一步优化,或长时间无法收敛
暂退法Dropout(解决过拟合)
平时神经元们抱团干活,比如 A 负责认猫耳朵,B 负责认猫尾巴,可能 A 记太死 “没耳朵就不是猫”,用 Dropout 后,A 偶尔摸鱼,网络不得不让其他神经元(比如 C)也学会认耳朵,避免过度依赖某几个学霸神经元
目的:防止过拟合,让模型更聪明,遇到新数据能认得
训练是的参数和说明
随机种子
深度学习中有很多随机过程,如权重初始化、数据打乱等。设置固定的随机种子可以确保每次运行代码时这些随机过程的结果相同
随机数生成器通常使用种子值来初始化内部状态,然后根据确定性算法生成一系列看似随机的数字。只要种子值相同,生成的随机数序列就相同。
批次大小
在训练过程中,数据会被分成多个小批次喂给模型。批次大小指定了每个批次包含的样本数量
中等批次(64-256) 通常是一个安全的起点
大批次(如 128+):适合数据量大、分布均匀的场景,需搭配较大学习率或 warm-up 策略。
小批次(如 16-32):适合数据量小、需增强泛化性的场景,或作为初始调试(便于观察训练波动)
批次越大:
- 每次迭代处理的数据量越多,计算资源(如 GPU)利用率更高,训练速度更快(可能因内存不足导致训练崩溃)
- 梯度更平滑(数据平均效应),收敛过程更稳定,但可能陷入局部最优解(尤其当批次过大时)
- 训练更 “确定性”,若数据分布均匀,可能收敛到更精确的解;但若数据存在偏差,大批次可能放大该偏差,导致泛化性下降
实训–蔬菜识别完整笔记
数据集准备环节
首先问AI我该如何获取蔬菜图片相关数据集,他推荐了网站(Kaggle: Your Machine Learning and Data Science Community)我在上面找到了适合项目的蔬菜集,网址如下Vegetable Image Dataset(https://www.kaggle.com/datasets/misrakahmed/vegetable-image-dataset/data)
项目目录
因为是小组项目,考虑到后续其他队友可能需要调整代码,模块分工,所以在项目里我用了模块化设计(让AI帮我拆解),每个模块负责特定的功能
1. config.py配置模块
设置随机种子(一个整数值,设置固定的随即种子能让深度学习中的随机过程的结果相同),数据集路径,批次大小(指定每个批次包含的样本数量,批次大训练快也更准确,但是内存占用大),每类样本最大数量(数据集图片太多了,限制用200个),训练轮次,模型保存路径。
设置中文字体配置FONT_PATHS
设置蔬菜营养信息,键值对的方式,键为模型预测类型
设置中英文类别映射,也是键值对的方式
2. data.py数据加载模块
读取蔬菜图像数据(VegetableDataset 类):初始化时指定数据集根目录、图像预处理转换和每类最大样本数(默认用 config 里的 200),
限制每类样本数量(_load_samples 方法),
图像转为RGB格式(__getitem__方法)
图像预处理转换(get_transforms 函数):随机裁剪、水平翻转、随机旋转、颜色抖动、验证测试集用固定尺寸裁剪,都转为张量(理解:将图像或其他格式的数据转换为神经网络能够处理的张量(Tensor)格式)并归一化。
先从识别处训练、验证、测试三个数据集的目录,然后创建训练、验证和测试数据加载器(数据加载器是一个迭代器,负责按批次加载、预处理数据,并输送给模型训练或推理)(create_data_loaders 函数),最后返回结果
3. model.py模型定义模块
基于ResNet18 创建蔬菜分类模型,使用预训练的 ResNet18 模型(利用 ImageNet 数据集上的预训练权重,可加速收敛并提升泛化能力)
冻结特征提取层参数(将model.parameters ()的requires_grad设为False,只只训练最后一层全连接层,适合小数据集微调)
将模型移至指定设备(config.py中定义的DEVICE)
4. evaluator.py模型训练模块
大白话理解:给模型看很多训练集中的蔬菜图片,让它学会识别蔬菜,再定期从验证集取出新图片测试,最后把学习最好的模型参数保存下来
初始化训练历史记录(保存训练和验证的损失、准确率),循环每个训练轮次(num_epochs):
训练阶段:先设置模型为训练模式(model.train ()),遍历训练数据加载器,使用 tqdm 显示进度,将数据移至指定设备(DEVICE),梯度清零,前向传播计算输出,获取预测类别,计算损失,反向传播更新参数累积损失和正确预测数,计算本轮平均指标
训练阶段代码理解:
model.train() # 告诉模型:现在是上课,要认真学
running_loss = 0.0 # 记录这学期学错的总次数
running_corrects = 0 # 记录这学期学对的总次数
for inputs, labels in tqdm(train_loader):
# 把图片和标签放到GPU(如果有的话)上计算
inputs, labels = inputs.to(DEVICE), labels.to(DEVICE)
optimizer.zero_grad() # 清空之前的学习误差记录
# 前向传播:模型猜这是什么蔬菜
outputs = model(inputs)
_, preds = torch.max(outputs, 1) # 选出模型认为最可能的蔬菜类别
# 计算错误程度(损失)
loss = criterion(outputs, labels)
# 反向传播:告诉模型哪里猜错了
loss.backward()
# 优化器:帮模型调整「思路」(参数)
optimizer.step()
# 记录这一批次的学习情况
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
验证阶段:先设置模型为评估模式(model.eval ()),然后进行验证,如果验证准确率高于历史最好的,就保存模型权重,返回训练好的模型和训练历史记录
5. visualizer.py可视化模型
先配置matplotlib库支持中文显示,让它遍历config里设置的中文字体路劲,然后使用
然后绘制模型训练过程中的损失和准确率曲线(plot_training_history(history))
曲线怎么绘制的呢,再训练过程中history字典会记录每一轮的关键指标,在这里把这些记录的指标进行初始化。
左图:损失曲线衡量模型预测值与真实值的差距,数值越小表示预测越准确,随轮次增加逐渐下降并趋于平稳
蓝色的训练损失曲线是模型在训练数据集上的误差,反映模型对训练数据的拟合程度
黄色的验证损失曲线,是模型在验证数据集上的误差,反映模型的泛化能力(对新数据的适应能力)
右图:准确率曲线是表示模型正确预测的样本比例,数值越高表示模型性能越好,随轮次增加逐渐上升,最终趋于平稳
蓝色的训练准确率曲线是模型在训练集上的正确预测率
黄色的验证准确率曲线是模型在验证集上的正确预测率,更反映模型的实际应用能力
6. predict.py 图像预测模块
展示单张图片的识别结果((display_prediction 函数)):先图像预处理,然后图片上添加类别和置信度,底部添加该类别对应的文字说明信息
7.main.py
协调整个系统的运行流程
执行步骤:配置中文字体;加载数据;创建模型;训练模型;可视化训练结果;评估模型;随机选择样本进行预测并展示结果