已经花了1天时间,把Tensorflow环境搭建好,并且初步了解了Python的语法情况。那么可以开始探索一下,进入TensorFlow的世界了。

Tensor

特地词典搜了一下Tensor和Flow这两个单词,Tensor被翻译为张量,搜图出来的大部分和肌肉有关,Flow无非就是流了。张量这个词本身在中文里也不是个形象可理解的词,姑且先把Tensor理解成是个名词,而这总是不会错的。慢慢的接触下来,感觉可以理解成矩阵?以下是官网给的例子,可以对Tensor有更直观的理解。

3 # a rank 0 tensor; a scalar with shape []
[1., 2., 3.] # a rank 1 tensor; a vector with shape [3]
[[1., 2., 3.], [4., 5., 6.]] # a rank 2 tensor; a matrix with shape [2, 3]
[[[1., 2., 3.]], [[7., 8., 9.]]] # a rank 3 tensor with shape [2, 1, 3]

计算图(computational graph)

TensorFlow代码核心思想主要分两步

第一步:构建计算图(Building the computational graph.)

第二步:执行计算图(Running the computational graph.)

那么什么是计算图(computational graph)呢?

官网的解释直译过来是:一系列的计算节点组成的图。每一个计算节点(node)用0或多个Tensor作为输入,并且产生一个Tensor作为输出。其中特殊的,输入使用0个Tensor的,就是常量了,例如:

node1 = tf.constant(3.0, dtype=tf.float32)
node2 = tf.constant(4.0) # also tf.float32 implicitly
print(node1, node2)

输出并不是设想中的3.0 , 4.0而是

(<tf.Tensor 'Const:0' shape=() dtype=float32>, <tf.Tensor 'Const_1:0' shape=() dtype=float32>)

因为我们只是构建了计算图,而没有执行它。我们在session中执行计算图。

sess = tf.Session()
print(sess.run([node1, node2]))

此时输出的就是 [3.0,4.0]了

另外,运算本身也可以看作一个节点,如下例:

node3 = tf.add(node1, node2)
print("node3:", node3)
print("sess.run(node3):", sess.run(node3))

Placeholder

计算图构建期的占位符,在执行期间设置参数。

node1 = tf.placeholder(tf.float32)
node2 = tf.placeholder(tf.float32)
adder_node = node1 + node2
print(sess.run(adder_node, {a: 3, b: 4.5}))
print(sess.run(adder_node, {a: [1, 3], b: [2, 4]}))

一个实际的线性拟合并计算损失函数的例子

(损失函数loss类似统计学里的方差概念,方差一般用于衡量偏移的大小,类似的概念还有信息熵,用于衡量事务的不确定性。此时有种预感,后续一定会有遇到以信息熵最低来判断模型优劣的场景。)

import tensorflow as tf

# 模型参数
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# 模型输入输出
x = tf.placeholder(tf.float32)
linear_model = W*x + b
y = tf.placeholder(tf.float32)

# 损失函数
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# 优化训练
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)

# 训练数据
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]
# 训练循环
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, {x: x_train, y: y_train})
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

经过1000次的训练,输出结果接近于自己手算的W=-1,b=1, Loss=0

W:  [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11

修改最后的几行代码(最后两行各加两个空格,让1000次训练,将W,b,loss都输出出来)可以看到训练的过程,W和b接近“正确值”的过程由急变缓,越来越接近。这里采用了tf.train.GradientDescentOptimizer, 直译为梯度下降法。具体算法相关的不在此论述。

tf.estimator

官网对其的介绍是一个高阶的可以简化机器学习机制的库。它自带的很多模型可以处理大部分场景,避免重复造轮子。

import numpy as np
import tensorflow as tf

# Declare list of features. We only have one numeric feature. There are many
# other types of columns that are more complicated and useful.
feature_columns = [tf.feature_column.numeric_column("x", shape=[1])]

# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# linear classification, and many neural network classifiers and regressors.
# The following code provides an estimator that does linear regression.
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)

# TensorFlow provides many helper methods to read and set up data sets.
# Here we use two data sets: one for training and one for evaluation
# We have to tell the function how many batches
# of data (num_epochs) we want and how big each batch should be.
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)

# We can invoke 1000 training steps by invoking the  method and passing the
# training data set.
estimator.train(input_fn=input_fn, steps=1000)

# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)

当然也总有一些需要自己造轮子的时候,可以自定义tf.estimator.Estimator的子类。例如上例的tf.estimator.LinearRegressor就是tf.estimator.Estimator的子类。

当然也可以像如下做法:定义model_fn,告知该如何计算predictions,loss和train_op

import numpy as np
import tensorflow as tf

# Declare list of features, we only have one real-valued feature
def model_fn(features, labels, mode):
  # Build a linear model and predict values
  W = tf.get_variable("W", [1], dtype=tf.float64)
  b = tf.get_variable("b", [1], dtype=tf.float64)
  y = W*features['x'] + b
  # Loss sub-graph
  loss = tf.reduce_sum(tf.square(y - labels))
  # Training sub-graph
  global_step = tf.train.get_global_step()
  optimizer = tf.train.GradientDescentOptimizer(0.01)
  train = tf.group(optimizer.minimize(loss),
                   tf.assign_add(global_step, 1))
  # EstimatorSpec connects subgraphs we built to the
  # appropriate functionality.
  return tf.estimator.EstimatorSpec(
      mode=mode,
      predictions=y,
      loss=loss,
      train_op=train)

estimator = tf.estimator.Estimator(model_fn=model_fn)
# define our data sets
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7., 0.])
input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)

# train
estimator.train(input_fn=input_fn, steps=1000)
# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)