tensorflow 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eace7d05756f006a0710499d67eeb878234a5c67fafb877aa5e154f7f58a0b0b
4
- data.tar.gz: 87f168e411872d952562550b6dfd73ed902c989b5d54df241198732f7a518ae5
3
+ metadata.gz: 1be807c9cecb0736fd171d31c9144d265f66ba677f9b045bf4e1d8245eb7c330
4
+ data.tar.gz: eef070cae5c973b546af0658a75bd8954a87f5db5a30be9114e5317ac5508f17
5
5
  SHA512:
6
- metadata.gz: cc67f8f76b77adc109f85c86aba641e71e6a52f60f7de9a0c983af9bd8a1ada5dc989ebfc8ae40b75da2957d24c07716385d6d949d1df7dc5fd88d4e7bb1172c
7
- data.tar.gz: 545a0fb338134f3cd1088d6467cbaa3ebba2465a845bdb91ada369cbc594f5e63108d20a6d6d5e4884885a42b915483fce8414e0ae1ec27b0833b9861a176fe1
6
+ metadata.gz: 428d8e228de1cdd6f17ac0592b522c2b28fc7cfd7e5007d141c96bd16f1471cdf2fa1be559e44a696247e0454cab8bcf6ab36bab1b45d215f3c1158a1e23b1ca
7
+ data.tar.gz: 3e91f6daa182a8aa270192e581b1f86755d80ea257e625fbd0678c9a60584e3662666af3b9b55608ecb65fca7162df84d324ce9b3d954bf08c094be1cdf474e2
data/CHANGELOG.md CHANGED
@@ -1,16 +1,23 @@
1
- ## 0.1.2
1
+ ## 0.2.0 (2021-07-07)
2
+
3
+ - Added support for TensorFlow 2.5
4
+ - Dropped support for TensorFlow < 2.5
5
+ - Dropped support for Ruby < 2.6
6
+ - Changed to Apache 2.0 license to match TensorFlow
7
+
8
+ ## 0.1.2 (2019-09-24)
2
9
 
3
10
  - Added `Audio`, `Bitwise`, `Image`, `IO`, `Linalg`, `NN`, `Strings`, and `Data::Dataset` modules
4
11
  - Added `numo` method to tensors
5
12
  - Added Boston housing dataset
6
13
  - Fixed string encoding
7
14
 
8
- ## 0.1.1
15
+ ## 0.1.1 (2019-09-20)
9
16
 
10
17
  - Added `Math` and `RawOps` modules
11
18
  - Added support for more data types
12
19
  - Added MNIST dataset
13
20
 
14
- ## 0.1.0
21
+ ## 0.1.0 (2019-09-17)
15
22
 
16
23
  - First release
data/LICENSE.txt CHANGED
@@ -1,22 +1,202 @@
1
- Copyright (c) 2019 Andrew Kane
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/NOTICE.txt ADDED
@@ -0,0 +1,14 @@
1
+ Copyright 2019-2021 The TensorFlow Authors
2
+ Copyright 2019-2021 Andrew Kane
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # TensorFlow
2
2
 
3
- [TensorFlow](https://github.com/tensorflow/tensorflow) - the end-to-end machine learning platform - for Ruby
3
+ :fire: [TensorFlow](https://github.com/tensorflow/tensorflow) - the end-to-end machine learning platform - for Ruby
4
4
 
5
- :fire: Uses the C API under the hood
5
+ This gem is currently experimental and only supports basic tensor operations at the moment. Check out [Torch.rb](https://github.com/ankane/torch-rb) for a more complete deep learning library.
6
6
 
7
- [![Build Status](https://travis-ci.org/ankane/tensorflow.svg?branch=master)](https://travis-ci.org/ankane/tensorflow)
7
+ To run a TensorFlow model in Ruby, [convert it to ONNX](https://github.com/onnx/tensorflow-onnx) and use [ONNX Runtime](https://github.com/ankane/onnxruntime). Check out [this tutorial](https://ankane.org/tensorflow-ruby) for a full example.
8
+
9
+ [![Build Status](https://github.com/ankane/tensorflow/workflows/build/badge.svg?branch=master)](https://github.com/ankane/tensorflow/actions)
8
10
 
9
11
  ## Installation
10
12
 
@@ -22,13 +24,13 @@ gem 'tensorflow'
22
24
 
23
25
  ## Getting Started
24
26
 
25
- This library follows the TensorFlow 2.0 [Python API](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf). Many methods and options are missing at the moment. Here’s the [current plan](https://github.com/ankane/tensorflow/issues/1). Additional PRs welcome!
27
+ This library follows the TensorFlow 2 [Python API](https://www.tensorflow.org/api_docs/python/tf). Many methods and options are missing at the moment. Here’s the [current plan](https://github.com/ankane/tensorflow/issues/1). Additional PRs welcome!
26
28
 
27
29
  ## Constants
28
30
 
29
31
  ```ruby
30
- a = Tf.constant(2)
31
- b = Tf.constant(3)
32
+ a = Tf.constant([1, 2, 3])
33
+ b = Tf.constant([4, 5, 6])
32
34
  a + b
33
35
  ```
34
36
 
@@ -42,8 +44,8 @@ w = v + 1
42
44
  ## Math
43
45
 
44
46
  ```ruby
45
- Tf::Math.abs(-2)
46
- Tf::Math.sqrt(4)
47
+ Tf::Math.abs([-1, -2])
48
+ Tf::Math.sqrt([1.0, 4.0, 9.0])
47
49
  ```
48
50
 
49
51
  ## FizzBuzz
@@ -137,11 +139,11 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
137
139
  - Write, clarify, or fix documentation
138
140
  - Suggest or add new features
139
141
 
140
- To get started with development and testing:
142
+ To get started with development:
141
143
 
142
144
  ```sh
143
145
  git clone https://github.com/ankane/tensorflow.git
144
146
  cd tensorflow
145
147
  bundle install
146
- rake test
148
+ bundle exec rake test
147
149
  ```
data/lib/tensorflow.rb CHANGED
@@ -43,11 +43,18 @@ require "tensorflow/keras/datasets/fashion_mnist"
43
43
  require "tensorflow/keras/datasets/imdb"
44
44
  require "tensorflow/keras/datasets/mnist"
45
45
  require "tensorflow/keras/datasets/reuters"
46
+ require "tensorflow/keras/layers/conv"
47
+ require "tensorflow/keras/layers/conv2d"
46
48
  require "tensorflow/keras/layers/dense"
47
49
  require "tensorflow/keras/layers/dropout"
48
50
  require "tensorflow/keras/layers/flatten"
51
+ require "tensorflow/keras/losses/sparse_categorical_crossentropy"
49
52
  require "tensorflow/keras/metrics/mean"
53
+ require "tensorflow/keras/metrics/sparse_categorical_accuracy"
54
+ require "tensorflow/keras/model"
50
55
  require "tensorflow/keras/models/sequential"
56
+ require "tensorflow/keras/optimizers/adam"
57
+ require "tensorflow/keras/preprocessing/image"
51
58
  require "tensorflow/keras/utils"
52
59
 
53
60
  module TensorFlow
@@ -80,6 +87,9 @@ module TensorFlow
80
87
 
81
88
  def convert_to_tensor(value, dtype: nil)
82
89
  value = Tensor.new(value, dtype: dtype) unless value.is_a?(Tensor)
90
+ if dtype && value.dtype != dtype
91
+ raise Error, "Tensor conversion requested dtype #{dtype} for Tensor with dtype #{value.dtype}"
92
+ end
83
93
  value
84
94
  end
85
95
  end
@@ -9,6 +9,30 @@ module TensorFlow
9
9
  FFI.TFE_DeleteContextOptions(options)
10
10
  end
11
11
 
12
+ def function?(name)
13
+ FFI.TFE_ContextHasFunction(@pointer, name) != 0
14
+ end
15
+
16
+ def device_policy
17
+ FFI::ContextDevicePlacementPolicy[FFI.TFE_ContextGetDevicePlacementPolicy(@pointer)]
18
+ end
19
+
20
+ def enable_run_metadata
21
+ FFI.TFE_ContextEnableRunMetadata(@pointer)
22
+ end
23
+
24
+ def disable_run_metadata
25
+ FFI.TFE_ContextDisableRunMetadata(@pointer)
26
+ end
27
+
28
+ def start_step
29
+ FFI.TFE_ContextStartStep(@pointer)
30
+ end
31
+
32
+ def end_step
33
+ FFI.TFE_ContextEndStep(@pointer)
34
+ end
35
+
12
36
  def self.finalize(pointer)
13
37
  # must use proc instead of stabby lambda
14
38
  proc { FFI.TFE_DeleteContext(pointer) }
@@ -36,11 +36,16 @@ module TensorFlow
36
36
  attach_function :TF_DeleteTensor, %i[pointer], :void
37
37
  attach_function :TF_TensorData, %i[pointer], :pointer
38
38
  attach_function :TF_TensorByteSize, %i[pointer], :size_t
39
- attach_function :TF_StringEncode, %i[pointer size_t pointer size_t pointer], :size_t
40
- attach_function :TF_StringDecode, %i[pointer size_t pointer pointer pointer], :size_t
41
- attach_function :TF_StringEncodedSize, %i[size_t], :size_t
39
+
40
+ # https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/tf_tstring.h
41
+ attach_function :TF_StringInit, %i[pointer], :void
42
+ attach_function :TF_StringCopy, %i[pointer pointer size_t], :void
43
+ attach_function :TF_StringGetDataPointer, %i[pointer], :string
44
+ attach_function :TF_StringGetSize, %i[pointer], :size_t
42
45
 
43
46
  # https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/eager/c_api.h
47
+ ContextDevicePlacementPolicy = enum(:explicit, :warn, :silent, :silent_for_int32)
48
+
44
49
  attach_function :TFE_NewContextOptions, %i[], :pointer
45
50
  attach_function :TFE_ContextOptionsSetAsync, %i[pointer char], :void
46
51
  attach_function :TFE_DeleteContextOptions, %i[pointer], :void
@@ -75,5 +80,10 @@ module TensorFlow
75
80
  attach_function :TFE_OpSetAttrTypeList, %i[pointer string pointer int], :void
76
81
  attach_function :TFE_OpSetAttrShapeList, %i[pointer string pointer pointer int pointer], :void
77
82
  attach_function :TFE_Execute, %i[pointer pointer pointer pointer], :pointer
83
+ attach_function :TFE_ContextHasFunction, %i[pointer string], :uchar
84
+ attach_function :TFE_ContextEnableRunMetadata, %i[pointer], :void
85
+ attach_function :TFE_ContextDisableRunMetadata, %i[pointer], :void
86
+ attach_function :TFE_ContextStartStep, %i[pointer], :void
87
+ attach_function :TFE_ContextEndStep, %i[pointer], :void
78
88
  end
79
89
  end
@@ -0,0 +1,14 @@
1
+ module TensorFlow
2
+ module Keras
3
+ module Layers
4
+ class Conv
5
+ def initialize(rank, filters, kernel_size, activation: nil)
6
+ @rank = rank
7
+ @filter = filters
8
+ @kernel_size = kernel_size
9
+ @activation = activation
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module TensorFlow
2
+ module Keras
3
+ module Layers
4
+ class Conv2D < Conv
5
+ def initialize(filters, kernel_size, activation: nil)
6
+ super(2, filters, kernel_size, activation: activation)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -2,7 +2,65 @@ module TensorFlow
2
2
  module Keras
3
3
  module Layers
4
4
  class Dense
5
- def initialize(units, activation: nil)
5
+ def initialize(units, activation: nil, use_bias: true, kernel_initializer: "glorot_uniform", bias_initializer: "zeros", dtype: :float)
6
+ @units = units
7
+ @activation = activation
8
+ @use_bias = use_bias
9
+ @kernel_initializer = kernel_initializer
10
+ @bias_initializer = bias_initializer
11
+ @dtype = dtype
12
+ @built = false
13
+ end
14
+
15
+ def build(input_shape)
16
+ last_dim = input_shape.last
17
+ @kernel = Utils.add_weight(name: "kernel", shape: [last_dim, @units], initializer: @kernel_initializer, dtype: @dtype)
18
+
19
+ if @use_bias
20
+ @bias = Utils.add_weight(name: "bias", shape: [@units], initializer: @bias_initializer, dtype: @dtype)
21
+ else
22
+ @bias = nil
23
+ end
24
+
25
+ @output_shape = [last_dim, @units]
26
+
27
+ @built = true
28
+ end
29
+
30
+ def output_shape
31
+ @output_shape
32
+ end
33
+
34
+ def count_params
35
+ @units + @kernel.shape.inject(&:*)
36
+ end
37
+
38
+ def call(inputs)
39
+ build(inputs.shape) unless @built
40
+
41
+ rank = inputs.shape.size
42
+
43
+ if rank > 2
44
+ raise Error, "Rank > 2 not supported yet"
45
+ else
46
+ inputs = TensorFlow.cast(inputs, @dtype)
47
+ outputs = TensorFlow.matmul(inputs, @kernel)
48
+ end
49
+
50
+ if @use_bias
51
+ outputs = NN.bias_add(outputs, @bias)
52
+ end
53
+
54
+ case @activation
55
+ when "relu"
56
+ NN.relu(outputs)
57
+ when "softmax"
58
+ NN.softmax(outputs)
59
+ when nil
60
+ outputs
61
+ else
62
+ raise "Unknown activation: #{@activation}"
63
+ end
6
64
  end
7
65
  end
8
66
  end
@@ -4,6 +4,23 @@ module TensorFlow
4
4
  class Dropout
5
5
  def initialize(rate)
6
6
  end
7
+
8
+ def build(input_shape)
9
+ @output_shape = input_shape
10
+ end
11
+
12
+ def call(inputs)
13
+ # TODO implement
14
+ TensorFlow.identity(inputs)
15
+ end
16
+
17
+ def output_shape
18
+ @output_shape
19
+ end
20
+
21
+ def count_params
22
+ 0
23
+ end
7
24
  end
8
25
  end
9
26
  end
@@ -3,6 +3,21 @@ module TensorFlow
3
3
  module Layers
4
4
  class Flatten
5
5
  def initialize(input_shape: nil)
6
+ @input_shape = input_shape
7
+ end
8
+
9
+ def output_shape
10
+ flattened_dim = @input_shape.inject(&:*)
11
+ [-1, flattened_dim]
12
+ end
13
+
14
+ def count_params
15
+ 0
16
+ end
17
+
18
+ def call(inputs)
19
+ flattened_dim = inputs.shape[1..-1].inject(&:*)
20
+ TensorFlow.reshape(inputs, [-1, flattened_dim])
6
21
  end
7
22
  end
8
23
  end
@@ -0,0 +1,14 @@
1
+ module TensorFlow
2
+ module Keras
3
+ module Losses
4
+ class SparseCategoricalCrossentropy
5
+ def call(target, output)
6
+ output = Math.log(output)
7
+ target = TensorFlow.cast(target, :int64)
8
+ cost, _ = RawOps.sparse_softmax_cross_entropy_with_logits(features: output, labels: target)
9
+ Math.reduce_sum(cost) / TensorFlow.cast(RawOps.size(input: cost), :float)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -2,15 +2,29 @@ module TensorFlow
2
2
  module Keras
3
3
  module Metrics
4
4
  class Mean
5
+ def initialize(name: nil, dtype: :float)
6
+ @dtype = dtype
7
+ @total = Utils.add_weight(name: "total", initializer: "zeros", dtype: @dtype)
8
+ @count = Utils.add_weight(name: "count", initializer: "zeros", dtype: @dtype)
9
+ end
10
+
11
+ def call(*args)
12
+ update_state(*args)
13
+ end
14
+
5
15
  def update_state(values)
6
- input = TensorFlow.convert_to_tensor(values, dtype: :float)
7
- @total = Math.reduce_sum(input)
8
- @count = RawOps.size(input: input)
16
+ input = TensorFlow.convert_to_tensor(values)
17
+ input = TensorFlow.cast(input, @dtype)
18
+ @total.assign_add(Math.reduce_sum(input))
19
+ @count.assign_add(TensorFlow.cast(RawOps.size(input: input), @dtype))
9
20
  end
10
21
 
11
22
  def result
12
23
  RawOps.div_no_nan(x: @total, y: TensorFlow.cast(@count, :float))
13
24
  end
25
+
26
+ def reset_states
27
+ end
14
28
  end
15
29
  end
16
30
  end
@@ -0,0 +1,20 @@
1
+ module TensorFlow
2
+ module Keras
3
+ module Metrics
4
+ class SparseCategoricalAccuracy < Mean
5
+ def update_state(y_true, y_pred)
6
+ y_true = TensorFlow.convert_to_tensor(y_true)
7
+ y_pred = TensorFlow.convert_to_tensor(y_pred)
8
+
9
+ y_pred = RawOps.arg_max(input: y_pred, dimension: -1)
10
+
11
+ if y_pred.dtype != y_true.dtype
12
+ y_pred = TensorFlow.cast(y_pred, y_true.dtype)
13
+ end
14
+
15
+ super(Math.equal(y_true, y_pred))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ module TensorFlow
2
+ module Keras
3
+ class Model
4
+ end
5
+ end
6
+ end
@@ -25,6 +25,31 @@ module TensorFlow
25
25
  def evaluate(x, y)
26
26
  raise "Not implemented"
27
27
  end
28
+
29
+ def summary
30
+ sep = "_________________________________________________________________\n"
31
+
32
+ output_shape = nil
33
+ @layers.each do |layer|
34
+ layer.build(output_shape) if layer.respond_to?(:build)
35
+ output_shape = layer.output_shape
36
+ end
37
+
38
+ total_params = @layers.map(&:count_params).sum
39
+
40
+ summary = String.new("")
41
+ summary << "Model: \"sequential\"\n"
42
+ summary << sep
43
+ summary << "Layer (type) Output Shape Param # \n"
44
+ summary << "=================================================================\n"
45
+ summary << @layers.map { |l| "%-28s %-25s %-10s\n" % [l.class.name.split("::").last, ([nil] + l.output_shape[1..-1]).inspect, l.count_params] }.join(sep)
46
+ summary << "=================================================================\n"
47
+ summary << "Total params: #{total_params}\n"
48
+ summary << "Trainable params: #{total_params}\n"
49
+ summary << "Non-trainable params: 0\n"
50
+ summary << sep
51
+ puts summary
52
+ end
28
53
  end
29
54
  end
30
55
  end
@@ -0,0 +1,8 @@
1
+ module TensorFlow
2
+ module Keras
3
+ module Optimizers
4
+ class Adam
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,22 @@
1
+ module TensorFlow
2
+ module Keras
3
+ module Preprocessing
4
+ module Image
5
+ class << self
6
+ def load_img(path, target_size: nil)
7
+ img = MiniMagick::Image.open(path)
8
+ if target_size
9
+ # TODO make resize consistent with Python
10
+ img.resize "#{target_size.map(&:to_i).join("x")}!", "-filter", "point"
11
+ end
12
+ img
13
+ end
14
+
15
+ def img_to_array(img)
16
+ Numo::SFloat.cast(img.get_pixels)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -2,6 +2,32 @@ module TensorFlow
2
2
  module Keras
3
3
  module Utils
4
4
  class << self
5
+ def add_weight(name: nil, shape: [], initializer: nil, dtype: :float)
6
+ variable = Variable.new(shape: shape, name: name, dtype: dtype)
7
+ initial_value =
8
+ case initializer
9
+ when "zeros"
10
+ TensorFlow.fill(TensorFlow.convert_to_tensor(shape, dtype: :int64), 0.0)
11
+ when "glorot_uniform"
12
+ # TODO compute fans
13
+ fan_in = shape[0]
14
+ fan_out = shape[1]
15
+ scale = 1.0
16
+ scale /= [1.0, (fan_in + fan_out) / 2.0].max
17
+ limit = ::Math.sqrt(3.0 * scale)
18
+
19
+ minval = -limit
20
+ maxval = limit
21
+
22
+ rnd = RawOps.random_uniform(shape: shape, dtype: :float)
23
+ Math.add(rnd * (maxval - minval), minval)
24
+ else
25
+ raise Error, "Unknown initializer: #{initializer}"
26
+ end
27
+ variable.assign(initial_value)
28
+ variable
29
+ end
30
+
5
31
  def get_file(fname, origin, file_hash: nil, cache_subdir: "datasets")
6
32
  # destination
7
33
  # TODO handle this better
@@ -493,7 +493,7 @@ module TensorFlow
493
493
 
494
494
  def reduction_dims(input_tensor)
495
495
  rank = RawOps.rank(input: input_tensor).value
496
- (0...rank).to_a
496
+ TensorFlow.constant((0...rank).to_a, dtype: :int32)
497
497
  end
498
498
  end
499
499
  end
@@ -29,6 +29,10 @@ module TensorFlow
29
29
  RawOps.range(start: start, limit: limit, delta: delta)
30
30
  end
31
31
 
32
+ def reshape(tensor, shape)
33
+ RawOps.reshape(tensor: tensor, shape: shape)
34
+ end
35
+
32
36
  def squeeze(input, axis: nil)
33
37
  RawOps.squeeze(input: input, squeeze_dims: axis)
34
38
  end
@@ -105,19 +105,9 @@ module TensorFlow
105
105
  when :complex128
106
106
  data_pointer.read_array_of_double(element_count * 2).each_slice(2).map { |v| Complex(*v) }
107
107
  when :string
108
- # string tensor format
109
- # https://github.com/tensorflow/tensorflow/blob/5453aee48858fd375172d7ae22fad1557e8557d6/tensorflow/c/tf_tensor.h#L57
110
- start_offset_size = element_count * 8
111
- offsets = data_pointer.read_array_of_uint64(element_count)
112
- byte_size = FFI.TF_TensorByteSize(tensor_pointer)
108
+ tf_string_size = 24
113
109
  element_count.times.map do |i|
114
- str_len = (offsets[i + 1] || (byte_size - start_offset_size)) - offsets[i]
115
- str = (data_pointer + start_offset_size + offsets[i]).read_bytes(str_len)
116
- dst = ::FFI::MemoryPointer.new(:char, str.bytesize + 100)
117
- dst_len = ::FFI::MemoryPointer.new(:size_t)
118
- FFI.TF_StringDecode(str, str.bytesize, dst, dst_len, @status)
119
- check_status @status
120
- dst.read_pointer.read_bytes(dst_len.read_int32)
110
+ FFI.TF_StringGetDataPointer(data_pointer + i * tf_string_size)
121
111
  end
122
112
  when :bool
123
113
  data_pointer.read_array_of_int8(element_count).map { |v| v == 1 }
@@ -226,20 +216,13 @@ module TensorFlow
226
216
  shape
227
217
  end
228
218
 
229
- # string tensor format
230
- # https://github.com/tensorflow/tensorflow/blob/5453aee48858fd375172d7ae22fad1557e8557d6/tensorflow/c/tf_tensor.h#L57
231
219
  def string_ptr(data)
232
- start_offset_size = data.size * 8
233
- offsets = [0]
234
- data.each do |str|
235
- offsets << offsets.last + str.bytesize + 1
236
- end
237
- data_ptr = ::FFI::MemoryPointer.new(:char, start_offset_size + offsets.pop)
238
- data_ptr.write_array_of_uint64(offsets)
239
- data.zip(offsets) do |str, offset|
240
- dst_len = FFI.TF_StringEncodedSize(str.bytesize)
241
- FFI.TF_StringEncode(str, str.bytesize, data_ptr + start_offset_size + offset, dst_len, @status)
242
- check_status @status
220
+ tf_string_size = 24
221
+ data_ptr = ::FFI::MemoryPointer.new(:char, data.size * tf_string_size)
222
+ data.each_with_index do |str, i|
223
+ offset = data_ptr + i * tf_string_size
224
+ FFI.TF_StringInit(offset)
225
+ FFI.TF_StringCopy(offset, str, str.bytesize)
243
226
  end
244
227
  data_ptr
245
228
  end
@@ -1,9 +1,13 @@
1
1
  module TensorFlow
2
2
  class Variable
3
- def initialize(initial_value, dtype: nil)
3
+ attr_reader :name
4
+
5
+ def initialize(initial_value = nil, dtype: nil, shape: nil, name: nil)
4
6
  @dtype = dtype || Utils.infer_type(Array(initial_value).flatten)
7
+ @shape = shape
8
+ @name = name
5
9
  @pointer = RawOps.var_handle_op(dtype: type_enum, shape: [], shared_name: Utils.default_context.shared_name)
6
- assign(initial_value)
10
+ assign(initial_value) if initial_value
7
11
  end
8
12
 
9
13
  def assign(value)
@@ -42,12 +46,21 @@ module TensorFlow
42
46
  inspect
43
47
  end
44
48
 
49
+ def shape
50
+ read_value.shape
51
+ end
52
+
45
53
  def inspect
46
54
  value = read_value
47
55
  inspection = %w(numo shape dtype).map { |v| "#{v}: #{value.send(v).inspect}"}
56
+ inspection.unshift("name: #{name}") if name
48
57
  "#<#{self.class} #{inspection.join(", ")}>"
49
58
  end
50
59
 
60
+ def to_ptr
61
+ read_value.to_ptr
62
+ end
63
+
51
64
  private
52
65
 
53
66
  def type_enum
@@ -1,3 +1,3 @@
1
1
  module TensorFlow
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tensorflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-24 00:00:00.000000000 Z
11
+ date: 2021-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -52,84 +52,15 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: minitest
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '5'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '5'
97
- - !ruby/object:Gem::Dependency
98
- name: google-protobuf
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: nokogiri
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- description:
126
- email: andrew@chartkick.com
55
+ description:
56
+ email: andrew@ankane.org
127
57
  executables: []
128
58
  extensions: []
129
59
  extra_rdoc_files: []
130
60
  files:
131
61
  - CHANGELOG.md
132
62
  - LICENSE.txt
63
+ - NOTICE.txt
133
64
  - README.md
134
65
  - lib/tensorflow.rb
135
66
  - lib/tensorflow/audio.rb
@@ -149,11 +80,18 @@ files:
149
80
  - lib/tensorflow/keras/datasets/imdb.rb
150
81
  - lib/tensorflow/keras/datasets/mnist.rb
151
82
  - lib/tensorflow/keras/datasets/reuters.rb
83
+ - lib/tensorflow/keras/layers/conv.rb
84
+ - lib/tensorflow/keras/layers/conv2d.rb
152
85
  - lib/tensorflow/keras/layers/dense.rb
153
86
  - lib/tensorflow/keras/layers/dropout.rb
154
87
  - lib/tensorflow/keras/layers/flatten.rb
88
+ - lib/tensorflow/keras/losses/sparse_categorical_crossentropy.rb
155
89
  - lib/tensorflow/keras/metrics/mean.rb
90
+ - lib/tensorflow/keras/metrics/sparse_categorical_accuracy.rb
91
+ - lib/tensorflow/keras/model.rb
156
92
  - lib/tensorflow/keras/models/sequential.rb
93
+ - lib/tensorflow/keras/optimizers/adam.rb
94
+ - lib/tensorflow/keras/preprocessing/image.rb
157
95
  - lib/tensorflow/keras/utils.rb
158
96
  - lib/tensorflow/linalg.rb
159
97
  - lib/tensorflow/math.rb
@@ -167,9 +105,9 @@ files:
167
105
  - lib/tensorflow/version.rb
168
106
  homepage: https://github.com/ankane/tensorflow
169
107
  licenses:
170
- - MIT
108
+ - Apache-2.0
171
109
  metadata: {}
172
- post_install_message:
110
+ post_install_message:
173
111
  rdoc_options: []
174
112
  require_paths:
175
113
  - lib
@@ -177,15 +115,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
177
115
  requirements:
178
116
  - - ">="
179
117
  - !ruby/object:Gem::Version
180
- version: '2.4'
118
+ version: '2.6'
181
119
  required_rubygems_version: !ruby/object:Gem::Requirement
182
120
  requirements:
183
121
  - - ">="
184
122
  - !ruby/object:Gem::Version
185
123
  version: '0'
186
124
  requirements: []
187
- rubygems_version: 3.0.3
188
- signing_key:
125
+ rubygems_version: 3.2.3
126
+ signing_key:
189
127
  specification_version: 4
190
128
  summary: TensorFlow - the end-to-end machine learning platform - for Ruby
191
129
  test_files: []