在MapReduce中实现logistic回归和LOESS

来源:互联网 发布:秃瓢淘宝 小龙虾 编辑:程序博客网 时间:2024/04/29 23:27

对MapReduce也用了一段时间,基本的数据处理都已比较熟悉,但目前用的S1的参数和直觉调的参数。这样下去不行啊,果断要开搞机器学习。虽然阿里给我们提供了Xlab,看起来也挺强大的,各种模型都很丰富,但作为一个不造轮子会死的程序猿,还是想实现自己的训练方法和模型,这也有利于后期的提高,所以就找了点资料研究了如何用MapReduce进行机器学习的训练。

MapReduce的入门,可以参考这个文章:http://www.yumumu.me/MapReduce_In_Odps/

本文主要参考了这篇论文Zinkevich1,并实现了一个线性回归的实例,实现很简单,主要想起到抛砖引玉的作用,欢迎大家一起讨论,提出更优的解决办法。

随机梯度下降法的(SGD)基本算法

SGD的基本算法如下:

Algorithm 1 SGD({c(1), . . . , c(m)}, T, η, w0)for t = 1 to T do    Draw j ∈ {1 . . . m} uniformly at random.    w(t) = w(t−1) − η*∂w(c(j))*w(t−1);end forreturn wT
c(i) 表示第i个样本的损失函数,η为学习速率,∂w为w的梯度,T为迭代次数。 算法的主要思想就是每次从样本中随机抽取一个样本,用来训练。

如果要在MapReduce中实现SGD,理论上算法如下:

Algorithm 2 ParallelSGD({c(1), . . . , c(m)}, T, η, w0,k)  for all i ∈ {1, . . . k} parallel do  v(i) = SGD({c(1), . . . , c(m)}, T, η, w0) on client  end for  Aggregate from all computers v =sum(v(1),...,v(k))/k and return v

这个算法需要在每台机器上进行随机梯度下降。但由于使用MapReduce,每次Mapper里面只能是一条条记录读入,无法进行随机选择,所以最终算法如下:

Algorithm 3 SimuParallelSGD({c(1), . . . , c(m)}, T, η, w0,k)for all i ∈ {1, . . . k} parallel do    Randomly shuffle the data on machine i.    Initialize w(i,0) = 0.for all t ∈ {1, . . . T }: do    Get the (t)th example on the (i)th machine (this machine),     w(i,t) = w(i,t−1) − η*∂w(c(i))*w(i,t−1);end for    Aggregate from all computers v =sum(w(1,t),...,v(k,t))/k and return

算法3先把数据进行打乱,并平均分配到每台机器上。每台机器不再进行数据的随机选择,而是一条条读入进行训练,最后再把每台机器的训练结果汇总取平均。

实例:线性回归的MapReduce训练

由于是第一次使用MapReduce,上述算法的实现需要几个条件,现在进行一一测试确认。

  1. 在MapReduce中,每个独立的Mapper对象中是否能够共享变量,且和其他mapper对象独立,因为训练需要保存上一次的结果。这里我在Mapper中使用了一个类内的全局变量count,然后每次调用一次map函数就累加,count如果大于10就不再输出。最后系统产生了259个Mapper,生成的表有2590行数据,这说明每个Mapper对象内的变量是共享且独立的。
  2. 能否自己指定Mapper和Reducer的数量,最后结果要汇总到一台机器,所以Reducer数量必须为1。这个看文档也是可以实现的。但需要注意的是,Mapper的数量直接设置貌似没有效果,需要靠设置spiltSize来调整Mapper大小。

现在就用最简单的一元线性回归来实现一个随机梯度下降的MapperReduce训练过程,损失函数为最小平方和。

(以下代码未测试)

SGDMapper代码:

public class SGDReduce extends ReducerBase{    Record result;    public setup(TaskContext context) throws IOException{        result = context.createOutputRecord();    }    public void reduce(Record key, Iterator <Record> values,TaskContext context) throws IOException{        int count = 0;        double b0 = 0;        double b1 = 0;        while(values.hasNext())        {            Record val = values.next();            b0 += val.getDouble(0);            b1 += val.getDouble(1);            count += 1;        }        b0 /= count;        b1 /= count;        result.set(0,b0);        result.set(1,b1);        context.write(result);    }}

其是需要批量的迭代训练的,这可以在Driver的main函数中调用多次MR任务,并用Jobconf.set 和 get来保存每一次迭代的结果。

此外,在Driver的Main函数中还可以调用sql语句。这就可以利用表作为中转,执行级联的MapReduce任务。

0 0
原创粉丝点击