TensorFlow 线性回归

1. TensorFlow 实现线性回归

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import tensorflow as tf
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

def linear_regression():
"""
自实现一个线性回归预测
:return: None
"""

with tf.variable_scope("data"):
"""
第1步: 生成实验数据
"""

# 生成 x,张量形状100行1列 [100, 1]
x = tf.random_normal([100, 1], mean=1.75, stddev=0.5, name="x_data")

# 生成 y=0.7x+0.8,矩阵相乘必须是二维的,所以0.7表示成 [[0.7]]
y_true = tf.matmul(x, [[0.7]]) + 0.8

with tf.variable_scope("model"):
"""
第2步:建立线性回归模型 y=w*x+b
weight(w): 权重
bias(b): 偏置
随机给生成weight和bias初始值,计算y_predict=x*w+b,再去计算损失,再在当前状态下优化

注意weight/bias用tf.Variable定义为变量才能优化,不能定义为常量
"""

# tf.random_normal生成一个随机的weight,形状[1, 1]
weight = tf.Variable(tf.random_normal([1, 1], mean=0.0, stddev=1.0), name="w")
# 生成bias,设置为0.0即可
bias = tf.Variable(0.0, name="b")

# 计算y_predict = x * w + b 形状 y_predict[100,1] <== x[100,1] x w[1,1] + b
y_predict = tf.matmul(x, weight) + bias

with tf.variable_scope("loss"):
"""
第3步:建立损失函数,取均方误差MSE
"""
loss = tf.reduce_mean(tf.square(y_true - y_predict))

with tf.variable_scope("optimizer"):
"""
第4步:梯度下降优化损失
leaning_rate: 一般取 0~1、2、3、5、7、10
"""

# GradientDescentOptimizer(learning_rate)
# minimize(loss)将损失最小化
train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

# 定义一个初始化变量的op
init_op = tf.global_variables_initializer()

# 通过session运行程序
with tf.Session() as sess:
# 初始化变量
sess.run(init_op)

# 打印随机最先初始化的权重和偏置
print("随机初始化的参数权重为:%f, 偏置为:%f" % (weight.eval(), bias.eval()))

# 循环训练 运行优化
max_step = 5000 # 定义训练次数
for i in range(max_step):
sess.run(train_op)

# 打印每一次训练之后的weight和bias
print("第%d次优化的参数权重为:%f, 偏置为:%f" % (i + 1, weight.eval(), bias.eval()))

if __name__ == "__main__":
linear_regression()

1.1. tf.Variable的trainable参数

trainable参数决定了变量在训练时,是否能被optimizer更新。默认值为True

这里我们使用的optimizer是GradientDescentOptimizer,也就是説,在递降下降优化时,如果变量的trainable设置为False,则不会更新该变量

修改程序,设置bias变量的trainable为False。weight不修改,trainable默认为True

1
2
3
4
5
6
7
8
9
10
11
weight = tf.Variable(tf.random_normal([1, 1], mean=0.0, stddev=1.0), name="w")
bias = tf.Variable(0.0, name="b", trainable=False)

"""
训练优化时,可以看到weight在更新,但是bias就不会被更新
随机初始化的参数权重为:0.108960, 偏置为:0.000000
第1次优化的参数权重为:0.790025, 偏置为:0.000000
第2次优化的参数权重为:1.016438, 偏置为:0.000000
第3次优化的参数权重为:1.079658, 偏置为:0.000000
第4次优化的参数权重为:1.091300, 偏置为:0.000000
"""

反一下,将weight的trainable设置为False

1
2
3
4
5
6
7
8
9
10
11
weight = tf.Variable(tf.random_normal([1, 1], mean=0.0, stddev=1.0), name="w", trainable=False)
bias = tf.Variable(0.0, name="b")

"""
训练优化时,可以看到weight不更新,bias在更新
随机初始化的参数权重为:-0.799985, 偏置为:0.000000
第1次优化的参数权重为:-0.799985, 偏置为:0.668632
第2次优化的参数权重为:-0.799985, 偏置为:1.230450
第3次优化的参数权重为:-0.799985, 偏置为:1.676977
第4次优化的参数权重为:-0.799985, 偏置为:2.022964
"""

1.2. 学习率的设置

学习率一般都是设置为纯小数,0.1、0.01、0.05、0.0001都是比较常见的,不同场景取值不一定相同

尝试将学习率设置为1.0

1
2
3
4
5
6
7
8
train_op = tf.train.GradientDescentOptimizer(1.0).minimize(loss)
"""
学习率过大,导致无法收敛
第44次优化的参数权重为:-inf, 偏置为:-258865874387307336192779716312766087168.000000
第45次优化的参数权重为:nan, 偏置为:inf
第46次优化的参数权重为:nan, 偏置为:nan
第47次优化的参数权重为:nan, 偏置为:nan
"""

尝试将学习率设置为0.5

1
2
3
4
5
6
7
8
train_op = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
"""
学习率过大,无法收敛
第73次优化的参数权重为:25116022189550720086865452449868546048.000000, 偏置为:14163305502976779258935682315874992128.000000
第74次优化的参数权重为:-74728367966826988948298285007438348288.000000, 偏置为:-42178556168502280071211426706320523264.000000
第75次优化的参数权重为:inf, 偏置为:inf
第76次优化的参数权重为:nan, 偏置为:nan
"""

尝试将学习率设置为0.3

1
2
3
4
5
6
7
8
9
10
train_op = tf.train.GradientDescentOptimizer(0.3).minimize(loss)
"""
学习率过大,无法收敛
第199次优化的参数权重为:27622535044875995800150868730826457088.000000, 偏置为:14452844505972508223613938308202102784.000000
第200次优化的参数权重为:-38350900392920344132144949338126155776.000000, 偏置为:-21995243882872851252496778696681586688.000000
第201次优化的参数权重为:59621299127281493356407110148567334912.000000, 偏置为:31287847878689103312685269306321141760.000000
第202次优化的参数权重为:-inf, 偏置为:-51636013054275812452146957581006405632.000000
第203次优化的参数权重为:nan, 偏置为:inf
第204次优化的参数权重为:nan, 偏置为:nan
"""

尝试将学习率设置为0.2

1
2
3
4
5
6
7
8
train_op = tf.train.GradientDescentOptimizer(0.2).minimize(loss)
"""
差不多训练500多次,就达到目标值
第542次优化的参数权重为:0.700000, 偏置为:0.799999
第543次优化的参数权重为:0.700000, 偏置为:0.799999
第544次优化的参数权重为:0.700000, 偏置为:0.800000
第545次优化的参数权重为:0.700000, 偏置为:0.800000
"""

尝试将学习率设置为0.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
"""
差不多训练1000多次,近似达到目标值
第1005次优化的参数权重为:0.700001, 偏置为:0.799998
第1006次优化的参数权重为:0.700001, 偏置为:0.799998
第1007次优化的参数权重为:0.700001, 偏置为:0.799999
第1008次优化的参数权重为:0.700001, 偏置为:0.799999
......
第4996次优化的参数权重为:0.700000, 偏置为:0.799999
第4997次优化的参数权重为:0.700000, 偏置为:0.799999
第4998次优化的参数权重为:0.700000, 偏置为:0.799999
第4999次优化的参数权重为:0.700000, 偏置为:0.799999
第5000次优化的参数权重为:0.700000, 偏置为:0.799999
"""

1.3. tf.variable_scope设置变量作用域

tf.variable_scope() 设置变量作用域,本来的作用是结合tf.get_variable()实现变量的共享。但是这里使用tf.variable_scope,主要目的是为了使程序结构更加清晰。而且使用TensorBoard查看时,图的结构也更加清晰

2. 线性回归可视化

2.1. 增加可视化功能

在程序中添加tf.summary.FileWriter,将图序列化到事件文件

1
2
3
with tf.Session() as sess:
# 序列化生成事件文件
filewriter = tf.summary.FileWriter("summary", graph=sess.graph)

启动TensorBoard

1
tensorboard --logdir summary

2.2. 添加数据的显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# tf.summary.scalar添加标量统计结果
tf.summary.scalar("losses", loss)
# tf.summary.histogram添加任意shape的Tensor,统计这个Tensor的取值分布
tf.summary.histogram("weights", weight)
# 合并所有的summary操作,之后session只需要运行该op,就可以运行所有的summary op
merged = tf.summary.merge_all()

with tf.Session() as sess:
# ...
# 序列化生成事件文件
filewriter = tf.summary.FileWriter("summary", graph=sess.graph)

max_step = 5000
for i in range(max_step):
sess.run(train_op)

# 运行合并的tensor
summary = sess.run(merged)
# 序列化summary
filewriter.add_summary(summary, i + 1)

3. 保存与加载模型

假设训练要非常久,有时候训练到一半宕机了,下一次必须从头开始训练,这样前面的工作都白费了。

我们可以每训练一定次数,就把weight和bias序列化到文件中。下一次读取weight和bias的值,作为初始值进行训练即可

下面设置模型的保存

1
2
3
4
5
6
7
8
9
# 定义一个保存模型的实例
saver = tf.train.Saver()

with tf.Session() as sess:
for i in range(max_step):
# ......

# 训练结束后保存模型,将模型保存到model目录下
saver.save(sess, "model/linear_regression_model")

保存模型之后,在model目录可以看到

1
2
3
4
5
model
|--checkpoint
|--linear_regression_model.data-00000-of-00001
|--linear_regression_model.index
|--linear_regression_model.meta

设置加载模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义一个保存模型的实例
saver = tf.train.Saver()

with tf.Session() as sess:
# 开始训练之前,先加载模型,覆盖模型当中随机定义的参数,从上次训练的参数结果开始
# 如果存在model/checkpoint,说明之前已经保存过模型,才加载
if os.path.exists("model/checkpoint"):
saver.restore(sess, "model/linear_regression_model")

for i in range(max_step):
# ......

# 训练结束后保存模型,将模型保存到model目录下
saver.save(sess, "model/linear_regression_model")

4. 自定义命令行参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"""
TF定义命令行参数:
DEFINE_xxx(参数名, 默认值, 描述)
"""
tf.app.flags.DEFINE_integer("max_step", 100, "模型训练的步数")
tf.app.flags.DEFINE_string("model_dir", "model/linear_regression_model", "模型文件的加载的路径")

# 从命令行中取出参数,之后可以通过FLAGS.max_step和FLAGS.model_dir引用对应的参数
FLAGS = tf.app.flags.FLAGS

def linear_regression():
# ......

with tf.Session() as sess:
if os.path.exists("model/checkpoint"):
saver.restore(sess, FLAGS.model_dir) # 引用FLAGS.model_dir

for i in range(FLAGS.max_step): # 引用FLAGS.max_step
# ......

saver.save(sess, FLAGS.model_dir) # 引用FLAGS.model_dir

用命令行执行该py文件

1
python tf_linear_regression.py --max_step=200 --model_dir="model/linear_regression_model"

5. 最终代码

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import tensorflow as tf
import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

"""
TF定义命令行参数:
DEFINE_xxx(参数名, 默认值, 描述)
"""
tf.app.flags.DEFINE_integer("max_step", 100, "模型训练的步数")
tf.app.flags.DEFINE_string("model_dir", "model/linear_regression_model", "模型文件的加载的路径")

# 从命令行中取出参数,之后可以通过FLAGS.max_step和FLAGS.model_dir引用对应的参数
FLAGS = tf.app.flags.FLAGS


def linear_regression():
"""
自实现一个线性回归预测
:return: None
"""

with tf.variable_scope("data"):
"""
第1步: 生成实验数据
"""

# 生成 x,张量形状100行1列 [100, 1]
x = tf.random_normal([100, 1], mean=1.75, stddev=0.5, name="x_data")

# 生成 y=0.7x+0.8,矩阵相乘必须是二维的,所以0.7表示成 [[0.7]]
y_true = tf.matmul(x, [[0.7]]) + 0.8

with tf.variable_scope("model"):
"""
第2步:建立线性回归模型 y=w*x+b
weight(w): 权重
bias(b): 偏置
随机给生成weight和bias初始值,计算y_predict=x*w+b,再去计算损失,再在当前状态下优化

注意weight/bias用tf.Variable定义为变量才能优化,不能定义为常量
"""

# tf.random_normal生成一个随机的weight,形状[1, 1]
weight = tf.Variable(tf.random_normal([1, 1], mean=0.0, stddev=1.0), name="w")
# 生成bias,设置为0.0即可
bias = tf.Variable(0.0, name="b")

# 计算y_predict = x * w + b 形状 y_predict[100,1] <== x[100,1] x w[1,1] + b
y_predict = tf.matmul(x, weight) + bias

with tf.variable_scope("loss"):
"""
第3步:建立损失函数,取均方误差MSE
"""
loss = tf.reduce_mean(tf.square(y_true - y_predict))

with tf.variable_scope("optimizer"):
"""
第4步:梯度下降优化损失
leaning_rate: 一般取 0~1、2、3、5、7、10
"""

# GradientDescentOptimizer(learning_rate)
# minimize(loss)将损失最小化
train_op = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

# 定义一个初始化变量的op
init_op = tf.global_variables_initializer()

# tf.summary.scalar添加标量统计结果
tf.summary.scalar("losses", loss)
# tf.summary.histogram添加任意shape的Tensor,统计这个Tensor的取值分布
tf.summary.histogram("weights", weight)
# 合并所有的summary操作,之后session只需要运行该op,就可以运行所有的summary op
merged = tf.summary.merge_all()

# 定义一个保存模型的实例
saver = tf.train.Saver()

# 通过session运行程序
with tf.Session() as sess:
# 初始化变量
sess.run(init_op)

# 打印随机最先初始化的权重和偏置
print("随机初始化的参数权重为:%f, 偏置为:%f" % (weight.eval(), bias.eval()))

# 序列化生成事件文件
filewriter = tf.summary.FileWriter("summary", graph=sess.graph)

# 开始训练之前,先加载模型,覆盖模型当中随机定义的参数,从上次训练的参数结果开始
# 如果存在model/checkpoint,说明之前已经保存过模型,才加载
if os.path.exists("model/checkpoint"):
saver.restore(sess, FLAGS.model_dir)

# 循环训练 运行优化
for i in range(FLAGS.max_step):
sess.run(train_op)

# 运行合并的tensor
summary = sess.run(merged)
filewriter.add_summary(summary, i + 1)

# 打印每一次训练之后的weight和bias
print("第%d次优化的参数权重为:%f, 偏置为:%f" % (i + 1, weight.eval(), bias.eval()))

saver.save(sess, FLAGS.model_dir)


if __name__ == "__main__":
linear_regression()
panchaoxin wechat
关注我的公众号
支持一下