2019/01/11 追記
RubyからMNISTを利用したい人はRed Datasetsがおすすめです。
RubyでMNISTやCIFAR-10を呼び出すRed Datasetsを使ってみる
RubyでMNIST画像を表示する方法はたくさんあると思います。しかし、ここでは敢えてわかりやすさを捨てて、NArrayの行列計算の威力に頼ることにします。配列の形を変えて、並び替えることでMNIST画像をタイルのように並べて表示しようという方針です。画像ファイルの作成はMiniMagickを使うことにしました。Mnistのデータはred-chainerで呼び出しました。
require 'chainer'
require 'mini_magick'
x, t = Chainer::Datasets::Mnist.get_mnist
pixels = Numo::NArray.concatenate(Array.new(100) { |i| x[i][0] })
pixels = pixels.reshape(10, 10, 28, 28).transpose(0, 2, 1, 3)
str = Numo::UInt8.cast(pixels * 255).to_string
img = MiniMagick::Image.import_pixels(str, 280, 280, 8, 'gray', 'png')
img.write('output.png')
…途中の行列の転置、おわかりいただけたでしょうか。これだけでわかってしまう人はものすごく数学に強い人だと思います(当社比)。
同じ処理をもっとわかりやすく書くと、こんな感じだと思います。
require 'chainer'
require 'mini_magick'
x, t = Chainer::Datasets::Mnist.get_mnist
pixels = Numo::DFloat.zeros(280, 280)
10.times do |i|
10.times do |j|
pixels[i * 28...(i + 1) * 28, j * 28...(j + 1) * 28] = x[i * 10 + j][0].reshape(28, 28)
end
end
str = Numo::UInt8.cast(pixels * 255).to_string
img = MiniMagick::Image.import_pixels(str, 280, 280, 8, 'gray', 'png')
img.write('output.png')
実は、私の場合、reshape や transposeをどうすれば、正しいMNISTの画像が生成できるか、よく考えてもわかりませんでした。
3次元でもわからないのに、4次元になると、本格的に何もわからなくなります。わかる人は尊敬します。
そこで、考えるのはやめて総当りです。permutationを使います。
require 'chainer'
require 'mini_magick'
x, t = Chainer::Datasets::Mnist.get_mnist
pixels = Numo::NArray.concatenate(Array.new(100) { |i| x[i][0] })
[28,28,10,10].permutation.each do |a|
[0,1,2,3].permutation.each do |b|
pixels = pixels.reshape(*a).transpose(*b)
str = Numo::UInt8.cast(pixels * 255).to_string
img = MiniMagick::Image.import_pixels(str, 280, 280, 8, 'gray', 'png')
img.write('png/output#{a}#{b}.png')
end
end
この総当りの過程で生成されたMNistの画像がとても味わい深かったので、いくつかここに載せます。
私が知ってるMNISTは右下だけです。けれども、驚くべきことに上の模様はすべてMNISTです。ただ4次元に持って行って、すこし配列の並び方を変えると、こんな不思議な画像が生成されてしまいました。はたして、今まで私は本当にMNISTを知っていたのでしょうか。それはMNISTの仮初の姿に過ぎなかったのではないでしょうか。
……
不思議な気分になったところで、本日はこの辺で失礼します。