Bootstrap

【神经网络基础】

1.损失函数
1.损失函数的概念

什么是损失函数

在深度学习中,**损失函数是用来衡量模型参数质量的函数,**衡量方式是比较网络输出和真实输出之间的差异.

在这里插入图片描述

不同文献中有不同命名方式

loss function:损失函数

cost function:代价函数

objective function:目标函数

error function:误差函数

2.分类任务损失函数-多分类损失:

使用nn.CrossEntropyLoss()计算交叉熵损失值

多分类任务中通常使用softmax将logits(逻辑值)转换为概率形式,多分类的交叉熵损失也叫softmax 损失,计算方法是
L = − ∑ i = 1 n y i l o g ( f θ ( X i ) ) L = -\sum_{i=1}^n{y_i}{log(f_θ(X_i))} L=i=1nyilog(fθ(Xi))

  1. y是样本x属于某一个类别的真实概率

  2. 而f(x)是样本属于某一个类别的预测分数

  3. s为softmax激活函数,将属于莫一类别的预测分数转换成概率

  4. L是用来衡量真实值y与预测值f(x)之间差异性的损失结果

​ 计算 L交叉熵的值越小越与真实值更加接近

在这里插入图片描述

在Python中实现使用nn.CrossEntropyLoss()如下所示:

# 构建多分类损失函数-CrossEntropy
import torch
from torch import nn

# 多分类任务交叉熵损失:使用nn.CrossEntropyLoss()实现
def test01():
    # 设置真实值:可以是热编码后的结果也可以不是
    y_true = torch.tensor([[0, 1, 0], [0, 0, 1]], dtype=torch.float32)
    # 注意的类别必须是64为整数型
    # y_true = torch.tensor([1, 2], dtype=torch.int64)
    # 构建预测值计算损失结果
    y_pred = torch.tensor([[0.2, 0.6, 0.2], [0.1, 0.8, 0.1]], dtype=torch.float32)
    # 实例化交叉熵损失
    loss = nn.CrossEntropyLoss()
    # 计算损失结果:默认情况下,CrossEntropyLoss()会自动将预测值进行one-hot编码。
    # 转换为numpy类型
    my_loss = loss(y_pred, y_true).numpy()
    print('loss', my_loss)
3.分类任务损失函数-二分类损失:

使用nn.BCELoss()计算二分类交叉熵

在处理二分类任务时使用sigmoid激活函数,使用二分类的交叉熵损失函数:

L = − y l o g y ^ − ( 1 − y ) l g ( 1 − y ^ ) L = -ylog\hat y - (1-y)lg(1-\hat y) L=ylogy^(1y)lg(1y^)

  1. y样本x属于某一个类别的真实概率
  2. 而y^是样本属于某一类别的预测概率
  3. L是衡量真实值与预测值之间差异性的损失结果

在Python实现nn.BCELoss()结果:如下所示

 # 2-二分类-BCELoss.py
import torch
from torch import nn


def test01():
    # 1.设置真实值与预测值
    # 预测值为sigmoid()函数的输出结果
    # requires_grad=True:表示需要计算梯度,用于反向传播。
    y_pred = torch.tensor([0.6901, 0.5459, 0.2469], requires_grad=True)
    y_true = torch.tensor([0, 1, 0], dtype=torch.float32)
    # 2.实例化二分类交叉熵
    loss = nn.BCELoss()
    # 3,计算损失值
    # 在 PyTorch 中,如果一个张量需要梯度(即 requires_grad=True),
    # 则不能直接调用 .numpy() 方法,因为这会导致梯度信息丢失,从而影响反向传播
    # 需要使用 .detach() 方法
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss', my_loss)
4.回归任务损失函数计算-MAE损失

Mean absolute loss (MAE)被称为L1 Loss,以绝对误差作为距离,损失函数公式

L = 1 n ∑ i = 1 n ∣ y i − f θ ( x i ) ∣ L = \frac{1}{n}\sum_{i=1}^n|y_i-f_θ(x_i)| L=n1i=1nyifθ(xi)
曲线图如下:
在这里插入图片描述

特点是

  • 1.由于 LI Loss具有稀疏性,为了惩罚较大的值常作为正则化添加到其他loss中作为约束

  • 2. L1 Loss最大问题就是零点梯度不平滑,导致会跳过极小值

在python中实现使用nn.L1Loss()实现

import torch
from torch import nn


def test01():
    # 1.设置真实值与预测值
    #  requires_grad=True:表示需要计算梯度,前向传播会记录梯度,用于反向传播。
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.9], dtype=torch.float32)
    # 2.实例化MAE损失对象
    loss = nn.L1Loss()
    # 3.计算损失
    my_loss = loss(y_pred,y_true).detach().numpy()
    print('loss',my_loss)
if __name__ == '__main__':
    test01()
5.回归任务损失函数-MSE损失

MSE:L2 Loss 损失或者叫欧式距离,以误差的平方和的均值作为距离

损失公式

L = 1 n ∑ i = 1 n ( y i − f θ ( x i ) ) 2 L = \frac{1}{n}\sum_{i=1}^n(y_i-fθ(x_i))^2 L=n1i=1n(yifθ(xi))2
曲线图如下:
在这里插入图片描述

特点是:

1.L2 loss也常作为正则化项

2.当预测值与目标值相差较大时,梯度容易发生爆炸

在 python中使用nn.MSELoss()实现,如下所示

import torch
from torch import nn


def test01():
    # 1.设置真实值与预测值
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.0], dtype=torch.float32)
    # 2.实例化MSE损失对象
    loss = nn.MSELoss()
    # 3.计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss', my_loss)

if __name__ == '__main__':
    test01()
6.回归任务损失函数-Smooth L1损失

smooth L1说的是光滑之后的L1,损失函数公式:
s m o o t h L 1 ( x ) = { 0.5 ( x ) 2 if  ∣ x ∣ < 1 ∣ x ∣ − 0.5 otherwise smooth_{L1}(x) = \begin{cases} 0.5(x )^2 & \text{if } |x | < 1 \\ |x | - 0.5 & \text{otherwise} \end{cases} smoothL1(x)={0.5(x)2x0.5if x<1otherwise

x = f(x) - y 为真实值 和 预测值之间的差值

从下图可以看出该函数实际为一个分段函数

​ 1.在区间[-1,1]实际是L2损失,解决了L1不光滑问题

​ 2.在区间[-1,1]外,实际就是L1损失,这就解决离群点爆炸问题

在这里插入图片描述

在python中使用 nn.SmoothL1Loss()实现,如下所示

import torch
from torch import nn


def test01():
    # 1.设置真实值与预测值
    y_pred = torch.tensor([0.6, 0.4], requires_grad=True)
    y_true = torch.tensor([0, 3])
    # 2.实例化SmoothL1损失对象
    loss = nn.SmoothL1Loss()
    # 3.计算损失
    # detach():将损失张量从计算图中分离出来,不影响梯度计算
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss', my_loss)


if __name__ == '__main__':
    test01()
2.网络优化方法
1.梯度下降算法

梯度下降法是一种寻找使损失函数最小化的方法,从数学的角度看,梯度方向是函数增长最快的方向, 梯度的反方向就是函数减少最快的方向,所以有:

W i j n e w = W i j o i d − α ∂ E ∂ W i j W_{ij}^{new} = W_{ij}^{oid} - α\frac{∂E}{∂W_{ij}} Wijnew=WijoidαWijE
其中α为学习率,如果学习率太小,得到的效果就太小,增大训练成本.学习率太大可能跳过最优解,解决方法是,让学习率需要需要随着训练的进行而变化.

在这里插入图片描述

在进行模型训练时,有三个基础概念:

  1. Epoch:使用全部数据对模型进行完整的训练,训练轮次

  2. Batch_size:使用 训练集中小部分样本对模型权重进行以此反向传播的参数的更新,每次训练每批次的数据

  3. Iteration:使用一个Batch的数据对模型进行一次参数的更新的过程

# 假设数据集有 50000 个训练样本,现在选择 Batch Size = 256 对模型进行训练。

- 每个 Epoch 要训练的图片数量:50000

- 训练集具有的 Batch 个数:50000/256+1=196

- 每个 Epoch 具有的 Iteration 个数:196

- 10个 Epoch 具有的 Iteration 个数:1960

在深度学习过程中,梯度下降的几种方式根本区别在于Batch_size的不同,如下表所示:

在这里插入图片描述

:上表中Mini-Batch的Batch个数为N/B+1是针对未整除的情况,整除则是N/B

2.反向传播算法(BP算法)

**前向传播:**指的是数据输入的神经网络中,逐层向前传输,一直=运输到输出层为止

**反向传播:利用损失函数从后往前,结合梯度下降算法,**依次对各个参数的偏导,并进行参数更新

在这里插入图片描述

**反向传播对神经网络中的各个节点的权重进行更新.**一个简单的神经网络 用来举例:激活函数为sigmoid
在这里插入图片描述

前向传播运算过程:

在这里插入图片描述

反向传播:我们先来求最简单的,求误差E对w5的导数。要求误差E对w5的导数,需要先求误差E对out o1的导数,再求out o1对net o1的导数,最后再求net o1对w5的导数,经过这个处理,我们就可以求出误差E对w5的导数(偏导),如下图所示:
在这里插入图片描述

导数(梯度)计算出来,下面就是反向传播与参数更新过程:
在这里插入图片描述

如果要想求误差E对W1的导数,误差E对W1的求导路径不止一条,计算过程如图所示:
在这里插入图片描述

  • 代码实现
# 构建神经元网络
# 导入数据包
import torch
# 导入神经元nn模块
import torch.nn as nn
# 优化器
from torch import optim


# 创建神经元网络类
class Model(nn.Module):
    # 初始化两个方法
    # 初始化参数
    def __init__(self):
        # 调用父类初始化方法
        super(Model, self).__init__()
        # 构建网络层
        self.linear1 = nn.Linear(2, 2)
        self.linear2 = nn.Linear(2, 2)
        # 初始化权重参数
        nn.init.kaiming_normal_(self.linear1.weight)
        nn.init.xavier_normal_(self.linear2.weight)

    # 前向传播
    def forward(self, x):
        # 数据经过第一层网络
        x = self.linear1(x)
        # 计算第一层激活值
        x = torch.relu(x)
        # 数据经过第二层网络
        x = self.linear2(x)
        # 计算第二层激活值
        x = torch.sigmoid(x)
        return x


if __name__ == '__main__':
    # 定义输入值和目标值
    inputs = torch.tensor([[0.05, 0.10]])
    target = torch.tensor([0.01, 0.99])
    # 实例化神经元网络对象
    model = Model()
    # 预测值
    output = model(inputs)
    # 计算误差
    loss = nn.MSELoss()
    my_loss = loss(output, target)
    print('loss', my_loss)
    # 优化方法和反向传播方法
    optimizer = optim.SGD(model.parameters(), lr=1e-2)
    optimizer.zero_grad()
    # 自己计算的损失函数进行反向传播
    my_loss.backward()
    print('梯度', model.linear1.weight.grad)
    print('梯度', model.linear2.weight.grad)
    optimizer.step()
    # 打印神经网络参数
    # state_dict():于获取模型参数状态字典的方法
    print(model.state_dict())

总结
前向传播:指的就是数据输入的神经网络中,逐层向前传输,一直运算到输出层为止

反向传播(Back Propagation):利用损失函数ERROR,从后往前,结合梯度下降算法,一次求各个参数的偏导数

3.梯度下降优化方法

梯度下降优化算法中,可能碰到以下情况:

​ 1.碰到平缓区域,梯度值较小,参数优化变慢

​ 2.碰到’‘鞍点’',梯度为0,参数无法优化

​ 3.碰到局部最小值,参数不是最优

对于以下问题,出现一些梯度下降算法的优化方法,例如: Monmentum,AdaGrad,RMSprop,Adqam等.

在这里插入图片描述

1.指数加权平均

指数移动加权平均则是参考各数值 ,并且各数值权重都不同,距离越远的数字对平均计算贡献越小,距离越近则对平均数的计算贡献越大.

计算公式为:

S t = { Y 1 , t = 0 β ∗ S t − 1 + ( 1 − β ) ∗ Y t t>0 S_t = \begin{cases} Y_1, & \text t =0 \\ β*S_{t-1} + (1-β)*Y_t & \text{t>0} \end{cases} St={Y1,βSt1+(1β)Ytt=0t>0

St表示指数加权平均值

Yt表示t时刻的值

β 调节权重系数,该值越大平均数越平缓

2.动量算法Momentum:

梯度计算公式:Dt = β * St-1 + (1- β) * Wt

梯度更新公式为:

St-1 表示历史梯度移动加权平均值

Wt 表示当前时刻的梯度值

Dt 为当前时刻的指数加权平均梯度值

β 为权重系数

假设:权重 β 为 0.9,例如:

  • 第一次梯度值:D1 = S1 = W1
  • 第二次梯度值:D2=S2 = 0.9 * S1 + W2 * 0.1
  • 第三次梯度值:D3=S3 = 0.9 * S2 + W3 * 0.1
  • 第四次梯度值:D4=S4 = 0.9 * S3 + W4 * 0.1

梯度下公式中的梯度计算,不在是当前时刻的t的梯度值,而是历史梯度值而历史梯度值的指数移动加权平均值,公式修改为:
W i j n e w = W i j o i d − α D t W_{ij}^{new} = W_{ij}^{oid} - αD_t Wijnew=WijoidαDt

Monmentum 优化方法是如何一定程度上克服 “平缓”、”鞍点” 的问题呢?

在这里插入图片描述

当处于鞍点位置时,由于当前的梯度为 0,参数无法更新。但是 Momentum 动量梯度下降算法已经在先前积累了一些梯度值,很有可能使得跨过鞍点

由于 mini-batch 普通的梯度下降算法,每次选取少数的样本梯度确定前进方向,可能会出现震荡,使得训练时间变长。Momentum 使用移动加权平均,平滑了梯度的变化,使得前进方向更加平缓,有利于加快训练过程。

import torch
import matplotlib.pyplot as plt

def test03():
    # 1 初始化权重参数
    w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)
    y = ((w ** 2) / 2.0).sum()
    # 2 实例化优化方法,SGD指定参数beta=0.9
    optimizer = torch.optim.SGD([w], lr=0.01, momentum=0.9)
    # 3 第一次更新计算梯度,并对参数进行更新
    optimizer.zero_grad()
    y.backward()
    optimizer.step()
    print('第1次: 梯度w.grad: %f,更新后的权重:%f' % (w.grad.numpy(), w.detach().numpy()))
    # 4 第2次更新 计算梯度,并对参数进行更新
    # 使用更新后的参数机选输出结果
    y = ((w ** 2) / 2.0).sum()
    optimizer.zero_grad()
    y.backward()
    optimizer.step()
    print('第2次: 梯度w.grad: %f, 更新后的权重:%f' % (w.grad.numpy(), w.detach().numpy())

3.AdaGrad:通过对不同的参数分量使用不同的学习率,AdaGrad学习率总体会逐渐减小

计算步骤如下:

import torch
import matplotlib.pyplot as plt

def test04():
    # 1 初始化权重参数
    w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)
    y = ((w ** 2) / 2.0).sum()
    # 2 实例化优化方法:adagrad优化方法
    optimizer = torch.optim.Adagrad([w], lr=0.01)
    # 3 第1次更新 计算梯度,并对参数进行更新
    optimizer.zero_grad()
    y.backward()
    optimizer.step()
    print('第1次: 梯度w.grad: %f, 更新后的权重:%f' % (w.grad.numpy(), w.detach().numpy()))
    # 4 第2次更新 计算梯度,并对参数进行更新
    # 使用更新后的参数机选输出结果
    y = ((w ** 2) / 2.0).sum()
    optimizer.zero_grad()
    y.backward()
    optimizer.step()
    print('第2次: 梯度w.grad: %f, 更新后的权重:%f' % (w.grad.numpy(), w.detach().numpy()))

1.初始化学习率 α、初始化参数 θ、小常数 σ = 1e-6(表示为10的-6次方)

2.初始化梯度累积变量 s = 0

3.从训练集中采样 m 个样本的小批量,计算梯度 g

4.累积平方梯度 s = s + g ⊙ g,⊙ 表示各个分量相乘

学习率计算α的计算公式为:
α = α s + σ α = \frac{α}{\sqrt{s} + σ} α=s +σα
参数更新公式为:
w = w − α s + σ w = w - \frac{α}{\sqrt{s} + σ} w=ws +σα

:AdaGrad缺点是可能使得学习率过早,过量的降低,导致模型 训练到后期学习率太小,难以找到最优解.

4.RMSProp

RMSProp优化算法是对AdaGrad的优化,使用指数移动加权平均梯度替换历史梯度的平方和,计算如下:

# alpha=0.9 初始化β权重系数
"""
初始化学习率 α、初始化参数 θ、小常数 σ = 1e-6

初始化参数 θ

初始化梯度累计变量 s

从训练集中采样 m 个样本的小批量,计算梯度 g

使用指数移动平均累积历史梯度,
"""

公式如下:

s = β ∗ s + ( 1 − β ) g ⊙ g ( ⊙ 表示各个分量相乘 ) s = β*s + (1-β)g⊙g (⊙ 表示各个分量相乘) s=βs+(1β)gg(表示各个分量相乘)
学习率计算公式为:
α = α s + σ α = \frac{α}{\sqrt{s} + σ} α=s +σα
参数更新公式为:
w = w − α s + σ . g w = w - \frac{α}{\sqrt{s} + σ}.g w=ws +σα.g

import torch
import matplotlib.pyplot as plt

def test05():
    # 1 初始化权重参数
    w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)
    y = ((w ** 2) / 2.0).sum()
    # 2 实例化优化方法:RMSprop算法,其中alpha对应这beta
    optimizer = torch.optim.RMSprop([w], lr=0.01, alpha=0.9)
    # 3 第1次更新 计算梯度,并对参数进行更新
    optimizer.zero_grad()
    y.backward()
    optimizer.step()
    print('第1次: 梯度w.grad: %f, 更新后的权重:%f' % (w.grad.numpy(), w.detach().numpy()))
    # 4 第2次更新 计算梯度,并对参数进行更新
    # 使用更新后的参数机选输出结果
    y = ((w ** 2) / 2.0).sum()
    optimizer.zero_grad()
    y.backward()
    optimizer.step()
    print('第2次: 梯度w.grad: %f, 更新后的权重:%f' % (w.grad.numpy(), w.detach().numpy()))

5.Adam:使用动量和RMSProp来动态调整每个参数的学习率

  • Momentum使用指数加权平均计算当前梯度值
  • AdaGrad , RMSProp 使用自适应的学习率
  • Adam优化算法将Momentum 和RMSProp算法结合一起
  • 修正梯度:使用梯度的指数加权平均
  • 修正学习率:使用梯度平方的指数加权平均
# 2 实例化优化方法:Adam算法,其中betas是指数加权的系数
optimizer = torch.optim.Adam([w], lr=0.01, betas=[0.9, 0.99])
4.学习率衰减方法

1.等间隔学习率衰减

学习率衰减方法-等间隔学习率衰减

​ 如图所示

在这里插入图片描述

def test_StepLR():
    # 0.参数初始化
    LR = 0.1  # 设置学习率初始化值为0.1
    iteration = 10
    max_epoch = 200
    # 1 初始化参数
    y_true = torch.tensor([0])
    x = torch.tensor([1.0])
    w = torch.tensor([1.0], requires_grad=True)
    # 2.优化器
    optimizer = optim.SGD([w], lr=LR, momentum=0.9)
    # 3.设置学习率下降策略
    scheduler_lr = optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.5)
    # 4.获取学习率的值和当前的epoch
    lr_list, epoch_list = list(), list()

    for epoch in range(max_epoch):
        lr_list.append(scheduler_lr.get_last_lr()) # 获取当前lr
        epoch_list.append(epoch) # 获取当前的epoch
        for i in range(iteration):  # 遍历每一个batch数据
            loss = ((w*x-y_true)**2)/2.0 # 目标函数
            optimizer.zero_grad()
            # 反向传播
            loss.backward()
            optimizer.step()
        # 更新下一个epoch的学习率
        scheduler_lr.step()
    # 5.绘制学习率变化的曲线
    plt.plot(epoch_list, lr_list, label="Step LR Scheduler")
    plt.xlabel("Epoch")
    plt.ylabel("Learning rate")
    plt.legend()
    plt.show()

2.指定间隔学习率衰减

学习率优化方法-指定间隔学习率衰减

​ 如图所示

在这里插入图片描述

def test_MultiStepLR():
    torch.manual_seed(1)
    LR = 0.1
    iteration = 10
    max_epoch = 200
    weights = torch.randn((1), requires_grad=True)
    target = torch.zeros((1))
    print('weights--->', weights, 'target--->', target)
    optimizer = optim.SGD([weights], lr=LR, momentum=0.9)
    # 设定调整时刻数
    milestones = [50, 125, 160]
    # 设置学习率下降策略
    scheduler_lr = optim.lr_scheduler.MultiStepLR(optimizer, milestones=milestones, gamma=0.5)
    lr_list, epoch_list = list(), list()

    for epoch in range(max_epoch):
        lr_list.append(scheduler_lr.get_last_lr())
        epoch_list.append(epoch)
        for i in range(iteration):
            loss = torch.pow((weights - target), 2)
            optimizer.zero_grad()
            # 反向传播
            loss.backward()
            # 参数更新
            optimizer.step()
        # 更新下一个epoch的学习率
        scheduler_lr.step()
    plt.plot(epoch_list, lr_list, label="Multi Step LR Scheduler\nmilestones:{}".format(milestones))
    plt.xlabel("Epoch")
    plt.ylabel("Learning rate")
    plt.legend()
    plt.show()

3.按指数学习率衰减

学习率优化方法-按指数学习率衰减

​ 如图所示

在这里插入图片描述

def test_ExponentialLR():
    # 0.参数初始化
    LR = 0.1  # 设置学习率初始化值为0.1
    iteration = 10
    max_epoch = 200
    # 1 初始化参数
    y_true = torch.tensor([0])
    x = torch.tensor([1.0])
    w = torch.tensor([1.0], requires_grad=True)
    # 2.优化器
    optimizer = optim.SGD([w], lr=LR, momentum=0.9)
    # 3.设置学习率下降策略
    gamma = 0.95
    scheduler_lr = optim.lr_scheduler.ExponentialLR(optimizer, gamma=gamma)
    # 4.获取学习率的值和当前的epoch
    lr_list, epoch_list = list(), list()

    for epoch in range(max_epoch):
        lr_list.append(scheduler_lr.get_last_lr())
        epoch_list.append(epoch)
        for i in range(iteration):  # 遍历每一个batch数据
            loss = ((w * x - y_true) ** 2) / 2.0
            optimizer.zero_grad()
            # 反向传播
            loss.backward()
            optimizer.step()
        # 更新下一个epoch的学习率
        scheduler_lr.step()
    # 5.绘制学习率变化的曲线
    plt.plot(epoch_list, lr_list, label="Multi Step LR Scheduler")
    plt.xlabel("Epoch")
    plt.ylabel("Learning rate")
    plt.legend()
    plt.show()
3.正则化方法

正则化作用:防止神经网络表示过拟合

Dropout(随机失活)

在神经网络中模型参数较多,在数据不足的情况下,容易过拟合,**Dropout(随机失活)**是一个简单有效的正则化方法.

在这里插入图片描述

在训练过程中,Dropout的实现是让神经元 以超参数p的概率停止工作或者 激活被置为0,未被置为0的进行缩放,缩放比例为1/(1-p)

在测试过程中,随机失活不起作用

import torch
import torch.nn as nn

def test():
    # 初始化随机失活层
    dropout = nn.Dropout(p=0.4)
    # 初始化输入数据:表示某一层的weight信息
    inputs = torch.randint(0, 10, size=[1, 4]).float()
    layer = nn.Linear(4,5)
    y = layer(inputs)
    print("未失活FC层的输出结果:\n", y)

    y =  dropout(y)
    print("失活后FC层的输出结果:\n", y)
    
# 上述代码将 Dropout 层的概率 p 设置为 0.4,此时经过 Dropout 层计算的张量中就出现了很多 0 , 未变为0的按照(1/(1-0.4))进行处理。
;