これまで、様々なツールを用いて機械学習の勉強をしてきた。ツールが出る度に試しているのでミーハーなことこの上無いのだが、一応代表的なツールは見てきたつもりだ。
その中で入門として使ってきたのが、関数フィッティングだった。様々な関数を、多項式にフィッティングさせてみる。この題材を使って、各種機械学習のフレームワークでどのような違いがあるのか、比較してまとめてみたいと思う。
- TensorFlow: Googleの開発している機械学習ツール。フロントエンドはPython。 https://www.tensorflow.org/ チュートリアルがかなりしっかりしているので、みんなが飛び付く(私も含む)。
- Chainer: Preferred Networksが開発している機械学習ツール。フロントエンドはPython。 http://chainer.org/ 日本製なので日本語の資料がしっかりしているかと思いきや英語ばかりで苦労する。
- CNTK: Microsoftの開発している機械学習ツール。フロントエンドは謎のDSL。https://www.cntk.ai/ あまり普及していない。Pythonでないのと、資料が膨大すぎてどこから手を付けていいのか途方にくれる。
関数フィッティング問題とは
とあるデータが与えられて、それがどのような多項式に近いのかを学習する。例えば矩形波のデータが与えられた場合、これを7次多項式にフィッティングさせる。
その結果、以下のような波形が得られる。
これをどのように実現するか、ということだ。
基本的には、多項式のモデルを作成し、それに対して入力値と出力値の誤差が最小になるようにパラメータを調整する、という具合になる。
モデルの作成方法
Chainerでの多項式モデルの作成方法
Chainerでは、多項式のモデルを作るというより、ニューラルネットワークをまずは作成し、そこに近い様に入力と出力の接続を構成する。
最初にネットワークの構成を定義し、次に計算方法(forward)を定義するという訳だ。ここでは線形関数を接続していき、全てのノードに対して入力値xを食わせることにより、多項式を実現している。
super(Function3DimentionModel, self).__init__( fc1=chainer.functions.Linear(1, 1, 1), fc2=chainer.functions.Linear(1, 1), fc3=chainer.functions.Linear(1, 1), fc4=chainer.functions.Linear(1, 1), fc5=chainer.functions.Linear(1, 1), fc6=chainer.functions.Linear(1, 1), fc7=chainer.functions.Linear(1, 1), ) def forward(self, x): h1 = self.fc1(x) h2 = self.fc2(h1*x) h3 = self.fc3(h2*x) h4 = self.fc4(h3*x) h5 = self.fc5(h4*x) h6 = self.fc6(h5*x) h7 = self.fc7(h6*x) return h7
TensorFlowでのモデルの作成方法
TensorFlowでは、Pythonの記述を使って多項式をそのまま定義してしまった。ここで、ニューラルネットワークの構造とか、あまり指定することは無い。単純に関数を定義しただけだ。
W3 = tf.Variable(random.random()) W2 = tf.Variable(random.random()) W1 = tf.Variable(random.random()) W0 = tf.Variable(random.random()) y4 = W3*x_data*x_data*x_data+W2*x_data*x_data + W1*x_data + W0
CNTKでのモデルの作成方法
CNTKの場合には、Pythonを使わずに独自の記述言語を利用する。以下は2次多項式の場合。
DNN=[ W1 = Parameter (1, 1, init="uniform", initValueScale=1.0) W2 = Parameter (1, 1, init="uniform", initValueScale=1.0) W3 = Parameter (1, 1, init="uniform", initValueScale=1.0) y0 = Times(W1, ElementTimes(features, features)) y1 = Times(W2, features) y = Plus(Plus(y0, y1), W3)
こちらも、あまりネットワークの構成とか、気にせずにモデルを作成している。
最適化の行い方
Chainerの学習実施方法
Chainerで最適化を実行するためには、先程のネットワークにどんどんデータを入力していき、誤差を0の方向にするためにデータをバックプロパゲートしていく。
まるで本当にニューラルネットワークを触っているような、そんな感覚になる。
def train(self, x_data, y_data): x = chainer.Variable(x_data.astype(np.float32), volatile=False) y = chainer.Variable(y_data.astype(np.float32), volatile=False) h = self.forward(x) optimizer.zero_grads() # error = chainer.functions.sigmoid(h, y) error = F.mean_squared_error(h, y) error.backward() optimizer.update()
TensorFlowでの学習実施方法
TensorFlowでの最適化を実行するのも同様だ。データを入力していき、誤差が0になるように関数の最適化を実行していく。このあたりのモデルは、Chainerととても良く似ている気がする。
loss = tf.reduce_mean(tf.square(y4 - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
CNTKでの学習実施方法
CNTKでの最適化の実施方法だが、上記のChainerやTensorFlowとは異なり、ネットワークの設定パラメータとして記述していく。SGDを使いたいのなら、DNNのパラメータとして指定していく。 このあたりは、Pythonで手続として記述できないので、ちょっと敷居が高い。
Simple_Demo_Train = [ action = "train" NDLNetworkBuilder = [ networkDescription = "$ConfigDir$/Simple2.ndl" ] SGD = [ # epochSize = 0 means epochSize is the size of the training set epochSize = 0 minibatchSize = 2 randomizeRange = 0 learningRatesPerMB = 0.5:0.2*20:0.1 momentumPerMB = 0.9 dropoutRate = 0.0 maxEpochs = 10 ]
3つの機械学習ツールを比較して
ChainerとTensorFlowは、学習のための手続が非常に似ており、Pythonを使って手続を記述できることもあって敷居が低い。気軽に様々なことがトライできるのが利点かもしれない。
一方でCNTKは記述の方法にPythonが使えず、モデルの構築方法も敷居が高い。その分、Microsoftが言っているように、高速なネットワークを構築することが可能、ということかもしれないが、初心者にはちょっと敷居が高いかな。