Class: Tensorflow::Tensor

Inherits:
Object
  • Object
show all
Defined in:
lib/tensorflow/tensor.rb

Overview

Tensor is an n-dimensional array or list which represents a value produced by an Operation. A tensor has a rank, and a shape. A Tensor is a symbolic handle to one of the outputs of an Operation. It does not hold the values of that operation’s output, but instead provides a means of computing those values in a TensorFlow Session. It holds a multi-dimensional array of elements of a single data type. Official documentation of tensor. This class has two primary purposes:

  • Description :

    • A Tensor can be passed as an input to another Operation. This builds a dataflow connection between

    operations, which enables TensorFlow to execute an entire Graph that represents a large, multi-step computation.

    • After the graph has been launched in a session, the value of the Tensor can be computed by passing it to

    a Session.

The Tensor class takes array as input and creates a Tensor from it using SWIG.

  • Arguments :

    • Data -> A Ruby array to be converted to tensor.

  • Examples :

    input = Tensor.new([[[2,3,4],[2,3,4],[2,3,4]],[[2,3,4],[2,3,4],[2,3,4]]])
    input.shape          =>  [2, 3, 3]
    input.rank           =>  3
    input.element_type   =>  Integer
    

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, type = nil) ⇒ Tensor

Returns a new instance of Tensor.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/tensorflow/tensor.rb', line 43

def initialize(value, type = nil)
    self.shape = self.class.shape_of(value)
    self.rank = shape.size
    self.element_type = type.nil? ? find_type(value) : set_type(type)
    if rank > 1 && type_num == Tensorflow::TF_STRING
        raise 'Multi-dimensional tensor not supported for string value type.'
    end
    self.flatten = [value].flatten
    self.tensor_data = ruby_array_to_c(flatten, type_num)
    self.dimension_data = ruby_array_to_c(
        rank.zero? ? [1] : shape, Tensorflow::TF_INT64
    )
    if type_num == Tensorflow::TF_STRING
     self.tensor = Tensorflow::String_encoder(CString(value), CString([0].pack("Q")) )
     return self
    end
    self.tensor = Tensorflow::TF_NewTensor_wrapper(type_num,
                                                   dimension_data, rank, tensor_data, data_size * flatten.length)
end

Instance Attribute Details

#data_sizeObject

Returns the value of attribute data_size.



27
28
29
# File 'lib/tensorflow/tensor.rb', line 27

def data_size
  @data_size
end

#dimension_dataObject

Returns shape of the tensor in the form of a c array.



43
44
45
# File 'lib/tensorflow/tensor.rb', line 43

def dimension_data
  @dimension_data
end

#element_typeObject

Return data type of the tensor element. (It is best if proper design decision is made regarding this. Because Currently data type support is limited to int64 and double.)



43
44
45
# File 'lib/tensorflow/tensor.rb', line 43

def element_type
  @element_type
end

#flattenObject

Returns data array after flattening it.



43
44
45
# File 'lib/tensorflow/tensor.rb', line 43

def flatten
  @flatten
end

#rankObject

Return the Rank of the Tensor.



43
44
45
# File 'lib/tensorflow/tensor.rb', line 43

def rank
  @rank
end

#shapeObject

Return the shape of the tensor in an array.



43
44
45
# File 'lib/tensorflow/tensor.rb', line 43

def shape
  @shape
end

#tensorObject

Returns the value of attribute tensor.



27
28
29
# File 'lib/tensorflow/tensor.rb', line 27

def tensor
  @tensor
end

#tensor_dataObject

Returns serialized data in the form of a c array.



43
44
45
# File 'lib/tensorflow/tensor.rb', line 43

def tensor_data
  @tensor_data
end

#tensor_shape_protoObject

Returns the value of attribute tensor_shape_proto.



27
28
29
# File 'lib/tensorflow/tensor.rb', line 27

def tensor_shape_proto
  @tensor_shape_proto
end

#type_numObject

Return the enum value of data type.



43
44
45
# File 'lib/tensorflow/tensor.rb', line 43

def type_num
  @type_num
end

Instance Method Details

#deleteObject

Deletes the tensor which will also ensure that the tensor_deallocator function is called and the C++ memory is freed properly. A memory leak will occur anytime the ruby garbage collector deletes a tensor before this function is called.



66
67
68
# File 'lib/tensorflow/tensor.rb', line 66

def delete()
    Tensorflow::TF_DeleteTensor(@tensor)
end

#find_type(data) ⇒ Object

Converts a give ruby array to C array (using SWIG) by detecting the data type automatically. Design decision needs to be made regarding this so the all the data types are supported. Currently Integer(Ruby) is converted to long long© and Float(Ruby) is converted double©.

  • Returns :

    • Data type



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/tensorflow/tensor.rb', line 100

def find_type(data)
    first_element = rank.zero? ? data : data.flatten[0]

    type, self.type_num, self.data_size = case first_element
                                          when Integer
                                              [Integer, Tensorflow::TF_INT64, 8]
                                          when Float, nil
                                              [Float, Tensorflow::TF_DOUBLE, 8]
                                          when String
                                              [String, Tensorflow::TF_STRING, 8]
                                          when Complex
                                              [Complex, Tensorflow::TF_COMPLEX128, 16]
                                          else
                                              raise 'Data type not supported.'
    end

    return type if rank == 0
    if type == Integer || type == Float
        float_flag = type == Float ? 1 : 0
        data.flatten.each do |i|
            raise 'Different data types in array.' unless i.is_a?(Float) || i.is_a?(Integer)
            float_flag = 1 if i.is_a?(Float)
        end
        if float_flag == 1
            type = Float
            self.type_num = Tensorflow::TF_DOUBLE
            self.data_size = 8
        end
    else
        data.flatten.each do |i|
            raise 'Different data types in array.' unless i.is_a?(type)
        end
    end

    type
end

#getval(dimension) ⇒ Object

Returns the value of the element contained in the specified position in the tensor.

  • Input :

    • Dimension array(1 based indexing).

  • Returns :

    • Value of the element contained in the specified position in the tensor.

Raises:

  • ('Invalid dimension array passed as input.')


181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/tensorflow/tensor.rb', line 181

def getval(dimension)
    raise('Invalid dimension array passed as input.', ShapeError) if dimension.length != shape.length
    (0..dimension.length - 1).each do |i|
        raise('Invalid dimension array passed as input.', ShapeError) if dimension[i] > shape[i] || dimension[i] < 1 || !(dimension[i].is_a? Integer)
    end
    sum = dimension.last - 1
    prod = shape.last
    (0..dimension.length - 2).each do |i|
        sum += (dimension[dimension.length - 2 - i] - 1) * prod
        prod *= shape[shape.length - 2 - i]
    end

    flatten[sum]
end

#ruby_array_to_c(array, type) ⇒ Object

Converts a give ruby array to C array (using SWIG) by detecting the data type automatically. Design decision needs to be made regarding this so the all the data types are supported. Currently Integer(Ruby) is converted to long long© and Float(Ruby) is converted double©.

  • Returns :

    • A c array.



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/tensorflow/tensor.rb', line 145

def ruby_array_to_c(array, type)
    c_array = []
    case type
    when Tensorflow::TF_FLOAT
        c_array = Tensorflow::Float.new(array.length)
        array.each_with_index { |value, i| c_array[i] = value }
    when Tensorflow::TF_DOUBLE
        c_array = Tensorflow::Double.new(array.length)
        array.each_with_index { |value, i| c_array[i] = value }
    when Tensorflow::TF_INT32
        c_array = Tensorflow::Int.new(array.length)
        array.each_with_index { |value, i| c_array[i] = value }
    when Tensorflow::TF_INT64
        c_array = Tensorflow::Long_long.new(array.length)
        array.each_with_index { |value, i| c_array[i] = value }
    when Tensorflow::TF_STRING
        c_array = Tensorflow::String_Vector.new
        array.each_with_index { |value, i| c_array[i] = value }
        c_array = Tensorflow.string_array_from_string_vector(c_array)
    else
        c_array = Tensorflow::Complex_Vector.new
        array.each_with_index { |value, i| c_array[i] = value }
        c_array = Tensorflow.complex_array_from_complex_vector(c_array)
    end
    c_array
end

#set_type(type) ⇒ Object

Helper function to automatically set the data type of tensor.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/tensorflow/tensor.rb', line 73

def set_type(type)
    self.type_num, self.data_size, self.element_type = case type
                                                       when :float
                                                           [Tensorflow::TF_FLOAT, 8, Float]
                                                       when :float64
                                                           [Tensorflow::TF_DOUBLE, 8, Float]
                                                       when :int32
                                                           [Tensorflow::TF_INT32, 4, Integer]
                                                       when :int64
                                                           [Tensorflow::TF_INT64, 8, Integer]
                                                       when :string
                                                           [Tensorflow::TF_STRING, 8, String]
                                                       when :complex
                                                           [Tensorflow::TF_COMPLEX128, 16, Complex]
                                                       else
                                                           raise ArgumentError, "Data type #{type} not supported"
    end
end