李沐-->深度学习计算
文章目录
- 前言
- 一、层和块
- 1. 层和块
- 1.1 自定义块
- 1.2. 顺序块
- 1.3. 在前向传播函数中执行代码
- 二、参数管理
- 1.如何访问参数
- 1.1.访问某一个具体的参数
- 1.2.一次性访问所有参数
- 1.3.从嵌套块收集参数
- 2.参数初始化
- 2.1.内置初始化:
- 2.2.自定义初始化
- 2.3.参数绑定
- 3.延后初始化
- 4.自定义层
- 4.1.构造一个没有任何参数的自定义层
- 4.2.构造一个带参数的层
- 5.读写文件
- 5.1 加载和保存张量
- 5.2 加载和保存模型参数
- 6. GPU
- 6.1 如何使用GPU
- 6.2 在GPU上创建张量
- 6.3 神经网络与GPU
前言
提示:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、层和块
对于多层感知机而言,整个模型及其组成层的架构:整个模型接受原始输入(特征),生成输出(预测),并包含一些参数(所有组成层的参数集合)。同样,每个单独的层接收输入(由前一层提供),生成输出(到下一层的输入),并且具有一组可调参数,这些参数根据从下一层反向传播的信号进行更新。
1. 层和块
块(block):
可以描述单个层、由多个层组成的组件或整个模型本身。
使用块抽象的好处是可以将一些块组合成更大的组件,这一过程通常是递归的,即通过定义代码来按需生成任意复杂的块(可以通过简洁的代码实现复杂的神经网络)
从编程的角度看:块是由类来表示的。它的任何子类都必须定义一个将其输入转换为输出的前向传播函数,并且必须存储任何必需的参数(但有些块不需要任何参数)。最后计算梯度,块必须具有反向传播函数(可由后端实现,不需考虑)。
1.1 自定义块
这里简单说一下每个块必须提供的基本功能:
- 将输入数据作为其前向传播函数的参数。
- 通过前向传播函数来生成输出
- 计算其输出关于输入的梯度,可通过反向传播函数进行访问。(这通常会自动发生)
- 存储和访问前向传播计算所需的参数。
- 根据需要初始化模型参数。
class MLP(nn.Module):# 用模型参数声明层。这里,我们声明两个全连接的层def __init__(self):# 调用MLP的父类Module的构造函数来执行必要的初始化。# 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)super().__init__()self.hidden = nn.Linear(20, 256) # 隐藏层self.out = nn.Linear(256, 10) # 输出层# 定义模型的前向传播,即如何根据输入X返回所需的模型输出def forward(self, X):# 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。return self.out(F.relu(self.hidden(X)))
首先我们定义的__ init__函数通过super().__ init__()调用父类的__ init__函数,省去了重复编写模板代码的步骤。然后我们实例化两个全连接层:self.hidden–隐藏层和self.out–输出层。注意除非我们实现一个新的运算符,否则不必担心反向传播函数或参数初始化,系统将自动生成这些。
然后我们看forward函数,它以x作为输入,计算带有激活函数的隐藏表示,并输出其未规范化的输出值。
块的一个主要优点是它的多功能性。 我们可以子类化块以创建层(如全连接层的类)、 整个模型(如上面的MLP类)或具有中等复杂度的各种组件
1.2. 顺序块
构建一个自己的MySequential类,我们只需定义两个关键函数:
- 一种将块逐个追加到列表中的函数
- 一种前向传播函数,用于将输入按追加块的顺序传递给块组成的“链条”。
class MySequential(nn.Module):def __init__(self, *args):super().__init__()for idx, module in enumerate(args):# 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员# 变量_modules中。_module的类型是OrderedDictself._modules[str(idx)] = moduledef forward(self, X):# OrderedDict保证了按照成员添加的顺序遍历它们for block in self._modules.values():X = block(X)return X
__ init__ 函数将每个模块逐个添加到有序字典_modules中。(每个Module都有一个_modules属性:在模块初始化的过程中,系统知道在_modules字典中查找需要初始化参数的子块)
forward函数被调用是,每个添加的块都按照它们被添加的顺序执行。
1.3. 在前向传播函数中执行代码
我们所需要的所有架构并不都是简单的顺序架构,当需要更强的灵活性时,我们需要定义自己的块(例如,我们希望在前向传播函数中执行Python的控制流,或是执行任意的数学运算)
我们希望在网络中合并既不是上一层结果,也不是可更新参数的项,我们称之为常数参数。
例如 f ( x , w ) = c ⋅ w ⊤ x f(\mathbf{x},\mathbf{w}) = c \cdot \mathbf{w}^\top \mathbf{x} f(x,w)=c⋅w⊤x,其中x是输入,w是参数,而c是某个在优化过程中没有更新的指定常量。
class FixedHiddenMLP(nn.Module):def __init__(self):super().__init__()# 不计算梯度的随机权重参数。因此其在训练期间保持不变self.rand_weight = torch.rand((20, 20), requires_grad=False)self.linear = nn.Linear(20, 20)def forward(self, X):X = self.linear(X)# 使用创建的常量参数以及relu和mm函数X = F.relu(torch.mm(X, self.rand_weight) + 1)# 复用全连接层。这相当于两个全连接层共享参数X = self.linear(X)# 控制流while X.abs().sum() > 1:X /= 2return X.sum()
在这个FixedHiddenMLP模型中,我们实现了一个隐藏层,它的权重在实例化时被随机初始化,之后为常量,这个权重不是一个模型参数,因此它永远不会被反向传播更新。在前向传播时,在控制流里面可以写入一些任意的代码来集成到神经网络计算的流程中。
当然我们也可以搭配各种组合快的方法:
class NestMLP(nn.Module):def __init__(self):super().__init__()self.net = nn.Sequential(nn.Linear(20, 64), nn.ReLU(),nn.Linear(64, 32), nn.ReLU())self.linear = nn.Linear(32, 16)def forward(self, X):return self.linear(self.net(X))chimera = nn.Sequential(NestMLP(), nn.Linear(16, 20), FixedHiddenMLP())
chimera(X)
二、参数管理
1.如何访问参数
首先我们定义了一个简单的网络net(线性层–>激活函数–>线性层),
import torch
from torch import nnnet = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
net(X)
现在我们把每一层里面的权重拿出来,在net中它其实就是一个Sequential,可以看作是类似于python里的list的一个东西,所以在net中,nn.Linear(4, 8)是net[0],nn.ReLU()是net[1], nn.Linear(8, 1)是net[2]。
state_dict()就是当前的状态,也就是当前层权重和偏置的此时的值。
print(net[2].state_dict())
输出:
OrderedDict([(‘weight’, tensor([[ 0.0251, -0.2952, -0.1204, 0.3436, -0.3450, -0.0372, 0.0462, 0.2307]])), (‘bias’, tensor([0.2871]))])
1.1.访问某一个具体的参数
print(type(net[2].bias))
print(net[2].bias)
print(net[2].bias.data)
输出:
<class ‘torch.nn.parameter.Parameter’>
Parameter containing:
tensor([0.2871], requires_grad=True)
tensor([0.2871])
net[2].weight.grad == None
输出:
True
1.2.一次性访问所有参数
可通过named_parameters()这个函数可以把所有的参数拿出来
print(*[(name, param.shape) for name, param in net[0].named_parameters()])
print(*[(name, param.shape) for name, param in net.named_parameters()])
(‘weight’, torch.Size([8, 4])) (‘bias’, torch.Size([8]))
(‘0.weight’, torch.Size([8, 4])) (‘0.bias’, torch.Size([8])) (‘2.weight’, torch.Size([1, 8])) (‘2.bias’, torch.Size([1]))
0.weigh、0.bias,相当于这个参数的名字,有了名字之后,我们可以通过名字来访问这个参数。
net.state_dict()['2.bias'].data
输出:
tensor([0.2871])
1.3.从嵌套块收集参数
假设整个网络有嵌套的时候会怎么样?
我们定义两个block
block1就是一个Sequential,包括两个线性层。
block2也是个Sequential,但是其中会插入4个block1在for循环里面,net.add_module(f’block {i}', block1()):其中会给每一个block,给一个名字‘block 0’/‘block 1’/‘block 2’/‘block3’,方便访问。rgnet在外面再套一层Sequential。
def block1():return nn.Sequential(nn.Linear(4, 8), nn.ReLU(),nn.Linear(8, 4), nn.ReLU())def block2():net = nn.Sequential()for i in range(4):# 在这里嵌套net.add_module(f'block {i}', block1())return netrgnet = nn.Sequential(block2(), nn.Linear(4, 1))
rgnet(X)
print(rgnet)
输出:
Sequential(
(0): Sequential(
(block 0): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
(block 1): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
(block 2): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
(block 3): Sequential(
(0): Linear(in_features=4, out_features=8, bias=True)
(1): ReLU()
(2): Linear(in_features=8, out_features=4, bias=True)
(3): ReLU()
)
)
(1): Linear(in_features=4, out_features=1, bias=True)
)
把复杂的网络组和成这样模块化的网络的话,在打印和访问上都有好处。
2.参数初始化
2.1.内置初始化:
来修改我们默认的初始函数来得到新的初始函数。
定义一个正态分布的初始化,m是一个module,若module是一个线性层(全连接层)的话:就对weight做均值为0.方差为1
的一个初始化。bias直接附0。
normal_、zeros_都是在init这个module中,这里面包含了大量的可以用来做初始化的函数。
nn.init.normal_(m.weight, mean=0, std=0.01)中normal_ 的下划线代表的是一个替换函数,就是把m.weight直接替换成我们得到的值。
net.apply(init_normal)中apply就是说对net里面所有的module去调用init_normal这个函数。
def init_normal(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, mean=0, std=0.01)nn.init.zeros_(m.bias)
net.apply(init_normal)
net[0].weight.data[0], net[0].bias.data[0]
输出
(tensor([-0.0145, 0.0053, 0.0055, -0.0044]), tensor(0.))
当然也可以做一些别的事情,比如把weight设置成一个全为1,但实际中并不会这么做。
def init_constant(m):if type(m) == nn.Linear:nn.init.constant_(m.weight, 1)nn.init.zeros_(m.bias)
net.apply(init_constant)
net[0].weight.data[0], net[0].bias.data[0]
输出:
(tensor([1., 1., 1., 1.]), tensor(0.))
对某些块应用不同的初始化方法:
比如我们可以对不同的层apply不同的事情
def init_xavier(m):if type(m) == nn.Linear:nn.init.xavier_uniform_(m.weight)
def init_42(m):if type(m) == nn.Linear:nn.init.constant_(m.weight, 42)net[0].apply(init_xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)
输出:
tensor([-0.4792, 0.4968, 0.6094, 0.3063])
tensor([[42., 42., 42., 42., 42., 42., 42., 42.]])
2.2.自定义初始化
自己定义一个函数my_init,
def my_init(m):if type(m) == nn.Linear:print("Init", *[(name, param.shape)for name, param in m.named_parameters()][0])nn.init.uniform_(m.weight, -10, 10)m.weight.data *= m.weight.data.abs() >= 5 #保留绝对值大于5的那些权重,不是的话就设置成0net.apply(my_init)
net[0].weight[:2]
Init weight torch.Size([8, 4])
Init weight torch.Size([1, 8])
tensor([[-6.9027, 7.6638, -0.0000, -0.0000],
[-0.0000, 5.5632, -6.1899, 0.0000]], grad_fn=< SliceBackward0>)
我们还可以直接设置参数的值
net[0].weight.data[:] += 1
net[0].weight.data[0, 0] = 42
net[0].weight.data[0]
tensor([42.0000, 8.6638, 1.0000, 1.0000]
2.3.参数绑定
我们想要在一些层之间share参数,就是说有两个数据流进来,net中有两个层想要共享这些权重,这时就需要参数绑定。
我们需要先把share的层构造出来,此时参数就会被一起申请下来。然后我们在设置全连接的时候,可以看到我们的第2个隐藏层和第4个隐藏层是share权重的。
# 我们需要给共享层一个名称,以便可以引用它的参数
shared = nn.Linear(8, 8)
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(),shared, nn.ReLU(),shared, nn.ReLU(),nn.Linear(8, 1))
net(X)
# 检查参数是否相同
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# 确保它们实际上是**同一个对象**,而不只是有相同的值
print(net[2].weight.data[0] == net[4].weight.data[0])
tensor([True, True, True, True, True, True, True, True])
tensor([True, True, True, True, True, True, True, True])
3.延后初始化
截止目前我们还不清楚:
- 我们定义了网络架构,但没有指定输入维度
- 我们添加层时没有指定前一层的输出维度。
- 我们在初始化参数时,甚至没有足够的信息来确定模型应该包含多少参数
解决这一问题的方法就是延后初始化,即直到数据第一次通过模型传递时,框架才会动态地推断出每个层的大小。
现在我们编写代码时,也无需知道维度是什么就可以设置参数,这种能力大大简化定义和修改模型任务。
4.自定义层
自定义一个层和自定义一个网络没有本质区别,都需要继承nn.Module。
4.1.构造一个没有任何参数的自定义层
__ init__函数里面什么都没有,也可以不用写__ init__函数,系统会自动帮你加上;同时也需要定义forward函数。和pytorch构造一个自定义的类和自定义的Module是一样的
import torch
import torch.nn.functional as F
from torch import nnclass CenteredLayer(nn.Module):def __init__(self):super().__init__()def forward(self, X):return X - X.mean()
layer = CenteredLayer()
layer(torch.FloatTensor([1, 2, 3, 4, 5]))
输出:
tensor([-2., -1., 0., 1., 2.])
现在我们将层作为组件合并到更复杂的模型中
我们构造一个sequential的类,放入Linear和自定义的CenteredLayer。
net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())
Y = net(torch.rand(4, 8))
Y.mean()
输出:
tensor(0., grad_fn=< MeanBackward0>)
4.2.构造一个带参数的层
我们的参数都是Parameter类的实例,所以我们要访问参数就要调用相应的Parameter类。
现在我们定义一个自己的线性层,in_units表示输入的维度, units表示输出的维度,放在__init__函数中,该函数中还带有两个参数:self.weight、self.bias。
在用这些参数的时候要知道我们是通过 .data来访问的(self.weight.data)。
class MyLinear(nn.Module):def __init__(self, in_units, units):super().__init__()self.weight = nn.Parameter(torch.randn(in_units, units))self.bias = nn.Parameter(torch.randn(units,))def forward(self, X):linear = torch.matmul(X, self.weight.data) + self.bias.datareturn F.relu(linear)
linear = MyLinear(5, 3)
linear.weight
输出:
Parameter containing:
tensor([[-1.4779, -0.6027, -0.2225],
[ 1.1270, -0.6127, -0.2008],
[-2.1864, -1.0548, 0.2558],
[ 0.0225, 0.0553, 0.4876],
[ 0.3558, 1.1427, 1.0245]], requires_grad=True)
使用自定义层直接执行正向传播计算
linear(torch.rand(2, 5))
输出:
tensor([[0.0000, 0.0000, 0.2187],
[0.0000, 0.0000, 0.0000]])
使用自定义层构建模型
net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
net(torch.rand(2, 64))
输出:
tensor([[ 7.4571],
[12.7505]])
5.读写文件
就是说我们已经训练好的东西怎么样存储下来。
5.1 加载和保存张量
首先我们看一下如何存一个矩阵。
torch.save把x存在x-file这个文件中,就会把x在当前目录下存下来。
然后可以用torch.load把它load进来,它返回一个tensor,与x是一样的东西。
import torch
from torch import nn
from torch.nn import functional as Fx = torch.arange(4)
torch.save(x, 'x-file')
x2 = torch.load('x-file')
x2
输出:
tensor([0, 1, 2, 3])
接下来我们看看如何存储一个list,然后把他们读回内存
y = torch.zeros(4)
torch.save([x, y],'x-files')
x2, y2 = torch.load('x-files')
(x2, y2)
输出:
(tensor([0, 1, 2, 3]), tensor([0., 0., 0., 0.]))
也可以写入或读取从字符串映射到张量的字典
mydict = {'x': x, 'y': y}
torch.save(mydict, 'mydict')
mydict2 = torch.load('mydict')
mydict2
输出:
{‘x’: tensor([0, 1, 2, 3]), ‘y’: tensor([0., 0., 0., 0.])}
5.2 加载和保存模型参数
当我们有一个MLP时,该怎么办?
首先我们应该清楚,对于一个神经网络我们要存什么东西,对于pytorch来说没有办法把整个神经网络存下来,所以我们只需要把它的权重存下来就行了,计算那一部分就不存了。
我们定义一个MLP:
class MLP(nn.Module):def __init__(self):super().__init__()self.hidden = nn.Linear(20, 256)self.output = nn.Linear(256, 10)def forward(self, x):return self.output(F.relu(self.hidden(x)))net = MLP()
X = torch.randn(size=(2, 20))
Y = net(X)
然后接下来我们将模型的参数存储在一个叫做 ’mlp.params‘ 的文件中。
我们可以通过 state_dict() 来得到所有的Parameter它的一个字符串到Parameter的一个映射
torch.save(net.state_dict(), 'mlp.params')
然后我们给它load回来,需要把存数据的文件’mlp.params’带走,还要把MLP的定义给带走,因为我们用的时候,需要把MLP给声明出来,调用load_state_dict来把从文件’mlp.params’中读出来的字典放进去,就可以覆盖掉在声明是初始化的参数。
clone = MLP()
clone.load_state_dict(torch.load('mlp.params'))
clone.eval()
输出:
MLP(
(hidden): Linear(in_features=20, out_features=256, bias=True)
(output): Linear(in_features=256, out_features=10, bias=True)
)
可以验证一下:
Y_clone = clone(X)
Y_clone == Y
输出:
tensor([[True, True, True, True, True, True, True, True, True, True],
[True, True, True, True, True, True, True, True, True, True]])
6. GPU
首先要确保在自己电脑有GPU,
在cmd中运行下面的代码
nvidia-smi
得到结果如下图所示:可以看到自己电脑上有几个GPU,GPU的使用率等关于GPU的一些信息。
6.1 如何使用GPU
torch.device(‘cpu’):用cpu的设备
torch.device(‘cuda’):表示用第0个GPU
torch.device(‘cuda:1’):有多个GPU时访问第1个GPU
import torch
from torch import nntorch.device('cpu'), torch.device('cuda'), torch.device('cuda:1')
输出:
(device(type=‘cpu’), device(type=‘cuda’), device(type=‘cuda’, index=1))
可以查询可用GPU的数量:
若返回0,则表示没有GPU
torch.cuda.device_count()
现在我们定义两个函数,这两个函数允许我们在请求的GPU不存在的情况下运行代码:
#尝试把GPU拿出来,如果存在,则返回gpu(i),否则返回cpu()
def try_gpu(i=0): #@saveif torch.cuda.device_count() >= i + 1:return torch.device(f'cuda:{i}')return torch.device('cpu')def try_all_gpus(): #@save"""返回所有可用的GPU,如果没有GPU,则返回[cpu(),]"""devices = [torch.device(f'cuda:{i}') for i in range(torch.cuda.device_count())]return devices if devices else [torch.device('cpu')]try_gpu(), try_gpu(10), try_all_gpus()
输出:
(device(type=‘cuda’, index=0),
device(type=‘cpu’),
[device(type=‘cuda’, index=0), device(type=‘cuda’, index=1)])
6.2 在GPU上创建张量
查询张量所在的设备
默认创建的tensor是在CPU上,可以通过 .device来查看
x = torch.tensor([1, 2, 3])
x.device
输出:
device(type=‘cpu’)
我们可以在创建的时候,指定把该张量放在GPU上:在创建的时候加上device=‘XXX’来指定。
X = torch.ones(2, 3, device=try_gpu())
Y = torch.rand(2, 3, device=try_gpu(1))
X
输出:
tensor([[1., 1., 1.],
[1., 1., 1.]], device=‘cuda:0’)
我们如果要在GPU上计算X+Y的话,就需要保证X和Y都在GPU上,而且必须要在同一个GPU上。
X.cuda(1):就是把X复制到代号为1的GPU上,并赋值给Z。
下列代码可以看到,X的device在0号GPU上,Z的device在1号GPU上。
Z = X.cuda(1)
print(X)
print(Z)
输出:
tensor([[1., 1., 1.],
[1., 1., 1.]], device=‘cuda:0’)
tensor([[1., 1., 1.],
[1., 1., 1.]], device=‘cuda:1’)
此时X和Y都在1号GPU上,现在就可以进行X+Y的运算了。
Y + Z
输出:
tensor([[1.1379, 1.4532, 1.9869],
[1.4779, 1.7426, 1.9622]], device=‘cuda:1’)
假设变量Z已经存在于1号GPU上。 如果我们还是调用Z.cuda(1)会发生什么? 它将返回Z,而不会复制并分配新内存。
Z.cuda(1) is Z
True
6.3 神经网络与GPU
怎样在GPU上做神经网络呢?
首先我们在CPU上创建神经网络,初始化权重。
然后调用 .to这个方法,把神经网络和初始化的权重和输入复制到GPU上。
我们的X也在0号GPU上,所以这个net的前向运算都是在0号GPU上,就可以做运算了
net = nn.Sequential(nn.Linear(3, 1))
net = net.to(device=try_gpu())
net(X)
输出:
tensor([[-0.0132],
[-0.0132]], device=‘cuda:0’, grad_fn=< AddmmBackward0>)
可以确认一下模型的参数存储在同一个GPU上:
net[0].weight.data.device
输出:
device(type=‘cuda’, index=0)
李沐-->深度学习计算相关推荐
- 关于安装李沐深度学习d2l包报错的解决办法(保姆教程)
目录:d2l包安装失败的解决过程 前言 一.李沐提供的安装方式 1. 创建一个新的环境 2. 激活 d2l 环境 3. 安装深度学习框架和d2l软件包 3.1 安装PyTorch的CPU或GPU版本 ...
- Softmax回归及损失函数(李沐深度学习课程、自用)
1 Softmax回归 回归预测连续值,分类预测离散值 分类多个输出,第i个输出代表第i类的置信度. 1.1 置信度转换 在分类中,希望能尽可能地使正确类别的置信度远大于其它类别.同时我们可以将输出置 ...
- 脉脉发布AI人才数据图鉴;『李沐·深度学习论文精读』视频合辑;CVPR 2022自动驾驶资源合集;线性代数图绘笔记;前沿论文 | ShowMeAI资讯日报
ShowMeAI日报系列全新升级!覆盖AI人工智能 工具&框架 | 项目&代码 | 博文&分享 | 数据&资源 | 研究&论文 等方向.点击查看 历史文章列表, ...
- 李沐深度学习Accumulator函数
class Accumulator: # @save"""在`n`个变量上累加."""def __init__(self, n):self. ...
- 【机器学习】《动手学深度学习 PyTorch版》李沐深度学习笔记(Alexnet)
AlexNet 一.alexnet与lenet的区别 二.主要区别 (1)激活函数从sigmoid变成ReLu(缓解梯度消失) (2)隐层全连接层后加入了丢弃层 (3)数据增强(图像的随机翻转) 三. ...
- Mac M1芯片安装李沐深度学习包d2l
踩了无数坑,总结出来的 首先安装miniforge,注意miniforge的版本,这里有很多教程,可以搜索mac M1 miniforge安装 然后创建虚拟环境: conda create -n d2 ...
- 【动手学深度学习v2李沐】学习笔记07:权重衰退、正则化
前文回顾:模型选择.欠拟合和过拟合 文章目录 一.权重衰退 1.1 硬性限制 1.2 柔性限制(正则化) 1.3 参数更新法则 1.4 总结 二.代码实现 2.1 从零开始实现 2.1.1 人工数据集 ...
- 1 跟李沐老师学习深度学习(介绍监督【分类回归】、非监督【聚类】)
目录 在回归中,我们训练一个回归函数来输出一个数值: 而在分类中,我们训练一个分类器,它的输出即为预测的类别. 把关键章节标注了出来~(由于第一章我当年看过视频了,所以就没再看一遍,而是浏览了笔记) ...
- 笔记|李沐-动手学习机器学习|CNN基础知识(视频19-23)
李沐-动手学习机器学习|CNN基础知识 卷积层(视频19) 从全连接到卷积(卷积算子) 进行图像识别的两个原则 如何从全连接层出发,应用以上两个原则,得到卷积 卷积层 二维交叉相关 二维卷积层 交叉相 ...
- 如何从系统层面优化深度学习计算?
编者按:在图像.语音识别.自然语言处理.强化学习等许多技术领域中,深度学习已经被证明是非常有效的,并且在某些问题上已经达到甚至超越了人类的水平.然而,深度学习对于计算能力有着很大的依赖,除了改变模型和 ...
最新文章
- 2022-2028年中国自热米饭市场竞争策略及行业投资潜力预测报告
- 为什么jdk源码推荐ThreadLocal使用static
- leetcode算法题--回文链表
- 一枚角度渐变描边 loading 图标的 SVG 修炼之路
- SharePoint Server 2007 trial --- 年末大餐细细品尝 (第七口)
- Unity-Animator深入系列---控制IK
- ubuntu上面svn用merge合并到之前的版本
- 5分钟内完成胸部CT扫描机器学习
- OneAPM NI 基于旁路镜像数据的真实用户体验监控
- 【干货来了】ComponentOne经典在线演示等你来体验!(上)
- 超强OCR文字识别软件,图片转文字上班族必备
- 【前端实用工具集】js对url进行编码和解码的三种方式
- 好玩的Java塔防游戏,根本停不下来!五款经典又好玩的塔防游戏推荐
- 邮箱被国际反垃圾邮件组织拉黑的解决方法
- 【Scratch一级真题解析】电子学会等级考试一级(选择题)-2021年9月
- C语言中的a = b = c ? d : e;
- FOR 循环 珠峰折纸
- 分享高压超低噪声LDO测试结果(High Voltage Ultra-low Noise LDO)
- 剑指Offer——编程题的Java实现
- prometheus +granfana监控告警
热门文章
- 网页设计图片素材网站 收集
- 当台式机能搜索到WiFi,但是连不上WiFi时,如何解决?
- KD2684S绕组匝间故障检测仪
- .NET Core、Xamarin、.NET Standard和.NET Framework四者之间的区别
- 计算机公共基础知识总结,记住 | 公共基础知识备考之电脑常识总结!
- openssl验证证书是否由CA证书颁发的问题
- python四级中考有用的_中考又出新政策:一半的孩子将上不了高中?
- 如何在Nginx上 安装SSL证书
- Android去除烦人的默认闪退
- Android 隐藏/透明小白条