实际处理和解决机器学习工程化问题过程中,我们很难通过单点完成机器学习模型的训练。这些场景包括在线推荐,CTR预估,Lookalike营销等,当有上亿条数据,上千上万维特征,这些应用涉及到的数据量在10G以上甚至TB级别,那么该如何基于海量数据来训练模型呢?
增量学习与特征选择
增量学习
增量学习即使用小batch的数据中进行学习(有时候也称为online learning)是这种学习方式的核心,因为它能让任何一段时间内内存中只有少量的数据,然后将最终的结果通过Voting的方式产生输出,如下是参考代码
#切分块数
cnt=20
size = math.ceil(len(train) / cnt)
result=[]
for i in range(cnt):
start = size * i
end = (i + 1) * size if (i + 1) * size < len(train) else len(train)
#对数据做batch
slice = train[start:end]
result.append(batch_predict(pd.concat([slice,test]),i))
gc.collect()
特征选择
特征选择即从稀疏的特征中删除特征重要度为0,特征重要度排序较低的特征值,并通过npz的格式将特征持久化,供后续加载,核心代码如下
se = pd.Series(clf.feature_importances_)
se = se[se>0]
##将特征重要性进行排序
col =list(se.sort_values(ascending=False).index)
pd.Series(col).to_csv('data_preprocessing/col_sort_one.csv',index=False)
##打印出来不为零的特征以及个数
print('特征重要性不为零的编码特征有',len(se),'个')
n = clf.best_iteration_
baseloss = clf.best_score_['valid']['auc']
print('baseloss',baseloss)
#通过筛选特征找出最优特征个数
clf = LGBMClassifier(boosting_type='gbdt',
num_leaves=31, max_depth=-1,
learning_rate=0.1, n_estimators=n,
subsample_for_bin=200000, objective=None,
class_weight=None, min_split_gain=0.0,
min_child_weight=0.001,
min_child_samples=20, subsample=1.0, subsample_freq=1,
colsample_bytree=1.0,
reg_alpha=0.0, reg_lambda=0.0, random_state=None,
n_jobs=-1, silent=True)
print('开始进行特征选择计算...')
all_num = int(len(se)/100)*100
print('共有',all_num,'个待计算特征')
loss = []
break_num = 0
for i in range(100,all_num,100):
loss.append(evalsLoss(col[:i]))
if loss[-1]>baseloss:
best_num = i
baseloss = loss[-1]
break_num+=1
print('前',i,'个特征的得分为',loss[-1],'而全量得分',baseloss)
print('\n')
if break_num==2:
break
print('筛选出来最佳特征个数为',best_num,'这下子训练速度终于可以大大提升了')
如上所述,我们介绍了增量学习+特征选择的方式,他适用的场景普遍在数据量在10G左右的单机计算,这种方式也适用于开发人员也可以通过阿里PAI搭载计算资源Maxcompute来做模型验证,采用这种方式有如下优势
优势:
- 模型的泛化能力最强,性能最好;
- 易于部署和模型迭代;
- 支持较为复杂的树模型,模型可解释强;
局限:
- 仅适用于单机场景,超过100G级别的数据很难训练;
MMLSpark
Spark 是为通用数据处理而设计的,并非专用于机器学习任务 ,所以真正意义下Spark不是一个机器学习框架。 要在 Spark 上运行机器学习任务,可以使用 MLlib for Spark;但该方案通常存在如下局限:
- 不支持较为复杂的模型,如集成树模型的训练;
- 适用的场景多为baseline,对于参数的选择支持有限,需要开发者自己重构(比如kmeans算法,spark内部使用的两个向量间的距离是欧式距离。如果希望调整为余弦或者马氏距离,就需要重构了);
- 对网格调参支持并不理想;
鉴于此,微软开发了MMLSpark,为Apache Spark提供了一些深入的学习和数据科学工具,实现了将机器学习组件 CNTK、LightGBM 和 Spark的 统一,至此:
- 我们可以基于Spark来运行集成树模型的任务;
- 能够对叶子节点设置等复杂参数来做调整;
- 支持超参数的搜索
示例代码如下:
# 实例化一个LightGBM Regressor, 其参数和单机版本类似但不尽相同, 文档可以在以下链接找到:
# https://mmlspark.azureedge.net/docs/pyspark/LightGBMRegressor.html
lgbm = LightGBMRegressor(numIterations=120, objective='binary',
learningRate=0.007, baggingSeed=50,
boostingType="goss", lambdaL1=0.4, lambdaL2=0.4,
baggingFraction=0.87, minSumHessianInLeaf=0.003,
maxDepth=9, featureFraction=0.66, numLeaves=47,
labelCol="TARGET")
MMLSpark对比增量学习有如下优势
优势:
- 分布式训练;
- 支持PB级别数据训练建模;
局限:
- 环境搭建与维护成本过于复杂;
Tensorflow等深度学习框架
将数据集均等地分配到系统的各个节点(node),其中每个节点都有该神经网络的一个副本及其本地的权重。每个节点都会处理该数据集的一个不同子集并更新其本地权重集。这些本地权重会在整个集群*享,从而通过一个累积算法计算出一个新的全局权重集。这些全局权重又会被分配至所有节点,然后节点会在此基础上处理下一批数据
如上图所示,在 TensorFlow 中,分布式机器学习训练就使用了参数服务器方法(PS)。实现了数据集的并行处理和参数的全局共享
采用深度学习框架的优势如下
优势:
- Tensorflow、Mxnet与Pytorch天然支持分布式训练,配置简单灵活;
局限:
- 机器学习场景下,缺乏可解释性
- 数据并行计算带来了开发门槛
除开上述方法,如果采用阿里云的Maxcompute+Dataworks,可尝试机器学习PAI的方式做海量的数据建模,PAI屏蔽了分布式环境产生的开发复杂度,无需环境的配置与运维,应该说也是个“降本增效”的选择
在最新的版本中,PAI支持了小数据集模型运算,可以让开发者先跑通流程,在验证之成功后方可进行大规模数据的计算。