神经网络优化

神经网络优化

  • 一、损失函数
  • 二、学习率
  • 三、滑动平均
  • 四、正则化

一、损失函数

神经元模型:
神经网络优化_第1张图片

**激活函数:**引入非线性激活因素,提高模型表达力。
主要有三种,
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()

# 读入红蓝点,画出分割线,不包含正则化

figure:神经网络优化_第2张图片
以下为包含正则化的代码

# 导入所需模块
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:神经网络优化_第3张图片

可见figure2曲线更平滑。

你可能感兴趣的:(tensorflow)