MasaのITC Life

夢は起業家!全てにおいて凡人だけど頑張ることだけはいっちょ前!

AI/機械学習 プログラミング

【機械学習】Go言語でゼロから畳み込みニューラルネットワークを実装する(その1)

投稿日:



前回記事の多層パーセプトロンに続いて、

今回は畳み込みニューラルネットワークを

ゼロから作っていきましょう!



いっぺんに書くと長くなってしまうので、

この記事では特に畳み込み層にフォーカスします。




畳み込み層の概要



まずは畳み込み層の確認をしておきましょう。

素直に実装してありますので、

計算の流れを細かいところまで理解してあれば、

簡単にコードは落とし込めると思います。




畳み込み層は入力に対して、

フィルタ(カーネル)を掛けていきます。



入力とフィルタを1マスづつ順に掛けて総和をとります。

「掛けて総和をとる」という処理単位は、

フィルタサイズ分だけ行い、その後フィルタ自体を少しズラします。



このズラす幅のことをストライドと言い、

画像いっぱいまでズラしたら計算終了です。



もしここでフィルタをズラしていったときに、

画像サイズと合わずに中途半端なところで終わる場合は、

計算の前にパッディングしておきます。



フィルタの計算を終えたら、

最後にバイアスを足して出力を得ます。




畳み込み層のイメージはこんな感じです。






入力には画像が例に使われますが、

その画像がグレースケールではなく、

もしRGBで表現されていた場合、

入力はRGB×縦×横の3次元になります。




ここで実装において注意が必要なのが、

用意するフィルタはRGBそれぞれについて考えます。

例えばフィルタ”群”を3つ用意するとした場合、

実際には9つのフィルタを作る必要があります。



これは1つのフィルタ”群”にそれぞれ、

RGBに対応するフィルタがあるからです。

そもそもフィルタは特徴に反応してほしいものですので、

RGBのRだけに反応してほしい場合だってあるわけです。



「エッジに反応するフィルタ群があって、

その中でもRのエッジに反応してほしい」

フィルタを通した出力(値)は、

Rだけ0以外の値でGBの値はゼロ、

というようなイメージです。




以下がコードの説明になります。



畳み込み層をGo言語でゼロから作ってみる


コードは説明のために分けてありますが、

全てコピペして単純に1つにまとめれば動きます。




畳み込み層への入力はレナさんを使います。



まずは定義まわりのコードです。



3階テンソル、行列、カーネルの構造体を定義しています。

カーネル構造体で、畳み込み層の肝をまとめています。




次はmain文です。



チャネルごとにフィルターを用意するのは、

rgb別の細かいところで特徴を抽出するためです。




続いて入力画像を取得します。

レナさんを入力出来るように

画像データを配列に落とし込みます。

標準のimageパッケージを用います。

画像はpngもしくはjpegのみ受け付けます。



画像をデコードして得られるimage型を

imgToPixels関数で3次元配列に変えています。

img.At(x, y).RGBA()で取得できる値はuint32で、

8バイトRGB値を各々得るには、

コードのようにシフト演算します。




続いてカーネル構造体の設定です。





続いて数学関連の関数です。





続いてパディングするためのメソッドです。

最初にパディングする必要があるかを判断し、

必要なければそのまま戻り、

必要があれば最小限のパディングを行います。



img縦(横)とフィルタ縦(横)の差を

ストライドで割り切れなければパディングします。



パディングを左右(上下)均等にセット出来れば、

左右(上下)に均一のサイズだけパディングし、

もし不均一になるようであれば、

右(下)側がより多くなるようにセットします。




続いて実際の畳み込み計算のメソッドです。



フィルタを掛ける前にパディング済みなので、

計算は画像の隅から隅まで出来るはずです。




最後に活性化関数に関するメソッドです。

とりあえずReLu、LeaklyReLu、Tanhだけ用意しました。





最後まで読んでいただきありがとうございます。


-AI/機械学習, プログラミング

Copyright© MasaのITC Life , 2021 All Rights Reserved Powered by STINGER.