以预测鸢尾花分类为例,过程如下:
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()
损失函数的图示输出如下:
正确率的图示输出如下:
上例代码中一些功能的说明:
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 通过加权,求和后,还被作用了一个函数,这个函数就是激活函数。引入激活函数是为了增加神经网络模型的非线性。没有激活函数的每层都相当于矩阵相乘。就算你叠加了若干层之后,无非还是个矩阵相乘罢了。
常用的四种激活函数:
1) sigmoid
从上图可以看出,如果输入为大负数,它输出接近0;如果输入为大正数,它输出按近1;所以它相当于将输入进行归1化。但它收敛较慢,幂运算复杂,训练时间较长,易造成梯度消失。
2) Tanh
从上图看它输出是0均值,它依然存在幂运算复杂,训练时间较长,易造成梯度消失的特点。
3) relu
从上图可以看出它是一个分段函数,当输入小于0时,它输出为0;当输入x大于0时,它输出x的值;它解决了梯度消失问题;计算速度较快;收敛速度虽然超过sigmoid和tanh,但还是偏慢;但它会出现Dead Relu问题。
4) Leaky Relu
它是为了解决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、拟合
欠拟合是对现有数据集学习的不彻底,是模型不能有效拟合数据集;
过拟合是模型对当前数据拟合太好,但对新数据无法做出正确的判断。
欠拟合的解决方法: 增加输入特征项; 增加网络参数; 减少正则化参数 ;
过拟合的解决方法: 数据清洗; 增大训练集; 采用正则化; 增大正则化参数。
正则化:在损失函数中引入模型复杂度指标,利用给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
上图可以看出,画线轮廓不平滑,存在过拟合现象。
如果在上述代码中添加正则化代码如下所示:
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