tensor_stream 0.9.5 → 0.9.6
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/tensor_stream/evaluator/ruby/images_ops.rb +30 -1
- data/lib/tensor_stream/evaluator/ruby/nn_ops.rb +108 -0
- data/lib/tensor_stream/evaluator/ruby_evaluator.rb +2 -2
- data/lib/tensor_stream/helpers/infer_shape.rb +7 -0
- data/lib/tensor_stream/images.rb +4 -4
- data/lib/tensor_stream/math_gradients.rb +30 -0
- data/lib/tensor_stream/monkey_patches/array.rb +36 -0
- data/lib/tensor_stream/monkey_patches/patch.rb +4 -0
- data/lib/tensor_stream/nn/nn_ops.rb +105 -99
- data/lib/tensor_stream/train/saver.rb +12 -7
- data/lib/tensor_stream/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4059c6bb82fc83c5aee32090e9c58231f9fd421afb3aa8bea1cbff4857edeb18
|
4
|
+
data.tar.gz: b7ceee8509455146402c3b3cdf9fa0a63eeec3dfee5512dd6e097221f1247481
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 329eb6875b1add417656537beac95d67c1c061fa3eba3b04031d3ac6f1a20f7e26bf12e66873b70ad575fe7d9f0482c02888f0b544405ba9d73d5b325070966f
|
7
|
+
data.tar.gz: 639a4d90dc1525e063bcdac3b30805a38697b009634d17cb745c99189b88b10b95ce49a9136d5c9c0617fbf3ca3ee1a74429a8579437b7896954ff6529952e79
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.9.5] - 2018-11-05
|
8
|
+
- [NEW OP] assert_equal, relu6
|
9
|
+
- [TRAINING] learning_rate_decay, dropout
|
10
|
+
- [BUG FIX] argmin, argmax now works properly
|
11
|
+
- [BUG FIX] shape inference fixes
|
12
|
+
|
7
13
|
## [0.9.2] - 2018-10-19
|
8
14
|
- Add profiling support
|
9
15
|
- Make sure sparse ruby arrays are caught
|
@@ -7,11 +7,25 @@ module TensorStream
|
|
7
7
|
register_op :decode_png do |_context, tensor, inputs|
|
8
8
|
content = inputs[0]
|
9
9
|
channels = tensor.options[:channels]
|
10
|
+
resample_new_shape = tensor.options[:new_shape]
|
11
|
+
resample_method = tensor.options[:resample_method] || :bilinear
|
10
12
|
channels = 4 if channels.zero?
|
11
13
|
|
12
14
|
image = ChunkyPNG::Image.from_blob(content)
|
13
15
|
|
14
16
|
image.grayscale! if channels == 1
|
17
|
+
|
18
|
+
if resample_new_shape
|
19
|
+
case resample_method
|
20
|
+
when :bilinear
|
21
|
+
image.resample_bilinear!(resample_new_shape[1], resample_new_shape[0]) # width, # height
|
22
|
+
when :nearest_neighbor
|
23
|
+
image.resample_nearest_neighbor!(resample_new_shape[1], resample_new_shape[0])
|
24
|
+
else
|
25
|
+
raise TensorStream::ValueError, "invalid resample method provided #{resample_method}. Available (:bilinear, :nearest_neighbor)"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
15
29
|
image_data = image.pixels.collect do |pixel|
|
16
30
|
color_values = if channels == 4
|
17
31
|
[ChunkyPNG::Color.r(pixel),
|
@@ -35,10 +49,13 @@ module TensorStream
|
|
35
49
|
TensorShape.reshape(image_data, [image.height, image.width, channels])
|
36
50
|
end
|
37
51
|
|
38
|
-
register_op :encode_png do |_context,
|
52
|
+
register_op :encode_png do |_context, tensor, inputs|
|
39
53
|
image_data = inputs[0]
|
40
54
|
height, width, channels = shape_eval(image_data)
|
41
55
|
|
56
|
+
resample_new_shape = tensor.options[:new_shape]
|
57
|
+
resample_method = tensor.options[:resample_method] || :bilinear
|
58
|
+
|
42
59
|
png = ChunkyPNG::Image.new(width, height)
|
43
60
|
image_data.each_with_index do |rows, h_index|
|
44
61
|
rows.each_with_index do |p_data, w_index|
|
@@ -51,6 +68,18 @@ module TensorStream
|
|
51
68
|
end
|
52
69
|
end
|
53
70
|
end
|
71
|
+
|
72
|
+
if resample_new_shape
|
73
|
+
case resample_method
|
74
|
+
when :bilinear
|
75
|
+
png.resample_bilinear!(resample_new_shape[1], resample_new_shape[0]) # width, # height
|
76
|
+
when :nearest_neighbor
|
77
|
+
png.resample_nearest_neighbor!(resample_new_shape[1], resample_new_shape[0])
|
78
|
+
else
|
79
|
+
raise TensorStream::ValueError, "invalid resample method provided #{resample_method}. Available (:bilinear, :nearest_neighbor)"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
54
83
|
png.to_s
|
55
84
|
end
|
56
85
|
end
|
@@ -211,6 +211,114 @@ module TensorStream
|
|
211
211
|
register_op :relu6 do |context, tensor, inputs|
|
212
212
|
call_vector_op(tensor, :relu6, inputs[0], inputs[1], context, ->(t, u) { [[t, 0].max, 6].min })
|
213
213
|
end
|
214
|
+
|
215
|
+
register_op :conv2d do |_context, tensor, inputs|
|
216
|
+
filter = inputs[1]
|
217
|
+
filter_shape = shape_eval(filter)
|
218
|
+
strides = tensor.options[:strides]
|
219
|
+
height_stride = strides[1]
|
220
|
+
width_stride = strides[2]
|
221
|
+
|
222
|
+
raise TensorStream::ValueError, " Current implementation does not yet support strides in the batch and depth dimensions." if strides[0] != 1 || strides[3] != 1
|
223
|
+
|
224
|
+
inputs[0].collect do |image|
|
225
|
+
height, width, _channels = shape_eval(image)
|
226
|
+
f_height, f_width, _input_channels, _output_channels = filter_shape
|
227
|
+
|
228
|
+
(0...height).step(height_stride).map do |y|
|
229
|
+
(0...width).step(width_stride).map do |x|
|
230
|
+
filter_result = (0...f_height).map do |f_y|
|
231
|
+
(0...f_width).map do |f_x|
|
232
|
+
f_element = filter[f_y][f_x]
|
233
|
+
|
234
|
+
next if x + f_x >= width
|
235
|
+
next if y + f_y >= height
|
236
|
+
|
237
|
+
image[y + f_y][x + f_x].zip(f_element).map do |image_channel, filter_channels|
|
238
|
+
filter_channels.map { |c| image_channel * c }
|
239
|
+
end
|
240
|
+
end.compact
|
241
|
+
end.flatten(2)
|
242
|
+
|
243
|
+
filter_result.transpose.map { |e| e.reduce(:+) }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
register_op :conv2d_backprop_input do |_context, tensor, inputs|
|
250
|
+
image_shape, filter, grad = inputs
|
251
|
+
|
252
|
+
strides = tensor.options[:strides]
|
253
|
+
|
254
|
+
height_stride = strides[1]
|
255
|
+
width_stride = strides[2]
|
256
|
+
|
257
|
+
filter_shape = shape_eval(filter)
|
258
|
+
|
259
|
+
f_height, f_width, _input_channels, output_channels = filter_shape
|
260
|
+
batch, height, width, channels = image_shape
|
261
|
+
|
262
|
+
Array.new(batch) do |b|
|
263
|
+
image_gradient = TensorShape.reshape(Array.new(height * width * channels) { 0.0 }, [height, width, channels])
|
264
|
+
|
265
|
+
(0...height).step(height_stride).each do |y|
|
266
|
+
(0...width).step(width_stride).each do |x|
|
267
|
+
(0...f_height).each do |f_y|
|
268
|
+
(0...f_width).each do |f_x|
|
269
|
+
next if x + f_x >= width
|
270
|
+
next if y + f_y >= height
|
271
|
+
|
272
|
+
channels.times.each do |c|
|
273
|
+
image_gradient[y + f_y][x + f_x][c] += Array.new(output_channels) do |o_c|
|
274
|
+
filter[f_y][f_x][c][o_c] * grad[b][(y/height_stride) + f_y][(x/width_stride) + f_x][o_c]
|
275
|
+
end.reduce(:+)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
image_gradient
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
register_op :conv2d_backprop_filter do |_context, tensor, inputs|
|
287
|
+
images, filter_shape, grad = inputs
|
288
|
+
|
289
|
+
strides = tensor.options[:strides]
|
290
|
+
height_stride = strides[1]
|
291
|
+
width_stride = strides[2]
|
292
|
+
|
293
|
+
filter_gradient_sum = Array.new(filter_shape.reduce(:*)) { 0.0 }
|
294
|
+
|
295
|
+
images.each_with_index.map do |image, index|
|
296
|
+
height, width, _channels = shape_eval(image)
|
297
|
+
f_height, f_width, input_channels, output_channels = filter_shape
|
298
|
+
|
299
|
+
(0...height).step(height_stride).each do |y|
|
300
|
+
(0...width).step(width_stride).each do |x|
|
301
|
+
filter_result = (0...f_height).map do |f_y|
|
302
|
+
(0...f_width).map do |f_x|
|
303
|
+
|
304
|
+
next Array.new(input_channels * output_channels) { 0.0 } if x + f_x >= width
|
305
|
+
next Array.new(input_channels * output_channels) { 0.0 } if y + f_y >= height
|
306
|
+
|
307
|
+
image[y + f_y][x + f_x].each_with_index.map do |image_channel, c_channel|
|
308
|
+
output_channels.times.map do |o_c|
|
309
|
+
image_channel * grad[index][(y/height_stride) + f_y][(x/width_stride) + f_x][o_c]
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end.flatten
|
314
|
+
|
315
|
+
filter_gradient_sum = multi_array_op(->(a, b) { a + b }, filter_gradient_sum, filter_result)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
TensorShape.reshape(filter_gradient_sum, filter_shape)
|
321
|
+
end
|
214
322
|
end
|
215
323
|
end
|
216
324
|
end
|
@@ -364,7 +364,7 @@ module TensorStream
|
|
364
364
|
|
365
365
|
def get_op_with_axis(a, target_axis, current_axis, op)
|
366
366
|
rank = get_rank(a)
|
367
|
-
return a.
|
367
|
+
return a.send(:"#{op}_index") if rank == 1
|
368
368
|
|
369
369
|
if current_axis == target_axis
|
370
370
|
compare_items = a.collect(&:flatten).transpose
|
@@ -372,7 +372,7 @@ module TensorStream
|
|
372
372
|
elsif a[0].is_a?(Array)
|
373
373
|
a.map { |item| get_op_with_axis(item, target_axis, current_axis + 1, op) }
|
374
374
|
else
|
375
|
-
return a.
|
375
|
+
return a.send(:"#{op}_index")
|
376
376
|
end
|
377
377
|
end
|
378
378
|
|
@@ -171,6 +171,13 @@ module TensorStream
|
|
171
171
|
axis = rank + axis if axis < 0
|
172
172
|
rotated_shape = Array.new(axis + 1) { new_shape.shift }
|
173
173
|
rotated_shape.rotate!(-1) + new_shape
|
174
|
+
when :conv2d
|
175
|
+
return nil unless tensor.inputs[0].shape.known?
|
176
|
+
return nil unless tensor.inputs[1].shape.known?
|
177
|
+
|
178
|
+
new_shape = tensor.inputs[0].shape.shape.dup
|
179
|
+
new_shape[3] = tensor.inputs[1].shape.shape[3]
|
180
|
+
new_shape
|
174
181
|
else
|
175
182
|
return nil if tensor.inputs[0].nil?
|
176
183
|
return tensor.inputs[0].shape.shape if tensor.inputs.size == 1
|
data/lib/tensor_stream/images.rb
CHANGED
@@ -3,14 +3,14 @@ module TensorStream
|
|
3
3
|
extend OpHelper
|
4
4
|
extend TensorStream::Utils
|
5
5
|
|
6
|
-
def self.decode_png(contents, channels: 0, dtype: :uint8, name: nil)
|
7
|
-
_op(:decode_png, contents, channels: channels, data_type: dtype, name: name)
|
6
|
+
def self.decode_png(contents, channels: 0, dtype: :uint8, name: nil, new_shape: nil)
|
7
|
+
_op(:decode_png, contents, channels: channels, data_type: dtype, name: name, new_shape: new_shape)
|
8
8
|
end
|
9
9
|
|
10
|
-
def self.encode_png(contents, compression: -1, name: nil)
|
10
|
+
def self.encode_png(contents, compression: -1, name: nil, new_shape: nil, resample_method: nil)
|
11
11
|
check_allowed_types(contents, %i[uint8 uint16])
|
12
12
|
contents = convert_to_tensor(contents, dtype: :uint16)
|
13
|
-
_op(:encode_png, contents, compression: compression, name: name)
|
13
|
+
_op(:encode_png, contents, compression: compression, name: name, new_shape: new_shape, resample_method: resample_method)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -305,6 +305,8 @@ module TensorStream
|
|
305
305
|
Array.new(node.inputs.size) { |i| res[i] }
|
306
306
|
when :unstack
|
307
307
|
ts.stack(grad, axis: node.options[:axis])
|
308
|
+
when :conv2d
|
309
|
+
_Conv2DGrad(node, grad)
|
308
310
|
when :cast
|
309
311
|
t = %i[float16 float32 float64]
|
310
312
|
src_type = node.inputs[0].data_type
|
@@ -416,5 +418,33 @@ module TensorStream
|
|
416
418
|
out_grads = ts.split(grad, sizes, axis: non_neg_concat_dim, num: op.inputs.size - 1)
|
417
419
|
end_value_index <= dim_index ? out_grads + [nil] : [nil] + out_grads
|
418
420
|
end
|
421
|
+
|
422
|
+
def self._Conv2DGrad(op, grad)
|
423
|
+
# dilations = op.get_attr("dilations")
|
424
|
+
strides = op.options[:strides]
|
425
|
+
padding = op.options[:padding]
|
426
|
+
use_cudnn_on_gpu = op.options[:use_cudnn_on_gpu]
|
427
|
+
data_format = op.options[:data_format]
|
428
|
+
|
429
|
+
shape_0, shape_1 = ts.shape_n([op.inputs[0], op.inputs[1]])
|
430
|
+
[
|
431
|
+
_op(:conv2d_backprop_input,
|
432
|
+
shape_0,
|
433
|
+
op.inputs[1],
|
434
|
+
grad,
|
435
|
+
strides: strides,
|
436
|
+
padding: padding,
|
437
|
+
use_cudnn_on_gpu: use_cudnn_on_gpu,
|
438
|
+
data_format: data_format),
|
439
|
+
_op(:conv2d_backprop_filter,
|
440
|
+
op.inputs[0],
|
441
|
+
shape_1,
|
442
|
+
grad,
|
443
|
+
strides: strides,
|
444
|
+
padding: padding,
|
445
|
+
use_cudnn_on_gpu: use_cudnn_on_gpu,
|
446
|
+
data_format: data_format)
|
447
|
+
]
|
448
|
+
end
|
419
449
|
end
|
420
450
|
end
|
@@ -12,4 +12,40 @@ class Array
|
|
12
12
|
def **(other)
|
13
13
|
TensorStream.convert_to_tensor(self)**other
|
14
14
|
end
|
15
|
+
|
16
|
+
def max_index
|
17
|
+
if first.is_a?(Float)
|
18
|
+
highest = first
|
19
|
+
highest_index = 0
|
20
|
+
each_with_index do |item, index|
|
21
|
+
next if item.nan?
|
22
|
+
|
23
|
+
if item > highest
|
24
|
+
highest = item
|
25
|
+
highest_index = index
|
26
|
+
end
|
27
|
+
end
|
28
|
+
highest_index
|
29
|
+
else
|
30
|
+
index(max)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def min_index
|
35
|
+
if first.is_a?(Float)
|
36
|
+
highest = first
|
37
|
+
highest_index = 0
|
38
|
+
each_with_index do |item, index|
|
39
|
+
next if item.nan?
|
40
|
+
|
41
|
+
if item < highest
|
42
|
+
highest = item
|
43
|
+
highest_index = index
|
44
|
+
end
|
45
|
+
end
|
46
|
+
highest_index
|
47
|
+
else
|
48
|
+
index(min)
|
49
|
+
end
|
50
|
+
end
|
15
51
|
end
|
@@ -3,131 +3,137 @@ module TensorStream
|
|
3
3
|
class NN
|
4
4
|
extend TensorStream::OpHelper
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
class << self
|
7
|
+
def softmax(logits, axis: nil, name: nil)
|
8
|
+
_op(:softmax, logits, nil, axis: axis, name: name)
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
def relu(features, name: nil)
|
12
|
+
TensorStream.max(features, 0, name: "relu_#{name}")
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def relu6(features, name: nil)
|
16
|
+
TensorStream.name_scope(name, "Relu6", values: [features]) do
|
17
|
+
features = TensorStream.convert_to_tensor(features, name: "features")
|
18
|
+
_op(:relu6, features, name: name)
|
19
|
+
end
|
18
20
|
end
|
19
|
-
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
##
|
23
|
+
# Computes dropout.
|
24
|
+
#
|
25
|
+
# With probability keep_prob, outputs the input element scaled up by 1 / keep_prob, otherwise outputs 0. The scaling is so that the expected sum is unchanged.
|
26
|
+
def dropout(x, keep_prob, noise_shape: nil, seed: nil, name: nil)
|
27
|
+
TensorStream.name_scope(name, "dropout", values: [x]) do
|
28
|
+
x = TensorStream.convert_to_tensor(x, name: "x")
|
29
|
+
raise TensorStream::ValueError, "x has to be a floating point tensor since it's going to be scaled. Got a #{x.data_type} tensor instead." unless fp_type?(x.data_type)
|
30
|
+
raise TensorStream::ValueError, "keep_prob must be a scalar tensor or a float in the range (0, 1], got #{keep_prob}" if keep_prob.is_a?(Float) && !(0 < keep_prob && keep_prob <= 1)
|
30
31
|
|
31
|
-
|
32
|
+
return x if keep_prob.is_a?(Float) && keep_prob.to_f == 1.0
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
keep_prob = TensorStream.convert_to_tensor(keep_prob, dtype: x.dtype, name: "keep_prob")
|
35
|
+
return x if keep_prob.value == 1.0
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
noise_shape = if noise_shape.nil?
|
38
|
+
TensorStream.shape(x)
|
39
|
+
else
|
40
|
+
noise_shape
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
43
|
+
random_tensor = keep_prob
|
44
|
+
random_tensor += TensorStream.random_uniform(noise_shape, seed: seed, dtype: x.dtype)
|
44
45
|
|
45
|
-
|
46
|
-
|
46
|
+
binary_tensor = TensorStream.floor(random_tensor)
|
47
|
+
TensorStream.div(x, keep_prob) * binary_tensor
|
48
|
+
end
|
47
49
|
end
|
48
|
-
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
def sigmoid(input, name: nil)
|
52
|
+
TensorStream.sigmoid(input, name: name)
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
def softmax_cross_entropy_with_logits(labels: nil, logits: nil, name: nil)
|
56
|
+
softmax_cross_entropy_with_logits_v2(labels: labels, logits: logits, name: name)
|
57
|
+
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
def softmax_cross_entropy_with_logits_v2(labels: nil, logits: nil, name: nil)
|
60
|
+
TensorStream.name_scope(name, default: 'softmax_cross_entropy_with_logits', values: [logits, labels]) do
|
61
|
+
ts = TensorStream
|
62
|
+
logits = ts.convert_to_tensor(logits, name: 'logits')
|
63
|
+
labels = ts.convert_to_tensor(labels, name: 'labels')
|
64
|
+
labels = ts.cast(labels, logits.dtype)
|
64
65
|
|
65
|
-
|
66
|
-
|
66
|
+
output = _op(:softmax_cross_entropy_with_logits_v2, logits, labels)
|
67
|
+
output[0]
|
68
|
+
end
|
67
69
|
end
|
68
|
-
end
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
71
|
+
def sparse_softmax_cross_entropy_with_logits(labels: nil, logits: nil, name: nil)
|
72
|
+
TensorStream.name_scope(name, default: "SparseSoftmaxCrossEntropyWithLogits", values: [logits, labels]) do
|
73
|
+
tf = TensorStream
|
74
|
+
labels = tf.convert_to_tensor(labels)
|
75
|
+
logits = tf.convert_to_tensor(logits)
|
76
|
+
precise_logits = logits.data_type == :float16 ? tf.cast(logits, :float32) : logits
|
77
|
+
|
78
|
+
labels_static_shape = labels.shape
|
79
|
+
labels_shape = tf.shape(labels)
|
80
|
+
static_shapes_fully_defined = labels_static_shape.known? && logits.shape.known?
|
81
|
+
|
82
|
+
raise TensorStream::ValueError, "Logits cannot be scalars - received shape #{logits.shape.shape}." if logits.shape.known? && logits.shape.scalar?
|
83
|
+
raise TensorStream::ValueError, "Rank mismatch: Rank of labels (received #{labels_static_shape.ndims}) " +
|
84
|
+
"should equal rank of logits minus 1 (received #{logits.shape.ndims})." if logits.shape.known? && (labels_static_shape.known? && labels_static_shape.ndims != logits.shape.ndims - 1)
|
85
|
+
if logits.shape.ndims == 2
|
86
|
+
cost = _op(:sparse_softmax_cross_entropy_with_logits,
|
87
|
+
precise_logits, labels, name: name)
|
88
|
+
if logits.data_type == :float16
|
89
|
+
return tf.cast(cost[0], :float16)
|
90
|
+
else
|
91
|
+
return cost[0]
|
92
|
+
end
|
91
93
|
end
|
92
|
-
end
|
93
94
|
|
94
|
-
|
95
|
+
shape_checks = []
|
95
96
|
|
96
|
-
|
97
|
+
shape_checks << tf.assert_equal(tf.rank(labels), tf.rank(logits) - 1) unless static_shapes_fully_defined
|
97
98
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
99
|
+
tf.control_dependencies(shape_checks) do
|
100
|
+
num_classes = tf.shape(logits)[tf.rank(logits) - 1]
|
101
|
+
precise_logits = tf.reshape(precise_logits, [-1, num_classes])
|
102
|
+
labels = tf.reshape(labels, [-1])
|
103
|
+
cost = _op(:sparse_softmax_cross_entropy_with_logits, precise_logits, labels, name: name)
|
104
|
+
cost = tf.reshape(cost[0], labels_shape)
|
104
105
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
106
|
+
if logits.data_type == :float16
|
107
|
+
tf.cast(cost, :float16)
|
108
|
+
else
|
109
|
+
cost
|
110
|
+
end
|
109
111
|
end
|
110
112
|
end
|
111
113
|
end
|
112
|
-
end
|
113
114
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
115
|
+
# Computes log softmax activations.
|
116
|
+
def log_softmax(logits, axis: -1, name: nil)
|
117
|
+
_op(:log_softmax, logits, axis: axis, name: name)
|
118
|
+
end
|
119
|
+
|
120
|
+
def sigmoid_cross_entropy_with_logits(labels: nil, logits: nil, name: nil)
|
121
|
+
TensorStream.name_scope(name, default: 'logistic_loss', values: [logits, labels]) do |_name|
|
122
|
+
tf = TensorStream
|
123
|
+
logits = tf.convert_to_tensor(logits, name: 'logits')
|
124
|
+
labels = tf.convert_to_tensor(labels, name: 'labels')
|
125
|
+
zeros = tf.zeros_like(logits, dtype: logits.dtype)
|
126
|
+
cond = (logits >= zeros)
|
127
|
+
relu_logits = tf.where(cond, logits, zeros)
|
128
|
+
neg_abs_logits = tf.where(cond, -logits, logits)
|
129
|
+
|
130
|
+
tf.add(relu_logits - logits * labels,
|
131
|
+
tf.log1p(tf.exp(neg_abs_logits)), name: name)
|
132
|
+
end
|
133
|
+
end
|
118
134
|
|
119
|
-
|
120
|
-
|
121
|
-
tf = TensorStream
|
122
|
-
logits = tf.convert_to_tensor(logits, name: 'logits')
|
123
|
-
labels = tf.convert_to_tensor(labels, name: 'labels')
|
124
|
-
zeros = tf.zeros_like(logits, dtype: logits.dtype)
|
125
|
-
cond = (logits >= zeros)
|
126
|
-
relu_logits = tf.where(cond, logits, zeros)
|
127
|
-
neg_abs_logits = tf.where(cond, -logits, logits)
|
128
|
-
|
129
|
-
tf.add(relu_logits - logits * labels,
|
130
|
-
tf.log1p(tf.exp(neg_abs_logits)), name: name)
|
135
|
+
def conv2d(input, filter, strides, padding, name: nil)
|
136
|
+
_op(:conv2d, input, filter, strides: strides, padding: padding, name: name)
|
131
137
|
end
|
132
138
|
end
|
133
139
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'json'
|
2
|
+
require "zlib"
|
2
3
|
|
3
4
|
module TensorStream
|
4
5
|
module Train
|
@@ -12,11 +13,12 @@ module TensorStream
|
|
12
13
|
write_meta_graph: true,
|
13
14
|
write_state: true,
|
14
15
|
strip_default_attrs: false)
|
15
|
-
|
16
|
+
graph = TensorStream::Graph.get_default_graph
|
17
|
+
vars = graph.get_collection(GraphKeys::GLOBAL_VARIABLES)
|
16
18
|
|
17
19
|
variables = {}
|
18
|
-
|
19
|
-
gs =
|
20
|
+
|
21
|
+
gs = eval_global_step(session, global_step)
|
20
22
|
output_dump = {
|
21
23
|
'variables' => variables,
|
22
24
|
'global_step' => gs
|
@@ -24,7 +26,7 @@ module TensorStream
|
|
24
26
|
|
25
27
|
vars.each do |variable|
|
26
28
|
val = variable.read_value
|
27
|
-
packed_data = TensorStream::Packer.pack(val, variable.data_type)
|
29
|
+
packed_data = Zlib::Deflate.deflate(TensorStream::Packer.pack(val, variable.data_type))
|
28
30
|
variables[variable.name] = {
|
29
31
|
'shape' => shape_eval(val),
|
30
32
|
'data' => Base64.strict_encode64(packed_data)
|
@@ -36,18 +38,21 @@ module TensorStream
|
|
36
38
|
|
37
39
|
new_filename = File.join(path, [basename, gs].compact.join('-'))
|
38
40
|
File.write(new_filename, output_dump.to_yaml)
|
39
|
-
|
41
|
+
if write_meta_graph
|
42
|
+
graph_filename = "#{basename}.pbtext"
|
43
|
+
TensorStream.train.write_graph(graph, path, graph_filename)
|
44
|
+
end
|
40
45
|
path
|
41
46
|
end
|
42
47
|
|
43
48
|
def restore(_session, inputfile)
|
44
|
-
input_dump = YAML.
|
49
|
+
input_dump = YAML.safe_load(File.read(inputfile))
|
45
50
|
|
46
51
|
vars = TensorStream::Graph.get_default_graph.get_collection(GraphKeys::GLOBAL_VARIABLES)
|
47
52
|
vars.each do |variable|
|
48
53
|
next unless input_dump['variables'].key?(variable.name)
|
49
54
|
|
50
|
-
data = TensorStream::Packer.unpack(Base64.decode64(input_dump['variables'][variable.name]['data']), variable.data_type)
|
55
|
+
data = TensorStream::Packer.unpack(Zlib::Inflate.inflate(Base64.decode64(input_dump['variables'][variable.name]['data'])), variable.data_type)
|
51
56
|
shape = input_dump['variables'][variable.name]['shape']
|
52
57
|
variable.buffer = nil
|
53
58
|
variable.value = TensorShape.reshape(data, shape)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tensor_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Emmanuel Dayo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|