tensor_stream 0.8.1 → 0.8.5

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