以预测鸢尾花分类为例,过程如下:
1) 准备数据: 数据集读入;数据集乱序;生成训练集和测试集;配对(输入特征和标签)
2) 搭建网络: 定义神经网络中所有可训练参数
3) 参数优化: 嵌套循环迭代,with结构更新参数,显示当前loss
4) 测试效果: 计算当前参数前向传播后的准确率,显示当前acc
5) acc/loss 可视化

import tensorflow as tf
from sklearn import datasets
from pandas import DataFrame
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt

x_data = datasets.load_iris().data     #返回数据集的所有特征值
y_data = datasets.load_iris().target   #返回数据集的所有标签

#数据集乱序
np.random.seed(116) #使用相同的seed,使输入特征/标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)

#数据集分出永不相见的训练集和测试集
x_train = x_data[:30]      #把前120组数组做为训练集
y_train = y_data[:30]
x_test = x_data[-30:]      #把后30组数据做为测试集
y_test = y_data[-30:]

#转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)

#配对(将输入特征和标签对应),并分为每32组为一批的batch
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

#定义神经网络中所有可训练参数;4个输入特征,所以输入层为4个节点;输出3类,所以输出层为3个神经元
#使用seed使每次生成的随机数相同(仅为了方便理解,生产环境不使用seed)
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))

lr = 0.1  #定义学习率
train_loss_results = []  #将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = []       #将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500         #循环500轮
loss_all = 0        #每轮分4个step, loss_all记录四个step生成的4个loss之和

#嵌套循环迭代,with结构更新参数,显示当前loss
for epoch in range(epoch):
    for step, (x_train, y_train) in enumerate(train_db):
        with tf.GradientTape() as tape:         #记录梯度信息
            y = tf.matmul(x_train, w1) + b1     #神经网络乘加运算
            y = tf.nn.softmax(y)                #将y输出成符合概念分布的值
            y_ = tf.one_hot(y_train, depth=3)   #将标签值转换成独热码
            loss = tf.reduce_mean(tf.square(y_ - y))
            loss_all += loss.numpy()
        grads = tape.gradient(loss, [w1, b1])   #计算loss对各个参数的梯度

        #实现梯度更新 w1 = w1 - lr * w1_grad / b = b - lr * b_grad
        w1.assign_sub(lr * grads[0])  #参数自更新
        b1.assign_sub(lr * grads[1])

    print("Epoch {}, loss: {}".format(epoch, loss_all/4))
    train_loss_results.append(loss_all / 4)
    loss_all = 0

    total_correct, total_number = 0, 0  #定义"预测对儿"的样本个数和测试总样本数
    for x_test, y_test in test_db:
        y = tf.matmul(x_test, w1) + b1      #使用更新后的参数进行预测
        y = tf.nn.softmax(y)
        pred = tf.argmax(y, axis=1)         #返回y中最大值 的索引,即预测的分类
        pred = tf.cast(pred, dtype=y_test.dtype)

        #若分类正确,则correct=1, 否则0, 将bool型的结果转换为int型
        correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
        correct = tf.reduce_sum(correct)
        total_correct += int(correct)
        total_number += x_test.shape[0]

    acc = total_correct / total_number      #计算正确率
    test_acc.append(acc)
    print("Test_acc:", acc)
    print("-------------------")

plt.title('Loss Function Curve')   #图片标题
plt.xlabel('Epoch')     #x轴变量名称
plt.xlabel('Loss')      #y轴变量名称
plt.plot(train_loss_results, label='$loss$')    #逐点画出train_loss_results值并连线,连线图标是Loss
plt.legend()
plt.show()

plt.title('Acc Curve')
plt.xlabel('Epoch')
plt.ylabel('Acc')
plt.plot(test_acc, label="$Accuracy$")
plt.legend()
plt.show()

损失函数的图示输出如下:
Tensorflow学习笔记(1)_第1张图片
正确率的图示输出如下:
Tensorflow学习笔记(1)_第2张图片
上例代码中一些功能的说明:
1) 将特征值与标签配对儿

features = tf.constant([12, 23, 10, 17])
labels = tf.constant([0, 1, 1, 0])
dataset = tf.data.Dataset.from_tensor_slices((features, labels))
print(dataset)
for element in dataset:
    print(element)

输出结果:


(, )
(, )
(, )
(, )

2) 对参数求导

with tf.GradientTape() as tape:
    w = tf.Variable(tf.constant(3.0))  #定义w初始为3
    loss = tf.pow(w, 2)   #损失函数为w的平方
grad = tape.gradient(loss, w)  #计算损失函数对w的求导
print(grad)

输出结果:

tf.Tensor(6.0, shape=(), dtype=float32)

3) 将输出转换为独热码

classes = 3
labels = tf.constant([1, 0, 2])
output = tf.one_hot(labels, depth=classes)
print(output)

输出结果:

tf.Tensor(
[[0. 1. 0.]
 [1. 0. 0.]
 [0. 0. 1.]], shape=(3, 3), dtype=float32)

4) 将输出转换为概率分布值

y = tf.constant([1.01, 2.01, -0.66])
y_pro = tf.nn.softmax(y)
print(y_pro)

输出结果:

tf.Tensor([0.25598174 0.69583046 0.04818781], shape=(3,), dtype=float32)

5) 更新参数的值

w = tf.Variable(4)
w.assign_sub(1)
print(w)

输出结果:

6) 返回最大值

import numpy as np
test = np.array([[1, 2, 3], [2, 3, 4], [5, 4, 3], [8, 7, 2]])
print(tf.argmax(test, axis=0))
print(tf.argmax(test, axis=1))

输出结果

tf.Tensor([3 3 1], shape=(3,), dtype=int64)
tf.Tensor([2 2 0 0], shape=(4,), dtype=int64)

7) 生成随机正态分布

#生成2行2列、均值为0.5、标准差为0.1的正态分布
print(tf.random.normal([2, 2], mean=0.5, stddev=0.1))
#生成2行2列、均值为0.5、标准差为0.1的正态分布;且元素都在2倍标准差之内,数据会更向均值集中
print(tf.random.truncated_normal([2, 2], mean=0.5, stddev=0.1))

输出结果:

tf.Tensor(
[[0.47442842 0.6695974 ]
 [0.3250182  0.48049432]], shape=(2, 2), dtype=float32)
tf.Tensor(
[[0.41796872 0.64684904]
 [0.4972434  0.4422431 ]], shape=(2, 2), dtype=float32)

8) 生成网格坐标点

 x, y = np.mgrid[1:3:1, 2:4:0.5]
grid = np.c_[x.ravel(), y.ravel()]
print("x:", x)
print("y:", y)
print("grid:\n", grid)

说明:
np.mgrid[start:end:step, start:end:step, ...] 返回n组维度相同的等差数组
x.ravel() 将x变为一维数组 , 相当于把当前变量拉直
np.c_[数组1, 数组2, ...] 使返回的间隔数值点配对儿
输出结果:

x: [[1. 1. 1. 1.]
 [2. 2. 2. 2.]]
y: [[2.  2.5 3.  3.5]
 [2.  2.5 3.  3.5]]
grid:
 [[1.  2. ]
 [1.  2.5]
 [1.  3. ]
 [1.  3.5]
 [2.  2. ]
 [2.  2.5]
 [2.  3. ]
 [2.  3.5]]

9) 条件判断

 a = tf.constant([1, 2, 3, 1, 1])
b = tf.constant([0, 1, 3, 4, 5])
c = tf.where(tf.greater(a, b), a, b)  #若a>b, 返回a对应位置的元素;否则返回b对应位置的元素
print(c)

输出结果:

tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)

Tensorflow的基础知识

1、 神经网络的复杂度

NN复杂度 :多用NN层数和NN参数的个数表示
空间复杂度: 层数=隐藏层的层数+1个输出层 ; 总参数=总w+总b (输入层加隐藏层总参数个数)
时间复杂度: 乘加运算次数

2、学习率与参数更新

更新后的参数 = 当前参数 - 学习率 损失函数的梯度(偏导数,即损失函数对参数w的偏导数)
例 loss = (w + 1)^2 loss对w的偏导数为 2w + 2
学习率设置过小时会导致“需要迭代的次数”增加,损失下降过慢;
学习率设置过大时会导致不能收敛;
在生产中建议先使用较大的学习率,快速得到较优解,然后再逐步减小学习率,使模型在 训练后期稳定----指数衰减学习率
指数衰减学习率 = 初始学习率
学习率衰减率^(当前轮数/多少轮衰减一次)
下例使学习率根据衰减的轮数指数衰减:

w = tf.Variable(tf.constant(5, dtype=tf.float32))
epoch = 40
LR_BASE = 0.2  # 最初学习率
LR_DECAY = 0.99  # 学习率衰减率
LR_STEP = 1  # 喂入多少轮BATCH_SIZE后,更新一次学习率

#for epoch 定义顶层循环,表示对数据集循环epoch次,此例数据集数据仅有1个w,初始化时候constant赋值为5,循环迭代40次。
for epoch in range(epoch):  
    lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)
    with tf.GradientTape() as tape:  # with结构到grads框起了梯度的计算过程。
        loss = tf.square(w + 1)
    grads = tape.gradient(loss, w)  # .gradient函数告知谁对谁求导

    w.assign_sub(lr * grads)  # .assign_sub 对变量做自减 即:w -= lr*grads 即 w = w - lr*grads
    print("After %s epoch,w is %f,loss is %f,lr is %f" % (epoch, w.numpy(), loss, lr))

输出结果:

After 0 epoch,w is 2.600000,loss is 36.000000,lr is 0.200000
After 1 epoch,w is 1.174400,loss is 12.959999,lr is 0.198000
After 2 epoch,w is 0.321948,loss is 4.728015,lr is 0.196020
After 3 epoch,w is -0.191126,loss is 1.747547,lr is 0.194060
After 4 epoch,w is -0.501926,loss is 0.654277,lr is 0.192119
....
After 35 epoch,w is -0.999998,loss is 0.000000,lr is 0.140690
After 36 epoch,w is -0.999999,loss is 0.000000,lr is 0.139283
After 37 epoch,w is -0.999999,loss is 0.000000,lr is 0.137890
After 38 epoch,w is -0.999999,loss is 0.000000,lr is 0.136511
After 39 epoch,w is -0.999999,loss is 0.000000,lr is 0.135146

3、激活函数

激活函数(Activation functions)对于人工神经网络模型去学习、理解非常复杂和非线性的函数来说具有十分重要的作用。它们将非线性特性引入到网络中。如下图,在神经元中,输入的 inputs 通过加权,求和后,还被作用了一个函数,这个函数就是激活函数。引入激活函数是为了增加神经网络模型的非线性。没有激活函数的每层都相当于矩阵相乘。就算你叠加了若干层之后,无非还是个矩阵相乘罢了。
Tensorflow学习笔记(1)_第3张图片
常用的四种激活函数:
1) sigmoid
Tensorflow学习笔记(1)
Tensorflow学习笔记(1)_第4张图片
从上图可以看出,如果输入为大负数,它输出接近0;如果输入为大正数,它输出按近1;所以它相当于将输入进行归1化。但它收敛较慢,幂运算复杂,训练时间较长,易造成梯度消失。
2) Tanh
Tensorflow学习笔记(1)
Tensorflow学习笔记(1)_第5张图片
从上图看它输出是0均值,它依然存在幂运算复杂,训练时间较长,易造成梯度消失的特点。
3) relu
Tensorflow学习笔记(1)
Tensorflow学习笔记(1)_第6张图片
从上图可以看出它是一个分段函数,当输入小于0时,它输出为0;当输入x大于0时,它输出x的值;它解决了梯度消失问题;计算速度较快;收敛速度虽然超过sigmoid和tanh,但还是偏慢;但它会出现Dead Relu问题。
4) Leaky Relu
Tensorflow学习笔记(1)_第7张图片
它是为了解决relu负区间为0导致Dead Relu问题而设计的。它负区间使用一个固定的斜率。(生产环境中它使用的并不多)

4、损失函数

损失函数目的是预测值(y)与已知答案(y_)的差距;
常用的损失函数有三种: mes(Mean Squared Error)、自定义、交叉熵ce(Cross Entropy)
loss_mes = tf.reducemean(tf.square(y - y))
1) 均方差

SEED = 23455

rdm = np.random.RandomState(seed=SEED)  # 生成[0,1)之间的随机数
x = rdm.rand(32, 2)
y_ = [[x1 + x2 + (rdm.rand() / 10.0 - 0.05)] for (x1, x2) in x]  # 生成噪声[0,1)/10=[0,0.1); [0,0.1)-0.05=[-0.05,0.05)
x = tf.cast(x, dtype=tf.float32)

w1 = tf.Variable(tf.random.normal([2, 1], stddev=1, seed=1))

epoch = 15000
lr = 0.002

for epoch in range(epoch):
    with tf.GradientTape() as tape:
        y = tf.matmul(x, w1)
        loss_mse = tf.reduce_mean(tf.square(y_ - y))

    grads = tape.gradient(loss_mse, w1)
    w1.assign_sub(lr * grads)

    if epoch % 500 == 0:
        print("After %d training steps,w1 is " % (epoch))
        print(w1.numpy(), "\n")
print("Final w1 is: ", w1.numpy())

输出结果:

After 0 training steps,w1 is 
[[-0.8096241]
 [ 1.4855157]] 

After 500 training steps,w1 is 
[[-0.21934733]
 [ 1.6984866 ]] 
 ...
 After 14000 training steps,w1 is 
[[0.9993659]
 [0.999166 ]] 

After 14500 training steps,w1 is 
[[1.0002553 ]
 [0.99838644]] 

Final w1 is:  [[1.0009792]
 [0.9977485]]
tf.Tensor([1 2 3 4 5], shape=(5,), dtype=int32)

2) 自定义损失函数
在预测商品销量时,预测多了损失成本,预测少了损失利润;

SEED = 23455
COST = 1        #成本
PROFIT = 99     #利润

rdm = np.random.RandomState(SEED)
x = rdm.rand(32, 2)
y_ = [[x1 + x2 + (rdm.rand() / 10.0 - 0.05)] for (x1, x2) in x]  # 生成噪声[0,1)/10=[0,0.1); [0,0.1)-0.05=[-0.05,0.05)
x = tf.cast(x, dtype=tf.float32)

w1 = tf.Variable(tf.random.normal([2, 1], stddev=1, seed=1))

epoch = 10000
lr = 0.002

for epoch in range(epoch):
    with tf.GradientTape() as tape:
        y = tf.matmul(x, w1)
        loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_) * COST, (y_ - y) * PROFIT))

    grads = tape.gradient(loss, w1)
    w1.assign_sub(lr * grads)

    if epoch % 500 == 0:
        print("After %d training steps,w1 is " % (epoch))
        print(w1.numpy(), "\n")
print("Final w1 is: ", w1.numpy())

输出结果:

After 0 training steps,w1 is 
[[2.0855923]
 [3.8476257]] 

After 500 training steps,w1 is 
[[1.1830753]
 [1.1627482]] 
...

After 9500 training steps,w1 is 
[[1.1611756]
 [1.0651482]] 

Final w1 is:  [[1.1626335]
 [1.1191947]]

上例成本很低(cost为1),利润很高(profit为99),人们希望多预测些,生成模型系数大于1,往多了预测;
如果把上例中的 cost成本改为99,而profit利润改为1,模型的输出结果都小于1,表示模型尽量往少了预测;这样就可以达到利益最大化。

3) 交叉熵损失函数
交叉熵损失函数表示两相概率分布之间的距离(值越小说明概率分布越接近)
例, 二分类,标准答案为[1,0],判断[0.6,0.4]和[0.8,0.2]哪个更接近标准答案:

loss_ce1 = tf.losses.categorical_crossentropy([1, 0], [0.6, 0.4])
loss_ce2 = tf.losses.categorical_crossentropy([1, 0], [0.8, 0.2])
print("loss_ce1:", loss_ce1)
print("loss_ce2:", loss_ce2)

输出结果:

loss_ce1: tf.Tensor(0.5108256, shape=(), dtype=float32)
loss_ce2: tf.Tensor(0.22314353, shape=(), dtype=float32)

可以先将输出使用softmax函数,再计算y与y_的交叉熵损失函数;
也可以直接使用tf.nn.softmax_cross_entropy_withlogits(y, y)函数,效果相同
例:

y_ = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0]])
y = np.array([[12, 3, 2], [3, 10, 1], [1, 2, 5], [4, 6.5, 1.2], [3, 6, 1]])
y_pro = tf.nn.softmax(y)
loss_ce1 = tf.losses.categorical_crossentropy(y_, y_pro)
loss_ce2 = tf.nn.softmax_cross_entropy_with_logits(y_, y)
print("loss_ce1:", loss_ce1)
print("loss_ce2:", loss_ce2)

输出结果:

loss_ce1: tf.Tensor(
[1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58349207e+00
 5.49852354e-02], shape=(5,), dtype=float64)
loss_ce2: tf.Tensor(
[1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58349207e+00
 5.49852354e-02], shape=(5,), dtype=float64)

5、拟合

Tensorflow学习笔记(1)_第8张图片
欠拟合是对现有数据集学习的不彻底,是模型不能有效拟合数据集;
过拟合是模型对当前数据拟合太好,但对新数据无法做出正确的判断。
欠拟合的解决方法: 增加输入特征项; 增加网络参数; 减少正则化参数 ;
过拟合的解决方法: 数据清洗; 增大训练集; 采用正则化; 增大正则化参数。
正则化:在损失函数中引入模型复杂度指标,利用给W加权值,弱化了训练数据的噪声(一般不正则化b) loss = loss(y与y_) + REGULARIZER * loss(w)
REGULARIZER 用超参数给出参数w在总loss中的比例,即正则化的权重
正则化的选择:
1) L1正则化大概率会使很多参数变为0,因此该方法可通过稀疏参数,即减少参数的数量,降低复杂度 ;
2) L2正则化会使参数很接过0但不为0,因此该方法可通过减少参数值的大小降低复杂度。
例:读出dot.csv的内容格式如下:

           x1        x2  y_c
0   -0.416758 -0.056267    1
1   -2.136196  1.640271    0
2   -1.793436 -0.841747    0
3    0.502881 -1.245288    1
4   -1.057952 -0.909008    1
..        ...       ...  ...
[300 rows x 3 columns]

对原文件做预测(不使用正则化的情况下) 如下所示:

# 读入数据/标签 生成x_train y_train
df = pd.read_csv('dot.csv')

x_data = np.array(df[['x1', 'x2']])
y_data = np.array(df['y_c'])

x_train = np.vstack(x_data).reshape(-1, 2)
y_train = np.vstack(y_data).reshape(-1, 1)

Y_c = [['red' if y else 'blue'] for y in y_train]

# 转换x的数据类型,否则后面矩阵相乘时会因数据类型问题报错
x_train = tf.cast(x_train, tf.float32)
y_train = tf.cast(y_train, tf.float32)

# from_tensor_slices函数切分传入的张量的第一个维度,生成相应的数据集,使输入特征和标签值一一对应
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)

# 生成神经网络的参数,输入层为2个神经元,隐藏层为11个神经元,1层隐藏层,输出层为1个神经元
# 用tf.Variable()保证参数可训练
w1 = tf.Variable(tf.random.normal([2, 11]), dtype=tf.float32)
b1 = tf.Variable(tf.constant(0.01, shape=[11]))

w2 = tf.Variable(tf.random.normal([11, 1]), dtype=tf.float32)
b2 = tf.Variable(tf.constant(0.01, shape=[1]))

lr = 0.01  # 学习率
epoch = 400  # 循环轮数

# 训练部分
for epoch in range(epoch):
    for step, (x_train, y_train) in enumerate(train_db):
        with tf.GradientTape() as tape:  # 记录梯度信息

            h1 = tf.matmul(x_train, w1) + b1  # 记录神经网络乘加运算
            h1 = tf.nn.relu(h1)   #使用relu激活函数实现前向传播
            y = tf.matmul(h1, w2) + b2

            # 采用均方误差损失函数mse = mean(sum(y-out)^2)
            loss = tf.reduce_mean(tf.square(y_train - y))

        # 计算loss对各个参数的梯度
        variables = [w1, b1, w2, b2]
        grads = tape.gradient(loss, variables)

        # 实现梯度更新
        # w1 = w1 - lr * w1_grad tape.gradient是自动求导结果与[w1, b1, w2, b2] 索引为0,1,2,3
        w1.assign_sub(lr * grads[0])
        b1.assign_sub(lr * grads[1])
        w2.assign_sub(lr * grads[2])
        b2.assign_sub(lr * grads[3])

    # 每20个epoch,打印loss信息
    if epoch % 20 == 0:
        print('epoch:', epoch, 'loss:', float(loss))

# 预测部分
print("*******predict*******")
xx, yy = np.mgrid[-3:3:.1, -3:3:.1]  # xx在-3到3之间以步长为0.01,yy在-3到3之间以步长0.01,生成间隔数值点
grid = np.c_[xx.ravel(), yy.ravel()]  # 将xx/yy拉直,并合并配对为二维张量,生成二维坐标点
grid = tf.cast(grid, tf.float32)

probs = []   # 将网格坐标点喂入神经网络,进行预测,probs为输出
for x_test in grid:
    # 使用训练好的参数进行预测
    h1 = tf.matmul([x_test], w1) + b1
    h1 = tf.nn.relu(h1)
    y = tf.matmul(h1, w2) + b2  # y为预测结果
    probs.append(y)

# 取第0列给x1,取第1列给x2
x1 = x_data[:, 0]
x2 = x_data[:, 1]
probs = np.array(probs).reshape(xx.shape)  # probs的shape调整成xx的样子
plt.scatter(x1, x2, color=np.squeeze(Y_c)) #squeeze去掉纬度是1的纬度,相当于去掉[['red'],[''blue]],内层括号变为['red','blue']
# 把坐标xx yy和对应的值 probs 放入contour 函数,给probs值为0.5的所有点上色  plt点show后 显示的是红蓝点的分界线
plt.contour(xx, yy, probs, levels=[.5])
plt.show()

输出结果:

epoch: 0 loss: 1.4007412195205688
epoch: 20 loss: 0.13496121764183044
epoch: 40 loss: 0.08043073862791061
epoch: 60 loss: 0.061831068247556686
epoch: 80 loss: 0.05049065873026848
...
epoch: 320 loss: 0.030078843235969543
epoch: 340 loss: 0.03010166436433792
epoch: 360 loss: 0.029989494010806084
epoch: 380 loss: 0.029927119612693787

Tensorflow学习笔记(1)_第9张图片
上图可以看出,画线轮廓不平滑,存在过拟合现象。
如果在上述代码中添加正则化代码如下所示:

df = pd.read_csv('dot.csv')
x_data = np.array(df[['x1', 'x2']])
y_data = np.array(df['y_c'])

x_train = x_data
y_train = y_data.reshape(-1, 1)

Y_c = [['red' if y else 'blue'] for y in y_train]

x_train = tf.cast(x_train, tf.float32)
y_train = tf.cast(y_train, tf.float32)

train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)

w1 = tf.Variable(tf.random.normal([2, 11]), dtype=tf.float32)
b1 = tf.Variable(tf.constant(0.01, shape=[11]))

w2 = tf.Variable(tf.random.normal([11, 1]), dtype=tf.float32)
b2 = tf.Variable(tf.constant(0.01, shape=[1]))

lr = 0.01  # 学习率为
epoch = 400  # 循环轮数

# 训练部分
for epoch in range(epoch):
    for step, (x_train, y_train) in enumerate(train_db):
        with tf.GradientTape() as tape:  # 记录梯度信息

            h1 = tf.matmul(x_train, w1) + b1  # 记录神经网络乘加运算
            h1 = tf.nn.relu(h1)
            y = tf.matmul(h1, w2) + b2

            # 采用均方误差损失函数mse = mean(sum(y-out)^2)
            loss_mse = tf.reduce_mean(tf.square(y_train - y))
            # 添加l2正则化
            loss_regularization = []
            # tf.nn.l2_loss(w)=sum(w ** 2) / 2
            loss_regularization.append(tf.nn.l2_loss(w1))
            loss_regularization.append(tf.nn.l2_loss(w2))
            # 求和
            # 例:x=tf.constant(([1,1,1],[1,1,1]))
            #   tf.reduce_sum(x)
            # >>>6
            # loss_regularization = tf.reduce_sum(tf.stack(loss_regularization))
            loss_regularization = tf.reduce_sum(loss_regularization)
            loss = loss_mse + 0.03 * loss_regularization #REGULARIZER = 0.03

        # 计算loss对各个参数的梯度
        variables = [w1, b1, w2, b2]
        grads = tape.gradient(loss, variables)

        # 实现梯度更新
        # w1 = w1 - lr * w1_grad
        w1.assign_sub(lr * grads[0])
        b1.assign_sub(lr * grads[1])
        w2.assign_sub(lr * grads[2])
        b2.assign_sub(lr * grads[3])

    if epoch % 20 == 0:
        print('epoch:', epoch, 'loss:', float(loss))

# 预测部分
print("*******predict*******")

xx, yy = np.mgrid[-3:3:.1, -3:3:.1]

grid = np.c_[xx.ravel(), yy.ravel()]
grid = tf.cast(grid, tf.float32)

probs = []
for x_predict in grid:
    h1 = tf.matmul([x_predict], w1) + b1
    h1 = tf.nn.relu(h1)
    y = tf.matmul(h1, w2) + b2  # y为预测结果
    probs.append(y)

x1 = x_data[:, 0]
x2 = x_data[:, 1]

probs = np.array(probs).reshape(xx.shape)
plt.scatter(x1, x2, color=np.squeeze(Y_c))

plt.contour(xx, yy, probs, levels=[.5])
plt.show()

输出结果:

epoch: 0 loss: 1.5565969944000244
epoch: 20 loss: 0.46720606088638306
epoch: 40 loss: 0.372771680355072
epoch: 60 loss: 0.32464340329170227
...
epoch: 320 loss: 0.1135006919503212
epoch: 340 loss: 0.10868880152702332
epoch: 360 loss: 0.10449237376451492
epoch: 380 loss: 0.10088545083999634

Tensorflow学习笔记(1)_第10张图片
比较两次输出,可以明显看出正则化可以有效缓解过拟合现象。

6、优化器(接下)