import simpleflow as sf
# Create a graph
with sf.Graph().as_default():
a = sf.constant(1.0, name='a')
b = sf.constant(2.0, name='b')
result = sf.add(a, b, name='result')
# Create a session to compute
with tf.Session() as sess:
print(sess.run(result))
class Operation(object):
''' Base class for all operations in simpleflow.
An operation is a node in computational graph receiving zero or more nodes
as input and produce zero or more nodes as output. Vertices could be an
operation, variable or placeholder.
'''
def __init__(self, *input_nodes, name=None):
''' Operation constructor.
:param input_nodes: Input nodes for the operation node.
:type input_nodes: Objects of `Operation`, `Variable` or `Placeholder`.
:param name: The operation name.
:type name: str.
'''
# Nodes received by this operation.
self.input_nodes = input_nodes
# Nodes that receive this operation node as input.
self.output_nodes = []
# Output value of this operation in session execution.
self.output_value = None
# Operation name.
self.name = name
# Graph the operation belongs to.
self.graph = DEFAULT_GRAPH
# Add this operation node to destination lists in its input nodes.
for node in input_nodes:
node.output_nodes.append(self)
# Add this operation to default graph.
self.graph.operations.append(self)
def compute_output(self):
''' Compute and return the output value of the operation.
'''
raise NotImplementedError
def compute_gradient(self, grad=None):
''' Compute and return the gradient of the operation wrt inputs.
'''
raise NotImplementedError
class Add(Operation):
''' An addition operation.
'''
def __init__(self, x, y, name=None):
''' Addition constructor.
:param x: The first input node.
:type x: Object of `Operation`, `Variable` or `Placeholder`.
:param y: The second input node.
:type y: Object of `Operation`, `Variable` or `Placeholder`.
:param name: The operation name.
:type name: str.
'''
super(self.__class__, self).__init__(x, y, name=name)
def compute_output(self):
''' Compute and return the value of addition operation.
'''
x, y = self.input_nodes
self.output_value = np.add(x.output_value, y.output_value)
return self.output_value
class Variable(object):
''' Variable node in computational graph.
'''
def __init__(self, initial_value=None, name=None, trainable=True):
''' Variable constructor.
:param initial_value: The initial value of the variable.
:type initial_value: number or a ndarray.
:param name: Name of the variable.
:type name: str.
'''
# Variable initial value.
self.initial_value = initial_value
# Output value of this operation in session execution.
self.output_value = None
# Nodes that receive this variable node as input.
self.output_nodes = []
# Variable name.
self.name = name
# Graph the variable belongs to.
self.graph = DEFAULT_GRAPH
# Add to the currently active default graph.
self.graph.variables.append(self)
if trainable:
self.graph.trainable_variables.append(self)
def compute_output(self):
''' Compute and return the variable value.
'''
if self.output_value is None:
self.output_value = self.initial_value
return self.output_value
def _get_prerequisite(operation):
''' Perform a post-order traversal to get a list of nodes to be computed in order.
'''
postorder_nodes = []
# Collection nodes recursively.
def postorder_traverse(operation):
if isinstance(operation, Operation):
for input_node in operation.input_nodes:
postorder_traverse(input_node)
postorder_nodes.append(operation)
postorder_traverse(operation)
return postorder_nodes
class Session(object):
# ...
def run(self, operation, feed_dict=None):
''' Compute the output of an operation.
:param operation: A specific operation to be computed.
:type operation: object of `Operation`, `Variable` or `Placeholder`.
:param feed_dict: A mapping between placeholder and its actual value for the session.
:type feed_dict: dict.
'''
# Get all prerequisite nodes using postorder traversal.
postorder_nodes = _get_prerequisite(operation)
for node in postorder_nodes:
if type(node) is Placeholder:
node.output_value = feed_dict[node]
else: # Operation and variable
node.compute_output()
return operation.output_value
例子
上面我们实现了计算图以及前向传播,我们就可以创建计算图计算表达式的值了, 如下:
import simpleflow as sf
# Create a graph
with sf.Graph().as_default():
w = sf.constant([[1, 2, 3], [3, 4, 5]], name='w')
x = sf.constant([[9, 8], [7, 6], [10, 11]], name='x')
b = sf.constant(1.0, 'b')
result = sf.matmul(w, x) + b
# Create a session to compute
with sf.Session() as sess:
print(sess.run(result))