tensor_stream 0.9.10 → 1.0.0.pre.rc1
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 +4 -4
- data/README.md +22 -11
- data/exe/model_utils +24 -0
- data/lib/tensor_stream/evaluator/operation_helpers/array_ops_helper.rb +19 -23
- data/lib/tensor_stream/evaluator/ruby/array_ops.rb +1 -1
- data/lib/tensor_stream/evaluator/ruby/check_ops.rb +1 -1
- data/lib/tensor_stream/evaluator/ruby/math_ops.rb +65 -65
- data/lib/tensor_stream/evaluator/ruby/nn_ops.rb +3 -3
- data/lib/tensor_stream/evaluator/ruby_evaluator.rb +51 -37
- data/lib/tensor_stream/graph.rb +5 -0
- data/lib/tensor_stream/graph_deserializers/yaml_loader.rb +24 -1
- data/lib/tensor_stream/graph_serializers/pbtext.rb +0 -1
- data/lib/tensor_stream/monkey_patches/op_patch.rb +68 -0
- data/lib/tensor_stream/monkey_patches/patch.rb +0 -61
- data/lib/tensor_stream/ops.rb +1 -1
- data/lib/tensor_stream/profile/report_tool.rb +3 -3
- data/lib/tensor_stream/session.rb +8 -7
- data/lib/tensor_stream/train/saver.rb +19 -26
- data/lib/tensor_stream/utils/freezer.rb +13 -5
- data/lib/tensor_stream/version.rb +1 -1
- data/tensor_stream.gemspec +4 -3
- metadata +8 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db2ea87e941f738407781b7f63b7cf120d62a87bc1c950f6f272942fa5eed6a2
|
4
|
+
data.tar.gz: b81949fb1e4ed9bca63d9a7ef07f21ce634e4939b032f299cb96afb3016ad6bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb5f081aac256b4d17222850727bbdd55ce327fd20f384d960c823abc0b7c6aa8f09888136df71e530af7bac835c57383cbe5cef88a959c55b02afb91bc21b13
|
7
|
+
data.tar.gz: 9dd9111eca29f8f3d3f99b94f92a2b8ffbdb2cad686cc9acc9eeda737b0e88483667072191dc77958b92948dd570015720ee2e410f6fdeb7afcfce90b1b561f5
|
data/README.md
CHANGED
@@ -365,34 +365,45 @@ File.write("model.pbtext", result.graph.as_graph_def)
|
|
365
365
|
## Performance notes
|
366
366
|
|
367
367
|
Comparative performance with respect to other ruby libraries have not yet been performed. However it is
|
368
|
-
notable that TruffleRuby and ruby-2.6.0
|
368
|
+
notable that TruffleRuby and ruby-2.6.0 performs considerably better with respect
|
369
369
|
to previous versions of ruby(< 2.6)
|
370
370
|
|
371
|
-
Benchmarks running samples/linear_regression.rb on an
|
371
|
+
Benchmarks running samples/linear_regression.rb with tensor_stream 1.0.0 on an AMD(R) Ryzen(TM) 3 1300X CPU
|
372
372
|
|
373
|
-
|
373
|
+
|
374
|
+
ruby 2.5
|
374
375
|
|
375
376
|
```
|
376
377
|
$ ruby -v
|
377
|
-
ruby 2.
|
378
|
+
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
|
378
379
|
$ ruby samples/linear_regression.rb
|
379
|
-
|
380
|
+
296 seconds 3000 epochs
|
380
381
|
```
|
381
382
|
|
382
|
-
ruby 2.6.0
|
383
|
+
ruby 2.6.0
|
383
384
|
|
384
385
|
```
|
385
386
|
$ ruby -v
|
386
|
-
ruby 2.6.
|
387
|
-
$ ruby
|
388
|
-
|
387
|
+
ruby 2.6.0p0 (2018-12-25 revision 66547) [x86_64-linux]
|
388
|
+
$ ruby samples/linear_regression.rb
|
389
|
+
232 seconds 10000 epochs
|
390
|
+
|
391
|
+
ruby --jit samples/linear_regression.rb
|
392
|
+
222 seconds 10000 epochs
|
389
393
|
```
|
390
394
|
|
391
395
|
truffleruby
|
392
396
|
```
|
393
397
|
$ ruby -v
|
394
|
-
truffleruby 1.0.0-
|
395
|
-
|
398
|
+
truffleruby 1.0.0-rc10, like ruby 2.4.4, GraalVM CE Native [x86_64-linux]
|
399
|
+
246 seconds 10000 epochs
|
400
|
+
```
|
401
|
+
|
402
|
+
jruby
|
403
|
+
```
|
404
|
+
$ ruby -v
|
405
|
+
jruby 9.2.0.0 (2.5.0) 2018-05-24 81156a8 OpenJDK 64-Bit Server VM 25.191-b12 on 1.8.0_191-8u191-b12-0ubuntu0.18.04.1-b12 +jit [linux-x86_64]
|
406
|
+
205 seconds 10000 epochs
|
396
407
|
```
|
397
408
|
|
398
409
|
For training large networks that works on images, the opencl evaluator is the only way to go.
|
data/exe/model_utils
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "tensor_stream"
|
5
|
+
require 'tensor_stream/utils/freezer'
|
6
|
+
|
7
|
+
if ARGV[0].nil?
|
8
|
+
puts "source checkpoint folder not specified"
|
9
|
+
puts "usage: model_utils <checkpoint folder> <target yaml>"
|
10
|
+
puts "example: model_utils sample_model/ frozen.yml"
|
11
|
+
exit(1)
|
12
|
+
end
|
13
|
+
|
14
|
+
if ARGV[1].nil?
|
15
|
+
puts "dest YAML file for frozen model not specified"
|
16
|
+
puts "usage: model_utils <checkpoint folder> <target yaml>"
|
17
|
+
puts "example: model_utils sample_model/ frozen.yml"
|
18
|
+
exit(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
sess = TensorStream.session
|
22
|
+
freezer = TensorStream::Freezer.new
|
23
|
+
freezer.convert(sess, ARGV[0], ARGV[1])
|
24
|
+
exit(0)
|
@@ -100,18 +100,18 @@ module TensorStream
|
|
100
100
|
end
|
101
101
|
|
102
102
|
# handle 2 tensor math operations
|
103
|
-
def vector_op(vector, vector2,
|
103
|
+
def vector_op(vector, vector2, switch = false, safe = true, &block)
|
104
104
|
if get_rank(vector) < get_rank(vector2) # upgrade rank of A
|
105
105
|
duplicated = Array.new(vector2.size) do
|
106
106
|
vector
|
107
107
|
end
|
108
|
-
return vector_op(duplicated, vector2,
|
108
|
+
return vector_op(duplicated, vector2, switch, &block)
|
109
109
|
end
|
110
110
|
|
111
|
-
return
|
111
|
+
return yield(vector, vector2) unless vector.is_a?(Array)
|
112
112
|
|
113
113
|
vector.each_with_index.collect do |input, index|
|
114
|
-
next vector_op(input, vector2,
|
114
|
+
next vector_op(input, vector2, switch, &block) if input.is_a?(Array) && get_rank(vector) > get_rank(vector2)
|
115
115
|
|
116
116
|
if safe && vector2.is_a?(Array)
|
117
117
|
next nil if vector2.size != 1 && index >= vector2.size
|
@@ -129,9 +129,9 @@ module TensorStream
|
|
129
129
|
end
|
130
130
|
|
131
131
|
if input.is_a?(Array)
|
132
|
-
vector_op(input, z,
|
132
|
+
vector_op(input, z, switch, &block)
|
133
133
|
else
|
134
|
-
switch ?
|
134
|
+
switch ? yield(z, input) : yield(input, z)
|
135
135
|
end
|
136
136
|
end.compact
|
137
137
|
end
|
@@ -165,12 +165,12 @@ module TensorStream
|
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
168
|
-
def process_function_op(a,
|
168
|
+
def process_function_op(a, &block)
|
169
169
|
# ruby scalar
|
170
170
|
if (a.is_a?(Tensor) && a.shape.rank > 0) || a.is_a?(Array)
|
171
|
-
vector_op(a, 0,
|
171
|
+
vector_op(a, 0, &block)
|
172
172
|
else
|
173
|
-
|
173
|
+
yield a, 0
|
174
174
|
end
|
175
175
|
end
|
176
176
|
|
@@ -264,11 +264,11 @@ module TensorStream
|
|
264
264
|
[new_arr, new_shape]
|
265
265
|
end
|
266
266
|
|
267
|
-
def reduce_axis(current_axis, axis, val, keep_dims,
|
267
|
+
def reduce_axis(current_axis, axis, val, keep_dims, &block)
|
268
268
|
return val unless val.is_a?(Array)
|
269
269
|
|
270
270
|
r = val.collect do |v|
|
271
|
-
reduce_axis(current_axis + 1, axis, v, keep_dims,
|
271
|
+
reduce_axis(current_axis + 1, axis, v, keep_dims, &block)
|
272
272
|
end
|
273
273
|
|
274
274
|
should_reduce_axis = axis.nil? || (axis.is_a?(Array) && axis.include?(current_axis)) || (current_axis == axis)
|
@@ -276,9 +276,13 @@ module TensorStream
|
|
276
276
|
if should_reduce_axis
|
277
277
|
reduced_val = r[0]
|
278
278
|
if r.size > 1
|
279
|
-
|
279
|
+
if block_given?
|
280
|
+
reduced_val = yield(r[0..val.size])
|
281
|
+
else
|
282
|
+
reduced_val = r[0..val.size].reduce(:+)
|
283
|
+
end
|
280
284
|
elsif r.empty?
|
281
|
-
reduced_val =
|
285
|
+
reduced_val = yield(nil)
|
282
286
|
end
|
283
287
|
keep_dims ? [reduced_val] : reduced_val
|
284
288
|
else
|
@@ -286,18 +290,10 @@ module TensorStream
|
|
286
290
|
end
|
287
291
|
end
|
288
292
|
|
289
|
-
def reduce(val, axis, keep_dims,
|
293
|
+
def reduce(val, axis, keep_dims, &block)
|
290
294
|
rank = get_rank(val)
|
291
295
|
return val if axis && axis.is_a?(Array) && axis.empty?
|
292
296
|
|
293
|
-
func = lambda do |arr|
|
294
|
-
reduced_val = arr[0]
|
295
|
-
arr[1..arr.size].each do |v|
|
296
|
-
reduced_val = vector_op(reduced_val, v, ->(t, u) { t + u })
|
297
|
-
end
|
298
|
-
reduced_val
|
299
|
-
end if func.nil?
|
300
|
-
|
301
297
|
axis = if axis.nil?
|
302
298
|
nil
|
303
299
|
elsif axis.is_a?(Array)
|
@@ -308,7 +304,7 @@ module TensorStream
|
|
308
304
|
axis < 0 ? rank - axis.abs : axis
|
309
305
|
end
|
310
306
|
|
311
|
-
reduce_axis(0, axis, val, keep_dims,
|
307
|
+
reduce_axis(0, axis, val, keep_dims, &block)
|
312
308
|
end
|
313
309
|
|
314
310
|
def arr_pad(arr, paddings, data_type = :float32, rank = 0)
|
@@ -335,7 +335,7 @@ module TensorStream
|
|
335
335
|
|
336
336
|
register_op %i[select where] do |context, tensor, inputs|
|
337
337
|
pred = inputs[0]
|
338
|
-
call_3way_vector_op(pred, inputs[1], inputs[2], context
|
338
|
+
call_3way_vector_op(pred, inputs[1], inputs[2], context) { |t, u, v| t ? u : v }
|
339
339
|
end
|
340
340
|
|
341
341
|
register_op :shape do |_context, tensor, inputs|
|
@@ -3,7 +3,7 @@ module TensorStream
|
|
3
3
|
def CheckOps.included(klass)
|
4
4
|
klass.class_eval do
|
5
5
|
register_op :assert_equal do |context, tensor, inputs|
|
6
|
-
result = call_vector_op(tensor, :equal, inputs[0], inputs[1], context
|
6
|
+
result = call_vector_op(tensor, :equal, inputs[0], inputs[1], context) { |t, u| t == u }
|
7
7
|
|
8
8
|
result = result.is_a?(Array) ? result.flatten.uniq : [result]
|
9
9
|
prefix = tensor.options[:message] || ""
|
@@ -3,24 +3,24 @@ module TensorStream
|
|
3
3
|
def MathOps.included(klass)
|
4
4
|
klass.class_eval do
|
5
5
|
register_op :tanh, no_eval: true do |context, _tensor, inputs|
|
6
|
-
call_op(inputs[0], context
|
6
|
+
call_op(inputs[0], context) { |t, _b| Math.tanh(t) }
|
7
7
|
end
|
8
8
|
|
9
9
|
register_op :tan, no_eval: true do |context, tensor, inputs|
|
10
|
-
call_op(inputs[0], context
|
10
|
+
call_op(inputs[0], context) { |t, _b| Math.tan(t) }
|
11
11
|
end
|
12
12
|
|
13
13
|
register_op :atan, no_eval: true do |context, _tensor, inputs|
|
14
|
-
call_op(inputs[0], context
|
14
|
+
call_op(inputs[0], context) { |t, _b| Math.atan(t) }
|
15
15
|
end
|
16
16
|
|
17
17
|
register_op :sin, no_eval: true do |context, _tensor, inputs|
|
18
|
-
call_op(inputs[0], context
|
18
|
+
call_op(inputs[0], context) { |t, _b| Math.sin(t) }
|
19
19
|
end
|
20
20
|
|
21
21
|
register_op :add, no_eval: true do |context, tensor, inputs|
|
22
22
|
a, b = inputs
|
23
|
-
call_vector_op(tensor, :add, a, b, context
|
23
|
+
call_vector_op(tensor, :add, a, b, context) { |t, u| t + u }
|
24
24
|
end
|
25
25
|
|
26
26
|
register_op :add_n, no_eval: true do |context, tensor, inputs|
|
@@ -31,7 +31,7 @@ module TensorStream
|
|
31
31
|
a = inputs.pop
|
32
32
|
until inputs.empty?
|
33
33
|
b = inputs.pop
|
34
|
-
a = call_vector_op(tensor, :add, a, b, context
|
34
|
+
a = call_vector_op(tensor, :add, a, b, context) { |t, u| t + u }
|
35
35
|
end
|
36
36
|
a
|
37
37
|
end
|
@@ -39,100 +39,100 @@ module TensorStream
|
|
39
39
|
|
40
40
|
register_op :sub, no_eval: true do |context, tensor, inputs|
|
41
41
|
a, b = inputs
|
42
|
-
call_vector_op(tensor, :sub, a, b, context
|
42
|
+
call_vector_op(tensor, :sub, a, b, context) { |t, u| t - u }
|
43
43
|
end
|
44
44
|
|
45
45
|
register_op %i[floor_mod mod], no_eval: true do |context, tensor, inputs|
|
46
46
|
a, b = inputs
|
47
|
-
call_vector_op(tensor, :mod, a, b, context
|
47
|
+
call_vector_op(tensor, :mod, a, b, context) { |t, u| t % u }
|
48
48
|
end
|
49
49
|
|
50
50
|
register_op %i[floor_div], no_eval: true do |context, tensor, inputs|
|
51
51
|
a, b = inputs
|
52
52
|
if fp_type?(tensor.data_type)
|
53
|
-
call_vector_op(tensor, :div, a, b, context
|
53
|
+
call_vector_op(tensor, :div, a, b, context) { |t, u| (t / u).to_i.to_f }
|
54
54
|
else
|
55
|
-
call_vector_op(tensor, :div, a, b, context
|
55
|
+
call_vector_op(tensor, :div, a, b, context) { |t, u| t / u }
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
register_op :mul, no_eval: true do |context, tensor, inputs|
|
60
60
|
a, b = inputs
|
61
|
-
call_vector_op(tensor, :mul, a, b, context
|
61
|
+
call_vector_op(tensor, :mul, a, b, context) { |t, u| t * u }
|
62
62
|
end
|
63
63
|
|
64
64
|
register_op :pow, no_eval: true do |context, tensor, inputs|
|
65
65
|
a, b = inputs
|
66
|
-
call_vector_op(tensor, :pow, a, b, context
|
66
|
+
call_vector_op(tensor, :pow, a, b, context) { |t, u| t**u }
|
67
67
|
end
|
68
68
|
|
69
69
|
register_op :squared_difference, no_eval: true do |context, tensor, inputs|
|
70
70
|
a, b = inputs
|
71
|
-
call_vector_op(tensor, :squared_difference, a, b, context
|
71
|
+
call_vector_op(tensor, :squared_difference, a, b, context) { |t, u| (t - u) * (t - u) }
|
72
72
|
end
|
73
73
|
|
74
74
|
register_op :round, no_eval: true do |context, _tensor, inputs|
|
75
|
-
call_op(inputs[0], context
|
75
|
+
call_op(inputs[0], context) { |t, _b| t.round }
|
76
76
|
end
|
77
77
|
|
78
78
|
register_op :abs, no_eval: true do |context, _tensor, inputs|
|
79
|
-
call_op(inputs[0], context
|
79
|
+
call_op(inputs[0], context) { |t, _b| t.abs }
|
80
80
|
end
|
81
81
|
|
82
82
|
register_op :asin, no_eval: true do |context, _tensor, inputs|
|
83
|
-
call_op(inputs[0], context
|
83
|
+
call_op(inputs[0], context) { |t, _b| Math.asin(t) }
|
84
84
|
end
|
85
85
|
|
86
86
|
register_op :acos, no_eval: true do |context, _tensor, inputs|
|
87
|
-
call_op(inputs[0], context
|
87
|
+
call_op(inputs[0], context) { |t, _b| Math.acos(t) }
|
88
88
|
end
|
89
89
|
|
90
90
|
register_op :cos, no_eval: true do |context, tensor, inputs|
|
91
|
-
call_op(inputs[0], context
|
91
|
+
call_op(inputs[0], context) { |t, _b| Math.cos(t) }
|
92
92
|
end
|
93
93
|
|
94
94
|
register_op :log1p, no_eval: true do |context, _tensor, inputs|
|
95
|
-
call_op(inputs[0], context
|
95
|
+
call_op(inputs[0], context) { |t, _b| Math.log(1 + t) }
|
96
96
|
end
|
97
97
|
|
98
98
|
register_op :log, no_eval: true do |context, _tensor, inputs|
|
99
|
-
call_op(inputs[0], context
|
99
|
+
call_op(inputs[0], context) { |t, _b| t < 0 ? Float::NAN : Math.log(t) }
|
100
100
|
end
|
101
101
|
|
102
102
|
register_op :exp, no_eval: true do |context, _tensor, inputs|
|
103
|
-
call_op(inputs[0], context
|
103
|
+
call_op(inputs[0], context) { |t, _b| Math.exp(t) }
|
104
104
|
end
|
105
105
|
|
106
106
|
register_op :sigmoid, no_eval: true do |context, _tensor, inputs|
|
107
|
-
call_op(inputs[0], context
|
107
|
+
call_op(inputs[0], context) { |t, _b| sigmoid(t) }
|
108
108
|
end
|
109
109
|
|
110
110
|
register_op :sqrt, no_eval: true do |context, _tensor, inputs|
|
111
|
-
call_op(inputs[0], context
|
111
|
+
call_op(inputs[0], context) { |t, _b| Math.sqrt(t) }
|
112
112
|
end
|
113
113
|
|
114
114
|
register_op :floor, no_eval: true do |context, _tensor, inputs|
|
115
|
-
call_op(inputs[0], context
|
115
|
+
call_op(inputs[0], context) { |t, _b| t.floor }
|
116
116
|
end
|
117
117
|
|
118
118
|
register_op :ceil, no_eval: true do |context, _tensor, inputs|
|
119
|
-
call_op(inputs[0], context
|
119
|
+
call_op(inputs[0], context) { |t, _b| t.ceil }
|
120
120
|
end
|
121
121
|
|
122
122
|
register_op :square, no_eval: true do |context, _tensor, inputs|
|
123
|
-
call_op(inputs[0], context
|
123
|
+
call_op(inputs[0], context) { |t, _b| t * t }
|
124
124
|
end
|
125
125
|
|
126
126
|
register_op :reciprocal, no_eval: true do |context, _tensor, inputs|
|
127
|
-
call_op(inputs[0], context
|
127
|
+
call_op(inputs[0], context) { |t, _b| 1 / t }
|
128
128
|
end
|
129
129
|
|
130
130
|
register_op %i[neg negate], no_eval: true do |context, tensor, inputs|
|
131
|
-
call_vector_op(tensor, :negate, inputs[0], nil, context
|
131
|
+
call_vector_op(tensor, :negate, inputs[0], nil, context) { |t, _u| -t }
|
132
132
|
end
|
133
133
|
|
134
134
|
register_op :tanh_grad, no_eval: true do |context, _tensor, inputs|
|
135
|
-
call_op(inputs[0], context
|
135
|
+
call_op(inputs[0], context) { |t, _b| 1 - Math.tanh(t) * Math.tanh(t) }
|
136
136
|
end
|
137
137
|
|
138
138
|
register_op(%i[argmax arg_max]) do |_context, tensor, inputs|
|
@@ -169,70 +169,70 @@ module TensorStream
|
|
169
169
|
c = fp_type?(tensor.data_type) ? 1.0 : 1
|
170
170
|
reverse_option = tensor.options[:reverse]
|
171
171
|
exclusive = tensor.options[:exclusive]
|
172
|
-
func = lambda do |arr|
|
173
|
-
return c if arr.nil?
|
174
|
-
|
175
|
-
count = arr.size
|
176
|
-
arr = arr.reverse if reverse_option
|
177
|
-
arr = [1] + arr if exclusive
|
178
172
|
|
179
|
-
|
180
|
-
|
181
|
-
|
173
|
+
reduction(context, tensor) do |arr|
|
174
|
+
if arr.nil?
|
175
|
+
c
|
176
|
+
else
|
177
|
+
count = arr.size
|
178
|
+
arr = arr.reverse if reverse_option
|
179
|
+
arr = [1] + arr if exclusive
|
180
|
+
|
181
|
+
start_prod = arr[0]
|
182
|
+
mapped = arr[1...count].map do |v|
|
183
|
+
start_prod = vector_op(start_prod, v) { |a, b| a * b }
|
184
|
+
end
|
185
|
+
|
186
|
+
arr = [arr[0]] + mapped
|
187
|
+
reverse_option ? arr.reverse : arr
|
182
188
|
end
|
183
|
-
|
184
|
-
arr = [arr[0]] + mapped
|
185
|
-
reverse_option ? arr.reverse : arr
|
186
189
|
end
|
187
|
-
reduction(context, tensor, func)
|
188
190
|
end
|
189
191
|
|
190
192
|
register_op :sum, noop: true do |context, tensor, _inputs|
|
191
|
-
|
193
|
+
|
194
|
+
reduction(context, tensor) do |arr|
|
192
195
|
reduced_val = arr[0]
|
193
196
|
arr[1..arr.size].each do |v|
|
194
|
-
reduced_val = vector_op(reduced_val, v
|
197
|
+
reduced_val = vector_op(reduced_val, v) { |t, u| t + u }
|
195
198
|
end
|
196
199
|
reduced_val
|
197
200
|
end
|
198
|
-
reduction(context, tensor, func)
|
199
201
|
end
|
200
202
|
|
201
203
|
register_op :prod, noop: true do |context, tensor, _inputs|
|
202
204
|
c = fp_type?(tensor.data_type) ? 1.0 : 1
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
205
|
+
reduction(context, tensor) do |arr|
|
206
|
+
if arr.nil?
|
207
|
+
c
|
208
|
+
else
|
209
|
+
reduced_val = arr[0]
|
210
|
+
arr[1..arr.size].each do |v|
|
211
|
+
reduced_val = vector_op(reduced_val, v) { |a, b| a * b }
|
212
|
+
end
|
213
|
+
reduced_val
|
210
214
|
end
|
211
|
-
reduced_val
|
212
215
|
end
|
213
|
-
|
214
|
-
reduction(context, tensor, func)
|
215
216
|
end
|
216
217
|
|
217
218
|
register_op :sigmoid_grad, no_eval: true do |context, tensor, inputs|
|
218
219
|
a, b = inputs
|
219
|
-
call_vector_op(tensor, :sigmoid_grad, a, b, context
|
220
|
+
call_vector_op(tensor, :sigmoid_grad, a, b, context) { |t, u| u * sigmoid(t) * (1 - sigmoid(t)) }
|
220
221
|
end
|
221
222
|
|
222
223
|
register_op :mean, noop: true do |context, tensor, _inputs|
|
223
224
|
c = fp_type?(tensor.data_type) ? 0.0 : 0
|
224
|
-
|
225
|
+
|
226
|
+
reduction(context, tensor) do |arr|
|
225
227
|
return c if arr.nil?
|
226
228
|
|
227
229
|
reduced_val = arr[0]
|
228
230
|
arr[1..arr.size].each do |v|
|
229
|
-
reduced_val = vector_op(reduced_val, v
|
231
|
+
reduced_val = vector_op(reduced_val, v) { |a, b| a + b }
|
230
232
|
end
|
231
233
|
|
232
|
-
vector_op(reduced_val, nil
|
234
|
+
vector_op(reduced_val, nil) { |a, _b| a / arr.size }
|
233
235
|
end
|
234
|
-
|
235
|
-
reduction(context, tensor, func)
|
236
236
|
end
|
237
237
|
|
238
238
|
register_op :mat_mul do |_context, tensor, inputs|
|
@@ -252,19 +252,19 @@ module TensorStream
|
|
252
252
|
end
|
253
253
|
|
254
254
|
register_op %i[max maximum], noop: true do |context, tensor, inputs|
|
255
|
-
call_vector_op(tensor, :max, inputs[0], inputs[1], context
|
255
|
+
call_vector_op(tensor, :max, inputs[0], inputs[1], context) { |t, u| [t, u].max }
|
256
256
|
end
|
257
257
|
|
258
258
|
register_op %i[min minimum], noop: true do |context, tensor, inputs|
|
259
|
-
call_vector_op(tensor, :min, inputs[0], inputs[1], context
|
259
|
+
call_vector_op(tensor, :min, inputs[0], inputs[1], context) { |t, u| [t, u].min }
|
260
260
|
end
|
261
261
|
|
262
|
-
def reduction(child_context, tensor,
|
262
|
+
def reduction(child_context, tensor, &block)
|
263
263
|
val = global_eval(tensor, tensor.inputs[0], child_context)
|
264
264
|
axis = global_eval(tensor, tensor.inputs[1], child_context)
|
265
265
|
keep_dims = global_eval(tensor, tensor.options[:keepdims], child_context)
|
266
266
|
|
267
|
-
reduce(val, axis, keep_dims,
|
267
|
+
reduce(val, axis, keep_dims, &block)
|
268
268
|
end
|
269
269
|
end
|
270
270
|
end
|
@@ -7,7 +7,7 @@ module TensorStream
|
|
7
7
|
target_var, learning_rate, delta = inputs
|
8
8
|
assign = tensor.inputs[0] || tensor
|
9
9
|
|
10
|
-
assign.container = process_vector_math_op(tensor, target_var, delta, context
|
10
|
+
assign.container = process_vector_math_op(tensor, target_var, delta, context) { |t, u| t - u * learning_rate }
|
11
11
|
assign.container
|
12
12
|
end
|
13
13
|
|
@@ -111,7 +111,7 @@ module TensorStream
|
|
111
111
|
end
|
112
112
|
reshaped_losses = TensorShape.reshape(losses.flatten, input_shape)
|
113
113
|
reshaped_backprops = TensorShape.reshape(backprobs.flatten, input_shape)
|
114
|
-
reshaped_losses = reduce(reshaped_losses, rank, false)
|
114
|
+
reshaped_losses = reduce(reshaped_losses, rank, false) { |a| a.reduce(:+) }
|
115
115
|
TensorStream::Evaluator::OutputGroup.new([reshaped_losses, reshaped_backprops], [tensor.inputs[0].data_type, tensor.inputs[0].data_type])
|
116
116
|
end
|
117
117
|
end
|
@@ -210,7 +210,7 @@ module TensorStream
|
|
210
210
|
end
|
211
211
|
|
212
212
|
register_op :relu6 do |context, tensor, inputs|
|
213
|
-
call_vector_op(tensor, :relu6, inputs[0], inputs[1], context
|
213
|
+
call_vector_op(tensor, :relu6, inputs[0], inputs[1], context) { |t, u| [[t, 0].max, 6].min }
|
214
214
|
end
|
215
215
|
|
216
216
|
register_op :conv2d do |_context, tensor, inputs|
|
@@ -102,11 +102,11 @@ module TensorStream
|
|
102
102
|
end
|
103
103
|
|
104
104
|
register_op(:cast) do |context, tensor, inputs|
|
105
|
-
call_op(inputs[0], context
|
105
|
+
call_op(inputs[0], context) { |t, _b| Tensor.cast_dtype(t, tensor.data_type) }
|
106
106
|
end
|
107
107
|
|
108
108
|
register_op(:sign) do |context, tensor, inputs|
|
109
|
-
|
109
|
+
call_op(inputs[0], context) do |x, _b|
|
110
110
|
if x.zero? || (x.is_a?(Float) && x.nan?)
|
111
111
|
0
|
112
112
|
elsif x < 0
|
@@ -116,21 +116,19 @@ module TensorStream
|
|
116
116
|
else
|
117
117
|
raise 'assert: cannot be here'
|
118
118
|
end
|
119
|
-
|
120
|
-
|
121
|
-
call_op(inputs[0], context, func)
|
119
|
+
end
|
122
120
|
end
|
123
121
|
|
124
122
|
register_op(:logical_and) do |context, tensor, inputs|
|
125
|
-
call_vector_op(tensor, :logical_and, inputs[0], inputs[1], context
|
123
|
+
call_vector_op(tensor, :logical_and, inputs[0], inputs[1], context) { |t, u| t && u }
|
126
124
|
end
|
127
125
|
|
128
126
|
register_op(:equal) do |context, tensor, inputs|
|
129
|
-
call_vector_op(tensor, :equal, inputs[0], inputs[1], context
|
127
|
+
call_vector_op(tensor, :equal, inputs[0], inputs[1], context) { |t, u| t == u }
|
130
128
|
end
|
131
129
|
|
132
130
|
register_op(:not_equal) do |context, tensor, inputs|
|
133
|
-
call_vector_op(tensor, :not_equal, inputs[0], inputs[1], context
|
131
|
+
call_vector_op(tensor, :not_equal, inputs[0], inputs[1], context) { |t, u| t != u }
|
134
132
|
end
|
135
133
|
|
136
134
|
register_op :placeholder, no_eval: true do |context, tensor, _inputs|
|
@@ -175,35 +173,35 @@ module TensorStream
|
|
175
173
|
register_op :assign_add, noop: true do |context, tensor, _inputs|
|
176
174
|
assign = tensor.inputs[0] || tensor
|
177
175
|
|
178
|
-
assign.container = process_vector_math_op(tensor, tensor.inputs[0], tensor.inputs[1], context
|
176
|
+
assign.container = process_vector_math_op(tensor, tensor.inputs[0], tensor.inputs[1], context) { |t, u| t + u }
|
179
177
|
assign.container
|
180
178
|
end
|
181
179
|
|
182
180
|
register_op :assign_sub, noop: true do |context, tensor, _inputs|
|
183
181
|
assign = tensor.inputs[0] || tensor
|
184
182
|
|
185
|
-
assign.container = process_vector_math_op(tensor, tensor.inputs[0], tensor.inputs[1], context
|
183
|
+
assign.container = process_vector_math_op(tensor, tensor.inputs[0], tensor.inputs[1], context) { |t, u| t - u }
|
186
184
|
assign.container
|
187
185
|
end
|
188
186
|
|
189
187
|
register_op :less do |context, tensor, inputs|
|
190
188
|
a, b = inputs
|
191
|
-
call_vector_op(tensor, :less, a, b, context
|
189
|
+
call_vector_op(tensor, :less, a, b, context) { |t, u| t < u }
|
192
190
|
end
|
193
191
|
|
194
192
|
register_op :greater do |context, tensor, inputs|
|
195
193
|
a, b = inputs
|
196
|
-
call_vector_op(tensor, :greater, a, b, context
|
194
|
+
call_vector_op(tensor, :greater, a, b, context) { |t, u| t > u }
|
197
195
|
end
|
198
196
|
|
199
197
|
register_op :greater_equal do |context, tensor, inputs|
|
200
198
|
a, b = inputs
|
201
|
-
call_vector_op(tensor, :greater_equal, a, b, context
|
199
|
+
call_vector_op(tensor, :greater_equal, a, b, context) { |t, u| t >= u }
|
202
200
|
end
|
203
201
|
|
204
202
|
register_op :less_equal do |context, tensor, inputs|
|
205
203
|
a, b = inputs
|
206
|
-
call_vector_op(tensor, :greater_equal, a, b, context
|
204
|
+
call_vector_op(tensor, :greater_equal, a, b, context) { |t, u| t <= u }
|
207
205
|
end
|
208
206
|
|
209
207
|
register_op :broadcast_transform do |_context, _tensor, inputs|
|
@@ -220,7 +218,7 @@ module TensorStream
|
|
220
218
|
end
|
221
219
|
|
222
220
|
register_op %i[div real_div], noop: true do |context, tensor, inputs|
|
223
|
-
process_vector_math_op(tensor, inputs[0], inputs[1], context
|
221
|
+
process_vector_math_op(tensor, inputs[0], inputs[1], context) { |t, u| t / u }
|
224
222
|
end
|
225
223
|
|
226
224
|
register_op :broadcast_gradient_args do |_context, tensor, inputs|
|
@@ -241,30 +239,46 @@ module TensorStream
|
|
241
239
|
outputfile = inputs[0]
|
242
240
|
inputs = tensor.inputs.dup
|
243
241
|
|
244
|
-
basename = File.basename(outputfile)
|
245
|
-
path = File.dirname(outputfile)
|
246
|
-
|
247
|
-
new_filename = File.join(path, [basename, gs].compact.join('-'))
|
248
|
-
|
249
242
|
inputs.shift
|
250
243
|
variables = {}
|
251
244
|
inputs.each do |savable|
|
252
|
-
|
245
|
+
val = savable.container
|
246
|
+
packed_data = Zlib::Deflate.deflate(TensorStream::Packer.pack(val, savable.data_type))
|
247
|
+
variables[savable.name] = {
|
248
|
+
'shape' => shape_eval(val),
|
249
|
+
'data' => Base64.strict_encode64(packed_data)
|
250
|
+
}
|
253
251
|
end
|
254
|
-
|
252
|
+
|
253
|
+
File.write(outputfile, { 'variables' => variables }.to_yaml)
|
254
|
+
nil
|
255
255
|
end
|
256
256
|
|
257
|
-
register_op :
|
258
|
-
|
257
|
+
register_op :restore_ts do |_context, tensor, inputs|
|
258
|
+
inputs = inputs.dup
|
259
|
+
filename = inputs.shift
|
260
|
+
tensor_names = inputs
|
261
|
+
|
262
|
+
input_dump = YAML.safe_load(File.read(filename), [Symbol])
|
263
|
+
vars = tensor.graph.get_collection(GraphKeys::GLOBAL_VARIABLES)
|
264
|
+
|
265
|
+
vars.select! { |v| input_dump['variables'].key?(v.name) && tensor_names.include?(v.name) }
|
266
|
+
vars.each do |variable|
|
267
|
+
data = TensorStream::Packer.unpack(Zlib::Inflate.inflate(Base64.decode64(input_dump['variables'][variable.name]['data'])), variable.data_type)
|
268
|
+
shape = input_dump['variables'][variable.name]['shape']
|
269
|
+
variable.buffer = nil
|
270
|
+
variable.value = TensorShape.reshape(data, shape)
|
271
|
+
end
|
272
|
+
|
273
|
+
nil
|
259
274
|
end
|
260
275
|
|
261
276
|
register_op :check_numerics do |context, tensor, inputs|
|
262
277
|
message = tensor.options[:message]
|
263
|
-
|
278
|
+
call_op(inputs[0], context) do |t, _b|
|
264
279
|
raise TensorStream::InvalidArgumentError, "#{message} Invalid argument" if t.nan? || t.infinite?
|
265
280
|
t
|
266
|
-
|
267
|
-
call_op(inputs[0], context, f)
|
281
|
+
end
|
268
282
|
end
|
269
283
|
|
270
284
|
def eval_operation(tensor, child_context)
|
@@ -342,18 +356,18 @@ module TensorStream
|
|
342
356
|
end
|
343
357
|
end
|
344
358
|
|
345
|
-
def call_op(a, child_context,
|
359
|
+
def call_op(a, child_context, &block)
|
346
360
|
a = complete_eval(a, child_context)
|
347
|
-
process_function_op(a,
|
361
|
+
process_function_op(a, &block)
|
348
362
|
end
|
349
363
|
|
350
|
-
def call_vector_op(tensor, op, a, b, child_context,
|
351
|
-
process_vector_math_op(tensor, a, b, child_context,
|
364
|
+
def call_vector_op(tensor, op, a, b, child_context, &block)
|
365
|
+
process_vector_math_op(tensor, a, b, child_context, &block)
|
352
366
|
rescue FullEvalNotPossible
|
353
367
|
TensorStream.send(op.to_sym, a, b)
|
354
368
|
end
|
355
369
|
|
356
|
-
def process_vector_math_op(tensor, a, b, child_context,
|
370
|
+
def process_vector_math_op(tensor, a, b, child_context, &block)
|
357
371
|
eval_a = global_eval(tensor, a, child_context) unless a.nil?
|
358
372
|
eval_b = global_eval(tensor, b, child_context) unless b.nil?
|
359
373
|
|
@@ -361,7 +375,7 @@ module TensorStream
|
|
361
375
|
|
362
376
|
# ruby scalar
|
363
377
|
eval_a, eval_b = broadcast(eval_a, eval_b)
|
364
|
-
vector_op(eval_a, eval_b,
|
378
|
+
vector_op(eval_a, eval_b, &block)
|
365
379
|
# if get_rank(eval_a).zero?
|
366
380
|
# if get_rank(eval_b).zero?
|
367
381
|
# op.call(eval_a, eval_b)
|
@@ -411,16 +425,16 @@ module TensorStream
|
|
411
425
|
end
|
412
426
|
|
413
427
|
# handle 3 tensor math operations
|
414
|
-
def call_3way_vector_op(v_a, v_b, v_c, child_context,
|
415
|
-
return
|
428
|
+
def call_3way_vector_op(v_a, v_b, v_c, child_context, &block)
|
429
|
+
return yield(v_a, v_b, v_c) unless v_a.is_a?(Array)
|
416
430
|
|
417
431
|
v_a.each_with_index.collect do |v1, index|
|
418
432
|
v2 = v_b[index]
|
419
433
|
v3 = v_c.is_a?(Array) ? v_c[index] : v_c
|
420
434
|
if v1.is_a?(Array)
|
421
|
-
call_3way_vector_op(v1, v2, v3, child_context,
|
435
|
+
call_3way_vector_op(v1, v2, v3, child_context, &block)
|
422
436
|
else
|
423
|
-
|
437
|
+
yield(v1, v2, v3)
|
424
438
|
end
|
425
439
|
end
|
426
440
|
end
|
data/lib/tensor_stream/graph.rb
CHANGED
@@ -118,6 +118,10 @@ module TensorStream
|
|
118
118
|
get_node(name)
|
119
119
|
end
|
120
120
|
|
121
|
+
def [](name)
|
122
|
+
get_node(name)
|
123
|
+
end
|
124
|
+
|
121
125
|
def add_node!(name, node)
|
122
126
|
@nodes[name] = node
|
123
127
|
node
|
@@ -219,6 +223,7 @@ module TensorStream
|
|
219
223
|
@placeholder_counter += 1
|
220
224
|
|
221
225
|
return '' if @placeholder_counter == 1
|
226
|
+
|
222
227
|
"_#{@placeholder_counter}"
|
223
228
|
end
|
224
229
|
|
@@ -1,15 +1,36 @@
|
|
1
1
|
module TensorStream
|
2
|
+
##
|
3
|
+
# Class for deserialization from a YAML file
|
2
4
|
class YamlLoader
|
3
5
|
def initialize(graph = nil)
|
4
6
|
@graph = graph || TensorStream.get_default_graph
|
5
7
|
end
|
6
8
|
|
9
|
+
##
|
10
|
+
# Loads a model Yaml file and builds the model from it
|
11
|
+
#
|
12
|
+
# Args:
|
13
|
+
# filename: String - Location of Yaml file
|
14
|
+
#
|
15
|
+
# Returns: Graph where model is restored to
|
16
|
+
def load_from_file(filename)
|
17
|
+
load_from_string(File.read(filename))
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Loads a model Yaml file and builds the model from it
|
22
|
+
#
|
23
|
+
# Args:
|
24
|
+
# buffer: String - String in Yaml format of the model
|
25
|
+
#
|
26
|
+
# Returns: Graph where model is restored to
|
7
27
|
def load_from_string(buffer)
|
8
|
-
serialized_ops = YAML.safe_load(buffer, [Symbol])
|
28
|
+
serialized_ops = YAML.safe_load(buffer, [Symbol], [], true)
|
9
29
|
serialized_ops.each do |op_def|
|
10
30
|
inputs = op_def[:inputs].map { |i| @graph.get_tensor_by_name(i) }
|
11
31
|
options = {}
|
12
32
|
|
33
|
+
new_var = nil
|
13
34
|
if op_def.dig(:attrs, :container)
|
14
35
|
new_var = Variable.new(op_def.dig(:attrs, :data_type))
|
15
36
|
var_shape = op_def.dig(:attrs, :container, :shape)
|
@@ -30,9 +51,11 @@ module TensorStream
|
|
30
51
|
new_op.data_type = new_op.set_data_type(op_def.dig(:attrs, :data_type))
|
31
52
|
new_op.is_const = new_op.infer_const
|
32
53
|
new_op.given_name = new_op.name
|
54
|
+
new_var.op = new_op if new_var
|
33
55
|
|
34
56
|
@graph.add_node(new_op)
|
35
57
|
end
|
58
|
+
@graph
|
36
59
|
end
|
37
60
|
end
|
38
61
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module TensorStream
|
2
|
+
module OpPatch
|
3
|
+
def self.included(klass)
|
4
|
+
ops = if klass == Array
|
5
|
+
{:+ => 'add', :- => 'sub', :* => 'mul'}
|
6
|
+
else
|
7
|
+
{:+ => 'add', :- => 'sub', :/ => 'div', :% => 'mod', :* => 'mul', :** => 'pow' }
|
8
|
+
end
|
9
|
+
|
10
|
+
ops.each do |m, name|
|
11
|
+
klass.send(:alias_method, :"_tensor_stream_#{name}_orig", m)
|
12
|
+
klass.send(:remove_method, m)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def +(other)
|
17
|
+
if other.is_a?(TensorStream::Tensor)
|
18
|
+
TensorStream.convert_to_tensor(self, dtype: other.data_type) + other
|
19
|
+
else
|
20
|
+
_tensor_stream_add_orig(other)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def -(other)
|
25
|
+
if other.is_a?(TensorStream::Tensor)
|
26
|
+
TensorStream.convert_to_tensor(self, dtype: other.data_type) - other
|
27
|
+
else
|
28
|
+
_tensor_stream_sub_orig(other)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def *(other)
|
33
|
+
if other.is_a?(TensorStream::Tensor)
|
34
|
+
TensorStream.convert_to_tensor(self, dtype: other.data_type) * other
|
35
|
+
else
|
36
|
+
_tensor_stream_mul_orig(other)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def /(other)
|
41
|
+
if other.is_a?(TensorStream::Tensor)
|
42
|
+
TensorStream.convert_to_tensor(self, dtype: other.data_type) * other
|
43
|
+
else
|
44
|
+
_tensor_stream_div_orig(other)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def %(other)
|
49
|
+
if other.is_a?(TensorStream::Tensor)
|
50
|
+
TensorStream.convert_to_tensor(self, dtype: other.data_type) % other
|
51
|
+
else
|
52
|
+
_tensor_stream_mod_orig(other)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def **(other)
|
57
|
+
if other.is_a?(TensorStream::Tensor)
|
58
|
+
TensorStream.convert_to_tensor(self, dtype: other.data_type)**other
|
59
|
+
else
|
60
|
+
_tensor_stream_pow_orig(other)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Integer.include TensorStream::OpPatch
|
67
|
+
Float.include TensorStream::OpPatch
|
68
|
+
Array.include TensorStream::OpPatch
|
@@ -2,19 +2,6 @@
|
|
2
2
|
module TensorStream
|
3
3
|
# various monkey patches to FixNum types
|
4
4
|
module MonkeyPatch
|
5
|
-
def self.included(klass)
|
6
|
-
ops = if klass == Array
|
7
|
-
{:+ => 'add', :- => 'sub', :* => 'mul'}
|
8
|
-
else
|
9
|
-
{:+ => 'add', :- => 'sub', :/ => 'div', :% => 'mod', :* => 'mul', :** => 'pow' }
|
10
|
-
end
|
11
|
-
|
12
|
-
ops.each do |m, name|
|
13
|
-
klass.send(:alias_method, :"_tensor_stream_#{name}_orig", m)
|
14
|
-
klass.send(:remove_method, m)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
5
|
def shape
|
19
6
|
TensorStream.shape_eval(self)
|
20
7
|
end
|
@@ -22,53 +9,5 @@ module TensorStream
|
|
22
9
|
def t(name = nil, dtype: nil)
|
23
10
|
TensorStream.convert_to_tensor(self, name: name, dtype: dtype)
|
24
11
|
end
|
25
|
-
|
26
|
-
def +(other)
|
27
|
-
if other.is_a?(TensorStream::Tensor)
|
28
|
-
TensorStream.convert_to_tensor(self, dtype: other.data_type) + other
|
29
|
-
else
|
30
|
-
_tensor_stream_add_orig(other)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def -(other)
|
35
|
-
if other.is_a?(TensorStream::Tensor)
|
36
|
-
TensorStream.convert_to_tensor(self, dtype: other.data_type) - other
|
37
|
-
else
|
38
|
-
_tensor_stream_sub_orig(other)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def *(other)
|
43
|
-
if other.is_a?(TensorStream::Tensor)
|
44
|
-
TensorStream.convert_to_tensor(self, dtype: other.data_type) * other
|
45
|
-
else
|
46
|
-
_tensor_stream_mul_orig(other)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def /(other)
|
51
|
-
if other.is_a?(TensorStream::Tensor)
|
52
|
-
TensorStream.convert_to_tensor(self, dtype: other.data_type) * other
|
53
|
-
else
|
54
|
-
_tensor_stream_div_orig(other)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def %(other)
|
59
|
-
if other.is_a?(TensorStream::Tensor)
|
60
|
-
TensorStream.convert_to_tensor(self, dtype: other.data_type) % other
|
61
|
-
else
|
62
|
-
_tensor_stream_mod_orig(other)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def **(other)
|
67
|
-
if other.is_a?(TensorStream::Tensor)
|
68
|
-
TensorStream.convert_to_tensor(self, dtype: other.data_type)**other
|
69
|
-
else
|
70
|
-
_tensor_stream_pow_orig(other)
|
71
|
-
end
|
72
|
-
end
|
73
12
|
end
|
74
13
|
end
|
data/lib/tensor_stream/ops.rb
CHANGED
@@ -137,7 +137,7 @@ module TensorStream
|
|
137
137
|
end
|
138
138
|
|
139
139
|
if shapes_known
|
140
|
-
inputs.collect { |input| cons(input.shape.shape, dtype: out_type) }
|
140
|
+
inputs.collect { |input| cons(input.shape.shape, dtype: out_type).op }
|
141
141
|
else
|
142
142
|
res = _op(:shape_n, *inputs, out_type: out_type, name: name)
|
143
143
|
Array.new(inputs.size) do |index|
|
@@ -5,13 +5,13 @@ module TensorStream
|
|
5
5
|
def self.profile_for(session, order_by: :slowest)
|
6
6
|
context = session.last_session_context
|
7
7
|
eval_times = context[:profile][:operations].map do |name, profile|
|
8
|
-
[name, profile[:
|
8
|
+
[name, profile[:op], profile[:eval_time], profile[:shape]]
|
9
9
|
end
|
10
10
|
|
11
11
|
if order_by == :slowest
|
12
|
-
eval_times.sort_by { |a| a[
|
12
|
+
eval_times.sort_by { |a| a[2] }.reverse!
|
13
13
|
else
|
14
|
-
eval_times.sort_by { |a| a[
|
14
|
+
eval_times.sort_by { |a| a[2] }
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -51,7 +51,8 @@ module TensorStream
|
|
51
51
|
|
52
52
|
context = {
|
53
53
|
_cache: @session_cache,
|
54
|
-
_options: options.merge(@evaluator_options)
|
54
|
+
_options: options.merge(@evaluator_options),
|
55
|
+
profile: { step: 0, operations: {} },
|
55
56
|
}
|
56
57
|
|
57
58
|
# scan for placeholders and assign value
|
@@ -62,18 +63,17 @@ module TensorStream
|
|
62
63
|
elsif k.is_a?(String)
|
63
64
|
target_graph = args[0].graph
|
64
65
|
node = target_graph.get_node(k)
|
65
|
-
if node.operation
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
raise "Cannot find placeholder with the name of #{k}" if node.operation != :placeholder
|
67
|
+
|
68
|
+
context[k.to_sym] = options[:feed_dict][k]
|
69
|
+
elsif k.is_a?(Operation) && k.operation == :placeholder
|
70
|
+
context[k.name.to_sym] = options[:feed_dict][k]
|
70
71
|
else
|
71
72
|
raise "Invalid placeholder type passed key must be a string or a placeholder type"
|
72
73
|
end
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
76
|
-
|
77
77
|
args.each { |t| prepare_evaluators(t, context) }
|
78
78
|
@last_session_context = context
|
79
79
|
|
@@ -119,6 +119,7 @@ module TensorStream
|
|
119
119
|
graph = tensor.graph
|
120
120
|
graph.nodes.select { |k, v| selector.call(k, v) }.collect do |k, node|
|
121
121
|
next unless @last_session_context[node.name]
|
122
|
+
|
122
123
|
"#{k} #{node.to_math(true, 1)} = #{@last_session_context[node.name]}"
|
123
124
|
end.compact
|
124
125
|
end
|
@@ -7,6 +7,16 @@ module TensorStream
|
|
7
7
|
class Saver
|
8
8
|
include TensorStream::OpHelper
|
9
9
|
|
10
|
+
def initialize
|
11
|
+
graph = TensorStream::Graph.get_default_graph
|
12
|
+
vars = graph.get_collection(GraphKeys::GLOBAL_VARIABLES)
|
13
|
+
|
14
|
+
@filename = graph['ts_filename'] || TensorStream.placeholder(:string, name: 'ts_filename', shape: [])
|
15
|
+
|
16
|
+
@save_op = _op(:save_ts, @filename, *vars)
|
17
|
+
@restore_op = _op(:restore_ts, @filename, *vars.map(&:name))
|
18
|
+
end
|
19
|
+
|
10
20
|
def save(session, outputdir, global_step: nil,
|
11
21
|
latest_filename: nil,
|
12
22
|
meta_graph_suffix: 'meta',
|
@@ -19,25 +29,13 @@ module TensorStream
|
|
19
29
|
variables = {}
|
20
30
|
|
21
31
|
gs = eval_global_step(session, global_step)
|
22
|
-
output_dump = {
|
23
|
-
'variables' => variables,
|
24
|
-
'global_step' => gs
|
25
|
-
}
|
26
|
-
|
27
|
-
vars.each do |variable|
|
28
|
-
val = variable.read_value
|
29
|
-
packed_data = Zlib::Deflate.deflate(TensorStream::Packer.pack(val, variable.data_type))
|
30
|
-
variables[variable.name] = {
|
31
|
-
'shape' => shape_eval(val),
|
32
|
-
'data' => Base64.strict_encode64(packed_data)
|
33
|
-
}
|
34
|
-
end
|
35
32
|
|
36
33
|
FileUtils.mkdir_p(outputdir)
|
37
34
|
basename = 'model'
|
38
35
|
File.write(File.join(outputdir, "#{basename}.meta"), { "gs" => gs }.to_json)
|
39
36
|
new_filename = File.join(outputdir, [basename, gs, '.ckpt'].compact.join('-'))
|
40
|
-
|
37
|
+
session.run(@save_op, feed_dict: { @filename => new_filename })
|
38
|
+
|
41
39
|
if write_meta_graph
|
42
40
|
graph_filename = "#{basename}.yaml"
|
43
41
|
TensorStream.train.write_graph(graph, outputdir, graph_filename, serializer: :yaml)
|
@@ -45,20 +43,15 @@ module TensorStream
|
|
45
43
|
outputdir
|
46
44
|
end
|
47
45
|
|
48
|
-
def restore(
|
49
|
-
|
50
|
-
|
51
|
-
input_dump = YAML.safe_load(File.read(File.join(modelpath, ['model', gs, '.ckpt'].compact.join('-'))))
|
46
|
+
def restore(session, modelpath)
|
47
|
+
meta_file = File.join(modelpath, "model.meta")
|
48
|
+
return unless File.exist?(meta_file)
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
meta_data = JSON.parse(File.read(meta_file))
|
51
|
+
gs = meta_data['gs']
|
52
|
+
filename = File.join(modelpath, ['model', gs, '.ckpt'].compact.join('-'))
|
56
53
|
|
57
|
-
|
58
|
-
shape = input_dump['variables'][variable.name]['shape']
|
59
|
-
variable.buffer = nil
|
60
|
-
variable.value = TensorShape.reshape(data, shape)
|
61
|
-
end
|
54
|
+
session.run(@restore_op, feed_dict: { @filename => filename })
|
62
55
|
end
|
63
56
|
|
64
57
|
private
|
@@ -1,18 +1,24 @@
|
|
1
1
|
module TensorStream
|
2
2
|
class Freezer
|
3
|
-
include OpHelper
|
3
|
+
include TensorStream::OpHelper
|
4
4
|
|
5
5
|
##
|
6
6
|
# Utility class to convert variables to constants for production deployment
|
7
7
|
#
|
8
|
-
def convert(
|
8
|
+
def convert(session, checkpoint_folder, output_file)
|
9
|
+
model_file = File.join(checkpoint_folder, 'model.yaml')
|
9
10
|
TensorStream.graph.as_default do |current_graph|
|
10
11
|
YamlLoader.new.load_from_string(File.read(model_file))
|
11
12
|
saver = TensorStream::Train::Saver.new
|
12
|
-
saver.restore(
|
13
|
+
saver.restore(session, checkpoint_folder)
|
14
|
+
|
15
|
+
# collect all assign ops and remove them from the graph
|
16
|
+
remove_nodes = Set.new(current_graph.nodes.values.select { |op| op.is_a?(TensorStream::Operation) && op.operation == :assign }.map { |op| op.consumers.to_a }.flatten.uniq)
|
17
|
+
|
13
18
|
output_buffer = TensorStream::Yaml.new.get_string(current_graph) do |graph, node_key|
|
14
19
|
node = graph.get_tensor_by_name(node_key)
|
15
|
-
|
20
|
+
case node.operation
|
21
|
+
when :variable_v2
|
16
22
|
value = node.container
|
17
23
|
options = {
|
18
24
|
value: value,
|
@@ -26,8 +32,10 @@ module TensorStream
|
|
26
32
|
const_op.shape = TensorShape.new(shape_eval(value))
|
27
33
|
|
28
34
|
const_op
|
35
|
+
when :assign
|
36
|
+
nil
|
29
37
|
else
|
30
|
-
node
|
38
|
+
remove_nodes.include?(node.name) ? nil : node
|
31
39
|
end
|
32
40
|
end
|
33
41
|
File.write(output_file, output_buffer)
|
data/tensor_stream.gemspec
CHANGED
@@ -35,12 +35,13 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_development_dependency "rspec", "~> 3.0"
|
36
36
|
spec.add_development_dependency "awesome_print"
|
37
37
|
spec.add_development_dependency "rubocop"
|
38
|
-
|
39
|
-
|
38
|
+
if RUBY_ENGINE == 'ruby'
|
39
|
+
spec.add_development_dependency "pry-byebug"
|
40
|
+
spec.add_development_dependency "byepry"
|
41
|
+
end
|
40
42
|
spec.add_development_dependency "colorize"
|
41
43
|
spec.add_development_dependency "rspec_junit_formatter"
|
42
44
|
spec.add_development_dependency "mnist-learn"
|
43
|
-
spec.add_development_dependency "opencl_ruby_ffi"
|
44
45
|
spec.add_development_dependency "simplecov"
|
45
46
|
spec.add_dependency "deep_merge"
|
46
47
|
spec.add_dependency "concurrent-ruby"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tensor_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Emmanuel Dayo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -150,20 +150,6 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: opencl_ruby_ffi
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - ">="
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - ">="
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
167
153
|
- !ruby/object:Gem::Dependency
|
168
154
|
name: simplecov
|
169
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -226,7 +212,8 @@ description: A reimplementation of TensorFlow for ruby. This is a ground up impl
|
|
226
212
|
well with support for an opencl evaluator.
|
227
213
|
email:
|
228
214
|
- joseph.dayo@gmail.com
|
229
|
-
executables:
|
215
|
+
executables:
|
216
|
+
- model_utils
|
230
217
|
extensions: []
|
231
218
|
extra_rdoc_files: []
|
232
219
|
files:
|
@@ -253,6 +240,7 @@ files:
|
|
253
240
|
- data_actual.json
|
254
241
|
- data_expected.json
|
255
242
|
- data_input.json
|
243
|
+
- exe/model_utils
|
256
244
|
- lib/tensor_stream.rb
|
257
245
|
- lib/tensor_stream/constant.rb
|
258
246
|
- lib/tensor_stream/control_flow.rb
|
@@ -293,6 +281,7 @@ files:
|
|
293
281
|
- lib/tensor_stream/monkey_patches/array.rb
|
294
282
|
- lib/tensor_stream/monkey_patches/float.rb
|
295
283
|
- lib/tensor_stream/monkey_patches/integer.rb
|
284
|
+
- lib/tensor_stream/monkey_patches/op_patch.rb
|
296
285
|
- lib/tensor_stream/monkey_patches/patch.rb
|
297
286
|
- lib/tensor_stream/nn/nn_ops.rb
|
298
287
|
- lib/tensor_stream/operation.rb
|
@@ -348,9 +337,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
348
337
|
version: '0'
|
349
338
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
350
339
|
requirements:
|
351
|
-
- - "
|
340
|
+
- - ">"
|
352
341
|
- !ruby/object:Gem::Version
|
353
|
-
version:
|
342
|
+
version: 1.3.1
|
354
343
|
requirements: []
|
355
344
|
rubygems_version: 3.0.1
|
356
345
|
signing_key:
|