fast.ai 深度学习笔记(三)(4)

简介: fast.ai 深度学习笔记(三)(4)

fast.ai 深度学习笔记(三)(3)https://developer.aliyun.com/article/1482898

消融研究

这是一个尝试打开和关闭模型不同部分以查看哪些部分产生哪些影响的过程,原始批量归一化论文中没有进行任何有效的消融。因此,缺失的一点是刚刚提出的这个问题——批量归一化放在哪里。这个疏忽导致了很多问题,因为原始论文实际上没有将其放在最佳位置。自那时以来,其他人已经弄清楚了这一点,当 Jeremy 向人们展示代码时,实际上放在更好位置的人们会说他的批量归一化放错了位置。

  • 尽量在每一层上都使用批量归一化。
  • 不要停止对数据进行归一化,这样使用您的数据的人就会知道您是如何对数据进行归一化的。其他库可能无法正确处理预训练模型的批量归一化,因此当人们开始重新训练时可能会出现问题。
class ConvBnNet(nn.Module):
    def __init__(self, layers, c):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 10, kernel_size=5, stride=1, padding=2)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i + 1])
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
    def forward(self, x):
        x = self.conv1(x)
        for l in self.layers: x = l(x)
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        return F.log_softmax(self.out(x), dim=-1)
  • 代码的其余部分类似——使用BnLayer而不是ConvLayer
  • 在开始时添加了一个单个卷积层,试图接近现代方法。它具有更大的内核大小和步幅为 1。基本思想是我们希望第一层具有更丰富的输入。它使用 5x5 区域进行卷积,这使它可以尝试在该 5x5 区域中找到更有趣更丰富的特征,然后输出更大的输出(在这种情况下,是 10x5x5 个滤波器)。通常是 5x5 或 7x7,甚至是 11x11 卷积,输出相当多的滤波器(例如 32 个滤波器)。
  • 由于padding = kernel_size — 1 / 2stride=1,输入大小与输出大小相同——只是有更多的滤波器。
  • 这是尝试创建更丰富的起点的好方法。

深度批量归一化

让我们增加模型的深度。我们不能只添加更多的步幅为 2 的层,因为每次都会将图像的大小减半。相反,在每个步幅为 2 的层之后,我们插入一个步幅为 1 的层。

class ConvBnNet2(nn.Module):
    def __init__(self, layers, c):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 10, kernel_size=5, stride=1, padding=2)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i+1])
            for i in range(len(layers) - 1)
        ])
        self.layers2 = nn.ModuleList([
            BnLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
    def forward(self, x):
        x = self.conv1(x)
        for l,l2 in zip(self.layers, self.layers2):
            x = l(x)
            x = l2(x)
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        return F.log_softmax(self.out(x), dim=-1)
learn = ConvLearner.from_model_data((ConvBnNet2([10, 20, 40, 80, 160], 10), data)
%time learn.fit(1e-2, 2)
'''
A Jupyter Widget
[ 0\.       1.53499  1.43782  0.47588]                       
[ 1\.       1.28867  1.22616  0.55537]                       
CPU times: user 1min 22s, sys: 34.5 s, total: 1min 56s
Wall time: 58.2 s
'''
%time learn.fit(1e-2, 2, cycle_len=1)
'''
A Jupyter Widget
[ 0\.       1.10933  1.06439  0.61582]                       
[ 1\.       1.04663  0.98608  0.64609]                       
CPU times: user 1min 21s, sys: 32.9 s, total: 1min 54s
Wall time: 57.6 s
'''

准确率与之前相同。现在深度为 12 层,即使对于批量归一化来说也太深了。可以训练 12 层深的卷积网络,但开始变得困难。而且似乎并没有太多帮助。

ResNet

class ResnetLayer(BnLayer):
    def forward(self, x): 
        return x + super().forward(x)
class Resnet(nn.Module):
    def __init__(self, layers, c):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 10, kernel_size=5, stride=1, padding=2)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i+1])
            for i in range(len(layers) - 1)
        ])
        self.layers2 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.layers3 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
    def forward(self, x):
        x = self.conv1(x)
        for l,l2,l3 in zip(self.layers, self.layers2, self.layers3):
            x = l3(l2(l(x)))
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        return F.log_softmax(self.out(x), dim=-1)
  • ResnetLayer继承自BnLayer并覆盖forward
  • 然后添加一堆层,使其深度增加 3 倍,仍然可以很好地训练,只是因为x + super().forward(x)
learn = ConvLearner.from_model_data(Resnet([10, 20, 40, 80, 160], 10), data)wd=1e-5%time learn.fit(1e-2, 2, wds=wd)
'''
A Jupyter Widget
[ 0\.       1.58191  1.40258  0.49131]                       
[ 1\.       1.33134  1.21739  0.55625]                       
CPU times: user 1min 27s, sys: 34.3 s, total: 2min 1s
Wall time: 1min 3s
'''
%time learn.fit(1e-2, 3, cycle_len=1, cycle_mult=2, wds=wd)
'''
A Jupyter Widget
[ 0\.       1.11534  1.05117  0.62549]                       
[ 1\.       1.06272  0.97874  0.65185]                       
[ 2\.       0.92913  0.90472  0.68154]                        
[ 3\.       0.97932  0.94404  0.67227]                        
[ 4\.       0.88057  0.84372  0.70654]                        
[ 5\.       0.77817  0.77815  0.73018]                        
[ 6\.       0.73235  0.76302  0.73633]                        
CPU times: user 5min 2s, sys: 1min 59s, total: 7min 1s
Wall time: 3min 39s
'''
%time learn.fit(1e-2, 8, cycle_len=4, wds=wd)
'''
A Jupyter Widget
[ 0\.       0.8307   0.83635  0.7126 ]                        
[ 1\.       0.74295  0.73682  0.74189]                        
[ 2\.       0.66492  0.69554  0.75996]                        
[ 3\.       0.62392  0.67166  0.7625 ]                        
[ 4\.       0.73479  0.80425  0.72861]                        
[ 5\.       0.65423  0.68876  0.76318]                        
[ 6\.       0.58608  0.64105  0.77783]                        
[ 7\.       0.55738  0.62641  0.78721]                        
[ 8\.       0.66163  0.74154  0.7501 ]                        
[ 9\.       0.59444  0.64253  0.78106]                        
[ 10\.        0.53      0.61772   0.79385]                    
[ 11\.        0.49747   0.65968   0.77832]                    
[ 12\.        0.59463   0.67915   0.77422]                    
[ 13\.        0.55023   0.65815   0.78106]                    
[ 14\.        0.48959   0.59035   0.80273]                    
[ 15\.        0.4459    0.61823   0.79336]                    
[ 16\.        0.55848   0.64115   0.78018]                    
[ 17\.        0.50268   0.61795   0.79541]                    
[ 18\.        0.45084   0.57577   0.80654]                    
[ 19\.        0.40726   0.5708    0.80947]                    
[ 20\.        0.51177   0.66771   0.78232]                    
[ 21\.        0.46516   0.6116    0.79932]                    
[ 22\.        0.40966   0.56865   0.81172]                    
[ 23\.        0.3852    0.58161   0.80967]                    
[ 24\.        0.48268   0.59944   0.79551]                    
[ 25\.        0.43282   0.56429   0.81182]                    
[ 26\.        0.37634   0.54724   0.81797]                    
[ 27\.        0.34953   0.54169   0.82129]                    
[ 28\.        0.46053   0.58128   0.80342]                    
[ 29\.        0.4041    0.55185   0.82295]                    
[ 30\.        0.3599    0.53953   0.82861]                    
[ 31\.        0.32937   0.55605   0.82227]                    
CPU times: user 22min 52s, sys: 8min 58s, total: 31min 51s
Wall time: 16min 38s
'''

ResNet 块

return x + super().forward(x)

y = x + f(x)

其中x是来自上一层的预测,y是来自当前层的预测。重新排列公式,我们得到:公式重新排列

f(x) = y − x

差异y − x残差。残差是迄今为止我们计算的错误。这意味着尝试找到一组卷积权重,试图填补我们偏离的量。换句话说,我们有一个输入,我们有一个函数试图预测错误(即我们偏离的量)。然后我们将输入的错误预测量相加,然后再添加另一个错误预测量,然后重复这个过程,逐层放大到正确答案。这基于一种称为boosting的理论。

  • 完整的 ResNet 在将其添加回原始输入之前进行了两次卷积(我们这里只做了一次)。
  • 在每个块x = l3(l2(l(x)))中,其中一层不是ResnetLayer而是一个带有stride=2的标准卷积——这被称为“瓶颈层”。ResNet 不是卷积层,而是我们将在第 2 部分中介绍的不同形式的瓶颈块。


ResNet 2 [01:59:33]

在这里,我们增加了特征的大小并添加了 dropout。

class Resnet2(nn.Module):
    def __init__(self, layers, c, p=0.5):
        super().__init__()
        self.conv1 = BnLayer(3, 16, stride=1, kernel_size=7)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i+1])
            for i in range(len(layers) - 1)
        ])
        self.layers2 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.layers3 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
        self.drop = nn.Dropout(p)
    def forward(self, x):
        x = self.conv1(x)
        for l,l2,l3 in zip(self.layers, self.layers2, self.layers3):
            x = l3(l2(l(x)))
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        x = self.drop(x)
        return F.log_softmax(self.out(x), dim=-1)
        
learn = ConvLearner.from_model_data(Resnet2([**16, 32, 64, 128, 256**], 10, 0.2), data)
wd=1e-6
%time learn.fit(1e-2, 2, wds=wd)
%time learn.fit(1e-2, 3, cycle_len=1, cycle_mult=2, wds=wd)
%time learn.fit(1e-2, 8, cycle_len=4, wds=wd)
log_preds,y = learn.TTA()
preds = np.mean(np.exp(log_preds),0)
metrics.log_loss(y,preds), accuracy(preds,y)
'''
(0.44507397166057938, 0.84909999999999997)
'''

85%是 2012 年或 2013 年 CIFAR 10 的最新技术。如今,它已经达到了 97%,因此还有改进的空间,但所有都基于这些技术:

  • 更好的数据增强方法
  • 更好的正则化方法
  • 对 ResNet 进行一些调整

问题[02:01:07]:我们可以将“训练残差”方法应用于非图像问题吗?是的!但是它已经被其他地方忽略了。在 NLP 中,“transformer 架构”最近出现,并被证明是翻译的最新技术,并且其中有一个简单的 ResNet 结构。这种一般方法称为“跳过连接”(即跳过一层的想法),在计算机视觉中经常出现,但似乎没有其他人多使用,尽管它与计算机视觉无关。好机会!

狗与猫 [02:02:03]

回到狗和猫。我们将创建 resnet34(如果您对尾随数字的含义感兴趣,请参阅这里——只是不同的参数)。

PATH = "data/dogscats/"
sz = 224
arch = resnet34  # <-- Name of the function 
bs = 64
m = arch(pretrained=True) # Get a model w/ pre-trained weight loaded
m
'''
ResNet(
  (conv1): Conv2d (3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
  (relu): ReLU(inplace)
  (maxpool): MaxPool2d(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), dilation=(1, 1))
  (**layer1**): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
    )
    (2): BasicBlock(
      (conv1): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d (64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (downsample): Sequential(
        (0): Conv2d (64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
    )
    (2): BasicBlock(
      (conv1): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
    )
    (3): BasicBlock(
      (conv1): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
    )
  )
  ...
  (avgpool): AvgPool2d(kernel_size=7, stride=7, padding=0, ceil_mode=False, count_include_pad=True)
  (fc): Linear(in_features=512, out_features=1000)
)
'''

我们的 ResNet 模型具有 Relu → BatchNorm。TorchVision 使用 BatchNorm → Relu。有三个不同版本的 ResNet 在流传,最好的是 PreAct (arxiv.org/pdf/1603.05027.pdf)。

  • 目前,最后一层有数千个特征,因为 ImageNet 有 1000 个特征,所以我们需要摆脱它。
  • 当您使用 fast.ai 的ConvLearner时,它会为您删除最后两层。fast.ai 用自适应平均池化和自适应最大池化替换AvgPool2d,并将两者连接在一起。
  • 对于这个练习,我们将做一个简单版本。
m = nn.Sequential(*children(m)[:-2], 
    nn.Conv2d(512, 2, 3, padding=1), 
    nn.AdaptiveAvgPool2d(1), 
    Flatten(), 
    nn.LogSoftmax()
)
  • 删除最后两层
  • 添加一个只有 2 个输出的卷积。
  • 进行平均池化然后进行 softmax
  • 最后没有线性层。这是产生两个数字的不同方式——这使我们能够进行 CAM!
tfms = tfms_from_model(arch, sz, aug_tfms=transforms_side_on, max_zoom=1.1)
data = ImageClassifierData.from_paths(PATH, tfms=tfms, bs=bs)
learn = ConvLearner.from_model_data(m, data)
learn.freeze_to(-4)
learn.fit(0.01, 1)
learn.fit(0.01, 1, cycle_len=1)
  • ConvLearner.from_model是我们之前学到的——允许我们使用自定义模型创建 Learner 对象。
  • 然后冻结除了我们刚刚添加的层之外的所有层。

类激活图(CAM)[02:08:55]

我们选择一个特定的图像,并使用一种称为 CAM 的技术,询问模型哪些部分的图像被证明是重要的。



它是如何做到的?让我们逆向工作。它是通过生成这个矩阵来做到的:


大数字对应于猫。那么这个矩阵是什么?这个矩阵简单地等于特征矩阵feat乘以py向量的值:

f2=np.dot(np.rollaxis(feat,0,3), py)
f2-=f2.min()
f2/=f2.max()
f2

py 向量是预测,表示“我对这是一只猫有 100%的信心”。feat 是最终卷积层(我们添加的Conv2d层)输出的值(2×7×7)。如果我们将feat乘以py,我们会得到所有第一个通道的值,而第二个通道的值为零。因此,它将返回与猫对应的部分的最后一个卷积层的值。换句话说,如果我们将feat乘以[0, 1],它将与狗对应。

sf = SaveFeatures(m[-4])
py = m(Variable(x.cuda()))
sf.remove()
py = np.exp(to_np(py)[0]); py
'''
array([ 1.,  0.], dtype=float32)
'''
feat = np.maximum(0, sf.features[0])
feat.shape

换句话说,在模型中,卷积层之后唯一发生的事情是平均池化层。平均池化层将 7×7 的网格平均化,计算出每个部分有多少“像猫”。然后,我们将“猫样”矩阵调整大小为与原始猫图像相同的大小,并叠加在顶部,然后你就得到了热图。

您可以在家中使用这种技术的方法是:

  1. 当您有一幅大图像时,您可以在一个快速小的卷积网络上计算这个矩阵。
  2. 放大具有最高值的区域
  3. 仅在该部分重新运行

由于时间不够,我们很快跳过了这部分,但我们将在第 2 部分中学习更多关于这种方法的内容。

“Hook”是让我们要求模型返回矩阵的机制。register_forward_hook要求 PyTorch 每次计算一个层时运行给定的函数 - 类似于每次计算一个层时发生的回调。在以下情况下,它保存了我们感兴趣的特定层的值:

class SaveFeatures():
    features=None
    def __init__(self, m): 
        self.hook = m.register_forward_hook(self.hook_fn)
    def hook_fn(self, module, input, output): 
        self.features = to_np(output)
    def remove(self): 
        self.hook.remove()

Jeremy 的问题[02:14:27]:“您对深度学习的探索”和“如何跟上从业者的重要研究”

“如果您打算参加第 2 部分,您应该掌握我们在第 1 部分学到的所有技术”。以下是您可以做的一些事情:

  1. 至少观看每个视频 3 次。
  2. 确保您可以重新创建笔记本而无需观看视频 - 可能使用不同的数据集来使其更有趣。
  3. 密切关注论坛上的最新论文和最新进展。
  4. 坚持不懈,继续努力!
相关文章
|
5天前
|
机器学习/深度学习 人工智能 TensorFlow
如何将OpenCV与AI深度学习结合使用
如何将OpenCV与AI深度学习结合使用
13 1
|
5天前
|
机器学习/深度学习 人工智能 算法
人工智能(AI)、机器学习(ML)和深度学习(DL)
人工智能(AI)、机器学习(ML)和深度学习(DL)
17 1
|
9天前
|
机器学习/深度学习 传感器 人工智能
敢不敢和AI比猜拳?能赢算我输----基于手势识别的AI猜拳游戏【含python源码+PyqtUI界面+原理详解】-python手势识别 深度学习实战项目
敢不敢和AI比猜拳?能赢算我输----基于手势识别的AI猜拳游戏【含python源码+PyqtUI界面+原理详解】-python手势识别 深度学习实战项目
|
9天前
|
机器学习/深度学习 人工智能 PyTorch
深度学习长文|使用 JAX 进行 AI 模型训练
深度学习长文|使用 JAX 进行 AI 模型训练
19 2
|
22天前
|
机器学习/深度学习 人工智能 自然语言处理
探索AI的无限可能:从机器学习到深度学习
【5月更文挑战第31天】本文旨在深入探讨人工智能(AI)的核心技术,包括机器学习和深度学习。我们将通过实例和案例研究,揭示这些技术如何改变我们的生活和工作方式。此外,我们还将讨论AI的未来发展趋势,以及它可能带来的挑战和机遇。
|
27天前
|
机器学习/深度学习 存储 人工智能
构建高效AI系统:深度学习模型压缩技术
【5月更文挑战第26天】 在资源受限的应用场景中,深度学习模型往往面临存储空间和计算能力的双重挑战。本文针对这一问题,深入探讨了深度学习模型压缩技术,旨在通过降低模型复杂度来优化其性能。文中首先分析了模型压缩的必要性,随后详细介绍了知识蒸馏、网络剪枝、量化等主流压缩方法,并通过实验验证了所提技术的有效性。最后,文章展望了模型压缩领域的未来发展方向,为相关研究提供了新的视角和思路。
|
27天前
|
机器学习/深度学习 数据采集 人工智能
构建高效AI模型:深度学习优化策略和实践
【5月更文挑战第26天】 在人工智能的浪潮中,深度学习作为一项核心技术,其模型构建与优化一直是研究的热点。本文旨在探讨如何通过一系列创新性的优化策略提升深度学习模型的性能及效率。我们将从理论与实践两个维度出发,详细阐述包括数据预处理、网络结构设计、损失函数选择、正则化技巧以及超参数调整等方面的优化措施。通过这些策略的综合运用,可以显著提高模型的准确性,降低过拟合风险,并缩短训练时间,为AI领域的研究者和工程师提供有价值的参考。
|
1月前
|
存储 人工智能 Linux
|
1月前
|
机器学习/深度学习 人工智能 算法
【AI】从零构建深度学习框架实践
【5月更文挑战第16天】 本文介绍了从零构建一个轻量级的深度学习框架tinynn,旨在帮助读者理解深度学习的基本组件和框架设计。构建过程包括设计框架架构、实现基本功能、模型定义、反向传播算法、训练和推理过程以及性能优化。文章详细阐述了网络层、张量、损失函数、优化器等组件的抽象和实现,并给出了一个基于MNIST数据集的分类示例,与TensorFlow进行了简单对比。tinynn的源代码可在GitHub上找到,目前支持多种层、损失函数和优化器,适用于学习和实验新算法。
121 2
|
1月前
|
机器学习/深度学习 人工智能 算法
AI大咖说-关于深度学习的一点思考
周志华教授探讨深度学习的成效,指出其关键在于大量数据、强大算力和训练技巧。深度学习依赖于函数可导性、梯度下降及反向传播算法,尽管硬件和数据集有显著进步,但核心原理保持不变。深度意味着增加模型复杂度,相较于拓宽,加深网络更能增强泛函表达能力,促进表示学习,通过逐层加工处理和内置特征变换实现抽象语义理解。周志华教授还提到了非神经网络的深度学习方法——深度森林。5月更文挑战第12天
49 5

热门文章

最新文章