Class: TensorStream::Evaluator::BaseEvaluator

Inherits:
Object
  • Object
show all
Defined in:
lib/tensor_stream/evaluator/base_evaluator.rb

Overview

Evaluator base class

Base class to be used by all tensor_stream evaluators, provides support functions

Direct Known Subclasses

RubyEvaluator

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(session, _device, thread_pool: nil, log_intermediates: false) ⇒ BaseEvaluator

Returns a new instance of BaseEvaluator.



33
34
35
36
37
38
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 33

def initialize(session, _device, thread_pool: nil, log_intermediates: false)
  @session = session
  @log_intermediates = log_intermediates
  @thread_pool = thread_pool || Concurrent::ImmediateExecutor.new
  @context[:compute_history] = [] if log_intermediates
end

Class Method Details

.default_deviceObject

Select the best device available in the system for this evaluator



48
49
50
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 48

def self.default_device
  Device.new("cpu", :cpu, self)
end

.fetch_device(_query = []) ⇒ Object

Selects the best device with the specified query, query can be evaluator specific



55
56
57
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 55

def self.fetch_device(_query = [])
  Device.new("cpu", :cpu, self)
end

.opsObject

gets all supported ops for this Evaluator class



113
114
115
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 113

def self.ops
  @ops ||= {}
end

.query_device(query) ⇒ Object

Select device using uri



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 61

def self.query_device(query)
  return default_device if query.nil? || query == :default

  all_devices = query_supported_devices
  substrs = query.split("/")
  substrs.each do |q|
    components = q.split(":")
    next if components.size.zero?

    if components[0] == "device" # use tensorflow convention
      device_type = components[1]
      select_index = components[2].to_i

      devices = all_devices.select { |d| d.type == device_type.downcase.to_sym }
      return nil if devices.empty?

      select_index = [devices.size - 1, select_index].min
      return devices[select_index]
    elsif %w[cpu gpu].include?(components[0])
      device_type = components[0].to_sym
      select_index = components[1].to_i

      devices = all_devices.select { |d| d.type == device_type.downcase.to_sym }
      return nil if devices.empty?

      select_index = [devices.size - 1, select_index].min
      return devices[select_index]
    elsif components[0] == "ts" # tensorstream specific
      evaluator_class = TensorStream::Evaluator.evaluators[components[1]][:class]
      return nil unless self == evaluator_class
      return evaluator_class.fetch_device(components[2..components.size]) if evaluator_class.respond_to?(:fetch_device)

      return nil
    end
  end
end

.query_supported_devicesObject

Query all supported devices



42
43
44
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 42

def self.query_supported_devices
  [Device.new("cpu", :cpu, self)]
end

.register_op(opcode, options = {}, &block) ⇒ Object

registers an op for the current evaluator class



100
101
102
103
104
105
106
107
108
109
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 100

def self.register_op(opcode, options = {}, &block)
  @ops ||= {}
  if opcode.is_a?(Array)
    opcode.each do |op|
      @ops[op.to_sym] = {options: options, block: block}
    end
  else
    @ops[opcode.to_sym] = {options: options, block: block}
  end
end

Instance Method Details

#invoke(tensor, execution_context) ⇒ Object

Raises:



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/tensor_stream/evaluator/base_evaluator.rb', line 117

def invoke(tensor, execution_context)
  return eval_tensor(tensor, execution_context) unless tensor.is_a?(Operation)
  raise UnsupportedOp.new(tensor), "op #{tensor.operation} is not yet supported" unless self.class.ops.key?(tensor.operation.to_sym)

  op = self.class.ops[tensor.operation.to_sym]
  op_options = op[:options]

  resolved_inputs = tensor.inputs.map { |i|
    next if i.nil?
    next i if op_options[:noop]

    if i.is_a?(Array)
      next i.collect { |sub_item| sub_item.is_a?(Tensor) ? global_eval(tensor, sub_item, execution_context) : sub_item }
    end

    global_eval(tensor, i, execution_context, op_options)
  }

  start_time = if profile_enabled?
    time = Time.now
    time.to_i * (10**9) + time.nsec
  end

  instance_exec(execution_context, tensor, resolved_inputs, &op[:block]).tap do |result|
    if profile_enabled?
      time = Time.now
      end_time = time.to_i * (10**9) + time.nsec
      @context[:profile] ||= {step: 0, operations: {}}
      @context[:profile][:step] += 1
      @context[:profile][:operations][tensor.name] = {op: tensor.operation,
                                                       step: @context[:profile][:step],
                                                       eval_time: end_time - start_time,
                                                       shape: tensor.shape ? tensor.shape.shape : nil,
                                                       data_type: tensor.data_type,
                                                       tensor: tensor,}
    end
  end
end