linear and logistic regression in TensorFlow

Linear Regression

问题定义:

设X为生育率,Y为预期寿命,能否找到一个线性函数f使得Y = f(X)?

数据集描述:

名称: Birth rate - life expectancy in 2010
X = 生育率. Type: float.
Y = 预期寿命. Type: foat.
数据量: 190
数据形式: (X,Y)

方法1:

假设X和Y之间的关系是线性的,这意味着有w和b,满足:Y_pred = wX + b.
本例中w,b都是scalar,

1
2
w = tf.get_variable('weights',initializer=tf.constant(0.0))
b = tf.get_variable('bias',initializer=tf.constant(0.0))

损失函数使用均方误差

1
2
Y_pred = w*X+b
loss = tf.square(Y-Y_pred,name='loss')

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import tensorflow as tf
import utils

DATA_FILE = "data/birth_life_2010.txt"

# Step 1: 加载数据,形式为(190,2)的numpy数组,每一行代表一个点
data, n_samples = utils.read_birth_life_data(DATA_FILE)

# Step 2: 创建placeholders
X = tf.placeholder(tf.float32, name='X')
Y = tf.placeholder(tf.float32, name='Y')

# Step 3: 创建变量,初始化为0
w = tf.get_variable('weights', initializer=tf.constant(0.0))
b = tf.get_variable('bias', initializer=tf.constant(0.0))

# Step 4: 模型
Y_predicted = w * X + b

# Step 5: 损失函数
loss = tf.square(Y - Y_predicted, name='loss')

# Step 6: GD最小化loss
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)

with tf.Session() as sess:
# Step 7: 变量初始化
sess.run(tf.global_variables_initializer())

# Step 8: 训练100回
for i in range(100): # run 100 epochs
# 每次传入一个数据点,事实上,使用batches of data更好一点。
for x, y in data:
# Session runs train_op to minimize loss
sess.run(optimizer, feed_dict={X: x, Y:y})

# Step 9: output the values of w and b
w_out, b_out = sess.run([w, b])

结论:
经过100次训练后,平均损失为30.04,w = -6.07,b = 84.93。
这证实了我们的假设,即出生率与一个国家人口的预期寿命之间存在负相关关系。 但是,这并不意味着多一个孩子会减少6年的寿命。

方法2:

假设X和Y满足:Y_pred = wX^2 + uX + b

只需修改部分代码:

1
2
3
4
5
6
7
# Step 3: 创建变量,初始化为0
w = tf.get_variable('weights_1', initializer=tf.constant(0.0))
u = tf.get_variable('weights_2', initializer=tf.constant(0.0))
b = tf.get_variable('bias', initializer=tf.constant(0.0))

# Step 4: 模型
Y_predicted = w * X * X + X * u + b

由于平方损失会给离群点太多的权重,这里损失函数考虑使用Huber loss:

tensorflow提供了一些控制流操作:

1
2
3
4
5
6
# 具体实现
def huber_loss(labels, predictions, delta=14.0):
residual = tf.abs(labels - predictions)
def f1(): return 0.5 * tf.square(residual)
def f2(): return delta * residual - 0.5 * tf.square(delta)
return tf.cond(residual < delta, f1, f2)

最后结果为:w: -5.883589, b: 85.124306.

which one is better?

we do need test data set!!!

tf.data

使用placeholder和feed_dicts的好处是将数据处理与TensorFlow分离,使用python就可以轻松地shuffle, batch, generate arbitrary data. 不好的地方是,数据处理的线程很有可能是瓶颈,使整个程序slow down。

使用队列也是TF中处理数据的一个选项,队列允许pipelining、threading操作,减少了数据加载到placeholders的时间,但是难以使用且容易崩溃。

tf.data比placeholder更快,比队列更容易使用,而且不会crash。

数据存储在一个tf.data.Dataset对象中,而不是一个non-TensorFLow对象(numpy array)

tf.data基操:

  1. 创建DataSet

    1. 从tensor创建

      1
      2
      # features,labels都是tensors,也可以是numpy arrays
      tf.data.DataSet.from_tensor_slice((features,labels))
    2. 从file创建

      1
      2
      3
      4
      5
      6
      # 文件每一行代表一个数据,例如csv文件
      tf.data.TextLineDataset(filenames)
      # 每一个文件长度都固定,比如都是28*28的图片
      tf.data.FixedLengthRecordDataset([file1,file2,file3,file4,...])
      # tfrecord格式,(还没用过
      tf.data.TFRecordDataset(filenames)
  2. 创建Iterator

    取dataset中的数据需要用到迭代器

    1
    2
    3
    4
    5
    6
    # 只能遍历一遍
    iterator = dataset.make_one_shot_iterator()
    # 多次初始化,多次遍历
    iterator = dataset.make_initializable_iterator()
    # 返回一个或者一组样本
    iterator.get_next()
  3. 训练

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    iterator = dataset.make_initializable_iterator()
    ...
    for i in range(100):
    # 每一个epoch都要初始化iterator
    sess.run(iterator.initializer)
    total_loss = 0
    try:
    while True:
    sess.run([optimizer])
    except tf.errors.OutOfRangeError:
    pass

其它操作

1
2
3
4
5
6
#简单的命令操作dataset
dataset = dataset.shuffle(1000)
dataset = dataset.repeat(100)
dataset = dataset.batch(128)
dataset = dataset.map(lambda x: tf.one_hot(x, 10))
# convert each element of dataset to one_hot vector

Logistic Regression with MINIST

一个问题:

这个实验有多个数据集,训练集、验证集和测试集,如果每个数据集都有各自的iterator,那我们就得为每一个iterator创建一个graph。

不,可以用一个迭代器,用不同的数据初始化它

1
2
3
4
5
iterator = tf.data.Iterator.from_structure(train_data.output_types,
train_data.output_shapes)
# 每一个epoch的训练前,都要sess.run(train_init)
train_init = iterator.make_initializer(train_data)
test_init = iterator.make_initializer(test_data)

完整代码, tensorboard图示如下:

下一步,尝试将这个graph改造得有条理一些。