神经网络基础

一、神经网络

(1)人工神经网络

        人工神经网络(ANN),简称神经网络(NN),是一种模仿生物神经网络结构和功能的计算模型。

神经网络:

        神经网络中信息只向一个方向移动,即从输入节点向前移动,通过隐藏节点,再向输出节点移动。

神经网络的构成:

        输入层:即输入x的那一层

        隐藏层:即输入层和输出层之间的都是隐藏层

        输出层:即输入y的那一层

特点:

        1.同一层神经元之间没有连接

        2.第N层的每个神经元和第N-1层的所有神经元相连(full connected),这就是全连接神经网络。

        3.第N-1层神经元的输出就是第N层神经元的输入

        4.每一个连接都有一个权重值(w系数和b系数)

深度学习和机器学习的关系:

        深度学习是机器学习的一种特殊方法,机器学习 = 传统机器学习(有特征工程的操作)+ 深度学习(无特征工程的操作)

(2)激活函数(重点) 

        激活函数用于对每层的输出数据进行变换,进而为整个网络注入了非线性因素。此时,神经网络就可以拟合各种曲线。

        1.没有引入非线性因素的网络等价于使用一个线性模型来拟合。

        2.通过给网络输出增加激活函数,实现引入非线性因素,使得网络模型可以更加的逼近任意函数,提升网络模型对复杂问题的拟合能力。

神经网络演示

1.sigmoid激活函数

        

import torch
import matplotlib.pyplot as plt
# 创建画布和坐标轴
_, axes = plt.subplots(1, 2)
# 函数图像
x = torch.linspace(-20, 20, 1000)
# 输入值x通过sigmoid函数转换成激活值y
y = torch.sigmoid(x) 
axes[0].plot(x, y)
axes[0].grid() 
axes[0].set_title('Sigmoid 函数图像')
# 导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.sigmoid(x).sum().backward()
# x.detach():输入值x的数值
# x.grad:计算梯度,求导
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('Sigmoid 导数图像')
plt.show()
  • 原函数值域范围:[0,1]
  • 导数值域范围:[0,0.25]
  • 有效区间:[-6,6]有明显的差异、[-3,3]有比较好的效果
  • 适用类型:二分类 
  • 导数图像分析:
  •         1.当输入<-6或者>6的时候,sigmoid激活函数图像的导数接近为0,此时网络模型的参数将更新的非常慢,或者无法更新
  •         2.一般来说,sigmoid网络模型在五层之内就会产生梯度消失的现象

2.tanh激活函数 

# 创建画布和坐标轴
_, axes = plt.subplots(1, 2)
# 函数图像
x = torch.linspace(-20, 20, 1000)
y = torch.tanh(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('Tanh 函数图像')
# 导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.tanh(x).sum().backward()
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('Tanh 导数图像')
plt.show()
  • 原函数值域范围:[-1,1]
  • 导数值域范围:[0,0.25]
  • 中心对称(收敛的速度非常的快)
  • tanh函数与sigmoid函数的比较:
  • 1.tanh函数是以0为中心的,梯度相对于sigmoid函数大,收敛的速度也比sigmoid函数的大。
  • 2.和sigmoid函数一样,tanh两侧的导数也为0,同样会造成梯度的消失。
  • 3.可以在隐藏层使用tanh函数,在输出层使用sigmoid函数。

3.ReLU激活函数 

# 创建画布和坐标轴
_, axes = plt.subplots(1, 2)
# 函数图像
x = torch.linspace(-20, 20, 1000)
y = torch.relu(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('ReLU 函数图像')
# 导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.relu(x).sum().backward()
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('ReLU 导数图像')
plt.show()
  • ReLU函数将小于0的值映射为0,而大于0的值则保持不变,这种激活函数的运算更为简单。
  • 当x<0时,ReLU导数为0,而当x>0时,则不存在饱和问题。所以,ReLU 能够在x>0时保持梯 度不衰减,从而缓解梯度消失问题。然而,随着训练的推进,部分输入会落入小于0区域,导致对应权重无法更新。这种现象被称为“神经元死亡” 。
  • ReLU函数与sigmoid函数相比
    采用sigmoid函数,计算量大(指数运算),反向传播求误差梯度时,计算量相对大,而采用 Relu激活函数,整个过程的计算量节省很多。 sigmoid函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。 Relu会使一部分神经元的输出为0,这样就造成了 网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

4.SoftMax激活函数 

scores = torch.tensor([0.2, 0.02, 0.15, 0.15, 1.3, 0.5, 0.06, 1.1, 0.05, 3.75])
# dim = 0,按行计算
probabilities = torch.softmax(scores, dim=0)
print(probabilities)

#输出结果:
#tensor([0.0212, 0.0177, 0.0202, 0.0202, 0.0638, 0.0287, 0.0185, 0.0522, 0.0183,0.7392])
Softmax 就是将网络输出的 logits 通过 softmax 函数,就映射成为(0,1)的值,而 这些值的累和 为1 (满足概率的性质),那么我们将它理解成概率, 选取概率最大(也就是值对应最大的)节 ,作为我们的 预测目标类别

5.其他激活函数 

总结

 对于隐藏层:

  1. 优先选择ReLU函数
  2. 如果ReLU函数的效果不好,那么就尝试其他的激活函数,如Leaky ReLU等
  3. 如果你使用了ReLU,需要注意一下Dead ReLU问题,避免出现了大的梯度从而导致过多的神经元死亡。
  4. 少用sigmoid激活函数,可以尝试使用tanh激活函数

对于输出层:

  1. 二分类问题选择sigmoid激活函数
  2. 多分类问题选择softmax激活函数
  3. 回归问题选择identity激活函数

激活函数的作用:

        向神经网络添加非线性的元素

(3)参数初始化 

均匀分布初始化

        权重参数初始化从区间均匀随机取值。即在(-1/\sqrt{}d,1/\sqrt{}d)均匀分布中生存当前神经元的权重,其中d为每个神经元的输入数量。

正态分布初始化

        随机初始化从均值为0,标准差是1的高斯分布(标准正态分布)中,使用一些很小的值对参数w进行优化处理。

全0初始化

        将神经网络中的所有权重参数初始化为0

全1初始化

        将神经网络中的所有权重参数初始化为1

固定值初始化

        将神经网络中的所有权重参数初始化为某个固定值

kaiming初始化

xavier初始化

kaiming初始化和xavier初始化(重点) 

import torch
import torch.nn.functional as F
import torch.nn as nn
# 1. 均匀分布随机初始化
def test01():
linear = nn.Linear(5, 3)
# 从0-1均匀分布产生参数
nn.init.uniform_(linear.weight)
print(linear.weight.data)
# 2.固定初始化
def test02():
linear = nn.Linear(5, 3)
nn.init.constant_(linear.weight, 5)
print(linear.weight.data)
# 3. 全0初始化
def test03():
linear = nn.Linear(5, 3)
nn.init.zeros_(linear.weight)
print(linear.weight.data)
# 4. 全1初始化
def test04():
linear = nn.Linear(5, 3)
nn.init.ones_(linear.weight)
print(linear.weight.data)
# 5. 正态分布随机初始化
def test05():
linear = nn.Linear(5, 3)
nn.init.normal_(linear.weight, mean=0, std=1)
print(linear.weight.data)
# 6. kaiming 初始化
def test06():
# kaiming 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_normal_(linear.weight)
print(linear.weight.data)
# kaiming 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_uniform_(linear.weight)
print(linear.weight.data)
# 7. xavier 初始化
def test07():
# xavier 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_normal_(linear.weight)
print(linear.weight.data)
# xavier 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_uniform_(linear.weight)
print(linear.weight.data)

总结 

        一般我们在使用Pytorch构建网络模型的时候,每个网络层的参数都有默认的初始化方法,优先会选择kaiming的初始化方法,xavier初始化方法

(4)神经网络的搭建方法

  • 定义继承来自nn.Module的模型类
  • 在__init__方法中定义网络中的层结构
  • 在forward()方法中定义数据的传输方式(激活函数)
  • 网格参数量的统计方法:统计每一层的权重w和偏置b的数量 

 (5)神经网络的优缺点

优点:

  1. 精度高、性能优于其他的机器学习算法,甚至在某些领域超过了人类
  2. 可以近似任意的非线性函数随之计算机硬件的发展
  3. 有大量的框架和库可以调用

缺点:

  1. 黑箱,很难解释模型是怎么工作的
  2. 训练时间长,需要大量的计算资源
  3. 网路结构复杂,需要调整参数
  4. 部分数据集上表现不佳,容易发生过拟合

二、损失函数 

        概念:损失函数就是用来衡量模型参数的质量的函数,比较的是网络模型的预测值与真实值之间的误差

        别名:论文可能提到的不一样,损失函数(loss function)、代价函数(cost function)、目标函数(objective function)、误差函数(error function)

(1)多任务的损失函数 

        在多任务任务中通常使用softmax()将逻辑值转换成概率值的形式,所以多分类的交叉熵损失也叫做softmax损失。

  1. y是样本x属于某一个类别的真实概率
  2. 而f(x)是样本属于某一类别的预测分数
  3. S是softmax()激活函数,将属于某一类别的预测分数转换成概率
  4. L是用来衡量真实值y和预测值f(x)之间差异性的损失结果

API:多分类损失函数在pytroch中使用nn.CrossEntropyLoss()实现

# 分类损失函数:交叉熵损失使用nn.CrossEntropyLoss()实现。
# nn.CrossEntropyLoss()=softmax + 损失计算
def test():
    # 设置真实值: 可以是热编码后的结果也可以不进行热编码  
    # 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()
    # 计算损失结果
    my_loss = loss(y_pred, y_true).numpy()
    print('loss:', my_loss)

 (2)二分类损失函数

        在处理二分类任务时,我们不再使用softmax()激活函数,而是使用sigmoid()激活函数,损失函数也会进行相应的调整

  1. y是样本x属于某一个类别的真实数据
  2. \widehat{y}是样本属于某一类别的预测数据
  3. L是用来衡量真实值y与预测值\widehat{y}之间差异性的损失结果

API:在pytorch中实现时使用nn.BCELoss()

def test2():
    # 1 设置真实值和预测值
    # 预测值是sigmoid输出的结果
    y_pred = torch.tensor([0.6901, 0.5459, 0.2469], requires_grad=True)
    y_true = torch.tensor([0, 1, 0], dtype=torch.float32)
    # 2 实例化二分类交叉熵损失
    criterion = nn.BCELoss()
    # 3 计算损失
    my_loss = criterion(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

 (3)回归任务损失函数-MAE损失函数

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

特点:

  1. 由于L1 Loss具有稀疏性,为了惩罚较大的值,因此常常将其作为正则项添加到其他loss中作为约束。
  2. L1 Loss的最大问题就是梯度在零点不平滑,导致会跳过极小值。

API:在pytorch中使用nn.L1Loss()实现

# 计算算inputs与target之差的绝对值def test3():
    # 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 实例MAE损失对象
    loss = nn.L1Loss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

 (4)回归任务损失函数-MSE损失函数

        Mean Squared Loss/ Quadratic Loss(MSE loss)也被称为L2 loss,或欧氏距离,它以误差的平方和的均值作为距离

        

特点:

  1. L2 Loss也是常常作为正则项
  2. 当预测值与目标值差距很大的时候,容易梯度爆炸

API:在pytorch中使用nn.MSELoss()实现

def test4():
    # 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('myloss:', my_loss)

 (5)回归任务损失函数-smooth L1损失函数

smooth L1就是光滑之后的L1

其中:x = f(x)- y为真实值与预测值之间的差值

从上图可以看出,这是一个分段函数:

  1. 在[-1,1]之间实际上就是L2损失,这样解决了L1的不光滑问题
  2. 在[-1,1]区间外,实际就是L1损失,这样就解决了梯度爆炸的问题 

API:在pytorch中使用nn.smoothL1Loss()实现

def test5():
    # 1 设置真实值和预测值
    y_true = torch.tensor([0, 3])
    y_pred = torch.tensor ([0.6, 0.4], requires_grad=True)
    # 2 实例smmothL1损失对象
    loss = nn.SmoothL1Loss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

 总结

分类任务的损失函数

  1. 多分类的交叉熵损失函数:nn.softmax()        将逻辑值转换成概率值
  2. 二分类的交叉熵损失函数:nn.sigmoid()

回归任务的损失函数

  1. MAE:nn.L1Loss()        绝对值误差的均值        零点不平滑
  2. MSE:nn.MSELoss()        均方误差的均值        容易梯度爆炸
  3. smoothL1:nn.smoothL1Loss()        结合了MAE和MSE,光滑的L1

 三、网络的优化方法

(1)梯度下降算法

概念:梯度下降法是一种寻找损失函数最小化的网络优化方法

数学角度分析:梯度的方向就是函数增长速度最快的方向,那么梯度的反方向就是函数减少最快的方向。

学习率如果太小,那么每次训练之后得到的效果都太小,增大训练的时间成本。

学习率如果太大,那么就有可能直接跳过最优解,进入无限的训练当中去(振荡)。

解决办法:学习率也要随着训练的进行不断地更新。

(2)网络训练过程中的epoch,batch,iter

进行模型训练时的三个基础的概念:

  • Epoch:使用全部数据对模型进行完整训练
  • Batch_size:使用训练集的小部分样本对模型权重进行以此反向传播的参数更新,每次训练每批次样本数量。
  • Iteration:使用一个Batch数据对一个模型进行一次参数更新的过程

在深度学习中,梯度下降的几种方式的根本区别在于Batch Size不同

(3)反向传播的算法过程(了解)

了解反向传播之前我们要先了解前向传播的过程

前向传播:指的就是数据在输入的神经网络中,逐层向前传输,一直到运算到输出层为止(输入层-->隐藏层-->输出层)

   反向传播(Back Propagation):利用损失函数ERROR,从后往前,结合梯度下降算法,依次求各个参数的偏导,并且进行参数更新的过程。

反向传播 

反向传播对神经网络中的各个节点的权重进行更新。

以下用一个简单的神经网络举例:激活函数为sigmoid()

import torch
from torch import 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)
        # 初始化神经网络参数
        self.linear1.weight.data = torch.tensor([[0.15, 0.20], [0.25, 0.30]])
        self.linear2.weight.data = torch.tensor([[0.40, 0.45], [0.50, 0.55]])
        self.linear1.bias.data = torch.tensor([0.35, 0.35])
        self.linear2.bias.data = torch.tensor([0.60, 0.60])
    # 前向传播方法
    def forward(self, x):
        # 数据经过第一层隐藏层
        x = self.linear1(x)
        # 计算第一层激活值
        x = torch.sigmoid(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)
    print("output-->", output)
    loss = torch.sum((output - target) ** 2) / 2    # 计算误差
    print("loss-->", loss)
    # 优化方法和反向传播算法
    optimizer = optim.SGD(model.parameters(), lr=0.5)
    optimizer.zero_grad()
    loss.backward()
    print("w1,w2,w3,w4-->", model.linear1.weight.grad.data)
    print("w5,w6,w7,w8-->", model.linear2.weight.grad.data)
    optimizer.step()
    # 打印神经网络参数
    print(model.state_dict())



# output--> tensor([[0.7514, 0.7729]], grad_fn=<SigmoidBackward0>)
# loss--> tensor(0.2984, grad_fn=<DivBackward0>)
# w1,w2,w3,w4--> tensor([[0.0004, 0.0009],
#        [0.0005, 0.0010]])
# w5,w6,w7,w8--> tensor([[ 0.0822,  0.0827],
#        [-0.0226, -0.0227]])
# OrderedDict([('linear1.weight', tensor([[0.1498, 0.1996],
#        [0.2498, 0.2995]])), ('linear1.bias', tensor([0.3456, 0.3450])), # ## 
# ('linear2.weight', tensor([[0.3589, 0.4087],
#        [0.5113, 0.5614]])), ('linear2.bias', tensor([0.5308, 0.6190]))])


总结 

前向传播:

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

反向传播(Back Propagation):

        利用损失函数ERROR,从后往前,结合梯度下降算法,依次求各个参数的偏导,并进行参数更新的过程。

(4)梯度下降的优化方法

梯度下降优化算法中,可能会遇到的问题:

  1. 碰到平缓的区域,梯度值较小,参数优化比较慢
  2. 碰到“鞍点”,梯度为0,参数无法优化
  3. 碰到局部最小值,参数不是最优

 1.梯度下降的优化方法-指数加权平均

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

2.梯度下降的优化方法-动量算法(Momentum)

def test01():
    # 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 第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次: 梯度w.grad: 1.0000000000, 更新后的权重:0.9900000095
# 第2次: 梯度w.grad: 0.9900000095, 更新后的权重:0.9711000323

3.梯度下降的优化方法-adaGrad 

缺点:

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

def test02():
    # 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次: 梯度w.grad: 1.000000, 更新后的权重:0.990000 
# 第2次: 梯度w.grad: 0.990000, 更新后的权重:0.982965

4.梯度下降的优化方法-RMSProp 

def test03():
    # 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()))



# 第1次: 梯度w.grad: 1.000000, 更新后的权重:0.968377 
# 第2次: 梯度w.grad: 0.968377, 更新后的权重:0.945788

5.梯度下降的优化方法-Adam(重要使用) 

Momentum使用指数加权平均计算当前的梯度值

AdaGrad、RMSProp使用自适应的学习率

Adam优化算法(Adaptive Moment Estimation,自适应矩估计)将Momentum和RMSProp算法结合在一起

  1. 修正梯度:使用梯度的指数加权平均
  2. 修正学习率:使用梯度平方的指数加权平均
def test04():
    # 1 初始化权重参数
    w = torch.tensor([1.0], requires_grad=True)
    y = ((w ** 2) / 2.0).sum()
    # 2 实例化优化方法:Adam算法,其中betas是指数加权的系数
    optimizer = torch.optim.Adam([w], lr=0.01,betas=[0.9,0.99])
    # 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次: 梯度w.grad: 1.000000, 更新后的权重:0.990000 
# 第2次: 梯度w.grad: 0.990000, 更新后的权重:0.980003

(5)知道学习率优化策略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值