tensor_stream 0.5.1 → 0.6.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.
@@ -16,22 +16,17 @@ module TensorStream
16
16
  node.consumers.include?(tensor.name) || node.equal?(tensor)
17
17
  end.compact + [wrt_dx.name]
18
18
 
19
- grad = i_op(:ones_like, wrt_dx)
19
+ grad = i_op(:fill, tf.shape(tensor), tf.constant(1, dtype: wrt_dx.data_type))
20
20
 
21
- result = _propagate(grad, tensor, wrt_dx, nodes_to_compute, options[:stop_gradients] || [])
22
- i_op(:truncate, result, tf.shape(wrt_dx))
21
+ _propagate(grad, tensor, wrt_dx, nodes_to_compute, options[:stop_gradients] || [] ) || i_op(:zeros_like, wrt_dx)
23
22
  end
24
23
 
25
24
  def self._propagate(grad, tensor, stop_tensor, nodes_to_compute, stop_gradients = [])
26
- return grad * i_op(:ones_like, stop_tensor) if stop_tensor.equal?(tensor)
27
- return i_op(:zeros_like, stop_tensor) if stop_gradients && _include?(stop_gradients, tensor)
28
- return i_op(:zeros_like, stop_tensor) unless tensor.is_a?(Operation)
25
+ return grad if stop_tensor.equal?(tensor)
26
+ return nil if stop_gradients && _include?(stop_gradients, tensor)
27
+ return nil unless tensor.is_a?(Operation)
29
28
 
30
- computed_op = if _op_supports_broadcast?(tensor)
31
- _compute_derivative(tensor, _broadcast_transform(tensor, grad)[1])
32
- else
33
- _compute_derivative(tensor, grad)
34
- end
29
+ computed_op = _compute_derivative(tensor, grad)
35
30
 
36
31
  if computed_op.is_a?(Array)
37
32
  partials = []
@@ -43,9 +38,9 @@ module TensorStream
43
38
  end
44
39
  end
45
40
 
46
- partials.reduce(:+)
41
+ partials.compact.reduce(:+)
47
42
  else
48
- return tf.zeros_like(stop_tensor) if computed_op.nil?
43
+ return nil if computed_op.nil?
49
44
  _propagate(computed_op, tensor.inputs[0], stop_tensor, nodes_to_compute, stop_gradients)
50
45
  end
51
46
  end
@@ -57,66 +52,74 @@ module TensorStream
57
52
 
58
53
  case node.operation
59
54
  when :add
60
- return [grad, grad] if _shapes_fully_specified_and_equal(x, y)
61
-
55
+ return [grad, grad] if shapes_fully_specified_and_equal(x, y)
62
56
  sx = tf.shape(x, name: 'add/shape_x')
63
57
  sy = tf.shape(y, name: 'add/shape_y')
64
58
  rx, ry = _broadcast_gradient_args(sx, sy)
65
- keep_dims_x = tf.rank(x) == tf.rank(grad)
66
- keep_dims_y = tf.rank(y) == tf.rank(grad)
67
59
 
68
- [tf.reduce_sum(grad, rx, name: 'add/reduce_sum_x', keepdims: keep_dims_x),
69
- tf.reduce_sum(grad, ry, name: 'add/reduce_sum_y', keepdims: keep_dims_y)]
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) ]
70
62
  when :sub
71
- return [grad, -grad] if _shapes_fully_specified_and_equal(x, y)
63
+ return [grad, -grad] if shapes_fully_specified_and_equal(x, y)
72
64
 
73
65
  sx = tf.shape(x, name: 'sub/shape_x')
74
66
  sy = tf.shape(y, name: 'sub/shape_y')
75
67
  rx, ry = _broadcast_gradient_args(sx, sy)
76
- [tf.reduce_sum(grad, rx), -tf.reduce_sum(grad, ry)]
68
+
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) ]
77
71
  when :mul
78
72
  sx = tf.shape(x)
79
73
  sy = tf.shape(y)
80
74
  rx, ry = _broadcast_gradient_args(sx, sy)
81
75
 
82
- [ tf.reduce_sum(tf.mul(grad, y), rx),
83
- tf.reduce_sum(tf.mul(x, grad), ry)]
76
+ [ tf.reshape(tf.reduce_sum(tf.mul(grad, y), rx), sx),
77
+ tf.reshape(tf.reduce_sum(tf.mul(x, grad), ry), sy)]
84
78
  when :div
85
79
  sx = i_op(:shape, x)
86
80
  sy = i_op(:shape, y)
87
81
  rx, ry = _broadcast_gradient_args(sx, sy)
88
82
 
89
- [tf.reduce_sum(tf.div(grad, y), rx),
90
- tf.reduce_sum(grad * tf.div(tf.div(-x, y), y),
91
- ry)]
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)]
87
+ when :mod
88
+ sx = tf.shape(x)
89
+ sy = tf.shape(y)
90
+ rx, ry = _broadcast_gradient_args(sx, sy)
91
+ floor_xy = tf.floor_div(x, y)
92
+ gx = tf.reshape(tf.reduce_sum(grad, rx), sx)
93
+ gy = tf.reshape(tf.reduce_sum(grad * tf.negative(floor_xy), ry), sy)
94
+
95
+ [gx, gy]
96
+ when :squared_difference
97
+ sx = i_op(:shape, x)
98
+ sy = i_op(:shape, y)
99
+ rx, ry = _broadcast_gradient_args(sx, sy)
100
+
101
+ x_grad = tf.mul(2.0, grad) * (x - y)
102
+
103
+ [ tf.reshape(tf.reduce_sum(x_grad, rx), sx),
104
+ tf.reshape(-tf.reduce_sum(x_grad, ry), sy)]
92
105
  when :matmul
93
106
  t_a = node.options[:transpose_a]
94
107
  t_b = node.options[:transpose_b]
95
108
 
96
- s0 = tf.shape(x)
97
- s1 = tf.shape(y)
98
-
99
- identity_0 = tf.ones([ s0[0], s1[1] ], dtype: x.data_type, name: 'matmul/identity0')
100
- identity_1 = tf.ones([ s0[0], s1[1] ], dtype: y.data_type, name: 'matmul/identity1')
101
-
102
- grad_a, grad_b = nil
103
109
  if !t_a && !t_b
104
- grad_a = tf.matmul(identity_0, y, transpose_b: true)
105
- grad_b = tf.matmul(x, identity_1, transpose_a: true)
110
+ grad_a = tf.matmul(grad, y, transpose_b: true)
111
+ grad_b = tf.matmul(x, grad, transpose_a: true)
106
112
  elsif !ta && tb
107
- grad_a = tf.matmul(identity_0, y)
108
- grad_b = tf.matmul(identity_1, x, transpose_a: true)
113
+ grad_a = tf.matmul(grad, y)
114
+ grad_b = tf.matmul(grad, x, transpose_a: true)
109
115
  elsif t_a && !t_b
110
- grad_a = tf.matmul(y, identity_0, transpose_b: true)
111
- grad_b = tf.matmul(x, identity_1)
116
+ grad_a = tf.matmul(y, grad, transpose_b: true)
117
+ grad_b = tf.matmul(x, grad)
112
118
  elsif t_a && t_b
113
- grad_a = tf.matmul(y, identity_0, transpose_a: true, transpose_b: true)
114
- grad_b = tf.matmul(identity_1, x, transpose_a: true, transpose_b: true)
119
+ grad_a = tf.matmul(y, grad, transpose_a: true, transpose_b: true)
120
+ grad_b = tf.matmul(grad, x, transpose_a: true, transpose_b: true)
115
121
  end
116
122
 
117
- grad_a = i_op(:mul, grad, grad_a, name: 'matmul/grad_a_norm_mul_da')
118
- grad_b = i_op(:mul, grad, grad_b, name: 'matmul/grad_b_norm_mul_db')
119
-
120
123
  [grad_a, grad_b]
121
124
  when :sin
122
125
  grad * tf.cos(x)
@@ -153,7 +156,7 @@ module TensorStream
153
156
  -grad
154
157
  when :exp
155
158
  grad * node
156
- when :identity
159
+ when :identity, :print
157
160
  grad
158
161
  when :sum
159
162
  _sum_grad(x, y, grad)
@@ -175,7 +178,7 @@ module TensorStream
175
178
  y_cond = i_op(:cond, i_op(:zeros_like, x), i_op(:ones_like, x), pred: node.options[:pred])
176
179
  [x_cond * grad, y_cond * grad]
177
180
  when :mean
178
- sum_grad = _sum_grad(x, y, grad)
181
+ sum_grad = _sum_grad(x, y, grad)[0]
179
182
  input_shape = tf.shape(x)
180
183
  output_shape = tf.shape(node)
181
184
  factor = _safe_shape_div(tf.reduce_prod(input_shape), tf.reduce_prod(output_shape))
@@ -186,6 +189,10 @@ module TensorStream
186
189
  i_op(:sigmoid_grad, x, grad)
187
190
  when :softmax
188
191
  i_op(:softmax_grad, x, grad)
192
+ when :softmax_cross_entropy_with_logits_v2
193
+ # -grad * tf.reciprocal(i_op(:softmax, x))
194
+ [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)))
189
196
  when :floor, :ceil
190
197
  # non differentiable
191
198
  nil
@@ -202,7 +209,8 @@ module TensorStream
202
209
  end
203
210
 
204
211
  def self._broadcast_gradient_args(input_a, input_b)
205
- [_op(:broadcast_gradient_args, input_b, input_a), _op(:broadcast_gradient_args, input_a, input_b)]
212
+ res = _op(:broadcast_gradient_args, input_a, input_b)
213
+ [res[0], res[1]]
206
214
  end
207
215
 
208
216
  def self._broadcast_transform(input_a, input_b)
@@ -210,11 +218,18 @@ module TensorStream
210
218
  end
211
219
 
212
220
  def self._safe_shape_div(x, y)
213
- x / tf.maximum(y, 1)
221
+ _op(:floor_div, x , tf.maximum(y, 1))
214
222
  end
215
223
 
216
224
  def self._sum_grad(x, y, grad)
217
- tf.ones_like(grad) * grad
225
+ input_shape = _op(:shape, x)
226
+ output_shape_kept_dims = tf.reduced_shape(input_shape, y)
227
+ tile_scaling = _safe_shape_div(input_shape, output_shape_kept_dims)
228
+ new_grad = _op(:reshape, grad, output_shape_kept_dims)
229
+
230
+ grad = _op(:cond, _op(:fill, input_shape, grad) , _op(:tile, new_grad, tile_scaling), pred: _op(:rank, grad) == 0 )
231
+
232
+ [grad, nil ]
218
233
  end
219
234
 
220
235
  def self._op_supports_broadcast?(node)
@@ -233,20 +248,5 @@ module TensorStream
233
248
  arr.each { |a| return true if a.equal?(obj) }
234
249
  false
235
250
  end
236
-
237
- def self._shapes_fully_specified_and_equal(x, y)
238
- return false if !_shape_full_specified(x) || !_shape_full_specified(y)
239
- return false if x.shape.shape != y.shape.shape
240
-
241
- true
242
- end
243
-
244
- def self._shape_full_specified(tensor)
245
- return false if tensor.shape.nil?
246
- return false if tensor.shape.shape.nil?
247
-
248
- tensor.shape.shape.each { |s| return false if s.nil? }
249
- true
250
- end
251
251
  end
252
252
  end
@@ -15,12 +15,16 @@ module TensorStream
15
15
  end
16
16
 
17
17
  def self.softmax_cross_entropy_with_logits(labels: nil, logits: nil, name: nil)
18
- TensorStream.name_scope(name, default: 'softmax_cross_entropy_with_logits', values: [logits, labels]) do |name|
18
+ softmax_cross_entropy_with_logits_v2(labels, logits, name)
19
+ end
20
+
21
+ def self.softmax_cross_entropy_with_logits_v2(labels: nil, logits: nil, name: nil)
22
+ TensorStream.name_scope(name, default: 'softmax_cross_entropy_with_logits', values: [logits, labels]) do
19
23
  tf = TensorStream
20
24
  logits = tf.convert_to_tensor(logits, name: 'logits')
21
25
  labels = tf.convert_to_tensor(labels, name: 'labels')
22
26
  labels = tf.cast(labels, logits.dtype)
23
- softmax_logits = -tf.log(softmax(logits)) * labels
27
+ softmax_logits = _op(:softmax_cross_entropy_with_logits_v2, logits, labels)
24
28
  tf.reduce_sum(softmax_logits, tf.rank(logits) - 1)
25
29
  end
26
30
  end
@@ -69,10 +69,12 @@ module TensorStream
69
69
 
70
70
  def set_data_type(passed_data_type)
71
71
  case operation
72
+ when :fill
73
+ @inputs[1].data_type
72
74
  when :greater, :less, :equal, :not_equal, :greater_equal, :less_equal, :logical_and
73
75
  :boolean
74
76
  when :shape, :rank
75
- :int32
77
+ options[:out_type] || :int32
76
78
  when :random_normal, :random_uniform, :glorot_uniform
77
79
  passed_data_type || :float32
78
80
  when :index
@@ -282,13 +284,25 @@ module TensorStream
282
284
  def propagate_consumer(consumer)
283
285
  super
284
286
  @inputs.compact.each do |input|
285
- input.send(:propagate_consumer, consumer) if input.name != name
287
+ if input.is_a?(Array)
288
+ input.flatten.compact.each do |t|
289
+ t.send(:propagate_consumer, consumer) if t.is_a?(Tensor)
290
+ end
291
+ else
292
+ input.send(:propagate_consumer, consumer) if input.name != name
293
+ end
286
294
  end
287
295
  end
288
296
 
289
297
  def propagate_outputs
290
298
  @inputs.compact.each do |input|
291
- input.send(:setup_output, self) if input.name != self.name
299
+ if input.is_a?(Array)
300
+ input.flatten.compact.each do |t|
301
+ t.send(:setup_output, self) if t.is_a?(Tensor)
302
+ end
303
+ else
304
+ input.send(:setup_output, self) if input.is_a?(Tensor) && (input.name != self.name)
305
+ end
292
306
  end
293
307
  end
294
308
 
@@ -89,6 +89,9 @@ module TensorStream
89
89
  ##
90
90
  # This operation returns a 1-D integer tensor representing the shape of input
91
91
  def shape(input, name: nil, out_type: :int32)
92
+ return constant(shape_eval(input, out_type), dtype: out_type, name: name) if input.is_a?(Array)
93
+ return constant(input.shape.shape, dtype: out_type, name: "Shape/#{input.name}") if shape_full_specified(input)
94
+
92
95
  _op(:shape, input, nil, name: name, out_type: out_type)
93
96
  end
94
97
 
@@ -287,6 +290,24 @@ module TensorStream
287
290
  _op(:sub, input_a, input_b, name: name)
288
291
  end
289
292
 
293
+ ##
294
+ # Returns element-wise remainder of division.
295
+ def mod(input_a, input_b, name: nil)
296
+ input_a, input_b = check_data_types(input_a, input_b)
297
+ _op(:mod, input_a, input_b, name: name)
298
+ end
299
+
300
+ ##
301
+ # Returns element-wise integer divistion.
302
+ def floor_div(input_a, input_b, name: nil)
303
+ input_a, input_b = check_data_types(input_a, input_b)
304
+ _op(:floor_div, input_a, input_b, name: name)
305
+ end
306
+
307
+ def range(start, limit, delta = 1, dtype: nil, name: 'range')
308
+ _op(:range, start, limit, delta, data_type: dtype, name: name)
309
+ end
310
+
290
311
  ##
291
312
  # Returns x - y element-wise.
292
313
  #
@@ -476,6 +497,19 @@ module TensorStream
476
497
  _op(:exp, input, nil, name: name)
477
498
  end
478
499
 
500
+ ##
501
+ # Creates a tensor filled with a scalar value.
502
+ #
503
+ # This operation creates a tensor of shape dims and fills it with value.
504
+ #
505
+ # For example:
506
+ # Output tensor has shape [2, 3].
507
+ # fill([2, 3], 9) => [[9, 9, 9]
508
+ # [9, 9, 9]]
509
+ def fill(dims, value, name: nil)
510
+ _op(:fill, dims, value, name: name)
511
+ end
512
+
479
513
  ##
480
514
  # Computes sigmoid of x element-wise.
481
515
  def sigmoid(input, name: nil)
@@ -512,5 +546,18 @@ module TensorStream
512
546
  def check_numerics(tensor, message, name: nil)
513
547
  _op(:check_numerics, tensor, nil, message: message, name: name)
514
548
  end
549
+
550
+ def size(tensor, name: nil, out_type: :int32)
551
+ _op(:size, tensor, name: name, out_type: out_type)
552
+ end
553
+
554
+ def squared_difference(input_a, input_b, name: nil)
555
+ _op(:squared_difference, input_a, input_b, name: name)
556
+ end
557
+
558
+ def broadcast_gradient_args(shape_a, shape_b, name: nil)
559
+ op_result = _op(:broadcast_gradient_args, shape_a, shape_b, name: name)
560
+ [op_result[0], op_result[1]]
561
+ end
515
562
  end
516
563
  end
@@ -71,7 +71,7 @@ module TensorStream
71
71
  end
72
72
  result = args.collect do |e|
73
73
  value = delegate_to_evaluator(e, context, {})
74
- value.respond_to?(:to_ruby) ? value.to_ruby : value
74
+ recursive_eval(value)
75
75
  end
76
76
  result.size == 1 ? result.first : result
77
77
  end
@@ -122,6 +122,14 @@ module TensorStream
122
122
 
123
123
  protected
124
124
 
125
+ def recursive_eval(value, depth = 2)
126
+ if value.is_a?(Array) && depth > 0
127
+ value.collect { |v| recursive_eval(v, depth - 1) }
128
+ else
129
+ value.respond_to?(:to_ruby) ? value.to_ruby : value
130
+ end
131
+ end
132
+
125
133
  def assign_evaluator(tensor)
126
134
  device = @evaluator_classes.map do |klass|
127
135
  next nil if tensor.is_a?(Operation) && !klass.ops.include?(tensor.operation.to_sym)
@@ -87,6 +87,19 @@ module TensorStream
87
87
  _op(:negate, self, nil)
88
88
  end
89
89
 
90
+ def %(other)
91
+ _a, other = TensorStream.check_data_types(self, other)
92
+ _op(:mod, self, TensorStream.convert_to_tensor(other, dtype: data_type))
93
+ end
94
+
95
+ def floor
96
+ TensorStream.floor(self)
97
+ end
98
+
99
+ def ceil
100
+ TensorStream.ceil(self)
101
+ end
102
+
90
103
  def ==(other)
91
104
  _a, other = TensorStream.check_data_types(self, other)
92
105
  _op(:equal, self, other)
@@ -199,6 +212,8 @@ module TensorStream
199
212
  :int32
200
213
  elsif value.is_a?(Array)
201
214
  return detect_type(value[0])
215
+ elsif value.is_a?(Tensor)
216
+ value.data_type
202
217
  else
203
218
  :float32
204
219
  end
@@ -141,6 +141,10 @@ module TensorStream
141
141
  TensorStream::ControlFlow.new(:group, inputs, nil, name: name)
142
142
  end
143
143
 
144
+ def dynamic_stitch(indices, data, name: nil)
145
+ TensorStream::DynamicStitch.new(:dynamic_stitch, [indices, data], name: name)
146
+ end
147
+
144
148
  def get_variable(name, dtype: nil, shape: nil, initializer: nil, trainable: true, collections: nil)
145
149
  TensorStream::Variable.new(dtype || :float32, nil, shape, collections: collections, name: name, initializer: initializer, trainable: trainable)
146
150
  end
@@ -204,7 +208,7 @@ module TensorStream
204
208
  input_a = convert_to_tensor(input_a)
205
209
  input_b = convert_to_tensor(input_b)
206
210
  end
207
-
211
+
208
212
  if norm_dtype(input_a.data_type) != norm_dtype(input_b.data_type)
209
213
  raise "Value Error: Tensor conversion requested dtype #{input_a.data_type} for tensor type #{input_b.data_type}"
210
214
  end
@@ -1,5 +1,5 @@
1
1
  module TensorStream
2
- VERSION = '0.5.1'.freeze
2
+ VERSION = '0.6.0'.freeze
3
3
 
4
4
  def self.version
5
5
  VERSION
data/lib/tensor_stream.rb CHANGED
@@ -16,6 +16,7 @@ require 'tensor_stream/variable'
16
16
  require 'tensor_stream/operation'
17
17
  require 'tensor_stream/placeholder'
18
18
  require 'tensor_stream/control_flow'
19
+ require 'tensor_stream/dynamic_stitch'
19
20
  require 'tensor_stream/trainer'
20
21
  require 'tensor_stream/nn/nn_ops'
21
22
  require 'tensor_stream/evaluator/evaluator'