网站制作好学吗/银川网页设计公司

网站制作好学吗,银川网页设计公司,微信营销软件免费版,网站写手怎么做1. 背景 XGBoost模型作为机器学习中的一大“杀器”,被广泛应用于数据科学竞赛和工业领域,XGBoost官方也提供了可运行于各种平台和环境的对应代码,如适用于Spark分布式训练的XGBoost on Spark。然而,在XGBoost on Spark的官方实现中…

1. 背景

XGBoost模型作为机器学习中的一大“杀器”,被广泛应用于数据科学竞赛和工业领域,XGBoost官方也提供了可运行于各种平台和环境的对应代码,如适用于Spark分布式训练的XGBoost on Spark。然而,在XGBoost on Spark的官方实现中,却存在一个因XGBoost缺失值和Spark稀疏表示机制而带来的不稳定问题。

事情起源于美团内部某机器学习平台使用方同学的反馈,在该平台上训练出的XGBoost模型,使用同一个模型、同一份测试数据,在本地调用(Java引擎)与平台(Spark引擎)计算的结果不一致。但是该同学在本地运行两种引擎(Python引擎和Java引擎)进行测试,两者的执行结果是一致的。因此质疑平台的XGBoost预测结果会不会有问题?

该平台对XGBoost模型进行过多次定向优化,在XGBoost模型测试时,并没有出现过本地调用(Java引擎)与平台(Spark引擎)计算结果不一致的情形。而且平台上运行的版本,和该同学本地使用的版本,都来源于Dmlc的官方版本,JNI底层调用的应该是同一份代码,理论上,结果应该是完全一致的,但实际中却不同。

从该同学给出的测试代码上,并没有发现什么问题:

//测试结果中的一行,41列
double[] input = new double[]{1, 2, 5, 0, 0, 6.666666666666667, 31.14, 29.28, 0, 1.303333, 2.8555, 2.37, 701, 463, 3.989, 3.85, 14400.5, 15.79, 11.45, 0.915, 7.05, 5.5, 0.023333, 0.0365, 0.0275, 0.123333, 0.4645, 0.12, 15.082, 14.48, 0, 31.8425, 29.1, 7.7325, 3, 5.88, 1.08, 0, 0, 0, 32];
//转化为float[]
float[] testInput = new float[input.length];
for(int i = 0, total = input.length; i < total; i++){testInput[i] = new Double(input[i]).floatValue();
}
//加载模型
Booster booster = XGBoost.loadModel("${model}");
//转为DMatrix,一行,41列
DMatrix testMat = new DMatrix(testInput, 1, 41);
//调用模型
float[][] predicts = booster.predict(testMat);

上述代码在本地执行的结果是333.67892,而平台上执行的结果却是328.1694030761719。

两次结果怎么会不一样,问题出现在哪里呢?

2. 执行结果不一致问题排查历程

如何排查?首先想到排查方向就是,两种处理方式中输入的字段类型会不会不一致。如果两种输入中字段类型不一致,或者小数精度不同,那结果出现不同就是可解释的了。仔细分析模型的输入,注意到数组中有一个6.666666666666667,是不是它的原因?

一个个Debug仔细比对两侧的输入数据及其字段类型,完全一致。

这就排除了两种方式处理时,字段类型和精度不一致的问题。

第二个排查思路是,XGBoost on Spark按照模型的功能,提供了XGBoostClassifier和XGBoostRegressor两个上层API,这两个上层API在JNI的基础上,加入了很多超参数,封装了很多上层能力。会不会是在这两种封装过程中,新加入的某些超参数对输入结果有着特殊的处理,从而导致结果不一致?

与反馈此问题的同学沟通后得知,其Python代码中设置的超参数与平台设置的完全一致。仔细检查XGBoostClassifier和XGBoostRegressor的源代码,两者对输出结果并没有做任何特殊处理。

再次排除了XGBoost on Spark超参数封装问题。

再一次检查模型的输入,这次的排查思路是,检查一下模型的输入中有没有特殊的数值,比方说,NaN、-1、0等。果然,输入数组中有好几个0出现,会不会是因为缺失值处理的问题?

快速找到两个引擎的源码,发现两者对缺失值的处理真的不一致!

XGBoost4j中缺失值的处理

XGBoost4j缺失值的处理过程发生在构造DMatrix过程中,默认将0.0f设置为缺失值:

  /*** create DMatrix from dense matrix** @param data data values* @param nrow number of rows* @param ncol number of columns* @throws XGBoostError native error*/public DMatrix(float[] data, int nrow, int ncol) throws XGBoostError {long[] out = new long[1];//0.0f作为missing的值XGBoostJNI.checkCall(XGBoostJNI.XGDMatrixCreateFromMat(data, nrow, ncol, 0.0f, out));handle = out[0];}

XGBoost on Spark中缺失值的处理

而xgboost on Spark将NaN作为默认的缺失值。

  /*** @return A tuple of the booster and the metrics used to build training summary*/@throws(classOf[XGBoostError])def trainDistributed(trainingDataIn: RDD[XGBLabeledPoint],params: Map[String, Any],round: Int,nWorkers: Int,obj: ObjectiveTrait = null,eval: EvalTrait = null,useExternalMemory: Boolean = false,//NaN作为missing的值missing: Float = Float.NaN,hasGroup: Boolean = false): (Booster, Map[String, Array[Float]]) = {//...}

也就是说,本地Java调用构造DMatrix时,如果不设置缺失值,默认值0被当作缺失值进行处理。而在XGBoost on Spark中,默认NaN会被为缺失值。原来Java引擎和XGBoost on Spark引擎默认的缺失值并不一样。而平台和该同学调用时,都没有设置缺失值,造成两个引擎执行结果不一致的原因,就是因为缺失值不一致!

修改测试代码,在Java引擎代码上设置缺失值为NaN,执行结果为328.1694,与平台计算结果完全一致。

    //测试结果中的一行,41列double[] input = new double[]{1, 2, 5, 0, 0, 6.666666666666667, 31.14, 29.28, 0, 1.303333, 2.8555, 2.37, 701, 463, 3.989, 3.85, 14400.5, 15.79, 11.45, 0.915, 7.05, 5.5, 0.023333, 0.0365, 0.0275, 0.123333, 0.4645, 0.12, 15.082, 14.48, 0, 31.8425, 29.1, 7.7325, 3, 5.88, 1.08, 0, 0, 0, 32];float[] testInput = new float[input.length];for(int i = 0, total = input.length; i < total; i++){testInput[i] = new Double(input[i]).floatValue();}Booster booster = XGBoost.loadModel("${model}");//一行,41列DMatrix testMat = new DMatrix(testInput, 1, 41, Float.NaN);float[][] predicts = booster.predict(testMat);

3. XGBoost on Spark源码中缺失值引入的不稳定问题

然而,事情并没有这么简单。

Spark ML中还有隐藏的缺失值处理逻辑:SparseVector,即稀疏向量。

SparseVector和DenseVector都用于表示一个向量,两者之间仅仅是存储结构的不同。

其中,DenseVector就是普通的Vector存储,按序存储Vector中的每一个值。

而SparseVector是稀疏的表示,用于向量中0值非常多场景下数据的存储。

SparseVector的存储方式是:仅仅记录所有非0值,忽略掉所有0值。具体来说,用一个数组记录所有非0值的位置,另一个数组记录上述位置所对应的数值。有了上述两个数组,再加上当前向量的总长度,即可将原始的数组还原回来。

因此,对于0值非常多的一组数据,SparseVector能大幅节省存储空间。

SparseVector存储示例见下图:

如上图所示,SparseVector中不保存数组中值为0的部分,仅仅记录非0值。因此对于值为0的位置其实不占用存储空间。下述代码是Spark ML中VectorAssembler的实现代码,从代码中可见,如果数值是0,在SparseVector中是不进行记录的。

    private[feature] def assemble(vv: Any*): Vector = {val indices = ArrayBuilder.make[Int]val values = ArrayBuilder.make[Double]var cur = 0vv.foreach {case v: Double =>//0不进行保存if (v != 0.0) {indices += curvalues += v}cur += 1case vec: Vector =>vec.foreachActive { case (i, v) =>//0不进行保存if (v != 0.0) {indices += cur + ivalues += v}}cur += vec.sizecase null =>throw new SparkException("Values to assemble cannot be null.")case o =>throw new SparkException(s"$o of type ${o.getClass.getName} is not supported.")}Vectors.sparse(cur, indices.result(), values.result()).compressed}

不占用存储空间的值,也是某种意义上的一种缺失值。SparseVector作为Spark ML中的数组的保存格式,被所有的算法组件使用,包括XGBoost on Spark。而事实上XGBoost on Spark也的确将Sparse Vector中的0值直接当作缺失值进行处理:

    val instances: RDD[XGBLabeledPoint] = dataset.select(col($(featuresCol)),col($(labelCol)).cast(FloatType),baseMargin.cast(FloatType),weight.cast(FloatType)).rdd.map { case Row(features: Vector, label: Float, baseMargin: Float, weight: Float) =>val (indices, values) = features match {//SparseVector格式,仅仅将非0的值放入XGBoost计算case v: SparseVector => (v.indices, v.values.map(_.toFloat))case v: DenseVector => (null, v.values.map(_.toFloat))}XGBLabeledPoint(label, indices, values, baseMargin = baseMargin, weight = weight)}

XGBoost on Spark将SparseVector中的0值作为缺失值为什么会引入不稳定的问题呢?

重点来了,Spark ML中对Vector类型的存储是有优化的,它会自动根据Vector数组中的内容选择是存储为SparseVector,还是DenseVector。也就是说,一个Vector类型的字段,在Spark保存时,同一列会有两种保存格式:SparseVector和DenseVector。而且对于一份数据中的某一列,两种格式是同时存在的,有些行是Sparse表示,有些行是Dense表示。选择使用哪种格式表示通过下述代码计算得到:

  /*** Returns a vector in either dense or sparse format, whichever uses less storage.*/@Since("2.0.0")def compressed: Vector = {val nnz = numNonzeros// A dense vector needs 8 * size + 8 bytes, while a sparse vector needs 12 * nnz + 20 bytes.if (1.5 * (nnz + 1.0) < size) {toSparse} else {toDense}}

在XGBoost on Spark场景下,默认将Float.NaN作为缺失值。如果数据集中的某一行存储结构是DenseVector,实际执行时,该行的缺失值是Float.NaN。而如果数据集中的某一行存储结构是SparseVector,由于XGBoost on Spark仅仅使用了SparseVector中的非0值,也就导致该行数据的缺失值是Float.NaN和0。

也就是说,如果数据集中某一行数据适合存储为DenseVector,则XGBoost处理时,该行的缺失值为Float.NaN。而如果该行数据适合存储为SparseVector,则XGBoost处理时,该行的缺失值为Float.NaN和0。

即,数据集中一部分数据会以Float.NaN和0作为缺失值,另一部分数据会以Float.NaN作为缺失值! 也就是说在XGBoost on Spark中,0值会因为底层数据存储结构的不同,同时会有两种含义,而底层的存储结构是完全由数据集决定的。

因为线上Serving时,只能设置一个缺失值,因此被选为SparseVector格式的测试集,可能会导致线上Serving时,计算结果与期望结果不符。

4. 问题解决

查了一下XGBoost on Spark的最新源码,依然没解决这个问题。

赶紧把这个问题反馈给XGBoost on Spark, 同时修改了我们自己的XGBoost on Spark代码。

   val instances: RDD[XGBLabeledPoint] = dataset.select(col($(featuresCol)),col($(labelCol)).cast(FloatType),baseMargin.cast(FloatType),weight.cast(FloatType)).rdd.map { case Row(features: Vector, label: Float, baseMargin: Float, weight: Float) =>//这里需要对原来代码的返回格式进行修改val values = features match {//SparseVector的数据,先转成Densecase v: SparseVector => v.toArray.map(_.toFloat)case v: DenseVector => v.values.map(_.toFloat)}XGBLabeledPoint(label, null, values, baseMargin = baseMargin, weight = weight)}
    /*** Converts a [[Vector]] to a data point with a dummy label.** This is needed for constructing a [[ml.dmlc.xgboost4j.scala.DMatrix]]* for prediction.*/def asXGB: XGBLabeledPoint = v match {case v: DenseVector =>XGBLabeledPoint(0.0f, null, v.values.map(_.toFloat))case v: SparseVector =>//SparseVector的数据,先转成DenseXGBLabeledPoint(0.0f, null, v.toArray.map(_.toFloat))}

问题得到解决,而且用新代码训练出来的模型,评价指标还会有些许提升,也算是意外之喜。

希望本文对遇到XGBoost缺失值问题的同学能够有所帮助,也欢迎大家一起交流讨论。

作者简介

  • 兆军,美团配送事业部算法平台团队技术专家。

招聘信息

美团配送事业部算法平台团队,负责美团一站式大规模机器学习平台图灵平台的建设。围绕算法整个生命周期,利用可视化拖拽方式定义模型训练和预测流程,提供强大的模型管理、线上模型预测和特征服务能力,提供多维立体的AB分流支持和线上效果评估支持。团队的使命是为算法相关同学提供统一的,端到端的,一站式自助服务平台,帮助算法同学降低算法研发复杂度,提升算法迭代效率。

现面向数据工程,数据开发,算法工程,算法应用等领域招聘资深研发工程师/技术专家/方向负责人(机器学习平台/算法平台),欢迎有兴趣的同学一起加入,简历可投递至:tech@meituan.com(注明:美团配送事业部)

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

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

相关文章

Android官方开发文档Training系列课程中文版:添加ActionBar之添加Action按钮

原文地址 : http://android.xsoftlab.net/training/basics/actionbar/adding-buttons.html 添加Action按钮 ActionBar允许在当前的APP上下文内添加很多重要的功能按钮。这样便可以通过图标或者文字作为功能按钮直接展示在ActionBar上。功能按钮如果没有足够空间或无足轻重的按…

快手搜索技术部招聘NLP算法工程师!

星标/置顶小屋&#xff0c;带你解锁最萌最前沿的NLP、搜索与推荐技术工作职责快手搜索技术部招聘&#xff0c;负责研发快手主APP搜索中的关键NLP模型/算法&#xff0c;包括但不限于&#xff1a;适合快手数据生态的NLP预训练语言模型&#xff0c;并推动预训练模型在query解析&am…

论文浅尝 | 解决知识图谱补全中的长尾关系和不常见实体问题

论文笔记整理&#xff1a;汪寒&#xff0c;浙江大学硕士。链接&#xff1a;https://www.aclweb.org/anthology/P19-1024.pdf动机KG的分布遵循长尾分布&#xff0c;大部分关系只有很少的三元组&#xff0c;且大体趋势是关系出现的频率和与之相关的不常见实体的比例呈反比关系。而…

LeetCode 944. 删列造序

1. 题目 题目链接 每个单词的位组成的列非降&#xff0c;最少删除几列。 示例 1&#xff1a;输入&#xff1a;["cba", "daf", "ghi"] 输出&#xff1a;1 解释&#xff1a; 当选择 D {1}&#xff0c;删除后 A 的列为&#xff1a;["c&quo…

Android官方开发文档Training系列课程中文版:添加ActionBar之自定义ActionBar样式

原文地址 : http://android.xsoftlab.net/training/basics/actionbar/styling.html ActionBar的样式 ActionBar提供了为用户提供了常见的习惯性的用户界面以及按钮功能。但是这并不意味着必须要和其它APP看起来一模一样。如果需要设计更符合产品品牌样式风格的话&#xff0c;…

美团 iOS 工程 zsource 命令背后的那些事儿

zsource 命令是什么&#xff1f; 美团 App 在 2015 年就已经基于 CocoaPods 完成了组件化的工作。在组件化的改造过程中&#xff0c;为了能够加速整体工程的构建速度&#xff0c;我们对需要集成进美团 App 的组件进行了二进制化&#xff0c;同时提供一个叫做 cocoapods-binary …

互联网大厂CTR预估前沿进展

文 | Ruhjkg编 | 小鹿鹿lulu源 | 知乎前言CTR&#xff08;click through rate&#xff09;预估模型是广告推荐领域的核心问题。早期主要是使用LR&#xff08;线性回归&#xff09;人工特征工程的机器学习方法&#xff0c;但是存在人工组合特征工程成本较高&#xff0c;不同任务…

以史为鉴 | 为什么要将「知识图谱」追溯到1956年?

本文转载自公众号&#xff1a;AI科技评论。作者 | Claudio Gutierrez 编译 | MrBear编辑 | Tokai以史为鉴&#xff0c;可以知兴替。纵观近期包括 AAAI、NeurIPS、IJCAI 在内的AI顶级会议&#xff0c;对图结构模型的研究是一个绕不开的话题&#xff0c;大量学者涌入这个赛道&…

Android官方开发文档Training系列课程中文版:添加ActionBar之ActionBar浮层效果

原文地址 : http://android.xsoftlab.net/training/basics/actionbar/overlaying.html 浮层效果的ActionBar 默认情况下&#xff0c;ActionBar总是会出现在Activity窗口的顶部&#xff0c;这样会稍微的减少Activity布局的剩余空间。如果需要在用户使用的时候隐藏和显示Action…

美团大规模微服务通信框架及治理体系OCTO核心组件开源

微服务通信框架及治理平台OCTO作为美团基础架构设施的重要组成部分&#xff0c;目前已广泛应用于公司技术线&#xff0c;稳定承载上万应用、日均支撑千亿级的调用。业务基于OCTO提供的标准化技术方案&#xff0c;能够轻松实现服务注册/发现、负载均衡、容错处理、降级熔断、灰度…

领域应用 | 知识结构化在阿里小蜜中的应用

本文转载自公众号&#xff1a;DataFunTalk。分享嘉宾&#xff1a;李凤麟 阿里巴巴 算法专家文章整理&#xff1a;付一韬内容来源&#xff1a;2019知识图谱前沿技术论坛出品社区&#xff1a;DataFun导读&#xff1a;阿里小蜜是阿里巴巴服务领域的重要人工智能产品&#xff0c;是…

内卷的世界,我们是否可以换一种思维生活?

文 | Flood Sung源 | 知乎前言今年最热门的词汇之一当属内卷了。似乎很多行业都由于份额有限而陷入内卷当中。最火的或许是清华学生的这张图&#xff0c;“骑车写代码”&#xff1a;图片来自网络虽然后来知道是这位同学怕关了屏幕程序就断了&#xff0c;但这不禁让人思考&#…

LeetCode 513. 找树左下角的值(按层遍历 queue)

1. 题目 给定一个二叉树&#xff0c;在树的最后一行找到最左边的值。 2. 解题 利用队列按层次遍历顺序&#xff0c;根右左&#xff0c;要求最左边的一个&#xff0c;所以根右左&#xff0c;最后一个队列元素就是答案 class Solution { public:int findBottomLeftValue(TreeN…

Hadoop YARN:调度性能优化实践

背景 YARN作为Hadoop的资源管理系统&#xff0c;负责Hadoop集群上计算资源的管理和作业调度。 美团的YARN以社区2.7.1版本为基础构建分支。目前在YARN上支撑离线业务、实时业务以及机器学习业务。 离线业务主要运行的是Hive on MapReduce&#xff0c; Spark SQL为主的数据仓库作…

LeetCode 39. 组合总和(排列组合 回溯)

1. 题目 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明&#xff1a; 所有数字&#xff08;包括 target&#xff09;都是正整数。 解集不能包…

深度学习平台的未来:谁会赢得下半场?

今天这篇文章无意引战&#xff0c;只想从历史发展的角度来谈谈深度学习大背景下的开发工具变迁&#xff0c;以及对未来发展趋势的想象。TensorFlow&#xff1a;无力回天的深度学习里程碑不知道有多少小伙伴是2017年以前入坑深度学习的&#xff0c;那时候人工智能概念火热&#…

论文浅尝 | 基于属性嵌入的知识图谱实体对齐

论文笔记整理&#xff1a;王中昊&#xff0c;天津大学硕士&#xff0c;方向&#xff1a;自然语言处理。来源&#xff1a;AAAI2019论文链接&#xff1a; https://doi.org/10.1609/aaai.v33i01.3301297概述知识图谱之间的实体对齐的任务目标是去找到那些在两个不同的知识图谱上表…

基本功 | Litho的使用及原理剖析

1. 什么是Litho&#xff1f; Litho是Facebook推出的一套高效构建Android UI的声明式框架&#xff0c;主要目的是提升RecyclerView复杂列表的滑动性能和降低内存占用。下面是Litho官网的介绍&#xff1a; Litho is a declarative framework for building efficient user interfa…

论文浅尝 | 基于深度强化学习将图注意力机制融入知识图谱推理

论文笔记整理&#xff1a;陈名杨&#xff0c;浙江大学直博生。Introduction知识图谱&#xff08;KGs&#xff09;在很多NLP的下游应用中起着越来越重要的作用。但是知识图谱常常是不完整的&#xff0c;所以解决知识图谱补全的任务也非常重要。主要有三种方法来完成知识图谱补全…

聊聊如何提升推荐系统的结果多样性

文 | 洪九(李戈)源 | 知乎个性化推荐系统的出现为处理信息过载问题提供了一个有效的工具&#xff0c;已经成为互联网各大平台(电商、信息流等)的标配&#xff0c;并在技术(个性化召回、个性化排序等)上取得了长足的发展&#xff0c;逐渐从传统模型过度到深度学习时代。但是&…