本博客为作者原创,如需转载请注明参考
 
        在深入理解Spark ML中的各类算法之前,先理一下整个库的设计框架,是非常有必要的,优秀的框架是对复杂问题的抽象和解剖,对这种抽象的学习本身,就是加深框架所面对的问题的理解的一种有效途径。纷繁复杂的机器学习问题,经过优秀框架的解析,变得简单清晰起来。
        基于面向对象语言的程序设计,本质上类似于搭积木,从一个最抽象、最简单的内容开始,一点一点的往上堆叠,形成一个对象的框架。比如Java中的Object,Python中的PyObject等等,这也是面向对象语言教给我们的一种解决问题的思路:剥洋葱,把外层非本质的核一个一个剥去,剩下的就是事物的本质与核心。
        那么,机器学习问题的核心是什么呢?Spark ML给出的答案是,参数。所有的机器学习模型、算法,说到底都是对参数的学习,都离不开参数。因此,在Spark ML框架中,最底层也是最抽象的类,就是Param,一个对象只要是能包含参数的,都可以叫做Param。
        在param文件夹下,包含了对参数类及其子类的代码。参数类的子类,主要分成两种,第一种是数据类型类,包括IntParam,DoubleParam,顾名思义,这些参数包含了某种数据类型的数据,第二种是参数集合Params,表示其中包含了许多参数,这个类就很了不起了,从它开始衍生出了很多实用的参数,比如HasRegParam,表示其中包含了正则化的参数,再比如HasMaxIter,表示其中包含了最大迭代次数的参数。看,机器学习模型的积木已经帮我们准备好了,从参数的角度来抽象各类机器学习问题,可以按照是否包含某个参数,对机器学习模型和算法进行拆解,一个算法需要什么参数,就在定义时,像搭积木一样,把对应的参数包括进来就好了。
        参数仅是静态的内容,如果要让这个对象有用,就需要让它具有一定的功能。最底层的具有功能性的类时PipelineStage,它实际上是一个Params,关于Pipeline的概念,我们稍后介绍,这里需要理解的是,虽然PipelineStage与Pipeline的名称很相似,但它们之间还隔了一层,完全不是一个层面上的东西。PipelineStage是一个抽象的阶段,它本身不具备任何功能,它的存在仅是为了给真正有功能的类一个公共的子类,与Param的其它子类相区分。
        接下来就到了我们日常使用时最常用的类,Transformer。一个类,只要它拥有将一个数据集转化成另外一个数据集的功能,它就是一个Transformer。注意,一个Transformer就是一个PipelineStage。
仅能完成数据转换,还不够,在机器学习中,最重要的事情是对数据的拟合,这里Estimator类正式登场,只要具有数据拟合的功能,即,只要能从数据中学习,就是Estimator,这个类里包含了我们最熟悉的一个函数,fit,是它赋予了所有Estimator从数据中学习的能力。
        到这里,我们在机器学习中最常见的“模型”的概念,就已经呼之欲出了。Model类本质上是一个Transformer,这个很好理解,一个训练得到的模型,本身的任务就是做预测,做数据转化的。Model的独特之处在于,它是由Estimator的fit方法生成的,一个Estimator在经过对数据的学习之后,就产生了一个Model,而一个Model中除了一个指向生成自己的Estimator的指针之外,真的什么都没有。
        这里我们再总结一下Transformer(简称T),Estimator(简称E),Model(简称M)三者之间的关系。T和E本质上都是PipelineStage,更本质的来说都是Param,而M本质上是一个T,但它是由E产生的,因此M是连接T和E之间的桥梁。
        下面要介绍的就是Pipeline,我们知道很多机器学习的任务,都不是一步能完成的,比如做分类,我们要先对数据进行预处理,进行分类,然后再对分类结果进行处理,才能得到想要的结果。于是Spark ML提供了一个非常棒的抽象,流水线(Pipeline),它的引入能使得机器学习的各个任务能像流水线一样被顺序执行,因此能提供非常简洁的编程接口。Pipeline本质上是一个E,它是由一个一个的PipelineStage组成的。通过上文我们知道,T和E都是PipelineStage,因此一个Pipeline中就包含了许多的T和E。由于Pipeline本质上是一个E,因此它在调用fit函数之后,会产生一个PipelineModel,这就是一个Model了。还记得Model的本质是Transformer吗?
        我们知道,机器学习中的问题可以简单分为两类,监督学习和非监督学习,监督学习的一个特点就是,能够对某个事情做出“预测”,而非监督学习更多的是挖掘数据中的一些内在本质特点,不能做出预测,因此,为了将监督学习的本质提炼出来,设计了一个Predictor类。
        能做出预测的类,需要有一些共同的参数,还记得刚才我们对于Param的分析吗?参数是区分各类机器学习算法的一种角度,PredictorParams就是有预测能力的监督学习模型拥有参数的一种抽象,而Predictor本质上是一个带有PredictorParams的Estimator,而每一个Estimator在调用fit函数之后都会产生一个Model,这里产生的就是一个PredictorModel,这是一个带有PredictorParams的Model。
       
        好了,今天就写到这里。写作也是整理思路的一种很好的方式,在刚才的写作中,对Spark ML的设计思路又有了新的认识。由于本人才疏学浅,以上的理解不免会有纰漏,还请大家不吝赐教。下次将跟大家一起分析下具体算法的设计。

Spark ML源码分析之一 设计框架解读的更多相关文章

  1. Spark ML源码分析之二 从单机到分布式

            前一节从宏观角度给大家介绍了Spark ML的设计框架(链接:http://www.cnblogs.com/jicanghai/p/8570805.html),本节我们将介绍,Spar ...

  2. Spark ML源码分析之三 分类器

            前面跟大家扯了这么多废话,终于到具体的机器学习模型了.大部分机器学习的教程,总要从监督学习开始讲起,而监督学习的众多算法当中,又以分类算法最为基础,原因在于分类问题非常的单纯直接,几乎 ...

  3. Spark ML源码分析之四 树

            之前我们讲过,在Spark ML中所有的机器学习模型都是以参数作为划分的,树相关的参数定义在treeParams.scala这个文件中,这里构建一个关于树的体系结构.首先,以Decis ...

  4. 第十一篇:Spark SQL 源码分析之 External DataSource外部数据源

    上周Spark1.2刚发布,周末在家没事,把这个特性给了解一下,顺便分析下源码,看一看这个特性是如何设计及实现的. /** Spark SQL源码分析系列文章*/ (Ps: External Data ...

  5. 【Spark SQL 源码分析系列文章】

    从决定写Spark SQL源码分析的文章,到现在一个月的时间里,陆陆续续差不多快完成了,这里也做一个整合和索引,方便大家阅读,这里给出阅读顺序 :) 第一篇 Spark SQL源码分析之核心流程 第二 ...

  6. Spring5源码分析(1)设计思想与结构

    1 源码地址(带有中文注解)git@github.com:yakax/spring-framework-5.0.2.RELEASE--.git Spring 的设计初衷其实就是为了简化我们的开发 基于 ...

  7. [转]Libev源码分析 -- 整体设计

    Libev源码分析 -- 整体设计 libev是Marc Lehmann用C写的高性能事件循环库.通过libev,可以灵活地把各种事件组织管理起来,如:时钟.io.信号等.libev在业界内也是广受好 ...

  8. 第十篇:Spark SQL 源码分析之 In-Memory Columnar Storage源码分析之 query

    /** Spark SQL源码分析系列文章*/ 前面讲到了Spark SQL In-Memory Columnar Storage的存储结构是基于列存储的. 那么基于以上存储结构,我们查询cache在 ...

  9. 第九篇:Spark SQL 源码分析之 In-Memory Columnar Storage源码分析之 cache table

    /** Spark SQL源码分析系列文章*/ Spark SQL 可以将数据缓存到内存中,我们可以见到的通过调用cache table tableName即可将一张表缓存到内存中,来极大的提高查询效 ...

随机推荐

  1. 洛谷P1896 [SCOI2005]互不侵犯King【状压DP】

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入格式: 只有一行,包含两个数N,K ...

  2. Java并发系列[6]----Semaphore源码分析

    Semaphore(信号量)是JUC包中比较常用到的一个类,它是AQS共享模式的一个应用,可以允许多个线程同时对共享资源进行操作,并且可以有效的控制并发数,利用它可以很好的实现流量控制.Semapho ...

  3. [翻译]编写高性能 .NET 代码 第一章:工具介绍 -- Performance Counters(性能计数器)

    <<返回目录 Performance Counters(性能计数器) 性能计数器是监视应用程序和系统性能的最简单的方法之一.它有几十个类别数百个计数器在,包括一些.net特有的计数器.要访 ...

  4. 使用JSONP进行跨域Ajax 调用

    JSONP 是啥 JSONP 全称是JSON with Padding. 当需要进行跨域Ajax 调用的时候, 需要用到JSONP 协议. 客户端 $.ajax({ url: 'http://xxx' ...

  5. bzoj 3166 [Heoi2013]Alo 可持久化Trie

    3166: [Heoi2013]Alo Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1227  Solved: 569[Submit][Status ...

  6. rxjs-流式编程

    前言 第一次接触rxjs也是因为angular2应用,内置了rxjs的依赖,了解之后发现它的强大,是一个可以代替promise的框架,但是只处理promise的东西有点拿尚方宝剑砍蚊子的意思. 如果我 ...

  7. GB 标准

    std::map<int, std::string> GB2261 = { { 0,"未知的性别" }, { 1,"男性" }, { 2," ...

  8. JavaScript设计模式之策略模式

    所谓"条条道路通罗马",在现实中,为达到某种目的往往不是只有一种方法.比如挣钱养家:可以做点小生意,可以打分工,甚至还可以是偷.抢.赌等等各种手段.在程序语言设计中,也会遇到这种类 ...

  9. DTCMS插件的制作实例电子资源管理(四)URL重写

    总目录 插件目录结构(一) Admin后台页面编写(二) 前台模板页编写(三) URL重写(四) 本实例旨在以一个实际的项目中的例子来介绍如何在dtcms中制作插件,本系列文章非入门教程,部分逻辑实现 ...

  10. 多文件工程的编译-Makefile的简便写法

    通常我们在命令行使用GCC对程序进行编译,如果对于单个或者几个文件时比较方便的,但当工程中的文件逐渐增多甚至变得十分庞大的时候,使用GCC显然力不从心,不好管理.因此我们有必要编写一个Makefile ...