tensor_stream 0.9.7 → 0.9.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/data_1.json +4764 -0
- data/data_2.json +4764 -0
- data/data_actual.json +28 -0
- data/data_expected.json +28 -0
- data/data_input.json +28 -0
- data/lib/tensor_stream/evaluator/ruby/nn_ops.rb +68 -24
- data/lib/tensor_stream/evaluator/ruby/random_ops.rb +52 -0
- data/lib/tensor_stream/evaluator/ruby_evaluator.rb +2 -1
- data/lib/tensor_stream/helpers/infer_shape.rb +20 -3
- data/lib/tensor_stream/helpers/op_helper.rb +1 -1
- data/lib/tensor_stream/operation.rb +2 -2
- data/lib/tensor_stream/ops.rb +8 -1
- data/lib/tensor_stream/version.rb +1 -1
- metadata +7 -2
data/data_actual.json
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
**********
|
7
|
+
********************
|
8
|
+
********************
|
9
|
+
********************
|
10
|
+
********************
|
11
|
+
********************
|
12
|
+
********************
|
13
|
+
***************
|
14
|
+
**********
|
15
|
+
**********
|
16
|
+
**********
|
17
|
+
**********
|
18
|
+
***********
|
19
|
+
***********
|
20
|
+
**********
|
21
|
+
***********
|
22
|
+
**********
|
23
|
+
***********
|
24
|
+
**********
|
25
|
+
**********
|
26
|
+
*********
|
27
|
+
*********
|
28
|
+
*********
|
data/data_expected.json
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
**********
|
7
|
+
********************
|
8
|
+
********************
|
9
|
+
********************
|
10
|
+
********************
|
11
|
+
********************
|
12
|
+
********************
|
13
|
+
***************
|
14
|
+
**********
|
15
|
+
**********
|
16
|
+
**********
|
17
|
+
**********
|
18
|
+
***********
|
19
|
+
***********
|
20
|
+
**********
|
21
|
+
***********
|
22
|
+
**********
|
23
|
+
***********
|
24
|
+
**********
|
25
|
+
**********
|
26
|
+
*********
|
27
|
+
*********
|
28
|
+
*********
|
data/data_input.json
ADDED
@@ -214,25 +214,32 @@ module TensorStream
|
|
214
214
|
|
215
215
|
register_op :conv2d do |_context, tensor, inputs|
|
216
216
|
filter = inputs[1]
|
217
|
+
|
217
218
|
filter_shape = shape_eval(filter)
|
218
219
|
strides = tensor.options[:strides]
|
220
|
+
padding_option = tensor.options[:padding]
|
219
221
|
height_stride = strides[1]
|
220
222
|
width_stride = strides[2]
|
221
223
|
|
222
224
|
raise TensorStream::ValueError, " Current implementation does not yet support strides in the batch and depth dimensions." if strides[0] != 1 || strides[3] != 1
|
223
225
|
|
226
|
+
_batch, height, width, _channels = shape_eval(inputs[0])
|
227
|
+
padding = conv2d_padding_options(padding_option, filter_shape, height, width, height_stride, width_stride)
|
224
228
|
inputs[0].collect do |image|
|
225
|
-
height, width, _channels = shape_eval(image)
|
226
229
|
f_height, f_width, _input_channels, _output_channels = filter_shape
|
230
|
+
(-padding[0]...height).step(height_stride).map do |y|
|
231
|
+
next if (y + f_height) > (height + padding[2])
|
232
|
+
|
233
|
+
(-padding[1]...width).step(width_stride).map do |x|
|
234
|
+
next if (x + f_width) > (width + padding[3])
|
227
235
|
|
228
|
-
(0...height).step(height_stride).map do |y|
|
229
|
-
(0...width).step(width_stride).map do |x|
|
230
236
|
filter_result = (0...f_height).map do |f_y|
|
231
237
|
(0...f_width).map do |f_x|
|
232
238
|
f_element = filter[f_y][f_x]
|
233
239
|
|
234
|
-
next if x + f_x >= width
|
235
|
-
next if y + f_y >= height
|
240
|
+
next if (x + f_x >= width) || (x + f_x < 0)
|
241
|
+
next if (y + f_y >= height) || (y + f_y < 0)
|
242
|
+
|
236
243
|
|
237
244
|
image[y + f_y][x + f_x].zip(f_element).map do |image_channel, filter_channels|
|
238
245
|
filter_channels.map { |c| image_channel * c }
|
@@ -241,16 +248,15 @@ module TensorStream
|
|
241
248
|
end.flatten(2)
|
242
249
|
|
243
250
|
filter_result.transpose.map { |e| e.reduce(:+) }
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
251
|
+
end.compact
|
252
|
+
end.compact
|
253
|
+
end.compact
|
247
254
|
end
|
248
255
|
|
249
256
|
register_op :conv2d_backprop_input do |_context, tensor, inputs|
|
250
257
|
image_shape, filter, grad = inputs
|
251
|
-
|
252
258
|
strides = tensor.options[:strides]
|
253
|
-
|
259
|
+
padding_option = tensor.options[:padding]
|
254
260
|
height_stride = strides[1]
|
255
261
|
width_stride = strides[2]
|
256
262
|
|
@@ -259,25 +265,34 @@ module TensorStream
|
|
259
265
|
f_height, f_width, _input_channels, output_channels = filter_shape
|
260
266
|
batch, height, width, channels = image_shape
|
261
267
|
|
268
|
+
padding = conv2d_padding_options(padding_option, filter_shape, height, width, height_stride, width_stride)
|
269
|
+
|
262
270
|
Array.new(batch) do |b|
|
263
271
|
image_gradient = TensorShape.reshape(Array.new(height * width * channels) { 0.0 }, [height, width, channels])
|
264
272
|
|
265
|
-
(0...height).step(height_stride).each do |y|
|
266
|
-
(
|
267
|
-
|
273
|
+
((0 - padding[0])...height).step(height_stride).each do |y|
|
274
|
+
next if (y + f_height) > (height + padding[2])
|
275
|
+
|
276
|
+
((0 - padding[1])...width).step(width_stride).each do |x|
|
277
|
+
next if (x + f_width) > (width + padding[3])
|
268
278
|
|
269
279
|
(0...f_height).each do |f_y|
|
270
280
|
(0...f_width).each do |f_x|
|
271
|
-
next if
|
272
|
-
next if
|
281
|
+
next if (y + f_y) < 0 || (y + f_y) >= height
|
282
|
+
next if (x + f_x) < 0 || (x + f_x) >= width
|
283
|
+
|
284
|
+
img_grad = grad[b][(y + padding[0]) / height_stride][(x + padding[1]) / width_stride]
|
273
285
|
|
274
286
|
channels.times.each do |c|
|
275
|
-
|
287
|
+
g = Array.new(output_channels) do |o_c|
|
276
288
|
filter[f_y][f_x][c][o_c] * img_grad[o_c]
|
277
289
|
end.reduce(:+)
|
290
|
+
|
291
|
+
image_gradient[y + f_y][x + f_x][c] += g
|
278
292
|
end
|
279
293
|
end
|
280
294
|
end
|
295
|
+
|
281
296
|
end
|
282
297
|
end
|
283
298
|
|
@@ -289,25 +304,28 @@ module TensorStream
|
|
289
304
|
images, filter_shape, grad = inputs
|
290
305
|
|
291
306
|
strides = tensor.options[:strides]
|
307
|
+
padding_option = tensor.options[:padding]
|
292
308
|
height_stride = strides[1]
|
293
309
|
width_stride = strides[2]
|
294
310
|
|
295
311
|
filter_gradient_sum = Array.new(filter_shape.reduce(:*)) { 0.0 }
|
296
312
|
|
313
|
+
_batch, height, width, _channels = shape_eval(images)
|
314
|
+
padding = conv2d_padding_options(padding_option, filter_shape, height, width, height_stride, width_stride)
|
315
|
+
|
297
316
|
images.each_with_index.map do |image, index|
|
298
|
-
height, width, _channels = shape_eval(image)
|
299
317
|
f_height, f_width, input_channels, output_channels = filter_shape
|
300
318
|
|
301
|
-
(0...height).step(height_stride).each do |y|
|
302
|
-
(0...width).step(width_stride).each do |x|
|
303
|
-
image_grad = grad[index][y/height_stride][x/width_stride]
|
319
|
+
((0 - padding[0])...height).step(height_stride).each do |y|
|
320
|
+
((0 - padding[1])...width).step(width_stride).each do |x|
|
304
321
|
filter_result = (0...f_height).map do |f_y|
|
305
322
|
(0...f_width).map do |f_x|
|
306
|
-
next Array.new(input_channels * output_channels) { 0.0 } if x + f_x >= width
|
307
|
-
next Array.new(input_channels * output_channels) { 0.0 } if y + f_y >= height
|
323
|
+
next Array.new(input_channels * output_channels) { 0.0 } if x + f_x >= width || (x + f_x < 0) || ((x + f_width) > (width + padding[3]))
|
324
|
+
next Array.new(input_channels * output_channels) { 0.0 } if y + f_y >= height || (y + f_y < 0) || ((y + f_height) > (height + padding[2]))
|
308
325
|
|
309
|
-
|
310
|
-
|
326
|
+
image_grad = grad[index][(y + padding[0]) / height_stride][(x + padding[1])/ width_stride]
|
327
|
+
image[y + f_y][x + f_x].map do |image_channel|
|
328
|
+
Array.new(output_channels) do |o_c|
|
311
329
|
image_channel * image_grad[o_c]
|
312
330
|
end
|
313
331
|
end
|
@@ -321,6 +339,32 @@ module TensorStream
|
|
321
339
|
|
322
340
|
TensorShape.reshape(filter_gradient_sum, filter_shape)
|
323
341
|
end
|
342
|
+
|
343
|
+
|
344
|
+
def conv2d_padding_options(padding_option, filter_shape, height, width, h_stride, w_stride)
|
345
|
+
case padding_option
|
346
|
+
when 'SAME'
|
347
|
+
[
|
348
|
+
calc_pad(height, h_stride, filter_shape[0]),
|
349
|
+
calc_pad(width, w_stride, filter_shape[1]),
|
350
|
+
calc_pad(height, h_stride, filter_shape[0], true),
|
351
|
+
calc_pad(width, w_stride, filter_shape[1], true)
|
352
|
+
]
|
353
|
+
when 'VALID'
|
354
|
+
[0, 0, 0, 0]
|
355
|
+
else
|
356
|
+
raise TensorStream::ValueError, "Unsupported padding value #{padding_option}, valid values 'SAME', 'VALID'"
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def calc_pad(w, stride, f_shape, ceil = false)
|
361
|
+
r = ((w / stride - 1) * stride - w + f_shape)
|
362
|
+
if ceil
|
363
|
+
r.odd? ? r / 2 + 1 : r / 2
|
364
|
+
else
|
365
|
+
r / 2
|
366
|
+
end
|
367
|
+
end
|
324
368
|
end
|
325
369
|
end
|
326
370
|
end
|
@@ -45,6 +45,58 @@ module TensorStream
|
|
45
45
|
shape = inputs[0] || tensor.shape.shape
|
46
46
|
generate_vector(shape, generator: generator)
|
47
47
|
end
|
48
|
+
|
49
|
+
|
50
|
+
register_op :truncated_normal, no_eval: true do |_context, tensor, inputs|
|
51
|
+
seed = tensor.options[:seed]
|
52
|
+
random = _get_randomizer(tensor, seed)
|
53
|
+
r = RandomGaussian.new(tensor.options.fetch(:mean), tensor.options.fetch(:stddev), -> { random.rand })
|
54
|
+
random = _get_randomizer(tensor, seed)
|
55
|
+
generator = -> { r.rand }
|
56
|
+
shape = inputs[0] || tensor.shape.shape
|
57
|
+
random_values = Array.new(shape.reduce(:*) || 1) {
|
58
|
+
generator.call
|
59
|
+
}
|
60
|
+
mean = random_values.reduce(:+) / random_values.size
|
61
|
+
|
62
|
+
# standard deviation
|
63
|
+
|
64
|
+
stddev = Math.sqrt( random_values.map { |v| ( v - mean )**2 }.reduce(:+) / (random_values.size - 1) )
|
65
|
+
minval = random_values.min
|
66
|
+
maxval = random_values.max
|
67
|
+
max_iterations = 100
|
68
|
+
|
69
|
+
if (minval.infinite? && minval < 0.0) || (maxval < mean)
|
70
|
+
# Reverse all calculations. normMin and normMax will be flipped.
|
71
|
+
a = minval
|
72
|
+
minval = maxval
|
73
|
+
maxval = a
|
74
|
+
stddev = -stddev
|
75
|
+
end
|
76
|
+
|
77
|
+
norm_min = (minval - mean) / stddev;
|
78
|
+
norm_max = (maxval - mean) / stddev;
|
79
|
+
sqrt_factor = Math.sqrt((norm_min * norm_min) + 4.0);
|
80
|
+
cutoff = 2.0 * Math.exp( 0.5 + (norm_min * (norm_min - sqrt_factor)) / 4.0 ) / (norm_min + sqrt_factor)
|
81
|
+
diff = norm_max - norm_min;
|
82
|
+
|
83
|
+
val = random_values.map { |v|
|
84
|
+
iterations = 0
|
85
|
+
pick = v
|
86
|
+
while ( (pick > norm_max) || (pick < norm_min) )
|
87
|
+
pick = generator.call
|
88
|
+
iterations += 1
|
89
|
+
if iterations > 100
|
90
|
+
pick = v
|
91
|
+
break
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
pick
|
96
|
+
}
|
97
|
+
|
98
|
+
TensorShape.reshape(val, shape)
|
99
|
+
end
|
48
100
|
end
|
49
101
|
end
|
50
102
|
end
|
@@ -289,7 +289,8 @@ module TensorStream
|
|
289
289
|
# assertions to make sure inferred shapes == actual evaluated shapes
|
290
290
|
if tensor.shape.known? && (result.is_a?(Array) || result.is_a?(Float) || result.is_a?(Integer))
|
291
291
|
if shape_eval(result) != tensor.shape.shape
|
292
|
-
|
292
|
+
|
293
|
+
raise "assert error #{tensor.name} #{shape_eval(result)} != #{tensor.shape.shape}"
|
293
294
|
end
|
294
295
|
end
|
295
296
|
|
@@ -66,14 +66,16 @@ module TensorStream
|
|
66
66
|
return nil if tensor.inputs[0].shape.nil?
|
67
67
|
|
68
68
|
input_shape = tensor.inputs[0].shape.shape
|
69
|
-
return new_shape if input_shape.nil?
|
70
|
-
return nil if input_shape.include?(nil)
|
69
|
+
return new_shape if input_shape.nil? && !new_shape.include?(-1) && !new_shape.include?(nil)
|
70
|
+
return nil if input_shape.nil? || input_shape.include?(nil)
|
71
|
+
|
71
72
|
TensorShape.fix_inferred_elements(new_shape, input_shape.reduce(:*))
|
72
73
|
when :flow_group
|
73
74
|
[]
|
74
|
-
when :zeros, :ones, :fill, :random_standard_normal, :random_uniform
|
75
|
+
when :zeros, :ones, :fill, :random_standard_normal, :random_uniform, :truncated_normal
|
75
76
|
a_shape = tensor.inputs[0] ? tensor.inputs[0].const_value : tensor.options[:shape]
|
76
77
|
return nil if a_shape.nil?
|
78
|
+
|
77
79
|
a_shape.is_a?(Array) ? a_shape : [a_shape]
|
78
80
|
when :zeros_like, :ones_like
|
79
81
|
tensor.inputs[0].shape.shape
|
@@ -177,6 +179,21 @@ module TensorStream
|
|
177
179
|
|
178
180
|
new_shape = tensor.inputs[0].shape.shape.dup
|
179
181
|
new_shape[3] = tensor.inputs[1].shape.shape[3]
|
182
|
+
|
183
|
+
# account for stride and padding options
|
184
|
+
strides = tensor.options[:strides]
|
185
|
+
|
186
|
+
case tensor.options[:padding]
|
187
|
+
when 'SAME'
|
188
|
+
new_shape[1] /= strides[1]
|
189
|
+
new_shape[2] /= strides[2]
|
190
|
+
when 'VALID'
|
191
|
+
new_shape[1] = (new_shape[1] - tensor.inputs[1].shape.shape[0]) / strides[1] + 1
|
192
|
+
new_shape[2] = (new_shape[2] - tensor.inputs[1].shape.shape[1]) / strides[2] + 1
|
193
|
+
else
|
194
|
+
raise TensorStream::ValueError, "Invalid padding option only 'SAME', 'VALID' accepted"
|
195
|
+
end
|
196
|
+
|
180
197
|
new_shape
|
181
198
|
when :conv2d_backprop_input
|
182
199
|
return nil unless tensor.inputs[0].value
|
@@ -46,7 +46,7 @@ module TensorStream
|
|
46
46
|
def infer_const
|
47
47
|
return false if breakpoint
|
48
48
|
case operation
|
49
|
-
when :random_standard_normal, :random_uniform, :glorot_uniform, :print, :check_numerics
|
49
|
+
when :random_standard_normal, :random_uniform, :truncated_normal, :glorot_uniform, :print, :check_numerics
|
50
50
|
false
|
51
51
|
else
|
52
52
|
non_const = @inputs.compact.find { |input| !input.is_const }
|
@@ -62,7 +62,7 @@ module TensorStream
|
|
62
62
|
:boolean
|
63
63
|
when :shape, :rank, :shape_n
|
64
64
|
options[:out_type] || :int32
|
65
|
-
when :random_standard_normal, :random_uniform, :glorot_uniform
|
65
|
+
when :random_standard_normal, :random_uniform, :glorot_uniform, :truncated_normal
|
66
66
|
passed_data_type || :float32
|
67
67
|
when :concat
|
68
68
|
@inputs[1].data_type
|
data/lib/tensor_stream/ops.rb
CHANGED
@@ -92,6 +92,13 @@ module TensorStream
|
|
92
92
|
_op(:random_standard_normal, shape, nil, options)
|
93
93
|
end
|
94
94
|
|
95
|
+
##
|
96
|
+
# Outputs random values from a truncated normal distribution.
|
97
|
+
def truncated_normal(shape, dtype: :float32, mean: 0.0, stddev: 1.0, seed: nil, name: nil)
|
98
|
+
options = { dtype: dtype, mean: mean, stddev: stddev, seed: seed, name: name }
|
99
|
+
_op(:truncated_normal, shape, nil, options)
|
100
|
+
end
|
101
|
+
|
95
102
|
##
|
96
103
|
# Stops gradient computation.
|
97
104
|
#
|
@@ -114,7 +121,7 @@ module TensorStream
|
|
114
121
|
# This operation returns a 1-D integer tensor representing the shape of input
|
115
122
|
def shape(input, name: nil, out_type: :int32)
|
116
123
|
return constant(shape_eval(input, out_type), dtype: out_type, name: "Shape/#{name}") if input.is_a?(Array) && !input[0].is_a?(Tensor)
|
117
|
-
return constant(input.shape.shape, dtype: out_type, name: "Shape/#{input.name}") if shape_full_specified(input)
|
124
|
+
return constant(input.shape.shape, dtype: out_type, name: "Shape/#{input.name}_c") if shape_full_specified(input)
|
118
125
|
|
119
126
|
_op(:shape, input, name: name, out_type: out_type)
|
120
127
|
end
|
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.9.
|
4
|
+
version: 0.9.8
|
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: 2018-11-
|
11
|
+
date: 2018-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -248,6 +248,11 @@ files:
|
|
248
248
|
- benchmark_ryzen_amd.txt
|
249
249
|
- bin/console
|
250
250
|
- bin/setup
|
251
|
+
- data_1.json
|
252
|
+
- data_2.json
|
253
|
+
- data_actual.json
|
254
|
+
- data_expected.json
|
255
|
+
- data_input.json
|
251
256
|
- lib/tensor_stream.rb
|
252
257
|
- lib/tensor_stream/control_flow.rb
|
253
258
|
- lib/tensor_stream/debugging/debugging.rb
|