附:课程链接
第四讲.神经网络优化
4.4正则化
由于个人使用Win7系统,并未完全按照课程所讲,以下记录的也基本是我的结合课程做的Windows系统+PyCharm操作。且本人有python基础,故一些操作可能简略。并未完全按照网课。
记住编写代码时,除注释内容外,字符均使用英文格式。
二、神经网络的优化(从四个方面理解:损失函数loss、学习率learning_rate、滑动平均ema、正则化regularization)
4.正则化regularization
过拟合:神经网络模型在训练数据集上的准确率较高,在新的数据进行预测或分类时准确率较低,说明模型的泛化能力差。
正则化:在损失函数中给每个参数w加上权重,引入模型复杂度指标,从而抑制模型噪声,减小过拟合。(一般不对偏置b使用正则化)
使用正则化后,损失函数loss变成两部分:
loss(w)有两种正则化方法,L1正则化、L2正则化,使用时选择其中一个即可:
用tensorflow实现正则化:
tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(regularizer)(w))
#tf.add_to_collection把计算好的所有w正则化,加在losses集合中
loss = cem + tf.add_n(tf.get_collection('losses'))
#用tf.add_n可以把losses里的所有值相加,再加上交叉熵cem,就得到了总损失函数loss
实例感受正则化的作用:
题目:用300个符合正态分布的点X[x0,x1]作为数据集,根据点X[x0,x1]计算生成标注Y_,将数据集标注为红点和蓝点。
标注Y_规则:当,即如图:
我们尝试拟合一条曲线,把红色的点和蓝色的点分开。这里我们引入一个新模块matplotlib,它可帮助我们实现图形可视化。
代码讲解用法及套用公式(不是例子):
import matplotlib.pyplot as plt #matplotlib帮助实现图形可视化
plt.scatter(x_label,y_label,c = 'color') #可视化数据点,给出x坐标和y坐标,并给出这个坐标点打算显示的颜色
plt.show() #把图像散点画出来
xx.yy = np.mgrid[start;end:step,start:end:step]
#用np.mgrid,x轴从起点开始到止点结束,以步长打点,y轴同理
#二者分别作为x坐标和y坐标,这样我们就找到了一个小区域,以步长为分辨率的行、列形成网格坐标点
grid = np.c_[xx.ravel(),yy.ravel()]
#用ravel()函数把xx坐标拉直,即降低它的维度,变成1行n列。yy坐标同理。
#再用np.c_把xx坐标、yy坐标对应位置配对,组成矩阵。
#这样我们就收集起这个区域内所有的网格坐标点。
#probs = sess.run(y,feed_dict = {x:grid})
#我们把所有收集来的坐标点喂入神经网络,经网络计算推送求得结果y,赋值给probs
#这个probs就是区域中所有坐标点偏红还是偏蓝的变化值,
#probs = probs.reshape(xx.shape)
#把probs整形,让它的形状和xx.shape一样
plt.contour(x_label,y_label,该点的高度,levels = [等高线的高度]) #这里语法有误,但仅是套用公式,不要误解
#然后用plt.contour()函数把x坐标、y坐标、各点的高度,用levels把各点描上颜色
plt.show() #画出来
代码验证:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt #matplotlib帮助实现图形可视化
BATCH_SIZE = 30
seed = 2
rdm = np.random.RandomState(seed) #基于seed产生随机数
#随机数返回300行2列的矩阵,表示300组坐标点(x0,x1)作为输入数据集
X = rdm.randn(300,2)
#从X这个300行2列的矩阵中取出一行,判断如果两个坐标的平方和小于2,给Y赋值1,其余赋值0
Y_ = [int(x0*x0 + x1*x1 <2) for (x0,x1) in X]
#遍历Y中的元素,1赋值'red',其余赋值'blue'。这样可视化显示时人可以直观区分
Y_c = [['red' if y else 'blue'] for y in Y_]
#对数据集X和标签Y进行shape整理,第一个元素为-1表示,随第二个参数计算得到。
#第二个元素表示多少列,把X整理为n行2列,把Y整理为n行1列。
#(np.vstack:按垂直方向(行顺序堆叠数组构成一个新的数组,文末有简书链接讲解))
X = np.vstack(X).reshape(-1,2)
Y_ = np.vstack(Y_).reshape(-1,1)
# print(X)
# print(Y_)
# print(Y_c)
#使用plt.scatter画出数据集X各行中第0列元素和第1列元素的点,即各行的(x0,x1),
#用各行Y_c对应的值表示颜色
plt.scatter(X[:,0],X[:,1],c = np.squeeze(Y_c))
plt.show()
#定义神经网络的输入、参数和输出,定义前向传播过程
def get_weight(shape,regularizer):
w = tf.Variable(tf.random_normal(shape),dtype = tf.float32)
tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(regularizer)(w))
return w
def get_bias(shape):
b = tf.Variable(tf.constant(0.01,shape = shape))
return b
x = tf.placeholder(tf.float32,shape = (None,2))
y_ = tf.placeholder(tf.float32,shape = (None,1))
w1 = get_weight([2,11],0.01)
b1 = get_bias([11])
y1 = tf.nn.relu(tf.matmul(x,w1) + b1)
w2 = get_weight([11,1],0.01)
b2 = get_bias([1])
y = tf.matmul(y1,w2) + b2 #输出层不过激活relu
#定义损失函数
loss_mse = tf.reduce_mean(tf.square(y - y_))
loss_total = loss_mse + tf.add_n(tf.get_collection('losses'))
#定义反向传播方法:不含正则化
train_step = tf.train.AdamOptimizer(0.0001).minimize(loss_mse)
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
STEPS = 40000
for i in range(STEPS):
start = (i*BATCH_SIZE) % 300
end = start + BATCH_SIZE
sess.run(train_step,feed_dict={x:X[start:end],y_:Y_[start:end]})
if i % 2000 == 0:
loss_mse_v = sess.run(loss_mse,feed_dict={x:X,y_:Y_})
print('After %d steps,loss is: %f'%(i,loss_mse_v))
#xx在-3到3之间以步长为0.01,yy在-3到3之间以步长为0.01,生成二维网络坐标点
xx,yy = np.mgrid[-3:3:0.01,-3:3:0.01]
#将xx,yy拉直,并合成一个2列的矩阵,得到一个网络坐标点的集合
grid = np.c_[xx.ravel(),yy.ravel()]
#将网络坐标点喂入神经网络,probs为输出
probs = sess.run(y,feed_dict={x:grid})
#probs的shape调整成xx的样子
probs = probs.reshape(xx.shape)
#把probs整形,让它的形状和xx.shape一样
print("w1:\n",sess.run(w1))
print("b1:\n",sess.run(b1))
print("w2:\n",sess.run(w2))
print("b2:\n",sess.run(b2))
plt.scatter(X[:, 0], X[:, 1], c=np.squeeze(Y_c)) #可视化数据点,给出x坐标和y坐标,并给出这个坐标点打算显示的颜色
plt.contour(xx,yy,probs,levels = [.5]) #然后用plt.contour()函数把x坐标、y坐标、各点的高度,用levels把各点描上颜色
plt.show() #把图像散点画出来
#定义反向传播方法:包含正则化
train_step = tf.train.AdamOptimizer(0.0001).minimize(loss_mse)
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
STEPS = 40000
for i in range(STEPS):
start = (i*BATCH_SIZE) % 300
end = start + BATCH_SIZE
sess.run(train_step,feed_dict={x:X[start:end],y_:Y_[start:end]})
if i % 2000 == 0:
loss_v = sess.run(loss_total,feed_dict={x:X,y_:Y_})
print('After %d steps,loss is: %f'%(i,loss_v))
#xx在-3到3之间以步长为0.01,yy在-3到3之间以步长为0.01,生成二维网络坐标点
xx,yy = np.mgrid[-3:3:0.01,-3:3:0.01]
#将xx,yy拉直,并合成一个2列的矩阵,得到一个网络坐标点的集合
grid = np.c_[xx.ravel(),yy.ravel()]
#将网络坐标点喂入神经网络,probs为输出
probs = sess.run(y,feed_dict={x:grid})
#probs的shape调整成xx的样子
probs = probs.reshape(xx.shape)
#把probs整形,让它的形状和xx.shape一样
print("w1:\n",sess.run(w1))
print("b1:\n",sess.run(b1))
print("w2:\n",sess.run(w2))
print("b2:\n",sess.run(b2))
plt.scatter(X[:,0],X[:,1],c = np.squeeze(Y_c)) #可视化数据点,给出x坐标和y坐标,并给出这个坐标点打算显示的颜色
plt.contour(xx,yy,probs,levels = [.5]) #然后用plt.contour()函数把x坐标、y坐标、各点的高度,用levels把各点描上颜色
plt.show() #把图像散点画出来
首先,数据可视化,
如图所示:
其次,实现无正则化的训练过程:
最后,实现正则化的训练过程:
对比无正则化与有正则化模型的训练结果,可看出有正则化模型的拟合曲线平滑,模型具有更好的泛化能力。
【跑代码的坑:运行代码的时候,由于那时候还没有看全网课,自己先码了代码,跑出来第一张图后迟迟没有看到第二张图的出现。以为是代码有bug就检查了好几遍,最后发现是应该一张图出现以后,关掉这张图,程序才会继续运行。然后出现第二张图、关掉第二张图、程序继续运行、出现第三张图。。。百度了一些办法能不能同时出现几张图绘制图形,没有找到有效的解决办法。。。其实在用python、matplotlib绘图的时候感觉和matlab有点像,但是没有找到解决问题的办法也是比较遗憾吧。】
代码中出现了一个np.vstack()函数,由于我隔了一段时间看这个,有些记不清了,所以就百度了一下,找到一个简书不错,链接附给大家:
python基础之np.vstack()&np.hstack()