LoginSignup
1
0

More than 3 years have passed since last update.

scalaで実装!Affine層を実装してみた!

Posted at

Affine層をscalaで実装!

復習

Affine層での処理は以下図の通りでしたね(詳細:図で理解!”学習”の基盤:ニューラルネットワークの”逆伝搬”と”更新”

Affine計算グラフ.png
Affine計算グラフ逆伝搬.png

ではこの処理を実際に、コードに落とし込んでいきましょう。

作成したい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層を実装してみようと思います。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0