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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +12 -6
  5. data/lib/tensor_stream.rb +1 -0
  6. data/lib/tensor_stream/evaluator/base_evaluator.rb +1 -1
  7. data/lib/tensor_stream/evaluator/ruby/array_ops.rb +282 -0
  8. data/lib/tensor_stream/evaluator/ruby/images_ops.rb +61 -0
  9. data/lib/tensor_stream/evaluator/ruby/math_ops.rb +111 -0
  10. data/lib/tensor_stream/evaluator/ruby/nn_ops.rb +48 -9
  11. data/lib/tensor_stream/evaluator/ruby/random_ops.rb +51 -0
  12. data/lib/tensor_stream/evaluator/ruby_evaluator.rb +20 -433
  13. data/lib/tensor_stream/images.rb +16 -0
  14. data/lib/tensor_stream/ops.rb +5 -1
  15. data/lib/tensor_stream/session.rb +15 -15
  16. data/lib/tensor_stream/tensor.rb +1 -1
  17. data/lib/tensor_stream/train/adadelta_optimizer.rb +52 -0
  18. data/lib/tensor_stream/train/adam_optimizer.rb +17 -2
  19. data/lib/tensor_stream/train/gradient_descent_optimizer.rb +7 -1
  20. data/lib/tensor_stream/trainer.rb +1 -0
  21. data/lib/tensor_stream/types.rb +4 -0
  22. data/lib/tensor_stream/utils.rb +4 -0
  23. data/lib/tensor_stream/variable_scope.rb +1 -0
  24. data/lib/tensor_stream/version.rb +1 -1
  25. data/samples/linear_regression.rb +4 -1
  26. data/samples/mnist_data.rb +64 -0
  27. data/samples/nearest_neighbor.rb +1 -2
  28. data/samples/raw_neural_net_sample.rb +1 -1
  29. data/tensor_stream.gemspec +1 -0
  30. metadata +23 -57
  31. data/lib/tensor_stream/evaluator/opencl/kernels/_bool_operand.cl +0 -45
  32. data/lib/tensor_stream/evaluator/opencl/kernels/_operand.cl +0 -45
  33. data/lib/tensor_stream/evaluator/opencl/kernels/abs.cl +0 -20
  34. data/lib/tensor_stream/evaluator/opencl/kernels/acos.cl +0 -8
  35. data/lib/tensor_stream/evaluator/opencl/kernels/add.cl +0 -3
  36. data/lib/tensor_stream/evaluator/opencl/kernels/apply_adam.cl +0 -23
  37. data/lib/tensor_stream/evaluator/opencl/kernels/apply_gradient.cl +0 -9
  38. data/lib/tensor_stream/evaluator/opencl/kernels/apply_momentum.cl +0 -16
  39. data/lib/tensor_stream/evaluator/opencl/kernels/argmax.cl +0 -8
  40. data/lib/tensor_stream/evaluator/opencl/kernels/argmin.cl +0 -8
  41. data/lib/tensor_stream/evaluator/opencl/kernels/asin.cl +0 -9
  42. data/lib/tensor_stream/evaluator/opencl/kernels/cast.cl +0 -10
  43. data/lib/tensor_stream/evaluator/opencl/kernels/ceil.cl +0 -8
  44. data/lib/tensor_stream/evaluator/opencl/kernels/cond.cl.erb +0 -6
  45. data/lib/tensor_stream/evaluator/opencl/kernels/cos.cl +0 -8
  46. data/lib/tensor_stream/evaluator/opencl/kernels/div.cl.erb +0 -3
  47. data/lib/tensor_stream/evaluator/opencl/kernels/exp.cl +0 -8
  48. data/lib/tensor_stream/evaluator/opencl/kernels/floor.cl +0 -8
  49. data/lib/tensor_stream/evaluator/opencl/kernels/floor_div.cl +0 -48
  50. data/lib/tensor_stream/evaluator/opencl/kernels/floor_mod.cl +0 -3
  51. data/lib/tensor_stream/evaluator/opencl/kernels/gemm.cl +0 -32
  52. data/lib/tensor_stream/evaluator/opencl/kernels/log.cl +0 -8
  53. data/lib/tensor_stream/evaluator/opencl/kernels/log1p.cl +0 -8
  54. data/lib/tensor_stream/evaluator/opencl/kernels/log_softmax.cl +0 -26
  55. data/lib/tensor_stream/evaluator/opencl/kernels/max.cl +0 -46
  56. data/lib/tensor_stream/evaluator/opencl/kernels/min.cl +0 -46
  57. data/lib/tensor_stream/evaluator/opencl/kernels/mod.cl +0 -3
  58. data/lib/tensor_stream/evaluator/opencl/kernels/mul.cl +0 -3
  59. data/lib/tensor_stream/evaluator/opencl/kernels/negate.cl +0 -8
  60. data/lib/tensor_stream/evaluator/opencl/kernels/pack.cl +0 -24
  61. data/lib/tensor_stream/evaluator/opencl/kernels/pow.cl +0 -46
  62. data/lib/tensor_stream/evaluator/opencl/kernels/real_div.cl +0 -3
  63. data/lib/tensor_stream/evaluator/opencl/kernels/reciprocal.cl +0 -8
  64. data/lib/tensor_stream/evaluator/opencl/kernels/round.cl +0 -8
  65. data/lib/tensor_stream/evaluator/opencl/kernels/sigmoid.cl +0 -9
  66. data/lib/tensor_stream/evaluator/opencl/kernels/sigmoid_grad.cl +0 -55
  67. data/lib/tensor_stream/evaluator/opencl/kernels/sign.cl +0 -21
  68. data/lib/tensor_stream/evaluator/opencl/kernels/sin.cl +0 -9
  69. data/lib/tensor_stream/evaluator/opencl/kernels/softmax.cl +0 -26
  70. data/lib/tensor_stream/evaluator/opencl/kernels/softmax_cross.cl +0 -32
  71. data/lib/tensor_stream/evaluator/opencl/kernels/softmax_cross_grad.cl +0 -28
  72. data/lib/tensor_stream/evaluator/opencl/kernels/softmax_grad.cl +0 -46
  73. data/lib/tensor_stream/evaluator/opencl/kernels/sqrt.cl +0 -9
  74. data/lib/tensor_stream/evaluator/opencl/kernels/square.cl +0 -9
  75. data/lib/tensor_stream/evaluator/opencl/kernels/squared_difference.cl +0 -53
  76. data/lib/tensor_stream/evaluator/opencl/kernels/sub.cl +0 -3
  77. data/lib/tensor_stream/evaluator/opencl/kernels/tan.cl +0 -8
  78. data/lib/tensor_stream/evaluator/opencl/kernels/tanh.cl +0 -8
  79. data/lib/tensor_stream/evaluator/opencl/kernels/tanh_grad.cl +0 -7
  80. data/lib/tensor_stream/evaluator/opencl/kernels/where.cl +0 -8
  81. data/lib/tensor_stream/evaluator/opencl/opencl_buffer.rb +0 -35
  82. data/lib/tensor_stream/evaluator/opencl/opencl_device.rb +0 -5
  83. data/lib/tensor_stream/evaluator/opencl/opencl_evaluator.rb +0 -1230
  84. 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 = process_vector_math_op(tensor, momentum_var, grad, context, ->(t, u) { t * momentum + u })
18
+ assign_acc.value = multi_array_op(->(t, u) { t * momentum + u }, momentum_var, grad )
19
19
  if tensor.options[:use_nesterov]
20
- delta = process_vector_math_op(tensor, grad, momentum_var, context, ->(g, acc) { g * learning_rate + acc * momentum * learning_rate })
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 = process_vector_math_op(tensor, target_var, momentum_var, context, ->(v, acc) { v - acc * learning_rate })
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
- m_delta = process_vector_math_op(tensor, grad, m, context, ->(g, m_d) { (g - m_d) * (1.0 - beta1_t) })
36
- assign_m.value = process_vector_math_op(tensor, m, m_delta, context, ->(u_d , v_d) { u_d + v_d })
37
- assign_v.value = process_vector_math_op(tensor, v, grad, context, ->(u_d , v_d) { u_d + (v_d ** 2 - u_d) * (1.0 - beta2_t)})
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 :stack do |_context, tensor, inputs|
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