A Simple Tensorflow Classification Model in Ruby

The main objective of this blog is to build a simple linear classification model in ruby using Tensorflow architecture. The main tensorflow compenents required to build and test the model are Operation, Placeholder, Variable and Session. These components are written as ruby classes. Lets start with the Operation class.

class Operation
  attr_accessor  :input_nodes, :output, :input

  def initialize(*input_nodes)
    @input_nodes = input_nodes
  end

  def compute
    raise "Should be implemented"
  end

end

The Operation class forms the basis of all the computation in tensorflow. The compute method carries out the computation required. Let us create few classes which inherit the Operation class and we will use sigmoid as the activation function for the model

require Matrix
class Add < Operation
  def initialize(*nodes)
    @input_nodes=nodes
  end

  def compute(x,y)
    return x.element(0,0) + y
  end
end

class Matmul < Operation
  def initialize(*nodes)
    @input_nodes=nodes
  end

  def compute(x,y)
    return Matrix[x] * Matrix[y].transpose
  end
end

class Sigmoid < Operation
  def initialize(*nodes)
    @input_nodes=nodes
  end

  def compute(z)
    1/(1+Math.exp(-z))
  end
end

Load the Matrix library at the begining for matrix computation. Now that we have created basic operation classes we will proceed to other components.

class Placeholder
  attr_accessor  :value, :output
end

class Variable
  attr_accessor  :value, :output

  def initialize(value)
    @value = value
  end
end

The Placeholder class holds objects which are input or output of the model. These object act as constant and their values dont change during the session. The Variable holds objects whose values are either weights or bias given to the model. In the actual tensorflow model these values are updated using the optimizer(eg AdamOptimizer, Stocastic Gradient Descent etc). We wont be updating any value in our approach. We are fixing the value for weight and bias as [1,1] and -5 respectively. Now we will define the session class.

class Session

  def run(operation,feed_dict={})
    nodes = traverse_postorder(operation)
    nodes.each do |node|
      if node.is_a? Placeholder
        node.output = feed_dict[node.object_id]
      elsif node.is_a? Variable
        node.output = node.value
      else
        node.input = node.input_nodes.map { |input| input.output }
        node.output = node.compute(*node.input)
      end
    end
    operation.output
  end
  
  def traverse_postorder(operation)
    node_operators = []
    recurse(operation,node_operators)
  end

  def recurse(node,node_operators)
    if node.is_a?(Operation)
      node.input_nodes.each do |input_node|
        recurse(input_node,node_operators)
      end
    end
    node_operators << node
  end
  
end

The Session class takes care of all the executions. It first converts the set of operations to postfix order. The operations are then executed one by one. Since we have created all the components required, lets jump into action.

W = Variable.new([1,1]) #Weight
b = Variable.new(-5) #bias
x = Placeholder.new() #input
y = Matmul.new(W,x)
z = Add.new(y,b) 
a = Sigmoid.new(z) #activation function
sess = Session.new()

Lets see the prediction for two extreme points

result = sess.run(a,feed_dict={x.object_id=>[0,-10]})
puts(result)%
3.059022269256247e-07

The point (0,-10) lies towards the lower left corner of the graph hence the sigmoid value is closer to 0

result = sess.run(a,feed_dict={x.object_id=>[8,10]})
puts(result)%
0.999997739675702

For the point (8,10) which lies near the upper right corner of the graph the sigmoid value is closer to 1.

Hope this example gives a good understanding of basic components of tensorflow in ruby. Happy learning !!!


•     •     •



← Previous Blog
Next Blog →