gcForest算法原理及Python实现

简介:

1.背景介绍

从目前来看深度学习大多建立在多层的神经网络基础上,也即一些参数化的多层可微的非线性模块,这样就可以通过后向传播去训练,Zhi-Hua Zhou和Ji Feng在Deep Forest论文中基于不可微的模块建立深度模块,这就是gcForest。

传统的深度学习有一定的弊端:

 ●  超参数个数较多,训练前需要大量初始化,主要靠经验调整,使得DNN更像一门艺术而非科学;
 ●  DNN的训练要求大量的训练数据,数据的标注成本太高;
 ●  DNN是一个黑盒子,训练的结果很难去解释描述,并且学习行为很难用理论去分析解释;
 ●  DNN在训练之前就得确定具体的网络结构,模型的复杂度也是提前设定好的,虽然有一些dropout等的技术。

但是有一点是我们相信的,在处理更复杂的学习问题时,算法的学习模块应该要变的更深,现在的深层网络结构依旧依赖于神经网络(我们这里把像CNN,RNN的基本结构单元也归结为神经网络单元), 周志华团队考虑深度学习的结构可不可以用其他不可微的模块组成:

Can deep learning be realized with non-differentiable modules?

这个问题会使我们想到一些其他问题:

 ●  深度学习是不是就等同于DNN(深度模型是不是只能通过可微的函数结构去构建?)?
 ●  是不是可以不通过后向传播训练深度模型?
 ●  是不是使得在一些RandomForest,XGBoost,lightGBM成功的学习任务上,深度模型能够战胜它们?

下面我们就来看一下,周志华团队是如何从传统的机器学习和深度学习中获得灵感,构建gcForest的。

2.gcForest模型灵感来源

我们本节首先介绍gcForest模型构建的灵感来源,论文提到了两个方面,一个是在DNN中,一个是在集成学习(Ensemble Learning)。

(1) DNN中的灵感来源

深度学习在一些学习任务上之所以成功,关键在于特征的表示学习上(representation learning,不知道翻译的对不对 :)),如下图所示,随着一层一层的处理(layer-by-layer processing),马的图像数据的特征被高度抽象出来用于动物分类任务。

e468d3544275a318fc785863c29feccf9aeb2977

也就是说DNN在做分类任务时最终使用的是生成抽象出来的关键高层特征,而决策树,Boosting等传统机器学习模型只是使用初始的特征表示去学习,换句话说并没有做模型内部的特征变换(in_model feature transformation)。

除此之外,DNN可以设计成任意的复杂度,而决策树和Boosting模型的复杂度是有限的,充足的模型复杂度虽然不是DNN必要的取胜法宝,但是也是非常重要的。

总结在设计gcForest来自DNN的灵感:

 ●  layer-by-layer processing
 ●  in_model feature transformation

 ●  suffcient model complexity

(2) 集成学习中的灵感来源

众所周知,集成学习通常比起单模型往往会有一个比较不错的表现,在构建一个好的集成模型时,要同时考虑子模型预测的准确度和子模型之间的多样性,尽量做到模型之间的互补,即理论上来说,子模型的准确度越高且子模型之间差异性越大(多样性),集成的效果越好。

但是,what is diversity? 怎样去度量模型之间的多样性?

在实践中,多样性增强的基本策略是在训练过程中引入基于启发式的随机性。粗略的说有4个机制:

 ●  数据样本机制: 它通过产生不同的数据样本来训练子模型;
 ●  输入特征机制:它通过选取不同特征子空间来训练子模型;
 ●  学习参数机制:他通过设定不同参数来使得子模型具有多样性;
 ●  输出表示机制:通过不同的输出表示增加子模型的多样性;

下一节通过本节的一些灵感构建gcForest模型。

3.gcForest模型

(1) 级联森林结构

基于上一节中的一些灵感,gcForest被构造成如下图所示的级联结构

c6c9dc127808e45648b87c4704805a0fe269e9ca

解释:

 ●  每一个Level包含若干个集成学习的分类器(这里是决策树森林,你可以换成XGBoost,lightGBM等),这是一种集成中的集成的结构;
 ●  为了体现多样性,黑色和蓝色的Forest代表了若干不同的集成学习器,为了说明这里用了两种,黑色的是完全随机森林:由500棵决策树组成,每棵树随机选取一个特征作为分裂树的分裂节点,然后一直生成长,直到每个叶节点细分到只有一个类或者不多于10个样本,蓝色的表示普通的随机森林:由500棵决策树组成,每棵树通过随机选取sqrt(d)(d表示输入特征的维度)个候选特征然后通过gini系数筛选分裂节点;
 ●  gcForest采用了DNN中的layer-by-layer结构,从前一层输入的数据和输出结果数据做concat作为下一层的输入;
 ●  为了防止过拟合的情况出现,每个森林的训练都使用了k-折交叉验证,也即每一个训练样本在Forest中都被使用k-1次,产生k-1个类别列表,取平均作为下一个Level级联的输入的一部分;
 ●  当级联扩展到新的Level后,之前所有级联结构的表现通过验证集去评估,如果评估结果没有太大的改变或提升则训练过程结束,因此级联结构的Level的个数被训练过程决定;
 ●  这里要注注意的是,当我们想控制训练过程的loss或限制计算资源的时候,我们也可以使用训练误差,而不是交叉验证的误差同样能够用于控制级联的增长;

 ●  以上这一点就是gcForest和神经网络的区别,gcForest可以通过训练自适应的调整模型的复杂度,并且在恰当的时候停止增加我们的Level;

(2) 多粒度扫描

为了增强级联森林结构我们增加了多粒度扫描,这实际上来源于深度网络中强大的处理特征之间关系能力,多粒度扫描的结构如下图所示

5fb7ea8c2a05a30c44b09c52cd840fe240539753

其过程可描述如下:

先输入一个完整的p维样本(p是样本特征的维度),然后通过一个长度为k的采样窗口进行滑动采样,得到s=(p-k)/1+1个k维特征子样本向量(这个过程就类似于CNN中的卷积核的操作,这里假设窗口移动的步长为1);接着每个子样本都用于完全随机森林和普通随机森林的训练,并在每个森林都获得一个长度为c的概率向量(c是分类类别个数,上图中c=3),这样每个森林都产生一个s*c的表征向量,最后把每层的F个森林的结果拼接在一起,得到样本输出。

上图是一个滑动窗口的简单情形,下图我们展示了多滑动窗口的过程:

29c298d77a9edd8550e7832d4456b75b27e699c2

这里的过程和上图中的过程是一致的,这里要特别注意在每个Level特征维度的变化,并且上图中的结构可以称为级联中的级联,也即每个级联结构中有多个级联子结构。

除了这种结构,我们的多粒度扫描的结构还可以有其他的形式,可以入下图所示:

f57d96d7a392b91505a8eea4e6adfd0d494868ce

这也是一种多粒度扫描结构,被称为gcForest_conc结构,即在多粒度扫描后进行了特征的concatenate,然后再去做级联结构,从实验结果上来看,该结构要稍微逊色于第一种结构。

(3) 小结

以上就是gcForset的模型结构和构建过程,我们可以清晰的看到gcForest的主要超参数:

级联结构中的超参数:

 ●  级联的每层的森林数
 ●  每个森林的决策树的数量
 ●  树停止生长的规则

多粒度扫描中的超参数:

 ●  多粒度扫描的森林数
 ●  每个森林的决策树数
 ●  树的停止生长规则
 ●  滑动窗口的数量和大小

其优点如下:

 ●  计算开销小,单机就相当于DNN中使用GPU(如果你没有钱购买GPU,可以考虑使用gcForest)
 ●  模型效果好(周老师的papar中实验对比了不同模型的效果,gcForest在传统的机器学习,图像,文本,语音上都表现不俗)
 ●  超参数少,模型对超参数不敏感,一套超参数可以用到不同的数据集
 ●  可以适用于不同大小的数据集,模型复杂度可自适用的伸缩
 ●  每个级联生成使用交叉验证,避免过拟合

 ●  相对于DNN,gcForest更容易进行理论分析

4.gcForest模型的Python实现

GitHub上有两个star比较多的gcForest项目,在参考文献中我们已经列出来了,下面我们就使用这两个gcForest的Python模块去尝试使用gcForest模型去解决一些问题,这里要说明的是其中参考文献3是官方提供(由gcForest的作者之一Ji Feng维护)的一个Python版本。目前gcForest并没有相对好用的R语言接口,我们在近期将会推出R语言的gcForest包,敬请期待。这里我们仅介绍参考文献4中的gcForest模块,如果感兴趣,可以自行研究官方提供的gcForest模块(官方模块,集成模型的选择除了随机森林外还可以选择其他的结构像XGBoost,ExtraTreesClassifierLogisticRegression,SGDClassifier等,因此建议使用该模块)。这里就介绍参考文献4中gcForest的模块使用。

Example1: iris数据集预测

 

from GCForest import gcForest
from sklearn.datasets import load_iris, load_digits
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

import pandas as pd
import numpy as np

iris = load_iris()
X = iris.data
y = iris.target
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.33)
print(pd.DataFrame(X_tr).head())

# 注意里边的参数设置,详细的参数意义
# 可以参考源码中的参数解释
gcf = gcForest(shape_1X=4, window=2, tolerance=0.0)
gcf.fit(X_tr, y_tr)

# 类别预测
pred_X = gcf.predict(X_te)
print(pred_X)

pred_X_prob = gcf.predict_proba(X_te)
print(pred_X_prob)

# 模型评估
accuracy = accuracy_score(y_true=y_te, y_pred=pred_X)
print('gcForest accuracy : {}'.format(accuracy))

# 模型保存
from sklearn.externals import joblib
joblib.dump(gcf, 'my_iris_model.sav')

# 模型加载
# joblib.load('my_iris_model.sav')

Example2:Digits数据集预测

 

from GCForest import gcForest
from sklearn.datasets import load_iris, load_digits
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

import pandas as pd
import numpy as np

digits = load_digits()
X = digits.data
y = digits.target
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.4)

# 注意参数设定
gcf = gcForest(shape_1X=[8,8], window=[4,6], tolerance=0.0, min_samples_mgs=10, min_samples_cascade=7)
gcf.fit(X_tr, y_tr)

# 类别预测
pred_X = gcf.predict(X_te)
print(pred_X)

# 模型评估
accuracy = accuracy_score(y_true=y_te, y_pred=pred_X)
print('gcForest accuracy : {}'.format(accuracy))

Example3:多粒度扫描和级联结构分离


因为多粒度扫描和级联结构是相对独立的模块,因此是可以分开的,如果代码中提供了参数y,则会自动去做训练,如果参数y是None,代码会回调最后训练的随机森林进行数据切片。

 

# 模型根据y_tr进行训练
gcf = gcForest(shape_1X=[8,8], window=5, min_samples_mgs=10, min_samples_cascade=7)
X_tr_mgs = gcf.mg_scanning(X_tr, y_tr)

# 回调最后训练的随机森林模型
X_te_mgs = gcf.mg_scanning(X_te)

# 使用多粒度扫描的输出作为级联结构的输入,这里要注意
# 级联结构不能直接返回预测,而是最后一层级联Level的结果
# 因此,需要求平均并且取做大作为预测值

gcf = gcForest(tolerance=0.0, min_samples_mgs=10, min_samples_cascade=7)
_ = gcf.cascade_forest(X_tr_mgs, y_tr)

pred_proba = gcf.cascade_forest(X_te_mgs)
tmp = np.mean(pred_proba, axis=0)
preds = np.argmax(tmp, axis=1)
accuracy_score(y_true=y_te, y_pred=preds)

Example4:去除多粒度扫描的级联结构

我们也可以使用最原始的不带多粒度扫描的级联结构进行预测

 

gcf = gcForest(tolerance=0.0, min_samples_cascade=20)
_ = gcf.cascade_forest(X_tr, y_tr)

pred_proba = gcf.cascade_forest(X_te)
tmp = np.mean(pred_proba, axis=0)
preds = np.argmax(tmp, axis=1)
accuracy_score(y_true=y_te, y_pred=preds)

感兴趣的小伙伴可以研究一下,官方提供(由gcForest的作者之一 Ji Feng维护的)的模块,其实都差不多,如果感兴趣,我们后期也会做相关的介绍。

5.小结

文中我们介绍了gcForest的模型算法和Python代码的实现,目前gcForest算法的官方Python包[参考文献3]并未托管在Pypi,但v1.1.1支持Python3.5,也有大牛实现基于Python3.x的gcForest version0.1.6版本(上一节中已经演示),但其功能要相对弱于参考文献3;如果你喜欢用R语言,我们会在近期推出R语言的gcForest的R包,供R语言用户调用。



原文发布时间为:2018-10-18
本文作者:徐静
本文来自云栖社区合作伙伴“ Python爱好者社区”,了解相关信息可以关注“ Python爱好者社区”。
相关文章
|
28天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
8天前
|
算法 容器
令牌桶算法原理及实现,图文详解
本文介绍令牌桶算法,一种常用的限流策略,通过恒定速率放入令牌,控制高并发场景下的流量,确保系统稳定运行。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
令牌桶算法原理及实现,图文详解
|
17天前
|
负载均衡 算法 应用服务中间件
5大负载均衡算法及原理,图解易懂!
本文详细介绍负载均衡的5大核心算法:轮询、加权轮询、随机、最少连接和源地址散列,帮助你深入理解分布式架构中的关键技术。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
5大负载均衡算法及原理,图解易懂!
|
4天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
21 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
4天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
19 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
4天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
20 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
8天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
25 2
|
9天前
|
搜索推荐 Python
快速排序的 Python 实践:从原理到优化,打造你的排序利器!
本文介绍了 Python 中的快速排序算法,从基本原理、实现代码到优化方法进行了详细探讨。快速排序采用分治策略,通过选择基准元素将数组分为两部分,递归排序。文章还对比了快速排序与冒泡排序的性能,展示了优化前后快速排序的差异。通过这些分析,帮助读者理解快速排序的优势及优化的重要性,从而在实际应用中选择合适的排序算法和优化策略,提升程序性能。
23 1
|
17天前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
18 3
|
20天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
65 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型