🐙

mruby-tflite-xnnpack を作った。

2022/01/28に公開

はじめに

以前、MRuby から TensorFlow Lite を扱える mruby-tflite を以前作りました。

https://mattn.kaoriya.net/software/lang/c/20190417102631.htm

またこの mrbgem から Coral EdgeTPU の delegate を使えるプラグイン的な mruby-tflite-edgetpu を作りました。

https://mattn.kaoriya.net/software/lang/c/20191130201502.htm

今回は XNNPACK delegate を作りました。

https://github.com/mattn/mruby-tflite-xnnpack

これにより、Coral EdgeTPU を持ってない人でも、高速(通常よりは)な推論ができる様になります。

どんな事ができるか

EdgeTPU delegate と同じく、mruby-tflite から delegate として追加できる様になっています。

options = TfLite::InterpreterOptions.new
options.add_delegate TfLite::XNNPACK.new(4)

model = TfLite::Model.from_file 'detect.tflite'
interpreter = TfLite::Interpreter.new(model, options)

引数はスレッド数です。最近の XNNPACK は随分と速くなった様で、先日 go-tflite という Go から TensorFlow Lite を扱えるパッケージで試した所、CPU だけで 30fps 出てビックリしてしまいました。

うごく物

MRuby には現状、OpenCV で描画もできるライブラリが無いので、端末上に推論結果を出す様な物しかできません。

#! ./bin/mruby

options = TfLite::InterpreterOptions.new
options.add_delegate TfLite::XNNPACK.new(4)

model = TfLite::Model.from_file 'detect.tflite'
interpreter = TfLite::Interpreter.new(model, options)
interpreter.allocate_tensors
input = interpreter.input_tensor(0)
output2 = interpreter.output_tensor(1)
output3 = interpreter.output_tensor(2)
wanted_width = input.dim(1)
wanted_height = input.dim(2)
wanted_channel = input.dim(3)
data = Array.new(wanted_height * wanted_width * wanted_channel, 0)
labels = File.read('labelmap.txt').lines.map(&:chomp)

cam = Webcam.new(ARGV[0]||0)
cam.set_size(wanted_width, wanted_height)
cam.each(true) do |img|
  decoded = GD::Image.new_from_jpeg_data(img)
  (0...wanted_width).each do |x|
    (0...wanted_height).each do |y|
      pixel = decoded.get_pixel(x, y)
      offset = (y * wanted_width + x) * wanted_channel
      data[offset..offset+2] = [decoded.red(pixel), decoded.green(pixel), decoded.blue(pixel)]
    end
  end
  decoded.destroy
  input.data = data
  interpreter.invoke
  result = []
  output3.data.each_with_index do |v, i|
    next if v < 0.6
    result.push([v, output2.data[i]])
  end
  result.sort{|a, b| b[0] <=> a[0] }.take(5).each_with_index do |v, i|
    s = v[0]
    i = v[1] + 1
    puts "#{labels[i]} #{i} #{s}"
  end 
  puts "---"
end

画像を読み込んで、配列に詰め直す部分が遅すぎて 15fps 程度しか出ませんが、なんとか動きます。OpenCV があれば...

おわりに

いやー、MRuby から OpenCV 扱いたいー!(自分で作れ)

Discussion