小言_互联网的博客

简洁明了的tensorflow2.0教程——正则化操作

449人阅读  评论(0)

通常我们在训练神经网络模型的时候会出现过拟合的情况,模型训练的过于好,导致泛化能力不强。一般我们引入正则化可以解决过拟合问题,正则化分为两类,L1型正则化,L2型正则化。接下来我们做简单介绍并给出tensorflow代码实现。完整代码位于我的github,链接:https://github.com/JohnLeek/Tensorflow-study,day2_regularizationfree.py(未使用正则化),和day2_regularization_L2.py(使用正则化),数据集为dot.csv。

通常L1正则化大概率会使得很多参数变为零,因此该方法可通过稀疏参数,即减少参数的数量,降低复杂度;L2正则化会使得参数很接近零但不为零,因此该方法可以通过减小参数值的大小降低复杂度。

一、L1型正则化和L2型正则化公式

L1正则化公式如上,这里不做推导和展开,只需要记住公式即可,其中,Ein 是未包含正则化项的训练样本误差(损失函数),λ 是正则化参数,w为正则化项。

L2正则化公式如上

二、未添加正则化项代码实现

本节使用的数据集为我自己准备的(dot.csv),预备知识是绘制网格坐标点,参考我的这篇博客https://blog.csdn.net/JohnLeeK/article/details/105758916

首先我们查看下数据集的格式

其中C1和C2为x_trian,C3为y_trian,注意C3这一列取值只有0和1。我们需要做的工作就是训练我们自己的神经网络将y为0和1的点区分开。

我的思路是这样的:首先我们构建一个神经网络将dot.csv中的数据送入神经网络进行训练得到训练好的模型,然后我们绘制网格坐标点,将所有的点送入神经网络进行预测,我们保留所有预测结果,最后把所有结果为0.5的点连接(预备知识matplotlib绘制轮廓图和散点图)起来这样就可以区分0和1了。

代码实现:

首先我们读取数据集生成训练集并将数据与标签匹配


  
  1. df = pd.read_csv( "dot.csv")
  2. x_data = np.array(df[[ "x1", "x2"]])
  3. y_data = np.array(df[ "y_c"])
  4. x_train = np.vstack(x_data).reshape( -1, 2)
  5. y_train = np.vstack(y_data).reshape( -1, 1)
  6. x_train = tf.cast(x_train,dtype=tf.float32)
  7. y_train = tf.cast(y_train,dtype=tf.float32)

然后我们根据下图开始搭建神经网络结构

如图,一共是两个输入对应dot.csv中的x1,x2,隐藏层一共有十一个神经元,输出层为一个神经元。


  
  1. w1 = tf.Variable(tf.random.normal([ 2, 11]),dtype=tf.float32)
  2. b1 = tf.Variable(tf.random.normal([ 11]))
  3. w2 = tf.Variable(tf.random.normal([ 11, 1]),dtype=tf.float32)
  4. b2 = tf.Variable(tf.random.normal([ 1]),dtype=tf.float32)

指定学习率还有训练次数


  
  1. lr = 0.005
  2. epoch = 1000

开始训练我们的神经网络模型


  
  1. for epoch in range(epoch):
  2. for step,(x_train,y_train) in enumerate(train_db):
  3. with tf.GradientTape() as tp: #采用梯度下降的方法求神经网络参数
  4. h1 = tf.matmul(x_train,w1)+b1
  5. h1 = tf.nn.relu(h1) #使用relu激活函数
  6. y = tf.matmul(h1,w2)+b2
  7. loss = tf.reduce_mean(tf.square(y_train-y)) #使用均方误差函数作为 损失函数
  8. variables = [w1,b1,w2,b2]
  9. #参数自更新
  10. grads = tp.gradient(loss,variables)
  11. w1.assign_sub(lr*grads[ 0])
  12. b1.assign_sub(lr*grads[ 1])
  13. w2.assign_sub(lr*grads[ 2])
  14. b2.assign_sub(lr*grads[ 3])
  15. if epoch % 20 == 0:
  16. print( "epoch:",epoch, "loss:",float(loss))

重点来了,生成网格坐标点:


  
  1. xx,yy = np.mgrid[ -3: 3: 1, -3: 3: 1]
  2. grid = np.c_[xx.ravel(),yy.ravel()]
  3. grid = tf.cast(grid,tf.float32)

这里我们以1为步长,从-3到2生成网格坐标点,然后进行拉直操作再讲xx,yy进行配对,然后将numpy数据类型转化为tensor类型。

接下来就是预测的部分,我们将所有的网格坐标点送入训练好的模型做预测,然后保存所有预测结果


  
  1. for x_test in grid:
  2. h1 = tf.matmul([x_test],w1)+b1
  3. h1 = tf.nn.relu(h1)
  4. y = tf.matmul(h1,w2)+b2
  5. probs.append(y)
  6. x1 = x_data[:, 0]
  7. x2 = x_data[:, 1]

最后我们绘制图片,这里需要用到matplotlib中的散点图还有轮廓图,不会的可以自行百度,后面我要是有时间我会更新matplotlib绘图进阶操作。


  
  1. Y_c = [[ "red" if y else "blue"] for y in y_train] #y为1的点为红色,0的点为蓝色
  2. x1 = x_data[:, 0]
  3. x2 = x_data[:, 1]
  4. probs = np.array(probs).reshape(xx.shape)
  5. plt.scatter(x1,x2,color=np.squeeze(Y_c))
  6. plt.contour(xx,yy,probs,levels=[ .5])
  7. plt.savefig( "./re_free")

三、L2型正则化代码实现

做正则化我们要修改的地方就是在训练的过程中指定正则化方式,tensorflow已经帮我们实现了,我们只需要做一部分简单的工作即可。


  
  1. for epoch in range(epoch):
  2. for step,(x_train,y_train) in enumerate(train_db):
  3. with tf.GradientTape() as tp:
  4. h1 = tf.matmul(x_train,w1)+b1
  5. h1 = tf.nn.relu(h1)
  6. y = tf.matmul(h1,w2)+b2
  7. loss_mes = tf.reduce_mean(tf.square(y_train-y))
  8. loss_regularization = []
  9. loss_regularization.append(tf.nn.l2_loss(w1)) #使用L2正则化
  10. loss_regularization.append(tf.nn.l2_loss(w2))) #使用L2正则化
  11. loss_regularization = tf.reduce_sum(loss_regularization)
  12. loss = loss_mes+ 0.03*loss_regularization
  13. variables = [w1,b1,w2,b2]
  14. grads = tp.gradient(loss,variables)
  15. w1.assign_sub(lr*grads[ 0])
  16. b1.assign_sub(lr*grads[ 1])
  17. w2.assign_sub(lr*grads[ 2])
  18. b2.assign_sub(lr*grads[ 3])
  19. if epoch % 20 == 0:
  20. print( "epoch:",epoch, "loss:",float(loss))

这里有问题的可以看看我给出的L2正则化公式,然后结合代码看看应该就能明白了,

四、结果对比

未使用正则化结果截图:

使用L2正则化结果截图:

总的来看对比结果不是很明显,但是我们也可以发现为使用正则化的时候,做分割0和1的时候在将所有的红点和蓝点分开,圈内基本是红点,有点过拟合,二使用L2正则化以后分割的曲线只是尽可能使更多的红点落在圈内。

到这里正则化的内容就讲解完了,我给出了L2正则化的代码,但是未给出L1正则化,有时间的读者可以自行实现.。

 


转载:https://blog.csdn.net/JohnLeeK/article/details/106335532
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场