深度学习推荐系统(四)WideDeep模型及其在Criteo数据集上的应用

深度学习推荐系统(四)Wide&Deep模型及其在Criteo数据集上的应用

在2016年, 随着微软的Deep Crossing, 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出, 推荐系统全面进入了深度学习时代, 时至今日, 依然是主流。 推荐模型主要有下面两个进展:

  • 与传统的机器学习模型相比, 深度学习模型的表达能力更强, 能够挖掘更多数据中隐藏的模式

  • 深度学习模型结构非常灵活, 能够根据业务场景和数据特点, 灵活调整模型结构, 使模型与应用场景完美契合

深度学习推荐模型,以多层感知机(MLP)为核心, 通过改变神经网络结构进行演化。

在这里插入图片描述

1 Wide&Deep模型原理

1.1 Wide&Deep模型提出的背景

  • 简单的模型, 比如协同过滤, 逻辑回归等,能够从历史数据中学习到高频共现的特征组合能力, 但是泛化能力不足

  • 而像矩阵分解, embedding再加上深度学习网络, 能够利用相关性的传递性去探索历史数据中未出现的特征组合, 挖掘数据潜在的关联模式, 但是对于某些特定的场景(数据分布长尾, 共现矩阵稀疏高秩)很难有效学习低纬度的表示, 造成推荐的过渡泛化。

因此,在2016年,Google提出Wide&Deep模型,将线性模型与DNN很好的结合起来,在提高模型泛化能力的同时,兼顾模型的记忆性。Wide&Deep这种线性模型与DNN的并行连接模式,后来成为推荐领域的经典模式, 奠定了后面深度学习模型的基础,是一个里程碑式的改变。

1.2 模型的记忆能力和泛化能力

1.2.1 记忆能力的理解

记忆能力可以被理解为模型直接学习并利用历史数据中物品和特征的共现频率的能力。

一般来说, 协同过滤、逻辑回归这种都具有较强的“记忆能力”, 由于这类模型比较简单, 原始数据往往可以直接影响推荐结果, 产生类似于如果点击A, 就推荐B这类规则的推荐, 相当于模型直接记住了历史数据的分布特点, 并利用这些记忆进行推荐。

以谷歌APP推荐场景为例理解一下:

假设在Google Play推荐模型训练过程中,设置如下组合特征:AND(user_installed_app=netflix,
impression_app=pandora),它代表了用户安装了netflix这款应用,而且曾在应用商店中看到过pandora这款应用。

如果以“最终是否安装pandora”为标签,可以轻而易举的统计netfilx&pandora这个特征与安装pandora标签之间的共现频率。比如二者的共现频率高达10%,那么在设计模型的时候,就希望模型只要发现这一特征,就推荐pandora这款应用(像一个深刻记忆点一样印在脑海),这就是所谓的“记忆能力”。

像逻辑回归这样的模型,发现这样的强特,就会加大权重,对这种特征直接记忆。
但是对于神经网络这样的模型来说,特征会被多层处理,不断与其他特征进行交叉,因此模型这个强特记忆反而没有简单模型的深刻。

1.2.2 泛化能力的理解

泛化能力可以被理解为模型传递特征的相关性, 以及发掘稀疏甚至从未出现过的稀有特征与最终标签相关性的能力

比如矩阵分解, embedding等, 使得数据稀少的用户或者物品也能生成隐向量, 从而获得由数据支撑的推荐得分, 将全局数据传递到了稀疏物品上, 提高泛化能力。

再比如神经网络, 通过特征自动组合, 可以深度发掘数据中的潜在模式,提高泛化等。

所以, Wide&Deep模型的直接动机就是将两者进行融合, 使得模型既有了简单模型的这种“记忆能力”, 也有了神经网络的这种“泛化能力”, 这也是记忆与泛化结合的伟大模式的初始尝试。

1.3 Wide&Deep的模型结构

在这里插入图片描述

经典的W&D的模型如图所示:

  • 左边的是wide部分, 也就是一个简单的线性模型, 右边是deep部分, 一个经典的DNN模型

  • W&D模型把单输入层的Wide部分Embedding+多层的全连接的部分(deep部分)连接起来, 一起输入最终的输出层得到预测结果

  • 单层的wide层善于处理大量的稀疏的id类特征, Deep部分利用深层的特征交叉, 挖掘在特征背后的数据模式。 最终, 利用逻辑回归, 输出层部分和Deep组合起来, 形成统一的模型。

1.3.1 Wide部分

在这里插入图片描述

  • 对于wide部分训练时候使用的优化器是带正则的FTRL算法(Follow-the-regularized-leader),可以把FTRL当作一个稀疏性很好,精度又不错的随机梯度下降方法, 该算法是非常注重模型稀疏性质的。

  • 也就是说W&D模型采用L1 FTRL是想让Wide部分变得更加的稀疏,即Wide部分的大部分参数都为0,这就大大压缩了模型权重及特征向量的维度。

  • Wide部分模型训练完之后留下来的特征都是非常重要的,模型的“记忆能力”可以理解为发现"直接的",“暴力的”,“显然的”关联规则的能力

1.3.2 Deep部分

  • Deep部分主要是一个Embedding+MLP的神经网络模型

  • 大规模稀疏特征通过embedding转化为低维密集型特征。然后特征进行拼接输入到MLP中,挖掘藏在特征背后的数据模式。

  • 输入的特征有两类, 一类是数值型特征, 一类是类别型特征(经过embedding)。

  • DNN模型随着层数的增加,中间的特征就越抽象,也就提高了模型的泛化能力。

  • 对于Deep部分的DNN模型作者使用了深度学习常用的优化器AdaGrad,这也是为了使得模型可以得到更精确的解。

1.3.3 Wide&Deep的模型详细结构

在这里插入图片描述

从上图我们可以详细地了解Google Play推荐团队设计的 Wide&Deep 模型到底将哪些特征作为 Deep 部分的输入,将哪些特征作为 Wide 部分的输入。

  • Wide 部分的输入仅仅是已安装应用和曝光应用两类特征,其中已安装应用代表用户的历史行为,而曝光应用代表当前的待推荐应用。选择这两类特征的原因是充分发挥 Wide部分记忆能力强的优势。

  • Deep 部分的输入是全量的特征向量,包括用户年龄 (Age )、已安装应用数量(#App Installs )、设备类型(Device Class )、已安装应用(User Installed App)、曝光应用(Impression App)等特征。已安装应用、曝光应用等类别型特征,需要经过 Embedding 层输人连接层(Concatenated Embedding),拼接成1200维的再依次经过3层ReLU全连接层,最终输入 LogLoss 输出层Embedding向量。

1.4 Wide&Deep模型代码

import torch.nn as nn
import torch.nn.functional as F
import torchclass Linear(nn.Module):"""Linear part"""def __init__(self, input_dim):super(Linear, self).__init__()self.linear = nn.Linear(in_features=input_dim, out_features=1)def forward(self, x):return self.linear(x)class Dnn(nn.Module):"""Dnn part"""def __init__(self, hidden_units, dropout=0.5):"""hidden_units: 列表, 每个元素表示每一层的神经单元个数, 比如[256, 128, 64], 两层网络, 第一层神经单元128, 第二层64, 第一个维度是输入维度dropout: 失活率"""super(Dnn, self).__init__()self.dnn_network = nn.ModuleList([nn.Linear(layer[0], layer[1]) for layer in list(zip(hidden_units[:-1], hidden_units[1:]))])self.dropout = nn.Dropout(p=dropout)def forward(self, x):for linear in self.dnn_network:x = linear(x)x = F.relu(x)x = self.dropout(x)return x'''
WideDeep模型:主要包括Wide部分和Deep部分
'''
class WideDeep(nn.Module):def __init__(self, feature_info, hidden_units, embed_dim=8):"""DeepCrossing:feature_info: 特征信息(数值特征, 类别特征, 类别特征embedding映射)hidden_units: 列表, 隐藏单元dropout: Dropout层的失活比例embed_dim: embedding维度"""super(WideDeep, self).__init__()self.dense_features, self.sparse_features, self.sparse_features_map = feature_info# embedding层, 这里需要一个列表的形式, 因为每个类别特征都需要embeddingself.embed_layers = nn.ModuleDict({'embed_' + str(key): nn.Embedding(num_embeddings=val, embedding_dim=embed_dim)for key, val in self.sparse_features_map.items()})# 统计embedding_dim的总维度# 一个离散型(类别型)变量 通过embedding层变为8纬embed_dim_sum = sum([embed_dim] * len(self.sparse_features))# 总维度 = 数值型特征的纬度 + 离散型变量经过embedding后的纬度dim_sum = len(self.dense_features) + embed_dim_sumhidden_units.insert(0, dim_sum)# dnn网络self.dnn_network = Dnn(hidden_units)# 线性层self.linear = Linear(input_dim=len(self.dense_features))# 最终的线性层self.final_linear = nn.Linear(hidden_units[-1], 1)def forward(self, x):# 1、先把输入向量x分成两部分处理、因为数值型和类别型的处理方式不一样dense_input, sparse_inputs = x[:, :len(self.dense_features)], x[:, len(self.dense_features):]# 2、转换为long形sparse_inputs = sparse_inputs.long()# 2、不同的类别特征分别embeddingsparse_embeds = [self.embed_layers['embed_' + key](sparse_inputs[:, i]) for key, i inzip(self.sparse_features_map.keys(), range(sparse_inputs.shape[1]))]# 3、把类别型特征进行拼接,即emdedding后,由3行转换为1行sparse_embeds = torch.cat(sparse_embeds, axis=-1)# 4、数值型和类别型特征进行拼接dnn_input = torch.cat([sparse_embeds, dense_input], axis=-1)# Wide部分,使用的特征为数值型类型wide_out = self.linear(dense_input)# Deep部分,使用全部特征deep_out = self.dnn_network(dnn_input)deep_out = self.final_linear(deep_out)# out  将Wide部分的输出和Deep部分的输出进行合并outputs = F.sigmoid(0.5 * (wide_out + deep_out))return outputsif __name__ == '__main__':x = torch.rand(size=(1, 5), dtype=torch.float32)feature_info = [['I1', 'I2'],  # 连续性特征['C1', 'C2', 'C3'],  # 离散型特征{'C1': 20,'C2': 20,'C3': 20}]# 建立模型hidden_units = [256, 128, 64]net = WideDeep(feature_info, hidden_units)print(net)print(net(x))
WideDeep((embed_layers): ModuleDict((embed_C1): Embedding(20, 8)(embed_C2): Embedding(20, 8)(embed_C3): Embedding(20, 8))(dnn_network): Dnn((dnn_network): ModuleList((0): Linear(in_features=26, out_features=256, bias=True)(1): Linear(in_features=256, out_features=128, bias=True)(2): Linear(in_features=128, out_features=64, bias=True))(dropout): Dropout(p=0.5, inplace=False))(linear): Linear((linear): Linear(in_features=2, out_features=1, bias=True))(final_linear): Linear(in_features=64, out_features=1, bias=True)
)
tensor([[0.6531]], grad_fn=<SigmoidBackward0>)

2 Wide&Deep模型在Criteo数据集的应用

数据的预处理及一些函数或类可以参考:

深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用

2.1 准备训练数据

import pandas as pdimport torch
from torch.utils.data import TensorDataset, Dataset, DataLoaderimport torch.nn as nn
from sklearn.metrics import auc, roc_auc_score, roc_curveimport warnings
warnings.filterwarnings('ignore')
# 封装为函数
def prepared_data(file_path):# 读入训练集,验证集和测试集train_set = pd.read_csv(file_path + 'train_set.csv')val_set = pd.read_csv(file_path + 'val_set.csv')test_set = pd.read_csv(file_path + 'test.csv')# 这里需要把特征分成数值型和离散型# 因为后面的模型里面离散型的特征需要embedding, 而数值型的特征直接进入了stacking层, 处理方式会不一样data_df = pd.concat((train_set, val_set, test_set))# 数值型特征直接放入stacking层dense_features = ['I' + str(i) for i in range(1, 14)]# 离散型特征需要需要进行embedding处理sparse_features = ['C' + str(i) for i in range(1, 27)]# 定义一个稀疏特征的embedding映射, 字典{key: value},# key表示每个稀疏特征, value表示数据集data_df对应列的不同取值个数, 作为embedding输入维度sparse_feas_map = {}for key in sparse_features:sparse_feas_map[key] = data_df[key].nunique()feature_info = [dense_features, sparse_features, sparse_feas_map]  # 这里把特征信息进行封装, 建立模型的时候作为参数传入# 把数据构建成数据管道dl_train_dataset = TensorDataset(# 特征信息torch.tensor(train_set.drop(columns='Label').values).float(),# 标签信息torch.tensor(train_set['Label'].values).float())dl_val_dataset = TensorDataset(# 特征信息torch.tensor(val_set.drop(columns='Label').values).float(),# 标签信息torch.tensor(val_set['Label'].values).float())dl_train = DataLoader(dl_train_dataset, shuffle=True, batch_size=16)dl_vaild = DataLoader(dl_val_dataset, shuffle=True, batch_size=16)return feature_info,dl_train,dl_vaild,test_set
file_path = './preprocessed_data/'feature_info,dl_train,dl_vaild,test_set = prepared_data(file_path)

2.2 建立Wide&Deep模型

from _01_wide_deep import WideDeephidden_units = [256, 128, 64]
net = WideDeep(feature_info, hidden_units)

2.3 模型的训练

from AnimatorClass import Animator
from TimerClass import Timer# 模型的相关设置
def metric_func(y_pred, y_true):pred = y_pred.datay = y_true.datareturn roc_auc_score(y, pred)def try_gpu(i=0):if torch.cuda.device_count() >= i + 1:return torch.device(f'cuda:{i}')return torch.device('cpu')def train_ch(net, dl_train, dl_vaild, num_epochs, lr, device):"""⽤GPU训练模型"""print('training on', device)net.to(device)# 二值交叉熵损失loss_func = nn.BCELoss()# 注意:这里没有使用原理提到的优化器optimizer = torch.optim.Adam(params=net.parameters(), lr=lr)animator = Animator(xlabel='epoch', xlim=[1, num_epochs],legend=['train loss', 'train auc', 'val loss', 'val auc'],figsize=(8.0, 6.0))timer, num_batches = Timer(), len(dl_train)log_step_freq = 10for epoch in range(1, num_epochs + 1):# 训练阶段net.train()loss_sum = 0.0metric_sum = 0.0for step, (features, labels) in enumerate(dl_train, 1):timer.start()# 梯度清零optimizer.zero_grad()# 正向传播predictions = net(features)loss = loss_func(predictions, labels.unsqueeze(1) )try:          # 这里就是如果当前批次里面的y只有一个类别, 跳过去metric = metric_func(predictions, labels)except ValueError:pass# 反向传播求梯度loss.backward()optimizer.step()timer.stop()# 打印batch级别日志loss_sum += loss.item()metric_sum += metric.item()if step % log_step_freq == 0:animator.add(epoch + step / num_batches,(loss_sum/step, metric_sum/step, None, None))# 验证阶段net.eval()val_loss_sum = 0.0val_metric_sum = 0.0for val_step, (features, labels) in enumerate(dl_vaild, 1):with torch.no_grad():predictions = net(features)val_loss = loss_func(predictions, labels.unsqueeze(1))try:val_metric = metric_func(predictions, labels)except ValueError:passval_loss_sum += val_loss.item()val_metric_sum += val_metric.item()if val_step % log_step_freq == 0:animator.add(epoch + val_step / num_batches, (None,None,val_loss_sum / val_step , val_metric_sum / val_step))print(f'final: loss {loss_sum/len(dl_train):.3f}, auc {metric_sum/len(dl_train):.3f},'f' val loss {val_loss_sum/len(dl_vaild):.3f}, val auc {val_metric_sum/len(dl_vaild):.3f}')print(f'{num_batches * num_epochs / timer.sum():.1f} examples/sec on {str(device)}')
lr, num_epochs = 0.001, 10
# 其实发生了过拟合
train_ch(net, dl_train, dl_vaild, num_epochs, lr, try_gpu())

在这里插入图片描述

2.4 模型的预测

y_pred_probs = net(torch.tensor(test_set.values).float())
y_pred = torch.where(y_pred_probs>0.5,torch.ones_like(y_pred_probs),torch.zeros_like(y_pred_probs)
)
y_pred.data[:10]

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

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

相关文章

聚焦磷酸铁锂产线革新,宏工科技一站式解决方案

兼顾了低成本与安全性两大属性&#xff0c;磷酸铁锂市场在全球范围内持续升温&#xff0c;并有望保持较高的景气度。巨大的需求空间之下&#xff0c;行业对于锂电装备企业的自动化与智能化水平、整线交付能力、产品效率与稳定性等均提出了新的要求。 以宏工科技股份有限公司&a…

C#通过ModbusTcp协议读写西门子PLC中的浮点数

一、Modbus TCP通信概述 MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列通讯协议的派生产品&#xff0c;显而易见&#xff0c;它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用用途是为诸如PLC&#xff0c;I/…

LiveGBS流媒体平台GB/T28181功能-支持数据库切换为高斯数据库信创瀚高数据信创数据库

LiveGBS流媒体平台GB/T28181功能-支持数据库切换为高斯数据库信创瀚高数据信创数据库 1、如何配置切换高斯数据库&#xff1f;2、如何配置切换信创瀚高数据库&#xff1f;3、搭建GB28181视频直播平台 1、如何配置切换高斯数据库&#xff1f; livecms.ini -> [db]下面添加配…

华为Mate60低调发布,你所不知道的高调真相?

华为Mate60 pro 这两天的劲爆新闻想必各位早已知晓&#xff0c;那就是华为Mate60真的来了&#xff01;&#xff01;&#xff01;并且此款手机搭载了最新国产麒麟9000s芯片&#xff0c;该芯片重新定义了手机性能的巅峰。不仅在Geekbench测试中表现出色&#xff0c;还在实际应用…

成都瀚网科技有限公司:抖店的评论会消失吗?

抖店是抖音推出的电子商务平台。很多用户在购物后都会对产品进行评价。但有时用户可能会发现抖店评论缺失&#xff0c;让用户产生一些疑惑和困惑。本文将围绕这个问题提供一些答案和解决方案。 1.为什么抖店评论不见了&#xff1f; 首先需要明确的是&#xff0c;抖店评论消失可…

单值二叉树

目录 题目题目要求示例 解答方法一、实现思路时间复杂度和空间复杂度代码 方法二、实现思路时间复杂度和空间复杂度代码 题目 单值二叉树 题目要求 题目链接 示例 解答 方法一、 递归 实现思路 时间复杂度和空间复杂度 时间复杂度&#xff1a;O(N) 空间复杂度&#xf…

Jenkins详解(三)

Jenkins详解(三) 目录 Jenkins详解(三) 1、Jenkins介绍2、Jenkins CI/CD 流程3、部署环境 3.1 环境准备3.2 安装GitLab3.3 初始化GitLab3.4 GitLab中文社区版补丁包安装3.5 修改GitLab配置文件/etc/gitlab/gitlab.rb3.6 在宿主机输入 http://192.168.200.26:88 地址就可以访问了…

什么是AJAX?如何使用原生JavaScript搭建AJAX请求?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;⭐ 原生JavaScript中的AJAX请求1. 创建XMLHttpRequest对象2. 配置请求3. 设置回调函数4. 发送请求 ⭐ 完整示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开…

实现Android APK瘦身99.99%

摘要&#xff1a; 如何瘦身是 APK 的重要优化技术。APK 在安装和更新时都需要经过网络下载到设备&#xff0c;APK 越小&#xff0c;用户体验越好。本文作者通过对 APK 内在机制的详细解析&#xff0c;给出了对 APK 各组成成分的优化方法及技术&#xff0c;并实现了一个基本 APK…

Unity 安卓(Android)端AVProVideo插件播放不了视频,屏幕一闪一闪的

编辑器运行没有问题&#xff0c;但是安卓就有问题&#xff0c;在平板上运行就会报错&#xff1a; vulkan graphics API is notsupported 说不支持Vulkan图形API,解决方法&#xff1a;把Vulkan删除掉

QTableView合并单元格

QtableView的功能 QTableView是Qt框架提供的用于显示表格数据的类。它是基于MVC&#xff08;模型-视图-控制器&#xff09;设计模式的一部分&#xff0c;用于将数据模型和界面视图分离。 以下是一些QTableView的主要特点和功能&#xff1a; 1. 显示表格数据&#xff1a; QTa…

手写Mybatis:第20章-Mybatis 框架源码10种设计模式分析

文章目录 一、类型&#xff1a;创建型模式1.1 工厂模式1.2 单例模式1.3 建造者模式 二、类型&#xff1a;结构型模式2.1 适配器模式2.2 代理模式2.3 组合模式2.4 装饰器模式 三、类型&#xff1a;行为型模式3.1 模板模式3.2 策略模式3.3 迭代器模式 一、类型&#xff1a;创建型…

题①拷贝构造相关笔试题

问&#xff1a;此代码中有几次构造&#xff0c;几次拷贝构造&#xff1f; W f&#xff08;W u&#xff09; {W v(u);W w v;return w; } int main() {w x;w y f(x);return 0;解析&#xff1a;一次构造&#xff0c;四次拷贝构造。 再来一题 W f&#xff08;W u&#xff09;…

Redis未授权访问漏洞复现

Redis 简单使用 Redis 未设置密码&#xff0c;客户端工具可以直接链接。 Redis 是非关系型数据库系统&#xff0c;没有库表列的逻辑结构&#xff0c;仅仅以键值对的方式存储数据。 先启动容器 Redis 未设置密码&#xff0c;客户端工具可以直接链接 https://github.com/xk11z/…

Laravel 模型的关联查询 Debugbar 调试器 模型的预加载 ⑩②

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; THINK PHP &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

冠达管理:券商8月调研热情高 工业机械行业受青睐

截至9月4日记者发稿&#xff0c;8月以来券商累计调研次数约1.44万次&#xff0c;环比增加超160%。其间&#xff0c;工业机械职业公司获券商调研最多。 调研逾900只个股 截至9月4日发稿&#xff0c;8月以来券商累计调研948只个股。从个股调研热度看&#xff0c;容百科技最受券…

【ES6】JavaScript中的Symbol

Symbol是JavaScript中的一种特殊的、不可变的、不可枚举的数据类型。它通常用于表示一个唯一的标识符&#xff0c;可以作为对象的属性键&#xff0c;确保对象的属性键的唯一性和不可变性。 Symbol.for()是Symbol的一个方法&#xff0c;它用于创建一个已经注册的Symbol对象。当…

基于Matlab实现多个图像融合案例(附上源码+数据集)

图像融合是将多幅图像合成为一幅图像的过程&#xff0c;旨在融合不同图像的信息以获得更多的细节和更丰富的视觉效果。在本文中&#xff0c;我们将介绍如何使用Matlab实现图像融合。 文章目录 简单案例源码数据集下载 简单案例 首先&#xff0c;我们需要了解图像融合的两种主…

理解 std::thread::join

C多线程并发编程入门&#xff08;目录&#xff09; 本文用最简单易懂的实际案例&#xff0c;讲清楚了 join 的实际内涵&#xff0c;保证你过目不忘。 Hello join 示例 join 函数是我们接触C多线程 thread 遇到的第一个函数。 比如&#xff1a; int main() {thread t(f);t.…

修改PX4飞控的imu频率

QGroundControl 连接上飞控后&#xff0c;打开 Analyze Tools 下的 MAVLink Inspector 界面 可以看到当前的 IMU 频率为50 HZ&#xff0c;或者在终端启动 mavros&#xff0c;终端输入 sudo chmod 777 /dev/ttyACM0 roslaunch mavros px4.launch 然后查看频率 rostopic hz /m…