CPUがガリガリ回る計算が遅い偏微分での二層ニューラルネットを実装。次回は誤差伝搬法で高速実装の予定
基本関数
数値偏微分
二層のニューラルネット
two_layer_neuralnet.rb
require 'numo/narray'
require './functions'
require './numerical_gradient'
class TwoLayerNeuralNet
# 初期化
def initialize(input_size, hidden_size, output_size, weight_init_std = 0.01)
@params = {}
@params['w1'] = weight_init_std * Numo::DFloat.new(input_size, hidden_size).rand_norm
@params['b1'] = Numo::DFloat.zeros(hidden_size)
@params['w2'] = weight_init_std * Numo::DFloat.new(hidden_size, output_size).rand_norm
@params['b2'] = Numo::DFloat.zeros(output_size)
end
# self.paramsで参照できるように
def params
@params
end
# ニューラルネットの行列計算
def predict(x)
w1, w2 = self.params['w1'], self.params['w2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = x.dot(w1) + b1
z1 = sigmoid(a1)
a2 = z1.dot(w2) + b2
softmax(a2)
end
# 誤差伝搬関数
def loss(x, t)
y = self.predict(x)
cross_entropy_error(y, t)
end
# 精度計算
def accuracy(x, t)
y = predict(x)
y = y.max_index(1) % 10
y.eq(t).cast_to(Numo::UInt32).sum / y.shape[0].to_f
end
# 該当の数値微分、最適化
def numerical_gradients(x,t)
loss_w = lambda {|w| loss(x, t) }
grads = {}
grads['w1'] = numerical_gradient(loss_w, self.params['w1'])
grads['b1'] = numerical_gradient(loss_w, self.params['b1'])
grads['w2'] = numerical_gradient(loss_w, self.params['w2'])
grads['b2'] = numerical_gradient(loss_w, self.params['b2'])
grads
end
end
実行関数
exec_numerical_gradent_neuralnet.rb
require 'numo/narray'
require './functions'
require './numerical_gradient'
require './two_layer_neural_net'
require 'datasets'
require 'mini_magick'
train_size = 60000
test_size = 10000
batch_size = 100
iters_num = 10000
learning_rate = 0.1
train = Datasets::MNIST.new(type: :train)
x_train = Numo::NArray.concatenate(train.map{|t| t.pixels }).reshape(train_size,784)
t_train = Numo::NArray.concatenate(train.map{|t| t.label })
test = Datasets::MNIST.new(type: :test)
x_test = Numo::NArray.concatenate(test.map{|t| t.pixels }).reshape(test_size,784)
t_test = Numo::NArray.concatenate(test.map{|t| t.label })
train_loss_list = []
train_acc_list = []
test_acc_list = []
keys = ['w1', 'b1', 'w2', 'b2']
iter_per_epoch = [train_size / batch_size,1].max
network = TwoLayerNeuralNet.new(input_size=784, hidden_size=50, output_size=10)
iters_num.times do |i|
batch_mask = Array.new(batch_size){ rand test_size }
x_batch = x_train[batch_mask, true]
t_batch = t_train[batch_mask]
grad = network.numerical_gradients(x_batch, t_batch)
keys.each do |key|
network.params[key] -= learning_rate * grad[key]
end
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
if i % iter_per_epoch == 0
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
p "train acc, test acc | " + train_acc.to_s + ", " + test_acc.to_s
end
end