menoh 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|