深度学习笔记(五)——网络优化(1):学习率自调整、激活函数、损失函数、正则化

文中程序以Tensorflow-2.6.0为例
部分概念包含笔者个人理解,如有遗漏或错误,欢迎评论或私信指正。
截图和程序部分引用自北京大学机器学习公开课

通过学习已经掌握了主要的基础函数之后具备了搭建一个网络并使其正常运行的能力,那下一步我们还需要进一步对网络中的重要节点进行优化并加深认知。
首先我们知道NN(自然神经)网络算法能够相比传统建模类算法发挥更好效果的原因是网络对复杂非线性函数的拟合效果更好,且使用简单。实际应用中通常利用多层神经网络级联来发挥效果。既然涉及到回归和分类问题,不难发现,拟合效果,系统线性还是非线性,拟合结果输入输出结构,如何自动更新参数等等概念,成为了深度学习研究的重中之重。 这篇笔记重点关注优化网络时除了参数优化器以外的其它概念。同时数学概念会相对增加一些。

神经网络复杂度

评价一个网络模型的好坏是多方面的,其中很重要的一点就是看网络的复杂程度。网络完整的计算一次需要的运算次数可以用浮点运算次数(FPLOPs)或者乘加运算次数来表示。通过计算次数可以表示网络的时间复杂度,计算量需要越大的网络,时间复杂度自然越高。
除了时间复杂度,还可以从网络的规模,也就是所有层中总的参数量和输出特征图的数量来表示,网络规模的大小表示了网络的空间复杂度。在ML神经元模型中,单一 一个神经元就含有n+1个参数,其中n个数是上个层的输入,1个偏置系数。而在一个层中可以包含多个神经元。
这里涉及两个概念

  • 网络参数量:指网络模型中所有层中总的可变参数(权重参数)数量;
  • 特征图:网络在运行过程中,每个层的输出矩阵被称之为这个层的特征图,矩阵的维度大小称为特征图大小。

学习率调整策略

在权重参数反向传播跟新的过程中,学习率是一个直接影响权重跟新变化大小的参数。在权重更新时,最基础的方法是原权重参数减去学习率乘以损失函数梯度 W t + 1 = W t − l r × ∂ l o s s ∂ W t W_{t+1} = W_{t} - lr \times \frac{\partial loss}{\partial W_{t}} Wt+1=Wtlr×Wtloss 但是这样的参数更新是线性函数,有时候需要学习的数据呈现复杂的非线性特征,并且网络规模也各不相同,最主要的还是线性函数导致自始至终网络的学习能力(就是参数的跟新效率)是不变的。所以我们希望在损失计算较大时用一个较大学习率更新参数,随着损失的降低能不断地调小学习率,更加精细的调整网络权重。
所以引入指数衰减学习率 D l r = l r × φ N θ Dlr = lr\times \varphi ^{\frac{N}{\theta } } Dlr=lr×φθN 其中Dlr 是当前需要更新计算中使用的学习率,lr是初始学习率,fai是定义的衰减率,N是从开始到当前总的训练次数,sita表示每多少轮衰减一次学习率。根据指数函数性质可以知道要使学习率是下降趋势fai需要取值0到1之间。

import tensorflow as tf
from matplotlib import pyplot as plt

w = tf.Variable(tf.constant(5, dtype=tf.float32))

epoch = 40
LR_BASE = 0.4  # 最初学习率
LR_DECAY = 0.9  # 学习率衰减率
LR_STEP = 2  # 定义每经过两次BATCH_SIZE后,更新一次学习率
ls_list = []

for epoch in range(epoch):  # for epoch 定义顶层循环,表示对数据集循环epoch次,此例数据集数据仅有1个w,初始化时候constant赋值为5,循环100次迭代。
    lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)    # 学习率指数衰减,每两轮衰减一次学习率
    ls_list.append(lr)
    with tf.GradientTape() as tape:  # with结构到grads框起了梯度的计算过程。
        loss = tf.square(w + 1)
    grads = tape.gradient(loss, w)  # .gradient函数告知谁对谁求导,这里是loss函数对w求导

    w.assign_sub(lr * grads)  # .assign_sub 对变量做自减,更新参数 即:w -= lr*grads 即 w = w - lr*grads
    print("After %s epoch,w is %f,loss is %f,lr is %f" % (epoch, w.numpy(), loss, lr))

plt.title('Learning rate attenuation')  # 图片标题
plt.xlabel('Epoch')  # x轴变量名称
plt.ylabel('Lr')  # y轴变量名称
plt.plot(ls_list, label="$Learning Rate$")  # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()

可以看到最终结果,随着迭代次数的增加,学习率逐渐逐渐降低,成非线性下降,且下降程度根据学习率衰减率的减小而加快。
在这里插入图片描述
除了指数衰减以外,还可以根据迭代次数,设置分段函数的学习率。一般来说使用分段函数,各个段的长度取多少,每段内学习率设置为多少取决于设计者对网络调试的经验,往往难度较高。

# 其它上下文同上一段代码相同
epochs = epoch
for epoch in range(epoch):  # for epoch 定义顶层循环,表示对数据集循环epoch次,此例数据集数据仅有1个w,初始化时候constant赋值为5,循环100次迭代。
    # lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)    # 学习率指数衰减,每两轮衰减一次学习率
    if epoch < epochs*0.5:  # 分段处理
        lr = 0.4
    elif epoch < epochs*0.7:
        lr = 0.2
    elif epoch < epochs*0.9:
        lr = 0.1
    elif epoch < epochs:
        lr = 0.05

举例设置了分四段的学习率函数
在这里插入图片描述

激活函数

在前面的博文中针对神经元只使用了输入权重参数和偏置系数。回顾一下基础的ML神经元模型结构:
在这里插入图片描述
其实神经元的输出位置还有一个非线性函数。假如我们不使用这个函数,那么无论网络复合多少层,依然总体上是一个线性函数的组合,所以引入这个函数对于复杂非线性数据的学习显得尤为重要。简而言之,为了提高模型对非线性数据的表达能力,需要添加输出位置的非线性函数。这个函数称之为激活函数
根据激活函数的用途以及位置特点,一个优秀的激活应该满足:

  • 非线性:使用非线性激活函数,并通过多层网络组合,几乎可以拟合所有函数类型。也正是由于非线性激活函数的存在才使得多层网络的深度叠加有了意义
  • 连续单调可导:因为绝大多数参数更新是利用梯度下降法,反向传播过程中从输出层到输入层逐层链式求导,满足连续可导是梯度下降法的要求。同时函数应该单调,最好能是凸函数,这样能使求导后结果正有负,可以更加快速的完成参数更新
  • 近似恒等:指函数输出应该近似等于输入,这样可以避免数据的丢失,并且保证在求和结果很小时依然能有稳定输出值。
    在使用激活函数应该注意,对于使用梯度下降法更新参数的网络,适合使用输出是有界的激活函数。当激活函数输出无届时,应该尽量使用小的学习率,避免输出数据爆炸增涨。

常用激活函数

在选择激活函数时有几个简单的规律:

  • 首选ReLu函数
  • 学习率设置一个较小的数,例如0.01
  • 将输入的数据先进行标准归一化,也就是竟可能让数据的值域分布满足均值为0,标准差为1,或者处于[-1,1]之间
  • 初始化网络参数时,各层的随机参数可以符合均值为0,方差为 σ = 2 当 前 层 输 入 特 征 个 数 \sigma = \sqrt{\frac{2}{当前层输入特征个数} } σ=2 的标准正态分布
1、Sigmoid函数

f ( x ) = 1 1 + e − x f(x) = \frac{1}{1+e^{-x} } f(x)=1+ex1 其导数为 f ( x ) ′ = ( 1 1 + e − x ) ′ = − ( − e − x ) ( 1 + e − x ) 2 = 1 1 + e − x × e − x 1 + e − x = f ( x ) × ( 1 − f ( x ) ) f{(x)}' = {( \frac{1}{1+e^{-x} }) } ' =\frac{-(-e^{-x}) }{(1+e^{-x})^{2}}= \frac{1}{1+e^{-x} }\times \frac{e^{-x} }{1+e^{-x} }=f(x)\times (1-f(x)) fx=(1+ex1)=(1+ex)2(ex)=1+ex1×1+exex=f(x)×(1f(x)) (根据“小学一年级数学”,后文函数偏导数可自行计算)

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

# 定义 Sigmoid 函数
def sigmoid(x):
    return 1 / (1 + tf.exp(-x))
# 定义 Sigmoid 函数的导数
def sigmoid_derivative(x):
    return sigmoid(x) * (1 - sigmoid(x)) # 推导得到的导数公式

# 生成 x 值
x_values = np.linspace(-7, 7, 200)
# 计算 Sigmoid 函数在 x_values 上的值
y_sigmoid = sigmoid(x_values)
# 计算 Sigmoid 函数的导数在 x_values 上的值
y_derivative = sigmoid_derivative(x_values)

# 绘制 Sigmoid 函数
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(x_values, y_sigmoid, label='Sigmoid Function')
plt.title('Sigmoid Function')
plt.xlabel('x')
plt.ylabel('sigmoid(x)')
plt.grid(True)
plt.legend()
# 绘制 Sigmoid 函数的导数
plt.subplot(1, 2, 2)
plt.plot(x_values, y_derivative, label='Sigmoid Derivative')
plt.title('Sigmoid Derivative')
plt.xlabel('x')
plt.ylabel('sigmoid\'(x)')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

在这里插入图片描述
观察sigmoid激活函数的特点可以发现它具有以下特点:

  • 容易梯度消失,导数值小于0.25,多次求导后可能导致输出接近0(解决:让激活函数导数值域更大)
  • 非0均值,函数均值非0收敛速度会比0均值函数更慢(解决:使用分段函数或奇函数)
  • 幂运算会导致计算量大,使训练时间长(解决:钞能力,购买更厉害的显卡和CPU进行训练,👀👻)
2、Tanh函数

f ( x ) = 1 − e − 2 x 1 + e − 2 x f(x)=\frac{1-e^{-2x}}{1+e^{-2x}} f(x)=1+e2x1e2x

# 上下文程序可以根据sigmoid函数部分代码简单修改函数名和画图部分标签名实现
# 定义 tanh 函数
def tanh(x):
    return tf.math.tanh(x)

# 定义 tanh 函数的导数
def tanh_derivative(x):
    return 1 - tf.math.square(tf.math.tanh(x))

在这里插入图片描述
观察函数图像可以知道tanh 函数的输出是0均值(奇函数),但是只有当x属于[-2, 2]的区间内函数导数输出才有一个相对合适的值,其它大部分范围输出接近0,这样同样会造成梯度消失。并且同样使用了幂运算。

3、ReLu函数

f ( x ) = m a x ( x , 0 ) = { 0 x < 0 x x > = 0 f(x)=max(x, 0)= \left\{\begin{matrix} 0 \qquad x<0 \\ x \qquad x>=0 \end{matrix}\right. f(x)=max(x,0)={0x<0xx>=0

# 上下文程序可以根据sigmoid函数部分代码简单修改函数名和画图部分标签名实现
# 定义 ReLU 函数
def relu(x):
    return tf.nn.relu(x)
# 定义 ReLU 函数的导数
def relu_derivative(x):
    return tf.where(x > 0, 1.0, 0.0)

x_values = np.linspace(-3, 3, 200)		# 生成 x 值
y_relu = relu(x_values)  # 计算 ReLU 函数的值
y_derivative = relu_derivative(x_values)		# 计算导数

在这里插入图片描述
Relu函数则直接使用无界分段函数,首先解决了梯度消失的问题,但是只当输出值大于0时有效。
其次只用判断输出是否大于0,速度快,但是这样会导致训练过程中某些神经元的输出一直是0,这样该神经元参数不更新,失去学习效果,成为神经元死亡(dead relu)。为了解决这个问题往往初始化网络时会使用较多的正值参数,尽可能保证输出值是正数,同时调小学习率。

4、LeakyRelu函数

f ( x ) = m a x ( a x , x ) = { a x x < 0 x x > = 0 f(x) = max(ax,x)= \left\{\begin{matrix} ax \qquad x<0 \\ x \qquad x>=0 \end{matrix}\right. f(x)=max(ax,x)={axx<0xx>=0
函数在小于0时使用了一个带参数的一元函数。当a取值合适时,理论上LeakyRelu激活函数将具有Relu的所有优点同时避免其缺点,但是目前还没有严格的被证明LeakyRelu总是优于Relu。自己使用时可以多进行实验找到最合适的激活函数。

# 上下文程序可以根据sigmoid函数部分代码简单修改函数名和画图部分标签名实现
# 定义 Leaky ReLU 函数 其中alpha为小于0时的斜率系数,通常应用时这个值取0.02等较小的数
def leaky_relu(x, alpha=0.15):
    return tf.nn.leaky_relu(x, alpha)

# 定义 Leaky ReLU 函数的导数
def leaky_relu_derivative(x, alpha=0.15):
    return tf.where(x > 0, 1.0, alpha)

x_values = np.linspace(-3, 3, 200)
y_leaky_relu = leaky_relu(x_values)
y_derivative = leaky_relu_derivative(x_values)

在这里插入图片描述

损失函数(Loss)

损失函数计算的是计算得到的输出值和已知标签(正确答案)之间的差距
结合之前的介绍,我们知道反向传播的过程中需要使损失函数最小化,不同的损失函数会对网络的跟新和输出趋势产生影响。可以理解为损失函数的值直接影响着反向传播参数的更新(所以反向传播就类似于控制系统中的反馈控制,损失函数就类似反馈回路的传递函数)。所以损失函数的设计十分重要。

常用的损失函数

1、MSE均方误差

M S E ( Y , Y ^ ) = ∑ i = 1 n ( Y i − Y i ^ ) 2 n MSE(Y,\hat{Y} ) = \frac{\sum_{i=1}^{n}(Y_i - \hat{Y_i})^{2} }{n} MSE(Y,Y^)=ni=1n(YiYi^)2
均方误差就是所有实际值和计算输出值差的平方的平均值。均方误差应用最多的领域就是计算回归问题。使用均方误差可以很快的找到数据中的规律性,实现网络的回归拟合。

import numpy as np
import tensorflow as tf
np.random.seed(42) # 设置随机数种子
true_values = np.random.randint(0, 10, 100)		# 生成两组随机数
predicted_values = true_values + np.random.normal(0, 2, 100)

# 转换为 TensorFlow 的张量
true_values_tensor = tf.constant(true_values, dtype=tf.float32)
predicted_values_tensor = tf.constant(predicted_values, dtype=tf.float32)

# 计算均方误差 (MSE)
# 使用 tf.reduce_mean(平均数) 和 tf.square(平方)计算MSE
mse = tf.reduce_mean(tf.square(true_values_tensor - predicted_values_tensor))	

# 输出 MSE 的值
print("Mean Squared Error (MSE):", mse.numpy())
2、CE交叉熵损失

H ( Y , Y ^ ) = − ∑ Y i ^ × l n Y i H(Y,\hat{Y} ) = -\sum \hat{Y_i}\times lnY_i H(Y,Y^)=Yi^×lnYi 上式中Y表示真实值的概率,Y一巴表示网络计算的输出值的概率。
交叉熵表征两个概率分布之间的距离,交叉熵越小说明二者分布越接近。交叉熵的计算考虑了真实数据的概率分布,相比MSE交叉熵有一定的加权效果。除了回归问题,交叉熵则广泛应用在分类和迁移学习上。要注意的一点是,在网络的输出中往往最终输出的结果不符合概率分布,所以需要配合softmax函数一起使用。其原理可以看深度学习笔记(四)——softmax,一般流程值网络计算得到输出张量,经过softmax后转化为概率分布矩阵,随后计算CE。

import numpy as np
import tensorflow as tf
# 生成两组数据 y_ 已经符合概率分布要求,y 可以认为是网轮的输出矩阵
y_ = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0]])
y = np.array([[12, 3, 2], [3, 10, 1], [1, 2, 5], [4, 6.5, 1.2], [3, 6, 1]])
y_pro = tf.nn.softmax(y)	# 计算输出数据的概率分布
loss_ce1 = tf.losses.categorical_crossentropy(y_,y_pro)	# 计算交叉熵
loss_ce2 = tf.nn.softmax_cross_entropy_with_logits(y_, y)	# 复合了softmax和交叉熵计算的函数

print('分步计算的结果:\n', loss_ce1)
print('结合计算的结果:\n', loss_ce2)

提示:如果你的环境是tensorflow2.6.0,且安装步骤是按照前面几篇笔记来的,那你可能会遇到这一行代码报错tf.losses.categorical_crossentropy,请终端在对应虚拟环境中执行pip install keras==2.6即可

3、自定义损失函数

根据具体任务和目的,可设计不同的损失函数。例如,我们可以看目标检测中的多种损失函数。目标检测的主要功能是定位和识别,损失函数的功能主要就是让定位更精确,识别准确率更高。目标检测任务的损失函数由分类损失(Classificition Loss)和回归损失(Bounding Box Regeression Loss)两部分构成。近几年来回归损失主要有Smooth L1 Loss(2015), IoU Loss(2016 ACM), GIoU Loss(2019 CVPR), DIoU Loss & CIoU Loss(2020AAAI)等,分类损失有交叉熵、softmax loss、logloss、focal loss等。主要是认识到:需要时,得针对特定的背景、具体的任务设计损失函数。

欠拟合和过拟合

在这里插入图片描述
上面这幅图很好的表达了三种拟合情况的区别,欠拟合时网络判断能力不够,无法输出正确结果,过拟合时网络陷入局部最优,失去了泛化能力,容易把相同但只有细微差别的输入数据判断为两种情况。拟合的好坏决定了训练好的模型迁移到新的环境中对新数据输出的准确程度。良好的模型训练过程应该避免欠拟合与过拟合的出现。
解决欠拟合的方法:

  • 扩大数据的特征数量(学习更多的细节)
  • 增加网络的参数和网络的层数(提高学习和理解能力)
  • 减少正则化参数(降低学习的复杂程度)

解决过拟合的方法:

  • 清洗输入数据(让学习的数据特征更明显,噪声更少,押题战术)
  • 增大训练数据集(学习更多的样本,题海战术)
  • 使用正则化(提高复杂度和计算量,回归基础,认识特征)
  • 增大正则化参数(上强度,深挖概念,排除错误选项)

正则化方法

正则化是用于缓解训练过程中出现过度拟合的一种有效手段。通过正则化可以在损失函数中引入模型的复杂度指标,也就是在原有损失函数计算的基础上,进一步的给权重参数加权。正则化的方式通常有两种:L1正则和L2正则,其中L1正则为: l o s s L 1 ( W ) = ∑ i ∣ W i ∣ loss_{L1}(W) = \sum_{i}^{}\left | W_i \right | lossL1(W)=iWi L2正则为: l o s s L 2 ( W ) = ∑ i ∣ W i 2 ∣ loss_{L2}(W) = \sum_{i}^{}\left | W_i^{2} \right | lossL2(W)=iWi2 正则化计算得到的损失函数为: l o s s = l o s s ( Y , Y ^ ) + R e g u l a r i z e r × l o s s ( W ) loss = loss(Y,\hat{Y} ) + Regularizer \times loss (W) loss=loss(Y,Y^)+Regularizer×loss(W) 其中等式右边第一项loss计算输出值和真实值的损失,第二项的Regularizer 为正则化的权重系数,第二个loss则计算需要正则的参数w。
使用正则化时,L1正则会将较多的参数变为0,所以该方法可以稀疏参数,减少非0的参数数量,降低模型的复杂度。
L2正则由于使用平方计算,会使参数接近0但不等于0,这个方法可以减小部分参数的权重(反应为参数变小),降低模型的复杂度。
抽象一点理解,加入了正则化,局部计算就难以过度拟合,可以让模型的拟合效果变的更加平滑。

正则化拟合示例

1、无正则

# @ 引用自:北京大学-《人工智能实践》-曹建
# 导入所需模块
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.005  # 学习率
epoch = 800  # 循环轮数

# 训练部分
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函数,给probs值为0.5的所有点上色  plt.show()后 显示的是红蓝点的分界线
plt.contour(xx, yy, probs, levels=[.5])
plt.show()

在这里插入图片描述

2、加入L2正则后:

# 接上一段程序,修改43行到46行为下面的 正则化计算
			 # 采用均方误差损失函数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(loss_regularization)
            loss = loss_mse + 0.03 * loss_regularization  # REGULARIZER = 0.03

在这里插入图片描述
不难看出使用了正则化后参数的拟合变得更加平滑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/317902.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux环境之Ubuntu安装Docker流程

今天分享Linux环境之Ubuntu安装docker流程&#xff0c;Docker 是目前非常流行的容器&#xff0c;对其基本掌握很有必要。下面我们通过阿里云镜像的方式安装&#xff1a; 本来今天准备用清华大学镜像安装呢&#xff0c;好像有点问题&#xff0c;于是改成阿里云安装了。清华安装…

《矩阵分析》笔记

来源&#xff1a;【《矩阵分析》期末速成 主讲人&#xff1a;苑长&#xff08;5小时冲上90&#xff09;】https://www.bilibili.com/video/BV1A24y1p76q?vd_sourcec4e1c57e5b6ca4824f87e74170ffa64d 这学期考矩阵论&#xff0c;使用教材是《矩阵论简明教程》&#xff0c;因为没…

Linux———ps命令详解

目录 ps 命令&#xff08;"process status" 的缩写。&#xff09; 常用选项和参数&#xff1a; a&#xff1a;显示所有用户的进程&#xff0c;包括其他用户的进程。​ u&#xff1a;显示详细的进程信息&#xff0c;包括进程的所有者、CPU 使用率、内存使用量等。…

【LabVIEW FPGA入门】模拟输入和模拟输出

1.简单模拟输入和输出测试 1.打开项目&#xff0c;在FPGA终端下面新建一个VI 2.本示例以模拟输入卡和模拟输出卡同时举例。 3.新建一个VI编写程序&#xff0c;同时将卡1的输出连接到卡2的输入使用物理连线。 4.编译并运行程序&#xff0c;观察是否能从通道中采集和输出信号。 5…

【天龙八部】攻略day6

关键字&#xff1a; 灵武、寻宝要求、雁门 1】灵武选择 西凉枫林&#xff0c;锦带&#xff0c;短匕 白溪湖&#xff0c;明镜&#xff0c;双刺 竹海&#xff0c;玉钩&#xff0c;锁甲 2】楼兰寻宝需求 等级80级&#xff0c;40级前6本心法 3】雁门奖励 简单35*4元佑碎金 普…

PyCharm连接服务器 - 1

文章目录 利用PyCharm实现远程开发使用认证代理连接服务器 利用PyCharm实现远程开发 【注】该连接服务器的方法适用于代码在服务器&#xff0c;我们是通过 GateWay 打开远程服务器的代码进行操作。 该功能只有在PyCharm专业版下才可以使用&#xff0c;并且必须是官方的正版许…

不方便拉网线,房间又没Wifi信号?按照这个教程,让你家里每个角落都有网

前言 前段时间去了一个朋友家里&#xff0c;她老是和我叨叨说她家的卧室一点Wifi信号都没有。每次一躺床上都只能用手机流量上网。 家里明明有拉宽带&#xff0c;为什么在某一些地方还是得用自己手机流量&#xff1f;哎&#xff0c;有钱人的痛就是房子太大了。 我问她为啥不多…

LeetCode264. 丑数 II(相关话题:多重指针动态规划)

题目描述 给你一个整数 n &#xff0c;请你找出并返回第 n 个 丑数 。丑数 就是质因子只包含 2、3 和 5 的正整数。 示例 1&#xff1a; 输入&#xff1a;n 10 输出&#xff1a;12 解释&#xff1a;[1, 2, 3, 4, 5, 6, 8, 9, 10, 12] 是由前 10 个丑数组成的序列。示例 2&am…

MySQL数据库入门到大牛_高级_00_MySQL高级特性篇的内容简介

文章目录 一、整个MySQL的思维导图二、MySQL高级特性篇大纲1. MySQL架构篇2. 索引及调优篇3. 事务篇4. 日志与备份篇 一、整个MySQL的思维导图 下图为整个MySQL内容&#xff0c;01-05是基础篇&#xff0c;06-09是高级篇 二、MySQL高级特性篇大纲 MySQL高级特性分为4个篇章&…

鸿蒙开发现在就业前景怎样?

随着科技的不断进步&#xff0c;鸿蒙系统逐渐崭露头角&#xff0c;成为智能设备领域的一颗新星。作为华为自主研发的操作系统&#xff0c;鸿蒙系统拥有着广阔的市场前景和就业机会。那么&#xff0c;鸿蒙开发的就业前景究竟怎样呢&#xff1f; 一、市场需求持续增长 随着鸿蒙…

【Docker】Linux中Docker镜像结构及自定义镜像,并且上传仓库可提供使用

目录 一、镜像结构 1. 基本结构 2. 常用命令 二、自定义镜像 1. 基本镜像 2. 进阶镜像 3. 完善镜像 三、镜像上传仓库 每篇一获 一、镜像结构 自定义 Docker 镜像有很多用途&#xff0c;以下是一些主要的应用场景&#xff1a; 一致性环境&#xff1a;通过自定义镜像&a…

如何实现接口重试

重试机制 在复杂的接口业务中&#xff0c;API请求数量很多&#xff0c;并且业务处理复杂&#xff0c;便难免会遇到一些网络问题(timeout)或者未知错误(error)&#xff0c;这时候需要加入重试机制了。让我们来回顾一下都有什么实现机制吧。 8种重试机制实现 1. 循环重试 这是最…

Hive命令行运行SQL将数据保存到本地如何去除日志信息

1.场景分析 先有需求需要查询hive数仓数据并将结果保存到本地&#xff0c;但是在操作过程中总会有日志信息和表头信息一起保存到本地&#xff0c;不符合业务需要&#xff0c;那如何才能解决该问题呢&#xff1f; 废话不多少&#xff0c;直接上代码介绍&#xff1a; 2.问题解决…

计算机毕业设计 | SpringBoot+vue的家庭理财 财务管理系统(附源码)

1&#xff0c;绪论 1.1 项目背景 网络的发展已经过去了七十多年&#xff0c;网络技术的发展&#xff0c;将会影响到人类的方方面面&#xff0c;网络的出现让各行各业都得到了极大的发展&#xff0c;为整个社会带来了巨大的生机。 现在许多的产业都与因特网息息相关&#xff…

从零开发短视频电商 PaddleOCR Java推理 (一)飞桨引擎推理

文章目录 简介方式一&#xff1a;DJL 飞浆引擎 飞桨模型方式二&#xff1a;ONNXRuntime 飞桨转换后的ONNX模型&#xff08;Paddle2ONNX&#xff09; 添加依赖文字识别OCR过程分析文字区域检测文字角度检测文字识别&#xff08;裁减旋转后的文字区域&#xff09; 高级替换模型…

猫头虎分享:探索TypeScript的世界 — TS基础入门 ‍

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…

逆变器3前级推免(高频变压器)

一节电池标压是在2.8V—4.2V之间&#xff0c;所以24V电压需要大概七节电池串联。七节电池电压大概在19.6V—29.4V之间。 从24V的电池逆变到到220V需要升压的过程。那么我们具体需要升压到多少&#xff1f; 市电AC220V是有效值电压&#xff0c;峰值电压是220V*1.414311V 如果…

语义分割miou指标计算详解

文章目录 1. 语义分割的评价指标2. 混淆矩阵计算2.1 np.bincount的使用2.2 混淆矩阵计算 3. 语义分割指标计算3.1 IOU计算方式1(推荐)方式2 3.2 Precision 计算3.3 总体的Accuracy计算3.4 Recall 计算3.5 MIOU计算 参考 MIoU全称为Mean Intersection over Union&#xff0c;平均…

C++算法学习心得五.二叉树(4)

1.二叉搜索树中的插入操作&#xff08;701题&#xff09; 题目描述&#xff1a;给定二叉搜索树&#xff08;BST&#xff09;的根节点和要插入树中的值&#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证&#xff0c;新值和原始二叉搜索树中的任意…

Java内置锁:深度解析Lock接口中lock方法和lockInterruptibly方法

Java11中的Lock接口提供lock()和lockInterruptibly()两种锁定方法&#xff0c;用于获取锁&#xff0c;但处理线程中断时有所不同&#xff0c;lock()使线程等待直到锁释放&#xff0c;期间无视中断&#xff1b;而lockInterruptibly()在等待中若收到中断请求&#xff0c;会立即响…