menoh 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +55 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Dockerfile +49 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +80 -0
- data/Rakefile +18 -0
- data/Vagrantfile +46 -0
- data/bin/console +10 -0
- data/bin/setup +6 -0
- data/docs/tutorial.md +121 -0
- data/example/data/0.png +0 -0
- data/example/data/1.png +0 -0
- data/example/data/2.png +0 -0
- data/example/data/3.png +0 -0
- data/example/data/4.png +0 -0
- data/example/data/5.png +0 -0
- data/example/data/6.png +0 -0
- data/example/data/7.png +0 -0
- data/example/data/8.png +0 -0
- data/example/data/9.png +0 -0
- data/example/data/mnist.onnx +0 -0
- data/example/example_mnist.rb +74 -0
- data/example/example_mnist_with_block.rb +75 -0
- data/example/example_vgg16.rb +89 -0
- data/ext/menoh_native/extconf.rb +14 -0
- data/ext/menoh_native/menoh_ruby.c +328 -0
- data/ext/menoh_native/menoh_ruby.h +7 -0
- data/lib/menoh.rb +87 -0
- data/lib/menoh/version.rb +3 -0
- data/menoh.gemspec +29 -0
- metadata +146 -0
data/example/data/0.png
ADDED
Binary file
|
data/example/data/1.png
ADDED
Binary file
|
data/example/data/2.png
ADDED
Binary file
|
data/example/data/3.png
ADDED
Binary file
|
data/example/data/4.png
ADDED
Binary file
|
data/example/data/5.png
ADDED
Binary file
|
data/example/data/6.png
ADDED
Binary file
|
data/example/data/7.png
ADDED
Binary file
|
data/example/data/8.png
ADDED
Binary file
|
data/example/data/9.png
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rmagick'
|
2
|
+
require 'menoh'
|
3
|
+
|
4
|
+
# load dataset
|
5
|
+
image_list = [
|
6
|
+
'./data/0.png',
|
7
|
+
'./data/1.png',
|
8
|
+
'./data/2.png',
|
9
|
+
'./data/3.png',
|
10
|
+
'./data/4.png',
|
11
|
+
'./data/5.png',
|
12
|
+
'./data/6.png',
|
13
|
+
'./data/7.png',
|
14
|
+
'./data/8.png',
|
15
|
+
'./data/9.png'
|
16
|
+
]
|
17
|
+
input_shape = {
|
18
|
+
channel_num: 1,
|
19
|
+
width: 28,
|
20
|
+
height: 28
|
21
|
+
}
|
22
|
+
|
23
|
+
# load ONNX file
|
24
|
+
onnx_obj = Menoh::Menoh.new './data/mnist.onnx'
|
25
|
+
|
26
|
+
# onnx variable name
|
27
|
+
MNIST_IN_NAME = '139900320569040'.freeze
|
28
|
+
MNIST_OUT_NAME = '139898462888656'.freeze
|
29
|
+
|
30
|
+
# model options for model
|
31
|
+
model_opt = {
|
32
|
+
backend: 'mkldnn',
|
33
|
+
input_layers: [
|
34
|
+
{
|
35
|
+
name: MNIST_IN_NAME,
|
36
|
+
dims: [
|
37
|
+
image_list.length,
|
38
|
+
input_shape[:channel_num],
|
39
|
+
input_shape[:width],
|
40
|
+
input_shape[:height]
|
41
|
+
]
|
42
|
+
}
|
43
|
+
],
|
44
|
+
output_layers: [MNIST_OUT_NAME]
|
45
|
+
}
|
46
|
+
# make model for inference under 'model_opt'
|
47
|
+
model = onnx_obj.make_model model_opt
|
48
|
+
|
49
|
+
# prepare dataset
|
50
|
+
image_set = [
|
51
|
+
{
|
52
|
+
name: MNIST_IN_NAME,
|
53
|
+
data: image_list.map do |image_filepath|
|
54
|
+
image = Magick::Image.read(image_filepath).first
|
55
|
+
image = image.resize_to_fill(input_shape[:width], input_shape[:height])
|
56
|
+
image.export_pixels(0, 0, image.columns, image.rows, 'i').map { |pix| pix / 256 }
|
57
|
+
end.flatten
|
58
|
+
}
|
59
|
+
]
|
60
|
+
# execute inference
|
61
|
+
inferenced_results = model.run image_set
|
62
|
+
|
63
|
+
categories = (0..9).to_a
|
64
|
+
TOP_K = 1
|
65
|
+
layer_result = inferenced_results.find { |x| x[:name] == MNIST_OUT_NAME }
|
66
|
+
layer_result[:data].zip(image_list).each do |image_result, image_filepath|
|
67
|
+
# sort by score
|
68
|
+
sorted_result = image_result.zip(categories).sort_by { |x| -x[0] }
|
69
|
+
|
70
|
+
# display result
|
71
|
+
sorted_result[0, TOP_K].each do |score, category|
|
72
|
+
puts "#{image_filepath} = #{category} : #{score}"
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'rmagick'
|
2
|
+
require 'menoh'
|
3
|
+
|
4
|
+
# load dataset
|
5
|
+
image_list = [
|
6
|
+
'./data/0.png',
|
7
|
+
'./data/1.png',
|
8
|
+
'./data/2.png',
|
9
|
+
'./data/3.png',
|
10
|
+
'./data/4.png',
|
11
|
+
'./data/5.png',
|
12
|
+
'./data/6.png',
|
13
|
+
'./data/7.png',
|
14
|
+
'./data/8.png',
|
15
|
+
'./data/9.png'
|
16
|
+
]
|
17
|
+
input_shape = {
|
18
|
+
channel_num: 1,
|
19
|
+
width: 28,
|
20
|
+
height: 28
|
21
|
+
}
|
22
|
+
|
23
|
+
# onnx variable name
|
24
|
+
MNIST_IN_NAME = '139900320569040'.freeze
|
25
|
+
MNIST_OUT_NAME = '139898462888656'.freeze
|
26
|
+
|
27
|
+
# model options for model
|
28
|
+
model_opt = {
|
29
|
+
backend: 'mkldnn',
|
30
|
+
input_layers: [
|
31
|
+
{
|
32
|
+
name: MNIST_IN_NAME,
|
33
|
+
dims: [
|
34
|
+
image_list.length,
|
35
|
+
input_shape[:channel_num],
|
36
|
+
input_shape[:width],
|
37
|
+
input_shape[:height]
|
38
|
+
]
|
39
|
+
}
|
40
|
+
],
|
41
|
+
output_layers: [MNIST_OUT_NAME]
|
42
|
+
}
|
43
|
+
|
44
|
+
# load ONNX file
|
45
|
+
Menoh::Menoh.new './data/mnist.onnx' do |onnx_obj|
|
46
|
+
# make model for inference under 'model_opt'
|
47
|
+
onnx_obj.make_model model_opt do |model|
|
48
|
+
# prepare dataset
|
49
|
+
image_set = [
|
50
|
+
{
|
51
|
+
name: MNIST_IN_NAME,
|
52
|
+
data: image_list.map do |image_filepath|
|
53
|
+
image = Magick::Image.read(image_filepath).first
|
54
|
+
image = image.resize_to_fill(input_shape[:width], input_shape[:height])
|
55
|
+
image.export_pixels(0, 0, image.columns, image.rows, 'i').map { |pix| pix / 256 }
|
56
|
+
end.flatten
|
57
|
+
}
|
58
|
+
]
|
59
|
+
# execute inference
|
60
|
+
model.run image_set do |inferenced_results|
|
61
|
+
categories = (0..9).to_a
|
62
|
+
TOP_K = 1
|
63
|
+
layer_result = inferenced_results.find { |x| x[:name] == MNIST_OUT_NAME }
|
64
|
+
layer_result[:data].zip(image_list).each do |image_result, image_filepath|
|
65
|
+
# sort by score
|
66
|
+
sorted_result = image_result.zip(categories).sort_by { |x| -x[0] }
|
67
|
+
|
68
|
+
# display result
|
69
|
+
sorted_result[0, TOP_K].each do |score, category|
|
70
|
+
puts "#{image_filepath} = #{category} : #{score}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'rmagick'
|
3
|
+
require 'menoh'
|
4
|
+
# TODO revise api
|
5
|
+
# download dependencies
|
6
|
+
def download_file(url, output)
|
7
|
+
return if File.exist? output
|
8
|
+
puts "downloading... #{url}"
|
9
|
+
File.open(output, 'wb') do |f_output|
|
10
|
+
open(url, 'rb') do |f_input|
|
11
|
+
f_output.write f_input.read
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
download_file('https://www.dropbox.com/s/bjfn9kehukpbmcm/VGG16.onnx?dl=1', './data/VGG16.onnx')
|
16
|
+
download_file('https://raw.githubusercontent.com/HoldenCaulfieldRye/caffe/master/data/ilsvrc12/synset_words.txt', './data/synset_words.txt')
|
17
|
+
download_file('https://upload.wikimedia.org/wikipedia/commons/5/54/Light_sussex_hen.jpg', './data/Light_sussex_hen.jpg')
|
18
|
+
download_file('https://upload.wikimedia.org/wikipedia/commons/f/fd/FoS20162016_0625_151036AA_%2827826100631%29.jpg', './data/honda_nsx.jpg')
|
19
|
+
|
20
|
+
# load dataset
|
21
|
+
image_list = [
|
22
|
+
'./data/Light_sussex_hen.jpg',
|
23
|
+
'./data/honda_nsx.jpg'
|
24
|
+
]
|
25
|
+
input_shape = {
|
26
|
+
channel_num: 3,
|
27
|
+
width: 224,
|
28
|
+
height: 224
|
29
|
+
}
|
30
|
+
|
31
|
+
# load ONNX file
|
32
|
+
onnx_obj = Menoh::Menoh.new './data/VGG16.onnx'
|
33
|
+
|
34
|
+
# onnx variable name
|
35
|
+
CONV1_1_IN_NAME = '140326425860192'.freeze
|
36
|
+
FC6_OUT_NAME = '140326200777584'.freeze
|
37
|
+
SOFTMAX_OUT_NAME = '140326200803680'.freeze
|
38
|
+
|
39
|
+
# model options for model
|
40
|
+
model_opt = {
|
41
|
+
backend: 'mkldnn',
|
42
|
+
input_layers: [
|
43
|
+
{
|
44
|
+
name: CONV1_1_IN_NAME,
|
45
|
+
dims: [
|
46
|
+
image_list.length,
|
47
|
+
input_shape[:channel_num],
|
48
|
+
input_shape[:width],
|
49
|
+
input_shape[:height]
|
50
|
+
]
|
51
|
+
}
|
52
|
+
],
|
53
|
+
output_layers: [FC6_OUT_NAME, SOFTMAX_OUT_NAME]
|
54
|
+
}
|
55
|
+
# make model for inference under 'model_opt'
|
56
|
+
model = onnx_obj.make_model model_opt
|
57
|
+
|
58
|
+
# prepare dataset
|
59
|
+
image_set = [
|
60
|
+
{
|
61
|
+
name: CONV1_1_IN_NAME,
|
62
|
+
data: image_list.map do |image_filepath|
|
63
|
+
image = Magick::Image.read(image_filepath).first
|
64
|
+
image = image.resize_to_fill(input_shape[:width], input_shape[:height])
|
65
|
+
'BGR'.split('').map do |color|
|
66
|
+
image.export_pixels(0, 0, image.columns, image.rows, color).map { |pix| pix / 256 }
|
67
|
+
end.flatten
|
68
|
+
end.flatten
|
69
|
+
}
|
70
|
+
]
|
71
|
+
|
72
|
+
# execute inference
|
73
|
+
inferenced_results = model.run image_set
|
74
|
+
|
75
|
+
# load category definition
|
76
|
+
categories = File.read('./data/synset_words.txt').split("\n")
|
77
|
+
TOP_K = 5
|
78
|
+
layer_result = inferenced_results.find { |x| x[:name] == SOFTMAX_OUT_NAME }
|
79
|
+
layer_result[:data].zip(image_list).each do |image_result, image_filepath|
|
80
|
+
puts "=== Result for #{image_filepath} ==="
|
81
|
+
|
82
|
+
# sort by score
|
83
|
+
sorted_result = image_result.zip(categories).sort_by { |x| -x[0] }
|
84
|
+
|
85
|
+
# display result
|
86
|
+
sorted_result[0, TOP_K].each do |score, category|
|
87
|
+
puts "#{category} : #{score}"
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
# have_library("stdc++")
|
4
|
+
have_library('mkldnn')
|
5
|
+
have_library('protobuf')
|
6
|
+
|
7
|
+
menoh_dir = dir_config('menoh')
|
8
|
+
$INCFLAGS << " -I#{menoh_dir[0]}/menoh"
|
9
|
+
have_library('menoh')
|
10
|
+
|
11
|
+
# $CPPFLAGS << " -std=c++14"
|
12
|
+
$DLDFLAGS << ' -rdynamic'
|
13
|
+
|
14
|
+
create_makefile('menoh/menoh_native')
|
@@ -0,0 +1,328 @@
|
|
1
|
+
#include "menoh_ruby.h"
|
2
|
+
|
3
|
+
#define ERROR_CHECK(statement, exceptiontype) \
|
4
|
+
{ \
|
5
|
+
menoh_error_code ec = statement; \
|
6
|
+
if (ec) { \
|
7
|
+
rb_raise(exceptiontype, "%s", menoh_get_last_error_message()); \
|
8
|
+
return Qnil; \
|
9
|
+
} \
|
10
|
+
}
|
11
|
+
|
12
|
+
typedef struct menoh_ruby {
|
13
|
+
menoh_model_data_handle model_data;
|
14
|
+
} menoh_ruby;
|
15
|
+
|
16
|
+
static menoh_ruby *getONNX(VALUE self) {
|
17
|
+
menoh_ruby *p;
|
18
|
+
Data_Get_Struct(self, menoh_ruby, p);
|
19
|
+
return p;
|
20
|
+
}
|
21
|
+
|
22
|
+
static void wrap_menoh_free(menoh_ruby *p) {
|
23
|
+
if (p) {
|
24
|
+
if (p->model_data) menoh_delete_model_data(p->model_data);
|
25
|
+
ruby_xfree(p);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
static VALUE wrap_menoh_alloc(VALUE klass) {
|
30
|
+
void *p = ruby_xmalloc(sizeof(menoh_ruby));
|
31
|
+
memset(p, 0, sizeof(menoh_ruby));
|
32
|
+
return Data_Wrap_Struct(klass, NULL, wrap_menoh_free, p);
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE wrap_menoh_init(VALUE self, VALUE vfilename) {
|
36
|
+
menoh_error_code ec = menoh_error_code_success;
|
37
|
+
FilePathValue(vfilename);
|
38
|
+
char *filename = StringValueCStr(vfilename);
|
39
|
+
|
40
|
+
// Load ONNX model
|
41
|
+
menoh_model_data_handle model_data;
|
42
|
+
ERROR_CHECK(menoh_make_model_data_from_onnx(filename, &model_data),
|
43
|
+
rb_eArgError);
|
44
|
+
getONNX(self)->model_data = model_data;
|
45
|
+
|
46
|
+
return Qnil;
|
47
|
+
}
|
48
|
+
|
49
|
+
typedef struct menohModel {
|
50
|
+
menoh_model_data_handle model_data;
|
51
|
+
VALUE vbackend;
|
52
|
+
float **input_buffs;
|
53
|
+
float **output_buffs;
|
54
|
+
menoh_variable_profile_table_builder_handle vpt_builder;
|
55
|
+
menoh_variable_profile_table_handle variable_profile_table;
|
56
|
+
menoh_model_builder_handle model_builder;
|
57
|
+
menoh_model_handle model;
|
58
|
+
VALUE vinput_layers;
|
59
|
+
VALUE voutput_layers;
|
60
|
+
int32_t input_layer_num;
|
61
|
+
} menohModel;
|
62
|
+
|
63
|
+
static menohModel *getModel(VALUE self) {
|
64
|
+
menohModel *p;
|
65
|
+
Data_Get_Struct(self, menohModel, p);
|
66
|
+
return p;
|
67
|
+
}
|
68
|
+
|
69
|
+
static void wrap_model_free(menohModel *p) {
|
70
|
+
if (p) {
|
71
|
+
if (p->variable_profile_table)
|
72
|
+
menoh_delete_variable_profile_table(p->variable_profile_table);
|
73
|
+
if (p->vpt_builder)
|
74
|
+
menoh_delete_variable_profile_table_builder(p->vpt_builder);
|
75
|
+
if (p->model) menoh_delete_model(p->model);
|
76
|
+
if (p->model_builder) menoh_delete_model_builder(p->model_builder);
|
77
|
+
if (p->input_buffs) {
|
78
|
+
for (int32_t i = 0; i < p->input_layer_num; i++) {
|
79
|
+
if (p->input_buffs[i]) ruby_xfree(p->input_buffs[i]);
|
80
|
+
}
|
81
|
+
ruby_xfree(p->input_buffs);
|
82
|
+
}
|
83
|
+
if (p->output_buffs) ruby_xfree(p->output_buffs);
|
84
|
+
ruby_xfree(p);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
static void wrap_model_mark(menohModel *p) {
|
89
|
+
if (p) {
|
90
|
+
if (p->vbackend) rb_gc_mark(p->vbackend);
|
91
|
+
if (p->vinput_layers) rb_gc_mark(p->vinput_layers);
|
92
|
+
if (p->voutput_layers) rb_gc_mark(p->voutput_layers);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
static VALUE wrap_model_alloc(VALUE klass) {
|
97
|
+
void *p = ruby_xmalloc(sizeof(menohModel));
|
98
|
+
memset(p, 0, sizeof(menohModel));
|
99
|
+
return Data_Wrap_Struct(klass, wrap_model_mark, wrap_model_free, p);
|
100
|
+
}
|
101
|
+
|
102
|
+
static VALUE wrap_model_init(VALUE self, VALUE vonnx, VALUE option) {
|
103
|
+
// option
|
104
|
+
getModel(self)->model_data = getONNX(vonnx)->model_data;
|
105
|
+
VALUE vbackend = rb_hash_aref(option, rb_to_symbol(rb_str_new2("backend")));
|
106
|
+
getModel(self)->vbackend = vbackend;
|
107
|
+
|
108
|
+
// option
|
109
|
+
VALUE vinput_layers =
|
110
|
+
rb_hash_aref(option, rb_to_symbol(rb_str_new2("input_layers")));
|
111
|
+
VALUE voutput_layers =
|
112
|
+
rb_hash_aref(option, rb_to_symbol(rb_str_new2("output_layers")));
|
113
|
+
|
114
|
+
getModel(self)->vinput_layers = vinput_layers;
|
115
|
+
getModel(self)->voutput_layers = voutput_layers;
|
116
|
+
|
117
|
+
// get vpt builder
|
118
|
+
ERROR_CHECK(
|
119
|
+
menoh_make_variable_profile_table_builder(&(getModel(self)->vpt_builder)),
|
120
|
+
rb_eStandardError);
|
121
|
+
|
122
|
+
// set output_layer
|
123
|
+
int32_t output_layer_num =
|
124
|
+
NUM2INT(rb_funcall(voutput_layers, rb_intern("length"), 0, NULL));
|
125
|
+
for (int32_t i = 0; i < output_layer_num; i++) {
|
126
|
+
VALUE voutput_layer = rb_ary_entry(voutput_layers, i);
|
127
|
+
ERROR_CHECK(menoh_variable_profile_table_builder_add_output_profile(
|
128
|
+
getModel(self)->vpt_builder, StringValueCStr(voutput_layer),
|
129
|
+
menoh_dtype_float),
|
130
|
+
rb_eStandardError);
|
131
|
+
}
|
132
|
+
|
133
|
+
// set input layer
|
134
|
+
int32_t input_layer_num =
|
135
|
+
NUM2INT(rb_funcall(vinput_layers, rb_intern("length"), 0, NULL));
|
136
|
+
getModel(self)->input_layer_num = input_layer_num;
|
137
|
+
for (int32_t i = 0; i < input_layer_num; i++) {
|
138
|
+
VALUE vinput_layer = rb_ary_entry(vinput_layers, i);
|
139
|
+
VALUE vname = rb_hash_aref(vinput_layer, rb_to_symbol(rb_str_new2("name")));
|
140
|
+
VALUE vdims = rb_hash_aref(vinput_layer, rb_to_symbol(rb_str_new2("dims")));
|
141
|
+
int32_t dims_length =
|
142
|
+
NUM2INT(rb_funcall(vdims, rb_intern("length"), 0, NULL));
|
143
|
+
|
144
|
+
switch (dims_length) {
|
145
|
+
case 2:
|
146
|
+
ERROR_CHECK(
|
147
|
+
menoh_variable_profile_table_builder_add_input_profile_dims_2(
|
148
|
+
getModel(self)->vpt_builder, StringValueCStr(vname),
|
149
|
+
menoh_dtype_float, NUM2INT(rb_ary_entry(vdims, 0)),
|
150
|
+
NUM2INT(rb_ary_entry(vdims, 1))),
|
151
|
+
rb_eStandardError);
|
152
|
+
break;
|
153
|
+
case 4:
|
154
|
+
ERROR_CHECK(
|
155
|
+
menoh_variable_profile_table_builder_add_input_profile_dims_4(
|
156
|
+
getModel(self)->vpt_builder, StringValueCStr(vname),
|
157
|
+
menoh_dtype_float, NUM2INT(rb_ary_entry(vdims, 0)),
|
158
|
+
NUM2INT(rb_ary_entry(vdims, 1)),
|
159
|
+
NUM2INT(rb_ary_entry(vdims, 2)),
|
160
|
+
NUM2INT(rb_ary_entry(vdims, 3))),
|
161
|
+
rb_eStandardError);
|
162
|
+
break;
|
163
|
+
default:
|
164
|
+
rb_raise(rb_eStandardError, "invalid dimension length");
|
165
|
+
return Qnil;
|
166
|
+
}
|
167
|
+
|
168
|
+
// build variable provile table
|
169
|
+
ERROR_CHECK(menoh_build_variable_profile_table(
|
170
|
+
getModel(self)->vpt_builder, getModel(self)->model_data,
|
171
|
+
&(getModel(self)->variable_profile_table)),
|
172
|
+
rb_eStandardError);
|
173
|
+
|
174
|
+
// optimize
|
175
|
+
ERROR_CHECK(
|
176
|
+
menoh_model_data_optimize(getModel(self)->model_data,
|
177
|
+
getModel(self)->variable_profile_table),
|
178
|
+
rb_eStandardError);
|
179
|
+
|
180
|
+
// get model buildler
|
181
|
+
ERROR_CHECK(menoh_make_model_builder(getModel(self)->variable_profile_table,
|
182
|
+
&(getModel(self)->model_builder)),
|
183
|
+
rb_eStandardError);
|
184
|
+
|
185
|
+
// attach input buffer to model builder
|
186
|
+
getModel(self)->input_buffs =
|
187
|
+
(float **)ruby_xmalloc(sizeof(float **) * input_layer_num);
|
188
|
+
for (int32_t i = 0; i < input_layer_num; i++) {
|
189
|
+
VALUE vinput_layer = rb_ary_entry(vinput_layers, i);
|
190
|
+
VALUE vname =
|
191
|
+
rb_hash_aref(vinput_layer, rb_to_symbol(rb_str_new2("name")));
|
192
|
+
VALUE vdims =
|
193
|
+
rb_hash_aref(vinput_layer, rb_to_symbol(rb_str_new2("dims")));
|
194
|
+
int32_t dims_length =
|
195
|
+
NUM2INT(rb_funcall(vdims, rb_intern("length"), 0, NULL));
|
196
|
+
|
197
|
+
// prepare input buffer
|
198
|
+
int32_t buffer_length = 1;
|
199
|
+
for (int32_t j = 0; j < dims_length; j++)
|
200
|
+
buffer_length *= NUM2INT(rb_ary_entry(vdims, j));
|
201
|
+
|
202
|
+
float *input_buff = (float *)ruby_xmalloc(sizeof(float) * buffer_length);
|
203
|
+
getModel(self)->input_buffs[i] = input_buff;
|
204
|
+
ERROR_CHECK(
|
205
|
+
menoh_model_builder_attach_external_buffer(
|
206
|
+
getModel(self)->model_builder, StringValueCStr(vname), input_buff),
|
207
|
+
rb_eStandardError);
|
208
|
+
}
|
209
|
+
|
210
|
+
// build model
|
211
|
+
ERROR_CHECK(menoh_build_model(
|
212
|
+
getModel(self)->model_builder, getModel(self)->model_data,
|
213
|
+
StringValueCStr(vbackend), "", &(getModel(self)->model)),
|
214
|
+
rb_eStandardError);
|
215
|
+
|
216
|
+
return Qnil;
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
static VALUE wrap_model_run(VALUE self, VALUE dataset) {
|
221
|
+
VALUE vbackend = getModel(self)->vbackend;
|
222
|
+
VALUE vinput_layers = getModel(self)->vinput_layers;
|
223
|
+
VALUE voutput_layers = getModel(self)->voutput_layers;
|
224
|
+
|
225
|
+
int32_t input_layer_num =
|
226
|
+
NUM2INT(rb_funcall(vinput_layers, rb_intern("length"), 0, NULL));
|
227
|
+
int32_t output_layer_num =
|
228
|
+
NUM2INT(rb_funcall(voutput_layers, rb_intern("length"), 0, NULL));
|
229
|
+
|
230
|
+
// Copy input image data to model's input array
|
231
|
+
for (int32_t i = 0; i < input_layer_num; i++) {
|
232
|
+
VALUE vinput_layer = rb_ary_entry(vinput_layers, i);
|
233
|
+
VALUE vname = rb_hash_aref(vinput_layer, rb_to_symbol(rb_str_new2("name")));
|
234
|
+
VALUE vdims = rb_hash_aref(vinput_layer, rb_to_symbol(rb_str_new2("dims")));
|
235
|
+
int32_t dims_length =
|
236
|
+
NUM2INT(rb_funcall(vdims, rb_intern("length"), 0, NULL));
|
237
|
+
int32_t buffer_length = 1;
|
238
|
+
for (int32_t j = 0; j < dims_length; j++)
|
239
|
+
buffer_length *= NUM2INT(rb_ary_entry(vdims, j));
|
240
|
+
|
241
|
+
VALUE data = rb_ary_entry(dataset, i);
|
242
|
+
for (int32_t j = 0; j < buffer_length; j++) {
|
243
|
+
getModel(self)->input_buffs[i][j] =
|
244
|
+
(float)(NUM2DBL(rb_ary_entry(data, j)));
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
// attach output buffer to model
|
249
|
+
getModel(self)->output_buffs =
|
250
|
+
(float **)ruby_xmalloc(sizeof(float *) * output_layer_num);
|
251
|
+
for (int32_t i = 0; i < output_layer_num; i++) {
|
252
|
+
VALUE voutput_layer = rb_ary_entry(voutput_layers, i);
|
253
|
+
float *output_buff;
|
254
|
+
ERROR_CHECK(menoh_model_get_variable_buffer_handle(
|
255
|
+
getModel(self)->model, StringValueCStr(voutput_layer),
|
256
|
+
(void **)&output_buff),
|
257
|
+
rb_eStandardError);
|
258
|
+
getModel(self)->output_buffs[i] = output_buff;
|
259
|
+
}
|
260
|
+
|
261
|
+
// run model
|
262
|
+
ERROR_CHECK(menoh_model_run(getModel(self)->model), rb_eStandardError);
|
263
|
+
|
264
|
+
// Get output
|
265
|
+
VALUE results = rb_ary_new();
|
266
|
+
for (int32_t output_layer_i = 0; output_layer_i < output_layer_num;
|
267
|
+
output_layer_i++) {
|
268
|
+
VALUE voutput_layer = rb_ary_entry(voutput_layers, output_layer_i);
|
269
|
+
VALUE result_each = rb_hash_new();
|
270
|
+
|
271
|
+
// get dimention of output layers
|
272
|
+
int32_t dim_size;
|
273
|
+
int32_t output_buffer_length = 1;
|
274
|
+
ERROR_CHECK(menoh_variable_profile_table_get_dims_size(
|
275
|
+
getModel(self)->variable_profile_table,
|
276
|
+
StringValueCStr(voutput_layer), &(dim_size)),
|
277
|
+
rb_eStandardError);
|
278
|
+
VALUE vresult_shape = rb_ary_new();
|
279
|
+
// get each size of dimention
|
280
|
+
for (int32_t dim = 0; dim < dim_size; dim++) {
|
281
|
+
int32_t size;
|
282
|
+
ERROR_CHECK(menoh_variable_profile_table_get_dims_at(
|
283
|
+
getModel(self)->variable_profile_table,
|
284
|
+
StringValueCStr(voutput_layer), dim, &(size)),
|
285
|
+
rb_eStandardError);
|
286
|
+
rb_ary_push(vresult_shape, INT2NUM(size));
|
287
|
+
output_buffer_length *= size;
|
288
|
+
}
|
289
|
+
|
290
|
+
// Convert result to Ruby Array
|
291
|
+
VALUE vresult_buffer = rb_ary_new();
|
292
|
+
for (int32_t j = 0; j < output_buffer_length; j++) {
|
293
|
+
float *output_buff;
|
294
|
+
output_buff = getModel(self)->output_buffs[output_layer_i];
|
295
|
+
rb_ary_push(vresult_buffer, DBL2NUM(*(output_buff + j)));
|
296
|
+
}
|
297
|
+
|
298
|
+
rb_hash_aset(result_each, rb_to_symbol(rb_str_new2("name")), voutput_layer);
|
299
|
+
rb_hash_aset(result_each, rb_to_symbol(rb_str_new2("shape")),
|
300
|
+
vresult_shape);
|
301
|
+
rb_hash_aset(result_each, rb_to_symbol(rb_str_new2("data")),
|
302
|
+
vresult_buffer);
|
303
|
+
rb_ary_push(results, result_each);
|
304
|
+
}
|
305
|
+
|
306
|
+
return results;
|
307
|
+
}
|
308
|
+
|
309
|
+
VALUE mMenoh;
|
310
|
+
|
311
|
+
void Init_menoh_native() {
|
312
|
+
mMenoh = rb_define_module("Menoh");
|
313
|
+
|
314
|
+
VALUE onnx = rb_define_class_under(mMenoh, "Menoh", rb_cObject);
|
315
|
+
|
316
|
+
rb_define_alloc_func(onnx, wrap_menoh_alloc);
|
317
|
+
rb_define_private_method(onnx, "native_init",
|
318
|
+
RUBY_METHOD_FUNC(wrap_menoh_init), 1);
|
319
|
+
|
320
|
+
VALUE model = rb_define_class_under(mMenoh, "MenohModel", rb_cObject);
|
321
|
+
|
322
|
+
rb_define_alloc_func(model, wrap_model_alloc);
|
323
|
+
rb_define_private_method(model, "native_init",
|
324
|
+
RUBY_METHOD_FUNC(wrap_model_init), 2);
|
325
|
+
|
326
|
+
rb_define_private_method(model, "native_run",
|
327
|
+
RUBY_METHOD_FUNC(wrap_model_run), 1);
|
328
|
+
}
|