tensor_stream 1.0.5 → 1.0.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/USAGE_GUIDE.md +68 -0
- data/lib/tensor_stream/evaluator/ruby/math_ops.rb +18 -0
- data/lib/tensor_stream/generated_stub/ops.rb +196 -162
- data/lib/tensor_stream/generated_stub/stub_file.erb +4 -4
- data/lib/tensor_stream/nn/nn_ops.rb +13 -0
- data/lib/tensor_stream/op_maker.rb +22 -1
- data/lib/tensor_stream/operation.rb +2 -10
- data/lib/tensor_stream/ops.rb +0 -8
- data/lib/tensor_stream/ops/bias_add.rb +16 -0
- data/lib/tensor_stream/ops/equal.rb +4 -0
- data/lib/tensor_stream/ops/greater.rb +4 -0
- data/lib/tensor_stream/ops/greater_equal.rb +4 -0
- data/lib/tensor_stream/ops/less.rb +19 -0
- data/lib/tensor_stream/ops/less_equal.rb +4 -0
- data/lib/tensor_stream/ops/not_equal.rb +19 -0
- data/lib/tensor_stream/version.rb +1 -1
- data/samples/neural_networks/lstm.rb +22 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3ecf49d32d385479e8dbf1c4e0ab57f120f3f0b1d78ab201d5032c42e5686f2
|
4
|
+
data.tar.gz: 8a299cbb8d49bac037d827f986478338cad7c3390897d3974557f4b65711da5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37ed2c4b56bf7e859dfd458b87d93acdd1c0dec1079add7a7bee23493d679c2310c55a404f31ad55b64e4e7b2a6d0c46336b715752bc067242c3a496fcd7af70
|
7
|
+
data.tar.gz: be270b79c342832484726f83660e4b391328f41cbf61c4dd0d6f5e0016a040d1f3beac0916f7998b536b5f21336c46c187914b4fa1021c194c0f56fc4f83a4fc
|
data/USAGE_GUIDE.md
CHANGED
@@ -223,6 +223,74 @@ vars = graph.get_collection(TensorStream::GraphKeys::GLOBAL_VARIABLES)
|
|
223
223
|
=> [Variable(Variable:0 shape: TensorShape([]) data_type: float32)]
|
224
224
|
```
|
225
225
|
|
226
|
+
High Performance Computing
|
227
|
+
--------------------------
|
228
|
+
|
229
|
+
TensorStream has been designed from the ground up to support multiple execution backends.
|
230
|
+
|
231
|
+
What this means is you can build your models once and then be able to execute them later on specialized hardware when available like GPUs.
|
232
|
+
|
233
|
+
An OpenCL backend is available that you can use for compute intensive taks like machine learning, especially those that use convolutional networks.
|
234
|
+
|
235
|
+
Using OpenCL is as simple as installing the tensorstream-opencl gem
|
236
|
+
|
237
|
+
```
|
238
|
+
gem install tensor_stream-opencl
|
239
|
+
```
|
240
|
+
|
241
|
+
You can then require the library in your programs and it will get used automatically (assuming you also installed OpenCL drivers for your system)
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
require 'tensor_stream'
|
245
|
+
|
246
|
+
# enable OpenCL
|
247
|
+
require 'tensor_stream/opencl'
|
248
|
+
|
249
|
+
tf = TensorStream
|
250
|
+
|
251
|
+
srand(5)
|
252
|
+
seed = 5
|
253
|
+
tf.set_random_seed(seed)
|
254
|
+
|
255
|
+
SHAPES = [32, 32]
|
256
|
+
tf = TensorStream
|
257
|
+
sess = tf.session
|
258
|
+
large_tensor = tf.constant(sess.run(tf.random_uniform([256, 256])))
|
259
|
+
|
260
|
+
sum_axis_1 = tf.reduce_sum(large_tensor, 1)
|
261
|
+
sess.run(sum_axis_1)
|
262
|
+
```
|
263
|
+
|
264
|
+
Using OpenCL can improve performance dramatically in scenarios involving large tensors:
|
265
|
+
|
266
|
+
```
|
267
|
+
Linux 4.15.0-46-generic #49-Ubuntu SMP
|
268
|
+
model name : AMD Ryzen 3 1300X Quad-Core Processor
|
269
|
+
OpenCL device NVIDIA CUDA GeForce GTX 1060 6GB
|
270
|
+
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-linux]
|
271
|
+
|
272
|
+
user system total real
|
273
|
+
pure ruby softmax : 0.024724 0.000000 0.024724 ( 0.024731)
|
274
|
+
opencl softmax : 0.006237 0.003945 0.010182 ( 0.009005)
|
275
|
+
pure ruby matmul : 0.679538 0.000000 0.679538 ( 0.680048)
|
276
|
+
opencl matmul : 0.003456 0.007965 0.011421 ( 0.008568)
|
277
|
+
pure ruby sum : 3.210619 0.000000 3.210619 ( 3.210064)
|
278
|
+
opencl sum : 0.002431 0.008030 0.010461 ( 0.007522)
|
279
|
+
pure ruby sum axis 1 : 3.208789 0.000000 3.208789 ( 3.208125)
|
280
|
+
opencl sum axis 1 : 0.006075 0.003963 0.010038 ( 0.007679)
|
281
|
+
pure ruby conv2d_backprop : 3.738167 0.000000 3.738167 ( 3.737946)
|
282
|
+
opencl conv2d_backprop : 0.031267 0.003958 0.035225 ( 0.030381)
|
283
|
+
pure ruby conv2d : 0.794182 0.000000 0.794182 ( 0.794100)
|
284
|
+
opencl conv2d : 0.015865 0.004020 0.019885 ( 0.016878)
|
285
|
+
```
|
286
|
+
|
287
|
+
A quick glance shows not a marginal increase but an order of magnitude performance increase in most operations.
|
288
|
+
In fact we are looking at almost a 200x faster compute on operations like matmul and softmax (essential operations in machine learning). This is not a surprise because of the "embarrasingly" parallel nature of machine learning computation. Because of this, GPUs are basically a requirement in most machine learning tasks.
|
289
|
+
|
290
|
+
The code containing these benchmarks can be found at:
|
291
|
+
|
292
|
+
tensor_stream-opencl/benchmark/benchmark.rb
|
293
|
+
|
226
294
|
Limitations
|
227
295
|
-----------
|
228
296
|
|
@@ -37,6 +37,24 @@ module TensorStream
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
register_op :bias_add do |_context, _tensor, inputs|
|
41
|
+
value, bias = inputs
|
42
|
+
arr = value.flatten.each_slice(bias.size).map do |slice|
|
43
|
+
slice.each_with_index.map { |elem, index| elem + bias[index] }
|
44
|
+
end
|
45
|
+
TensorShape.reshape(arr, shape_eval(value))
|
46
|
+
end
|
47
|
+
|
48
|
+
register_op :bias_add_grad do |_context, _tensor, inputs|
|
49
|
+
received_grad = inputs[0]
|
50
|
+
bias_size = shape_eval(received_grad).last
|
51
|
+
grad_sum = Array.new(bias_size) { 0.0 }
|
52
|
+
received_grad.flatten.each_slice(bias_size) do |slice|
|
53
|
+
slice.each_with_index.map { |elem, index| grad_sum[index] += elem }
|
54
|
+
end
|
55
|
+
grad_sum
|
56
|
+
end
|
57
|
+
|
40
58
|
register_op :sub, no_eval: true do |context, tensor, inputs|
|
41
59
|
a, b = inputs
|
42
60
|
call_vector_op(tensor, :sub, a, b, context) { |t, u| t - u }
|
@@ -9,12 +9,12 @@ module TensorStream
|
|
9
9
|
#
|
10
10
|
# This operation supports broadcasting
|
11
11
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# +input_b+:: tensor Y
|
12
|
+
# @param input_a tensor X
|
13
|
+
# @param input_b tensor Y
|
15
14
|
#
|
16
15
|
# Options:
|
17
|
-
#
|
16
|
+
# @option name Optional name
|
17
|
+
# @return Tensor
|
18
18
|
def add(input_a, input_b, name: nil)
|
19
19
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
20
20
|
_op(:add, input_a, input_b, name: name)
|
@@ -25,14 +25,14 @@ module TensorStream
|
|
25
25
|
# Returns the index with the largest value across axes of a tensor.
|
26
26
|
#
|
27
27
|
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# +axis+:: Describes which axis of the input tensor to reduce across. For vectors, use axis = 0 (of type INTEGER_TYPES)
|
28
|
+
# @param input_a tensor X (of type NUMERIC_TYPES)
|
29
|
+
# @param axis Describes which axis of the input tensor to reduce across. For vectors, use axis = 0 (of type INTEGER_TYPES)
|
31
30
|
#
|
32
31
|
# Options:
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
32
|
+
# @option name Optional name
|
33
|
+
# @option dimension Same as axis
|
34
|
+
# @option output_type Output data type defaults to int32 default (:int32)
|
35
|
+
# @return Tensor
|
36
36
|
def argmax(input_a, axis = nil, name: nil, dimension: nil, output_type: :int32)
|
37
37
|
check_allowed_types(input_a, TensorStream::Ops::NUMERIC_TYPES)
|
38
38
|
check_allowed_types(axis, TensorStream::Ops::INTEGER_TYPES)
|
@@ -44,14 +44,14 @@ module TensorStream
|
|
44
44
|
# Returns the index with the smallest value across axes of a tensor.
|
45
45
|
#
|
46
46
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
# +axis+:: Describes which axis of the input tensor to reduce across. For vectors, use axis = 0 (of type INTEGER_TYPES)
|
47
|
+
# @param input_a tensor X (of type NUMERIC_TYPES)
|
48
|
+
# @param axis Describes which axis of the input tensor to reduce across. For vectors, use axis = 0 (of type INTEGER_TYPES)
|
50
49
|
#
|
51
50
|
# Options:
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
51
|
+
# @option name Optional name
|
52
|
+
# @option dimension Same as axis
|
53
|
+
# @option output_type Output data type defaults to int32 default (:int32)
|
54
|
+
# @return Tensor
|
55
55
|
def argmin(input_a, axis = nil, name: nil, dimension: nil, output_type: :int32)
|
56
56
|
check_allowed_types(input_a, TensorStream::Ops::NUMERIC_TYPES)
|
57
57
|
check_allowed_types(axis, TensorStream::Ops::INTEGER_TYPES)
|
@@ -63,11 +63,11 @@ module TensorStream
|
|
63
63
|
# Returns element-wise smallest integer in not less than x
|
64
64
|
#
|
65
65
|
#
|
66
|
-
#
|
67
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
66
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
68
67
|
#
|
69
68
|
# Options:
|
70
|
-
#
|
69
|
+
# @option name Optional name
|
70
|
+
# @return Tensor
|
71
71
|
def ceil(input_a, name: nil)
|
72
72
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
73
73
|
_op(:ceil, input_a, name: name)
|
@@ -78,11 +78,11 @@ module TensorStream
|
|
78
78
|
# Computes cos of input element-wise.
|
79
79
|
#
|
80
80
|
#
|
81
|
-
#
|
82
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
81
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
83
82
|
#
|
84
83
|
# Options:
|
85
|
-
#
|
84
|
+
# @option name Optional name
|
85
|
+
# @return Tensor
|
86
86
|
def cos(input_a, name: nil)
|
87
87
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
88
88
|
_op(:cos, input_a, name: name)
|
@@ -94,12 +94,12 @@ module TensorStream
|
|
94
94
|
#
|
95
95
|
# This operation supports broadcasting
|
96
96
|
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# +input_b+:: tensor Y
|
97
|
+
# @param input_a tensor X
|
98
|
+
# @param input_b tensor Y
|
100
99
|
#
|
101
100
|
# Options:
|
102
|
-
#
|
101
|
+
# @option name Optional name
|
102
|
+
# @return Tensor
|
103
103
|
def div(input_a, input_b, name: nil)
|
104
104
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
105
105
|
_op(:div, input_a, input_b, name: name)
|
@@ -111,12 +111,12 @@ module TensorStream
|
|
111
111
|
#
|
112
112
|
# This operation supports broadcasting
|
113
113
|
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
# +input_b+:: tensor Y
|
114
|
+
# @param input_a tensor X
|
115
|
+
# @param input_b tensor Y
|
117
116
|
#
|
118
117
|
# Options:
|
119
|
-
#
|
118
|
+
# @option name Optional name
|
119
|
+
# @return Tensor
|
120
120
|
def equal(input_a, input_b, name: nil)
|
121
121
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
122
122
|
_op(:equal, input_a, input_b, name: name)
|
@@ -129,12 +129,12 @@ module TensorStream
|
|
129
129
|
# dimension index axis starts at zero; if you specify a negative number for axis it is counted backward from the end.
|
130
130
|
#
|
131
131
|
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
# +axis+:: Specifies the dimension index at which to expand the shape of input. Must be in the range [-rank(input) - 1, rank(input)].
|
132
|
+
# @param input A tensor
|
133
|
+
# @param axis Specifies the dimension index at which to expand the shape of input. Must be in the range [-rank(input) - 1, rank(input)].
|
135
134
|
#
|
136
135
|
# Options:
|
137
|
-
#
|
136
|
+
# @option name Optional name
|
137
|
+
# @return Tensor
|
138
138
|
def expand_dims(input, axis, name: nil)
|
139
139
|
_op(:expand_dims, input, axis, name: name)
|
140
140
|
end
|
@@ -144,12 +144,12 @@ module TensorStream
|
|
144
144
|
# This operation creates a tensor of shape dims and fills it with value.
|
145
145
|
#
|
146
146
|
#
|
147
|
-
#
|
148
|
-
#
|
149
|
-
# +value+:: scalar value to fill with
|
147
|
+
# @param dims tensor shape
|
148
|
+
# @param value scalar value to fill with
|
150
149
|
#
|
151
150
|
# Options:
|
152
|
-
#
|
151
|
+
# @option name Optional name
|
152
|
+
# @return Tensor
|
153
153
|
def fill(dims, value, name: nil)
|
154
154
|
_op(:fill, dims, value, name: name)
|
155
155
|
end
|
@@ -159,11 +159,11 @@ module TensorStream
|
|
159
159
|
# Returns element-wise largest integer not greater than x.
|
160
160
|
#
|
161
161
|
#
|
162
|
-
#
|
163
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
162
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
164
163
|
#
|
165
164
|
# Options:
|
166
|
-
#
|
165
|
+
# @option name Optional name
|
166
|
+
# @return Tensor
|
167
167
|
def floor(input_a, name: nil)
|
168
168
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
169
169
|
_op(:floor, input_a, name: name)
|
@@ -175,12 +175,12 @@ module TensorStream
|
|
175
175
|
#
|
176
176
|
# This operation supports broadcasting
|
177
177
|
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
# +input_b+:: tensor Y
|
178
|
+
# @param input_a tensor X
|
179
|
+
# @param input_b tensor Y
|
181
180
|
#
|
182
181
|
# Options:
|
183
|
-
#
|
182
|
+
# @option name Optional name
|
183
|
+
# @return Tensor
|
184
184
|
def floor_div(input_a, input_b, name: nil)
|
185
185
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
186
186
|
_op(:floor_div, input_a, input_b, name: name)
|
@@ -192,12 +192,12 @@ module TensorStream
|
|
192
192
|
#
|
193
193
|
# This operation supports broadcasting
|
194
194
|
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
# +input_b+:: tensor Y
|
195
|
+
# @param input_a tensor X
|
196
|
+
# @param input_b tensor Y
|
198
197
|
#
|
199
198
|
# Options:
|
200
|
-
#
|
199
|
+
# @option name Optional name
|
200
|
+
# @return Tensor
|
201
201
|
def greater(input_a, input_b, name: nil)
|
202
202
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
203
203
|
_op(:greater, input_a, input_b, name: name)
|
@@ -209,29 +209,46 @@ module TensorStream
|
|
209
209
|
#
|
210
210
|
# This operation supports broadcasting
|
211
211
|
#
|
212
|
-
#
|
213
|
-
#
|
214
|
-
# +input_b+:: tensor Y
|
212
|
+
# @param input_a tensor X
|
213
|
+
# @param input_b tensor Y
|
215
214
|
#
|
216
215
|
# Options:
|
217
|
-
#
|
216
|
+
# @option name Optional name
|
217
|
+
# @return Tensor
|
218
218
|
def greater_equal(input_a, input_b, name: nil)
|
219
219
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
220
220
|
_op(:greater_equal, input_a, input_b, name: name)
|
221
221
|
end
|
222
222
|
|
223
223
|
|
224
|
+
##
|
225
|
+
# Returns the truth value of (x < y) element-wise.
|
226
|
+
#
|
227
|
+
# This operation supports broadcasting
|
228
|
+
#
|
229
|
+
# @param input_a tensor X
|
230
|
+
# @param input_b tensor Y
|
231
|
+
#
|
232
|
+
# Options:
|
233
|
+
# @option name Optional name
|
234
|
+
# @return Tensor
|
235
|
+
def less(input_a, input_b, name: nil)
|
236
|
+
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
237
|
+
_op(:less, input_a, input_b, name: name)
|
238
|
+
end
|
239
|
+
|
240
|
+
|
224
241
|
##
|
225
242
|
# Returns the truth value of (x <= y) element-wise.
|
226
243
|
#
|
227
244
|
# This operation supports broadcasting
|
228
245
|
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
# +input_b+:: tensor Y
|
246
|
+
# @param input_a tensor X
|
247
|
+
# @param input_b tensor Y
|
232
248
|
#
|
233
249
|
# Options:
|
234
|
-
#
|
250
|
+
# @option name Optional name
|
251
|
+
# @return Tensor
|
235
252
|
def less_equal(input_a, input_b, name: nil)
|
236
253
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
237
254
|
_op(:less_equal, input_a, input_b, name: name)
|
@@ -242,11 +259,11 @@ module TensorStream
|
|
242
259
|
# Computes natural logarithm of x element-wise.
|
243
260
|
#
|
244
261
|
#
|
245
|
-
#
|
246
|
-
# +input+:: tensor X
|
262
|
+
# @param input tensor X
|
247
263
|
#
|
248
264
|
# Options:
|
249
|
-
#
|
265
|
+
# @option name Optional name
|
266
|
+
# @return Tensor
|
250
267
|
def log(input, name: nil)
|
251
268
|
_op(:log, input, name: name)
|
252
269
|
end
|
@@ -257,14 +274,14 @@ module TensorStream
|
|
257
274
|
#
|
258
275
|
# This operation supports broadcasting
|
259
276
|
#
|
260
|
-
#
|
261
|
-
#
|
262
|
-
# +input_b+:: tensor Y
|
277
|
+
# @param input_a tensor X
|
278
|
+
# @param input_b tensor Y
|
263
279
|
#
|
264
280
|
# Options:
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
281
|
+
# @option transpose_a Transpose matrix A first default (false)
|
282
|
+
# @option transpose_b Transpose matrix B first default (false)
|
283
|
+
# @option name Optional name
|
284
|
+
# @return Tensor
|
268
285
|
def mat_mul(input_a, input_b, transpose_a: false, transpose_b: false, name: nil)
|
269
286
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
270
287
|
_op(:mat_mul, input_a, input_b, transpose_a: transpose_a, transpose_b: transpose_b, name: name)
|
@@ -277,12 +294,12 @@ module TensorStream
|
|
277
294
|
#
|
278
295
|
# This operation supports broadcasting
|
279
296
|
#
|
280
|
-
#
|
281
|
-
#
|
282
|
-
# +input_b+:: tensor Y (of type NUMERIC_TYPES)
|
297
|
+
# @param input_a tensor X (of type NUMERIC_TYPES)
|
298
|
+
# @param input_b tensor Y (of type NUMERIC_TYPES)
|
283
299
|
#
|
284
300
|
# Options:
|
285
|
-
#
|
301
|
+
# @option name Optional name
|
302
|
+
# @return Tensor
|
286
303
|
def max(input_a, input_b, name: nil)
|
287
304
|
check_allowed_types(input_a, TensorStream::Ops::NUMERIC_TYPES)
|
288
305
|
check_allowed_types(input_b, TensorStream::Ops::NUMERIC_TYPES)
|
@@ -296,12 +313,12 @@ module TensorStream
|
|
296
313
|
#
|
297
314
|
# This operation supports broadcasting
|
298
315
|
#
|
299
|
-
#
|
300
|
-
#
|
301
|
-
# +input_b+:: tensor Y (of type NUMERIC_TYPES)
|
316
|
+
# @param input_a tensor X (of type NUMERIC_TYPES)
|
317
|
+
# @param input_b tensor Y (of type NUMERIC_TYPES)
|
302
318
|
#
|
303
319
|
# Options:
|
304
|
-
#
|
320
|
+
# @option name Optional name
|
321
|
+
# @return Tensor
|
305
322
|
def min(input_a, input_b, name: nil)
|
306
323
|
check_allowed_types(input_a, TensorStream::Ops::NUMERIC_TYPES)
|
307
324
|
check_allowed_types(input_b, TensorStream::Ops::NUMERIC_TYPES)
|
@@ -315,12 +332,12 @@ module TensorStream
|
|
315
332
|
#
|
316
333
|
# This operation supports broadcasting
|
317
334
|
#
|
318
|
-
#
|
319
|
-
#
|
320
|
-
# +input_b+:: tensor Y
|
335
|
+
# @param input_a tensor X
|
336
|
+
# @param input_b tensor Y
|
321
337
|
#
|
322
338
|
# Options:
|
323
|
-
#
|
339
|
+
# @option name Optional name
|
340
|
+
# @return Tensor
|
324
341
|
def mod(input_a, input_b, name: nil)
|
325
342
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
326
343
|
_op(:mod, input_a, input_b, name: name)
|
@@ -332,12 +349,12 @@ module TensorStream
|
|
332
349
|
#
|
333
350
|
# This operation supports broadcasting
|
334
351
|
#
|
335
|
-
#
|
336
|
-
#
|
337
|
-
# +input_b+:: tensor Y
|
352
|
+
# @param input_a tensor X
|
353
|
+
# @param input_b tensor Y
|
338
354
|
#
|
339
355
|
# Options:
|
340
|
-
#
|
356
|
+
# @option name Optional name
|
357
|
+
# @return Tensor
|
341
358
|
def mul(input_a, input_b, name: nil)
|
342
359
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
343
360
|
_op(:mul, input_a, input_b, name: name)
|
@@ -348,16 +365,33 @@ module TensorStream
|
|
348
365
|
# Computes numerical negative value element-wise.
|
349
366
|
#
|
350
367
|
#
|
351
|
-
#
|
352
|
-
# +input+:: tensor X
|
368
|
+
# @param input tensor X
|
353
369
|
#
|
354
370
|
# Options:
|
355
|
-
#
|
371
|
+
# @option name Optional name
|
372
|
+
# @return Tensor
|
356
373
|
def negate(input, name: nil)
|
357
374
|
_op(:negate, input, name: name)
|
358
375
|
end
|
359
376
|
|
360
377
|
|
378
|
+
##
|
379
|
+
# Returns the truth value of (x != y) element-wise.
|
380
|
+
#
|
381
|
+
# This operation supports broadcasting
|
382
|
+
#
|
383
|
+
# @param input_a tensor X
|
384
|
+
# @param input_b tensor Y
|
385
|
+
#
|
386
|
+
# Options:
|
387
|
+
# @option name Optional name
|
388
|
+
# @return Tensor
|
389
|
+
def not_equal(input_a, input_b, name: nil)
|
390
|
+
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
391
|
+
_op(:not_equal, input_a, input_b, name: name)
|
392
|
+
end
|
393
|
+
|
394
|
+
|
361
395
|
##
|
362
396
|
# Creates a tensor with all elements set to 1.
|
363
397
|
# Given a single tensor (tensor), this operation returns a
|
@@ -365,12 +399,12 @@ module TensorStream
|
|
365
399
|
# Optionally, you can specify a new type (dtype) for the returned tensor.
|
366
400
|
#
|
367
401
|
#
|
368
|
-
#
|
369
|
-
# +input+:: A tensor
|
402
|
+
# @param input A tensor
|
370
403
|
#
|
371
404
|
# Options:
|
372
|
-
#
|
373
|
-
#
|
405
|
+
# @option dtype Optional new data type to cast into
|
406
|
+
# @option name Optional name
|
407
|
+
# @return Tensor
|
374
408
|
def ones_like(input, dtype: nil, name: nil)
|
375
409
|
_op(:ones_like, input, data_type: dtype, name: name)
|
376
410
|
end
|
@@ -381,12 +415,12 @@ module TensorStream
|
|
381
415
|
#
|
382
416
|
# This operation supports broadcasting
|
383
417
|
#
|
384
|
-
#
|
385
|
-
#
|
386
|
-
# +input_b+:: tensor Y
|
418
|
+
# @param input_a tensor X
|
419
|
+
# @param input_b tensor Y
|
387
420
|
#
|
388
421
|
# Options:
|
389
|
-
#
|
422
|
+
# @option name Optional name
|
423
|
+
# @return Tensor
|
390
424
|
def pow(input_a, input_b, name: nil)
|
391
425
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
392
426
|
_op(:pow, input_a, input_b, name: name)
|
@@ -401,13 +435,13 @@ module TensorStream
|
|
401
435
|
# If axis has no entries, all dimensions are reduced, and a tensor with a single element is returned.
|
402
436
|
#
|
403
437
|
#
|
404
|
-
#
|
405
|
-
#
|
406
|
-
# +axis+:: tensor X (of type INTEGER_TYPES)
|
438
|
+
# @param input_a tensor X
|
439
|
+
# @param axis tensor X (of type INTEGER_TYPES)
|
407
440
|
#
|
408
441
|
# Options:
|
409
|
-
#
|
410
|
-
#
|
442
|
+
# @option name Optional name
|
443
|
+
# @option keepdims If true, retains reduced dimensions with length 1. default (false)
|
444
|
+
# @return Tensor
|
411
445
|
def prod(input_a, axis = nil, name: nil, keepdims: false)
|
412
446
|
check_allowed_types(axis, TensorStream::Ops::INTEGER_TYPES)
|
413
447
|
input_a = TensorStream.convert_to_tensor(input_a)
|
@@ -422,15 +456,15 @@ module TensorStream
|
|
422
456
|
# Outputs random values from a uniform distribution.
|
423
457
|
#
|
424
458
|
#
|
425
|
-
#
|
426
|
-
# +shape+:: A 1-D integer Tensor or array. The shape of the output tensor.
|
459
|
+
# @param shape A 1-D integer Tensor or array. The shape of the output tensor.
|
427
460
|
#
|
428
461
|
# Options:
|
429
|
-
#
|
430
|
-
#
|
431
|
-
#
|
432
|
-
#
|
433
|
-
#
|
462
|
+
# @option name Optional name
|
463
|
+
# @option dtype The type of the output: float16, float32, float64, int32, or int64 default (:float32)
|
464
|
+
# @option minval A 0-D Tensor or ruby value of type dtype. The lower bound on the range of random values to generate. Defaults to 0. default (0)
|
465
|
+
# @option maxval A 0-D Tensor or ruby value of type dtype. The upper bound on the range of random values to generate. Defaults to 1 if dtype is floating point. default (1)
|
466
|
+
# @option seed A ruby integer. Used to create a random seed for the distribution. See set_random_seed for behavior.
|
467
|
+
# @return Tensor
|
434
468
|
def random_uniform(shape, name: nil, dtype: :float32, minval: 0, maxval: 1, seed: nil)
|
435
469
|
_op(:random_uniform, shape, name: name, dtype: dtype, minval: minval, maxval: maxval, seed: seed)
|
436
470
|
end
|
@@ -441,15 +475,15 @@ module TensorStream
|
|
441
475
|
# Creates a sequence of numbers that begins at start and extends by increments of delta up to but not including limit.
|
442
476
|
#
|
443
477
|
#
|
444
|
-
#
|
445
|
-
#
|
446
|
-
#
|
447
|
-
# +delta+:: Number that increments start. Defaults to 1.
|
478
|
+
# @param start Acts as first entry in the range if limit is not nil; otherwise, acts as range limit and first entry defaults to 0.
|
479
|
+
# @param limit Upper limit of sequence, exclusive. If nil, defaults to the value of start while the first entry of the range defaults to 0.
|
480
|
+
# @param delta Number that increments start. Defaults to 1.
|
448
481
|
#
|
449
482
|
# Options:
|
450
|
-
#
|
451
|
-
#
|
452
|
-
#
|
483
|
+
# @option name A name for the operation. Defaults to "range". default ("range")
|
484
|
+
# @option dtype The type of the elements of the resulting tensor.
|
485
|
+
# @option output_type Output data type defaults to int32 default (:int32)
|
486
|
+
# @return Tensor
|
453
487
|
def range(start = 0, limit = 0, delta = 1, name: "range", dtype: nil, output_type: :int32)
|
454
488
|
_op(:range, start, limit, delta, name: name, dtype: dtype, output_type: output_type)
|
455
489
|
end
|
@@ -459,11 +493,11 @@ module TensorStream
|
|
459
493
|
# Returns the rank of a tensor
|
460
494
|
#
|
461
495
|
#
|
462
|
-
#
|
463
|
-
# +input+:: A tensor
|
496
|
+
# @param input A tensor
|
464
497
|
#
|
465
498
|
# Options:
|
466
|
-
#
|
499
|
+
# @option name Optional name
|
500
|
+
# @return Tensor
|
467
501
|
def rank(input, name: nil)
|
468
502
|
input = convert_to_tensor(input)
|
469
503
|
return cons(input.shape.ndims) if input.shape.known?
|
@@ -476,12 +510,12 @@ module TensorStream
|
|
476
510
|
# Given tensor, this operation returns a tensor that has the same values as tensor with shape shape.
|
477
511
|
#
|
478
512
|
#
|
479
|
-
#
|
480
|
-
#
|
481
|
-
# +shape+:: A new tensor shape
|
513
|
+
# @param input A tensor
|
514
|
+
# @param shape A new tensor shape
|
482
515
|
#
|
483
516
|
# Options:
|
484
|
-
#
|
517
|
+
# @option name Optional name
|
518
|
+
# @return Tensor
|
485
519
|
def reshape(input, shape, name: nil)
|
486
520
|
_op(:reshape, input, shape, name: name)
|
487
521
|
end
|
@@ -491,11 +525,11 @@ module TensorStream
|
|
491
525
|
# Rounds the values of a tensor to the nearest integer, element-wise
|
492
526
|
#
|
493
527
|
#
|
494
|
-
#
|
495
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
528
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
496
529
|
#
|
497
530
|
# Options:
|
498
|
-
#
|
531
|
+
# @option name Optional name
|
532
|
+
# @return Tensor
|
499
533
|
def round(input_a, name: nil)
|
500
534
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
501
535
|
_op(:round, input_a, name: name)
|
@@ -506,12 +540,12 @@ module TensorStream
|
|
506
540
|
# This operation returns a 1-D integer tensor representing the shape of input
|
507
541
|
#
|
508
542
|
#
|
509
|
-
#
|
510
|
-
# +input+:: A tensor
|
543
|
+
# @param input A tensor
|
511
544
|
#
|
512
545
|
# Options:
|
513
|
-
#
|
514
|
-
#
|
546
|
+
# @option name Optional name
|
547
|
+
# @option out_type Optional output type default (:int32)
|
548
|
+
# @return Tensor
|
515
549
|
def shape(input, name: nil, out_type: :int32)
|
516
550
|
return constant(shape_eval(input, out_type), dtype: out_type, name: "Shape/#{name}") if input.is_a?(Array) && !input[0].is_a?(Tensor)
|
517
551
|
return constant(input.shape.shape, dtype: out_type, name: "Shape/#{input.name}_c") if shape_full_specified(input)
|
@@ -523,11 +557,11 @@ module TensorStream
|
|
523
557
|
# Computes sigmoid of x element-wise.
|
524
558
|
#
|
525
559
|
#
|
526
|
-
#
|
527
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
560
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
528
561
|
#
|
529
562
|
# Options:
|
530
|
-
#
|
563
|
+
# @option name Optional name
|
564
|
+
# @return Tensor
|
531
565
|
def sigmoid(input_a, name: nil)
|
532
566
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
533
567
|
_op(:sigmoid, input_a, name: name)
|
@@ -540,11 +574,11 @@ module TensorStream
|
|
540
574
|
# Zero is returned for NaN inputs.
|
541
575
|
#
|
542
576
|
#
|
543
|
-
#
|
544
|
-
# +input_a+:: tensor X
|
577
|
+
# @param input_a tensor X
|
545
578
|
#
|
546
579
|
# Options:
|
547
|
-
#
|
580
|
+
# @option name Optional name
|
581
|
+
# @return Tensor
|
548
582
|
def sign(input_a, name: nil)
|
549
583
|
_op(:sign, input_a, name: name)
|
550
584
|
end
|
@@ -554,11 +588,11 @@ module TensorStream
|
|
554
588
|
# Computes sin of input element-wise.
|
555
589
|
#
|
556
590
|
#
|
557
|
-
#
|
558
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
591
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
559
592
|
#
|
560
593
|
# Options:
|
561
|
-
#
|
594
|
+
# @option name Optional name
|
595
|
+
# @return Tensor
|
562
596
|
def sin(input_a, name: nil)
|
563
597
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
564
598
|
_op(:sin, input_a, name: name)
|
@@ -570,12 +604,12 @@ module TensorStream
|
|
570
604
|
# Returns a 0-D Tensor representing the number of elements in input of type out_type. Defaults to :int32.
|
571
605
|
#
|
572
606
|
#
|
573
|
-
#
|
574
|
-
# +input+:: A tensor
|
607
|
+
# @param input A tensor
|
575
608
|
#
|
576
609
|
# Options:
|
577
|
-
#
|
578
|
-
#
|
610
|
+
# @option name Optional name
|
611
|
+
# @option out_type Optional output type default (:int32)
|
612
|
+
# @return Tensor
|
579
613
|
def size(input, name: nil, out_type: :int32)
|
580
614
|
_op(:size, input, name: name, out_type: out_type)
|
581
615
|
end
|
@@ -586,12 +620,12 @@ module TensorStream
|
|
586
620
|
#
|
587
621
|
# This operation supports broadcasting
|
588
622
|
#
|
589
|
-
#
|
590
|
-
#
|
591
|
-
# +input_b+:: tensor Y
|
623
|
+
# @param input_a tensor X
|
624
|
+
# @param input_b tensor Y
|
592
625
|
#
|
593
626
|
# Options:
|
594
|
-
#
|
627
|
+
# @option name Optional name
|
628
|
+
# @return Tensor
|
595
629
|
def sub(input_a, input_b, name: nil)
|
596
630
|
input_a, input_b = apply_data_type_coercion(input_a, input_b)
|
597
631
|
_op(:sub, input_a, input_b, name: name)
|
@@ -607,13 +641,13 @@ module TensorStream
|
|
607
641
|
# If axis has no entries, all dimensions are reduced, and a tensor with a single element is returned.
|
608
642
|
#
|
609
643
|
#
|
610
|
-
#
|
611
|
-
#
|
612
|
-
# +axis+:: tensor X (of type INTEGER_TYPES)
|
644
|
+
# @param input_a tensor X
|
645
|
+
# @param axis tensor X (of type INTEGER_TYPES)
|
613
646
|
#
|
614
647
|
# Options:
|
615
|
-
#
|
616
|
-
#
|
648
|
+
# @option name Optional name
|
649
|
+
# @option keepdims If true, retains reduced dimensions with length 1. default (false)
|
650
|
+
# @return Tensor
|
617
651
|
def sum(input_a, axis = nil, name: nil, keepdims: false)
|
618
652
|
check_allowed_types(axis, TensorStream::Ops::INTEGER_TYPES)
|
619
653
|
input_a = TensorStream.convert_to_tensor(input_a)
|
@@ -628,11 +662,11 @@ module TensorStream
|
|
628
662
|
# Computes tan of input element-wise.
|
629
663
|
#
|
630
664
|
#
|
631
|
-
#
|
632
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
665
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
633
666
|
#
|
634
667
|
# Options:
|
635
|
-
#
|
668
|
+
# @option name Optional name
|
669
|
+
# @return Tensor
|
636
670
|
def tan(input_a, name: nil)
|
637
671
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
638
672
|
_op(:tan, input_a, name: name)
|
@@ -643,11 +677,11 @@ module TensorStream
|
|
643
677
|
# Computes tanh of input element-wise.
|
644
678
|
#
|
645
679
|
#
|
646
|
-
#
|
647
|
-
# +input_a+:: tensor X (of type FLOATING_POINT_TYPES)
|
680
|
+
# @param input_a tensor X (of type FLOATING_POINT_TYPES)
|
648
681
|
#
|
649
682
|
# Options:
|
650
|
-
#
|
683
|
+
# @option name Optional name
|
684
|
+
# @return Tensor
|
651
685
|
def tanh(input_a, name: nil)
|
652
686
|
check_allowed_types(input_a, TensorStream::Ops::FLOATING_POINT_TYPES)
|
653
687
|
_op(:tanh, input_a, name: name)
|
@@ -661,12 +695,12 @@ module TensorStream
|
|
661
695
|
# 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].
|
662
696
|
#
|
663
697
|
#
|
664
|
-
#
|
665
|
-
#
|
666
|
-
# +multiples+:: Must be one of the following types: int32, int64. 1-D. Length must be the same as the number of dimensions in input
|
698
|
+
# @param input A tensor
|
699
|
+
# @param multiples Must be one of the following types: int32, int64. 1-D. Length must be the same as the number of dimensions in input
|
667
700
|
#
|
668
701
|
# Options:
|
669
|
-
#
|
702
|
+
# @option name Optional name
|
703
|
+
# @return Tensor
|
670
704
|
def tile(input, multiples, name: nil)
|
671
705
|
_op(:tile, input, multiples, name: name)
|
672
706
|
end
|
@@ -676,12 +710,12 @@ module TensorStream
|
|
676
710
|
# Creates a tensor with all elements set to zero
|
677
711
|
#
|
678
712
|
#
|
679
|
-
#
|
680
|
-
# +shape+:: A 1-D integer Tensor or ruby array. The shape of the output tensor.
|
713
|
+
# @param shape A 1-D integer Tensor or ruby array. The shape of the output tensor.
|
681
714
|
#
|
682
715
|
# Options:
|
683
|
-
#
|
684
|
-
#
|
716
|
+
# @option dtype Optional name default (:float32)
|
717
|
+
# @option name Optional name
|
718
|
+
# @return Tensor
|
685
719
|
def zeros(shape, dtype: :float32, name: nil)
|
686
720
|
_op(:zeros, shape, dtype: dtype, name: name)
|
687
721
|
end
|
@@ -9,12 +9,12 @@ module TensorStream
|
|
9
9
|
<%end%> #
|
10
10
|
#<% if op.supports_broadcasting? %> This operation supports broadcasting
|
11
11
|
#<% end %>
|
12
|
-
#
|
13
|
-
<% op.parameters.each do |param| %> # +<%= param[:name] %>+:: <%= param[:description]%><%if param[:validate]%> (of type <%= param[:validate] %>)<%end%>
|
12
|
+
<% op.parameters.each do |param| %> # @param <%= param[:name] %> <%= param[:description]%><%if param[:validate]%> (of type <%= param[:validate] %>)<%end%>
|
14
13
|
<% end %> #
|
15
14
|
# Options:
|
16
|
-
<% op.options.each do |k, v| %> #
|
17
|
-
<%end%>
|
15
|
+
<% op.options.each do |k, v| %> # @option <%= k %> <%= v[:description]%><% if v[:default_value] != :nil %> default (<%= v[:default_value] %>)<%end%>
|
16
|
+
<%end%> # @return Tensor
|
17
|
+
def <%= op.operation.to_s %>(<%= (op.expand_params(true) + op.expand_options(true)).join(', ') %>)
|
18
18
|
<%= op.generate_body %>
|
19
19
|
end
|
20
20
|
<% op.aliases.each do |a|%>
|
@@ -137,6 +137,19 @@ module TensorStream
|
|
137
137
|
def conv2d(input, filter, strides, padding, name: nil)
|
138
138
|
_op(:conv2d, input, filter, strides: strides, padding: padding, name: name)
|
139
139
|
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Adds bias to value.
|
143
|
+
#
|
144
|
+
# This is a narrow version of tf add where the bias is restructed to 1-D only
|
145
|
+
def bias_add(value, bias, data_format: nil, name: nil)
|
146
|
+
value = TensorStream.convert_to_tensor(value, name: "input")
|
147
|
+
bias = TensorStream.convert_to_tensor(bias, dtype: value.dtype, name: "bias")
|
148
|
+
|
149
|
+
raise TensorStreamError, "value must be at least rank 2" if value.shape.known? && value.shape.ndims < 2
|
150
|
+
|
151
|
+
_op(:bias_add, value, bias, data_format: data_format, name: name)
|
152
|
+
end
|
140
153
|
end
|
141
154
|
end
|
142
155
|
|
@@ -2,7 +2,8 @@ class TensorStream::OpMaker
|
|
2
2
|
attr_reader :operation, :description, :parameters,
|
3
3
|
:options, :gradient, :check_types,
|
4
4
|
:supports_broadcast, :data_type_coercion,
|
5
|
-
:aliases, :custom, :infer_type_proc, :exclude
|
5
|
+
:aliases, :custom, :infer_type_proc, :exclude,
|
6
|
+
:data_type_block
|
6
7
|
|
7
8
|
def initialize(op)
|
8
9
|
@operation = op
|
@@ -58,6 +59,22 @@ class TensorStream::OpMaker
|
|
58
59
|
context_caller.instance_exec(tensor, &@ops[tensor.operation].infer_type_proc)
|
59
60
|
end
|
60
61
|
|
62
|
+
def self.infer_data_type(context_caller, tensor, passed_data_type)
|
63
|
+
return passed_data_type if passed_data_type
|
64
|
+
|
65
|
+
if @ops[tensor.operation] && @ops[tensor.operation].data_type_block
|
66
|
+
context_caller.instance_exec(tensor, &@ops[tensor.operation].data_type_block)
|
67
|
+
else
|
68
|
+
if tensor.inputs[0]
|
69
|
+
tensor.inputs[0].data_type
|
70
|
+
elsif tensor.inputs[1]
|
71
|
+
tensor.inputs[1].data_type
|
72
|
+
else
|
73
|
+
:unknown
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
61
78
|
def self.each_op(&block)
|
62
79
|
@ops.values.sort_by { |op| op.operation }.reject(&:exclude).each do |op|
|
63
80
|
block.call(op)
|
@@ -122,6 +139,10 @@ class TensorStream::OpMaker
|
|
122
139
|
@infer_type_proc = block
|
123
140
|
end
|
124
141
|
|
142
|
+
def define_data_type(&block)
|
143
|
+
@data_type_block = block
|
144
|
+
end
|
145
|
+
|
125
146
|
def expand_params(print_defaults)
|
126
147
|
@parameters.map { |param|
|
127
148
|
print_defaults && param[:default_value] ? "#{param[:name]} = #{default_with_nil(param[:default_value])}" : "#{param[:name]}"
|
@@ -96,7 +96,7 @@ module TensorStream
|
|
96
96
|
options[:data_type]
|
97
97
|
when :fill
|
98
98
|
@inputs[1].data_type
|
99
|
-
when :
|
99
|
+
when :logical_and
|
100
100
|
:boolean
|
101
101
|
when :shape, :rank, :shape_n
|
102
102
|
options[:out_type] || :int32
|
@@ -119,15 +119,7 @@ module TensorStream
|
|
119
119
|
@inputs[0].data_type
|
120
120
|
end
|
121
121
|
else
|
122
|
-
|
123
|
-
|
124
|
-
if @inputs[0]
|
125
|
-
@inputs[0].data_type
|
126
|
-
elsif @inputs[1]
|
127
|
-
@inputs[1].data_type
|
128
|
-
else
|
129
|
-
:unknown
|
130
|
-
end
|
122
|
+
OpMaker.infer_data_type(self, self, passed_data_type)
|
131
123
|
end
|
132
124
|
end
|
133
125
|
|
data/lib/tensor_stream/ops.rb
CHANGED
@@ -163,14 +163,6 @@ module TensorStream
|
|
163
163
|
_op(:ones, shape, data_type: dtype, name: name)
|
164
164
|
end
|
165
165
|
|
166
|
-
##
|
167
|
-
# Returns the truth value of (x < y) element-wise.
|
168
|
-
# This operation supports broadcasting
|
169
|
-
def less(input_a, input_b, name: nil)
|
170
|
-
check_data_types(input_a, input_b)
|
171
|
-
_op(:less, input_a, input_b, name: name)
|
172
|
-
end
|
173
|
-
|
174
166
|
##
|
175
167
|
# Returns the truth value of x AND y element-wise.
|
176
168
|
def logical_and(input_a, input_b, name: nil)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
TensorStream::OpMaker.define_operation :bias_add do |op|
|
2
|
+
op.what_it_does "Adds bias to value."
|
3
|
+
|
4
|
+
op.parameter :value, "A Tensor", :nil, validate: 'NUMERIC_TYPES'
|
5
|
+
op.parameter :bias, "A 1 D tensor", :nil, validate: 'NUMERIC_TYPES'
|
6
|
+
|
7
|
+
op.supports_broadcasting!
|
8
|
+
op.exclude!
|
9
|
+
|
10
|
+
op.option :name, "Optional name", :nil
|
11
|
+
op.option :data_format, "A string. 'NHWC' and 'NCHW' are supported.", :nil
|
12
|
+
|
13
|
+
op.define_gradient do |grad, node, _params|
|
14
|
+
[grad, _op(:bias_add_grad, grad, data_format: node.options[:data_format])]
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
TensorStream::OpMaker.define_operation :less do |op|
|
2
|
+
op.what_it_does "Returns the truth value of (x < y) element-wise."
|
3
|
+
|
4
|
+
op.parameter :input_a, "tensor X"
|
5
|
+
op.parameter :input_b, "tensor Y"
|
6
|
+
|
7
|
+
op.apply_data_type_coercion!
|
8
|
+
op.supports_broadcasting!
|
9
|
+
|
10
|
+
op.option :name, "Optional name", :nil
|
11
|
+
|
12
|
+
op.define_gradient do |grad, node, _params|
|
13
|
+
_min_or_max_grad(node.inputs, grad, ->(a, b) { ts.less(a, b) })
|
14
|
+
end
|
15
|
+
|
16
|
+
op.define_data_type do
|
17
|
+
:boolean
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
TensorStream::OpMaker.define_operation :not_equal do |op|
|
2
|
+
op.what_it_does "Returns the truth value of (x != y) element-wise."
|
3
|
+
|
4
|
+
op.parameter :input_a, "tensor X"
|
5
|
+
op.parameter :input_b, "tensor Y"
|
6
|
+
|
7
|
+
op.apply_data_type_coercion!
|
8
|
+
op.supports_broadcasting!
|
9
|
+
|
10
|
+
op.option :name, "Optional name", :nil
|
11
|
+
|
12
|
+
op.define_gradient do |grad, node, params|
|
13
|
+
_min_or_max_grad(node.inputs, grad, ->(a, b) { ts.not_equal(a, b) })
|
14
|
+
end
|
15
|
+
|
16
|
+
op.define_data_type do
|
17
|
+
:boolean
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# A ruby port of the example code discussed by Martin Gorner in
|
2
|
+
# "TensorFlow and Deep Learning without a PhD, Part 1 (Google Cloud Next '17)""
|
3
|
+
#
|
4
|
+
# https://www.youtube.com/watch?v=u4alGiomYP4
|
5
|
+
#
|
6
|
+
# Requirements:
|
7
|
+
# mnist-learn gem
|
8
|
+
# opencl_ruby_ffi gem
|
9
|
+
require "bundler/setup"
|
10
|
+
require "tensor_stream"
|
11
|
+
require "mnist-learn"
|
12
|
+
|
13
|
+
# Enable OpenCL hardware accelerated computation, not using OpenCL can be very slow
|
14
|
+
# gem install tensor_stream-opencl
|
15
|
+
require 'tensor_stream/opencl'
|
16
|
+
|
17
|
+
tf = TensorStream
|
18
|
+
|
19
|
+
# Import MNIST data
|
20
|
+
puts "downloading minst data"
|
21
|
+
mnist = Mnist.read_data_sets("/tmp/data", one_hot: true)
|
22
|
+
puts "downloading finished"
|
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: 1.0.
|
4
|
+
version: 1.0.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: 2019-03-
|
11
|
+
date: 2019-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -317,6 +317,7 @@ files:
|
|
317
317
|
- lib/tensor_stream/ops/add.rb
|
318
318
|
- lib/tensor_stream/ops/argmax.rb
|
319
319
|
- lib/tensor_stream/ops/argmin.rb
|
320
|
+
- lib/tensor_stream/ops/bias_add.rb
|
320
321
|
- lib/tensor_stream/ops/case.rb
|
321
322
|
- lib/tensor_stream/ops/cast.rb
|
322
323
|
- lib/tensor_stream/ops/ceil.rb
|
@@ -330,6 +331,7 @@ files:
|
|
330
331
|
- lib/tensor_stream/ops/floor_div.rb
|
331
332
|
- lib/tensor_stream/ops/greater.rb
|
332
333
|
- lib/tensor_stream/ops/greater_equal.rb
|
334
|
+
- lib/tensor_stream/ops/less.rb
|
333
335
|
- lib/tensor_stream/ops/less_equal.rb
|
334
336
|
- lib/tensor_stream/ops/log.rb
|
335
337
|
- lib/tensor_stream/ops/mat_mul.rb
|
@@ -338,6 +340,7 @@ files:
|
|
338
340
|
- lib/tensor_stream/ops/mod.rb
|
339
341
|
- lib/tensor_stream/ops/mul.rb
|
340
342
|
- lib/tensor_stream/ops/negate.rb
|
343
|
+
- lib/tensor_stream/ops/not_equal.rb
|
341
344
|
- lib/tensor_stream/ops/ones_like.rb
|
342
345
|
- lib/tensor_stream/ops/pow.rb
|
343
346
|
- lib/tensor_stream/ops/prod.rb
|
@@ -384,6 +387,7 @@ files:
|
|
384
387
|
- samples/datasets/iris.data
|
385
388
|
- samples/jupyter_notebooks/linear_regression.ipynb
|
386
389
|
- samples/neural_networks/iris.rb
|
390
|
+
- samples/neural_networks/lstm.rb
|
387
391
|
- samples/neural_networks/mnist_data.rb
|
388
392
|
- samples/neural_networks/raw_neural_net_sample.rb
|
389
393
|
- samples/neural_networks/rnn.rb
|