tensor_stream 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -13,10 +13,10 @@ module TensorStream
13
13
  # same as op but with a marker that it was internal generated
14
14
  def i_op(code, *args)
15
15
  options = if args.last.is_a?(Hash)
16
- args.pop
17
- else
18
- {}
19
- end
16
+ args.pop
17
+ else
18
+ {}
19
+ end
20
20
 
21
21
  args << options.merge(internal: true)
22
22
  Operation.new(code.to_sym, *args)
@@ -45,32 +45,6 @@ module TensorStream
45
45
  arr
46
46
  end
47
47
 
48
- def dtype_eval(rank, value, data_type = nil)
49
- dtype = if data_type.nil?
50
- Tensor.detect_type(value[0])
51
- else
52
- data_type
53
- end
54
-
55
- rank += 1 if dtype == :array
56
-
57
- [dtype, rank, value[0], value.size]
58
- end
59
-
60
- def val_to_dtype(value)
61
- if value.is_a?(String)
62
- :string
63
- elsif value.is_a?(Float)
64
- :float32
65
- elsif value.is_a?(Integer)
66
- :int32
67
- elsif value.is_a?(Array)
68
- :array
69
- else
70
- :float32
71
- end
72
- end
73
-
74
48
  def fp_type?(type)
75
49
  TensorStream::Ops::FLOATING_POINT_TYPES.include?(type)
76
50
  end
@@ -88,10 +62,10 @@ module TensorStream
88
62
  def shapes_fully_specified_and_equal(x, y)
89
63
  return false if !shape_full_specified(x) || !shape_full_specified(y)
90
64
  return false if x.shape.shape != y.shape.shape
91
-
65
+
92
66
  true
93
67
  end
94
-
68
+
95
69
  def shape_full_specified(tensor)
96
70
  return false if tensor.shape.nil?
97
71
  return false if tensor.shape.shape.nil?
@@ -108,7 +82,7 @@ module TensorStream
108
82
  axes = (axes + input_rank) % input_rank
109
83
  axes_shape = i_op(:shape, axes)
110
84
  TensorStream.dynamic_stitch([TensorStream.range(0, input_rank), axes],
111
- [input_shape, i_op(:fill, axes_shape, 1)])
85
+ [input_shape, i_op(:fill, axes_shape, 1)])
112
86
  end
113
87
  end
114
88
  end
@@ -1,4 +1,6 @@
1
1
  module TensorStream
2
+ # helper string methods usually found in ActiveSupport but
3
+ # need to replicate here
2
4
  module StringHelper
3
5
  def camelize(string, uppercase_first_letter = true)
4
6
  string = if uppercase_first_letter
@@ -8,5 +10,19 @@ module TensorStream
8
10
  end
9
11
  string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
10
12
  end
13
+
14
+ def underscore(string)
15
+ string.gsub(/::/, '/').
16
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
17
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
18
+ tr("-", "_").
19
+ downcase
20
+ end
21
+
22
+ def symbolize_keys(hash)
23
+ hash.map do |k, v|
24
+ [k.to_sym, v]
25
+ end.to_h
26
+ end
11
27
  end
12
28
  end
@@ -18,7 +18,7 @@ module TensorStream
18
18
 
19
19
  grad = i_op(:fill, tf.shape(tensor), tf.constant(1, dtype: wrt_dx.data_type))
20
20
 
21
- _propagate(grad, tensor, wrt_dx, nodes_to_compute, options[:stop_gradients] || [] ) || i_op(:zeros_like, wrt_dx)
21
+ _propagate(grad, tensor, wrt_dx, nodes_to_compute, options[:stop_gradients] || []) || i_op(:zeros_like, wrt_dx)
22
22
  end
23
23
 
24
24
  def self._propagate(grad, tensor, stop_tensor, nodes_to_compute, stop_gradients = [])
@@ -29,16 +29,12 @@ module TensorStream
29
29
  computed_op = _compute_derivative(tensor, grad)
30
30
 
31
31
  if computed_op.is_a?(Array)
32
- partials = []
33
- computed_op.each_with_index do |op_grad, index|
32
+ computed_op.each_with_index.collect do |op_grad, index|
34
33
  next if op_grad.nil?
34
+ next unless nodes_to_compute.include?(tensor.inputs[index].name)
35
35
 
36
- if nodes_to_compute.include?(tensor.inputs[index].name)
37
- partials << _propagate(op_grad, tensor.inputs[index], stop_tensor, nodes_to_compute, stop_gradients)
38
- end
39
- end
40
-
41
- partials.compact.reduce(:+)
36
+ _propagate(op_grad, tensor.inputs[index], stop_tensor, nodes_to_compute, stop_gradients)
37
+ end.compact.reduce(:+)
42
38
  else
43
39
  return nil if computed_op.nil?
44
40
  _propagate(computed_op, tensor.inputs[0], stop_tensor, nodes_to_compute, stop_gradients)
@@ -51,14 +47,32 @@ module TensorStream
51
47
  y = node.inputs[1] if node.inputs[1]
52
48
 
53
49
  case node.operation
50
+ when :add_n
51
+ return [grad] * node.inputs.size
54
52
  when :add
55
53
  return [grad, grad] if shapes_fully_specified_and_equal(x, y)
56
54
  sx = tf.shape(x, name: 'add/shape_x')
57
55
  sy = tf.shape(y, name: 'add/shape_y')
58
56
  rx, ry = _broadcast_gradient_args(sx, sy)
59
57
 
60
- [ tf.reshape(tf.reduce_sum(grad, rx, name: 'add/reduce_sum_x'),sx),
61
- tf.reshape(tf.reduce_sum(grad, ry, name: 'add/reduce_sum_y'),sy) ]
58
+ [tf.reshape(tf.reduce_sum(grad, rx, name: 'add/reduce_sum_x'), sx),
59
+ tf.reshape(tf.reduce_sum(grad, ry, name: 'add/reduce_sum_y'), sy)]
60
+ when :asin
61
+ tf.control_dependencies([grad]) do
62
+ x2 = tf.square(x)
63
+ one = tf.constant(1, dtype: grad.data_type)
64
+ den = tf.sqrt(tf.subtract(one, x2))
65
+ inv = tf.reciprocal(den)
66
+ grad * inv
67
+ end
68
+ when :acos
69
+ tf.control_dependencies([grad]) do
70
+ x2 = tf.square(x)
71
+ one = tf.constant(1, dtype: grad.data_type)
72
+ den = tf.sqrt(tf.subtract(one, x2))
73
+ inv = tf.reciprocal(den)
74
+ -grad * inv
75
+ end
62
76
  when :sub
63
77
  return [grad, -grad] if shapes_fully_specified_and_equal(x, y)
64
78
 
@@ -66,24 +80,22 @@ module TensorStream
66
80
  sy = tf.shape(y, name: 'sub/shape_y')
67
81
  rx, ry = _broadcast_gradient_args(sx, sy)
68
82
 
69
- [ tf.reshape(tf.reduce_sum(grad, rx, name: 'add/reduce_sub_x'),sx),
70
- -tf.reshape(tf.reduce_sum(grad, ry, name: 'add/reduce_sub_y'),sy) ]
83
+ [tf.reshape(tf.reduce_sum(grad, rx, name: 'add/reduce_sub_x'), sx),
84
+ -tf.reshape(tf.reduce_sum(grad, ry, name: 'add/reduce_sub_y'), sy)]
71
85
  when :mul
72
86
  sx = tf.shape(x)
73
87
  sy = tf.shape(y)
74
88
  rx, ry = _broadcast_gradient_args(sx, sy)
75
89
 
76
- [ tf.reshape(tf.reduce_sum(tf.mul(grad, y), rx), sx),
77
- tf.reshape(tf.reduce_sum(tf.mul(x, grad), ry), sy)]
90
+ [tf.reshape(tf.reduce_sum(tf.mul(grad, y), rx), sx),
91
+ tf.reshape(tf.reduce_sum(tf.mul(x, grad), ry), sy)]
78
92
  when :div
79
93
  sx = i_op(:shape, x)
80
94
  sy = i_op(:shape, y)
81
95
  rx, ry = _broadcast_gradient_args(sx, sy)
82
96
 
83
- [
84
- tf.reshape(tf.reduce_sum(tf.div(grad, y), rx), sx),
85
- tf.reshape(tf.reduce_sum(grad * tf.div(tf.div(-x, y), y),
86
- ry), sy)]
97
+ [tf.reshape(tf.reduce_sum(tf.div(grad, y), rx), sx),
98
+ tf.reshape(tf.reduce_sum(grad * tf.div(tf.div(-x, y), y), ry), sy)]
87
99
  when :mod
88
100
  sx = tf.shape(x)
89
101
  sy = tf.shape(y)
@@ -100,9 +112,9 @@ module TensorStream
100
112
 
101
113
  x_grad = tf.mul(2.0, grad) * (x - y)
102
114
 
103
- [ tf.reshape(tf.reduce_sum(x_grad, rx), sx),
104
- tf.reshape(-tf.reduce_sum(x_grad, ry), sy)]
105
- when :matmul
115
+ [tf.reshape(tf.reduce_sum(x_grad, rx), sx),
116
+ tf.reshape(-tf.reduce_sum(x_grad, ry), sy)]
117
+ when :mat_mul
106
118
  t_a = node.options[:transpose_a]
107
119
  t_b = node.options[:transpose_b]
108
120
 
@@ -140,14 +152,12 @@ module TensorStream
140
152
  grad * tf.sign(x)
141
153
  when :log
142
154
  grad * tf.reciprocal(x)
143
- when :tanh
144
- i_op(:tanh_grad, x) * grad
145
155
  when :cos
146
156
  -grad * tf.sin(x)
147
157
  when :max
148
- x_mask = tf.where(x > y, tf.ones_like(x), tf.zeros_like(y))
149
- y_mask = tf.where(x < y, tf.zeros_like(x), tf.ones_like(y))
150
- [x_mask * grad, y_mask * grad]
158
+ _min_or_max_grad(node.inputs, grad, ->(x, y) { tf.greater_equal(x, y) } )
159
+ when :min
160
+ _min_or_max_grad(node.inputs, grad, ->(x, y) { tf.less_equal(x, y) } )
151
161
  when :tan
152
162
  secx = tf.reciprocal(tf.cos(x))
153
163
  secx2 = tf.square(secx)
@@ -158,6 +168,8 @@ module TensorStream
158
168
  grad * node
159
169
  when :identity, :print
160
170
  grad
171
+ when :sign
172
+ tf.zeros(tf.shape(x), dtype: x.data_type)
161
173
  when :sum
162
174
  _sum_grad(x, y, grad)
163
175
  when :reciprocal
@@ -178,7 +190,7 @@ module TensorStream
178
190
  y_cond = i_op(:cond, i_op(:zeros_like, x), i_op(:ones_like, x), pred: node.options[:pred])
179
191
  [x_cond * grad, y_cond * grad]
180
192
  when :mean
181
- sum_grad = _sum_grad(x, y, grad)[0]
193
+ sum_grad = _sum_grad(x, y, grad)[0]
182
194
  input_shape = tf.shape(x)
183
195
  output_shape = tf.shape(node)
184
196
  factor = _safe_shape_div(tf.reduce_prod(input_shape), tf.reduce_prod(output_shape))
@@ -187,19 +199,20 @@ module TensorStream
187
199
  grad * tf.reciprocal(i_cons(1, dtype: grad.data_type) + x)
188
200
  when :sigmoid
189
201
  i_op(:sigmoid_grad, x, grad)
202
+ when :sigmoid_grad
203
+ gb = grad * y
204
+ [gb - 2.0 * gb * x, i_op(:sigmoid_grad, x, grad)]
190
205
  when :softmax
191
206
  i_op(:softmax_grad, x, grad)
192
207
  when :softmax_cross_entropy_with_logits_v2
193
- # -grad * tf.reciprocal(i_op(:softmax, x))
194
208
  [i_op(:softmax_cross_entropy_with_logits_v2_grad, x, y, grad), nil]
195
- # i_op(:softmax_grad, x, -grad * tf.reciprocal(i_op(:softmax, x)))
196
209
  when :floor, :ceil
197
210
  # non differentiable
198
211
  nil
199
212
  when :zeros_like
200
213
  # non differentiable
201
214
  nil
202
- when :argmin, :argmax
215
+ when :argmin, :argmax, :floor_div
203
216
  # non differentiable
204
217
  [nil, nil]
205
218
  else
@@ -217,19 +230,19 @@ module TensorStream
217
230
  _op(:broadcast_transform, input_a, input_b)
218
231
  end
219
232
 
220
- def self._safe_shape_div(x, y)
221
- _op(:floor_div, x , tf.maximum(y, 1))
233
+ def self._safe_shape_div(arg_x, arg_y)
234
+ _op(:floor_div, arg_x, tf.maximum(arg_y, 1))
222
235
  end
223
236
 
224
- def self._sum_grad(x, y, grad)
225
- input_shape = _op(:shape, x)
226
- output_shape_kept_dims = tf.reduced_shape(input_shape, y)
237
+ def self._sum_grad(arg_x, arg_y, grad)
238
+ input_shape = _op(:shape, arg_x)
239
+ output_shape_kept_dims = tf.reduced_shape(input_shape, arg_y)
227
240
  tile_scaling = _safe_shape_div(input_shape, output_shape_kept_dims)
228
241
  new_grad = _op(:reshape, grad, output_shape_kept_dims)
229
242
 
230
- grad = _op(:cond, _op(:fill, input_shape, grad) , _op(:tile, new_grad, tile_scaling), pred: _op(:rank, grad) == 0 )
243
+ grad = _op(:cond, _op(:fill, input_shape, grad), _op(:tile, new_grad, tile_scaling), pred: _op(:rank, grad).zero?)
231
244
 
232
- [grad, nil ]
245
+ [grad, nil]
233
246
  end
234
247
 
235
248
  def self._op_supports_broadcast?(node)
@@ -237,11 +250,21 @@ module TensorStream
237
250
  false
238
251
  end
239
252
 
240
- def self._min_or_max_grad(op, grad)
241
- y = op
242
- indicators = tf.cast(tf.equal(y, op.inputs[0]), grad.data_type)
243
- num_selected = tf.reduce_sum(indicators, op.inputs[1])
244
- _safe_shape_div(indicators, num_selected) * grad
253
+ def self._min_or_max_grad(inputs, grad, selector_op)
254
+ x = inputs[0]
255
+ y = inputs[1]
256
+ gdtype = grad.data_type
257
+ sx = tf.shape(x)
258
+ sy = tf.shape(y)
259
+ gradshape = tf.shape(grad)
260
+ zeros = tf.zeros(gradshape, dtype: gdtype)
261
+ xmask = selector_op.call(x, y)
262
+ rx, ry = _broadcast_gradient_args(sx, sy)
263
+ xgrad = tf.where(xmask, grad, zeros, name: 'x')
264
+ ygrad = tf.where(xmask, zeros, grad, name: 'y')
265
+ gx = tf.reshape(tf.reduce_sum(xgrad, rx), sx)
266
+ gy = tf.reshape(tf.reduce_sum(ygrad, ry), sy)
267
+ [gx, gy]
245
268
  end
246
269
 
247
270
  def self._include?(arr, obj)
@@ -249,4 +272,4 @@ module TensorStream
249
272
  false
250
273
  end
251
274
  end
252
- end
275
+ end
@@ -2,6 +2,7 @@ module TensorStream
2
2
  # High level machine learning functions
3
3
  class NN
4
4
  extend TensorStream::OpHelper
5
+
5
6
  def self.softmax(logits, axis: nil, name: nil)
6
7
  _op(:softmax, logits, nil, axis: axis, name: name)
7
8
  end
@@ -29,8 +30,13 @@ module TensorStream
29
30
  end
30
31
  end
31
32
 
33
+ # Computes log softmax activations.
34
+ def self.log_softmax(logits, axis: -1, name: nil)
35
+ _op(:log_softmax, logits, axis: axis, name: name)
36
+ end
37
+
32
38
  def self.sigmoid_cross_entropy_with_logits(labels: nil, logits: nil, name: nil)
33
- TensorStream.name_scope(name, default: 'logistic_loss', values: [logits, labels]) do |name|
39
+ TensorStream.name_scope(name, default: 'logistic_loss', values: [logits, labels]) do |_name|
34
40
  tf = TensorStream
35
41
  logits = tf.convert_to_tensor(logits, name: 'logits')
36
42
  labels = tf.convert_to_tensor(labels, name: 'labels')
@@ -6,10 +6,10 @@ module TensorStream
6
6
 
7
7
  def initialize(operation, *args)
8
8
  options = if args.last.is_a?(Hash)
9
- args.pop
10
- else
11
- {}
12
- end
9
+ args.pop
10
+ else
11
+ {}
12
+ end
13
13
 
14
14
  inputs = args
15
15
 
@@ -42,24 +42,10 @@ module TensorStream
42
42
  }
43
43
  end
44
44
 
45
- def self.empty_matrix?(input)
46
- if input.is_a?(Array)
47
- input.each do |input|
48
- if input.is_a?(Array)
49
- return false unless empty_matrix?(input)
50
- elsif input != 0 || input != 0.0
51
- return false
52
- end
53
- end
54
- end
55
-
56
- true
57
- end
58
-
59
45
  def infer_const
60
46
  return false if breakpoint
61
47
  case operation
62
- when :random_normal, :random_uniform, :glorot_uniform, :print
48
+ when :random_standard_normal, :random_uniform, :glorot_uniform, :print
63
49
  false
64
50
  else
65
51
  non_const = @inputs.compact.find { |input| !input.is_const }
@@ -75,7 +61,7 @@ module TensorStream
75
61
  :boolean
76
62
  when :shape, :rank
77
63
  options[:out_type] || :int32
78
- when :random_normal, :random_uniform, :glorot_uniform
64
+ when :random_standard_normal, :random_uniform, :glorot_uniform
79
65
  passed_data_type || :float32
80
66
  when :index
81
67
  if @inputs[0].is_a?(ControlFlow)
@@ -150,7 +136,7 @@ module TensorStream
150
136
  "gradient(#{sub_input})"
151
137
  when :stop_gradient
152
138
  sub_input
153
- when :matmul
139
+ when :mat_mul
154
140
  "#{sub_input}.matmul(#{sub_input2})"
155
141
  when :eye
156
142
  "eye(#{sub_input})"
@@ -261,13 +247,13 @@ module TensorStream
261
247
  return TensorShape.fix_inferred_elements(new_shape, input_shape.reduce(:*))
262
248
  when :flow_group
263
249
  return []
264
- when :zeros, :ones
250
+ when :zeros, :ones, :fill
265
251
  return inputs[0] ? inputs[0].value : options[:shape]
266
252
  when :zeros_like, :ones_like
267
253
  inputs[0].shape.shape
268
254
  when :shape
269
255
  return inputs[0].shape.shape ? [inputs[0].shape.shape.size] : nil
270
- when :matmul
256
+ when :mat_mul
271
257
  shape1 = inputs[0].shape.shape.nil? ? nil : inputs[0].shape.shape[0]
272
258
  shape2 = inputs[1].shape.shape.nil? ? nil : inputs[1].shape.shape[1]
273
259
  return [shape1, shape2]
@@ -285,11 +271,12 @@ module TensorStream
285
271
  super
286
272
  @inputs.compact.each do |input|
287
273
  if input.is_a?(Array)
288
- input.flatten.compact.each do |t|
289
- t.send(:propagate_consumer, consumer) if t.is_a?(Tensor)
274
+ input.flatten.compact.select { |t| t.is_a?(Tensor) }.each do |t|
275
+ next if t.consumers.include?(consumer.name)
276
+ t.send(:propagate_consumer, consumer)
290
277
  end
291
- else
292
- input.send(:propagate_consumer, consumer) if input.name != name
278
+ elsif input.name != name && !input.consumers.include?(consumer.name)
279
+ input.send(:propagate_consumer, consumer)
293
280
  end
294
281
  end
295
282
  end
@@ -35,24 +35,24 @@ module TensorStream
35
35
  # ys and xs are each a Tensor or a list of tensors. grad_ys is a list of Tensor, holding the gradients received by the ys. The list must be the same length as ys.
36
36
  #
37
37
  # Arguments:
38
- # +ys+ : A Tensor or list of tensors to be differentiated.
38
+ # +tensor_ys+ : A Tensor or list of tensors to be differentiated.
39
39
  # +wrt_xs+ : A Tensor or list of tensors to be used for differentiation.
40
- # +stop_gradients+: Optional. A Tensor or list of tensors not to differentiate through
41
- def gradients(ys, wrt_xs, name: 'gradients', stop_gradients: nil)
42
-
40
+ # +stop_gradients+ : Optional. A Tensor or list of tensors not to differentiate through
41
+ def gradients(tensor_ys, wrt_xs, name: 'gradients', stop_gradients: nil)
43
42
  gs = wrt_xs.collect do |x|
44
43
  stops = stop_gradients ? stop_gradients.map(&:name).join('_') : ''
45
- gradient_program_name = "grad_#{ys.name}_#{x.name}_#{stops}".to_sym
46
-
47
- tensor_program = if ys.graph.node_added?(gradient_program_name)
48
- ys.graph.get_node(gradient_program_name)
49
- else
50
- ys.graph.name_scope("gradient_wrt_#{x.name}") do
51
- derivative_ops = TensorStream::MathGradients.derivative(ys, x, graph: ys.graph,
52
- stop_gradients: stop_gradients)
53
- ys.graph.add_node!(gradient_program_name, derivative_ops)
54
- end
55
- end
44
+ gradient_program_name = "grad_#{tensor_ys.name}_#{x.name}_#{stops}".to_sym
45
+ tensor_graph = tensor_ys.graph
46
+
47
+ tensor_program = if tensor_graph.node_added?(gradient_program_name)
48
+ tensor_graph.get_node(gradient_program_name)
49
+ else
50
+ tensor_graph.name_scope("gradient_wrt_#{x.name}") do
51
+ derivative_ops = TensorStream::MathGradients.derivative(tensor_ys, x, graph: tensor_graph,
52
+ stop_gradients: stop_gradients)
53
+ tensor_graph.add_node!(gradient_program_name, derivative_ops)
54
+ end
55
+ end
56
56
  tensor_program
57
57
  end
58
58
  TensorStream.group(gs)
@@ -69,7 +69,7 @@ module TensorStream
69
69
  # Outputs random values from a normal distribution.
70
70
  def random_normal(shape, dtype: :float32, mean: 0.0, stddev: 1.0, seed: nil, name: nil)
71
71
  options = { shape: shape, dtype: dtype, mean: mean, stddev: stddev, seed: seed, name: name }
72
- _op(:random_normal, nil, nil, options)
72
+ _op(:random_standard_normal, nil, nil, options)
73
73
  end
74
74
 
75
75
  ##
@@ -86,6 +86,10 @@ module TensorStream
86
86
  _op(:eye, num_rows, num_columns || num_rows, data_type: dtype, name: name)
87
87
  end
88
88
 
89
+ def expand_dims(input, axis = nil, name: nil)
90
+ _op(:expand_dims, input, axis, name: name)
91
+ end
92
+
89
93
  ##
90
94
  # This operation returns a 1-D integer tensor representing the shape of input
91
95
  def shape(input, name: nil, out_type: :int32)
@@ -98,7 +102,9 @@ module TensorStream
98
102
  ##
99
103
  # Constructs a tensor by tiling a given tensor.
100
104
  #
101
- # This operation creates a new tensor by replicating input multiples times. The output tensor's i'th dimension has input.dims(i) * multiples[i] elements, and the values of input are replicated multiples[i] times along the 'i'th dimension. For example, tiling [a b c d] by [2] produces [a b c d a b c d].
105
+ # This operation creates a new tensor by replicating input multiples times.
106
+ # The output tensor's i'th dimension has input.dims(i) * multiples[i] elements,
107
+ # and the values of input are replicated multiples[i] times along the 'i'th dimension. For example, tiling [a b c d] by [2] produces [a b c d a b c d].
102
108
  def tile(input, multiples, name: nil)
103
109
  _op(:tile, input, multiples, name: name)
104
110
  end
@@ -118,7 +124,9 @@ module TensorStream
118
124
  ##
119
125
  # The Glorot uniform initializer, also called Xavier uniform initializer.
120
126
  #
121
- # It draws samples from a uniform distribution within [-limit, limit] where limit is sqrt(6 / (fan_in + fan_out)) where fan_in is the number of input units in the weight tensor and fan_out is the number of output units in the weight tensor.
127
+ # It draws samples from a uniform distribution within [-limit, limit]
128
+ # where limit is sqrt(6 / (fan_in + fan_out)) where fan_in is the number
129
+ # of input units in the weight tensor and fan_out is the number of output units in the weight tensor.
122
130
  def glorot_uniform_initializer(seed: nil, dtype: nil)
123
131
  TensorStream::Initializer.new(-> { _op(:glorot_uniform, nil, nil, seed: seed, data_type: dtype) })
124
132
  end
@@ -132,7 +140,9 @@ module TensorStream
132
140
  ##
133
141
  # Extracts a slice from a tensor.
134
142
  #
135
- # This operation extracts a slice of size size from a tensor input starting at the location specified by begin. The slice size is represented as a tensor shape, where size[i] is the number of elements of the 'i'th dimension of input that you want to slice. The starting location (begin) for the slice is represented as an offset in each dimension of input. In other words, begin[i] is the offset into the 'i'th dimension of input that you want to slice from.
143
+ # This operation extracts a slice of size size from a tensor input starting at the location specified by begin.
144
+ # The slice size is represented as a tensor shape, where size[i] is the number of elements of the 'i'th dimension of input that you want to slice. The starting location (begin) for the slice is
145
+ # represented as an offset in each dimension of input. In other words, begin[i] is the offset into the 'i'th dimension of input that you want to slice from.
136
146
  def slice(input, start, size, name: nil)
137
147
  _op(:slice, input, start, size: size, name: name)
138
148
  end
@@ -188,7 +198,7 @@ module TensorStream
188
198
 
189
199
  ##
190
200
  # Returns the truth value of (x >= y) element-wise.
191
- #
201
+ #
192
202
  # This operation supports broadcasting
193
203
  def greater_equal(input_a, input_b, name: nil)
194
204
  input_a, input_b = check_data_types(input_a, input_b)
@@ -205,14 +215,17 @@ module TensorStream
205
215
  ##
206
216
  # Computes the mean of elements across dimensions of a tensor.
207
217
  def reduce_mean(input_tensor, axis = nil, keepdims: false, name: nil)
208
- _op(:mean, input_tensor, axis, keepdims: keepdims, name: name)
218
+ _op(:mean, input_tensor, axis, keepdims: keepdims, name: name)
209
219
  end
210
220
 
211
221
  ##
212
222
  # Computes the sum of elements across dimensions of a tensor.
213
223
  #
214
- # Reduces input_tensor along the dimensions given in axis. Unless keepdims is true, the rank of the tensor is reduced by 1 for each entry in axis. If keepdims is true, the reduced dimensions are retained with length 1.
215
- # If axis has no entries, all dimensions are reduced, and a tensor with a single element is returned.
224
+ # Reduces input_tensor along the dimensions given in axis. Unless keepdims is true,
225
+ # the rank of the tensor is reduced by 1 for each entry in axis. If keepdims is true,
226
+ # the reduced dimensions are retained with length 1.
227
+ # If axis has no entries, all dimensions are reduced, and a tensor with a single element
228
+ # is returned.
216
229
  def reduce_sum(input_tensor, axis = nil, keepdims: false, name: nil)
217
230
  _op(:sum, input_tensor, axis, keepdims: keepdims, name: name)
218
231
  end
@@ -220,7 +233,9 @@ module TensorStream
220
233
  ##
221
234
  # Computes the product of elements across dimensions of a tensor.
222
235
  #
223
- # Reduces input_tensor along the dimensions given in axis. Unless keepdims is true, the rank of the tensor is reduced by 1 for each entry in axis. If keepdims is true, the reduced dimensions are retained with length 1.
236
+ # Reduces input_tensor along the dimensions given in axis. Unless keepdims is true, the rank of the
237
+ # tensor is reduced by 1 for each entry in axis. If keepdims is true, the reduced dimensions are
238
+ # retained with length 1.
224
239
  #
225
240
  # If axis has no entries, all dimensions are reduced, and a tensor with a single element is returned.
226
241
  def reduce_prod(input, axis = nil, keepdims: false, name: nil)
@@ -281,6 +296,28 @@ module TensorStream
281
296
  _op(:add, input_a, input_b, name: name)
282
297
  end
283
298
 
299
+ ##
300
+ # Adds all input tensors element-wise.
301
+ #
302
+ # Elements must all be the same shape and type
303
+ def add_n(inputs, name: nil)
304
+ _op(:add_n, *inputs, name: name)
305
+ end
306
+
307
+ ##
308
+ # Computes asin of input element-wise
309
+ def asin(input, name: nil)
310
+ check_allowed_types(input, FLOATING_POINT_TYPES)
311
+ _op(:asin, input, name: name)
312
+ end
313
+
314
+ ##
315
+ # Computes acos of input element-wise
316
+ def acos(input, name: nil)
317
+ check_allowed_types(input, FLOATING_POINT_TYPES)
318
+ _op(:acos, input, name: name)
319
+ end
320
+
284
321
  ##
285
322
  # Returns x - y element-wise.
286
323
  #
@@ -329,10 +366,22 @@ module TensorStream
329
366
  ##
330
367
  # Returns the max of x and y (i.e. x > y ? x : y) element-wise.
331
368
  def maximum(input_a, input_b, name: nil)
369
+ max(input_a, input_b, name: name)
370
+ end
371
+
372
+ ##
373
+ # Returns the min of x and y (i.e. x < y ? x : y) element-wise.
374
+ def min(input_a, input_b, name: nil)
332
375
  check_allowed_types(input_a, NUMERIC_TYPES)
333
376
  check_allowed_types(input_b, NUMERIC_TYPES)
334
377
  input_a, input_b = check_data_types(input_a, input_b)
335
- max(input_a, input_b, name: name)
378
+ _op(:min, input_a, input_b, name: name)
379
+ end
380
+
381
+ ##
382
+ # Returns the min of x and y (i.e. x < y ? x : y) element-wise.
383
+ def minimum(input_a, input_b, name: nil)
384
+ min(input_a, input_b, name: name)
336
385
  end
337
386
 
338
387
  ##
@@ -378,14 +427,18 @@ module TensorStream
378
427
 
379
428
  ##
380
429
  # reates a tensor with all elements set to zero.
381
- # Given a single tensor (tensor), this operation returns a tensor of the same type and shape as tensor with all elements set to zero. Optionally, you can use dtype to specify a new type for the returned tensor.
430
+ # Given a single tensor (tensor), this operation returns a tensor
431
+ # of the same type and shape as tensor with all elements set to zero.
432
+ # Optionally, you can use dtype to specify a new type for the returned tensor.
382
433
  def zeros_like(tensor, dtype: nil, name: nil)
383
434
  _op(:zeros_like, tensor, nil, data_type: dtype, name: name)
384
435
  end
385
436
 
386
437
  ##
387
438
  # Creates a tensor with all elements set to 1.
388
- # Given a single tensor (tensor), this operation returns a tensor of the same type and shape as tensor with all elements set to 1. Optionally, you can specify a new type (dtype) for the returned tensor.
439
+ # Given a single tensor (tensor), this operation returns a
440
+ # tensor of the same type and shape as tensor with all elements set to 1.
441
+ # Optionally, you can specify a new type (dtype) for the returned tensor.
389
442
  def ones_like(tensor, dtype: nil, name: nil)
390
443
  _op(:ones_like, tensor, nil, data_type: dtype, name: name)
391
444
  end
@@ -505,7 +558,7 @@ module TensorStream
505
558
  # For example:
506
559
  # Output tensor has shape [2, 3].
507
560
  # fill([2, 3], 9) => [[9, 9, 9]
508
- # [9, 9, 9]]
561
+ # [9, 9, 9]]
509
562
  def fill(dims, value, name: nil)
510
563
  _op(:fill, dims, value, name: name)
511
564
  end
@@ -524,7 +577,7 @@ module TensorStream
524
577
  transpose_b: false,
525
578
  name: nil)
526
579
  input_a, input_b = check_data_types(input_a, input_b)
527
- _op(:matmul, input_a, input_b, transpose_a: transpose_a, transpose_b: transpose_b, name: name)
580
+ _op(:mat_mul, input_a, input_b, transpose_a: transpose_a, transpose_b: transpose_b, name: name)
528
581
  end
529
582
 
530
583
  ##