tensor_stream 0.9.8 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +31 -14
- data/lib/tensor_stream.rb +4 -0
- data/lib/tensor_stream/constant.rb +41 -0
- data/lib/tensor_stream/control_flow.rb +2 -1
- data/lib/tensor_stream/dynamic_stitch.rb +3 -1
- data/lib/tensor_stream/evaluator/operation_helpers/array_ops_helper.rb +4 -4
- data/lib/tensor_stream/evaluator/ruby/array_ops.rb +74 -23
- data/lib/tensor_stream/evaluator/ruby/math_ops.rb +45 -43
- data/lib/tensor_stream/evaluator/ruby/nn_ops.rb +31 -30
- data/lib/tensor_stream/evaluator/ruby/random_ops.rb +6 -6
- data/lib/tensor_stream/evaluator/ruby_evaluator.rb +46 -111
- data/lib/tensor_stream/graph.rb +61 -12
- data/lib/tensor_stream/graph_builder.rb +3 -3
- data/lib/tensor_stream/graph_deserializers/yaml_loader.rb +38 -0
- data/lib/tensor_stream/graph_serializers/packer.rb +8 -0
- data/lib/tensor_stream/graph_serializers/pbtext.rb +62 -27
- data/lib/tensor_stream/graph_serializers/serializer.rb +2 -2
- data/lib/tensor_stream/graph_serializers/yaml.rb +27 -0
- data/lib/tensor_stream/helpers/infer_shape.rb +15 -9
- data/lib/tensor_stream/helpers/op_helper.rb +17 -6
- data/lib/tensor_stream/helpers/string_helper.rb +32 -1
- data/lib/tensor_stream/helpers/tensor_mixins.rb +135 -0
- data/lib/tensor_stream/math_gradients.rb +19 -12
- data/lib/tensor_stream/monkey_patches/float.rb +7 -0
- data/lib/tensor_stream/monkey_patches/integer.rb +7 -0
- data/lib/tensor_stream/monkey_patches/patch.rb +8 -8
- data/lib/tensor_stream/nn/nn_ops.rb +1 -1
- data/lib/tensor_stream/operation.rb +98 -36
- data/lib/tensor_stream/ops.rb +65 -13
- data/lib/tensor_stream/placeholder.rb +2 -2
- data/lib/tensor_stream/session.rb +15 -3
- data/lib/tensor_stream/tensor.rb +15 -172
- data/lib/tensor_stream/tensor_shape.rb +3 -1
- data/lib/tensor_stream/train/saver.rb +12 -10
- data/lib/tensor_stream/trainer.rb +7 -2
- data/lib/tensor_stream/utils.rb +13 -11
- data/lib/tensor_stream/utils/freezer.rb +37 -0
- data/lib/tensor_stream/variable.rb +17 -11
- data/lib/tensor_stream/variable_scope.rb +3 -1
- data/lib/tensor_stream/version.rb +1 -1
- data/samples/iris.rb +3 -4
- data/samples/linear_regression.rb +9 -5
- data/samples/logistic_regression.rb +11 -9
- data/samples/mnist_data.rb +8 -10
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d311558fd0e0503d46170a6e0d206cfa9eb3d3612143a1b42ef760b548155640
|
4
|
+
data.tar.gz: 5539763e003def63ee40417b9801b10c2694f08cf09f1be10ea3d7fd03cc0a4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1918a785288e1f25fd75798f5743c924d71e4d7bd63012acdb18df41c5d3ee36b15a66a65fff18740885454b8683479d3e733d4111cbbd3e11fd81cec4fc4765
|
7
|
+
data.tar.gz: fe48b102afb40c36d77f92a3a53ffc155db108a705c01d5fd3cfab5e84d88dfd5c1b7a41f19322430e43335d225a526cf63c757030f7e4ac27f1cc2440797f2f
|
data/README.md
CHANGED
@@ -2,17 +2,16 @@
|
|
2
2
|
|
3
3
|
# TensorStream
|
4
4
|
|
5
|
-
|
5
|
+
An opensource machine learning framework for ruby. Designed to run on a wide variety of ruby implementations (JRuby, TruffleRuby, MRI) as well as an option for High Performance computation (OpenCL).
|
6
6
|
|
7
|
-
|
7
|
+
This is a framework is heavily influenced by tensorflow and aims to be familiar with tensorflow users. This is a ground up implementation with no dependency on TensorFlow. Effort has been made to make the programming style as near to TensorFlow as possible, comes with a pure ruby evaluator by default with support for an opencl evaluator for large models and datasets.
|
8
8
|
|
9
|
-
## Features
|
9
|
+
## Goals & Features
|
10
10
|
|
11
|
+
- Easy to use - Improve model readability
|
11
12
|
- Replicates most of the commonly used low-level tensorflow ops (tf.add, tf.constant, tf.placeholder, tf.matmul, tf.sin etc...)
|
12
|
-
- Supports auto-differentiation
|
13
|
-
-
|
14
|
-
- Goal is to be as close to TensorFlow in behavior but with some freedom to add ruby specific enhancements (with lots of test cases)
|
15
|
-
- (08-08-2018) Load pbtext files from tensorflow (Graph.parse_from_string)
|
13
|
+
- Supports auto-differentiation using formal derivation
|
14
|
+
- Extensible - use your own opcode evaluator (OpenCL and Pure ruby currently supported)
|
16
15
|
|
17
16
|
## Compatibility
|
18
17
|
|
@@ -55,7 +54,8 @@ Or install it yourself as:
|
|
55
54
|
|
56
55
|
## Usage
|
57
56
|
|
58
|
-
Usage is similar to how you would use TensorFlow except with ruby syntax
|
57
|
+
Usage is similar to how you would use TensorFlow except with ruby syntax.
|
58
|
+
There are also enhancements to the syntax to make it as consice as possible.
|
59
59
|
|
60
60
|
Linear regression sample:
|
61
61
|
|
@@ -75,18 +75,24 @@ train_Y = [1.7,2.76,2.09,3.19,1.694,1.573,3.366,2.596,2.53,1.221,
|
|
75
75
|
|
76
76
|
n_samples = train_X.size
|
77
77
|
|
78
|
-
X = tf.placeholder("float")
|
79
|
-
|
78
|
+
# X = tf.placeholder("float")
|
79
|
+
X = Float.placeholder
|
80
|
+
|
81
|
+
# Y = tf.placeholder("float")
|
82
|
+
Y = Float.placeholder
|
80
83
|
|
81
84
|
# Set model weights
|
82
|
-
W = tf.variable(rand, name: "weight")
|
83
|
-
|
85
|
+
# W = tf.variable(rand, name: "weight")
|
86
|
+
W = rand.t.var name: "weight"
|
87
|
+
|
88
|
+
# b = tf.variable(rand, name: "bias")
|
89
|
+
b = rand.t.var name: "bias"
|
84
90
|
|
85
91
|
# Construct a linear model
|
86
92
|
pred = X * W + b
|
87
93
|
|
88
94
|
# Mean squared error
|
89
|
-
cost = ((pred - Y) ** 2).reduce
|
95
|
+
cost = ((pred - Y) ** 2).reduce / ( 2 * n_samples)
|
90
96
|
|
91
97
|
# optimizer = TensorStream::Train::MomentumOptimizer.new(learning_rate, momentum, use_nesterov: true).minimize(cost)
|
92
98
|
# optimizer = TensorStream::Train::AdamOptimizer.new(learning_rate).minimize(cost)
|
@@ -134,7 +140,7 @@ Not all ops are available. Available ops are defined in lib/tensor_stream/ops.rb
|
|
134
140
|
|
135
141
|
There are also certain differences with regards to naming conventions, and named parameters:
|
136
142
|
|
137
|
-
# Variables
|
143
|
+
# Variables and Constants
|
138
144
|
|
139
145
|
To make referencing python examples easier it is recommended to use "tf" as the TensorStream namespace
|
140
146
|
|
@@ -157,8 +163,15 @@ Ruby
|
|
157
163
|
|
158
164
|
```ruby
|
159
165
|
w = ts.variable(0, name: 'weights')
|
166
|
+
c = ts.constant(1.0)
|
167
|
+
|
168
|
+
# concise way when initializing using a constant
|
169
|
+
w = 0.t.var name: 'weights'
|
170
|
+
c = 1.0.t
|
160
171
|
```
|
161
172
|
|
173
|
+
Calling .t to Integer, Array and Float types converts it into a tensor
|
174
|
+
|
162
175
|
# Shapes
|
163
176
|
|
164
177
|
Python
|
@@ -173,6 +186,10 @@ Ruby
|
|
173
186
|
```ruby
|
174
187
|
x = ts.placeholder(:float32, shape: [1024, 1024])
|
175
188
|
x = ts.placeholder(:float32, shape: [nil, 1024])
|
189
|
+
|
190
|
+
# Another a bit more terse way
|
191
|
+
x = Float.placeholder shape: [1024, 1024]
|
192
|
+
y = Float.placeholder shape: [nil, 1024]
|
176
193
|
```
|
177
194
|
|
178
195
|
For debugging, each operation or tensor supports the to_math method
|
data/lib/tensor_stream.rb
CHANGED
@@ -13,7 +13,9 @@ require 'tensor_stream/graph'
|
|
13
13
|
require 'tensor_stream/device'
|
14
14
|
require 'tensor_stream/session'
|
15
15
|
require 'tensor_stream/tensor_shape'
|
16
|
+
require 'tensor_stream/helpers/tensor_mixins'
|
16
17
|
require 'tensor_stream/tensor'
|
18
|
+
require 'tensor_stream/constant'
|
17
19
|
require 'tensor_stream/variable'
|
18
20
|
require 'tensor_stream/variable_scope'
|
19
21
|
require 'tensor_stream/operation'
|
@@ -25,8 +27,10 @@ require 'tensor_stream/evaluator/evaluator'
|
|
25
27
|
require 'tensor_stream/graph_serializers/packer'
|
26
28
|
require 'tensor_stream/graph_serializers/serializer'
|
27
29
|
require 'tensor_stream/graph_deserializers/protobuf'
|
30
|
+
require 'tensor_stream/graph_deserializers/yaml_loader'
|
28
31
|
require 'tensor_stream/graph_serializers/pbtext'
|
29
32
|
require 'tensor_stream/graph_serializers/graphml'
|
33
|
+
require 'tensor_stream/graph_serializers/yaml'
|
30
34
|
require 'tensor_stream/math_gradients'
|
31
35
|
require "tensor_stream/debugging/debugging"
|
32
36
|
require 'tensor_stream/utils'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module TensorStream
|
2
|
+
# Class that defines a TensorStream variable
|
3
|
+
class Constant < Tensor
|
4
|
+
def initialize(data_type, rank, shape, options = {})
|
5
|
+
setup_initial_state(options)
|
6
|
+
@data_type = data_type
|
7
|
+
@rank = rank
|
8
|
+
@breakpoint = false
|
9
|
+
@shape = TensorShape.new(shape, rank)
|
10
|
+
@value = nil
|
11
|
+
@options = options
|
12
|
+
@is_const = true
|
13
|
+
@internal = options[:internal]
|
14
|
+
@name = [@graph.get_name_scope, options[:name] || build_name].compact.reject(&:empty?).join('/')
|
15
|
+
@given_name = @name
|
16
|
+
|
17
|
+
if options[:value]
|
18
|
+
if options[:value].is_a?(Array)
|
19
|
+
# check if single dimenstion array is passed
|
20
|
+
options[:value] = _reshape(options[:value], shape.reverse.dup) if shape.size >= 2 && !options[:value].empty? && !options[:value][0].is_a?(Array)
|
21
|
+
|
22
|
+
@value = options[:value].map { |v| v.is_a?(Tensor) ? Tensor.cast_dtype(v, @data_type) : v }
|
23
|
+
elsif !shape.empty?
|
24
|
+
@value = _reshape(Tensor.cast_dtype(options[:value], @data_type), shape.dup)
|
25
|
+
else
|
26
|
+
@value = Tensor.cast_dtype(options[:value], @data_type)
|
27
|
+
end
|
28
|
+
@shape = TensorShape.new(shape_eval(@value))
|
29
|
+
end
|
30
|
+
|
31
|
+
@op = Graph.get_default_graph.add_op!(:const, value: @value, data_type: @data_type, internal_name: @name, shape: @shape)
|
32
|
+
@name = @op.name
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def build_name
|
38
|
+
"Const"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -5,11 +5,12 @@ module TensorStream
|
|
5
5
|
|
6
6
|
def initialize(flow_type, inputs, ops = nil, options = {})
|
7
7
|
setup_initial_state(options)
|
8
|
-
|
8
|
+
@options = options
|
9
9
|
@operation = :"flow_#{flow_type}"
|
10
10
|
@inputs = inputs
|
11
11
|
@name = [@graph.get_name_scope, options[:name] || set_name].compact.join('/')
|
12
12
|
@ops = ops
|
13
|
+
@consumers = Set.new
|
13
14
|
@shape = TensorShape.new([inputs.size])
|
14
15
|
@graph.add_node(self)
|
15
16
|
end
|
@@ -7,8 +7,10 @@ module TensorStream
|
|
7
7
|
setup_initial_state(options)
|
8
8
|
|
9
9
|
@operation = :"flow_#{flow_type}"
|
10
|
-
@
|
10
|
+
@options = options.merge(n: inputs[0].size)
|
11
|
+
@inputs = inputs.flatten(1).map { |i| TensorStream.convert_to_tensor(i) }.map { |i| i ? i.op : nil }
|
11
12
|
|
13
|
+
@consumers = Set.new
|
12
14
|
@data_type = Tensor.detect_type(inputs[1])
|
13
15
|
@name = [@graph.get_name_scope, options[:name] || set_name].compact.join('/')
|
14
16
|
@ops = ops
|
@@ -16,10 +16,10 @@ module TensorStream
|
|
16
16
|
start_index = start.shift
|
17
17
|
current_size = size.shift
|
18
18
|
dimen_size = if current_size == -1
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
input.size - 1
|
20
|
+
else
|
21
|
+
start_index + current_size - 1
|
22
|
+
end
|
23
23
|
|
24
24
|
input[start_index..dimen_size].collect do |item|
|
25
25
|
if item.is_a?(Array)
|
@@ -11,10 +11,14 @@ module TensorStream
|
|
11
11
|
slice_tensor(input, start.dup, size.dup)
|
12
12
|
end
|
13
13
|
|
14
|
-
register_op %i[flow_dynamic_stitch dynamic_stitch] do |
|
15
|
-
|
14
|
+
register_op %i[flow_dynamic_stitch dynamic_stitch] do |context, tensor, inputs|
|
15
|
+
number_of_indexes = tensor.options[:n]
|
16
|
+
indexes = inputs[0...number_of_indexes]
|
17
|
+
data = inputs[number_of_indexes...inputs.size]
|
18
|
+
|
16
19
|
merged = []
|
17
|
-
|
20
|
+
|
21
|
+
merge_dynamic_stitch(merged, indexes, data, context)
|
18
22
|
merged
|
19
23
|
end
|
20
24
|
|
@@ -77,8 +81,6 @@ module TensorStream
|
|
77
81
|
end
|
78
82
|
|
79
83
|
register_op :unstack do |_context, tensor, inputs|
|
80
|
-
value = inputs[0]
|
81
|
-
|
82
84
|
axis = tensor.options[:axis] || 0
|
83
85
|
new_shape = shape_eval(inputs[0])
|
84
86
|
rank = new_shape.size - 1
|
@@ -133,11 +135,9 @@ module TensorStream
|
|
133
135
|
|
134
136
|
if !axis.empty?
|
135
137
|
axis.each do |x|
|
136
|
-
if shape[x]
|
137
|
-
|
138
|
-
|
139
|
-
raise TensorStream::ValueError, "unable to squeeze dimension that does not have a size of 1"
|
140
|
-
end
|
138
|
+
raise TensorStream::ValueError, "unable to squeeze dimension that does not have a size of 1" if shape[x] != 1
|
139
|
+
|
140
|
+
shape[x] = nil
|
141
141
|
end
|
142
142
|
else
|
143
143
|
shape = shape.map { |s| s == 1 ? nil : s }
|
@@ -319,7 +319,7 @@ module TensorStream
|
|
319
319
|
end
|
320
320
|
end
|
321
321
|
|
322
|
-
register_op :pad do |
|
322
|
+
register_op :pad do |_context, tensor, inputs|
|
323
323
|
arr_pad(inputs[0], inputs[1], tensor.data_type)
|
324
324
|
end
|
325
325
|
|
@@ -333,19 +333,9 @@ module TensorStream
|
|
333
333
|
tile.nil? ? [] : tile
|
334
334
|
end
|
335
335
|
|
336
|
-
register_op :cond, noop: true do |context, tensor, inputs|
|
337
|
-
pred = global_eval(tensor, tensor.options[:pred], context)
|
338
|
-
|
339
|
-
if all_true?(pred)
|
340
|
-
global_eval(tensor, inputs[0], context)
|
341
|
-
else
|
342
|
-
global_eval(tensor, inputs[1], context)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
336
|
register_op %i[select where] do |context, tensor, inputs|
|
347
|
-
pred =
|
348
|
-
call_3way_vector_op(pred, inputs[
|
337
|
+
pred = inputs[0]
|
338
|
+
call_3way_vector_op(pred, inputs[1], inputs[2], context, ->(t, u, v) { t ? u : v })
|
349
339
|
end
|
350
340
|
|
351
341
|
register_op :shape do |_context, tensor, inputs|
|
@@ -358,6 +348,67 @@ module TensorStream
|
|
358
348
|
end
|
359
349
|
TensorStream::Evaluator::OutputGroup.new(shapes, shapes.map { tensor.options[:out_type] })
|
360
350
|
end
|
351
|
+
|
352
|
+
register_op :transpose do |_context, _tensor, inputs|
|
353
|
+
shape = shape_eval(inputs[0])
|
354
|
+
rank = get_rank(inputs[0])
|
355
|
+
perm = inputs[1] || (0...rank).to_a.reverse
|
356
|
+
|
357
|
+
if rank == 2 && perm.nil? # use native transpose for general case
|
358
|
+
inputs[0].transpose
|
359
|
+
else
|
360
|
+
arr = inputs[0].flatten
|
361
|
+
|
362
|
+
new_shape = perm.map { |p| shape[p] }
|
363
|
+
new_arr = Array.new(shape.reduce(:*)) { 0 }
|
364
|
+
transpose_with_perm(arr, new_arr, shape, new_shape, perm)
|
365
|
+
TensorShape.reshape(new_arr, new_shape)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
register_op :case, noop: true do |context, tensor, _inputs|
|
370
|
+
pred = global_eval(tensor, tensor.inputs[0], context)
|
371
|
+
result = nil
|
372
|
+
|
373
|
+
if tensor.options[:exclusive]
|
374
|
+
p_true = pred.each_with_index.collect { |p, index| [p, index] }.select { |a| a[0] }
|
375
|
+
raise TensorStream::ValueError, "more than one predicate returns true pos #{p_true.map { |a| a[1] }.join(',')}" if p_true.size > 1
|
376
|
+
end
|
377
|
+
|
378
|
+
pred.each_with_index do |p, index|
|
379
|
+
next unless p
|
380
|
+
|
381
|
+
result = global_eval(tensor, tensor.inputs[2 + index], context)
|
382
|
+
end
|
383
|
+
|
384
|
+
result = global_eval(tensor, tensor.inputs[1], context) if result.nil?
|
385
|
+
|
386
|
+
result
|
387
|
+
end
|
388
|
+
|
389
|
+
register_op :case_grad do |_context, tensor, inputs|
|
390
|
+
index, pred, func, grad = inputs
|
391
|
+
if index < 0 && !pred.find { |p| !!p }
|
392
|
+
grad
|
393
|
+
elsif index >= 0 && pred[index]
|
394
|
+
grad
|
395
|
+
else
|
396
|
+
func = -> { int_type?(tensor.data_type) ? 0 : 0.0 }
|
397
|
+
shape = shape_eval(func)
|
398
|
+
generate_vector(shape, generator: func)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def merge_dynamic_stitch(merged, indexes, data, context)
|
403
|
+
indexes.each_with_index do |ind, m|
|
404
|
+
if ind.is_a?(Array)
|
405
|
+
merge_dynamic_stitch(merged, ind, data[m], context)
|
406
|
+
else
|
407
|
+
ind = ind.is_a?(Tensor) ? complete_eval(ind, context) : ind
|
408
|
+
merged[ind] = data[m]
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
361
412
|
end
|
362
413
|
end
|
363
414
|
end
|
@@ -2,24 +2,20 @@ module TensorStream
|
|
2
2
|
module MathOps
|
3
3
|
def MathOps.included(klass)
|
4
4
|
klass.class_eval do
|
5
|
-
register_op :tanh, no_eval: true do |context,
|
6
|
-
call_op(
|
5
|
+
register_op :tanh, no_eval: true do |context, _tensor, inputs|
|
6
|
+
call_op(inputs[0], context, ->(t, _b) { Math.tanh(t) })
|
7
7
|
end
|
8
8
|
|
9
9
|
register_op :tan, no_eval: true do |context, tensor, inputs|
|
10
|
-
call_op(
|
10
|
+
call_op(inputs[0], context, ->(t, _b) { Math.tan(t) })
|
11
11
|
end
|
12
12
|
|
13
|
-
register_op :atan, no_eval: true do |context,
|
14
|
-
call_op(
|
13
|
+
register_op :atan, no_eval: true do |context, _tensor, inputs|
|
14
|
+
call_op(inputs[0], context, ->(t, _b) { Math.atan(t) })
|
15
15
|
end
|
16
16
|
|
17
|
-
register_op :
|
18
|
-
call_op(
|
19
|
-
end
|
20
|
-
|
21
|
-
register_op :sin, no_eval: true do |context, tensor, inputs|
|
22
|
-
call_op(tensor, inputs[0], context, ->(t, _b) { Math.sin(t) })
|
17
|
+
register_op :sin, no_eval: true do |context, _tensor, inputs|
|
18
|
+
call_op(inputs[0], context, ->(t, _b) { Math.sin(t) })
|
23
19
|
end
|
24
20
|
|
25
21
|
register_op :add, no_eval: true do |context, tensor, inputs|
|
@@ -76,67 +72,67 @@ module TensorStream
|
|
76
72
|
end
|
77
73
|
|
78
74
|
register_op :round, no_eval: true do |context, _tensor, inputs|
|
79
|
-
call_op(
|
75
|
+
call_op(inputs[0], context, ->(t, _b) { t.round })
|
80
76
|
end
|
81
77
|
|
82
|
-
register_op :abs, no_eval: true do |context,
|
83
|
-
call_op(
|
78
|
+
register_op :abs, no_eval: true do |context, _tensor, inputs|
|
79
|
+
call_op(inputs[0], context, ->(t, _b) { t.abs })
|
84
80
|
end
|
85
81
|
|
86
|
-
register_op :asin, no_eval: true do |context,
|
87
|
-
call_op(
|
82
|
+
register_op :asin, no_eval: true do |context, _tensor, inputs|
|
83
|
+
call_op(inputs[0], context, ->(t, _b) { Math.asin(t) })
|
88
84
|
end
|
89
85
|
|
90
|
-
register_op :acos, no_eval: true do |context,
|
91
|
-
call_op(
|
86
|
+
register_op :acos, no_eval: true do |context, _tensor, inputs|
|
87
|
+
call_op(inputs[0], context, ->(t, _b) { Math.acos(t) })
|
92
88
|
end
|
93
89
|
|
94
90
|
register_op :cos, no_eval: true do |context, tensor, inputs|
|
95
|
-
call_op(
|
91
|
+
call_op(inputs[0], context, ->(t, _b) { Math.cos(t) })
|
96
92
|
end
|
97
93
|
|
98
|
-
register_op :log1p, no_eval: true do |context,
|
99
|
-
call_op(
|
94
|
+
register_op :log1p, no_eval: true do |context, _tensor, inputs|
|
95
|
+
call_op(inputs[0], context, ->(t, _b) { Math.log(1 + t) })
|
100
96
|
end
|
101
97
|
|
102
|
-
register_op :log, no_eval: true do |context,
|
103
|
-
call_op(
|
98
|
+
register_op :log, no_eval: true do |context, _tensor, inputs|
|
99
|
+
call_op(inputs[0], context, ->(t, _b) { t < 0 ? Float::NAN : Math.log(t) })
|
104
100
|
end
|
105
101
|
|
106
|
-
register_op :exp, no_eval: true do |context,
|
107
|
-
call_op(
|
102
|
+
register_op :exp, no_eval: true do |context, _tensor, inputs|
|
103
|
+
call_op(inputs[0], context, ->(t, _b) { Math.exp(t) })
|
108
104
|
end
|
109
105
|
|
110
|
-
register_op :sigmoid, no_eval: true do |context,
|
111
|
-
call_op(
|
106
|
+
register_op :sigmoid, no_eval: true do |context, _tensor, inputs|
|
107
|
+
call_op(inputs[0], context, ->(t, _b) { sigmoid(t) })
|
112
108
|
end
|
113
109
|
|
114
|
-
register_op :sqrt, no_eval: true do |context,
|
115
|
-
call_op(
|
110
|
+
register_op :sqrt, no_eval: true do |context, _tensor, inputs|
|
111
|
+
call_op(inputs[0], context, ->(t, _b) { Math.sqrt(t) })
|
116
112
|
end
|
117
113
|
|
118
|
-
register_op :floor, no_eval: true do |context,
|
119
|
-
call_op(
|
114
|
+
register_op :floor, no_eval: true do |context, _tensor, inputs|
|
115
|
+
call_op(inputs[0], context, ->(t, _b) { t.floor })
|
120
116
|
end
|
121
117
|
|
122
|
-
register_op :ceil, no_eval: true do |context,
|
123
|
-
call_op(
|
118
|
+
register_op :ceil, no_eval: true do |context, _tensor, inputs|
|
119
|
+
call_op(inputs[0], context, ->(t, _b) { t.ceil })
|
124
120
|
end
|
125
121
|
|
126
|
-
register_op :square, no_eval: true do |context,
|
127
|
-
call_op(
|
122
|
+
register_op :square, no_eval: true do |context, _tensor, inputs|
|
123
|
+
call_op(inputs[0], context, ->(t, _b) { t * t })
|
128
124
|
end
|
129
125
|
|
130
|
-
register_op :reciprocal, no_eval: true do |context,
|
131
|
-
call_op(
|
126
|
+
register_op :reciprocal, no_eval: true do |context, _tensor, inputs|
|
127
|
+
call_op(inputs[0], context, ->(t, _b) { 1 / t })
|
132
128
|
end
|
133
129
|
|
134
130
|
register_op %i[neg negate], no_eval: true do |context, tensor, inputs|
|
135
131
|
call_vector_op(tensor, :negate, inputs[0], nil, context, ->(t, _u) { -t })
|
136
132
|
end
|
137
133
|
|
138
|
-
register_op :tanh_grad, no_eval: true do |context,
|
139
|
-
call_op(
|
134
|
+
register_op :tanh_grad, no_eval: true do |context, _tensor, inputs|
|
135
|
+
call_op(inputs[0], context, ->(t, _b) { 1 - Math.tanh(t) * Math.tanh(t) })
|
140
136
|
end
|
141
137
|
|
142
138
|
register_op(%i[argmax arg_max]) do |_context, tensor, inputs|
|
@@ -170,16 +166,13 @@ module TensorStream
|
|
170
166
|
end
|
171
167
|
|
172
168
|
register_op :cumprod do |context, tensor, inputs|
|
173
|
-
x = inputs[0]
|
174
169
|
c = fp_type?(tensor.data_type) ? 1.0 : 1
|
175
170
|
reverse_option = tensor.options[:reverse]
|
176
171
|
exclusive = tensor.options[:exclusive]
|
177
|
-
|
178
172
|
func = lambda do |arr|
|
179
173
|
return c if arr.nil?
|
180
|
-
count = arr.size
|
181
|
-
|
182
174
|
|
175
|
+
count = arr.size
|
183
176
|
arr = arr.reverse if reverse_option
|
184
177
|
arr = [1] + arr if exclusive
|
185
178
|
|
@@ -207,6 +200,7 @@ module TensorStream
|
|
207
200
|
|
208
201
|
register_op :prod, noop: true do |context, tensor, _inputs|
|
209
202
|
c = fp_type?(tensor.data_type) ? 1.0 : 1
|
203
|
+
|
210
204
|
func = lambda do |arr|
|
211
205
|
return c if arr.nil?
|
212
206
|
|
@@ -264,6 +258,14 @@ module TensorStream
|
|
264
258
|
register_op %i[min minimum], noop: true do |context, tensor, inputs|
|
265
259
|
call_vector_op(tensor, :min, inputs[0], inputs[1], context, ->(t, u) { [t, u].min })
|
266
260
|
end
|
261
|
+
|
262
|
+
def reduction(child_context, tensor, func)
|
263
|
+
val = global_eval(tensor, tensor.inputs[0], child_context)
|
264
|
+
axis = global_eval(tensor, tensor.inputs[1], child_context)
|
265
|
+
keep_dims = global_eval(tensor, tensor.options[:keepdims], child_context)
|
266
|
+
|
267
|
+
reduce(val, axis, keep_dims, func)
|
268
|
+
end
|
267
269
|
end
|
268
270
|
end
|
269
271
|
end
|