0
import warnings
warnings.filterwarnings("ignore")

import tensorflow as tf
import matplotlib.pyplot as plt     # matplotlib 是 Python 的画图工具
1-1 构造数据
def pre(x):
    return 2 * x  + 3   # 这里 w 是 2, b 是 3

x = [1, 2, 3, 4, 5]
y = [pre(i) for i in x]
print(y)
# --> [5, 7, 9, 11, 13]
1-1-2 画图
plt.plot(x, y,'salmon')     # plt.plot 画折线图;salmon 指定颜色
plt.scatter(x, y)           # scatter 画点
plt.grid()
plt.show()
# 线性回归的当前任务是,只给出点,让网络自动 将 w 和 b 的值求出来

1-2 线性回归
x_input = [1, 2, 3, 4, 5]
y_input = [5, 7, 9, 11, 13]

# 正向过程,查看y预测值
graph = tf.Graph()
with graph.as_default():
    # w 和 b 的初始值为 0.5 和 0.2
    w =  tf.Variable(0.5, dtype=tf.float32)
    b =  tf.Variable(0.2, dtype=tf.float32)
    # x 和 y 是真实值,是需要传入到网络里的
    # 所以需要定义 2 个 placeholder,用这 2 个 placeholder 接收真实值
    x = tf.placeholder(tf.float32)
    y = tf.placeholder(tf.float32)
    # 计算y_pred
    y_pred = w*x+b
1-2-1 # 打印 预测的 y
# tf.Session 时,需要指定计算图,graph = graph
with tf.Session(graph=graph) as sess:
    init = tf.global_variables_initializer()
    # 第一次训练,首先需要进行初始化
    sess.run(init)
    # 这里注意,tf中参数的名称一定不能跟外界参数名称混淆
    y_pred_value = sess.run(y_pred,{x:x_input})
    print(y_pred_value)
# --> [0.7 1.2 1.7 2.2 2.7]
1-2-2 
# 正向过程,查看loss
graph = tf.Graph()
with graph.as_default():
    w =  tf.Variable(0.5, dtype=tf.float32)
    b =  tf.Variable(0.2, dtype=tf.float32)

    x = tf.placeholder(tf.float32)
    y = tf.placeholder(tf.float32)

    y_pred = w*x+b
    # 计算loss
    # 得到预测y后,将 预测输出y 和真实 y 做 MSE 均方误差
    # 因为要做平方,所以相减的顺序无所谓
    # tf.reduce_mean 求平均,得到损失loss
    loss = tf.reduce_mean(tf.square(y_pred - y))
with tf.Session(graph=graph) as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    y_pred_value,l = sess.run([y_pred,loss],{x:x_input,y:y_input})
    print(y_pred_value)
    print(l)
# --> 57.79
# 结果可以看出,loss 值还是很大的
# 前向过程结束后,需要进行反向传播
1-3 # 在反向传播之前,首先需要计算梯度
# 计算梯度和反向传播,TensorFlow把它们变成了高度封装的函数
# 也就是变成了 优化器

# 定义优化器,训练一次,查看w,b变化情况
graph = tf.Graph()
with graph.as_default():
    # 一般placeholder放到最前面
    x = tf.placeholder(tf.float32)
    y = tf.placeholder(tf.float32)

    w =  tf.Variable(0.5, dtype=tf.float32)
    b =  tf.Variable(0.2, dtype=tf.float32)
    y_pred = w*x+b
    loss = tf.reduce_mean(tf.square(y_pred - y))
    # 定义优化器
    optimizer = tf.train.GradientDescentOptimizer(0.01)  
    # 定义一个 梯度下降 优化器,里面传入的 0.01 是学习率,返回优化器对象 optimizer
    train_step = optimizer.minimize(loss)   
    # 找最小的损失,返回 train_step 迭代对象,这就是在计算图中定义反向传播

# 反向传播,运行一次优化器
with tf.Session(graph=graph) as sess:
    init = tf.global_variables_initializer()    # 将变量初始化
    sess.run(init)
    _,l = sess.run([train_step,loss],{x:x_input,y:y_input})
    w_value,b_value = sess.run([w,b])
    print(_)
    print(l)
    print(w_value,b_value)
# -->
# None
# 57.79
# 0.998 0.34600002
# loss 的值没有变,是因为只运行了一次 反向传播;而在运行反向传播之前,loss 已经被计算出来了
# 所以,这里的 loss 还是之前的 loss
# 但是 w 和 b 的值,已经和 初始化的值 不一样了
# 但是这一次反向传播,没有学习到想要获得的值,所以可以尝试多运行几次
1-4 # 一个完整的简单的线性回归
# 循环多次,查看最终结果
graph = tf.Graph()
with graph.as_default():
    # 一般placeholder放到最前面
    x = tf.placeholder(tf.float32)
    y = tf.placeholder(tf.float32)

    w =  tf.Variable(0.5, dtype=tf.float32)
    b =  tf.Variable(0.2, dtype=tf.float32)
    y_pred = w*x+b
    loss = tf.reduce_mean(tf.square(y_pred - y))
    # 定义优化器
    optimizer = tf.train.GradientDescentOptimizer(0.01)
    train_step = optimizer.minimize(loss)
with tf.Session(graph=graph) as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    for i in range(2000):   
        _,l = sess.run([train_step,loss],{x:x_input,y:y_input})
        if i%100 == 0:      # 每 100 次 触发,看一眼 w 和 b 还有 loss 的值
            w_value,b_value = sess.run([w,b])
            print("w_value is {:.4}, b_value is {:.4}, loss is {:.4}".format(w_value,b_value,l))
    print('training over')
    w_value,b_value = sess.run([w,b])
    print(w_value,b_value)
# -->
# w_value is 0.998, b_value is 0.346, loss is 57.79
# w_value is 2.436, b_value is 1.427, loss is 0.4535
# w_value is 2.311, b_value is 1.879, loss is 0.2303
# ……
# w_value is 2.001, b_value is 2.996, loss is 2.301e-06
# training over
# 2.0007024 2.9974654
部分理论说明:
1. loss 
用预测的Y'和真实的Y,做一个MSE均方误差,就会 得到一个 loss值;
目标:将 loss 降到越小越好

2. 什么是学习率?
假设 横坐标是 θ,也就是刚刚的权重 w,纵坐标是 loss 值,这是一个明显的凸优化问题;
梯度就是 通过 loss 对 θ 求导 的导数;
梯度下降就是 下一次的 θ 值 等于当前的 θ 值,减掉 η 倍的梯度;
η 就是学习率,控制步长

3. 反向传播
不断改变 θ(权重w) 的过程就是反向传播