简洁明了的tensorflow2.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了。

代码实现:

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

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)

x_train = tf.cast(x_train,dtype=tf.float32)
y_train = tf.cast(y_train,dtype=tf.float32)

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

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

w1 = tf.Variable(tf.random.normal([2,11]),dtype=tf.float32)
b1 = tf.Variable(tf.random.normal([11]))

w2 = tf.Variable(tf.random.normal([11,1]),dtype=tf.float32)
b2 = tf.Variable(tf.random.normal([1]),dtype=tf.float32)

指定学习率还有训练次数

lr = 0.005
epoch = 1000

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

for epoch in range(epoch):
    for step,(x_train,y_train) in enumerate(train_db):
        with tf.GradientTape() as tp:#采用梯度下降的方法求神经网络参数

            h1 = tf.matmul(x_train,w1)+b1
            h1 = tf.nn.relu(h1)#使用relu激活函数
            y = tf.matmul(h1,w2)+b2

            loss = tf.reduce_mean(tf.square(y_train-y))#使用均方误差函数作为 损失函数

        variables = [w1,b1,w2,b2]
       #参数自更新
 grads = tp.gradient(loss,variables)
        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))

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

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

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

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

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

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

Y_c = [["red" if y else "blue"] for y in y_train]#y为1的点为红色,0的点为蓝色
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.savefig("./re_free")

三、L2型正则化代码实现

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

for epoch in range(epoch):
    for step,(x_train,y_train) in enumerate(train_db):
        with tf.GradientTape() as tp:
            h1 = tf.matmul(x_train,w1)+b1
            h1 = tf.nn.relu(h1)
            y = tf.matmul(h1,w2)+b2

            loss_mes = tf.reduce_mean(tf.square(y_train-y))
            loss_regularization = []
            loss_regularization.append(tf.nn.l2_loss(w1))#使用L2正则化
            loss_regularization.append(tf.nn.l2_loss(w2)))#使用L2正则化
            loss_regularization = tf.reduce_sum(loss_regularization)
            loss = loss_mes+0.03*loss_regularization

        variables = [w1,b1,w2,b2]
        grads = tp.gradient(loss,variables)
        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))

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

四、结果对比

未使用正则化结果截图:

使用L2正则化结果截图:

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

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

 

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值