Affine層をscalaで実装!
復習
Affine層での処理は以下図の通りでしたね(詳細:図で理解!”学習”の基盤:ニューラルネットワークの”逆伝搬”と”更新”)
ではこの処理を実際に、コードに落とし込んでいきましょう。
作成したいAffine層のクラスの大枠は以下のようになります。
*バッチ数(ここではデータ数と捉えてもらえれば)が1の場合
Affine.scala
class Affine(val xn:Int, val yn:Int) extends Layer {
override type T = Float
//必要な変数宣言
val rand = new util.Random(0)
var W = DenseMatrix.zeros[T](yn,xn).map(_=>rand.nextGaussian.toFloat *0.01f) //重み
var b = DenseVector.zeros[T](yn) //バイアス
var dW = DenseMatrix.zeros[T](yn,xn) //Wの誤差
var db = DenseVector.zeros[T](yn) //bの誤差
var xList = List[Array[T]]() //入力を格納
var sW = DenseMatrix.zeros[T](yn,xn) //update(Adam)で使用
var sb = DenseVector.zeros[T](yn) //update(Adam)で使用
var rW = DenseMatrix.zeros[T](yn,xn) //update(Adam)で使用
var rb = DenseVector.zeros[T](yn) //update(Adam)で使用
var p1t = 1f //update(Adam)で使用
var p2t = 1f //update(Adam)で使用
def push(x:Array[T]) = { xList ::= x; x }
def pop() = { val x = xList.head; xList = xList.tail; x }
def forward()={
//WX+bの処理
}
def backward()={
//WX+bの逆伝搬の処理
}
def update(){
//パラメーター更新
}
def reset(){
//パラメーターの初期化
}
}
forward実装
def forward(x:Array[T]) = {
push(x)
val xv = DenseVector(x) //xをベクトル化
val y = W * xv + b //WX+bの処理
y.toArray //出力を返す
}
backward実装
def backward(d:Array[T]) = {
val x = pop()
val dv = DenseVector(d)
// dW,dbを計算
dW += dv * DenseVector(x).t
db += dv
// dxを計算
var dx = DenseVector.zeros[T](xn)
dx = W.t * dv
dx.toArray //dxを返す
}
update実装(Adam)
def update() {
val ep = 0.01f //学習率
val p1 = 0.9f //モーメントの推定に対する指数減衰率
val p2 = 0.999f //モーメントの推定に対する指数減衰率
val delta = 0.00000001f //数値安定のための小さな定数デルタ
p1t = p1t * p1
p2t = p2t * p2
sW = p1 * sW + (1f-p1) * dW
sb = p1 * sb + (1f-p1) * db
rW = p2 * rW + (1f-p2) * ( dW *:* dW )
rb = p2 * rb + (1f-p2) * ( db *:* db )
val s_W = sW /:/ (1f-p1t)
val s_b = sb /:/ (1f-p1t)
val r_W = rW /:/ (1f-p2t)
val r_b = rb /:/ (1f-p2t)
W += -ep * s_W / (r_W.map(a=>math.sqrt(a).toFloat) + delta ) //パラメーターWの更新
b += -ep * s_b / (r_b.map(a=>math.sqrt(a).toFloat) + delta ) //パラメーターbの更新
}
Adamの更新方法については、別記事で解説予定なので、ここでは
”とりあえずパラメーターを更新している”
と考えてください。
reset実装
def reset() {
dW = DenseMatrix.zeros[T](yn,xn)
db = DenseVector.zeros[T](yn)
xList = List[Array[T]]()
}
まとめ:scalaで実装!Affine層を実装!
実際1つのネットワーク層を実装するとforward,backward,update,resetに大きく分かれ、
それぞれで処理を行います。
次回実装編はConvolution層を実装してみようと思います。