tensor_stream 0.1.4 → 0.1.5

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.
@@ -1,7 +1,7 @@
1
1
  module TensorStream
2
2
  # A class that defines a TensorStream graph
3
3
  class Graph
4
- attr_accessor :nodes, :collections, :eager_execution
4
+ attr_accessor :nodes, :collections, :eager_execution, :random_seed
5
5
 
6
6
  def initialize
7
7
  @eager_execution = false
@@ -16,13 +16,31 @@ module TensorStream
16
16
  @const_counter = 0
17
17
  @var_counter = 0
18
18
  @op_counter = 0
19
-
19
+ @random_seed = nil
20
20
  @nodes = {}
21
21
  @collections = {
22
22
  :"#{GraphKeys::GLOBAL_VARIABLES}" => []
23
23
  }
24
24
  end
25
25
 
26
+ def as_default
27
+ Thread.current[:tensor_stream_current_graph] = self
28
+ yield(self) if block_given?
29
+ self
30
+ end
31
+
32
+ def name_scope(name = nil)
33
+ Thread.current["ts_graph_#{object_id}"] ||= {}
34
+ Thread.current["ts_graph_#{object_id}"][:current_scope] ||= []
35
+ Thread.current["ts_graph_#{object_id}"][:current_scope] << name
36
+
37
+ begin
38
+ yield get_name_scope if block_given?
39
+ ensure
40
+ Thread.current["ts_graph_#{object_id}"][:current_scope].pop
41
+ end
42
+ end
43
+
26
44
  def self.get_default_graph
27
45
  Thread.current[:tensor_stream_current_graph] || create_default
28
46
  end
@@ -42,7 +60,13 @@ module TensorStream
42
60
 
43
61
  def add_node(node)
44
62
  raise 'Placeholder cannot be used when eager_execution is enabled' if @eager_execution && node.is_a?(Placeholder)
45
- node.name = uniqunify(node.name) if @nodes[node.name]
63
+
64
+ node.name = if @nodes[node.name]
65
+ uniqunify(node.name)
66
+ else
67
+ node.name
68
+ end
69
+
46
70
  @nodes[node.name] = node
47
71
  node.send(:propagate_consumer, node)
48
72
  node.value = node.eval if @eager_execution
@@ -62,10 +86,21 @@ module TensorStream
62
86
  end
63
87
 
64
88
  def add_variable(node, options = {})
65
- raise "duplicate variable detected #{node.name} and reuse=false in current scope" if @nodes[node.name] && !options[:reuse]
89
+ scope = _variable_scope
66
90
 
67
- add_to_collection(GraphKeys::GLOBAL_VARIABLES, node)
91
+ raise "duplicate variable detected #{node.name} and reuse=false in current scope" if @nodes[node.name] && !scope.reuse
68
92
 
93
+ return @nodes[node.name] if @nodes[node.name]
94
+
95
+ raise "shape is not declared for #{node.name}" if node.shape.nil?
96
+
97
+ if !options[:collections].nil? && !options[:collections].empty?
98
+ options[:collections] = [options[:collections]] unless options[:collections].is_a?(Array)
99
+ options[:collections].each { |coll| add_to_collection(coll, node) }
100
+ end
101
+
102
+ add_to_collection(GraphKeys::GLOBAL_VARIABLES, node)
103
+ add_to_collection(GraphKeys::TRAINABLE_VARIABLES, node) if node.trainable?
69
104
  add_node(node)
70
105
  end
71
106
 
@@ -120,8 +155,21 @@ module TensorStream
120
155
  name
121
156
  end
122
157
 
158
+ def get_name_scope
159
+ graph_thread_storage = Thread.current["ts_graph_#{object_id}"]
160
+ return nil if graph_thread_storage.nil?
161
+
162
+ graph_thread_storage[:current_scope].join('/')
163
+ end
164
+
123
165
  protected
124
166
 
167
+ def _variable_scope
168
+ return OpenStruct.new(name: '', reuse: false, initializer: nil) if Thread.current[:tensor_stream_variable_scope].nil? || Thread.current[:tensor_stream_variable_scope].empty?
169
+ scope = Thread.current[:tensor_stream_variable_scope].last
170
+ scope
171
+ end
172
+
125
173
  def uniqunify(name)
126
174
  counter = 0
127
175
  new_name = name
@@ -1,5 +1,6 @@
1
1
  module TensorStream
2
2
  class GraphKeys
3
3
  GLOBAL_VARIABLES = 'variables'.freeze
4
+ TRAINABLE_VARIABLES = 'trainable_variables'.freeze
4
5
  end
5
6
  end
@@ -0,0 +1,91 @@
1
+ module TensorStream
2
+ class Graphml
3
+ def initialize
4
+ end
5
+
6
+ def serialize(session, tensor, filename)
7
+ @session = session
8
+ @last_session_context = session.last_session_context
9
+
10
+ arr_buf = []
11
+ arr_buf << '<?xml version="1.0" encoding="UTF-8"?>'
12
+ arr_buf << '<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
13
+ xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">'
14
+ arr_buf << '<key id="d0" for="node" attr.name="label" attr.type="string"/>'
15
+ arr_buf << '<key id="d1" for="node" attr.name="formula" attr.type="string"/>'
16
+ arr_buf << '<key id="d2" for="node" attr.name="color" attr.type="string"/>'
17
+ arr_buf << '<key id="d3" for="node" attr.name="value" attr.type="string"/>'
18
+ arr_buf << "<graph id=\"g_#{_gml_string(tensor.name)}\" edgedefault=\"directed\">"
19
+ arr_buf << "<node id=\"out\">"
20
+ arr_buf << "<data key=\"d0\">out</data>"
21
+ arr_buf << "<data key=\"d2\">red</data>"
22
+ arr_buf << "</node>"
23
+ to_graph_ml(tensor, arr_buf)
24
+ arr_buf << "<edge source=\"#{_gml_string(tensor.name)}\" target=\"out\"/>"
25
+ arr_buf << "</graph>"
26
+ arr_buf << "</graphml>"
27
+ File.write(filename, arr_buf.join("\n"))
28
+ end
29
+
30
+ private
31
+
32
+ def _val(tensor)
33
+ JSON.pretty_generate(@last_session_context[tensor.name])
34
+ end
35
+
36
+ def to_graph_ml(tensor, arr_buf = [], added = {}, _id = 0)
37
+ puts tensor.name
38
+ added[tensor.name] = true
39
+ arr_buf << "<node id=\"#{_gml_string(tensor.name)}\">"
40
+ arr_buf << "<data key=\"d0\">#{tensor.operation}</data>"
41
+ arr_buf << "<data key=\"d1\">#{tensor.to_math(true, 1)}</data>"
42
+ arr_buf << "<data key=\"d2\">blue</data>"
43
+ if @last_session_context[tensor.name]
44
+ arr_buf << "<data key=\"d3\">#{_val(tensor)}</data>"
45
+ end
46
+ arr_buf << "</node>"
47
+
48
+ tensor.items.each do |item|
49
+ next unless item
50
+ next if _added[item.name]
51
+
52
+ next to_graph_ml(item, arr_buf, added) if item.is_a?(Operation)
53
+ added[item.name] = true
54
+ if item.is_a?(Variable)
55
+ arr_buf << "<node id=\"#{_gml_string(item.name)}\">"
56
+ arr_buf << "<data key=\"d0\">#{item.name}</data>"
57
+ arr_buf << "<data key=\"d2\">green</data>"
58
+ if @last_session_context[item.name]
59
+ arr_buf << "<data key=\"d3\">#{_val(tensor)}</data>"
60
+ end
61
+ arr_buf << "</node>"
62
+ elsif item.is_a?(Placeholder)
63
+ arr_buf << "<node id=\"#{_gml_string(item.name)}\">"
64
+ arr_buf << "<data key=\"d0\">#{item.name}</data>"
65
+ arr_buf << "<data key=\"d2\">yellow</data>"
66
+ if @last_session_context[item.name]
67
+ arr_buf << "<data key=\"d3\">#{_val(tensor)}</data>"
68
+ end
69
+ arr_buf << "</node>"
70
+ else
71
+ arr_buf << "<node id=\"#{_gml_string(item.name)}\">"
72
+ arr_buf << "<data key=\"d0\">#{item.name}</data>"
73
+ arr_buf << "<data key=\"d2\">black</data>"
74
+ if @last_session_context[item.name]
75
+ arr_buf << "<data key=\"d3\">#{_val(tensor)}</data>"
76
+ end
77
+ arr_buf << "</node>"
78
+ end
79
+ end
80
+
81
+ tensor.items.each do |item|
82
+ next unless item
83
+ arr_buf << "<edge source=\"#{_gml_string(item.name)}\" target=\"#{_gml_string(tensor.name)}\"/>"
84
+ end
85
+ end
86
+
87
+ def _gml_string(str)
88
+ str.gsub('/','-')
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,71 @@
1
+ module TensorStream
2
+ class Pbtext
3
+ def initialize
4
+ end
5
+
6
+ def serialize(session, filename, tensor)
7
+ end
8
+
9
+ def get_string(graph)
10
+ @lines = []
11
+ graph.nodes.each do |k, node|
12
+ @lines << "node {"
13
+ @lines << " name: #{node.name.to_json}"
14
+ if node.is_a?(TensorStream::Operation)
15
+ @lines << " op: #{node.operation.to_json}"
16
+ node.items.each do |input|
17
+ next unless input
18
+ @lines << " input: #{input.name.to_json}"
19
+ end
20
+ # type
21
+ pb_attr('T', sym_to_protobuf_type(node.data_type))
22
+ elsif node.is_a?(TensorStream::Tensor) && node.is_const
23
+ @lines << " op: \"Const\""
24
+ # type
25
+ pb_attr('T', sym_to_protobuf_type(node.data_type))
26
+ pb_attr('value', tensor_value(node))
27
+ end
28
+ @lines << "}"
29
+ end
30
+ @lines.join("\n")
31
+ end
32
+
33
+ private
34
+
35
+ def tensor_value(tensor)
36
+ arr = []
37
+ arr << "tensor {"
38
+ arr << " dtype: #{sym_to_protobuf_type(tensor.data_type)}"
39
+ arr << " float_val: #{tensor.value}"
40
+ arr << "}"
41
+ arr
42
+ end
43
+
44
+ def sym_to_protobuf_type(type)
45
+ case type
46
+ when :int32
47
+ "DT_INT32"
48
+ when :float, :float32
49
+ "DT_FLOAT"
50
+ else
51
+ "DT_UNKNOWN"
52
+ end
53
+ end
54
+
55
+ def pb_attr(key, value)
56
+ @lines << " attr {"
57
+ @lines << " key: \"#{key}\""
58
+ @lines << " value {"
59
+ if value.is_a?(Array)
60
+ value.each do |v|
61
+ @lines << " #{v}"
62
+ end
63
+ else
64
+ @lines << " #{value}"
65
+ end
66
+ @lines << " }"
67
+ @lines << " }"
68
+ end
69
+ end
70
+
71
+ end
@@ -1,7 +1,7 @@
1
1
  module TensorStream
2
2
  # module that contains helper functions useful for ops
3
3
  module OpHelper
4
- def op(code, t_a, t_b = nil, options = {})
4
+ def _op(code, t_a, t_b = nil, options = {})
5
5
  Operation.new(code.to_sym, t_a, t_b, options)
6
6
  end
7
7
 
@@ -58,5 +58,11 @@ module TensorStream
58
58
  def fp_type?(type)
59
59
  TensorStream::Ops::FLOATING_POINT_TYPES.include?(type)
60
60
  end
61
+
62
+ def format_source(trace)
63
+ grad_source = trace.select { |c| c.to_s.include?(File.join('lib', 'tensor_stream', 'math_gradients')) }.first
64
+ source = trace.reject { |c| c.to_s.include?(File.join('lib', 'tensor_stream')) }.first
65
+ [grad_source, source].compact.join("\n")
66
+ end
61
67
  end
62
68
  end
@@ -0,0 +1,16 @@
1
+ module TensorStream
2
+ class Initializer
3
+ attr_writer :op
4
+ def initialize(op)
5
+ @op = op
6
+ end
7
+
8
+ def op
9
+ @op.call
10
+ end
11
+
12
+ def shape
13
+ nil
14
+ end
15
+ end
16
+ end
@@ -5,6 +5,7 @@ module TensorStream
5
5
 
6
6
  def self.derivative(tensor, wrt_dx, options = {})
7
7
  gradient_program_name = "_grad_#{tensor.name}_#{wrt_dx.name}"
8
+
8
9
  return options[:graph].get_node(gradient_program_name) if options[:graph] && options[:graph].node_added?(gradient_program_name)
9
10
 
10
11
  constant_options = { dtype: options[:dtype] }
@@ -18,6 +19,10 @@ module TensorStream
18
19
  grad2 = derivative(tensor.items[1], wrt_dx, options) if tensor.items[1]
19
20
 
20
21
  case tensor.operation
22
+ when :zeros_like
23
+ i_cons(0, constant_options)
24
+ when :log1p
25
+ grad * _op(:reciprocal, i_cons(1, constant_options_1) + tensor.items[0])
21
26
  when :max
22
27
  x_mask = i_op(:where, i_op(:ones_like, tensor.items[0]), i_op(:zeros_like, tensor.items[1]), pred: tensor.items[0] > tensor.items[1])
23
28
  y_mask = i_op(:where, i_op(:zeros_like, tensor.items[0]), i_op(:ones_like, tensor.items[1]), pred: tensor.items[0] < tensor.items[1])
@@ -51,19 +56,19 @@ module TensorStream
51
56
  when :cos
52
57
  -i_op(:sin, tensor.items[0]) * grad
53
58
  when :add
54
- # rx = op(:shape, tensor.items[0])
55
- # ry = op(:shape, tensor.items[1])
59
+ # rx = _op(:shape, tensor.items[0])
60
+ # ry = _op(:shape, tensor.items[1])
56
61
 
57
- # ones_a = op(:ones_like, tensor.items[0])
58
- # ones_b = op(:ones_like, tensor.items[1])
62
+ # ones_a = _op(:ones_like, tensor.items[0])
63
+ # ones_b = _op(:ones_like, tensor.items[1])
59
64
  # inputs = _broadcast_transform(grad * ones_a, grad2 * ones_b)
60
65
  # sx, sy = _broadcast_gradient_args(rx, ry)
61
66
 
62
- # keep_dims_x = op(:rank, inputs[0]) == op(:rank, tensor.items[0])
63
- # keep_dims_y = op(:rank, inputs[1]) == op(:rank, tensor.items[1])
67
+ # keep_dims_x = _op(:rank, inputs[0]) == _op(:rank, tensor.items[0])
68
+ # keep_dims_y = _op(:rank, inputs[1]) == _op(:rank, tensor.items[1])
64
69
 
65
- # add_x = op(:reduce_sum, inputs[0], nil, axis: sy, keepdims: keep_dims_x)
66
- # add_y = op(:reduce_sum, inputs[1], nil, axis: sx, keepdims: keep_dims_y)
70
+ # add_x = _op(:reduce_sum, inputs[0], nil, axis: sy, keepdims: keep_dims_x)
71
+ # add_y = _op(:reduce_sum, inputs[1], nil, axis: sx, keepdims: keep_dims_y)
67
72
  # _filtered_sum(add_x, add_y, wrt_dx)
68
73
  _grad_with_broadcast(tensor, wrt_dx, ->(a, b) { i_op(:add, a, b, name: 'grad_add') }, options)
69
74
  when :sub
@@ -83,15 +88,15 @@ module TensorStream
83
88
  _reduce_when_necessary(gx + gy, wrt_dx)
84
89
  when :mul
85
90
  # apply the product rule
86
- rx = op(:shape, tensor.items[0])
87
- ry = op(:shape, tensor.items[1])
91
+ rx = _op(:shape, tensor.items[0])
92
+ ry = _op(:shape, tensor.items[1])
88
93
  sx, sy = _broadcast_gradient_args(rx, ry)
89
94
  inputs = _broadcast_transform(tensor.items[0], tensor.items[1])
90
- keep_dims_x = op(:rank, inputs[0]) == op(:rank, tensor.items[0])
91
- keep_dims_y = op(:rank, inputs[1]) == op(:rank, tensor.items[1])
95
+ keep_dims_x = _op(:rank, inputs[0]) == _op(:rank, tensor.items[0])
96
+ keep_dims_y = _op(:rank, inputs[1]) == _op(:rank, tensor.items[1])
92
97
 
93
- _filtered_sum(op(:reduce_sum, grad * _ds(inputs[1]), nil, axis: sy, keepdims: keep_dims_x),
94
- op(:reduce_sum, _ds(inputs[0]) * grad2, nil, axis: sx, keepdims: keep_dims_y), wrt_dx)
98
+ _filtered_sum(_op(:reduce_sum, grad * _ds(inputs[1]), nil, axis: sy, keepdims: keep_dims_x),
99
+ _op(:reduce_sum, _ds(inputs[0]) * grad2, nil, axis: sx, keepdims: keep_dims_y), wrt_dx)
95
100
  when :reduce_mean
96
101
  input_size = i_op(:reduce_prod, i_op(:shape, tensor.items[0]))
97
102
  output_size = i_op(:reduce_prod, i_op(:shape, tensor))
@@ -100,6 +105,8 @@ module TensorStream
100
105
  (grad / i_op(:cast, factor, data_type: grad.dtype))
101
106
  when :reduce_sum
102
107
  grad
108
+ when :reciprocal
109
+ -grad * (i_cons(1, constant_options_1) / _ds(tensor.items[0])**2)
103
110
  when :stop_gradient
104
111
  return i_cons(0, constant_options)
105
112
  when :matmul
@@ -113,20 +120,20 @@ module TensorStream
113
120
  identity_1 = i_op(:ones, [s0[0], s1[1]], nil, data_type: tensor.items[1].data_type)
114
121
 
115
122
  matmul_da = i_op(:matmul, identity_0, tensor.items[1], transpose_b: true,
116
- pad_zeros: true,
117
- name: 'matrix_dx')
123
+ pad_zeros: true,
124
+ name: 'matrix_dx')
118
125
  matmul_db = i_op(:matmul, tensor.items[0], identity_1, transpose_a: true,
119
- pad_zeros: true,
120
- name: 'matrix_dy')
121
- # matmul_db = op(:transpose, matmul_db, nil).first
126
+ pad_zeros: true,
127
+ name: 'matrix_dy')
128
+ # matmul_db = _op(:transpose, matmul_db, nil).first
122
129
 
123
- # begin_a = op(:zeros, op(:rank, matmul_db), nil, data_type: :int32, name: 'begin_a')
124
- # matmul_b_shape = op(:shape, matmul_db)
130
+ # begin_a = _op(:zeros, _op(:rank, matmul_db), nil, data_type: :int32, name: 'begin_a')
131
+ # matmul_b_shape = _op(:shape, matmul_db)
125
132
  # end_a = [matmul_b_shape[0], 1]
126
133
 
127
- matmul_da = i_op(:cond, matmul_da[0], matmul_da, pred: op(:rank, derivative_a) > 0)
134
+ matmul_da = i_op(:cond, matmul_da[0], matmul_da, pred: _op(:rank, derivative_a) > 0)
128
135
 
129
- # matmul_da = op(:cond, matmul_da[0], matmul_da, pred: op(:rank, derivative_a) > 0)
136
+ # matmul_da = _op(:cond, matmul_da[0], matmul_da, pred: _op(:rank, derivative_a) > 0)
130
137
  norm_a = i_op(:mul, derivative_a, matmul_da, name: 'grad_a_norm_mul_da')
131
138
  norm_b = i_op(:mul, derivative_b, matmul_db, name: 'grad_b_norm_mul_db')
132
139
 
@@ -173,23 +180,23 @@ module TensorStream
173
180
  end
174
181
 
175
182
  def self._reduce_when_necessary(tensor, wrt_dx)
176
- rank = op(:rank, tensor)
177
- dx_rank = op(:rank, wrt_dx)
178
- reduced = op(:reduce_sum, tensor, nil, axis: 0)
179
- op(:cond, ->{ reduced }, tensor, pred: rank > dx_rank)
183
+ rank = _op(:rank, tensor)
184
+ dx_rank = _op(:rank, wrt_dx)
185
+ reduced = _op(:reduce_sum, tensor, nil, axis: 0)
186
+ _op(:cond, ->{ reduced }, tensor, pred: rank > dx_rank)
180
187
  end
181
188
 
182
189
  def self._broadcast_gradient_args(input_a, input_b)
183
- [op(:broadcast_gradient_args, input_a, input_b), op(:broadcast_gradient_args, input_b, input_a)]
190
+ [_op(:broadcast_gradient_args, input_a, input_b), _op(:broadcast_gradient_args, input_b, input_a)]
184
191
  end
185
192
 
186
193
  def self._broadcast_transform(input_a, input_b)
187
- op(:broadcast_transform, input_a, input_b)
194
+ _op(:broadcast_transform, input_a, input_b)
188
195
  end
189
196
 
190
197
  # filter out zero arrays
191
198
  def self._filtered_sum(input_a, input_b, wrt_dx)
192
- zero_vect = op(:zeros_like, wrt_dx)
199
+ zero_vect = _op(:zeros_like, wrt_dx)
193
200
  (i_op(:cond, input_a, zero_vect, pred: i_op(:reduce_sum, input_a) != 0) + i_op(:cond, input_b, zero_vect, pred: i_op(:reduce_sum, input_b) != 0))
194
201
  end
195
202
  end