TensorFlow是Google公司2015年11月开源的第二代深度学习框架,是第一代框架DistBelief的改进版本.
TensorFlow支持python和c/c++语言, 可以在cpu或gpu上进行运算, 支持使用virtualenv或docker打包发布.
TensorFlow支持python2.7可以使用pip安装.仅使用cpu的版本:
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.5.0-cp27-none-linux_x86_64.whl
若安装了CUDA可以使用开启gpu支持的版本:
pip install https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.5.0-cp27-none-linux_x86_64.whl
开始使用
TensorFlow并不是一个纯粹的神经网络框架, 而是使用数据流图进行数值分析的框架.
TensorFlow使用有向图(graph)表示一个计算任务.图的节点称为ops
(operations)表示对数据的处理,图的边flow
描述数据的流向.
该框架计算过程就是处理tensor组成的流. 这也是TensorFlow名称的来源.
TensorFlow使用tensor
表示数据. tensor
意为张量即高维数组,在python中使用numpy.ndarray
表示.
TensorFlow使用Session执行图, 使用Variable维护状态.tf.constant是只能输出的ops, 常用作数据源.
下面我们构建一个只有两个constant做输入, 然后进行矩阵乘的简单图:
from tensorflow import Session, device, constant, matmul
with Session() as session: # 创建执行图的上下文
with device('/cpu:0'): # 指定运算设备
mat1 = constant([[3, 3]]) # 创建源节点
mat2 = constant([[2], [2]])
product = matmul(mat1, mat2) # 指定节点的前置节点, 创建图
result = session.run(product) # 执行计算
print(result)
# I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 4
#I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 4
#[[12]]
如果不使用with session()
语句, 需要手动执行session.close()
.
with device
设备指定了执行计算的设备:
"/cpu:0": 机器的 CPU.
"/gpu:0": 机器的第一个 GPU, 如果有的话.
"/gpu:1": 机器的第二个 GPU, 以此类推.
下面使用Variable做一个计数器:
from tensorflow import Session, constant, Variable, add, assign, initialize_all_variables
state = Variable(0, name='counter') # 创建计数器
one = constant(1) # 创建数据源: 1
val = add(state, one) # 创建新值节点
update = assign(state, val) # 更新计数器
setup = initialize_all_variables() # 初始化Variable
with Session() as session:
session.run(setup) # 执行初始化
print(session.run(state)) # 输出初值
for i in range(3):
session.run(update) # 执行更新
print session.run(state) # 输出计数器值
# 0
# 1
# 2
# 3
在使用变量前必须运行initialize_all_variables()
返回的图, 运行Variable节点将返回变量的值.
本示例中将构建图的过程写在了上下文之外, 而且没有指定运行设备.
上面示例中session.run
只接受一个op作为参数, 实际上run可以接受op列表作为输入:
session.run([op1, op2])
上述示例一直使用constant作为数据源, feed可以在运行时动态地输入数据:
from tensorflow import Session, placeholder, mul, float32
input1 = placeholder(float32)
input2 = placeholder(float32)
output = mul(input1, input2)
with Session() as session:
print session.run(output, feed_dict={input1: [3], input2: [2]})
参考资料:
实现一个简单神经网络
神经网络是应用广泛的机器学习模型, 关于神经网络的原理可以参见这篇随笔, 或者在tensorflow playground上体验一下在线demo.
首先定义一个BPNeuralNetwork类:
class BPNeuralNetwork:
def __init__(self):
self.session = tf.Session()
self.input_layer = None
self.label_layer = None
self.loss = None
self.trainer = None
self.layers = []
def __del__(self):
self.session.close()
编写一个生成单层神经网络函数,每层神经元用一个数据流图表示.使用一个Variable矩阵表示与前置神经元的连接权重, 另一个Variable向量表示偏置值, 并为该层设置一个激励函数.
def make_layer(inputs, in_size, out_size, activate=None):
weights = tf.Variable(tf.random_normal([in_size, out_size]))
basis = tf.Variable(tf.zeros([1, out_size]) + 0.1)
result = tf.matmul(inputs, weights) + basis
if activate is None:
return result
else:
return activate(result)
使用placeholder作为输入层.
self.input_layer = tf.placeholder(tf.float32, [None, 2])
placeholder的第二个参数为张量的形状, [None, 1]
表示行数不限, 列数为1的二维数组, 含义与numpy.array.shape相同.这里, self.input_layer
被定义为接受二维输入的输入层.
同样使用placeholder表示训练数据的标签:
self.label_layer = tf.placeholder(tf.float32, [None, 1])
使用make_layer
为神经网络定义两个隐含层, 并用最后一层作为输出层:
self.layers.append(make_layer(self.input_layer, 1, 10, activate=tf.nn.relu))
self.layers.append(make_layer(self.layers[0], 10, 1, activate=None))
可以看到第一个隐含层接受input_layer
的二维输入并产生十维输出, 第二隐含层接受来自第一隐含层的十维输入并产生一维输出.
可以对比第二隐含层的输出和训练标签定义损失函数:
self.loss = tf.reduce_mean(tf.reduce_sum(tf.square((self.label_layer - self.layers[1])), reduction_indices=[1]))
tf.train提供了一些优化器, 可以用来训练神经网络.以损失函数最小化为目标:
self.trainer = tf.train.GradientDescentOptimizer(learn_rate).minimize(self.loss)
使用Session运行神经网络模型:
initer = tf.initialize_all_variables()
# do training
self.session.run(initer)
for i in range(limit):
self.session.run(self.trainer, feed_dict={self.input_layer: cases, self.label_layer: labels})
使用训练好的模型进行预测:
self.session.run(self.layers[-1], feed_dict={self.input_layer: case})
完整源代码在这里查看.
上述模型虽然简单但是使用不灵活, 作者采用同样的思想实现了一个可以自定义输入输出维数以及多层隐含神经元的网络, 可以参见这里.