tensor_stream 0.6.1 → 0.7.0

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +40 -1
  5. data/benchmark/benchmark.rb +4 -1
  6. data/lib/tensor_stream.rb +5 -0
  7. data/lib/tensor_stream/debugging/debugging.rb +4 -2
  8. data/lib/tensor_stream/device.rb +2 -1
  9. data/lib/tensor_stream/evaluator/base_evaluator.rb +43 -32
  10. data/lib/tensor_stream/evaluator/evaluator.rb +0 -1
  11. data/lib/tensor_stream/evaluator/opencl/kernels/acos.cl +8 -0
  12. data/lib/tensor_stream/evaluator/opencl/kernels/apply_gradient.cl +9 -0
  13. data/lib/tensor_stream/evaluator/opencl/kernels/asin.cl +9 -0
  14. data/lib/tensor_stream/evaluator/opencl/kernels/floor_mod.cl +3 -0
  15. data/lib/tensor_stream/evaluator/opencl/kernels/log_softmax.cl +26 -0
  16. data/lib/tensor_stream/evaluator/opencl/kernels/max.cl +5 -5
  17. data/lib/tensor_stream/evaluator/opencl/kernels/min.cl +46 -0
  18. data/lib/tensor_stream/evaluator/opencl/kernels/real_div.cl +3 -0
  19. data/lib/tensor_stream/evaluator/opencl/kernels/softmax_cross.cl +27 -0
  20. data/lib/tensor_stream/evaluator/opencl/kernels/softmax_cross_grad.cl +28 -0
  21. data/lib/tensor_stream/evaluator/opencl/opencl_buffer.rb +5 -6
  22. data/lib/tensor_stream/evaluator/opencl/opencl_evaluator.rb +200 -265
  23. data/lib/tensor_stream/evaluator/operation_helpers/array_ops_helper.rb +4 -8
  24. data/lib/tensor_stream/evaluator/ruby_evaluator.rb +193 -122
  25. data/lib/tensor_stream/exceptions.rb +6 -0
  26. data/lib/tensor_stream/graph.rb +21 -6
  27. data/lib/tensor_stream/graph_builder.rb +67 -0
  28. data/lib/tensor_stream/graph_deserializers/protobuf.rb +271 -0
  29. data/lib/tensor_stream/graph_keys.rb +1 -0
  30. data/lib/tensor_stream/graph_serializers/pbtext.rb +11 -10
  31. data/lib/tensor_stream/helpers/op_helper.rb +7 -33
  32. data/lib/tensor_stream/helpers/string_helper.rb +16 -0
  33. data/lib/tensor_stream/math_gradients.rb +67 -44
  34. data/lib/tensor_stream/nn/nn_ops.rb +7 -1
  35. data/lib/tensor_stream/operation.rb +14 -27
  36. data/lib/tensor_stream/ops.rb +82 -29
  37. data/lib/tensor_stream/session.rb +4 -0
  38. data/lib/tensor_stream/tensor.rb +30 -12
  39. data/lib/tensor_stream/tensor_shape.rb +1 -1
  40. data/lib/tensor_stream/train/gradient_descent_optimizer.rb +37 -4
  41. data/lib/tensor_stream/train/saver.rb +46 -0
  42. data/lib/tensor_stream/train/utils.rb +37 -0
  43. data/lib/tensor_stream/trainer.rb +2 -0
  44. data/lib/tensor_stream/utils.rb +24 -14
  45. data/lib/tensor_stream/variable.rb +5 -11
  46. data/lib/tensor_stream/variable_scope.rb +15 -0
  47. data/lib/tensor_stream/version.rb +1 -1
  48. data/samples/iris.rb +8 -4
  49. data/samples/linear_regression.rb +1 -1
  50. data/samples/multigpu.rb +73 -0
  51. data/samples/nearest_neighbor.rb +3 -3
  52. data/tensor_stream.gemspec +1 -1
  53. data/test_samples/raw_neural_net_sample.rb +4 -1
  54. metadata +21 -6
@@ -167,15 +167,11 @@ module TensorStream
167
167
  end
168
168
 
169
169
  def last_axis(arr)
170
- all_items = []
171
- if get_rank(arr) <=2
172
- return arr
173
- else
174
- arr.each do |sub|
175
- all_items += last_axis(sub)
176
- end
170
+ return arr if get_rank(arr) <= 2
171
+
172
+ arr.inject([]).map do |sub, rows|
173
+ rows + last_axis(sub)
177
174
  end
178
- all_items
179
175
  end
180
176
 
181
177
  def softmax(arr)
@@ -31,9 +31,7 @@ module TensorStream
31
31
  include TensorStream::MathHelper
32
32
 
33
33
  def run(tensor, execution_context)
34
- if tensor.is_a?(Array) && tensor.size > 0 && tensor[0].is_a?(Tensor)
35
- return tensor.map { |t| run(t, execution_context) }
36
- end
34
+ return tensor.map { |t| run(t, execution_context) } if tensor.is_a?(Array) && !tensor.empty? && tensor[0].is_a?(Tensor)
37
35
 
38
36
  tensor = tensor.call if tensor.is_a?(Proc)
39
37
 
@@ -44,6 +42,8 @@ module TensorStream
44
42
  eval_variable(tensor, child_context)
45
43
  elsif tensor.is_a?(Placeholder)
46
44
  resolve_placeholder(tensor, child_context)
45
+ elsif tensor.is_a?(OutputGroup)
46
+ tensor.outputs[0]
47
47
  else
48
48
  eval_tensor(tensor, child_context)
49
49
  end
@@ -65,9 +65,11 @@ module TensorStream
65
65
 
66
66
  tensor = tensor.map { |t| complete_eval(t, context) } if tensor.is_a?(Array) && !tensor.empty? && tensor[0].is_a?(Tensor)
67
67
 
68
- return tensor if old_tensor.equal?(tensor)
69
- return tensor unless tensor.is_a?(Tensor)
68
+ break if old_tensor.equal?(tensor)
69
+ break unless tensor.is_a?(Tensor)
70
70
  end
71
+
72
+ tensor.is_a?(OutputGroup) ? tensor.outputs[0] : tensor
71
73
  end
72
74
 
73
75
  protected
@@ -86,9 +88,8 @@ module TensorStream
86
88
 
87
89
  def eval_variable(tensor, child_context)
88
90
  value = tensor.read_value
89
- if value.nil?
90
- raise "variable #{tensor.name} not initalized"
91
- end
91
+ raise "variable #{tensor.name} not initalized" if value.nil?
92
+
92
93
  eval_tensor(value, child_context).tap do |val|
93
94
  child_context[:returns] ||= {}
94
95
  child_context[:returns][:vars] ||= []
@@ -100,17 +101,21 @@ module TensorStream
100
101
  inputs
101
102
  end
102
103
 
103
- register_op(:const) do |context, _tensor, inputs|
104
+ register_op(:const) do |_context, _tensor, inputs|
104
105
  inputs[0]
105
106
  end
106
107
 
107
- register_op(:argmax) do |context, tensor, inputs|
108
+ register_op(%i[argmax arg_max]) do |_context, tensor, inputs|
108
109
  axis = tensor.options[:axis] || 0
110
+ rank = get_rank(inputs[0])
111
+ raise TensorStream::InvalidArgumentError, "Expected dimension in the range [#{-rank},#{rank}) but got #{axis}" if axis < -rank || axis >= rank
109
112
  get_op_with_axis(inputs[0], axis, 0, tensor.data_type)
110
113
  end
111
114
 
112
- register_op(:argmin) do |context, tensor, inputs|
115
+ register_op(%i[argmin arg_min]) do |_context, tensor, inputs|
113
116
  axis = tensor.options[:axis] || 0
117
+ rank = get_rank(inputs[0])
118
+ raise TensorStream::InvalidArgumentError, "Expected dimension in the range [#{-rank},#{rank}) but got #{axis}" if axis < -rank || axis >= rank
114
119
  get_op_with_axis(inputs[0], axis, 0, tensor.data_type, ->(a, b) { a < b })
115
120
  end
116
121
 
@@ -118,7 +123,7 @@ module TensorStream
118
123
  call_op(:cast, inputs[0], context, ->(t, _b) { Tensor.cast_dtype(t, tensor.data_type) })
119
124
  end
120
125
 
121
- register_op(:sign) do |context, tensor, inputs|
126
+ register_op(:sign) do |context, _tensor, inputs|
122
127
  func = lambda { |x, _b|
123
128
  if x.zero? || (x.is_a?(Float) && x.nan?)
124
129
  0
@@ -134,22 +139,26 @@ module TensorStream
134
139
  call_op(:sign, inputs[0], context, func)
135
140
  end
136
141
 
137
- register_op(:logical_and) do |context, tensor, inputs|
142
+ register_op(:logical_and) do |context, _tensor, inputs|
138
143
  call_vector_op(:logical_and, inputs[0], inputs[1], context, ->(t, u) { t && u })
139
144
  end
140
145
 
141
- register_op(:equal) do |context, tensor, inputs|
146
+ register_op(:equal) do |context, _tensor, inputs|
142
147
  call_vector_op(:equal, inputs[0], inputs[1], context, ->(t, u) { t == u })
143
148
  end
144
149
 
145
- register_op(:not_equal) do |context, tensor, inputs|
150
+ register_op(:not_equal) do |context, _tensor, inputs|
146
151
  call_vector_op(:not_equal, inputs[0], inputs[1], context, ->(t, u) { t != u })
147
152
  end
148
153
 
149
- register_op :index, no_eval: true do |context, tensor, inputs|
154
+ register_op :index, no_eval: true do |_context, _tensor, inputs|
150
155
  f = inputs[0]
151
156
  index = inputs[1]
152
- f[index]
157
+ if f.is_a?(OutputGroup)
158
+ f.outputs[index]
159
+ else
160
+ f[index]
161
+ end
153
162
  end
154
163
 
155
164
  register_op :slice do |context, tensor, inputs|
@@ -170,7 +179,7 @@ module TensorStream
170
179
  end
171
180
  end
172
181
 
173
- register_op :flow_dynamic_stitch, noop: true do |context, tensor, inputs|
182
+ register_op %i[flow_dynamic_stitch dynamic_stitch], noop: true do |_context, _tensor, inputs|
174
183
  indexes, data = inputs
175
184
  merged = []
176
185
  merge_dynamic_stitch(merged, indexes, data)
@@ -182,7 +191,7 @@ module TensorStream
182
191
  Tensor.cast_dtype(input.flatten.size, tensor.options[:out_type])
183
192
  end
184
193
 
185
- register_op :negate, no_eval: true do |context, _tensor, inputs|
194
+ register_op %i[neg negate], no_eval: true do |context, _tensor, inputs|
186
195
  call_vector_op(:negate, inputs[0], nil, context, ->(t, _u) { -t })
187
196
  end
188
197
 
@@ -191,24 +200,38 @@ module TensorStream
191
200
  call_vector_op(:add, a, b, context, ->(t, u) { t + u })
192
201
  end
193
202
 
203
+ register_op :add_n, no_eval: true do |context, _tensor, inputs|
204
+ if inputs.size == 1
205
+ complete_eval(inputs[0], context)
206
+ elsif inputs.size > 1
207
+
208
+ a = inputs.pop
209
+ until inputs.empty?
210
+ b = inputs.pop
211
+ a = call_vector_op(:add, a, b, context, ->(t, u) { t + u })
212
+ end
213
+ a
214
+ end
215
+ end
216
+
194
217
  register_op :sub, no_eval: true do |context, _tensor, inputs|
195
218
  a, b = inputs
196
219
  call_vector_op(:sub, a, b, context, ->(t, u) { t - u })
197
220
  end
198
221
 
199
- register_op :mod, no_eval: true do |context, _tensor, inputs|
222
+ register_op %i[floor_mod mod], no_eval: true do |context, _tensor, inputs|
200
223
  a, b = inputs
201
224
  call_vector_op(:sub, a, b, context, ->(t, u) { t % u })
202
225
  end
203
226
 
204
- register_op :floor_div, no_eval: true do |context, tensor, inputs|
227
+ register_op %i[floor_div real_div], no_eval: true do |context, tensor, inputs|
205
228
  a, b = inputs
206
229
  if fp_type?(tensor.data_type)
207
230
  call_vector_op(:sub, a, b, context, ->(t, u) { (t / u).to_i.to_f })
208
231
  else
209
232
  call_vector_op(:sub, a, b, context, ->(t, u) { t / u })
210
233
  end
211
- end
234
+ end
212
235
 
213
236
  register_op :mul, no_eval: true do |context, _tensor, inputs|
214
237
  a, b = inputs
@@ -225,55 +248,63 @@ module TensorStream
225
248
  call_vector_op(:squared_difference, a, b, context, ->(t, u) { (t - u) * (t - u) })
226
249
  end
227
250
 
228
- register_op :concat do |_context, tensor, inputs|
251
+ register_op %i[concat concat_v2] do |_context, tensor, inputs|
229
252
  concat_array(inputs[0], tensor.options[:axis])
230
253
  end
231
254
 
232
- register_op :round, no_eval: true do |context, tensor, inputs|
255
+ register_op :round, no_eval: true do |context, _tensor, inputs|
233
256
  call_op(:round, inputs[0], context, ->(t, _b) { t.round })
234
257
  end
235
258
 
236
- register_op :abs, no_eval: true do |context, tensor, inputs|
259
+ register_op :abs, no_eval: true do |context, _tensor, inputs|
237
260
  call_op(:abs, inputs[0], context, ->(t, _b) { t.abs })
238
261
  end
239
262
 
240
- register_op :tanh, no_eval: true do |context, tensor, inputs|
263
+ register_op :tanh, no_eval: true do |context, _tensor, inputs|
241
264
  call_op(:tanh, inputs[0], context, ->(t, _b) { Math.tanh(t) })
242
265
  end
243
266
 
244
- register_op :tan, no_eval: true do |context, tensor, inputs|
267
+ register_op :tan, no_eval: true do |context, _tensor, inputs|
245
268
  call_op(:tan, inputs[0], context, ->(t, _b) { Math.tan(t) })
246
269
  end
247
270
 
248
- register_op :sec, no_eval: true do |context, tensor, inputs|
271
+ register_op :sec, no_eval: true do |context, _tensor, inputs|
249
272
  call_op(:sec, inputs[0], context, ->(t, _b) { Math.sec(t) })
250
273
  end
251
274
 
252
- register_op :sin, no_eval: true do |context, tensor, inputs|
275
+ register_op :sin, no_eval: true do |context, _tensor, inputs|
253
276
  call_op(:sin, inputs[0], context, ->(t, _b) { Math.sin(t) })
254
277
  end
255
278
 
256
- register_op :cos, no_eval: true do |context, tensor, inputs|
279
+ register_op :asin, no_eval: true do |context, _tensor, inputs|
280
+ call_op(:asin, inputs[0], context, ->(t, _b) { Math.asin(t) })
281
+ end
282
+
283
+ register_op :acos, no_eval: true do |context, _tensor, inputs|
284
+ call_op(:acos, inputs[0], context, ->(t, _b) { Math.acos(t) })
285
+ end
286
+
287
+ register_op :cos, no_eval: true do |context, _tensor, inputs|
257
288
  call_op(:cos, inputs[0], context, ->(t, _b) { Math.cos(t) })
258
289
  end
259
290
 
260
- register_op :log1p, no_eval: true do |context, tensor, inputs|
291
+ register_op :log1p, no_eval: true do |context, _tensor, inputs|
261
292
  call_op(:log1p, inputs[0], context, ->(t, _b) { Math.log(1 + t) })
262
293
  end
263
294
 
264
- register_op :log, no_eval: true do |context, tensor, inputs|
295
+ register_op :log, no_eval: true do |context, _tensor, inputs|
265
296
  call_op(:log, inputs[0], context, ->(t, _b) { t < 0 ? Float::NAN : Math.log(t) })
266
297
  end
267
298
 
268
- register_op :exp, no_eval: true do |context, tensor, inputs|
299
+ register_op :exp, no_eval: true do |context, _tensor, inputs|
269
300
  call_op(:exp, inputs[0], context, ->(t, _b) { Math.exp(t) })
270
301
  end
271
302
 
272
- register_op :sigmoid, no_eval: true do |context, tensor, inputs|
303
+ register_op :sigmoid, no_eval: true do |context, _tensor, inputs|
273
304
  call_op(:sigmoid, inputs[0], context, ->(t, _b) { sigmoid(t) })
274
305
  end
275
306
 
276
- register_op :sqrt, no_eval: true do |context, tensor, inputs|
307
+ register_op :sqrt, no_eval: true do |context, _tensor, inputs|
277
308
  call_op(:sqrt, inputs[0], context, ->(t, _b) { Math.sqrt(t) })
278
309
  end
279
310
 
@@ -285,21 +316,21 @@ module TensorStream
285
316
  call_op(:ceil, inputs[0], context, ->(t, _b) { t.ceil })
286
317
  end
287
318
 
288
- register_op :square, no_eval: true do |context, tensor, inputs|
289
- call_op(:square, inputs[0], context, ->(t, _b) { t * t })
319
+ register_op :square, no_eval: true do |context, _tensor, inputs|
320
+ call_op(:square, inputs[0], context, ->(t, _b) { t * t })
290
321
  end
291
322
 
292
- register_op :reciprocal, no_eval: true do |context, tensor, inputs|
293
- call_op(:reciprocal, inputs[0], context, ->(t, _b) { 1 / t })
323
+ register_op :reciprocal, no_eval: true do |context, _tensor, inputs|
324
+ call_op(:reciprocal, inputs[0], context, ->(t, _b) { 1 / t })
294
325
  end
295
326
 
296
- register_op :stop_gradient, no_eval: true do |_context, _tensor, inputs|
327
+ register_op :stop_gradient, no_eval: true do |_context, _tensor, inputs|
297
328
  inputs[0]
298
329
  end
299
330
 
300
331
  register_op :sigmoid_grad, no_eval: true do |context, _tensor, inputs|
301
332
  a, b = inputs
302
- call_vector_op(:sigmoid_grad, a, b, context, ->(t, u) { u * sigmoid(t) * (1 - sigmoid(t))} )
333
+ call_vector_op(:sigmoid_grad, a, b, context, ->(t, u) { u * sigmoid(t) * (1 - sigmoid(t)) })
303
334
  end
304
335
 
305
336
  register_op :random_uniform, no_eval: true do |_context, tensor, _inputs|
@@ -313,7 +344,7 @@ module TensorStream
313
344
  generate_vector(shape, generator: generator)
314
345
  end
315
346
 
316
- register_op :random_normal, no_eval: true do |_context, tensor, _inputs|
347
+ register_op :random_standard_normal, no_eval: true do |_context, tensor, _inputs|
317
348
  seed = tensor.options[:seed]
318
349
  random = _get_randomizer(tensor, seed)
319
350
  r = RandomGaussian.new(tensor.options.fetch(:mean), tensor.options.fetch(:stddev), -> { random.rand })
@@ -345,18 +376,18 @@ module TensorStream
345
376
  generate_vector(shape, generator: generator)
346
377
  end
347
378
 
348
- register_op :assign, noop: true do |context, tensor, inputs|
379
+ register_op :assign, noop: true do |context, tensor, _inputs|
349
380
  assign = tensor.inputs[0] || tensor
350
381
  assign.value = complete_eval(tensor.inputs[1], context)
351
382
  assign.value
352
383
  end
353
384
 
354
- register_op :assign_add, noop: true do |context, tensor, inputs|
385
+ register_op :assign_add, noop: true do |context, tensor, _inputs|
355
386
  tensor.inputs[0].value = process_vector_math_op(tensor.inputs[0], tensor.inputs[1], context, ->(t, u) { t + u })
356
387
  tensor.inputs[0].value
357
388
  end
358
389
 
359
- register_op :assign_sub, noop: true do |context, tensor, inputs|
390
+ register_op :assign_sub, noop: true do |context, tensor, _inputs|
360
391
  tensor.inputs[0].value = process_vector_math_op(tensor.inputs[0], tensor.inputs[1], context, ->(t, u) { t - u })
361
392
  tensor.inputs[0].value
362
393
  end
@@ -378,7 +409,14 @@ module TensorStream
378
409
  end
379
410
 
380
411
  register_op :sum, noop: true do |context, tensor, _inputs|
381
- c = fp_type?(tensor.data_type) ? 0.0 : 0
412
+ # axis = complete_eval(tensor.inputs[1], context)
413
+ # # fast path
414
+ # if axis.nil? && !tensor.options[:keepdims]
415
+ # arr = complete_eval(tensor.inputs[0], context)
416
+ # next arr unless arr.is_a?(Array)
417
+ # next arr.flatten.reduce(:+)
418
+ # end
419
+
382
420
  func = lambda do |arr|
383
421
  reduced_val = arr[0]
384
422
  arr[1..arr.size].each do |v|
@@ -386,11 +424,19 @@ module TensorStream
386
424
  end
387
425
  reduced_val
388
426
  end
389
-
427
+
390
428
  reduction(context, tensor, func)
391
429
  end
392
430
 
393
431
  register_op :prod, noop: true do |context, tensor, _inputs|
432
+ # axis = complete_eval(tensor.inputs[1], context)
433
+ # # fast path
434
+ # if axis.nil? && !tensor.options[:keepdims]
435
+ # arr = complete_eval(tensor.inputs[0], context)
436
+ # next arr unless arr.is_a?(Array)
437
+ # next arr.flatten.reduce(:*)
438
+ # end
439
+
394
440
  c = fp_type?(tensor.data_type) ? 1.0 : 1
395
441
  func = lambda do |arr|
396
442
  return c if arr.nil?
@@ -405,13 +451,12 @@ module TensorStream
405
451
  reduction(context, tensor, func)
406
452
  end
407
453
 
408
- register_op :range do |context, tensor, inputs|
454
+ register_op :range do |_context, _tensor, inputs|
409
455
  start, limit, delta = inputs
410
456
  raise " delta !=0 " if delta.zero?
411
457
  raise " Requires start <= limit when delta > 0" if (start > limit) && delta > 0
412
458
  raise " Requires start >= limit when delta < 0" if (start < limit) && delta < 0
413
-
414
-
459
+
415
460
  cur_step = start
416
461
  r = []
417
462
  Kernel.loop do
@@ -446,6 +491,18 @@ module TensorStream
446
491
  end
447
492
  end
448
493
 
494
+ register_op :expand_dims do |context, tensor, inputs|
495
+ val, axis = inputs
496
+ axis = axis.nil? ? 0 : axis
497
+
498
+ shape = shape_eval(val)
499
+ axis = -axis if axis == shape.size
500
+
501
+ new_shape = shape.dup.insert(axis, 1).compact
502
+
503
+ TensorShape.reshape([val].flatten, new_shape)
504
+ end
505
+
449
506
  register_op :cond, noop: true do |context, tensor, inputs|
450
507
  pred = complete_eval(tensor.options[:pred], context)
451
508
 
@@ -456,7 +513,7 @@ module TensorStream
456
513
  end
457
514
  end
458
515
 
459
- register_op :where do |context, tensor, inputs|
516
+ register_op %i[select where] do |context, tensor, inputs|
460
517
  pred = complete_eval(tensor.options[:pred], context)
461
518
  call_3way_vector_op(pred, inputs[0], inputs[1], context, ->(t, u, v) { t ? u : v })
462
519
  end
@@ -481,7 +538,7 @@ module TensorStream
481
538
  call_vector_op(:greater_equal, a, b, context, ->(t, u) { t <= u })
482
539
  end
483
540
 
484
- register_op :fill do |_context, tensor, inputs|
541
+ register_op :fill do |_context, _tensor, inputs|
485
542
  shape = inputs[0]
486
543
  value = inputs[1]
487
544
 
@@ -528,7 +585,7 @@ module TensorStream
528
585
  shape_eval(inputs[0], tensor.options[:out_type])
529
586
  end
530
587
 
531
- register_op :matmul do |_context, tensor, inputs|
588
+ register_op :mat_mul do |_context, tensor, inputs|
532
589
  matrix_a, matrix_b = inputs
533
590
  rank_a = get_rank(matrix_a)
534
591
  rank_b = get_rank(matrix_b)
@@ -538,10 +595,6 @@ module TensorStream
538
595
  matrix_a = matrix_a.transpose if tensor.options[:transpose_a]
539
596
  matrix_b = matrix_b.transpose if tensor.options[:transpose_b]
540
597
 
541
- # handle matrix multiplication with constants like 1 or 0
542
- matrix_a = matmul_const_transform(matrix_a, matrix_b, tensor)
543
- matrix_b = matmul_const_transform(matrix_b, matrix_a, tensor)
544
-
545
598
  # check matrix dimensions
546
599
  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
547
600
 
@@ -593,12 +646,25 @@ module TensorStream
593
646
  arr_pad(inputs[0], p, tensor.data_type)
594
647
  end
595
648
 
596
- register_op :max, noop: true do |context, _tensor, inputs|
649
+ register_op %i[max maximum], noop: true do |context, _tensor, inputs|
597
650
  call_vector_op(:max, inputs[0], inputs[1], context, ->(t, u) { [t, u].max })
598
651
  end
599
652
 
653
+ register_op %i[min minimum], noop: true do |context, _tensor, inputs|
654
+ call_vector_op(:min, inputs[0], inputs[1], context, ->(t, u) { [t, u].min })
655
+ end
656
+
657
+ register_op :apply_gradient_descent do |context, tensor, inputs|
658
+ target_var, learning_rate, delta = inputs
659
+ assign = tensor.inputs[0] || tensor
660
+
661
+ assign.value = process_vector_math_op(target_var, delta, context, ->(t, u) { t - u * learning_rate })
662
+ assign.value
663
+ end
664
+
600
665
  register_op :broadcast_gradient_args do |_context, _tensor, inputs|
601
- get_broadcast_gradient_args(inputs[0], inputs[1])
666
+ rx, ry = get_broadcast_gradient_args(inputs[0], inputs[1])
667
+ OutputGroup.new([rx, ry])
602
668
  end
603
669
 
604
670
  register_op :tile do |_context, _tensor, inputs|
@@ -620,6 +686,14 @@ module TensorStream
620
686
  softmax(inputs[0])
621
687
  end
622
688
 
689
+ register_op :save_v2 do |context, tensor, inputs|
690
+ prefix, tensor_names, shape_and_slices = inputs[0..3]
691
+ end
692
+
693
+ register_op :restore_v2 do |context, tensor, inputs|
694
+ prefix, tensor_names, shape_and_slices = inputs[0..3]
695
+ end
696
+
623
697
  register_op :softmax_grad do |_context, _tensor, inputs|
624
698
  input, grad = inputs
625
699
  softmax_input = softmax(input)
@@ -628,10 +702,9 @@ module TensorStream
628
702
  last_dimen_list = last_axis(softmax_input)
629
703
  last_grad_list = last_axis(grad)
630
704
 
631
- func = -> (list, last_grad) {
632
-
705
+ func = lambda { |list, last_grad|
633
706
  f_grad = softmax_grad(list)
634
- f_grad.transpose.each_with_index.collect do |row, index|
707
+ f_grad.transpose.each.collect do |row|
635
708
  sum = 0.0
636
709
  row.each_with_index do |r, g_index|
637
710
  sum += r * last_grad[g_index]
@@ -641,55 +714,75 @@ module TensorStream
641
714
  }
642
715
 
643
716
  if input_shape.size == 1
644
- func.(last_dimen_list, last_grad_list)
717
+ func.call(last_dimen_list, last_grad_list)
645
718
  else
646
719
  arr = last_dimen_list.zip(last_grad_list).collect do |list, last_grad|
647
- func.(list, last_grad)
720
+ func.call(list, last_grad)
721
+ end
722
+ TensorShape.reshape(arr.flatten, input_shape)
723
+ end
724
+ end
725
+
726
+ register_op :log_softmax do |_context, _tensor, inputs|
727
+ input_shape = shape_eval(inputs[0])
728
+ last_dimen_list = last_axis(inputs[0])
729
+
730
+ func = lambda { |logits|
731
+ c = logits.max
732
+ transformed_logits = logits.map { |l| l - c }
733
+ sum = transformed_logits.map { |x| Math.exp(x) }.reduce(:+)
734
+ transformed_logits.map { |x| x - Math.log(sum) }
735
+ }
736
+
737
+ if input_shape.size == 1
738
+ func.call(last_dimen_list)
739
+ else
740
+ arr = last_dimen_list.collect do |list|
741
+ func.call(list)
648
742
  end
649
743
  TensorShape.reshape(arr.flatten, input_shape)
650
744
  end
651
-
652
745
  end
653
746
 
654
- register_op :softmax_cross_entropy_with_logits_v2 do |context, tensor, inputs|
747
+ register_op %i[softmax_cross_entropy_with_logits_v2 softmax_cross_entropy_with_logits] do |_context, _tensor, inputs|
655
748
  last_dimen_list = last_axis(inputs[0])
656
749
  input_shape = shape_eval(inputs[0])
657
750
  labels = last_axis(inputs[1])
658
- func = -> (logits, label) {
751
+ func = lambda { |logits, label|
659
752
  c = logits.max
660
- transformed_logits = logits.map { |l| l - c}
753
+ transformed_logits = logits.map { |l| l - c }
661
754
  sum = transformed_logits.map { |x| Math.exp(x) }.reduce(:+)
662
755
  transformed_logits.zip(label).map { |x, y| (Math.log(sum) - x) * y }
663
756
  }
664
757
 
665
758
  if input_shape.size == 1
666
- func.(last_dimen_list, labels)
759
+ func.call(last_dimen_list, labels)
667
760
  else
668
761
  arr = last_dimen_list.zip(labels).collect do |list, label|
669
- func.(list, label)
762
+ func.call(list, label)
670
763
  end
671
764
  TensorShape.reshape(arr.flatten, input_shape)
672
765
  end
673
766
  end
674
767
 
675
- register_op :softmax_cross_entropy_with_logits_v2_grad do |context, tensor, inputs|
768
+ register_op :softmax_cross_entropy_with_logits_v2_grad do |_context, _tensor, inputs|
676
769
  last_dimen_list = last_axis(inputs[0])
677
770
  labels = last_axis(inputs[1])
678
771
  passed_grads = last_axis(inputs[2])
679
772
  input_shape = shape_eval(inputs[0])
680
773
 
681
- func = -> (logits, label, grad) {
774
+ func = lambda { |logits, label, grad|
682
775
  c = logits.max
683
776
  transformed_logits = logits.map { |l| Math.exp(l - c) }
684
777
  e_sum = transformed_logits.reduce(:+)
685
- transformed_logits.zip(label).zip(grad).map { |(x, y), g| (x / e_sum) * g - y }
778
+ transformed_logits.zip(label).zip(grad).map { |(x, y), g| (x / e_sum) * g - y }
686
779
  }
687
780
 
688
781
  if input_shape.size == 1
689
- func.(last_dimen_list, labels, passed_grads)
782
+ func.call(last_dimen_list, labels, passed_grads)
690
783
  else
691
- arr = last_dimen_list.zip(labels).zip(passed_grads).collect do | (list, label), passed_grad|
692
- func.(list, label, passed_grad)
784
+ arr = last_dimen_list.zip(labels).zip(passed_grads).collect do |(list, label), passed_grad|
785
+ func.call(list, label, passed_grad)
693
786
  end
694
787
  TensorShape.reshape(arr.flatten, input_shape)
695
788
  end
@@ -697,7 +790,10 @@ module TensorStream
697
790
 
698
791
  register_op :check_numerics do |context, tensor, inputs|
699
792
  message = tensor.options[:message]
700
- f = ->(t, _b) { raise "#{message} Invalid argument" if t.nan? || t.infinite?; t }
793
+ f = lambda { |t, _b|
794
+ raise "#{message} Invalid argument" if t.nan? || t.infinite?
795
+ t
796
+ }
701
797
  call_op(:check_numerics, inputs[0], context, f)
702
798
  end
703
799
 
@@ -731,17 +827,19 @@ module TensorStream
731
827
  end
732
828
  rescue EvaluatorExcecutionException => e
733
829
  raise e
830
+ rescue TensorStreamError => e
831
+ raise e
734
832
  rescue StandardError => e
735
- a = resolve_placeholder(tensor.inputs[0], child_context) if tensor.inputs && tensor.inputs[0]
736
- b = resolve_placeholder(tensor.inputs[1], child_context) if tensor.inputs && tensor.inputs[1]
833
+ # a = resolve_placeholder(tensor.inputs[0], child_context) if tensor.inputs && tensor.inputs[0]
834
+ # b = resolve_placeholder(tensor.inputs[1], child_context) if tensor.inputs && tensor.inputs[1]
737
835
  puts e.message
738
836
  puts e.backtrace.join("\n")
739
837
  # shape_a = a.shape.shape if a
740
838
  # shape_b = b.shape.shape if b
741
839
  # dtype_a = a.data_type if a
742
840
  # dtype_b = b.data_type if b
743
- a = complete_eval(a, child_context)
744
- b = complete_eval(b, child_context)
841
+ # a = complete_eval(a, child_context)
842
+ # b = complete_eval(b, child_context)
745
843
  # puts "name: #{tensor.given_name}"
746
844
  # # puts "op: #{tensor.to_math(true, 1)}"
747
845
  # puts "A #{shape_a} #{dtype_a}: #{a}" if a
@@ -749,7 +847,7 @@ module TensorStream
749
847
  # dump_intermediates if @log_intermediates
750
848
  # File.write('/home/jedld/workspace/tensor_stream/samples/error.graphml', TensorStream::Graphml.new.get_string(tensor, @session))
751
849
  # File.write('/Users/josephemmanueldayo/workspace/gradients.graphml', TensorStream::Graphml.new.get_string(tensor, @session))
752
- raise EvaluatorExcecutionException.new(e, tensor), "error #{e.message} while evaluating #{tensor.name} : #{tensor.to_math(true,1)} defined at #{tensor.source}"
850
+ raise EvaluatorExcecutionException.new(e, tensor), "error #{e.message} while evaluating #{tensor.name} : #{tensor.to_math(true, 1)} defined at #{tensor.source}"
753
851
  end
754
852
 
755
853
  def eval_tensor(tensor, child_context)
@@ -771,7 +869,7 @@ module TensorStream
771
869
  end
772
870
  end
773
871
 
774
- def convert_from_buffer(tensor, result)
872
+ def convert_from_buffer(_tensor, result)
775
873
  result.buffer
776
874
  end
777
875
 
@@ -818,14 +916,14 @@ module TensorStream
818
916
  return val if axis && axis.is_a?(Array) && axis.empty?
819
917
 
820
918
  axis = if axis.nil?
821
- nil
822
- elsif axis.is_a?(Array)
823
- return val if axis.empty?
919
+ nil
920
+ elsif axis.is_a?(Array)
921
+ return val if axis.empty?
824
922
 
825
- axis.map { |a| a < 0 ? rank - a.abs : a }
826
- else
827
- axis < 0 ? rank - axis.abs : axis
828
- end
923
+ axis.map { |a| a < 0 ? rank - a.abs : a }
924
+ else
925
+ axis < 0 ? rank - axis.abs : axis
926
+ end
829
927
 
830
928
  reduce_axis(0, axis, val, keep_dims, func)
831
929
  end
@@ -855,17 +953,6 @@ module TensorStream
855
953
  end
856
954
  end
857
955
 
858
- def matmul_const_transform(mat, mat_b, tensor)
859
- if !mat.is_a?(Array)
860
- compat_shape = shape_eval(mat_b).reverse
861
- func = -> { tensor.data_type == :int32 ? mat.to_i : mat.to_f }
862
-
863
- generate_vector(compat_shape, generator: func)
864
- else
865
- mat
866
- end
867
- end
868
-
869
956
  def call_op(op, a, child_context, func)
870
957
  a = complete_eval(a, child_context)
871
958
  process_function_op(a, func)
@@ -899,22 +986,6 @@ module TensorStream
899
986
  # end
900
987
  end
901
988
 
902
- # determine possible reduction axis to be used
903
- def _broadcast_gradient_op(vector_shape1, vector_shape2, level)
904
- va_rank = _rank_from_shape(vector_shape1)
905
- vb_rank = _rank_from_shape(vector_shape2)
906
- return [] if vector_shape1 == vector_shape2 # same shape so no reductions
907
-
908
- shape2_r = vector_shape2.reverse
909
-
910
- vector_shape1.reverse.each_with_index.collect do |s, index|
911
- next va_rank - index - 1 if index >= shape2_r.size
912
- next nil if shape2_r[index] == s
913
- next nil if shape2_r[index] > s
914
- va_rank - index - 1
915
- end.compact
916
- end
917
-
918
989
  def _rank_from_shape(shape)
919
990
  shape.is_a?(Array) ? shape.size : 0
920
991
  end
@@ -967,10 +1038,10 @@ module TensorStream
967
1038
  reduced_val = r[0]
968
1039
  if r.size > 1
969
1040
  reduced_val = f.call(r[0..val.size])
970
- elsif r.size == 0
1041
+ elsif r.empty?
971
1042
  reduced_val = f.call(nil)
972
1043
  end
973
- keep_dims ? [ reduced_val ] : reduced_val
1044
+ keep_dims ? [reduced_val] : reduced_val
974
1045
  else
975
1046
  r
976
1047
  end
@@ -1037,7 +1108,7 @@ module TensorStream
1037
1108
  def dump_intermediates
1038
1109
  arr = []
1039
1110
  arr << "============== start ==================="
1040
- @context[:compute_history].each_with_index do |history, index|
1111
+ @context[:compute_history].each_with_index do |history, _index|
1041
1112
  arr << "------------------------------------"
1042
1113
  arr << history[:name]
1043
1114
  arr << "#{history[:type]} #{history[:shape]}"
@@ -1049,10 +1120,10 @@ module TensorStream
1049
1120
  end
1050
1121
  arr << "============== end ====================="
1051
1122
  str = arr.join("\n")
1052
- File.write("/tmp/intermediates.txt", str)
1123
+ File.write('/tmp/intermediates.txt', str)
1053
1124
  end
1054
1125
  end
1055
1126
  end
1056
1127
  end
1057
1128
 
1058
- TensorStream::Evaluator.register_evaluator(TensorStream::Evaluator::RubyEvaluator, "ruby")
1129
+ TensorStream::Evaluator.register_evaluator(TensorStream::Evaluator::RubyEvaluator, 'ruby')