【深度学习】多目标融合算法(六):渐进式分层提取模型PLE(Progressive Layered Extraction)

目录

一、引言

二、PLE(Progressive Layered Extraction,渐进式分层提取模型)

2.1 技术原理

2.2 技术优缺点

2.3 业务代码实践

2.3.1 业务场景与建模

2.3.2 模型代码实现

2.3.3 模型训练与推理测试

2.3.4 打印模型结构 

三、总结


一、引言

上一篇我们讲了PLE的前置模型CGC(Customized Gate Control)定制门控网络,核心思想是在MMoE基础上,为每一个任务tower定制独享专家,使用任务独享专家与共享专家共同决定任务Tower的输入,相比于MMoE仅用Gate门控表征任务Tower的方法,CGC引入独享专家,对任务表征更加全面,又通过共享专家保证关联性。

今天在CGC的基础上,重点讲解PLE(Progressive Layered Extraction)模型,可以理解PLE为CGC的多层堆叠,通过将独享专家、共享专家基于门控网络交叉学习,既能学习独有任务的特异性,又能学习共享信息。

二、PLE(Progressive Layered Extraction,渐进式分层提取模型)

2.1 技术原理

PLE(Progressive Layered Extraction)全称为渐进式分层提取模型,‌是一种改进的多任务学习模型,旨在解决多任务学习中的负迁移和跷跷板现象。PLE模型通过分层提取机制结合共享特征和任务特定特征,逐步优化多任务学习的性能。主要由多层CGC网络堆叠而成,每个CGC网络包含一组共享专家、若干组独立专家,通过对应的共享专家门控、独立专家门控对共享专家组、独立专家组内的多个MLP加权结果平均。

  • 共享专家网络:样本数据分别输入num_shared_experts个专家网络进行推理,每个共享专家网络实际上是一个多层感知机(MLP),输入维度为x,输出维度为output_experts_dim。
  • 独享专家网络:样本数据分别输入num_task_experts个专家网络进行推理,每个共享专家网络实际上是一个多层感知机(MLP),输入维度为x,输出维度为output_experts_dim。
  • 门控网络:样本数据输出各自任务对应的门控网络,每个门控网络可以是一个多层感知机,也可以是一个双层的交叉,主要是为了输出专家网络的加权平均权重。
  • 任务网络:对于每一个Task,将各自对应num_shared_experts个共享专家和num_task_experts个独立专家,基于对应gate门控网络的softmax加权平均,作为各自Task的输入,所有Task的输入统一维度均为output_experts_dim。

2.2 技术优缺点

相较于MMoE网络,CGC为每一个任务tower定制独享专家,实用任务独享专家与共享专家共同决定任务Tower的输入,相比于MMoE仅用Gate门控表征任务Tower的方法,CGC引入独享专家,对任务表征更加全面,又通过共享专家保证关联性。

优点:

  • ‌分层提取结构‌:PLE通过多层提取机制逐步分离共享特征和任务特定特征,避免了传统多任务学习中的过度耦合问题。
  • ‌CGC(Customized Gate Control)‌:每层包含共享专家和任务特定专家,通过门控机制动态分配特征,既保留了共享信息,又增强了任务特定性。
  • ‌任务特定性增强‌:相比传统的多任务学习模型,PLE在每一层都为每个任务引入特定专家,增强了任务之间的解耦,提高了模型对不同任务的适应性。
  • ‌多任务性能提升‌:通过分层结构和门控机制,PLE能在多任务场景中更好地平衡任务间冲突,提升整体性能‌。

缺点: 

  • 相较于DeepSeekMoE的路由方法,PLE专家组合不足。

2.3 业务代码实践

2.3.1 业务场景与建模

我们还是以小红书推荐场景为例,针对一个视频,用户可以点红心(互动),也可以点击视频进行播放(点击),针对互动和点击两个目标进行多目标建模

我们构建一个100维特征输入,2层CGC,第一层CGC包含1组共享专家网络(含2个共享专家),2组独享专家网络(各含2个独享专家),3个门控网络(1个共享门控,2个独立门控),第二层CGC包含1组共享专家网络(含2个共享专家),2组独享专家网络(各含2个独享专家),2个门控网络(2个独立门控),用于建模多目标学习问题,模型架构图如下:

​​​​​​​

如架构图所示,其中有几个注意的点:

  • num_shared_experts + num_task_experts独立Gate的维度等于共享专家的维度(MLP个数,图中为2)加上任务独享专家的维度(MLP个数,图中为2)。
  • num_shared_experts + num_task_experts + num_task_experts:共享Gate的维度等于共享专家的维度(MLP个数,图中为2)加上所有(图中为2组)任务独享专家的维度(MLP个数,图中为2)。
  • output_experts_dim:共享专家、独享专家网络的输出维度和task网络的输入维度相同,task网络承接的是专家网络各维度的加权平均值,experts网络与task网络是直接对应关系。
  • Softmax:Gate门控网络对共享专家和独享专家的偏好权重采用Softmax归一化,保证专家网络加权平均后值域相同

2.3.2 模型代码实现

基于pytorch,实现上述PLE网络架构,如下:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDatasetclass PLEModel(nn.Module):def __init__(self, input_dim, experts_hidden1_dim, experts_hidden2_dim, output_experts_dim, task_hidden1_dim, task_hidden2_dim, output_task1_dim, output_task2_dim, gate_hidden1_dim, gate_hidden2_dim, num_shared_experts, num_task_experts):super(PLEModel, self).__init__()# 初始化函数外使用初始化变量需要赋值,否则默认使用全局变量# 初始化函数内使用初始化变量不需要赋值 self.num_shared_experts = num_shared_expertsself.num_task_experts = num_task_expertsself.output_experts_dim = output_experts_dim# 初始化1层共享专家self.shared_experts_1 = nn.ModuleList([nn.Sequential(nn.Linear(input_dim, experts_hidden1_dim),nn.ReLU(),nn.Linear(experts_hidden1_dim, experts_hidden2_dim),nn.ReLU(),nn.Linear(experts_hidden2_dim, output_experts_dim),nn.ReLU()) for _ in range(num_shared_experts)])# 初始化1层任务1专家self.task1_experts_1 = nn.ModuleList([nn.Sequential(nn.Linear(input_dim, experts_hidden1_dim),nn.ReLU(),nn.Linear(experts_hidden1_dim, experts_hidden2_dim),nn.ReLU(),nn.Linear(experts_hidden2_dim, output_experts_dim),nn.ReLU()) for _ in range(num_task_experts)])# 初始化1层任务2专家self.task2_experts_1 = nn.ModuleList([nn.Sequential(nn.Linear(input_dim, experts_hidden1_dim),nn.ReLU(),nn.Linear(experts_hidden1_dim, experts_hidden2_dim),nn.ReLU(),nn.Linear(experts_hidden2_dim, output_experts_dim),nn.ReLU()) for _ in range(num_task_experts)])# 初始化2层共享专家self.shared_experts_2 = nn.ModuleList([nn.Sequential(nn.Linear(output_experts_dim, experts_hidden1_dim),nn.ReLU(),nn.Linear(experts_hidden1_dim, experts_hidden2_dim),nn.ReLU(),nn.Linear(experts_hidden2_dim, output_experts_dim),nn.ReLU()) for _ in range(num_shared_experts)])# 初始化2层任务1专家self.task1_experts_2 = nn.ModuleList([nn.Sequential(nn.Linear(output_experts_dim, experts_hidden1_dim),nn.ReLU(),nn.Linear(experts_hidden1_dim, experts_hidden2_dim),nn.ReLU(),nn.Linear(experts_hidden2_dim, output_experts_dim),nn.ReLU()) for _ in range(num_task_experts)])# 初始化2层任务2专家self.task2_experts_2 = nn.ModuleList([nn.Sequential(nn.Linear(output_experts_dim, experts_hidden1_dim),nn.ReLU(),nn.Linear(experts_hidden1_dim, experts_hidden2_dim),nn.ReLU(),nn.Linear(experts_hidden2_dim, output_experts_dim),nn.ReLU()) for _ in range(num_task_experts)])# 初始化门控网络1层任务1self.gating1_network_1 = nn.Sequential(nn.Linear(input_dim, gate_hidden1_dim),nn.ReLU(),nn.Linear(gate_hidden1_dim, gate_hidden2_dim),nn.ReLU(),nn.Linear(gate_hidden2_dim, num_shared_experts+num_task_experts),nn.Softmax(dim=1))# 初始化门控网络1层任务2self.gating2_network_1 = nn.Sequential(nn.Linear(input_dim, gate_hidden1_dim),nn.ReLU(),nn.Linear(gate_hidden1_dim, gate_hidden2_dim),nn.ReLU(),nn.Linear(gate_hidden2_dim, num_shared_experts+num_task_experts),nn.Softmax(dim=1))# 初始化1层共享门控self.gating_shared_network_1 = nn.Sequential(nn.Linear(input_dim, gate_hidden1_dim),nn.ReLU(),nn.Linear(gate_hidden1_dim, gate_hidden2_dim),nn.ReLU(),nn.Linear(gate_hidden2_dim, num_shared_experts + num_task_experts + num_task_experts),nn.Softmax(dim=1))# 初始化门控网络2层任务1self.gating1_network_2 = nn.Sequential(nn.Linear(output_experts_dim, gate_hidden1_dim),nn.ReLU(),nn.Linear(gate_hidden1_dim, gate_hidden2_dim),nn.ReLU(),nn.Linear(gate_hidden2_dim, num_shared_experts+num_task_experts),nn.Softmax(dim=1))# 初始化门控网络2层任务2self.gating2_network_2 = nn.Sequential(nn.Linear(output_experts_dim, gate_hidden1_dim),nn.ReLU(),nn.Linear(gate_hidden1_dim, gate_hidden2_dim),nn.ReLU(),nn.Linear(gate_hidden2_dim, num_shared_experts+num_task_experts),nn.Softmax(dim=1))# 定义任务1的输出层self.task1_head = nn.Sequential(nn.Linear(output_experts_dim, task_hidden1_dim),nn.ReLU(),nn.Linear(task_hidden1_dim, task_hidden2_dim),nn.ReLU(),nn.Linear(task_hidden2_dim, output_task1_dim),nn.Sigmoid()) # 定义任务2的输出层self.task2_head = nn.Sequential(nn.Linear(output_experts_dim, task_hidden1_dim),nn.ReLU(),nn.Linear(task_hidden1_dim, task_hidden2_dim),nn.ReLU(),nn.Linear(task_hidden2_dim, output_task2_dim),nn.Sigmoid()) def forward(self, x):#处理第一层#第一层门控gates1 = self.gating1_network_1(x)gates2 = self.gating2_network_1(x)gates_shared = self.gating_shared_network_1(x)#定义第一层输出batch_size, _ = x.shapetask1_expert_inputs = torch.zeros(batch_size, self.output_experts_dim)task2_expert_inputs = torch.zeros(batch_size, self.output_experts_dim)shared_expert_inputs = torch.zeros(batch_size, self.output_experts_dim)#第一层task1、shared、task2专家网络输出task1_experts_1_output_0 = self.task1_experts_1[0](x)task1_experts_1_output_1 = self.task1_experts_1[1](x)shared_experts_1_output_0 = self.shared_experts_1[0](x)shared_experts_1_output_1 = self.shared_experts_1[1](x)task2_experts_1_output_0 = self.task2_experts_1[0](x)task2_experts_1_output_1 = self.task2_experts_1[1](x)#第一层共享专家网络输出shared_expert_inputs += task1_experts_1_output_0 * gates_shared[:, 0].unsqueeze(1)shared_expert_inputs += task1_experts_1_output_1 * gates_shared[:, 1].unsqueeze(1)shared_expert_inputs += shared_experts_1_output_0 * gates_shared[:, 2].unsqueeze(1)shared_expert_inputs += shared_experts_1_output_1 * gates_shared[:, 3].unsqueeze(1)shared_expert_inputs += task2_experts_1_output_0 * gates_shared[:, 4].unsqueeze(1)shared_expert_inputs += task2_experts_1_output_1 * gates_shared[:, 5].unsqueeze(1)#第一层任务1网络输出task1_expert_inputs += task1_experts_1_output_0 * gates1[:, 0].unsqueeze(1)task1_expert_inputs += task1_experts_1_output_1 * gates1[:, 1].unsqueeze(1)task1_expert_inputs += shared_experts_1_output_0 * gates1[:, 2].unsqueeze(1)task1_expert_inputs += shared_experts_1_output_1 * gates1[:, 3].unsqueeze(1)#第一层任务2网络输出task2_expert_inputs += shared_experts_1_output_0 * gates2[:, 0].unsqueeze(1)task2_expert_inputs += shared_experts_1_output_1 * gates2[:, 1].unsqueeze(1)task2_expert_inputs += task2_experts_1_output_0 * gates2[:, 2].unsqueeze(1)task2_expert_inputs += task2_experts_1_output_1 * gates2[:, 3].unsqueeze(1)#处理第二层gates1 = self.gating1_network_2(task1_expert_inputs)gates2 = self.gating2_network_2(task2_expert_inputs)#定义第二层输出task1_inputs = torch.zeros(batch_size, self.output_experts_dim)task2_inputs = torch.zeros(batch_size, self.output_experts_dim)#第二层task1、shared、task2专家网络输出task1_experts_2_output_0 = self.task1_experts_2[0](task1_expert_inputs)task1_experts_2_output_1 = self.task1_experts_2[1](task1_expert_inputs)shared_experts_2_output_0 = self.shared_experts_2[0](shared_expert_inputs)shared_experts_2_output_1 = self.shared_experts_2[1](shared_expert_inputs)task2_experts_2_output_0 = self.task2_experts_2[0](task2_expert_inputs)task2_experts_2_output_1 = self.task2_experts_2[1](task2_expert_inputs)#第二层任务1网络输出task1_inputs += task1_experts_2_output_0 * gates1[:, 0].unsqueeze(1)task1_inputs += task1_experts_2_output_1 * gates1[:, 1].unsqueeze(1)task1_inputs += shared_experts_2_output_0 * gates1[:, 2].unsqueeze(1)task1_inputs += shared_experts_2_output_1 * gates1[:, 3].unsqueeze(1)#第二层任务2网络输出task2_inputs += shared_experts_2_output_0 * gates2[:, 0].unsqueeze(1)task2_inputs += shared_experts_2_output_1 * gates2[:, 1].unsqueeze(1)task2_inputs += task2_experts_2_output_0 * gates2[:, 2].unsqueeze(1)task2_inputs += task2_experts_2_output_1 * gates2[:, 3].unsqueeze(1)task1_outputs = self.task1_head(task1_inputs)task2_outputs = self.task2_head(task2_inputs)return task1_outputs, task2_outputs# 实例化模型对象
experts_hidden1_dim = 64
experts_hidden2_dim = 32
output_experts_dim = 16
gate_hidden1_dim = 16
gate_hidden2_dim = 8
task_hidden1_dim = 32
task_hidden2_dim = 16
output_task1_dim = 1
output_task2_dim = 1
num_shared_experts = 2
num_task_experts = 2# 构造虚拟样本数据
torch.manual_seed(42)  # 设置随机种子以保证结果可重复
input_dim = 100
num_samples = 1024
X_train = torch.randint(0, 2, (num_samples, input_dim)).float()
y_train_task1 = torch.rand(num_samples, output_task1_dim)  # 假设任务1的输出维度为1
y_train_task2 = torch.rand(num_samples, output_task2_dim)  # 假设任务2的输出维度为1# 创建数据加载器
train_dataset = TensorDataset(X_train, y_train_task1, y_train_task2)
train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True)model = PLEModel(input_dim, experts_hidden1_dim, experts_hidden2_dim, output_experts_dim, task_hidden1_dim, task_hidden2_dim, output_task1_dim, output_task2_dim, gate_hidden1_dim, gate_hidden2_dim, num_shared_experts, num_task_experts)# 定义损失函数和优化器
criterion_task1 = nn.MSELoss()
criterion_task2 = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 训练循环
num_epochs = 100
for epoch in range(num_epochs):model.train()running_loss = 0.0for batch_idx, (X_batch, y_task1_batch, y_task2_batch) in enumerate(train_loader):# 前向传播: 获取预测值#print(batch_idx, X_batch )#print(f'Epoch [{epoch+1}/{num_epochs}-{batch_idx}], Loss: {running_loss/len(train_loader):.4f}')outputs_task1, outputs_task2 = model(X_batch)# 计算每个任务的损失loss_task1 = criterion_task1(outputs_task1, y_task1_batch)loss_task2 = criterion_task2(outputs_task2, y_task2_batch)total_loss = loss_task1 + loss_task2# 反向传播和优化optimizer.zero_grad()total_loss.backward()optimizer.step()running_loss += total_loss.item()if epoch % 10 == 0:print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/len(train_loader):.4f}')print(model)
#for param_tensor in model.state_dict():
#    print(param_tensor, "\t", model.state_dict()[param_tensor].size())
# 模型预测
model.eval()
with torch.no_grad():test_input = torch.randint(0, 2, (1, input_dim)).float()  # 构造一个测试样本pred_task1, pred_task2 = model(test_input)print(f'互动目标预测结果: {pred_task1}')print(f'点击目标预测结果: {pred_task2}')

相比于上一篇CGC中的代码,PLE代码更加复杂,其中有很多地方可以复用与简化。

2.3.3 模型训练与推理测试

运行上述代码,模型启动训练,Loss逐渐收敛,测试结果如下:

2.3.4 打印模型结构 ​​​​​​​

PLEModel((shared_experts_1): ModuleList((0-1): 2 x Sequential((0): Linear(in_features=100, out_features=64, bias=True)(1): ReLU()(2): Linear(in_features=64, out_features=32, bias=True)(3): ReLU()(4): Linear(in_features=32, out_features=16, bias=True)(5): ReLU()))(task1_experts_1): ModuleList((0-1): 2 x Sequential((0): Linear(in_features=100, out_features=64, bias=True)(1): ReLU()(2): Linear(in_features=64, out_features=32, bias=True)(3): ReLU()(4): Linear(in_features=32, out_features=16, bias=True)(5): ReLU()))(task2_experts_1): ModuleList((0-1): 2 x Sequential((0): Linear(in_features=100, out_features=64, bias=True)(1): ReLU()(2): Linear(in_features=64, out_features=32, bias=True)(3): ReLU()(4): Linear(in_features=32, out_features=16, bias=True)(5): ReLU()))(shared_experts_2): ModuleList((0-1): 2 x Sequential((0): Linear(in_features=16, out_features=64, bias=True)(1): ReLU()(2): Linear(in_features=64, out_features=32, bias=True)(3): ReLU()(4): Linear(in_features=32, out_features=16, bias=True)(5): ReLU()))(task1_experts_2): ModuleList((0-1): 2 x Sequential((0): Linear(in_features=16, out_features=64, bias=True)(1): ReLU()(2): Linear(in_features=64, out_features=32, bias=True)(3): ReLU()(4): Linear(in_features=32, out_features=16, bias=True)(5): ReLU()))(task2_experts_2): ModuleList((0-1): 2 x Sequential((0): Linear(in_features=16, out_features=64, bias=True)(1): ReLU()(2): Linear(in_features=64, out_features=32, bias=True)(3): ReLU()(4): Linear(in_features=32, out_features=16, bias=True)(5): ReLU()))(gating1_network_1): Sequential((0): Linear(in_features=100, out_features=16, bias=True)(1): ReLU()(2): Linear(in_features=16, out_features=8, bias=True)(3): ReLU()(4): Linear(in_features=8, out_features=4, bias=True)(5): Softmax(dim=1))(gating2_network_1): Sequential((0): Linear(in_features=100, out_features=16, bias=True)(1): ReLU()(2): Linear(in_features=16, out_features=8, bias=True)(3): ReLU()(4): Linear(in_features=8, out_features=4, bias=True)(5): Softmax(dim=1))(gating_shared_network_1): Sequential((0): Linear(in_features=100, out_features=16, bias=True)(1): ReLU()(2): Linear(in_features=16, out_features=8, bias=True)(3): ReLU()(4): Linear(in_features=8, out_features=6, bias=True)(5): Softmax(dim=1))(gating1_network_2): Sequential((0): Linear(in_features=16, out_features=16, bias=True)(1): ReLU()(2): Linear(in_features=16, out_features=8, bias=True)(3): ReLU()(4): Linear(in_features=8, out_features=4, bias=True)(5): Softmax(dim=1))(gating2_network_2): Sequential((0): Linear(in_features=16, out_features=16, bias=True)(1): ReLU()(2): Linear(in_features=16, out_features=8, bias=True)(3): ReLU()(4): Linear(in_features=8, out_features=4, bias=True)(5): Softmax(dim=1))(task1_head): Sequential((0): Linear(in_features=16, out_features=32, bias=True)(1): ReLU()(2): Linear(in_features=32, out_features=16, bias=True)(3): ReLU()(4): Linear(in_features=16, out_features=1, bias=True)(5): Sigmoid())(task2_head): Sequential((0): Linear(in_features=16, out_features=32, bias=True)(1): ReLU()(2): Linear(in_features=32, out_features=16, bias=True)(3): ReLU()(4): Linear(in_features=16, out_features=1, bias=True)(5): Sigmoid())
)

三、总结

本文详细介绍了PLE多任务模型的算法原理、算法优势,并以小红书业务场景为例,构建PLE网络结构并使用pytorch代码实现对应的网络结构、训练流程。相比于CGC,PLE采用分层提取结构,每一层中采用共享门控、独享门控机制对共享专家组、独享专家组进行联合学习,增强了任务之间的解耦,提高了模型对不同任务的适应性,能在多任务场景中更好地平衡任务间冲突,提升多目标学习效果。

如果您还有时间,欢迎阅读本专栏的其他文章:

【深度学习】多目标融合算法(一):样本Loss加权(Sample Loss Reweight)

【深度学习】多目标融合算法(二):底部共享多任务模型(Shared-Bottom Multi-task Model) ​​​​​​​

【深度学习】多目标融合算法(三):混合专家网络MOE(Mixture-of-Experts) 

【深度学习】多目标融合算法(四):多门混合专家网络MMOE(Multi-gate Mixture-of-Experts)​​​​​​​

【深度学习】多目标融合算法(五):定制门控网络CGC(Customized Gate Control) 

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

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

相关文章

【Java开发日记】如何使用Java开发在线生成 pdf 文档

一、介绍 在实际的业务开发的时候,研发人员往往会碰到很多这样的一些场景,需要提供相关的电子凭证信息给用户,例如网银/支付宝/微信购物支付的电子发票、订单的库存打印单、各种电子签署合同等等,以方便用…

Oracle 11g 单实例使用+asm修改主机名导致ORA-29701 故障分析

解决 把服务器名修改为原来的,重启服务器。 故障 建表空间失败。 分析 查看告警日志 ORA-1119 signalled during: create tablespace splex datafile ‘DATA’ size 2000M… Tue May 20 18:04:28 2025 create tablespace splex datafile ‘DATA/option/dataf…

消息队列的使用

使用内存队列来处理基于内存的【生产者-消费者】场景 思考和使用Disruptor Disruptor可以实现单个或多个生产者生产消息,单个或多个消费者消息,且消费者之间可以存在消费消息的依赖关系 使用Disruptor需要结合业务特性,设计要灵活 什么业务…

《帝国时代1》游戏秘籍

资源类 PEPPERONI PIZZA:获得 1000 食物。COINAGE:获得 1000 金。WOODSTOCK:获得 1000 木头。QUARRY:获得 1000 石头。 建筑与生产类 STEROIDS:快速建筑。 地图类 REVEAL MAP:显示所有地图。NO FOG&#xf…

使用JSP踩过的坑

虽然说jsp已经过时了,但是有时维护比较老的项目还是需要的。 下面说下,我使用jsp踩过的坑: 1.关于打印输出 在jsp中输出使用 out.println("hello");而不是 System.out.println("hello");如果在定义函数部分需要打印…

redis集群创建时手动指定主从关系的方法

适用场景: 创建主从关系时默认参数 --cluster-replicas 1 会自动分配从节点。 为了能精确控制 Redis Cluster 的主从拓扑结构,我们通过 Redis Cluster 的手动分片功能来实现 一、手动指定主从关系的方法 使用 redis-cli --cluster-replicas 0 先创建纯…

ROS合集(七)SVIn2声呐模块分析

文章目录 一、整体思想二、具体误差建模流程三、总结明确(预测值与观测值)四、选点逻辑五、Sonar 数据处理流水线1. ROS Launch 配置(imagenex831l.launch)2. SonarNode 节点(sonar_node.py)3. Subscriber …

Python爬虫实战:研究PySpider框架相关技术

1. 引言 1.1 研究背景与意义 网络爬虫作为互联网数据采集的重要工具,在信息检索、舆情分析、市场调研等领域发挥着重要作用。随着互联网信息的爆炸式增长,如何高效、稳定地获取所需数据成为了一个关键挑战。PySpider 作为一款功能强大的 Python 爬虫框架,提供了丰富的功能…

《大模型开源与闭源的深度博弈:科技新生态下的权衡与抉择》

开源智能体大模型的核心魅力,在于它构建起了一个全球开发者共同参与的超级协作网络。想象一下,来自世界各个角落的开发者、研究者,无论身处繁华都市还是偏远小镇,只要心怀对技术的热爱与追求,就能加入到这场技术狂欢中…

大数据模型对陌生场景图像的识别能力研究 —— 以 DEEPSEEK 私有化部署模型为例

摘要 本研究聚焦于已训练的大数据模型能否识别未包含在样本数据集中的陌生场景图像这一问题,以 DEEPSEEK 私有化部署模型为研究对象,结合机器学习理论,分析模型识别陌生场景图像的影响因素,并通过理论探讨与实际应用场景分析&…

STM32——从点灯到传感器控制

STM32基础外设开发:从点灯到传感器控制 一、前言 本篇文章总结STM32F10x系列基础外设开发实例,涵盖GPIO控制、按键检测、传感器应用等。所有代码基于标准库开发,适合STM32初学者参考。 二、硬件准备 STM32F10x系列开发板LED模块有源蜂鸣器…

[特殊字符] 使用增量同步+MQ机制将用户数据同步到Elasticsearch

在开发用户搜索功能时,我们通常会将用户信息存储到 Elasticsearch(简称 ES) 中,以提高搜索效率。本篇文章将详细介绍我们是如何实现 MySQL 到 Elasticsearch 的增量同步,以及如何通过 MQ 消息队列实现用户信息实时更新…

MyBatis缓存机制全解析

在MyBatis中,缓存分为一级缓存和二级缓存,它们的主要目的是减少数据库的访问次数,提高查询效率。下面简述这两种缓存的工作原理: 一、 一级缓存(SqlSession级别的缓存) 一级缓存是MyBatis默认开启的缓存机…

【短距离通信】【WiFi】WiFi7关键技术之4096-QAM、MRU

目录 3. 4096-QAM 3.1 4096-QAM 3.2 QAM 的阶数越高越好吗? 4. MRU 4.1 OFDMA 和 RU 4.2 MRU 资源分配 3. 4096-QAM 摘要 本章主要介绍了Wi-Fi 7引入的4096-QAM对数据传输速率的提升。 3.1 4096-QAM 对速率的提升 Wi-Fi 标准一直致力于提升数据传输速率&a…

【二刷力扣】【力扣热题100】今天的题目是:283.移动零

题目: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输…

机器学习中的多GPU训练模式

文章目录 一、数据并行(Data Parallelism)二、模型并行(Model Parallelism)1. 模型并行2. 张量并行(Tensor Parallelism) 三、流水线并行(Pipeline Parallelism)四、混合并行&#x…

《JavaScript 性能优化:从原理到实战的全面指南》

《JavaScript 性能优化:从原理到实战的全面指南》 一、JavaScript 性能优化基础理论 在深入探讨 JavaScript 性能优化技术之前,我们需要明白JavaScript 的执行机制和性能瓶颈产生的根本原因。JavaScript 是一种单线程、非阻塞的脚本语言,其…

选择合适的Azure数据库监控工具

Azure云为组织提供了众多服务,使其能够无缝运行应用程序、Web服务和服务器部署,其中包括云端数据库部署。Azure数据库能够与云应用程序实现无缝集成,具备可靠、易扩展和易管理的特性,不仅能提升数据库可用性与性能,同时…

9.4在 VS Code 中配置 Maven

在 VS Code 中配置 Maven 需要完成 Maven 环境安装 一、安装 Maven(如果未安装) 下载 Maven 访问 Apache Maven 官网,下载最新版本的 Maven(如apache-maven-3.9.9-bin.zip)。 解压文件 将下载的 ZIP 文件解压到本地目…

影刀自动化流程复用技巧:流程复用

草莓时刻会创建一个新的空白流程。但是很多时候需要复用过往基础流程,在此基础上进行修改即可。而而不是重新创建基础流程。 为了解决这个问题,我们需要了解一下影刀流程的基础结构。 影刀流程基础结构概览 影刀自动化流程的基础结构主要包括几个关键组…