**激活函数:**引入非线性激活因素,提高模型表达力。
主要有三种,
tf.nn.relu(),tf.nn.sigmoid(),tf.nn.tanh()。
NN复杂度:
可用神经网络的层数和带优化参数的个数表示。
神经网络的层数:一般不计入输入层,层数=n个隐藏层+1个输出层。
神经网络上待优化的参数:
所有参数w的个数+所有参数b的个数。
损失函数:
1.均方误差
loss_mse=tf.reduce_mean(tf.square(y_-y))
举例
import tensorflow as tf
import numpy as np
BATCH_SIZE=8
SEED=23455
rdm=np.random.RandomState(SEED)
X=rdm.rand(32,2)
Y_=[[x1+x2+(rdm.rand()/10.0-0.05)] for (x1,x2) in X]
#定义输入,参数,输出
x=tf.placeholder(tf.float32,shape=(None,2))
y_=tf.placeholder(tf.float32,shape=(None,1))
w1=tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))
y=tf.matmul(x,w1)
#损失函数,反向传播训练方法
loss_mse=tf.reduce_mean(tf.square(y-y_))
train_step=tf.train.GradientDescentOptimizer(0.001).minimize(loss_mse)
#生成会话,训练STEPS轮
with tf.Session() as sess:
init_op=tf.global_variables_initializer()
sess.run(init_op)
STEPS=20000
for i in range(STEPS):
start=(i*BATCH_SIZE)%32
end=(i*BATCH_SIZE)%32+BATCH_SIZE
sess.run(train_step,feed_dict={
x:X[start:end],y_:Y_[start:end]})
if i%500==0:
print("After %d training steps,w1 is :"%(i))
print(sess.run(w1))
print("Final w1 is :\n",sess.run(w1))
2.自定义损失函数
如预测商品销量,预测多了,损失成本;预测少了,损失利润。
若利润不等于成本,则采用均方误差的方法无法将利润最大化。这时我们采用自定义损失函数的方法。
如:loss_zdy=tf.reduce_sum(tf.where(tf.greater(y,y_),COST(y-y_),PROFIT(y_-y))
酸奶利润为99,成本为1。
import numpy as np
import tensorflow as tf
SEED=23455
COST=1
PROFIT=99
rdm=np.random.RandomState(seed=SEED)
x=rdm.rand(32,2)
y_=[[x1+x2+(rdm.rand()/10.0-0.05)] for (x1,x2) in x]
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_zdy=tf.reduce_mean(tf.where(tf.greater(y,y_),(y-y_)*COST,(y_-y)*PROFIT))
grads=tape.gradient(loss_zdy,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())
3.交叉熵:
交叉熵损失函数表征两个概率分布之间的距离。
H(y_,y)=-Σy_*lny
用tensorflow代码表示为:tf.losses.categorical_crossentropy(y_,y)
学习率
学习率是参数每次更新的幅度。设置大了会导致带优化参数在最小值附近波动不收敛,设置小了会导致带优化参数收敛缓慢。
更新后的参数=当前参数-学习率*损失函数的导数
指数衰减学习率:
为解决设定学习率的问题,Tensorflow提供了一种灵活的学习率设置方法——指数衰减法。tf.train.exponential_decay函数实现了指数衰减学习率。这个方法可以通过先设置一个较大的学习率来得到一个较优解,然后随着迭代的次数增加,逐步减小学习率使模型训练后期更新更加稳定。学习率计算公式为:Learning_rate=LEARNING_RATE_BASE×LEANING_RATE_DECAY^( global_step/LEARNING_RATE_BATCH_SIZE)。
tf.train.exponential_decay函数实现了下述功能。
decayed_learning_rate=learning_rate*decay_rate^(global_step/decay_steps)
decayed_learning_rate:每一轮优化时使用的学习率。
learning_rate:学习率初始值。
decay_rate:衰减系数。
decay_steps:衰减速度。
tf.train.exponential_decay函数可以通过设置参数staircase选择不同的衰减方式。当设置为True时,global_step/decay_steps会被转化为整数。
举例
import tensorflow as tf
LEARNING_RATE_BASE=0.1
LEARNING_RATE_DECAY=0.99
LEARNING_RATE_STEP=1
global_step=tf.Variable(0,trainable=False)
learning_rate=tf.train.exponential_decay(LEARNING_RATE_BASE,global_step,LEARNING_RATE_STEP,LEARNING_RATE_DECAY,staircase=True)
w=tf.Variable(tf.constant(5,dtype=tf.float32))
loss=tf.square(w+1)
train_step=tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)
with tf.Session() as sess:
init_op=tf.global_variables_initializer()
sess.run(init_op)
for i in range(40):
sess.run(train_step)
learning_rate_val=sess.run(learning_rate)
global_step_val=sess.run(global_step)
w_val=sess.run(w)
loss_val=sess.run(loss)
print("After %s steps: global_step is %f,w is %f,learning_rate is %f,loss is %f" %(i,global_step_val,w_val,learning_rate_val,loss_val))
**滑动平均:**记录了一段时间以来模型中所有参数w和b各自的平均值。可以增强模型的泛化能力。
计算公式:
影子=衰减率*影子+(1-衰减率)*参数
衰减率=滑动平均衰减率与(1+轮数)/(10+轮数)中的最小值,影子初值等于参数初值。
用Tensorflow函数表示为:
ema=tf.train.ExponentialMovingAverage(Moving_AVERAGE_DECAY,global_step)
欠拟合与过拟合:
1.欠拟合无法有效预测,拟合效果差。解决方法:增加输入特征值,增加网络参数,减少正则化参数。
2.过拟合即在训练数据集上的准确率较高,在新的数据进行预测或分类时准确率较低,说明泛化能力差。解决方法:数据清理,增大训练集,采用正则化,增大正则化参数。
正则化:
在损失函数中给每个参数2加上权重,引入模型复杂度指标,从而抑制模型噪声,减小过拟合。
使用正则化后,损失函数loss变为两项之和:
loss=loss(y与y_)+REGLARIZER*loss(w)
正则化计算方法:
1.L1正则化:loss=Σ|wi|,大概率会使很多参数变为零,因此可通过稀疏参数,即减少参数的数量,降低复杂度。
2.L2正则化:loss=Σ(|wi|^2),会使参数很接近零但不为零,因此可通过减小参数值的大小降低复杂度。
例如`
with tf.GradientTape() as tape:
h1=tf.matmul(x_train,w1)+b1
h1=tf.nn.relu(h1)
y=tf.matmul(h1,w2)+b2
loss_mse=tf.reduce_mean(tf.square(y_train-y))
loss_regularization=[]
loss_regularization.append(tf.nn.l2_loss(w1))
loss_regularization.append(tf.nn.l2_loss(w2))
loss_regularization=tf.reduce_sum(loss_regularization)
loss=loss_mse+0.03*loss_regularization
variables=[w1,b1,w2,b2]
grads=tape.gradient(loss,variables)
以下为一组数据,通过此例感受正则化的作用。
以下为无正则化代码:
# 导入所需模块
import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
# 读入数据/标签 生成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)
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在-3到3之间以步长为0.01,yy在-3到3之间以步长0.01,生成间隔数值点
xx, yy = np.mgrid[-3:3:.1, -3:3:.1]
# 将xx , yy拉直,并合并配对为二维张量,生成二维坐标点
grid = np.c_[xx.ravel(), yy.ravel()]
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的shape调整成xx的样子
probs = np.array(probs).reshape(xx.shape)
plt.scatter(x1, x2, color=np.squeeze(Y_c)) #squeeze去掉纬度是1的纬度,相当于去掉[['red'],[''blue]],内层括号变为['red','blue']
# 把坐标xx yy和对应的值probs放入contour<[‘kɑntʊr]>函数,给probs值为0.5的所有点上色 plt点show后 显示的是红蓝点的分界线
plt.contour(xx, yy, probs, levels=[.5])
plt.show()
# 读入红蓝点,画出分割线,不包含正则化
# 导入所需模块
import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
# 读入数据/标签 生成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 = x_data
y_train = 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)
# 生成神经网络的参数,输入层为4个神经元,隐藏层为32个神经元,2层隐藏层,输出层为3个神经元
# 用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)
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])
# 每200个epoch,打印loss信息
if epoch % 20 == 0:
print('epoch:', epoch, 'loss:', float(loss))
# 预测部分
print("*******predict*******")
# xx在-3到3之间以步长为0.01,yy在-3到3之间以步长0.01,生成间隔数值点
xx, yy = np.mgrid[-3:3:.1, -3:3:.1]
# 将xx, yy拉直,并合并配对为二维张量,生成二维坐标点
grid = np.c_[xx.ravel(), yy.ravel()]
grid = tf.cast(grid, tf.float32)
# 将网格坐标点喂入神经网络,进行预测,probs为输出
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)
# 取第0列给x1,取第1列给x2
x1 = x_data[:, 0]
x2 = x_data[:, 1]
# probs的shape调整成xx的样子
probs = np.array(probs).reshape(xx.shape)
plt.scatter(x1, x2, color=np.squeeze(Y_c))
# 把坐标xx yy和对应的值probs放入contour<[‘kɑntʊr]>函数,给probs值为0.5的所有点上色 plt点show后 显示的是红蓝点的分界线
plt.contour(xx, yy, probs, levels=[.5])
plt.show()
# 读入红蓝点,画出分割线,包含正则化
可见figure2曲线更平滑。