class TensorStream::Evaluator::RubyEvaluator

PURE ruby evaluator used for testing and development

Attributes

retain[RW]

Public Class Methods

get_storage_manager() click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 48
def self.get_storage_manager
  RubyStorageManager.current_storage_manager
end

Public Instance Methods

complete_eval(tensor, context) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 76
def complete_eval(tensor, context)
  Kernel.loop do
    old_tensor = tensor
    tensor = run(tensor, context)

    tensor = tensor.map { |t| complete_eval(t, context) } if tensor.is_a?(Array) && !tensor.empty? && tensor[0].is_a?(Tensor)

    break if old_tensor.equal?(tensor)
    break unless tensor.is_a?(Tensor)
  end

  tensor.is_a?(OutputGroup) ? tensor.outputs : tensor
end
run(tensor, execution_context) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 52
def run(tensor, execution_context)
  return tensor.map { |t| run(t, execution_context) } if tensor.is_a?(Array) && !tensor.empty? && tensor[0].is_a?(Tensor)

  tensor = tensor.call if tensor.is_a?(Proc)

  child_context = execution_context.dup
  res = if tensor.is_a?(Operation)
          eval_operation(tensor, child_context)
        elsif !tensor.is_a?(Tensor)
          tensor
        else
          tensor.op
        end
  execution_context.deep_merge!(returns: child_context[:returns])
  res
end
run_with_buffer(tensor, context, execution_context) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 69
def run_with_buffer(tensor, context, execution_context)
  @context = context
  @context[:_cache][:_cl_buffers] ||= {} if context[:_cache]
  result = run(tensor, execution_context)
  TensorStream::Buffer.new(data_type: tensor.data_type, buffer: result)
end

Protected Instance Methods

convert_from_buffer(_tensor, result) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 280
def convert_from_buffer(_tensor, result)
  result.buffer
end
eval_operation(tensor, child_context) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 240
def eval_operation(tensor, child_context)
  return @context[tensor.name] if @context.key?(tensor.name)

  # puts "ruby eval #{tensor.operation} -> #{object_id}: #{tensor.name}"
  invoke(tensor, child_context).tap do |result|
    # puts "result done ruby #{object_id}: #{tensor.name}"
    # assertions to make sure inferred shapes == actual evaluated shapes
    if tensor.shape.known? && (result.is_a?(Array) || result.is_a?(Float) || result.is_a?(Integer))
      raise "assert error #{tensor.name} #{shape_eval(result)} != #{tensor.shape.shape}" if shape_eval(result) != tensor.shape.shape
    end

    if tensor.breakpoint
      a = tensor.inputs[0] if tensor.inputs && tensor.inputs[0]
      b = tensor.inputs[1] if tensor.inputs && tensor.inputs[1]
      a = complete_eval(a, child_context)
      b = complete_eval(b, child_context)
      tensor.breakpoint.call(tensor, a, b, complete_eval(result, child_context))
    end
    if @log_intermediates
      @context[:compute_history] << {
        name: tensor.name,
        type: tensor.data_type,
        shape: shape_eval(result),
        source: tensor.source,
        description: tensor.to_math(true, 1),
        value: result,
      }
    end
    @context[tensor.name] = result
  end
rescue EvaluatorExcecutionException => e
  raise e, "error #{e.message} while evaluating #{tensor.name} defined at #{tensor.source}"
rescue TensorStreamError => e
  raise e, "error #{e.message} while evaluating #{tensor.name} defined at #{tensor.source}"
rescue StandardError => e
  puts e.message
  puts e.backtrace.join("\n")
  raise EvaluatorExcecutionException.new(e, tensor), "error #{e.message} while evaluating #{tensor.name} : #{tensor.to_math(true, 1)} defined at #{tensor.source}"
end
prepare_input(tensor, context, options = {}) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 104
def prepare_input(tensor, context, options = {})
  return nil unless tensor

  if options[:noop]
    tensor
  elsif options[:no_eval]
    run(tensor, context)
  else
    complete_eval(tensor, context)
  end
end
var_assign_value(tensor, value) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 97
def var_assign_value(tensor, value)
  @storage_manager ||= TensorStream::RubyStorageManager.current_storage_manager
  @storage_manager.assign_value(tensor.graph, tensor.options[:var_name] || tensor.name, value)

  value
end
var_read_value(tensor) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 92
def var_read_value(tensor)
  @storage_manager ||= TensorStream::RubyStorageManager.current_storage_manager
  @storage_manager.read_value(tensor.graph, tensor.options[:var_name])
end

Private Instance Methods

_get_randomizer(tensor, seed) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 412
def _get_randomizer(tensor, seed)
  if tensor.graph.random_seed && seed
    Random.new(tensor.graph.random_seed ^ seed)
  elsif tensor.graph.random_seed
    @session.randomizer[tensor.graph.object_id] ||= Random.new(tensor.graph.random_seed)
    @session.randomizer[tensor.graph.object_id]
  elsif seed
    @session.randomizer[tensor.operation] ||= Random.new(seed)
    @session.randomizer[tensor.operation]
  else
    Random.new
  end
end
_rank_from_shape(shape) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 344
def _rank_from_shape(shape)
  shape.is_a?(Array) ? shape.size : 0
end
all_true?(arr) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 383
def all_true?(arr)
  if arr.is_a?(Array)
    arr.each do |a|
      return false unless all_true?(a)
    end
    return true
  end

  !!arr
end
call_3way_vector_op(v_a, v_b, v_c, child_context) { |v_a, v_b, v_c| ... } click to toggle source

handle 3 tensor math operations

# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 369
def call_3way_vector_op(v_a, v_b, v_c, child_context, &block)
  return yield(v_a, v_b, v_c) unless v_a.is_a?(Array)

  v_a.each_with_index.collect do |v1, index|
    v2 = v_b[index]
    v3 = v_c.is_a?(Array) ? v_c[index] : v_c
    if v1.is_a?(Array)
      call_3way_vector_op(v1, v2, v3, child_context, &block)
    else
      yield(v1, v2, v3)
    end
  end
end
call_op(a, child_context, &block) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 300
def call_op(a, child_context, &block)
  a = complete_eval(a, child_context)
  process_function_op(a, &block)
end
call_vector_op(tensor, op, a, b, child_context, &block) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 305
def call_vector_op(tensor, op, a, b, child_context, &block)
  process_vector_math_op(tensor, a, b, child_context, &block)
rescue FullEvalNotPossible
  TensorStream.send(op.to_sym, a, b)
end
concat(a, b, axis) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 358
def concat(a, b, axis)
  if axis.zero?
    a + b
  else
    a.each_with_index.collect do |i, index|
      concat(i, b[index], axis - 1)
    end
  end
end
concat_array(values, axis) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 348
def concat_array(values, axis)
  combined_array = values.shift
  axis = get_rank(combined_array) - 1 if axis == -1

  values.each do |v|
    combined_array = concat(combined_array, v, axis)
  end
  combined_array
end
dump_intermediates() click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 426
def dump_intermediates
  arr = []
  arr << "============== start ==================="
  @context[:compute_history].each_with_index do |history, _index|
    arr << "------------------------------------"
    arr << history[:name]
    arr << "#{history[:type]} #{history[:shape]}"
    arr << history[:source]
    arr << history[:description]
    arr << ""
    arr << history[:value].to_json
    arr << "------------------------------------"
  end
  arr << "============== end ====================="
  str = arr.join("\n")
  File.write("/tmp/intermediates.txt", str)
end
generate_vector(shape, dtype: :float32, generator:) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 394
def generate_vector(shape, dtype: :float32, generator:)
  if shape.is_a?(Integer)
    Array.new(shape) do
      generator.call
    end
  elsif shape.size > 1
    Array.new(shape[0]) do
      generate_vector(shape[1..shape.size], generator: generator, dtype: dtype)
    end
  elsif shape.size == 1
    Array.new(shape[0]) do
      generator.call
    end
  elsif shape.size.zero?
    generator.call
  end
end
get_op_with_axis(a, target_axis, current_axis, op) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 286
def get_op_with_axis(a, target_axis, current_axis, op)
  rank = get_rank(a)
  return a.send(:"#{op}_index") if rank == 1

  if current_axis == target_axis
    compare_items = a.collect(&:flatten).transpose
    compare_items.map { |item| item.index(item.send(:"#{op}")) }
  elsif a[0].is_a?(Array)
    a.map { |item| get_op_with_axis(item, target_axis, current_axis + 1, op) }
  else
    return a.send(:"#{op}_index")
  end
end
multi_array_op(func, *args) click to toggle source

multi array ops on ruby arrays with same sizes

# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 332
def multi_array_op(func, *args)
  elem = args[0]
  if elem.is_a?(Array)
    elem.each_with_index.collect do |_item, index|
      indexed_args = args.collect { |a| a = a.is_a?(Array) ? a : [a]; a[index] }
      multi_array_op(func, *indexed_args)
    end
  else
    func.call(*args)
  end
end
process_vector_math_op(tensor, a, b, child_context, &block) click to toggle source
# File lib/tensor_stream/evaluator/ruby_evaluator.rb, line 311
def process_vector_math_op(tensor, a, b, child_context, &block)
  eval_a = global_eval(tensor, a, child_context) unless a.nil?
  eval_b = global_eval(tensor, b, child_context) unless b.nil?

  raise FullEvalNotPossible.new, "full eval not possible for #{a.name}" if eval_a.is_a?(Tensor) || eval_b.is_a?(Tensor)

  # ruby scalar
  eval_a, eval_b = broadcast(eval_a, eval_b)
  vector_op(eval_a, eval_b, &block)
  # if get_rank(eval_a).zero?
  #   if get_rank(eval_b).zero?
  #     op.call(eval_a, eval_b)
  #   else
  #     vector_op(eval_b, eval_a, op, true)
  #   end
  # else
  #   vector_op(eval_a, eval_b, op)
  # end
end