Spark MLlib Deep Learning Deep Belief Network (深度学习-深度信念网络)2.1
http://blog.csdn.net/sunbow0
Spark MLlib Deep Learning工具箱,是根据现有深度学习教程《UFLDL教程》中的算法,在SparkMLlib中的实现。具体Spark MLlib Deep Learning(深度学习)目录结构:
第一章Neural Net(NN)
1、源码
2、源码解析
3、实例
第二章Deep Belief Nets(DBNs)
1、源码
2、源码解析
3、实例
第三章Convolution Neural Network(CNN)
第四章 Stacked Auto-Encoders(SAE)
第五章CAE
目前Spark MLlib Deep Learning工具箱源码的github地址为:
https://github.com/sunbow1/SparkMLlibDeepLearn
package DBN
import org.apache.spark._
import org.apache.spark.SparkContext._
import org.apache.spark.rdd.RDD
import org.apache.spark.Logging
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.linalg._
import org.apache.spark.mllib.linalg.distributed.RowMatrix
import breeze.linalg.{
Matrix => BM,
CSCMatrix => BSM,
DenseMatrix => BDM,
Vector => BV,
DenseVector => BDV,
SparseVector => BSV,
axpy => brzAxpy,
svd => brzSvd
}
import breeze.numerics.{
exp => Bexp,
tanh => Btanh
}
import scala.collection.mutable.ArrayBuffer
import java.util.Random
import scala.math._
/**
* W:权重
* b:偏置
* c:偏置
*/
case class DBNweight(
W: BDM[Double],
vW: BDM[Double],
b: BDM[Double],
vb: BDM[Double],
c: BDM[Double],
vc: BDM[Double]) extends Serializable
/**
* 配置参数
*/
case class DBNConfig(
size: Array[Int],
layer: Int,
momentum: Double,
alpha: Double) extends Serializable
/**
* DBN(Deep Belief Network)
*/
class DBN(
private var size: Array[Int],
private var layer: Int,
private var momentum: Double,
private var alpha: Double) extends Serializable with Logging {
// var size=Array(5, 10, 10)
// var layer=3
// var momentum=0.0
// var alpha=1.0
/**
* size = architecture; 网络结构
* layer = numel(nn.size); 网络层数
* momentum = 0.0; Momentum
* alpha = 1.0; alpha
*/
def this() = this(DBN.Architecture, 3, 0.0, 1.0)
/** 设置神经网络结构. Default: [10, 5, 1]. */
def setSize(size: Array[Int]): this.type = {
this.size = size
this
}
/** 设置神经网络层数据. Default: 3. */
def setLayer(layer: Int): this.type = {
this.layer = layer
this
}
/** 设置Momentum. Default: 0.0. */
def setMomentum(momentum: Double): this.type = {
this.momentum = momentum
this
}
/** 设置alpha. Default: 1. */
def setAlpha(alpha: Double): this.type = {
this.alpha = alpha
this
}
/**
* 深度信念网络(Deep Belief Network)
* 运行训练DBNtrain
*/
def DBNtrain(train_d: RDD[(BDM[Double], BDM[Double])], opts: Array[Double]): DBNModel = {
// 参数配置 广播配置
val sc = train_d.sparkContext
val dbnconfig = DBNConfig(size, layer, momentum, alpha)
// 初始化权重
var dbn_W = DBN.InitialW(size)
var dbn_vW = DBN.InitialvW(size)
var dbn_b = DBN.Initialb(size)
var dbn_vb = DBN.Initialvb(size)
var dbn_c = DBN.Initialc(size)
var dbn_vc = DBN.Initialvc(size)
// 训练第1层
printf("Training Level: %d.\n", 1)
val weight0 = new DBNweight(dbn_W(0), dbn_vW(0), dbn_b(0), dbn_vb(0), dbn_c(0), dbn_vc(0))
val weight1 = RBMtrain(train_d, opts, dbnconfig, weight0)
dbn_W(0) = weight1.W
dbn_vW(0) = weight1.vW
dbn_b(0) = weight1.b
dbn_vb(0) = weight1.vb
dbn_c(0) = weight1.c
dbn_vc(0) = weight1.vc
// 打印权重
printf("dbn_W%d.\n", 1)
val tmpw0 = dbn_W(0)
for (i <- 0 to tmpw0.rows - 1) {
for (j <- 0 to tmpw0.cols - 1) {
print(tmpw0(i, j) + "\t")
}
println()
}
// 训练第2层 至 n层
for (i <- 2 to dbnconfig.layer - 1) {
// 前向计算x
// x = sigm(repmat(rbm.c', size(x, 1), 1) + x * rbm.W');
printf("Training Level: %d.\n", i)
val tmp_bc_w = sc.broadcast(dbn_W(i - 2))
val tmp_bc_c = sc.broadcast(dbn_c(i - 2))
val train_d2 = train_d.map { f =>
val lable = f._1
val x = f._2
val x2 = DBN.sigm(x * tmp_bc_w.value.t + tmp_bc_c.value.t)
(lable, x2)
}
// 训练第i层
val weighti = new DBNweight(dbn_W(i - 1), dbn_vW(i - 1), dbn_b(i - 1), dbn_vb(i - 1), dbn_c(i - 1), dbn_vc(i - 1))
val weight2 = RBMtrain(train_d2, opts, dbnconfig, weighti)
dbn_W(i - 1) = weight2.W
dbn_vW(i - 1) = weight2.vW
dbn_b(i - 1) = weight2.b
dbn_vb(i - 1) = weight2.vb
dbn_c(i - 1) = weight2.c
dbn_vc(i - 1) = weight2.vc
// 打印权重
printf("dbn_W%d.\n", i)
val tmpw1 = dbn_W(i - 1)
for (i <- 0 to tmpw1.rows - 1) {
for (j <- 0 to tmpw1.cols - 1) {
print(tmpw1(i, j) + "\t")
}
println()
}
}
new DBNModel(dbnconfig, dbn_W, dbn_b, dbn_c)
}
/**
* 深度信念网络(Deep Belief Network)
* 每一层神经网络进行训练rbmtrain
*/
def RBMtrain(train_t: RDD[(BDM[Double], BDM[Double])],
opts: Array[Double],
dbnconfig: DBNConfig,
weight: DBNweight): DBNweight = {
val sc = train_t.sparkContext
var StartTime = System.currentTimeMillis()
var EndTime = System.currentTimeMillis()
// 权重参数变量
var rbm_W = weight.W
var rbm_vW = weight.vW
var rbm_b = weight.b
var rbm_vb = weight.vb
var rbm_c = weight.c
var rbm_vc = weight.vc
// 广播参数
val bc_config = sc.broadcast(dbnconfig)
// 训练样本数量
val m = train_t.count
// 计算batch的数量
val batchsize = opts(0).toInt
val numepochs = opts(1).toInt
val numbatches = (m / batchsize).toInt
// numepochs是循环的次数
for (i <- 1 to numepochs) {
StartTime = System.currentTimeMillis()
val splitW2 = Array.fill(numbatches)(1.0 / numbatches)
var err = 0.0
// 根据分组权重,随机划分每组样本数据
for (l <- 1 to numbatches) {
// 1 广播权重参数
val bc_rbm_W = sc.broadcast(rbm_W)
val bc_rbm_vW = sc.broadcast(rbm_vW)
val bc_rbm_b = sc.broadcast(rbm_b)
val bc_rbm_vb = sc.broadcast(rbm_vb)
val bc_rbm_c = sc.broadcast(rbm_c)
val bc_rbm_vc = sc.broadcast(rbm_vc)
// // 打印权重
// println(i + "\t" + l)
// val tmpw0 = bc_rbm_W.value
// for (i <- 0 to tmpw0.rows - 1) {
// for (j <- 0 to tmpw0.cols - 1) {
// print(tmpw0(i, j) + "\t")
// }
// println()
// }
// 2 样本划分
val train_split2 = train_t.randomSplit(splitW2, System.nanoTime())
val batch_xy1 = train_split2(l - 1)
// val train_split3 = train_t.filter { f => (f._1 >= batchsize * (l - 1) + 1) && (f._1 <= batchsize * (l)) }
// val batch_xy1 = train_split3.map(f => (f._2, f._3))
// 3 前向计算
// v1 = batch;
// h1 = sigmrnd(repmat(rbm.c', opts.batchsize, 1) + v1 * rbm.W');
// v2 = sigmrnd(repmat(rbm.b', opts.batchsize, 1) + h1 * rbm.W);
// h2 = sigm(repmat(rbm.c', opts.batchsize, 1) + v2 * rbm.W');
// c1 = h1' * v1;
// c2 = h2' * v2;
val batch_vh1 = batch_xy1.map { f =>
val lable = f._1
val v1 = f._2
val h1 = DBN.sigmrnd((v1 * bc_rbm_W.value.t + bc_rbm_c.value.t))
val v2 = DBN.sigmrnd((h1 * bc_rbm_W.value + bc_rbm_b.value.t))
val h2 = DBN.sigm(v2 * bc_rbm_W.value.t + bc_rbm_c.value.t)
val c1 = h1.t * v1
val c2 = h2.t * v2
(lable, v1, h1, v2, h2, c1, c2)
}
// 4 更新前向计算
// rbm.vW = rbm.momentum * rbm.vW + rbm.alpha * (c1 - c2) / opts.batchsize;
// rbm.vb = rbm.momentum * rbm.vb + rbm.alpha * sum(v1 - v2)' / opts.batchsize;
// rbm.vc = rbm.momentum * rbm.vc + rbm.alpha * sum(h1 - h2)' / opts.batchsize;
// W 更新方向
val vw1 = batch_vh1.map {
case (lable, v1, h1, v2, h2, c1, c2) =>
c1 - c2
}
val initw = BDM.zeros[Double](bc_rbm_W.value.rows, bc_rbm_W.value.cols)
val (vw2, countw2) = vw1.treeAggregate((initw, 0L))(
seqOp = (c, v) => {
// c: (m, count), v: (m)
val m1 = c._1
val m2 = m1 + v
(m2, c._2 + 1)
},
combOp = (c1, c2) => {
// c: (m, count)
val m1 = c1._1
val m2 = c2._1
val m3 = m1 + m2
(m3, c1._2 + c2._2)
})
val vw3 = vw2 / countw2.toDouble
rbm_vW = bc_config.value.momentum * bc_rbm_vW.value + bc_config.value.alpha * vw3
// b 更新方向
val vb1 = batch_vh1.map {
case (lable, v1, h1, v2, h2, c1, c2) =>
(v1 - v2)
}
val initb = BDM.zeros[Double](bc_rbm_vb.value.cols, bc_rbm_vb.value.rows)
val (vb2, countb2) = vb1.treeAggregate((initb, 0L))(
seqOp = (c, v) => {
// c: (m, count), v: (m)
val m1 = c._1
val m2 = m1 + v
(m2, c._2 + 1)
},
combOp = (c1, c2) => {
// c: (m, count)
val m1 = c1._1
val m2 = c2._1
val m3 = m1 + m2
(m3, c1._2 + c2._2)
})
val vb3 = vb2 / countb2.toDouble
rbm_vb = bc_config.value.momentum * bc_rbm_vb.value + bc_config.value.alpha * vb3.t
// c 更新方向
val vc1 = batch_vh1.map {
case (lable, v1, h1, v2, h2, c1, c2) =>
(h1 - h2)
}
val initc = BDM.zeros[Double](bc_rbm_vc.value.cols, bc_rbm_vc.value.rows)
val (vc2, countc2) = vc1.treeAggregate((initc, 0L))(
seqOp = (c, v) => {
// c: (m, count), v: (m)
val m1 = c._1
val m2 = m1 + v
(m2, c._2 + 1)
},
combOp = (c1, c2) => {
// c: (m, count)
val m1 = c1._1
val m2 = c2._1
val m3 = m1 + m2
(m3, c1._2 + c2._2)
})
val vc3 = vc2 / countc2.toDouble
rbm_vc = bc_config.value.momentum * bc_rbm_vc.value + bc_config.value.alpha * vc3.t
// 5 权重更新
// rbm.W = rbm.W + rbm.vW;
// rbm.b = rbm.b + rbm.vb;
// rbm.c = rbm.c + rbm.vc;
rbm_W = bc_rbm_W.value + rbm_vW
rbm_b = bc_rbm_b.value + rbm_vb
rbm_c = bc_rbm_c.value + rbm_vc
// 6 计算误差
val dbne1 = batch_vh1.map {
case (lable, v1, h1, v2, h2, c1, c2) =>
(v1 - v2)
}
val (dbne2, counte) = dbne1.treeAggregate((0.0, 0L))(
seqOp = (c, v) => {
// c: (e, count), v: (m)
val e1 = c._1
val e2 = (v :* v).sum
val esum = e1 + e2
(esum, c._2 + 1)
},
combOp = (c1, c2) => {
// c: (e, count)
val e1 = c1._1
val e2 = c2._1
val esum = e1 + e2
(esum, c1._2 + c2._2)
})
val dbne = dbne2 / counte.toDouble
err += dbne
}
EndTime = System.currentTimeMillis()
// 打印误差结果
printf("epoch: numepochs = %d , Took = %d seconds; Average reconstruction error is: %f.\n", i, scala.math.ceil((EndTime - StartTime).toDouble / 1000).toLong, err / numbatches.toDouble)
}
new DBNweight(rbm_W, rbm_vW, rbm_b, rbm_vb, rbm_c, rbm_vc)
}
}
/**
* NN(neural network)
*/
object DBN extends Serializable {
// Initialization mode names
val Activation_Function = "sigm"
val Output = "linear"
val Architecture = Array(10, 5, 1)
/**
* 初始化权重
* 初始化为0
*/
def InitialW(size: Array[Int]): Array[BDM[Double]] = {
// 初始化权重参数
// weights and weight momentum
// dbn.rbm{u}.W = zeros(dbn.sizes(u + 1), dbn.sizes(u));
val n = size.length
val rbm_W = ArrayBuffer[BDM[Double]]()
for (i <- 1 to n - 1) {
val d1 = BDM.zeros[Double](size(i), size(i - 1))
rbm_W += d1
}
rbm_W.toArray
}
/**
* 初始化权重vW
* 初始化为0
*/
def InitialvW(size: Array[Int]): Array[BDM[Double]] = {
// 初始化权重参数
// weights and weight momentum
// dbn.rbm{u}.vW = zeros(dbn.sizes(u + 1), dbn.sizes(u));
val n = size.length
val rbm_vW = ArrayBuffer[BDM[Double]]()
for (i <- 1 to n - 1) {
val d1 = BDM.zeros[Double](size(i), size(i - 1))
rbm_vW += d1
}
rbm_vW.toArray
}
/**
* 初始化偏置向量b
* 初始化为0
*/
def Initialb(size: Array[Int]): Array[BDM[Double]] = {
// 初始化偏置向量b
// weights and weight momentum
// dbn.rbm{u}.b = zeros(dbn.sizes(u), 1);
val n = size.length
val rbm_b = ArrayBuffer[BDM[Double]]()
for (i <- 1 to n - 1) {
val d1 = BDM.zeros[Double](size(i - 1), 1)
rbm_b += d1
}
rbm_b.toArray
}
/**
* 初始化偏置向量vb
* 初始化为0
*/
def Initialvb(size: Array[Int]): Array[BDM[Double]] = {
// 初始化偏置向量b
// weights and weight momentum
// dbn.rbm{u}.vb = zeros(dbn.sizes(u), 1);
val n = size.length
val rbm_vb = ArrayBuffer[BDM[Double]]()
for (i <- 1 to n - 1) {
val d1 = BDM.zeros[Double](size(i - 1), 1)
rbm_vb += d1
}
rbm_vb.toArray
}
/**
* 初始化偏置向量c
* 初始化为0
*/
def Initialc(size: Array[Int]): Array[BDM[Double]] = {
// 初始化偏置向量c
// weights and weight momentum
// dbn.rbm{u}.c = zeros(dbn.sizes(u + 1), 1);
val n = size.length
val rbm_c = ArrayBuffer[BDM[Double]]()
for (i <- 1 to n - 1) {
val d1 = BDM.zeros[Double](size(i), 1)
rbm_c += d1
}
rbm_c.toArray
}
/**
* 初始化偏置向量vc
* 初始化为0
*/
def Initialvc(size: Array[Int]): Array[BDM[Double]] = {
// 初始化偏置向量c
// weights and weight momentum
// dbn.rbm{u}.vc = zeros(dbn.sizes(u + 1), 1);
val n = size.length
val rbm_vc = ArrayBuffer[BDM[Double]]()
for (i <- 1 to n - 1) {
val d1 = BDM.zeros[Double](size(i), 1)
rbm_vc += d1
}
rbm_vc.toArray
}
/**
* Gibbs采样
* X = double(1./(1+exp(-P)) > rand(size(P)));
*/
def sigmrnd(P: BDM[Double]): BDM[Double] = {
val s1 = 1.0 / (Bexp(P * (-1.0)) + 1.0)
val r1 = BDM.rand[Double](s1.rows, s1.cols)
val a1 = s1 :> r1
val a2 = a1.data.map { f => if (f == true) 1.0 else 0.0 }
val a3 = new BDM(s1.rows, s1.cols, a2)
a3
}
/**
* Gibbs采样
* X = double(1./(1+exp(-P)))+1*randn(size(P));
*/
def sigmrnd2(P: BDM[Double]): BDM[Double] = {
val s1 = 1.0 / (Bexp(P * (-1.0)) + 1.0)
val r1 = BDM.rand[Double](s1.rows, s1.cols)
val a3 = s1 + (r1 * 1.0)
a3
}
/**
* sigm激活函数
* X = 1./(1+exp(-P));
*/
def sigm(matrix: BDM[Double]): BDM[Double] = {
val s1 = 1.0 / (Bexp(matrix * (-1.0)) + 1.0)
s1
}
/**
* tanh激活函数
* f=1.7159*tanh(2/3.*A);
*/
def tanh_opt(matrix: BDM[Double]): BDM[Double] = {
val s1 = Btanh(matrix * (2.0 / 3.0)) * 1.7159
s1
}
}
package DBN
import breeze.linalg.{
Matrix => BM,
CSCMatrix => BSM,
DenseMatrix => BDM,
Vector => BV,
DenseVector => BDV,
SparseVector => BSV
}
import org.apache.spark.rdd.RDD
import scala.collection.mutable.ArrayBuffer
class DBNModel(
val config: DBNConfig,
val dbn_W: Array[BDM[Double]],
val dbn_b: Array[BDM[Double]],
val dbn_c: Array[BDM[Double]]) extends Serializable {
/**
* DBN模型转化为NN模型
* 权重转换
*/
def dbnunfoldtonn(outputsize: Int): (Array[Int], Int, Array[BDM[Double]]) = {
//1 size layer 参数转换
val size = if (outputsize > 0) {
val size1 = config.size
val size2 = ArrayBuffer[Int]()
size2 ++= size1
size2 += outputsize
size2.toArray
} else config.size
val layer = if (outputsize > 0) config.layer + 1 else config.layer
//2 dbn_W 参数转换
var initW = ArrayBuffer[BDM[Double]]()
for (i <- 0 to dbn_W.length - 1) {
initW += BDM.horzcat(dbn_c(i), dbn_W(i))
}
(size, layer, initW.toArray)
}
}
转载请注明出处:
http://blog.csdn.net/sunbow0