tensor_stream 0.5.1 → 0.6.0

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