Red DatasetsのMNISTのデータの回答ラベルはt_train[0] = 5
みたいに整数型で入っている。これを[0,0,0,0,0,1,0,0,0,0]
のone-hot vector形式に変換してみる
コード
require 'numo/narray'
def change_one_hot_vector(t)
t_hot = Numo::UInt32.zeros(10 * t.length).reshape(t.length, 10)
t_label = Numo::UInt32.new(t.length).seq * 10 + t
t_hot[t_label] = 1
t_hot
end
結果
=>
> train = Datasets::MNIST.new(type: :train)
> t_train = Numo::NArray.concatenate(train.map{|t| t.label })
> t_hot = change_one_hot_vector(t_train)
> t_hot[[0,1,2,3],true] #とりあえず4つくらい表示
=> Numo::UInt32(view)#shape=[4,10]
[[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]]
> t_hot[1000,true].max_index == t[1000] #一致するかの確認
=> true
問題なく動作した。
これを元にSoftmax-with-Lossレイヤを実装
soft_max_with_loss.rb
require 'numo/narray'
require './functions'
class SoftmaxWithLoss
def initialize
@loss = nil
@y = nil
@t = nil
end
def forward(x, t)
@t = t
@y = softmax(x)
@loss = cross_entropy_error(@y, @t)
@loss
end
def backword(dout=1)
batch_size = @t.shape[0]
t_hot = @t
if @t.size != @y.size
t_hot = change_one_hot_vector(@t)
end
(@y - t_hot) / batch_size
end
private
def change_one_hot_vector(t)
t_hot = Numo::UInt32.zeros(10 * t.length).reshape(t.length, 10)
t_label = Numo::UInt32.new(t.length).seq * 10 + t
t_hot[t_label] = 1
t_hot
end
end