class TensorStream::Train::Optimizer

Base class for an optimizer This is a straight up port from the python version

Attributes

name[R]

Public Class Methods

new(name:, use_locking:) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 10
def initialize(name:, use_locking:)
  @name = name
  @use_locking = use_locking
  raise TensorStream::ValueError, "Must specify the optimizer name" unless @name

  @slots = {}
  @non_slots = {}
end

Public Instance Methods

apply_gradients(grads_and_vars, global_step: nil, name: nil) click to toggle source

Apply gradients to variables. This is the second part of minimize(). It returns an Operation that applies gradients.

# File lib/tensor_stream/train/optimizer.rb, line 27
def apply_gradients(grads_and_vars, global_step: nil, name: nil)
  varlist = grads_and_vars.map { |_grad, var| var }
  create_slots(varlist)
  TensorStream.name_scope(name, default: @name) do
    prepare
    apply_ops = grads_and_vars.map { |grad, var|
      TensorStream.name_scope("update_" + var.op.name) do
        apply_dense(grad, var)
      end
    }

    if global_step.nil?
      finish(apply_ops, name)
    else
      TensorStream.control_dependencies([finish(apply_ops, "update")]) do
        global_step.assign_add(1)
      end
    end
  end
end
compute_gradients(loss, var_list: nil, grad_loss: nil) click to toggle source

Compute gradients of loss for the variables in var_list.

This is the first part of minimize(). It returns a list of (gradient, variable) pairs where “gradient” is the gradient for “variable”.

# File lib/tensor_stream/train/optimizer.rb, line 52
def compute_gradients(loss, var_list: nil, grad_loss: nil)
  trainable_vars = if var_list
    raise "var_list must be an array" unless var_list.is_a?(Array)

    var_list.each_with_index { |var, index| raise "var #{index} not a Variable" unless var.is_a?(Variable) }

    var_list
  else
    loss.graph.get_collection(TensorStream::GraphKeys::TRAINABLE_VARIABLES)
  end
  all_grads = grad_loss || TensorStream.gradients(loss, trainable_vars)
  trainable_vars.each_with_index.collect do |var, index|
    [all_grads[index], var]
  end
end
get_slot(var, name) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 68
def get_slot(var, name)
  named_slots = @slots.fetch(name, nil)
  return nil if named_slots.nil?

  named_slots.fetch(var_key(var), nil)
end
get_slot_names() click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 75
def get_slot_names
  @slots.keys.sort
end
minimize(loss, var_list: nil, grad_loss: nil, global_step: nil, name: nil) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 19
def minimize(loss, var_list: nil, grad_loss: nil, global_step: nil, name: nil)
  grads_and_vars = compute_gradients(loss, var_list: var_list, grad_loss: grad_loss)
  apply_gradients(grads_and_vars, global_step: global_step, name: name)
end

Protected Instance Methods

apply_dense(_grad, _var) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 93
def apply_dense(_grad, _var)
  raise TensorStream::NotImplementedError, "not implemented"
end
call_if_callable(param) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 137
def call_if_callable(param)
  param.is_a?(Proc) ? param.call : param
end
create_non_slot_variable(initial_value, name, colocate_with) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 141
def create_non_slot_variable(initial_value, name, colocate_with)
  graph = colocate_with.graph

  key = [name, graph]
  v = @non_slots.fetch(key, nil)
  if v.nil?
    v = TensorStream.variable(initial_value, name: name, trainable: false)
    @non_slots[key] = v
  end
  v
end
create_slots(var_list) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 85
def create_slots(var_list)
  # no implementation
end
finish(update_ops, name_scope) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 81
def finish(update_ops, name_scope)
  TensorStream.group(update_ops, name: name_scope)
end
get_non_slot_variable(name, graph: nil) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 132
def get_non_slot_variable(name, graph: nil)
  non_slot = @non_slots.fetch([name, graph], nil)
  non_slot
end
get_or_make_slot_with_initializer(var, initializer, shape, dtype, slot_name, op_name) click to toggle source

Find or create a slot for a variable, using an Initializer.

# File lib/tensor_stream/train/optimizer.rb, line 155
def get_or_make_slot_with_initializer(var, initializer, shape, dtype, slot_name, op_name)
  named_slots = slot_dict(slot_name)
  unless named_slots.key?(var_key(var))
    new_slot_variable = create_slot_with_initializer(var, initializer, shape, dtype, op_name)
    named_slots[var_key(var)] = new_slot_variable
  end
  named_slots[var_key(var)]
end
prepare() click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 89
def prepare
  # no implementation
end
slot_dict(slot_name) click to toggle source

Returns a dict for caching slots created under the given name.

Args: slot_name string Name for the slot

Returns: A dict that maps primary 'Variable' objects to the slot created

# File lib/tensor_stream/train/optimizer.rb, line 119
def slot_dict(slot_name)
  named_slots = @slots.fetch(slot_name, nil)
  if named_slots.nil?
    named_slots = {}
    @slots[slot_name] = named_slots
  end
  named_slots
end
var_key(var) click to toggle source
# File lib/tensor_stream/train/optimizer.rb, line 128
def var_key(var)
  [var.op.graph, var.op.name]
end
zeros_slot(var, slot_name, op_name) click to toggle source

Find or create a slot initialized with 0.0.

Args:

var: Variable - A Variable object
slot_name: string - Name for the slot
op_name: string - Name to use when scoping the Variable that needs to be created
# File lib/tensor_stream/train/optimizer.rb, line 104
def zeros_slot(var, slot_name, op_name)
  named_slots = slot_dict(slot_name)
  unless named_slots.key?(var_key(var))
    named_slots[var_key(var)] = create_zeros_slot(var, op_name)
  end
  named_slots[var_key(var)]
end