知识点回顾:
  1. 随机种子
  2. 内参的初始化
  3. 神经网络调参指南
    1. 参数的分类
    2. 调参的顺序
    3. 各部分参数的调整心得

作业:对于day41的简单cnn,看看是否可以借助调参指南进一步提高精度。

随机种子

import torch
import torch.nn as nn# 定义简单的线性模型(无隐藏层)
# 输入2个纬度的数据,得到1个纬度的输出
class SimpleNet(nn.Module):def __init__(self):super(SimpleNet, self).__init__()# 线性层:2个输入特征,1个输出特征self.linear = nn.Linear(2, 1)def forward(self, x):# 前向传播:y = w1*x1 + w2*x2 + breturn self.linear(x)# 创建模型实例
model = SimpleNet()# 查看模型参数
print("模型参数:")
for name, param in model.named_parameters():print(f"{name}: {param.data}")

torch中很多场景都会存在随机数

1. 权重、偏置的随机初始化

2. 数据加载(shuffling打乱)与批次加载(随机批次加载)的随机化

3. 数据增强的随机化(随机旋转、缩放、平移、裁剪等)

4. 随机正则化dropout

5. 优化器中的随机性

import torch
import numpy as np
import os
import random# 全局随机函数
def set_seed(seed=42, deterministic=True):"""设置全局随机种子,确保实验可重复性参数:seed: 随机种子值,默认为42deterministic: 是否启用确定性模式,默认为True"""# 设置Python的随机种子random.seed(seed) os.environ['PYTHONHASHSEED'] = str(seed) # 确保Python哈希函数的随机性一致,比如字典、集合等无序# 设置NumPy的随机种子np.random.seed(seed)# 设置PyTorch的随机种子torch.manual_seed(seed) # 设置CPU上的随机种子torch.cuda.manual_seed(seed) # 设置GPU上的随机种子torch.cuda.manual_seed_all(seed)  # 如果使用多GPU# 配置cuDNN以确保结果可重复if deterministic:torch.backends.cudnn.deterministic = Truetorch.backends.cudnn.benchmark = False# 设置随机种子
set_seed(42)

介绍一下这个随机函数的几个部分:

1. python的随机种子,需要确保random模块、以及一些无序数据结构的一致性

2. numpy的随机种子,控制数组的随机性

3. torch的随机种子,控制张量的随机性,在cpu和gpu上均适用

4. cuDNN(CUDA Deep Neural Network library ,CUDA 深度神经网络库)的随机性,针对cuda的优化算法的随机性

上述种子可以处理大部分场景,实际上还有少部分场景(具体的函数)可能需要自行设置其对应的随机种子。

日常使用中,在最开始调用这部分已经足够。

内参的初始化

我们都知道,神经网络的权重需要通过反向传播来实现更新,那么最开始肯定需要一个值才可以更新参数。

这个最开始的值是什么样子的呢?如果恰好他们就是那一组最佳的参数附近的数,那么可能我训练的速度会快很多。

为了搞懂这个问题,帮助我们真正理解神经网络参数的本质,我们需要深入剖析一下,关注以下几个问题:①初始值的区间;②初始值的分布;③初始值是多少。

先介绍一下神经网络的对称性----为什么神经元的初始值需要各不相同?

本质神经网络的每一个神经元都是在做一件事,输入x--输出y的映射,这里我们假设激活函数是sigmoid。

y=sigmoid(wx+b),其中w是连接到该神经元的权重矩阵,b是该神经元的偏置。

如果所有神经元的权重和偏置都一样:

1. 如果都为0,那么所有神经元的输出都一致,无法区分不同特征;此时反向传播的时候梯度都一样,无法学习到特征,更新后的权重也完全一致。

2. 如果不为0,同上。

所以,无论初始值是否为 0,相同的权重和偏置会导致神经元在训练过程中始终保持同步。(因为神经网络的前向传播是导致权重的数学含义是完全对称的)具体表现为:

同一层的神经元相当于在做完全相同的计算,无论输入如何变化,它们的输出模式始终一致。例如:输入图像中不同位置的边缘特征,会被这些神经元以相同方式处理,无法学习到空间分布的差异。

所以需要随机初始化,让初始的神经元各不相同。即使初始差异很小,但激活函数的非线性(梯度不同)会放大这种差异。随着训练进行,这种分歧会逐渐扩大,最终形成功能各异的神经元。

所以初始值一般不会太大,结合不同激活函数的特性,而且初始值一般是小的值。最终训练完毕可能就会出现大的差异,这样最开始让每个参数都是有用的,至于最后是不是某些参数归0(失去价值),那得看训练才知道。

避免梯度消失 / 爆炸:

以 sigmoid 激活函数为例,其导数在输入绝对值较大时趋近于 0(如 | x|>5 时,导数≈0)。若初始权重过大,输入 x=w・input+b 可能导致激活函数进入 “饱和区”,反向传播时梯度接近 0,权重更新缓慢(梯度消失)。

类比:若初始权重是 “大值”,相当于让神经元一开始就进入 “极端状态”,失去对输入变化的敏感度。

如果梯度相对较大,就可以让变化处于sigmoid函数的非饱和区。

所以其实对于不同的激活函数 ,都有对应的饱和区和非饱和区,深层网络中,饱和区会使梯度在反向传播时逐层衰减,底层参数几乎无法更新;

注意下,这里是wx后才会经过激活函数,是多个权重印象的结果,不是收到单个权重决定的,所以单个权重可以取负数,但是如果求和后仍然小于0,那么输出会为0。

所以初始值一般不会太大,结合不同激活函数的特性,而且初始值一般是小的值。最终训练完毕可能就会出现大的差异,这样最开始让每个参数都是有用的,至于最后是不是某些参数归0(失去价值),那得看训练才知道。

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np# 设置设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 定义极简CNN模型(仅1个卷积层+1个全连接层)
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()# 卷积层:输入3通道,输出16通道,卷积核3x3self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)# 池化层:2x2窗口,尺寸减半self.pool = nn.MaxPool2d(kernel_size=2)# 全连接层:展平后连接到10个输出(对应10个类别)# 输入尺寸:16通道 × 16x16特征图 = 16×16×16=4096self.fc = nn.Linear(16 * 16 * 16, 10)def forward(self, x):# 卷积+池化x = self.pool(self.conv1(x))  # 输出尺寸: [batch, 16, 16, 16]# 展平x = x.view(-1, 16 * 16 * 16)  # 展平为: [batch, 4096]# 全连接x = self.fc(x)  # 输出尺寸: [batch, 10]return x# 初始化模型
model = SimpleCNN()
model = model.to(device)# 查看模型结构
print(model)# 查看初始权重统计信息
def print_weight_stats(model):# 卷积层conv_weights = model.conv1.weight.dataprint("\n卷积层 权重统计:")print(f"  均值: {conv_weights.mean().item():.6f}")print(f"  标准差: {conv_weights.std().item():.6f}")print(f"  理论标准差 (Kaiming): {np.sqrt(2/3):.6f}")  # 输入通道数为3# 全连接层fc_weights = model.fc.weight.dataprint("\n全连接层 权重统计:")print(f"  均值: {fc_weights.mean().item():.6f}")print(f"  标准差: {fc_weights.std().item():.6f}")print(f"  理论标准差 (Kaiming): {np.sqrt(2/(16*16*16)):.6f}")# 改进的可视化权重分布函数
def visualize_weights(model, layer_name, weights, save_path=None):plt.figure(figsize=(12, 5))# 权重直方图plt.subplot(1, 2, 1)plt.hist(weights.cpu().numpy().flatten(), bins=50)plt.title(f'{layer_name} 权重分布')plt.xlabel('权重值')plt.ylabel('频次')# 权重热图plt.subplot(1, 2, 2)if len(weights.shape) == 4:  # 卷积层权重 [out_channels, in_channels, kernel_size, kernel_size]# 只显示第一个输入通道的前10个滤波器w = weights[:10, 0].cpu().numpy()plt.imshow(w.reshape(-1, weights.shape[2]), cmap='viridis')else:  # 全连接层权重 [out_features, in_features]# 只显示前10个神经元的权重,重塑为更合理的矩形w = weights[:10].cpu().numpy()# 计算更合理的二维形状(尝试接近正方形)n_features = w.shape[1]side_length = int(np.sqrt(n_features))# 如果不能完美整除,添加零填充使能重塑if n_features % side_length != 0:new_size = (side_length + 1) * side_lengthw_padded = np.zeros((w.shape[0], new_size))w_padded[:, :n_features] = ww = w_padded# 重塑并显示plt.imshow(w.reshape(w.shape[0] * side_length, -1), cmap='viridis')plt.colorbar()plt.title(f'{layer_name} 权重热图')plt.tight_layout()if save_path:plt.savefig(f'{save_path}_{layer_name}.png')plt.show()# 打印权重统计
print_weight_stats(model)# 可视化各层权重
visualize_weights(model, "Conv1", model.conv1.weight.data, "initial_weights")
visualize_weights(model, "FC", model.fc.weight.data, "initial_weights")# 可视化偏置
plt.figure(figsize=(12, 5))# 卷积层偏置
conv_bias = model.conv1.bias.data
plt.subplot(1, 2, 1)
plt.bar(range(len(conv_bias)), conv_bias.cpu().numpy())
plt.title('卷积层 偏置')# 全连接层偏置
fc_bias = model.fc.bias.data
plt.subplot(1, 2, 2)
plt.bar(range(len(fc_bias)), fc_bias.cpu().numpy())
plt.title('全连接层 偏置')plt.tight_layout()
plt.savefig('biases_initial.png')
plt.show()print("\n偏置统计:")
print(f"卷积层偏置 均值: {conv_bias.mean().item():.6f}")
print(f"卷积层偏置 标准差: {conv_bias.std().item():.6f}")
print(f"全连接层偏置 均值: {fc_bias.mean().item():.6f}")
print(f"全连接层偏置 标准差: {fc_bias.std().item():.6f}")

训练时,权重会随反向传播迭代更新。通过权重分布图,能直观看到其从初始化(如随机分布)到逐渐收敛、形成规律模式的动态变化,理解模型如何一步步 “学习” 特征 。比如,卷积层权重初期杂乱,训练后可能聚焦于边缘、纹理等特定模式。

识别梯度异常:

1. 梯度消失:若权重分布越来越集中在 0 附近,且更新幅度极小,可能是梯度消失,模型难学到有效特征(比如深层网络用 Sigmoid 激活易出现 )。

2. 梯度爆炸:权重值突然大幅震荡、超出合理范围(比如从 [-0.1, 0.1] 跳到 [-10, 10] ),要警惕梯度爆炸,可能让训练崩溃。

借助tensorboard可以看到训练过程中权重图的变化。

神经网络调参指南

大部分时候,由于光是固定超参数的情况下,训练完模型就已经很耗时了,所以正常而言,基本不会采用传统机器学习的那些超参数方法,网格、贝叶斯、optuna之类的,看到一些博主用这些写文案啥的,感觉这些人都是脑子有问题的,估计也没学过机器学习直接就学深度学习了,搞混了二者的关系。

工业界卡特别多的情况下,可能可以考虑,尤其是在探究一个新架构的时候,我们直接忽视这些即可,只有手动调参这一条路。

参数的分类

之前我们介绍过了,参数=外参(实例化的手动指定的)+内参,其中我们把外参定义为超参数,也就是不需要数据驱动的那些参数

通常可以将超参数分为三类:网络参数、优化参数、正则化参数。

①网络参数:包括网络层之间的交互方式(如相加、相乘或串接)、卷积核的数量和尺寸、网络层数(深度)和激活函数等。

②优化参数:一般指学习率、批样本数量、不同优化器的参数及部分损失函数的可调参数。

③正则化参数:如权重衰减系数、丢弃比率(dropout)。

超参数调优的目的是优化模型,找到最优解与正则项之间的关系。网络模型优化的目的是找到全局最优解(或相对更好的局部最优解),而正则项则希望模型能更好地拟合到最优。两者虽然存在一定对立,但目标是一致的,即最小化期望风险。模型优化希望最小化经验风险,但容易过拟合,而正则项用来约束模型复杂度。因此,如何平衡两者关系,得到最优或较优的解,就是超参数调整的目标。

调参顺序

调遵循 “先保证模型能训练(基础配置)→ 再提升性能(核心参数)→ 最后抑制过拟合(正则化)” 的思路,类似 “先建框架,再装修,最后修细节”。

我们之前的课上,主要都是停留在第一步,先跑起来,如果想要更进一步提高精度,才是这些调参指南。所以下面顺序建立在已经跑通了的基础上。

1. 参数初始化----有预训练的参数直接起飞

2. batchsize---测试下能允许的最高值

3. epoch---这个不必多说,默认都是训练到收敛位置,可以采取早停策略

4. 学习率与调度器----收益最高,因为鞍点太多了,模型越复杂鞍点越多

5. 模型结构----消融实验或者对照试验

6. 损失函数---选择比较少,试出来一个即可,高手可以自己构建

7. 激活函数---选择同样较少

8. 正则化参数---主要是droupout,等到过拟合了用,上述所有步骤都为了让模型过拟合

这个调参顺序并不固定,而且也不是按照重要度来选择,是按照方便程度来选择,比如选择少的选完后,会减小后续实验的成本。

初始化参数

预训练参数是最好的参数初始化方法,在训练前先找找类似的论文有无预训练参数,其次是Xavir,尤其是小数据集的场景,多找论文找到预训练模型是最好的做法。关于预训练参数,我们介绍过了,优先动深层的参数,因为浅层是通用的;其次是学习率要采取分阶段的策略。

如果从0开始训练的话,PyTorch 默认用 Kaiming 初始化(适配 ReLU)或 Xavier 初始化(适配 Sigmoid/Tanh)。

bitchsize的选择

一般学生党资源都有限,所以基本都是bitchsize不够用的情况,富哥当我没说。

当Batch Size 太小的时候,模型每次更新学到的东西太少了,很可能白学了因为缺少全局思维。所以尽可能高一点,16的倍数即可,越大越好。

学习率调整

学习率就是参数更新的步长,LR 过大→不好收敛;LR 过小→训练停滞(陷入局部最优)

一般最开始用adam快速收敛,然后sgd收尾,一般精度会高一点;只能选一个就adam配合调度器使用。比如 CosineAnnealingLR余弦退火调度器、StepLR固定步长衰减调度器,比较经典的搭配就是Adam + ReduceLROnPlateau,SGD + CosineAnnealing,或者Adam → SGD + StepLR。

比如最开始随便选了做了一组,后面为了刷精度就可以考虑选择更精细化的策略了。

激活函数的选择

视情况选择,一般默认relu或者其变体,如leaky relu,再或者用tanh。只有二分类任务最后的输出层用sigmoid,多分类任务用softmax,其他全部用relu即可。此外,还有特殊场景下的,比如GELU(适配 Transformer)

损失函数的选择

大部分我们目前接触的任务都是单个损失函数构成的,正常选即可

分类任务:

1. 交叉熵损失函数Cross-Entropy Loss——多分类场景

2. 二元交叉熵损失函数Binary Cross-Entropy Loss——二分类场景

3. Focal Loss——类别不平衡场景

注意点:

①CrossEntropyLoss内置 Softmax,输入应为原始 logits(非概率)。

②BCEWithLogitsLoss内置 Sigmoid,输入应为原始 logits。

③若评价指标为准确率,用交叉熵损失;若为 F1 分数,考虑 Focal Loss 或自定义损失。

回归任务

1. 均方误差MSE

2. 绝对误差MAE

这个也要根据场景和数据特点来选,不同损失受到异常值的影响程度不同。

此外,还有一些序列任务的损失、生成任务的损失等等,以后再提。

后面会遇到一个任务中有多个损失函数构成,比如加权成一个大的损失函数,就需要注意到二者的权重配比还有数量级的差异。

模型架构中的参数

比如卷积核尺寸等,一般就是7*7、5*5、3*3这种奇数对构成,其实我觉得无所谓,最开始不要用太过分的下采样即可。

神经元的参数,直接用 Kaiming 初始化(适配 ReLU,PyTorch 默认)或 Xavier 初始化(适配 Sigmoid/Tanh)。

正则化系数

droupout一般控制在0.2-0.5之间,这里说一下小技巧,先追求过拟合后追求泛化性。也就是说先把模型做到过拟合,然后在慢慢增加正则化程度。

正则化中,如果train的loss可以很低,但是val的loss还是很高,则说明泛化能力不强,优先让模型过拟合,在考虑加大正则化提高泛化能力,可以分模块来droupout,可以确定具体是那部分参数导致过拟合,这里还有个小trick是引入残差链接后再利用droupout。

L2权重衰减这个在优化器中就有,这里提一下,也可以算是正则化吧。

其他补充

对于复杂的项目,尽可能直接对着别人已经可以跑通的源码来改。----注意是可以跑通的,目前有很多论文的开源都是假开源。

在调参过程中可以监控tensorboard来关注训练过程。

无论怎么调参,提升的都是相对较小,优先考虑数据+特征工程上做文章。还有很多试验灌水的方法,自行搜索即可。

今天说的内容其实相对而言比较基础,非常多的trick现在提也没有价值,主要都是随便一试出来了好结果然后编个故事,不具有可以系统化标准化的理解,掌握到今天说的这个程度够用咯.大家现阶段能把复杂的模型跑通和理解已经实属不易。

@浙大疏锦行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/94993.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94993.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/94993.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch 常用任务管理命令及实战应用

常用任务管理命令 列出所有任务 curl -X GET "http://<es_host>:<es_port>/_tasks?detailedtrue&pretty" -H Content-Type: application/json获取特定类型的任务 curl -X GET "http://<es_host>:<es_port>/_tasks?actions<act…

Java试题-选择题(26)

Java试题-选择题(26) 题目 下列有关Thread的描述,哪个是正确的 ? A:启动一个线程的方法是:thread. run() B:结束一个线程的通常做法是:thread. stop() C:将一个线程标记成daemon线程,意味着当主线程结束,并且没有其它正在运行的非daemon线程时,该daemon线程也会自…

缓存的原理、引入及设计

开篇寄语&#xff1a;缓存&#xff0c;你真的用对了吗&#xff1f; 我们为什么要学习缓存呢&#xff1f;有必要学习缓存吗&#xff1f; 缓存的使用&#xff0c;是提升系统性能、改善用户体验的唯一解决之道。 其实&#xff0c;作为互联网公司&#xff0c;只要有直接面对用户的业…

单片机如何控制模数转换芯片

一、介绍单片机控制模数转换&#xff08;ADC&#xff09;芯片的核心是通过通信接口发送控制指令&#xff0c;并读取转换后的数字信号&#xff0c;本质是“指令交互数据传输”的协同过程&#xff0c;具体实现需分4步完成&#xff0c;关键在于接口匹配和时序同步。二、核心1. 先明…

【Proteus仿真】开关控制系列仿真——开关控制LED/拨码开关二进制计数/开关和继电器控制灯灭

目录 0案例视频效果展示 0.1例子1&#xff1a;开关控制LED灯亮灭 0.2例子2&#xff1a;数码管显示拨码开关二进制计数(000~255) 0.3例子3&#xff1a;开关和继电器控制灯亮灭 1基础知识补充 1.1 74LS245双总线收发器 1.1.1 引脚及功能 1.1.2应用场景 1.1.3真值表 1.2…

Q1 Top IF 18.7 | 基于泛基因组揭示植物NLR进化

文章DOI: 10.1016/j.chom.2025.07.011 标题&#xff1a;Pangenomic context reveals the extent of intraspecific plant NLR evolution 期刊&#xff1a;Cell Hose & Microbe (https://i-blog.csdnimg.cn/direct/0e31f86b94d348b0a1adb084ec4e49b7.png)(https://i-blog.cs…

技术干货|Prometheus PromQL查询语言之聚合操作内置函数

聚合操作 Prometheus还提供了下列内置的聚合操作符,这些操作符作用域瞬时向量。可以将瞬时表达式返回的样本数据进行聚合,形成一个新的时间序列。 sum (求和) min (最小值) max (最大值) avg (平均值) stddev (标准差) stdvar (标准差异) count (计数) count_values …

Redis 哨兵(Sentinel)全面解析

在2025年的数字化浪潮中&#xff0c;想象这样一个场景&#xff1a;凌晨3点&#xff0c;电商平台流量突然暴增&#xff0c;主Redis服务器因硬件故障突然宕机。几年前&#xff0c;这意味着紧急电话、慌乱的运维人员和不可避免的业务中断。而今天&#xff0c;用户甚至没有察觉任何…

【数学史冷知识】关于行列式的发展史

学习的途中会遇到一些有意思的东西&#xff0c;我想着做一个专栏《艾萨克纪行简报》&#xff0c;专门写这些知识发展历史。可以让您从繁忙的学习生活中放松&#xff0c;添些耀彩。行列式和微积分一样&#xff0c;都是两个人独立发现的。而且还都有莱布尼茨。1683 年&#xff0c…

【python】python进阶——生成器

目录 一、生成器介绍 1.1 生成器与迭代器的关系 1.2 生成器与return比较 二、创建生成器 方法1: 生成器函数 方法2: 生成器表达式 三、生成器的实际应用场景 3.1 处理大型文件 3.2 生成无限序列 3.3 数据管道处理 四、生成器的高级用法 4.1 使用send()方法传递值 …

【Pytorch】生成对抗网络实战

GAN框架基于两个模型的竞争&#xff0c;Generator生成器和Discriminator鉴别器。生成器生成假图像&#xff0c;鉴别器则尝试从假图像中识别真实的图像。作为这种竞争的结果&#xff0c;生成器将生成更好看的假图像&#xff0c;而鉴别器将更好地识别它们。 目录 创建数据集 定…

Java基础第7天总结(代码块、内部类、函数式编程)

代码块静态代码块&#xff1a;有static修饰&#xff0c;属于类&#xff0c;与类一起优先加载&#xff0c;自动执行一次实例代码块&#xff1a;无static修饰&#xff0c;属于对象&#xff0c;每次创建对象时&#xff0c;都会优先执行一次。package com.itheima.code;import java…

文献综述写作指南:从海量文献到逻辑闭环的实战模板

文献综述往往是学术写作的“第一关难题”&#xff1a;面对成百上千篇文献&#xff0c;如何避免“简单罗列”的陷阱&#xff0c;梳理出有逻辑、有洞见的论述体系&#xff1f;本文结合学术写作实践&#xff0c;总结出一套模块化的文献综述“实战模板”&#xff0c;通过结构化方法…

CuTe C++ 简介01,从示例开始

这里先仅仅关注 C 层的介绍&#xff0c;python DSL 以后再说。在 ubuntu 22.04 X64 中&#xff0c;RTX 50801. 环境搭建1.1 安装 cuda1.2 下载源码git clone https://github.com/NVIDIA/cutlass.git1.3 编译mkdir build/ cmake .. -DCUTLASS_NVCC_ARCHS"120" -DCMAK…

Python实现异步多线程Web服务器:从原理到实践

目录Python实现异步多线程Web服务器&#xff1a;从原理到实践引言第一章&#xff1a;Web服务器基础1.1 Web服务器的工作原理1.2 HTTP协议简介1.3 同步 vs 异步 vs 多线程第二章&#xff1a;Python异步编程基础2.1 异步I/O概念2.2 协程与async/await2.3 事件循环第三章&#xff…

Deep Think with Confidence:llm如何进行高效率COT推理优化

1. 引言:大模型的推理解码优化 大型语言模型(LLM)在处理数学、编码等复杂推理任务时,一种强大但“耗能巨大”的技术是self-consistency,也称并行思考(parallel thinking)。其核心思想是让模型对同一个问题生成多条不同的“思考路径”(reasoning traces),然后通过多数…

vscode克隆远程代码步骤

一、直接使用VsCode1.复制git的https链接代码2.在vscode中点击 代码管理-克隆仓库3.粘贴&#xff08;在git里面复制的https链接&#xff09;4.选择需要存储的文件位置5.确认6.代码克隆成功二、使用命令行克隆1.确定文件放置位置&#xff0c;右键2.复制git的https链接代码3.粘贴…

spi总线

一、介绍SPI总线&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是一种高速全双工同步串行通信总线&#xff0c;核心通过“主从架构同步时钟”实现设备间数据传输&#xff0c;因结构简单、速率高&#xff0c;广泛用于MCU与传感器、存储芯片、显示…

COLA:大型语言模型高效微调的革命性框架

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 1 COLA技术概述 COLA&#xff08;Chain of LoRA&#xff09;是一种创…

数据结构与算法:线段树(三):维护更多信息

前言 这次的题思维上倒不是很难&#xff0c;就是代码量比较大。 一、开关 洛谷的这种板子题写起来比cf顺多了&#xff08;&#xff09; #include <bits/stdc.h> using namespace std;typedef long long ll; typedef pair<int,int> pii; typedef pair<ll,ll&…