# 实现属于自己的TensorFlow(一) - 计算图与前向传播

`https://github.com/PytLab/simpleflow`

```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')

# Create a session to compute
with tf.Session() as sess:
print(sess.run(result))```

1、Operation: 操作节点主要接受一个或者两个输入节点然后进行简单的操作运算，例如上图中的加法操作和乘法操作等。

2、Variable: 没有输入节点的节点，此节点包含的数据在运算过程中是可以变化的。

3、Constant: 类似Variable节点，也没有输入节点，此节点中的数据在图的运算过程中不会发生变化

4、Placeholder: 同样没有输入节点，此节点的数据是通过图建立好以后通过用户传入的

Operation节点

1、input_nodes: 输入节点，里面存放与当前节点相连接的输入节点的引用

2、output_nodes: 输出节点, 存放以当前节点作为输入的节点，也就是当前节点的去向

4、name: 当前节点的名称

5、graph: 此节点所属的图 下面我们定义了Operation基类用于表示图中的操作节点(详见https://github.com/PytLab/simpleflow/blob/master/simpleflow/operations.py):

```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

''' Compute and return the gradient of the operation wrt inputs.
'''
raise NotImplementedError```

1、将当前节点的引用添加到他输入节点的output_nodes这样可以在输入节点中找到当前节点。

2、将当前节点的引用添加到图中，方便后面对图中的资源进行回收等操作

```class Add(Operation):
'''
def __init__(self, x, y, name=None):
: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
return self.output_value```

Variable节点

```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```

Constant节点和Placeholder节点

Constant和Placeholder节点与Variable节点类似，具体实现详见:

`https://github.com/PytLab/simpleflow/blob/master/simpleflow/operations.py`

```class Graph(object):
''' Graph containing all computing nodes.
'''
def __init__(self):
''' Graph constructor.
'''
self.operations, self.constants, self.placeholders = [], [], []
self.variables, self.trainable_variables = [], []```

```from .graph import Graph

# Create a default graph.
import builtins
DEFAULT_GRAPH = builtins.DEFAULT_GRAPH = Graph()```

```class Graph(object):
#...
def __enter__(self):
''' Reset default graph.
'''
global DEFAULT_GRAPH
self.old_graph = DEFAULT_GRAPH
DEFAULT_GRAPH = self
return self

def __exit__(self, exc_type, exc_value, exc_tb):
''' Recover default graph.
'''
global DEFAULT_GRAPH
DEFAULT_GRAPH = self.old_graph

def as_default(self):
''' Set this graph as global default graph.
'''
return self```

Ok，根据上面的实现我们已经可以创建一个计算图了:

```import simpleflow as sf

with sf.Graph().as_default():
a = sf.constant([1.0, 2.0], name='a')
b = sf.constant(2.0, name='b')
c = a * b```

```class Session(object):
''' A session to compute a particular graph.
'''
def __init__(self):
''' Session constructor.
'''
# Graph the session computes for.
self.graph = DEFAULT_GRAPH

def __enter__(self):
''' Context management protocal method called before `with-block`.
'''
return self

def __exit__(self, exc_type, exc_value, exc_tb):
''' Context management protocal method called after `with-block`.
'''
self.close()

def close(self):
''' Free all output values in nodes.
'''
all_nodes = (self.graph.constants + self.graph.variables +
self.graph.placeholders + self.graph.operations +
self.graph.trainable_variables)
for node in all_nodes:
node.output_value = None

def run(self, operation, feed_dict=None):
''' Compute the output of an operation.'''
# ...```

```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))```

```array([[  54.,   54.],
[ 106.,  104.]])```

`https://github.com/PytLab/simpleflow`

```Deep Learning From Scratch
https://en.wikipedia.org/wiki/Tree_traversal#Post-order
https://zhuanlan.zhihu.com/p/25496760
http://blog.csdn.net/magic_anthony/article/details/77531552```

0 条评论

• ### 协同过滤的原理及Python实现

作者：李小文，先后从事过数据分析、数据挖掘工作，主要开发语言是Python，现任一家小型互联网公司的算法工程师。

• ### 用Python模拟登录学校教务系统抢课

-- Illustrations by Vladislav Solovjov --

• ### OpenStack中的RESTful API是如何实现的？

OpenStack作为一个开源的IaaS平台，各个组件和服务之间的消息传递都是通过RESTfulAPI和RPC传递，这里主要讲讲它是如何实现REST的。由于大家...

• ### 面向对象:反射,双下方法

反射的概念是由Smith在1982年首次提出的，主要是指程序可以访问、检测和修改它本身状态或行为的一种能力（自省）。这一概念的提出很快引发了计算机科学领域关于应...

• ### 图像处理: 超像素(superpixels)分割 SLIC算法

超像素概念是2003年Xiaofeng Ren提出和发展起来的图像分割技术，是指具有相似纹理、颜色、亮度等特征的相邻像素构成的有一定视觉意义的不规则像素块。它利...

• ### python项目练习八：使用XML-RPC进行远程文件共享

这是个不错的练习，使用python开发P2P程序，或许通过这个我们可以自己搞出来一个P2P下载工具，类似于迅雷。说到迅雷，关于其原理不知道大家是否了解，如果你不...

• ### 用 RNN 训练语言模型生成文本

---- 本文结构： 什么是 Language Model？ 怎么实现？怎么应用？ ---- cs224d Day 8: 项目2-用 RNN 建立 Langua...