tensor_stream 0.8.1 → 0.8.5
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/.gitignore +1 -0
- data/CHANGELOG.md +8 -0
- data/README.md +12 -6
- data/lib/tensor_stream.rb +1 -0
- data/lib/tensor_stream/evaluator/base_evaluator.rb +1 -1
- data/lib/tensor_stream/evaluator/ruby/array_ops.rb +282 -0
- data/lib/tensor_stream/evaluator/ruby/images_ops.rb +61 -0
- data/lib/tensor_stream/evaluator/ruby/math_ops.rb +111 -0
- data/lib/tensor_stream/evaluator/ruby/nn_ops.rb +48 -9
- data/lib/tensor_stream/evaluator/ruby/random_ops.rb +51 -0
- data/lib/tensor_stream/evaluator/ruby_evaluator.rb +20 -433
- data/lib/tensor_stream/images.rb +16 -0
- data/lib/tensor_stream/ops.rb +5 -1
- data/lib/tensor_stream/session.rb +15 -15
- data/lib/tensor_stream/tensor.rb +1 -1
- data/lib/tensor_stream/train/adadelta_optimizer.rb +52 -0
- data/lib/tensor_stream/train/adam_optimizer.rb +17 -2
- data/lib/tensor_stream/train/gradient_descent_optimizer.rb +7 -1
- data/lib/tensor_stream/trainer.rb +1 -0
- data/lib/tensor_stream/types.rb +4 -0
- data/lib/tensor_stream/utils.rb +4 -0
- data/lib/tensor_stream/variable_scope.rb +1 -0
- data/lib/tensor_stream/version.rb +1 -1
- data/samples/linear_regression.rb +4 -1
- data/samples/mnist_data.rb +64 -0
- data/samples/nearest_neighbor.rb +1 -2
- data/samples/raw_neural_net_sample.rb +1 -1
- data/tensor_stream.gemspec +1 -0
- metadata +23 -57
- data/lib/tensor_stream/evaluator/opencl/kernels/_bool_operand.cl +0 -45
- data/lib/tensor_stream/evaluator/opencl/kernels/_operand.cl +0 -45
- data/lib/tensor_stream/evaluator/opencl/kernels/abs.cl +0 -20
- data/lib/tensor_stream/evaluator/opencl/kernels/acos.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/add.cl +0 -3
- data/lib/tensor_stream/evaluator/opencl/kernels/apply_adam.cl +0 -23
- data/lib/tensor_stream/evaluator/opencl/kernels/apply_gradient.cl +0 -9
- data/lib/tensor_stream/evaluator/opencl/kernels/apply_momentum.cl +0 -16
- data/lib/tensor_stream/evaluator/opencl/kernels/argmax.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/argmin.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/asin.cl +0 -9
- data/lib/tensor_stream/evaluator/opencl/kernels/cast.cl +0 -10
- data/lib/tensor_stream/evaluator/opencl/kernels/ceil.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/cond.cl.erb +0 -6
- data/lib/tensor_stream/evaluator/opencl/kernels/cos.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/div.cl.erb +0 -3
- data/lib/tensor_stream/evaluator/opencl/kernels/exp.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/floor.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/floor_div.cl +0 -48
- data/lib/tensor_stream/evaluator/opencl/kernels/floor_mod.cl +0 -3
- data/lib/tensor_stream/evaluator/opencl/kernels/gemm.cl +0 -32
- data/lib/tensor_stream/evaluator/opencl/kernels/log.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/log1p.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/log_softmax.cl +0 -26
- data/lib/tensor_stream/evaluator/opencl/kernels/max.cl +0 -46
- data/lib/tensor_stream/evaluator/opencl/kernels/min.cl +0 -46
- data/lib/tensor_stream/evaluator/opencl/kernels/mod.cl +0 -3
- data/lib/tensor_stream/evaluator/opencl/kernels/mul.cl +0 -3
- data/lib/tensor_stream/evaluator/opencl/kernels/negate.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/pack.cl +0 -24
- data/lib/tensor_stream/evaluator/opencl/kernels/pow.cl +0 -46
- data/lib/tensor_stream/evaluator/opencl/kernels/real_div.cl +0 -3
- data/lib/tensor_stream/evaluator/opencl/kernels/reciprocal.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/round.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/sigmoid.cl +0 -9
- data/lib/tensor_stream/evaluator/opencl/kernels/sigmoid_grad.cl +0 -55
- data/lib/tensor_stream/evaluator/opencl/kernels/sign.cl +0 -21
- data/lib/tensor_stream/evaluator/opencl/kernels/sin.cl +0 -9
- data/lib/tensor_stream/evaluator/opencl/kernels/softmax.cl +0 -26
- data/lib/tensor_stream/evaluator/opencl/kernels/softmax_cross.cl +0 -32
- data/lib/tensor_stream/evaluator/opencl/kernels/softmax_cross_grad.cl +0 -28
- data/lib/tensor_stream/evaluator/opencl/kernels/softmax_grad.cl +0 -46
- data/lib/tensor_stream/evaluator/opencl/kernels/sqrt.cl +0 -9
- data/lib/tensor_stream/evaluator/opencl/kernels/square.cl +0 -9
- data/lib/tensor_stream/evaluator/opencl/kernels/squared_difference.cl +0 -53
- data/lib/tensor_stream/evaluator/opencl/kernels/sub.cl +0 -3
- data/lib/tensor_stream/evaluator/opencl/kernels/tan.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/tanh.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/kernels/tanh_grad.cl +0 -7
- data/lib/tensor_stream/evaluator/opencl/kernels/where.cl +0 -8
- data/lib/tensor_stream/evaluator/opencl/opencl_buffer.rb +0 -35
- data/lib/tensor_stream/evaluator/opencl/opencl_device.rb +0 -5
- data/lib/tensor_stream/evaluator/opencl/opencl_evaluator.rb +0 -1230
- data/lib/tensor_stream/evaluator/opencl/opencl_template_helper.rb +0 -95
@@ -15,16 +15,28 @@ module TensorStream
|
|
15
15
|
target_var, momentum_var, learning_rate, grad, momentum = inputs
|
16
16
|
assign = tensor.inputs[0] || tensor
|
17
17
|
assign_acc = tensor.inputs[1]
|
18
|
-
assign_acc.value =
|
18
|
+
assign_acc.value = multi_array_op(->(t, u) { t * momentum + u }, momentum_var, grad )
|
19
19
|
if tensor.options[:use_nesterov]
|
20
|
-
|
21
|
-
assign.value = process_vector_math_op(tensor,target_var, delta, context, ->(t, u) { t - u })
|
20
|
+
assign.value = multi_array_op(->(v, g, acc) { v - (g * learning_rate + acc * momentum * learning_rate) } , target_var, grad, momentum_var)
|
22
21
|
else
|
23
|
-
assign.value =
|
22
|
+
assign.value = multi_array_op(->(v, acc) { v - acc * learning_rate }, target_var, momentum_var)
|
24
23
|
end
|
25
24
|
assign.value
|
26
25
|
end
|
27
26
|
|
27
|
+
register_op :apply_adadelta do |context, tensor, inputs|
|
28
|
+
target_var, accum, accum_update, lr, rho, epsilon, grad = inputs
|
29
|
+
assign = tensor.inputs[0] || tensor
|
30
|
+
assign_acc = tensor.inputs[1]
|
31
|
+
assign_acc_update = tensor.inputs[2]
|
32
|
+
assign_acc.value = multi_array_op(->(acc_t, grad_t) { acc_t * rho + (grad_t * grad_t) * (1.0 - rho ) }, accum, grad)
|
33
|
+
update = multi_array_op(->(acc_update_t, acc_t, grad_t) { Math.sqrt(acc_update_t + epsilon) * (1.0 / Math.sqrt(acc_t + epsilon)) * grad_t }, accum_update, assign_acc.value, grad)
|
34
|
+
assign.value = multi_array_op(->(v, u) { v - (u * lr) }, target_var, update)
|
35
|
+
assign_acc_update.value = multi_array_op(->(acc_update_t, u) { acc_update_t * rho + (u * u) * (1.0 - rho) }, accum_update, update)
|
36
|
+
|
37
|
+
assign.value
|
38
|
+
end
|
39
|
+
|
28
40
|
register_op :apply_adam do |context, tensor, inputs|
|
29
41
|
target_var, m, v, beta1_power, beta2_power, lr_t, beta1_t, beta2_t, epsilon_t, grad = inputs
|
30
42
|
alpha = lr_t * Math.sqrt( 1.0 - beta2_power) / (1.0 - beta1_power)
|
@@ -32,11 +44,9 @@ module TensorStream
|
|
32
44
|
assign_m = tensor.inputs[1]
|
33
45
|
assign_v = tensor.inputs[2]
|
34
46
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
v_delta = process_vector_math_op(tensor, assign_m.value, assign_v.value, context, ->(m_d , v_d) { (m_d * alpha) / (Math.sqrt(v_d) + epsilon_t) })
|
39
|
-
assign.value = process_vector_math_op(tensor, target_var, v_delta, context, ->(var_d , delta_d) { var_d - delta_d })
|
47
|
+
assign_m.value = multi_array_op(->(u_d , g) { u_d + (g - u_d) * (1.0 - beta1_t) }, m, grad)
|
48
|
+
assign_v.value = multi_array_op(->(u_d , v_d) { u_d + (v_d ** 2 - u_d) * (1.0 - beta2_t)}, v, grad)
|
49
|
+
assign.value = multi_array_op( ->(t, m_d , v_d) { t - ((m_d * alpha) / (Math.sqrt(v_d) + epsilon_t)) }, target_var, assign_m.value, assign_v.value)
|
40
50
|
assign.value
|
41
51
|
end
|
42
52
|
|
@@ -93,6 +103,35 @@ module TensorStream
|
|
93
103
|
TensorShape.reshape(arr.flatten, input_shape)
|
94
104
|
end
|
95
105
|
end
|
106
|
+
|
107
|
+
register_op :softmax_grad do |_context, _tensor, inputs|
|
108
|
+
input, grad = inputs
|
109
|
+
softmax_input = softmax(input)
|
110
|
+
input_shape = shape_eval(input)
|
111
|
+
|
112
|
+
last_dimen_list = last_axis(softmax_input)
|
113
|
+
last_grad_list = last_axis(grad)
|
114
|
+
|
115
|
+
func = lambda { |list, last_grad|
|
116
|
+
f_grad = softmax_grad(list)
|
117
|
+
f_grad.transpose.each.collect do |row|
|
118
|
+
sum = 0.0
|
119
|
+
row.each_with_index do |r, g_index|
|
120
|
+
sum += r * last_grad[g_index]
|
121
|
+
end
|
122
|
+
sum
|
123
|
+
end
|
124
|
+
}
|
125
|
+
|
126
|
+
if input_shape.size == 1
|
127
|
+
func.call(last_dimen_list, last_grad_list)
|
128
|
+
else
|
129
|
+
arr = last_dimen_list.zip(last_grad_list).collect do |list, last_grad|
|
130
|
+
func.call(list, last_grad)
|
131
|
+
end
|
132
|
+
TensorShape.reshape(arr.flatten, input_shape)
|
133
|
+
end
|
134
|
+
end
|
96
135
|
end
|
97
136
|
end
|
98
137
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module TensorStream
|
2
|
+
## Collection of machine learning related ops
|
3
|
+
module RandomOps
|
4
|
+
def RandomOps.included(klass)
|
5
|
+
klass.class_eval do
|
6
|
+
register_op :glorot_uniform, no_eval: true do |_context, tensor, _inputs|
|
7
|
+
seed = tensor.options[:seed]
|
8
|
+
random = _get_randomizer(tensor, seed)
|
9
|
+
|
10
|
+
shape = tensor.options[:shape] || tensor.shape.shape
|
11
|
+
fan_in, fan_out = if shape.size.zero?
|
12
|
+
[1, 1]
|
13
|
+
elsif shape.size == 1
|
14
|
+
[1, shape[0]]
|
15
|
+
else
|
16
|
+
[shape[0], shape.last]
|
17
|
+
end
|
18
|
+
|
19
|
+
limit = Math.sqrt(6.0 / (fan_in + fan_out))
|
20
|
+
|
21
|
+
minval = -limit
|
22
|
+
maxval = limit
|
23
|
+
|
24
|
+
generator = -> { random.rand * (maxval - minval) + minval }
|
25
|
+
generate_vector(shape, generator: generator)
|
26
|
+
end
|
27
|
+
|
28
|
+
register_op :random_uniform, no_eval: true do |_context, tensor, _inputs|
|
29
|
+
maxval = tensor.options.fetch(:maxval, 1)
|
30
|
+
minval = tensor.options.fetch(:minval, 0)
|
31
|
+
seed = tensor.options[:seed]
|
32
|
+
|
33
|
+
random = _get_randomizer(tensor, seed)
|
34
|
+
generator = -> { random.rand * (maxval - minval) + minval }
|
35
|
+
shape = tensor.options[:shape] || tensor.shape.shape
|
36
|
+
generate_vector(shape, generator: generator)
|
37
|
+
end
|
38
|
+
|
39
|
+
register_op :random_standard_normal, no_eval: true do |_context, tensor, _inputs|
|
40
|
+
seed = tensor.options[:seed]
|
41
|
+
random = _get_randomizer(tensor, seed)
|
42
|
+
r = RandomGaussian.new(tensor.options.fetch(:mean), tensor.options.fetch(:stddev), -> { random.rand })
|
43
|
+
random = _get_randomizer(tensor, seed)
|
44
|
+
generator = -> { r.rand }
|
45
|
+
shape = tensor.options[:shape] || tensor.shape.shape
|
46
|
+
generate_vector(shape, generator: generator)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -4,6 +4,9 @@ require 'tensor_stream/evaluator/operation_helpers/math_helper'
|
|
4
4
|
require 'tensor_stream/evaluator/base_evaluator'
|
5
5
|
require 'tensor_stream/evaluator/ruby/math_ops'
|
6
6
|
require 'tensor_stream/evaluator/ruby/nn_ops'
|
7
|
+
require 'tensor_stream/evaluator/ruby/array_ops'
|
8
|
+
require 'tensor_stream/evaluator/ruby/random_ops'
|
9
|
+
require 'tensor_stream/evaluator/ruby/images_ops'
|
7
10
|
|
8
11
|
module TensorStream
|
9
12
|
module Evaluator
|
@@ -33,6 +36,9 @@ module TensorStream
|
|
33
36
|
include TensorStream::MathHelper
|
34
37
|
include TensorStream::MathOps
|
35
38
|
include TensorStream::NNOps
|
39
|
+
include TensorStream::ArrayOps
|
40
|
+
include TensorStream::RandomOps
|
41
|
+
include TensorStream::ImagesOps
|
36
42
|
|
37
43
|
def run(tensor, execution_context)
|
38
44
|
return tensor.map { |t| run(t, execution_context) } if tensor.is_a?(Array) && !tensor.empty? && tensor[0].is_a?(Tensor)
|
@@ -109,20 +115,6 @@ module TensorStream
|
|
109
115
|
inputs[0]
|
110
116
|
end
|
111
117
|
|
112
|
-
register_op(%i[argmax arg_max]) do |_context, tensor, inputs|
|
113
|
-
axis = tensor.options[:axis] || 0
|
114
|
-
rank = get_rank(inputs[0])
|
115
|
-
raise TensorStream::InvalidArgumentError, "Expected dimension in the range [#{-rank},#{rank}) but got #{axis}" if axis < -rank || axis >= rank
|
116
|
-
get_op_with_axis(inputs[0], axis, 0, tensor.data_type)
|
117
|
-
end
|
118
|
-
|
119
|
-
register_op(%i[argmin arg_min]) do |_context, tensor, inputs|
|
120
|
-
axis = tensor.options[:axis] || 0
|
121
|
-
rank = get_rank(inputs[0])
|
122
|
-
raise TensorStream::InvalidArgumentError, "Expected dimension in the range [#{-rank},#{rank}) but got #{axis}" if axis < -rank || axis >= rank
|
123
|
-
get_op_with_axis(inputs[0], axis, 0, tensor.data_type, ->(a, b) { a < b })
|
124
|
-
end
|
125
|
-
|
126
118
|
register_op(:cast) do |context, tensor, inputs|
|
127
119
|
call_op(:cast, inputs[0], context, ->(t, _b) { Tensor.cast_dtype(t, tensor.data_type) })
|
128
120
|
end
|
@@ -155,24 +147,6 @@ module TensorStream
|
|
155
147
|
call_vector_op(tensor, :not_equal, inputs[0], inputs[1], context, ->(t, u) { t != u })
|
156
148
|
end
|
157
149
|
|
158
|
-
register_op :index, no_eval: true do |_context, _tensor, inputs|
|
159
|
-
f = inputs[0]
|
160
|
-
index = inputs[1]
|
161
|
-
if f.is_a?(OutputGroup)
|
162
|
-
f.outputs[index]
|
163
|
-
else
|
164
|
-
f[index]
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
register_op :slice do |context, tensor, inputs|
|
169
|
-
input = inputs[0]
|
170
|
-
start = inputs[1]
|
171
|
-
size = complete_eval(tensor.options[:size], context)
|
172
|
-
raise "start index and size not of the same shape #{start.size} != #{size.size}" if start.size != size.size
|
173
|
-
slice_tensor(input, start, size)
|
174
|
-
end
|
175
|
-
|
176
150
|
def merge_dynamic_stitch(merged, indexes, data)
|
177
151
|
indexes.each_with_index do |ind, m|
|
178
152
|
if ind.is_a?(Array)
|
@@ -183,126 +157,10 @@ module TensorStream
|
|
183
157
|
end
|
184
158
|
end
|
185
159
|
|
186
|
-
register_op %i[flow_dynamic_stitch dynamic_stitch] do |_context, _tensor, inputs|
|
187
|
-
indexes, data = inputs
|
188
|
-
merged = []
|
189
|
-
merge_dynamic_stitch(merged, indexes, data)
|
190
|
-
merged
|
191
|
-
end
|
192
|
-
|
193
|
-
register_op :gather do |_context, _tensor, inputs|
|
194
|
-
params, indexes = inputs
|
195
|
-
gather(params, indexes)
|
196
|
-
end
|
197
|
-
|
198
|
-
register_op :setdiff1d do |_context, tensor, inputs|
|
199
|
-
input, remove = inputs
|
200
|
-
idx = []
|
201
|
-
out = []
|
202
|
-
input.each_with_index do |x, index|
|
203
|
-
next if remove.include?(x)
|
204
|
-
out << x
|
205
|
-
idx << index
|
206
|
-
end
|
207
|
-
idx = idx.map { |i| Tensor.cast_dtype(i, tensor.options[:index_dtype]) } unless tensor.options[:index_dtype] == :int32
|
208
|
-
OutputGroup.new([out, idx], tensor.inputs.map(&:data_type))
|
209
|
-
end
|
210
|
-
|
211
|
-
register_op :cumprod do |context, tensor, inputs|
|
212
|
-
x = inputs[0]
|
213
|
-
c = fp_type?(tensor.data_type) ? 1.0 : 1
|
214
|
-
reverse_option = tensor.options[:reverse]
|
215
|
-
exclusive = tensor.options[:exclusive]
|
216
|
-
|
217
|
-
func = lambda do |arr|
|
218
|
-
return c if arr.nil?
|
219
|
-
count = arr.size
|
220
|
-
|
221
|
-
|
222
|
-
arr = arr.reverse if reverse_option
|
223
|
-
arr = [1] + arr if exclusive
|
224
|
-
|
225
|
-
start_prod = arr[0]
|
226
|
-
mapped = arr[1...count].map do |v|
|
227
|
-
start_prod = vector_op(start_prod, v, ->(a, b) { a * b })
|
228
|
-
end
|
229
|
-
|
230
|
-
arr = [arr[0]] + mapped
|
231
|
-
reverse_option ? arr.reverse : arr
|
232
|
-
end
|
233
|
-
reduction(context, tensor, func)
|
234
|
-
end
|
235
|
-
|
236
|
-
register_op :invert_permutation do |_context, _tensor, inputs|
|
237
|
-
input = inputs[0]
|
238
|
-
output = input.dup
|
239
|
-
input.size.times.each do |index|
|
240
|
-
output[input[index]] = index
|
241
|
-
end unless input.nil?
|
242
|
-
output
|
243
|
-
end
|
244
|
-
|
245
|
-
register_op :size do |_context, tensor, inputs|
|
246
|
-
input = inputs[0]
|
247
|
-
Tensor.cast_dtype(input.flatten.size, tensor.options[:out_type])
|
248
|
-
end
|
249
|
-
|
250
|
-
register_op %i[concat concat_v2] do |_context, tensor, inputs|
|
251
|
-
concat_array(inputs, tensor.options[:axis])
|
252
|
-
end
|
253
|
-
|
254
160
|
register_op :stop_gradient, no_eval: true do |_context, _tensor, inputs|
|
255
161
|
inputs[0]
|
256
162
|
end
|
257
163
|
|
258
|
-
register_op :sigmoid_grad, no_eval: true do |context, tensor, inputs|
|
259
|
-
a, b = inputs
|
260
|
-
call_vector_op(tensor, :sigmoid_grad, a, b, context, ->(t, u) { u * sigmoid(t) * (1 - sigmoid(t)) })
|
261
|
-
end
|
262
|
-
|
263
|
-
register_op :random_uniform, no_eval: true do |_context, tensor, _inputs|
|
264
|
-
maxval = tensor.options.fetch(:maxval, 1)
|
265
|
-
minval = tensor.options.fetch(:minval, 0)
|
266
|
-
seed = tensor.options[:seed]
|
267
|
-
|
268
|
-
random = _get_randomizer(tensor, seed)
|
269
|
-
generator = -> { random.rand * (maxval - minval) + minval }
|
270
|
-
shape = tensor.options[:shape] || tensor.shape.shape
|
271
|
-
generate_vector(shape, generator: generator)
|
272
|
-
end
|
273
|
-
|
274
|
-
register_op :random_standard_normal, no_eval: true do |_context, tensor, _inputs|
|
275
|
-
seed = tensor.options[:seed]
|
276
|
-
random = _get_randomizer(tensor, seed)
|
277
|
-
r = RandomGaussian.new(tensor.options.fetch(:mean), tensor.options.fetch(:stddev), -> { random.rand })
|
278
|
-
random = _get_randomizer(tensor, seed)
|
279
|
-
generator = -> { r.rand }
|
280
|
-
shape = tensor.options[:shape] || tensor.shape.shape
|
281
|
-
generate_vector(shape, generator: generator)
|
282
|
-
end
|
283
|
-
|
284
|
-
register_op :glorot_uniform, no_eval: true do |_context, tensor, _inputs|
|
285
|
-
seed = tensor.options[:seed]
|
286
|
-
random = _get_randomizer(tensor, seed)
|
287
|
-
|
288
|
-
shape = tensor.options[:shape] || tensor.shape.shape
|
289
|
-
fan_in, fan_out = if shape.size.zero?
|
290
|
-
[1, 1]
|
291
|
-
elsif shape.size == 1
|
292
|
-
[1, shape[0]]
|
293
|
-
else
|
294
|
-
[shape[0], shape.last]
|
295
|
-
end
|
296
|
-
|
297
|
-
limit = Math.sqrt(6.0 / (fan_in + fan_out))
|
298
|
-
|
299
|
-
minval = -limit
|
300
|
-
maxval = limit
|
301
|
-
|
302
|
-
generator = -> { random.rand * (maxval - minval) + minval }
|
303
|
-
generate_vector(shape, generator: generator)
|
304
|
-
end
|
305
|
-
|
306
164
|
register_op :assign, noop: true do |context, tensor, _inputs|
|
307
165
|
assign = tensor.inputs[0] || tensor
|
308
166
|
assign.value = global_eval(tensor, tensor.inputs[1], context)
|
@@ -323,116 +181,7 @@ module TensorStream
|
|
323
181
|
tensor.inputs[0].value
|
324
182
|
end
|
325
183
|
|
326
|
-
register_op :
|
327
|
-
axis = tensor.options[:axis] || 0
|
328
|
-
shape = shape_eval(inputs[0])
|
329
|
-
rank = shape.size + 1
|
330
|
-
elem_size = shape.empty? ? 1 : shape.reduce(:*)
|
331
|
-
output_buffer = Array.new(inputs.size * elem_size) { 0 }
|
332
|
-
new_shape = [inputs.size]
|
333
|
-
shape.inject(new_shape) { |ns, s| ns << s }
|
334
|
-
|
335
|
-
divisors = new_shape.dup.drop(1).reverse.inject([1]) do |a, s|
|
336
|
-
a << s * a.last
|
337
|
-
end.reverse
|
338
|
-
|
339
|
-
axis = rank + axis if axis < 0
|
340
|
-
rotated_shape = Array.new(axis + 1) { new_shape.shift }
|
341
|
-
new_shape = rotated_shape.rotate! + new_shape
|
342
|
-
|
343
|
-
multipliers = new_shape.dup.drop(1).reverse.inject([1]) do |a, s|
|
344
|
-
a << s * a.last
|
345
|
-
end.reverse
|
346
|
-
|
347
|
-
inputs.each_with_index do |input, index|
|
348
|
-
raw_input = input.is_a?(Array) ? input.flatten : [input]
|
349
|
-
start = index * divisors.first
|
350
|
-
|
351
|
-
raw_input.each_with_index do |x, index2|
|
352
|
-
index_map = []
|
353
|
-
ptr = start + index2
|
354
|
-
divisors.each_with_object(index_map) do |div, a|
|
355
|
-
a << (ptr / div.to_f).floor
|
356
|
-
ptr = ptr % div
|
357
|
-
end
|
358
|
-
|
359
|
-
rotated_index = Array.new(axis + 1) { index_map.shift }
|
360
|
-
index_map = rotated_index.rotate! + index_map
|
361
|
-
|
362
|
-
ptr2 = 0
|
363
|
-
multipliers.each_with_index do |m, idx|
|
364
|
-
ptr2 += index_map[idx] * m
|
365
|
-
end
|
366
|
-
|
367
|
-
output_buffer[ptr2] = x
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
TensorShape.reshape(output_buffer, new_shape)
|
372
|
-
end
|
373
|
-
|
374
|
-
register_op :mean, noop: true do |context, tensor, _inputs|
|
375
|
-
c = fp_type?(tensor.data_type) ? 0.0 : 0
|
376
|
-
func = lambda do |arr|
|
377
|
-
return c if arr.nil?
|
378
|
-
|
379
|
-
reduced_val = arr[0]
|
380
|
-
arr[1..arr.size].each do |v|
|
381
|
-
reduced_val = vector_op(reduced_val, v, ->(a, b) { a + b })
|
382
|
-
end
|
383
|
-
|
384
|
-
vector_op(reduced_val, nil, ->(a, _b) { a / arr.size })
|
385
|
-
end
|
386
|
-
|
387
|
-
reduction(context, tensor, func)
|
388
|
-
end
|
389
|
-
|
390
|
-
register_op :sum, noop: true do |context, tensor, _inputs|
|
391
|
-
func = lambda do |arr|
|
392
|
-
reduced_val = arr[0]
|
393
|
-
arr[1..arr.size].each do |v|
|
394
|
-
reduced_val = vector_op(reduced_val, v, ->(t, u) { t + u })
|
395
|
-
end
|
396
|
-
reduced_val
|
397
|
-
end
|
398
|
-
|
399
|
-
reduction(context, tensor, func)
|
400
|
-
end
|
401
|
-
|
402
|
-
register_op :prod, noop: true do |context, tensor, _inputs|
|
403
|
-
c = fp_type?(tensor.data_type) ? 1.0 : 1
|
404
|
-
func = lambda do |arr|
|
405
|
-
return c if arr.nil?
|
406
|
-
|
407
|
-
reduced_val = arr[0]
|
408
|
-
arr[1..arr.size].each do |v|
|
409
|
-
reduced_val = vector_op(reduced_val, v, ->(a, b) { a * b })
|
410
|
-
end
|
411
|
-
reduced_val
|
412
|
-
end
|
413
|
-
|
414
|
-
reduction(context, tensor, func)
|
415
|
-
end
|
416
|
-
|
417
|
-
register_op :range do |_context, _tensor, inputs|
|
418
|
-
start, limit, delta = inputs
|
419
|
-
raise " delta !=0 " if delta.zero?
|
420
|
-
raise " Requires start <= limit when delta > 0" if (start > limit) && delta > 0
|
421
|
-
raise " Requires start >= limit when delta < 0" if (start < limit) && delta < 0
|
422
|
-
|
423
|
-
cur_step = start
|
424
|
-
r = []
|
425
|
-
Kernel.loop do
|
426
|
-
break if start == limit
|
427
|
-
break if (start < limit) && (cur_step >= limit)
|
428
|
-
break if (start > limit) && (cur_step <= limit)
|
429
|
-
r << cur_step
|
430
|
-
cur_step += delta
|
431
|
-
end
|
432
|
-
r
|
433
|
-
end
|
434
|
-
|
435
|
-
register_op :transpose do |_context, tensor, inputs|
|
184
|
+
register_op :transpose do |_context, _tensor, inputs|
|
436
185
|
shape = shape_eval(inputs[0])
|
437
186
|
rank = get_rank(inputs[0])
|
438
187
|
perm = inputs[1] || (0...rank).to_a.reverse
|
@@ -448,47 +197,6 @@ module TensorStream
|
|
448
197
|
end
|
449
198
|
end
|
450
199
|
|
451
|
-
register_op :eye do |_context, tensor, inputs|
|
452
|
-
rows, columns = inputs
|
453
|
-
|
454
|
-
Array.new(rows) do |i|
|
455
|
-
Array.new(columns) do |col|
|
456
|
-
if fp_type?(tensor.data_type)
|
457
|
-
i == col ? 1.0 : 0.0
|
458
|
-
else
|
459
|
-
i == col ? 1 : 0
|
460
|
-
end
|
461
|
-
end
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
register_op :expand_dims do |_context, _tensor, inputs|
|
466
|
-
val, axis = inputs
|
467
|
-
axis = axis.nil? ? 0 : axis
|
468
|
-
|
469
|
-
shape = shape_eval(val)
|
470
|
-
axis = -axis if axis == shape.size
|
471
|
-
|
472
|
-
new_shape = shape.dup.insert(axis, 1).compact
|
473
|
-
|
474
|
-
TensorShape.reshape([val].flatten, new_shape)
|
475
|
-
end
|
476
|
-
|
477
|
-
register_op :cond, noop: true do |context, tensor, inputs|
|
478
|
-
pred = global_eval(tensor, tensor.options[:pred], context)
|
479
|
-
|
480
|
-
if all_true?(pred)
|
481
|
-
global_eval(tensor, inputs[0], context)
|
482
|
-
else
|
483
|
-
global_eval(tensor, inputs[1], context)
|
484
|
-
end
|
485
|
-
end
|
486
|
-
|
487
|
-
register_op %i[select where] do |context, tensor, inputs|
|
488
|
-
pred = complete_eval(tensor.options[:pred], context)
|
489
|
-
call_3way_vector_op(pred, inputs[0], inputs[1], context, ->(t, u, v) { t ? u : v })
|
490
|
-
end
|
491
|
-
|
492
200
|
register_op :less do |context, tensor, inputs|
|
493
201
|
a, b = inputs
|
494
202
|
call_vector_op(tensor, :less, a, b, context, ->(t, u) { t < u })
|
@@ -509,77 +217,14 @@ module TensorStream
|
|
509
217
|
call_vector_op(tensor, :greater_equal, a, b, context, ->(t, u) { t <= u })
|
510
218
|
end
|
511
219
|
|
512
|
-
register_op :fill do |_context, _tensor, inputs|
|
513
|
-
shape = inputs[0]
|
514
|
-
value = inputs[1]
|
515
|
-
|
516
|
-
func = -> { value }
|
517
|
-
|
518
|
-
if shape.is_a?(Array) && shape.size.zero?
|
519
|
-
func.call
|
520
|
-
else
|
521
|
-
shape = [shape.to_i] unless shape.is_a?(Array)
|
522
|
-
generate_vector(shape, generator: func)
|
523
|
-
end
|
524
|
-
end
|
525
|
-
|
526
|
-
register_op %i[zeros ones zeros_like ones_like] do |_context, tensor, inputs|
|
527
|
-
shape = if %i[zeros_like ones_like].include?(tensor.operation)
|
528
|
-
shape_eval(inputs[0])
|
529
|
-
else
|
530
|
-
inputs[0] || tensor.shape.shape
|
531
|
-
end
|
532
|
-
|
533
|
-
func = if %i[zeros zeros_like].include?(tensor.operation)
|
534
|
-
-> { int_type?(tensor.data_type) ? 0 : 0.0 }
|
535
|
-
else
|
536
|
-
-> { int_type?(tensor.data_type) ? 1 : 1.0 }
|
537
|
-
end
|
538
|
-
|
539
|
-
if shape.is_a?(Array) && shape.size.zero?
|
540
|
-
func.call
|
541
|
-
else
|
542
|
-
shape = [shape.to_i] unless shape.is_a?(Array)
|
543
|
-
|
544
|
-
cache_key = "#{tensor.operation}_#{shape}"
|
545
|
-
if @context[:_cache].key?(cache_key)
|
546
|
-
@context[:_cache][cache_key]
|
547
|
-
else
|
548
|
-
generate_vector(shape, generator: func).tap do |v|
|
549
|
-
@context[:_cache][cache_key] = v
|
550
|
-
end
|
551
|
-
end
|
552
|
-
end
|
553
|
-
end
|
554
|
-
|
555
220
|
register_op :shape do |_context, tensor, inputs|
|
556
221
|
shape_eval(inputs[0], tensor.options[:out_type])
|
557
222
|
end
|
558
223
|
|
559
|
-
register_op :mat_mul do |_context, tensor, inputs|
|
560
|
-
matrix_a, matrix_b = inputs
|
561
|
-
rank_a = get_rank(matrix_a)
|
562
|
-
rank_b = get_rank(matrix_b)
|
563
|
-
raise "#{tensor.inputs[0].name} rank must be greater than 1" if rank_a < 2
|
564
|
-
raise "#{tensor.inputs[1].name} rank must be greater than 1" if rank_b < 2
|
565
|
-
|
566
|
-
matrix_a = matrix_a.transpose if tensor.options[:transpose_a]
|
567
|
-
matrix_b = matrix_b.transpose if tensor.options[:transpose_b]
|
568
|
-
|
569
|
-
# check matrix dimensions
|
570
|
-
raise "incompatible shape sizes for matrix multiplication (#{matrix_a[0].size} != #{matrix_b.size}) #{shape_eval(matrix_a)} vs #{shape_eval(matrix_b)}" if matrix_a[0].size != matrix_b.size
|
571
|
-
|
572
|
-
(Matrix[*matrix_a] * Matrix[*matrix_b]).to_a
|
573
|
-
end
|
574
|
-
|
575
224
|
register_op :broadcast_transform do |_context, _tensor, inputs|
|
576
225
|
broadcast(inputs[0], inputs[1])
|
577
226
|
end
|
578
227
|
|
579
|
-
register_op :truncate do |_context, _tensor, inputs|
|
580
|
-
truncate(inputs[0], inputs[1])
|
581
|
-
end
|
582
|
-
|
583
228
|
register_op :identity do |_context, _tensor, inputs|
|
584
229
|
inputs[0]
|
585
230
|
end
|
@@ -589,57 +234,15 @@ module TensorStream
|
|
589
234
|
inputs[0]
|
590
235
|
end
|
591
236
|
|
592
|
-
register_op :rank do |_context, _tensor, inputs|
|
593
|
-
get_rank(inputs[0])
|
594
|
-
end
|
595
|
-
|
596
237
|
register_op %i[div real_div], noop: true do |context, tensor, inputs|
|
597
238
|
process_vector_math_op(tensor, inputs[0], inputs[1], context, ->(t, u) { t / u })
|
598
239
|
end
|
599
240
|
|
600
|
-
register_op :reshape do |_context, _tensor, inputs|
|
601
|
-
arr, new_shape = inputs
|
602
|
-
|
603
|
-
arr = [arr] unless arr.is_a?(Array)
|
604
|
-
|
605
|
-
flat_arr = arr.flatten
|
606
|
-
if new_shape.size.zero? && flat_arr.size == 1
|
607
|
-
flat_arr[0]
|
608
|
-
else
|
609
|
-
new_shape = TensorShape.fix_inferred_elements(new_shape, flat_arr.size)
|
610
|
-
TensorShape.reshape(flat_arr, new_shape)
|
611
|
-
end
|
612
|
-
end
|
613
|
-
|
614
|
-
register_op :pad do |context, tensor, inputs|
|
615
|
-
p = complete_eval(tensor.options[:paddings], context)
|
616
|
-
|
617
|
-
arr_pad(inputs[0], p, tensor.data_type)
|
618
|
-
end
|
619
|
-
|
620
|
-
register_op %i[max maximum], noop: true do |context, tensor, inputs|
|
621
|
-
call_vector_op(tensor, :max, inputs[0], inputs[1], context, ->(t, u) { [t, u].max })
|
622
|
-
end
|
623
|
-
|
624
|
-
register_op %i[min minimum], noop: true do |context, tensor, inputs|
|
625
|
-
call_vector_op(tensor, :min, inputs[0], inputs[1], context, ->(t, u) { [t, u].min })
|
626
|
-
end
|
627
|
-
|
628
241
|
register_op :broadcast_gradient_args do |_context, tensor, inputs|
|
629
242
|
rx, ry = get_broadcast_gradient_args(inputs[0], inputs[1])
|
630
243
|
OutputGroup.new([rx, ry], tensor.inputs.map(&:data_type))
|
631
244
|
end
|
632
245
|
|
633
|
-
register_op :tile do |_context, _tensor, inputs|
|
634
|
-
input, multiples = inputs
|
635
|
-
rank = get_rank(input)
|
636
|
-
raise '1D or higher tensor required' if rank.zero?
|
637
|
-
raise "invalid multiple size passed #{rank} != #{multiples.size}" if rank != multiples.size
|
638
|
-
|
639
|
-
tile = tile_arr(input, 0, multiples)
|
640
|
-
tile.nil? ? [] : tile
|
641
|
-
end
|
642
|
-
|
643
246
|
register_op :flow_group, noop: true do |context, tensor, inputs|
|
644
247
|
inputs.each { |input| global_eval(tensor, input, context) }
|
645
248
|
nil # no output
|
@@ -657,35 +260,6 @@ module TensorStream
|
|
657
260
|
# prefix, tensor_names, shape_and_slices = inputs[0..3]
|
658
261
|
end
|
659
262
|
|
660
|
-
register_op :softmax_grad do |_context, _tensor, inputs|
|
661
|
-
input, grad = inputs
|
662
|
-
softmax_input = softmax(input)
|
663
|
-
input_shape = shape_eval(input)
|
664
|
-
|
665
|
-
last_dimen_list = last_axis(softmax_input)
|
666
|
-
last_grad_list = last_axis(grad)
|
667
|
-
|
668
|
-
func = lambda { |list, last_grad|
|
669
|
-
f_grad = softmax_grad(list)
|
670
|
-
f_grad.transpose.each.collect do |row|
|
671
|
-
sum = 0.0
|
672
|
-
row.each_with_index do |r, g_index|
|
673
|
-
sum += r * last_grad[g_index]
|
674
|
-
end
|
675
|
-
sum
|
676
|
-
end
|
677
|
-
}
|
678
|
-
|
679
|
-
if input_shape.size == 1
|
680
|
-
func.call(last_dimen_list, last_grad_list)
|
681
|
-
else
|
682
|
-
arr = last_dimen_list.zip(last_grad_list).collect do |list, last_grad|
|
683
|
-
func.call(list, last_grad)
|
684
|
-
end
|
685
|
-
TensorShape.reshape(arr.flatten, input_shape)
|
686
|
-
end
|
687
|
-
end
|
688
|
-
|
689
263
|
register_op :check_numerics do |context, tensor, inputs|
|
690
264
|
message = tensor.options[:message]
|
691
265
|
f = lambda { |t, _b|
|
@@ -868,6 +442,19 @@ module TensorStream
|
|
868
442
|
# end
|
869
443
|
end
|
870
444
|
|
445
|
+
# multi array ops on ruby arrays with same sizes
|
446
|
+
def multi_array_op(func, *args)
|
447
|
+
elem = args[0]
|
448
|
+
if (elem.is_a?(Array))
|
449
|
+
elem.each_with_index.collect do |item, index|
|
450
|
+
indexed_args = args.collect { |a| a[index] }
|
451
|
+
multi_array_op(func, *indexed_args)
|
452
|
+
end
|
453
|
+
else
|
454
|
+
func.call(*args)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
871
458
|
def _rank_from_shape(shape)
|
872
459
|
shape.is_a?(Array) ? shape.size : 0
|
873
460
|
end
|