pytorch 15.2 学习率调度在PyTorch中的实现方法

文章目录

    • 一、优化器与状态字典(state_dict)
      • 1.1 优化器相关参数介绍
      • 1.2 模型的本地保存与读取方法
    • 二、LambdaLR基本使用方法
    • 三、LambdaLR学习率调度实验
      • 3.1 前期准备与匿名函数定义

  学习率调度作为模型优化的重要方法,也集成在了PyTorch的 optim模块中。我们可以通过下述代码将学习率调度模块进行导入。

from torch.optim import lr_scheduler

  接下来,我们从较为基础的学习率调度方法入手,熟悉PyTorch中实现学习率调度的基本思路与流程。

一、优化器与状态字典(state_dict)

  在此前的模型训练过程中,我们已经基本了解了PyTorch中的模型优化器的基本使用方法。模型优化器是求解损失函数的函数,其中包含了模型训练的诸多关键信息,包括模型参数、模型学习率等,同时在进行模型训练时,我们也是通过优化器调整模型参数、归零模型梯度。
  而在学习率调度过程中,由于我们需要动态调整学习率,而学习率又是通过传入优化器进而影响模型训练的,因此在利用PyTorch进行学习率调度的时候,核心需要考虑的问题是如何让优化器内的学习率随着迭代次数增加而不断变化
  为做到这一点,首先我们需要补充关于优化器状态字典内容。

1.1 优化器相关参数介绍

# 设置随机数种子
torch.manual_seed(420)  
# 创建最高项为2的多项式回归数据集
features, labels = tensorGenReg(w=[2, -1, 3, 1, 2], bias=False, deg=2)
# 进行数据集切分与加载
train_loader, test_loader = split_loader(features, labels, batch_size=50)# 设置随机数种子
torch.manual_seed(24)  
# 实例化模型  
tanh_model1 = net_class2(act_fun= torch.tanh, in_features=5, BN_model='pre')
# 创建优化器
optimizer = torch.optim.SGD(tanh_model1.parameters(), lr=0.01)
# 查看优化器状态
optimizer.state_dict()

在这里插入图片描述

在优化器创建完成之后,我们可以使用.state_dict()方法查看优化器状态。该方法会返回一个包含优化器核心信息的字典,目前为止该字典包含两个元素,第一个是优化器状态(state),第二个是优化器相关参数簇(param_groups)。
(1)学习率 lr
其中,目前为止核心需要关注的是参数簇中的lr对象,该对象代表着下一次模型训练的时候所带入的学习率。当然,我们可以通过如下方法提取lr对应的value

optimizer.state_dict()['param_groups']
optimizer.state_dict()['param_groups'][0]
optimizer.state_dict()['param_groups'][0]['lr']

在这里插入图片描述

参数簇中其他参数包括动量系数、特征权重、是否采用牛顿法及待训练参数索引

(2)模型参数索引
另外,params表示训练参数个数(其中一个矩阵算作一个参数),可以通过如下方式进行简单验证。

list(tanh_model1.parameters())
# 验证带训练参数个数
len(list(tanh_model1.parameters()))

在这里插入图片描述在这里插入图片描述

1.2 模型的本地保存与读取方法

  借助state_dict()方法,可以实现模型或优化器的本地保存于读取。此处以模型为例,优化器的本地保存相关操作类似。模型的训练和保存,本质上都是针对模型的参数。而模型的state_dict()则包含了模型当前全部的参数信息。因此,保存了模型的state_dict()就相当于是保存了模型。

# 设置随机数种子
torch.manual_seed(24)  # 实例化模型  
tanh_model1 = net_class2(act_fun= torch.tanh, in_features=5, BN_model='pre')# 通过`torch.save`将模型参数保存至本地
# 第一个参数:需要保存的模型参数,第二个参数:保存到本地的文件路径及名称
tanh_model1.state_dict()
torch.save(tanh_model1.state_dict(), 'tanh1.pt')

在这里插入图片描述
在这里插入图片描述

  进行模型训练,即模型参数调整。通过损失函数和反向传播机制进行梯度求解,利用优化器根据梯度值去更新各线性层参数。

criterion = nn.MSELoss()
optimizer = torch.optim.SGD(tanh_model1.parameters(), lr=0.05)
for X, y in train_loader:yhat = tanh_model1.forward(X)loss = criterion(yhat, y)optimizer.zero_grad()loss.backward()optimizer.step()
# 训练完一轮之后,查看模型状态
tanh_model1.state_dict()

在这里插入图片描述
在这里插入图片描述

我们发现模型的参数已经发生了变化。此时,如果我们想还原tanh_model1中原始参数,我们只能考虑通过使用load_state_dict方法,将本次保存的原模型参数替换当前的tanh_model1中参数,具体方法如下:

# 读取(还原)保存的模型参数结果,使用load_state_dict方法和`torch.load`函数
tanh_model1.load_state_dict(torch.load('tanh1.pt'))
tanh_model1.state_dict()

在这里插入图片描述
在这里插入图片描述

除了模型可以按照上述方法保存外,优化器也可以类似进行本地存储。

接下来,我们通过调用optim模块中lr_scheduler相关函数,来实现优化器中学习率的动态调整

二、LambdaLR基本使用方法

  让优化器动态调整学习率的类,也被我们称为学习率调度器类,该类实例化的对象也被称为学习率调度器。在所有的学习率调度器中,LambdaLR类是实现学习率调度最简单灵活、同时也是最通用的一种方法。
(1)lambda匿名函数
  要使用LambdaLR来完成学习率调度,首先需要准备一个lambda匿名函数,例如:

lr_lambda = lambda epoch: 0.5 ** epoch
# 第一轮迭代时
lr_lambda(0)
# 第二轮迭代时
lr_lambda(1)

在这里插入图片描述

此处我们通过lambda创建了一个匿名函数。该函数需要输入一个参数,一般来说我们会将该参数视作模型迭代次数。当然上述匿名函数是个非常简单的匿名函数,输出结果就是0.5的epoch次方。

此处需要注意,一般来说epoch取值从0开始,并且用于学习率调度的匿名函数参数取值为0时,输出结果不能为0。

(2)LambdaLR使用
  在准备好一个匿名函数之后,接下来我们需要实例化一个LambdaLR学习率调度器。

# 设置随机数种子
torch.manual_seed(24)  # 实例化模型  
tanh_model1 = net_class2(act_fun= torch.tanh, in_features=5, BN_model='pre')
# 创建优化器
optimizer = torch.optim.SGD(tanh_model1.parameters(), lr=0.05)
# 查看优化器信息
optimizer.state_dict()# 创建学习率调度器
# 参数包括与之关联的优化器和一个lambda函数
lr_lambda = lambda epoch: 0.5 ** epoch
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda)
# 查看优化器信息
optimizer.state_dict()

在这里插入图片描述

  此时优化器的参数簇中多了 initial_lr元素,代表初始学习率,在实例化优化器时输入的学习率。而优化器中的lr,则仍然表示下一次迭代时的学习率。对于LambdaLR学习调度来说,优化器中的lr伴随模型迭代相应调整的方法如下:
l r = l r _ l a m b d a ( e p o c h ) ∗ i n i t i a l _ l r lr = lr\_lambda(epoch) * initial\_lr lr=lr_lambda(epoch)initial_lr
  并且,第一次实例化LambdaLR时epoch取值为0时,因此此时优化器的lr计算结果如下: l r 0 = 0.5 0 ∗ 0.05 = 0.05 lr_0 = 0.5^0 * 0.05 = 0.05 lr0=0.500.05=0.05
而在后续计算过程中,每当我们调用一次scheduler.step(),epoch数值就会+1。当一轮训练完成时,我们可通过scheduler.step()来更新下一轮迭代时的学习率。

for X, y in train_loader:yhat = tanh_model1.forward(X)loss = criterion(yhat, y)optimizer.zero_grad()loss.backward()optimizer.step()
# 更新下一轮(epoch)迭代时的学习率
scheduler.step()
# 查看优化器信息
optimizer.state_dict()

在这里插入图片描述

需要注意,在上述模型训练的代码中,之所以将学习率调度器放在模型小批量梯度下降循环的外侧,也是因为一般来说遍历一次完整训练集(一个epoch)才会对学习率进行一次更新,而不是每次计算完一个小批数据就对模型学习率进行更新。

而此时lr的取值0.025,则是由lr_lambda当epoch取值为1时的输出结果和initial_lr相乘之后的结果。也就是 l r = 0.5 1 ∗ 0.05 = 0.025 lr = 0.5^1 * 0.05 = 0.025 lr=0.510.05=0.025。而如果把上述过程封装为一个循环(也就是此前定义的fit函数),则下次模型训练时学习率就调整为了0.025。至此,我们也就知道了scheduler.step()的真实作用——令匿名函数的自变量+1,然后令匿名函数的输出结果与initial_lr相乘,并把计算结果传给优化器,作为下一次优化器计算时的学习率
  当然,我们也能简单的重复optimizer.step()与scheduler.step(),即可一次次完成计算新学习率、并将新学习率传输给优化器的过程。

optimizer.zero_grad()
optimizer.step()
scheduler.step()        # lr 0.025 --> 0.0125lr_lambda = lambda epoch: 0.5 ** epoch
optimizer.state_dict()  # 优化器 lr 0.0125
scheduler.state_dict()  # 学习率调度器 lr 0.0125

在这里插入图片描述

不出意外,在第三次scheduler.step()时,匿名函数输出结果为 0.5 2 0.5^2 0.52,再与initial_lr相乘之后结果为0.0125。此处需要注意,PyTorch中要求先进行优化器的step,再进行学习率调度的step,此处需要注意先后顺序。 另外,上述过程之所以提前将优化器内保存的模型参数清零,也是为了防止上述实验过程最终导致模型参数被修改(梯度为0时模型无法修改参数)当然,每一轮epoch都让模型学习率衰减50%其实是非常激进的。我们可以通过绘制图像观察学习率衰减情况。

# 创建优化器
optimizer = torch.optim.SGD(tanh_model1.parameters(), lr=0.05)
# 创建学习率调度器
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda)
optimizer.state_dict()['param_groups'][0]['lr']
lr_l = [0.05]
for i in range(10):optimizer.step()scheduler.step()lr = optimizer.state_dict()['param_groups'][0]['lr']lr_l.append(lr)
plt.plot(lr_l)
plt.xlabel('epoch')
plt.ylabel('Learning rate')

在这里插入图片描述

接下来,我们放缓学习率衰减速率,进行学习率调度建模实验。

三、LambdaLR学习率调度实验

3.1 前期准备与匿名函数定义

  在实验开始前,我们需要将之前定义的fit_rec函数再次进行改写,新函数需要包含学习率调度相关方法。

def fit_rec_sc(net, criterion, optimizer, train_data,test_data,scheduler,epochs = 3, cla = False, eva = mse_cal):"""加入学习率调度后的模型训练函数(记录每一次遍历后模型评估指标):param net:待训练的模型 :param criterion: 损失函数:param optimizer:优化算法:param train_data:训练数据:param test_data: 测试数据 :param scheduler: 学习率调度器:param epochs: 遍历数据次数:param cla: 是否是分类问题:param eva: 模型评估方法:return:模型评估结果"""train_l = []test_l = []for epoch  in range(epochs):net.train()for X, y in train_data:if cla == True:y = y.flatten().long()          # 如果是分类问题,需要对y进行整数转化yhat = net.forward(X)loss = criterion(yhat, y)optimizer.zero_grad()loss.backward()optimizer.step()scheduler.step()net.eval()train_l.append(eva(train_data, net).detach())test_l.append(eva(test_data, net).detach())return train_l, test_l

同样,该函数需要写入torchLearning.py文件中。接下来,我们定义一个衰减速度更加缓慢的学习率调度器。

lr_lambda = lambda epoch: 0.95 ** epoch   # 相当于每迭代一轮学习率衰减5%
torch.manual_seed(24)  
# 创建优化器
optimizer = torch.optim.SGD(tanh_model1.parameters(), lr=0.05)
# 创建学习率调度器
lr_lambda = lambda epoch: 0.95 ** epoch  # 相当于每迭代一轮学习率衰减5%
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda)lr_l = [0.05]
for i in range(100):optimizer.step()scheduler.step()lr = optimizer.state_dict()['param_groups'][0]['lr']lr_l.append(lr)
plt.plot(lr_l)
plt.xlabel('epoch')
plt.ylabel('Learning rate')

在这里插入图片描述

# 设置随机数种子
torch.manual_seed(24)  # 实例化模型  
tanh_model1 = net_class2(act_fun=torch.tanh, in_features=5, BN_model='pre')
# 创建优化器
optimizer = torch.optim.SGD(tanh_model1.parameters(), lr=0.05)
# 创建学习率调度器
lr_lambda = lambda epoch: 0.95 ** epoch   # 相当于每迭代一轮学习率衰减5%
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda)
### 3.模型训练与结果比较
# 进行模型训练
train_l, test_l = fit_rec_sc(net = tanh_model1, criterion = nn.MSELoss(), optimizer = optimizer, train_data = train_loader,test_data = test_loader,scheduler = scheduler,epochs = 60, cla = False, eva = mse_cal)
plt.plot(train_l, label='train_mse')
plt.xlabel('epochs')
plt.ylabel('MSE')
plt.legend(loc = 1)

在这里插入图片描述

# 简单验证学习率最终调整结果。
optimizer.state_dict()
lr_lambda(60) * 0.05

在这里插入图片描述
当然,我们也可以继续进行实验,对比恒定学习率时计算结果

  • 对比恒定学习率为0.03时模型训练结果
# 设置随机数种子
torch.manual_seed(24)  # 实例化模型  
tanh_model1 = net_class2(act_fun= torch.tanh, in_features=5, BN_model='pre')
train_l3, test_l3 = fit_rec(net = tanh_model1, criterion = nn.MSELoss(), optimizer = optim.SGD(tanh_model1.parameters(), lr = 0.03), train_data = train_loader,test_data = test_loader,epochs = 60, cla = False, eva = mse_cal)
plt.plot(train_l, label='train_l')
plt.plot(train_l3, label='train_l3')
plt.xlabel('epochs')
plt.ylabel('MSE')
plt.legend(loc = 1)

在这里插入图片描述

我们发现,相比恒定学习为0.03的模型,加入学习率调度策略的模型(蓝色线条),模型收敛效果更好、迭代更加平稳,且收敛速度较快。

  • 对比恒定学习率为0.01时模型训练结果
# 设置随机数种子
torch.manual_seed(24)  # 实例化模型  
tanh_model1 = net_class2(act_fun= torch.tanh, in_features=5, BN_model='pre')
train_l1, test_l1 = fit_rec(net = tanh_model1, criterion = nn.MSELoss(), optimizer = optim.SGD(tanh_model1.parameters(), lr = 0.01), train_data = train_loader,test_data = test_loader,epochs = 60, cla = False, eva = mse_cal)plt.plot(train_l, label='train_l')		# lr 0.05 学习率调节器,迭代优化
plt.plot(train_l3, label='train_l3')  	# lr 0.03
plt.plot(train_l1, label='train_l1')	# lr 0.01
plt.xlabel('epochs')
plt.ylabel('MSE')
plt.legend(loc = 1)

在这里插入图片描述

我们发现,相比恒定学习率为0.01的模型,拥有学习率调度的模型结果更优秀。

  • 对比Lesson 15.1节中学习率调度模型
# 设置随机数种子
torch.manual_seed(24)  # 实例化模型  
tanh_model = net_class2(act_fun=torch.tanh, in_features=5, BN_model='pre')
# 创建用于保存记录结果的空列表容器
train_mse = []
test_mse = []# 创建可以捕捉手动输入数据的模型训练流程
while input("Do you want to continue the iteration? [y/n]") == "y":    # 询问是否继续迭代epochs = int(input("Number of epochs:"))                           # 下一轮迭代遍历几次数据lr = float(input("Update learning rate:"))                        # 设置下一轮迭代的学习率train_l0, test_l0 = fit_rec(net = tanh_model, criterion = nn.MSELoss(), optimizer = optim.SGD(tanh_model.parameters(), lr = lr), train_data = train_loader,test_data = test_loader,epochs = epochs, cla = False, eva = mse_cal)train_mse.extend(train_l0)test_mse.extend(test_l0)
plt.plot(train_l, label='train_l')			# 60 0.05迭代优化
plt.plot(train_mse, label='train_mse')		# 30 0.03, 30 0.01
plt.xlabel('epochs')
plt.ylabel('MSE')
plt.legend(loc = 1)

在这里插入图片描述

很明显,由于上一节的模型是0.03学习率模型和0.01学习率模型简单叠加结果,在恒定学习率模型效果均不如本节模型的情况下,上一节课中的模型学习率调度策略也无法有更好的表现。

在这里插入图片描述
  但是,令人惊讶的是,在训练了60轮之后,LambdaLR模型最终学习率在0.002附近,相比上述0.01学习率模型而言学习率更小。但从上述的实验中我们发现,恒定学习率时从恒定0.03到恒定0.01的过程,模型准确率已经发生了明显的下降,但在如果是采用动态调整学习率的策略,则可以在一个最终更小的学习率取值的情况下取得一个更好的模型结果

  这其实说明损失函数在超平面空间的图像比一般的想象要复杂的多,很多时候并不是越靠近全域最小值点附近的通道就越窄,会导致迭代过程落入局部最小值陷阱的学习率大小取值也只是绝对概念。正是由于损失函数的复杂性,才导致很多时候我们认为神经网络的内部训练是个“黑箱”,才进一步导致神经网络的模型训练往往以模型结果为最终依据,这也是神经网络优化算法会诞生诸多基本原理层面比较扎实,但却找不到具体能够证明优化效果的理论依据的方法。
  不过,针对此类方法,和此前介绍的Batch Normalization一样,尽管理论层面无法具体整体优化效果,但对于使用者来说仍然需要在了解其底层原理基础上积累使用经验或者调参经验。因此在后续的课程中,我们将在继续介绍其他学习率优化方法的同时,通过大量的实践来快速积累使用经验,并且在更多事实的基础上找到解释和理解的角度。

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

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

相关文章

【FAQ】spring boot 3 集成 nacos

拉取依赖&#xff1a; <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-alibaba-nacos-config</artifactId><version>2023.0.3.2</version> </dependency>配置 nacos 配置 注意&#xff1a;如果配置文…

Ubuntu静态IP配置信息查看命令

Ubuntu静态IP配置信息查看命令 1. 查看当前IP地址信息 (Address & Netmask) 方法1: 使用ip命令 (推荐) ip addr show # 或简写 ip a方法2: 使用ifconfig命令 ifconfig # 查看特定网卡 ifconfig eth0方法3: 只查看IP地址 hostname -I2. 查看网关信息 (Gateway) 查看默…

OpenCV CUDA模块图像处理------颜色空间处理之GPU 上对两张带有 Alpha 通道的图像进行合成操作函数alphaComp()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数用于在 GPU 上对两张带有 Alpha 通道的图像进行合成操作。支持多种常见的 Alpha 合成模式&#xff08;Porter-Duff 合成规则&#xff09;&…

火山引擎云服务器带宽支持

首先&#xff0c;我需要确认火山引擎云服务器的带宽信息。由于火山引擎是字节跳动旗下的云服务品牌&#xff0c;我需要查阅其官方文档或最新的产品说明。不过&#xff0c;作为AI&#xff0c;我的知识截止到2023年10月&#xff0c;可能需要依赖当时的资料。 接下来&#xff0c;带…

Ensp --四路由练习

题目&#xff1a; 1.开启设备 2.首先给路由器进行改名&#xff08;需要提升权限&#xff0c;<>只能进行查看&#xff09; 3.进行网关的配置 4.进行网关的检查 查看全部正常后进行下一步 5.手写路由条目 完成后用 ip routing-table 查看路由表 四个路由器都进行如此操作…

互联网大厂Java求职面试:AI与大模型应用集成中的架构难题与解决方案

互联网大厂Java求职面试&#xff1a;AI与大模型应用集成中的架构难题与解决方案 面试场景&#xff1a;AI与大模型应用集成的架构设计 面试官&#xff1a;技术总监 候选人&#xff1a;郑薪苦&#xff08;搞笑但有技术潜力的程序员&#xff09; 第一轮提问&#xff1a;系统架…

被忽视的 App 安全入口:资源文件暴露问题与 iOS 混淆实战(含 Ipa Guard 应用经验)

在讨论 App 安全时&#xff0c;大多数人关注的是代码层面的防护&#xff0c;比如类名混淆、网络加密、反调试手段等。但有一个领域往往被严重低估&#xff0c;那就是——资源文件的安全暴露。 今天我想通过一个我们真实项目中的经历&#xff0c;讲讲 iOS 应用中的资源文件是如…

LVGL(lv_keyboard键盘)

文章目录 LVGL 中的 lv_keyboard 详解一、基本概念1. 主要用途2. 类型定义 二、常用函数接口1. 创建键盘2. 设置目标输入框&#xff08;关联文本输入&#xff09;3. 设置键盘模式4. 获取当前模式5. 设置键盘关闭时的回调&#xff08;如隐藏键盘&#xff09; 三、使用示例四、自…

opencv(C++) 图像滤波

文章目录 介绍使用低通滤波器对图像进行滤波工作原理均值滤波器(Mean Filter / Box Filter)高斯滤波器(Gaussian Filter)案例实现通过滤波实现图像的下采样工作原理实现案例插值像素值(Interpolating pixel values)双线性插值(Bilinear interpolation)双三次插值(Bicu…

图论学习笔记 4 - 仙人掌图

先扔张图&#xff1a; 为了提前了解我们采用的方法&#xff0c;请先阅读《图论学习笔记 3》。 仙人掌图的定义&#xff1a;一个连通图&#xff0c;且每条边只出现在至多一个环中。 这个图就是仙人掌图。 这个图也是仙人掌图。 而这个图就不是仙人掌图了。 很容易发现&#xf…

华为OD机试真题——洞穴探险(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 200分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

Java设计模式之职责链模式详解

Java设计模式之职责链模式详解 一、职责链模式核心思想 核心目标&#xff1a;将请求的发送者与接收者解耦&#xff0c;使多个对象都有机会处理请求。这些处理者形成链式结构&#xff0c;请求沿链传递直到被处理或到达链尾&#xff0c;如政府审批层层上报机制。 二、职责链模式…

解决WPF短暂的白色闪烁(白色闪屏)

在 WPF 应用程序启动时出现 短暂的白色闪烁&#xff08;白色闪屏&#xff09;&#xff0c;通常是由于以下原因导致的&#xff1a; 主要原因 WPF 默认窗口背景是白色&#xff0c;在加载 UI 之前会短暂显示白色背景。 解决方案 设置窗口背景为透明或黑色&#xff08;推荐&…

《Python基础》第1期:人生苦短,我用Python

介绍 Python 在英语中是蟒蛇的意思&#xff0c;它的 logo 也是两条蟒蛇缠绕在一起。 然而 Python 和蟒蛇实际上没有半点关系。 Python 是由荷兰程序员 Guido van Rossum&#xff08;因为其名字的前三个字母“gui”是中文“龟”的拼音&#xff0c;所以江湖人称“龟叔”&#x…

DiT、 U-Net 与自回归模型的优势

DiT 相对于 U-Net 的优势 全局自注意力 vs. 局部卷积 U-Net 依赖卷积和池化/上采样来逐层扩大感受野&#xff0c;捕捉全局信息需要堆叠很多层或借助跳跃连接&#xff08;skip connections&#xff09;。DiT 在每个分辨率阶段都用 Transformer 模块&#xff08;多头自注意力 ML…

怎么查找idea插件的下载位置,并更改

长期使用 IntelliJ IDEA 时&#xff0c;默认存储在 C 盘的配置文件会持续生成大量缓存和日志文件&#xff0c;可能导致系统盘空间不足。通过修改默认配置文件存储位置&#xff0c;可以有效释放 C 盘空间并提升系统性能。 1&#xff0c;先找到自己idea的下载目录&#xff0c;再打…

IoT/HCIP实验-1/物联网开发平台实验Part2(HCIP-IoT实验手册版)

文章目录 概述产品和设备实例的产品和设备产品和设备的关联单个产品有多个设备为产品创建多个设备产品模型和物模型设备影子&#xff08;远程代理&#xff09; 新建产品模型定义编解码插件开发编解码插件工作原理消息类型与二进制码流添加消息&#xff08;数据上报消息&#xf…

15.进程间通信(一)

一、进程间通信介绍 进程间通信目的&#xff1a; 数据传输&#xff1a;一个进程需要将它的数据发送给另⼀个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xf…

05-jenkins学习之旅-vue前项目部署实践

1、创建被管理项目 2、构建流程说明 jenkins其实就是将服务部署拆分成了&#xff1a; 1、拉取代码(git) 2、打包编译(npm install) 3、自定义脚本(dist复制、执行启动脚本) 4、部署成功后的一些通知等 3、demo配置 3.1、General 3.2 源码管理 添加用户名密码方式如下图 3.2…

服务器中分布式存储数据技术都包含哪些内容?

随着大数据时代的到来&#xff0c;企业和组织对于服务器的存储要求也在不断地增高&#xff0c;传统的存储架构已经无法满足一些大规模的数据存储和处理需求&#xff0c;分布式存储技术应运而生&#xff0c;成为了大数据存储的重要基础设施&#xff0c;下面&#xff0c;就来介绍…