Deep learning学习笔记

lec 1:Regression

1.5 Linear neural networks for regression线性神经网络的回归

I parameterizing output layer,
I handling data,
I specifying loss function,
I training model.
浅层网络包括线性模型,其中包含了许多经典的统计预测方法,如linear回归和softmax回归。

1.5.1 Linear regression

输入特征的仿射变换Affine transformation(特征的加权和的线性变换和附加偏差的变换)

损失函数为平方误差squared error

当训练模型时,找到在所有训练例子中使平均损失最小的参数(w∗,b∗):

 即使我们不能解析地求解模型,我们仍然可以使用梯度下降算法来训练模型(迭代更新参数的方向,逐步降低损失函数)。

损失函数的导数是数据集中每个示例的损失的平均值。非常慢,因为我们必须通过整个数据集来进行更新。

1.5.2 Minibatch stochastic gradient descent 小批量随机梯度下降

 策略:做一小批(Minibatch)观察。大小(size)取决于许多因素(内存、加速器的数量、图层的选择、总数据集的大小)。32到256之间,2^m(2的m次幂)这样的形式是一个好的开始。

●小批量随机梯度下降(SGD):

  初始化参数。在每次迭代t中,

  用|B|训练示例随机抽样一个小批量Bt

  计算小批量w.r.t.的平均损失梯度因素;

  使用η作为学习速率,执行更新:

  

小批量处理的大小和学习率是由用户定义的。这种在训练循环中没有更新的可调参数被称为超参数(hyperparameters)。

经过多次迭代训练后,我们记录了估计的参数(ˆw,ˆb)。这些不是损失的最小化。

1.5.3 Maximum likelihood estimation最大似然估计

最小化平方误差损失相当于线性模型在加性高斯噪声下的最大似然估计:

 线性回归是一个单层全连接的神经网络,有d个输入:x1,……,xd 和一个单一的输出。

 1.5.4 Synthetic data合成数据

从标准正态set(X∈R^1000×2)中生成1000个examples,用于训练集和验证集。

设置w = [2,−3.4]^T,b=4.。绘制ε~N(0,0.01²)。

#Synthetic data
import random
import torch
from d2l import torch as d2l
data = d2l.SyntheticRegressionData(w=torch.tensor([2,-3.4]), b=4.2, 
noise=0.01, num_train=1000, num_val=1000, batch_size=32)

模型训练需要多次传递一个数据集,每次使用一个小批处理来更新模型。数据处理器生成批量大小(batch_size)的小批量。每个小批处理都是一个特征和标签的元组。

在训练train模式下,我们以随机的顺序读取数据。在验证test模式下,按预定义的顺序读取数据可能对调试很重要。

X, y = next(iter(data.train_dataloader())) # inspect first minibatch
X.shape, y.shape # X: [32, 2], y: [32, 1]
len(data.train_dataloader()) # no. of batches: 32

1.5.5 Implementing linear regression 线性回归的实现

使用具有学习率lr=0.03max_epochs=3的小批量SGD训练线性回归模型。在每个epoch中,我们遍历整个训练数据集,并通过每个示例传递一次。在每个epoch结束时使用验证数据集来测量模型的性能。

通过从N(0,0.01²)采样来初始化权重,并将偏差设置为0。

model = d2l.LinearRegression(lr=0.03)
trainer = d2l.Trainer(max_epochs=3)
trainer.fit(model, data)
w, b = model.get_w_b()
#compute differences
data.w - w.reshape(data.w.shape)
data.b - b
# error in estimating w: tensor([0.0025, -0.0070])
# error in estimating b: tensor([0.0096])

 图中结果表明:估计的参数接近于真值。

•对于深度模型,不存在参数的唯一解。在机器学习中,我们不太关心恢复真正的基础参数,而是更关心能够导致准确预测的参数。

1.5.6 Generalization泛化

机器学习的基本问题是:发现能够泛化的模式。拟合更接近训练数据而不是基本分布的现象是过拟合overfitting,而对抗过拟合的技术被称为正则化regularization

在标准的监督学习中,我们假设训练数据和测试数据是从相同的分布中独立地抽取的。

训练误差Training error:根据训练集计算的统计量,

泛化错误Generalization error:一个期望的w.r.t.基础分布,

通过将模型应用于独立的测试集来估计泛化误差.

当我们有简单的模型和丰富的数据时,训练误差和泛化误差往往会很接近。当我们使用更复杂的模型或更少的例子时,我们期望训练误差会减少,但泛化差距会增加。

深度神经网络在实践中可以很好地推广,但它们太强大了,我们无法仅根据训练错误就得出结论。我们必须依靠验证(保留数据)错误来证明泛化。

——————————————————————————————————————————

当训练误差和验证误差很大,且它们之间的差距很小时,可能会出现不拟合的情况underfitting(模型表达不足)。

训练误差显著低于验证误差表示过拟合。

使用一个d度的多项式:来估计给定单一特征x的标签y。

高阶多项式的训练误差总是较低的。一个具有d = n的多项式可以完美地拟合训练集。

随着我们增加训练数据时,泛化误差通常会减少。如果有更多的数据,我们可以拟合更复杂的模型。只有当有成千上万的训练例子可用时,深度学习才优于线性模型。

K -fold  cross-validation

当训练数据稀缺时,我们可能没有足够的保留数据。在K倍交叉验证中,数据被分成K个不重叠的子集。模型训练和验证执行K次,每次在K−1个子集上进行训练,并对未使用的子集进行验证。训练和验证误差的估计是平均了K个实验的结果。

1.5.7 Weight decay 权重衰减

权重衰减可以通过限制参数采取的值来缓解过拟合。为了将w缩小到零,将其范数作为惩罚项(penalty term)添加到最小化损失的问题中:

正则化常数λ≥0是使用验证集选择的一个超参数。越小的λ对应于约束越小的w。我们通常不规范(正则化)偏差项b。

w的小批量SGD更新变为:

从上述方程式中生成数据,为了使过拟合效果更明显,设置n = 20和d = 200。

定义其中的类、数据和权重衰减:

#如何使用权重衰减(weight decay)来正则化模型
#定义了一个L2正则化项的函数l2_penalty,用来计算权重w的L2范数的平方除以2
def l2_penalty(w): 
    return (w**2).sum() / 2
#创建数据集data
data = Data(num_train=20, num_val=100,num_inputs=200, batch_size=5)
trainer = d2l.Trainer(max_epochs=10)
#创建了一个WeightDecay模型对象model,并将权重衰减参数wd设置为0,学习率lr设置为0.01。(对照)
model = WeightDecay(wd=0, lr=0.01)
#通过将model.board.yscale设置为'log',可以在训练过程中将损失函数的值以对数尺度显示
#有助于观察权重衰减的效果。
model.board.yscale='log'
trainer.fit(model, data)
l2_penalty(model.get_w_b()[0]) # 0.1318

#重新创建了一个WeightDecay模型对象model,将权重衰减参数wd设置为3,学习率lr设置为0.01(实验)
model = WeightDecay(wd=3, lr=0.01)
model.board.yscale='log'
trainer.fit(model, data)
l2_penalty(model.get_w_b()[0]) # 0.0145 比0.1318降低很多

在没有使用权值衰减时,我们非常糟糕的过拟合了。 

随着权值的衰减,训练误差增加,而验证误差减小。

lec5:Convolutional neural networks

卷积神经网络

5.1 Padding and stride

在CNN中,经过多次连续卷积后,输出会比输入小得多。例如,10层5×5卷积将240×240图像减少到200×200像素,切割出30%的图像。

为了更多地控制输出大小,使用填充padding和分层卷积strided convolutions

应用卷积层时图像周长perimeter 像素的损失:图描述了像素利用作为卷积核大小和图像中位置的函数。角落的像素很少使用。

在输入图像的边界周围添加额外的填充filler像素。将额外的像素设置为零。

垫Pad 3 x 3的输入,将其大小增加到5 x 5。输出大小增加到4 x 4。

5.1.1 Padding填充

如果我们添加ph行的填充(∼一半在上,一半在下)和pw列的填充(∼一半在左,一半在右),输出形状为:

输出的高度和宽度分别增加了ph和pw。

输入和输出相同大小:设置ph = kh−1,pw = kw−1。

①在构建网络时,更容易预测每层的输出形状。

②如果kh为奇数,则在位于高度的两侧填充ph/2行。

③如果kh为偶数,顶部填充ph/2行,底部填充ph/2c行。

④以相同的方式填充宽度的两侧。

CNN通常使用高度和宽度都为奇数(1、3、5或7)的卷积核。

#使用PyTorch中的nn.LazyConv2d模块来进行二维卷积操作
import torch
from torch import nn
from d2l import torch as d2l

#创建了一个随机初始化的8x8的张量X
X = torch.rand(size=(8, 8))
#形状变换为(1, 1, 8, 8),表示(batch_size, channels, height, width)的形状。
X = X.reshape((1, 1) + X.shape) # torch.Size([1, 1, 8, 8])

#创建了一个nn.LazyConv2d对象conv2d,指定输入通道数为1,卷积核大小为3x3,填充(padding)为1
#即在图像周围补充1个像素。对输入X进行卷积操作conv2d(X),输出的形状为(1, 1, 8, 8),与输入形状相同
conv2d = nn.LazyConv2d(1, kernel_size=3, padding=1) # 3 x 3 kernel, padding: 1 (all sides)
conv2d(X).shape # torch.Size([1, 1, 8, 8])

#创建了一个nn.LazyConv2d对象conv2d,指定输入通道数为1,卷积核大小为(5, 3),填充(padding)为(2, 1)
#即在高度上补充2个像素,在宽度上补充1个像素。输出的形状仍然为(1, 1, 8, 8),与输入形状相同。
conv2d = nn.LazyConv2d(1, kernel_size=(5,3), padding=(2,1)) # (5-1)/2 =2, (3-1)/2=1
conv2d(X).shape # torch.Size([1, 1, 8, 8])

case1:8×8→(四周+1pixel)→10×10

case2:8×8→(上下各加2pixel,左右各加1pixel)→12×10

5.1.2 Stride步幅

当计算互相关cross-correlation时,从输入张量左上角的卷积窗口开始,然后向下和向右滑动所有位置,每次一个元素

为了提高计算效率或降采样,一次移动窗口为多个元素,跳过中间位置。如果卷积内核很大,因为它捕获了一个大面积的底层图像。

No. of rows and columns traversed per slide: stride步幅。

到目前为止,我们用步幅为1来表示高度和宽度。

Figure: 2-dim cross-correlation with stride of 3 vertically and 2 horizontally.

垂直3步,水平2步。

当生成第一列的第2个元素时,卷积窗口会向下滑动3行。

当生成第一行的第2个元素时,卷积窗口会向右滑动2列。当卷积窗口继续向右滑动2列时,就没有输出。

当高度步幅为sh,宽度步幅为sw时,输出形状为:

如果并且

输出是

如果输入的高度和宽度可按高度和宽度上的步幅整除,则输出形状为 

>将高度和宽度上的步幅设置为2,从而将输入的高度和宽度减半:

conv2d = nn.LazyConv2d(1, kernel_size=3, padding=1, stride=2) # (8-3+1+2)/2 = 4
conv2d(X).shape 
# output:
# torch.Size([1, 1, 4, 4])

 >更复杂的例子:

conv2d = nn.LazyConv2d(1, kernel_size=(3,5), padding=(0,1), stride=(3,4))
conv2d(X).shape # floor((8-3+0+3)/3)=2, floor((8-5+1+4))/4)=2
# output:
# torch.Size([1, 1, 2, 2])

5.2channels 

5.2.1 Multiple input channels 多输入通道

如果卷积核的窗口是kh×kw,我们需要一个包含每个输入通道的kh×kw张量的核(当输入通道的数目 ci > 1)。连接ci张量得到一个ci×kh×kw卷积核。

由于输入核和卷积核都有ci通道,对每个通道的2维输入张量和2维卷积核张量进行互相关,并将ci个结果(通道之和sum over channels)相加得到2维张量。

#定义了一个函数corr2d_multi_in,用于计算多输入通道的二维互相关运算。
#函数接受两个输入:X表示输入张量,K表示卷积核张量,两者都是三维张量。
#函数的实现通过使用zip(X, K)将输入张量和卷积核张量按通道组合起来,
#然后对每对通道进行二维互相关运算,并将结果求和。
#最终返回的是一个二维张量,表示所有通道的互相关运算结果的和。
def corr2d_multi_in(X, K):
    return sum(d2l.corr2d(x, k) for x, k in zip(X, K))

#输入X是一个形状为(2, 3, 3)的张量,表示有两个通道,每个通道的大小为3x3。
X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])

#卷积核张量K是一个形状为(2, 2, 2)的张量,表示有两个通道,每个通道的卷积核大小为2x2。
K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])

#调用corr2d_multi_in(X, K)将对X的每个通道与K的对应通道进行二维互相关运算
#并将结果相加,最终返回一个形状为(2, 2)的张量,表示最终的互相关运算结果。
corr2d_multi_in(X, K) # tensor([[ 56., 72.], [104., 120.]])

到目前为止,我们只有一个输出通道,但在每一层都有多个通道是必要的。随着我们在网络中的深入,我们增加信道维度,降采样downsampling以权衡空间分辨率换取更大的信道深度。

让ci和co分别我输入通道和输出通道的个数,kh和kw分别为内核的高度和宽度。为了获得多个通道的输出,为每个输出通道创建一个ci×kh×kw核张量,并将它们连接concatenate 到输出通道维度上,得到一个卷积核。

每个输出通道的互相关结果是由输出通道的卷积核计算,并从输入张量的所有通道获取输入。

通过将K的核张量与K+1和K+2连接起来,构造具有3个输出通道的平凡卷积核。

#定义了一个函数corr2d_multi_in_out,用于计算多输入通道和多输出通道的二维互相关运算。
def corr2d_multi_in_out(X, K): # calculate output of multiple channels
#使用torch.stack将每个卷积核对应的互相关运算结果堆叠起来
#最终得到一个四维张量,表示多输出通道的互相关运算结果。
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)
K = torch.stack((K, K + 1, K + 2), 0)
K.shape # torch.Size([3, 2, 2, 2])
X.shape # torch.Size([2, 3, 3])
#调用corr2d_multi_in_out(X, K)将对X的每个通道与K的对应通道进行二维互相关运算,并将结果堆叠起来
#最终返回一个形状为(3, 2, 2)的张量,表示三个输出通道的互相关运算结果。
corr2d_multi_in_out(X, K) # output contains 3 channels

# tensor([[[ 56., 72.], [104., 120.]], # result of 1st channel is consistent
# [[ 76., 100.], [148., 172.]],
# [[ 96., 128.], [192., 224.]]])

5.2.3 1 x 1 convolutional layer  1×1卷积层

1 x 1的卷积最初可能没有意义,因为卷积关联了相邻的像素,但在深度网络中很流行。

由于使用最小窗口,1 x 1卷积不能识别高度和宽度维度上相邻元素之间的交互模式。在信道维度上只进行1 x 1卷积的计算。

图:使用1 x 1卷积核计算3个输入通道和2个输出通道计算互相关。输入和输出具有相同的高度和宽度。输出中的每个元素都是由输入图像中相同位置的元素的线性组合推导出来的。

一个1 x 1的卷积层构成一个在每个像素位置应用的全连接层fully connected layer,将ci输入值转换为co输出值,权重在像素位置之间绑定。它需要共同的权重(加上偏差)。

使用完全连接的图层实现1×1卷积。需要对矩阵乘法前后的数据形状进行调整。

X = torch.normal(0, 1, (3, 3, 3)) # X.shape: torch.Size([3, 3, 3])
K = torch.normal(0, 1, (2, 3, 1, 1)) # K.shape: torch.Size([2, 3, 1, 1])

#函数corr2d_multi_in_out_1x1,用于实现1x1卷积操作。
#1x1卷积是指卷积核大小为1x1的卷积操作,通常用于调整通道数或者进行特征融合。
#函数接受两个输入:X表示输入张量,K表示卷积核张量,两者都是四维张量。
def corr2d_multi_in_out_1x1(X, K):
    #函数首先获取输入张量X的通道数c_i,以及卷积核张量K的输出通道数c_o
    c_i, h, w = X.shape
    c_o = K.shape[0]
    #将输入张量Xreshape为(c_i, h * w)的形状,其中h * w表示每个通道展平后的长度
    #将卷积核张量Kreshape为(c_o, c_i)的形状,以便进行矩阵乘法操作
    X = X.reshape((c_i, h * w)) # X.shape: torch.Size([3, 9])
    K = K.reshape((c_o, c_i)) # K.shape: torch.Size([2, 3])
    #使用torch.matmul进行矩阵乘法,得到一个形状为(c_o, h * w)的中间结果张量Y
    Y = torch.matmul(K, X) # Y.shape: torch.Size([2, 9])
    #将Yreshape为(c_o, h, w)的形状,即为最终的输出张量。
    return Y.reshape((c_o, h, w)) # Y.shape: torch.Size([2, 3, 3]) 即返回形状为(2, 3, 3)

当执行1×1卷积时,上述函数相当于之前实现的互相关函数corr2d_multi_in_out

#使用corr2d_multi_in_out_1x1和corr2d_multi_in_out两个函数分别计算输入X和卷积核K的卷积结果
#并将结果分别存储在Y1和Y2中。
Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
#使用torch.abs计算Y1和Y2之间的绝对差值,并使用sum将所有元素相加得到总的差值
#使用assert语句检查总的差值是否小于1e-6,如果满足条件,则不会抛出异常,表示两种卷积方法得到的结果在误差范围内一致。
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6

5.3 Pooling 池化

终极任务经常会问一些关于图像的全局问题(它是否包含一只猫?)。因此,最后一层final layer的单位应该对整个输入都很敏感。

通过逐步聚合信息,我们学习了一个全局表示global representation,同时在处理的中间层保留了卷积层的优势。

网络越深,每个隐藏节点所敏感的感受域就越大。降低空间分辨率加速了这一过程,因为卷积核覆盖了一个更大的有效区域。

当检测低级特征(边)时,表示应该对平移不变。在现实中,物体很难出现在同一个地方。相机的振动可能会使一切改变一个像素。池化层Pooling layers降低了卷积层对位置和空间降样本表示的敏感性。

与卷积层一样,池运算符由一个固定形状的窗口组成,根据其步幅滑动到所有输入区域上,为池窗口pooling window遍历的每个位置计算输出。

与卷积层不同,池化层没有参数。池运算符计算池窗口中元素的最大(最大池max-pooling)或平均(平均池average pooling)。

5.3.1 Maximum pooling and average pooling 最大池化和平均池化

平均池化类似于对图像的降采样。由于我们结合了来自多个相邻像素的信息,因此我们对相邻像素进行平均,以获得信噪比更好的图像。

最大池化通常是首选的,因为它从图像中选择更亮的像素。平均池化平滑的图像和尖锐的特征可能不会被识别出来。

>最大池与2 x 2池窗口。

    输出张量的高度和宽度均为2。这4个元素来自于每个池化窗口中的最大值。

#使用PyTorch中的nn.MaxPool2d和nn.AvgPool2d模块实现二维最大池化和平均池化操作。
X = torch.tensor([[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]])
X = X.reshape((1,1,3,3)) # input format: (batchsize, no. of channels, height, width)

#创建了一个nn.MaxPool2d对象pool2d,指定池化核大小为2x2,步幅为1。
#调用pool2d(X)进行最大池化操作,得到tensor([[[[4., 5.], [7., 8.]]]]),表示经过最大池化后的输出。
pool2d = nn.MaxPool2d(2, stride=1) # Max-pooling
pool2d(X) # tensor([[[[4., 5.], [7., 8.]]]])

#创建了一个nn.AvgPool2d对象pool2d,指定池化核大小为2x2,步幅为1。
#调用pool2d(X)进行平均池化操作,得到tensor([[[[2., 3.], [5., 6.]]]]),表示经过平均池化后的输出。
pool2d = nn.AvgPool2d(2, stride=1) # Average pooling
pool2d(X) # tensor([[[[2., 3.], [5., 6.]]]])

#最大池化和平均池化是常用的池化操作,用于降低特征图的空间维度,减少计算量,并且具有一定的平移不变性。

池化图层会改变输出端的形状。通过填充输入和调整步幅来实现期望的输出形状。

当池聚合来自一个区域的信息时,深度学习框架默认为匹配池窗口的大小和步幅matching pooling window sizes and stride。如果我们使用(3,3)池化窗口,默认情况下我们会得到一个(3,3)个步幅。可以手动指定过渡段和填充,以覆盖默认值。

#手动修改默认值
X = torch.arange(16,dtype=torch.float32).reshape((1,1,4,4))
# tensor([[[[ 0., 1., 2., 3.],
# [ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.],
# [12., 13., 14., 15.]]]])
pool2d = nn.MaxPool2d(3)
pool2d(X) # tensor([[[[10.]]]])

pool2d = nn.MaxPool2d(3, padding=1, stride=2)
pool2d(X)
# tensor([[[[ 5., 7.], [13., 15.]]]])
pool2d = nn.MaxPool2d((2,3), stride=(2,3),padding=(0,1))
pool2d(X)
# tensor([[[[ 5., 7.], [13., 15.]]]])

5.3.2 Multiple channels 多通道

在处理多通道输入数据时,池化层将每个输入通道单独池化,而不是像卷积层那样在通道上的输入求和。因此池化层的输出通道的大小与输入通道的大小相同。

我们将张量X和X + 1连接在通道维数上,构造一个有2个通道的输入。池化后输出通道的大小仍然是2。

X = torch.cat((X, X + 1), 1)
X

pool2d = nn.MaxPool2d(3, padding=1, stride=2) 
pool2d(X)

练习:输入图像的大小为3x1024x1024,应用于其上的卷积核为5(out_channelsx3×2X2。输出的大小是多少?

5X1023X1023

3消掉因为channels求和,1023=1024-2+1

5.4 LeNet

现在我们有了组装全功能CNN的所有成分。之前,我们将MLP应用于Fashion-MNIST数据。

用卷积层代替全连接的层,我们保留了图像中的空间结构,并以更少的参数享受了更简洁的模型。

LeNet(1998)是计算机视觉中第一个引起关注的CNN之一。它是由Yann LeCun介绍的,用于识别图像中的手写数字。

LeNet-5有两部分: (i)具有2个卷积层的卷积编码器和(ii)具有3个完全连接层的密集块。

每个卷积层使用一个5 x 5的核和sigmoid激活函数。第一卷积层有6个输出通道,第二层有16个输出通道。每个2 x 2的平均池(2步)减少4倍(ReLUs,尚未发现的最大池)。

卷积块输出形状:(batch size, no. of channel, height, width).

要将输出从卷积块convolutional block传递到密集块dense block,在小批量中将每个例子变平flatten(将4维输入转换为完全连接层期望的2维输入)。2-dim表示使用第一个dim来索引小批中的示例,第2个dim来给出每个示例的向量表示。

密集块有3个完全连接的层(分别为120、84和10个输出)。

LeNet模型可以使用d2l.Lenet()来实现,它使用Xavier初始化和通过顺序块将层链连接在一起。

要可视化LeNet,将一个单通道(黑白)28x28图像的形状通过它,并在每一层打印输出形状。

#打印LeNet模型在输入为(1, 1, 28, 28)时各层的输出形状信息
model = d2l.LeNet()
model.layer_summary((1, 1, 28, 28))

output:

第一个卷积层使用2的填充来补偿由5×5内核导致的高度和宽度的减少。第二个卷积层放弃了填充物。因此,高度和宽度都减少了4个像素。

当我们往层的上方走时,在第1卷积层后,通道数从1增加到6,在第2卷积层后增加16,但是每个池化层的高度和宽度都减半了。每一层完全连接的层降低维数,最终输出的维度与用于分类的类相匹配。

>>>在Fashion-MNIST上应用LeNet。与MLPs一样,损失函数是交叉熵cross-entropy的,我们通过小批量SGD将其最小化。

#应用LeNet
#使用了d2l库中的Trainer来训练LeNet模型在FashionMNIST数据集上

#创建了一个Trainer对象trainer,设置最大迭代次数为10,使用1个GPU进行训练
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)

#创建了一个FashionMNIST数据集对象data,设置批量大小为128
data = d2l.FashionMNIST(batch_size=128)

#创建了一个LeNet模型对象model,并设置学习率为0.1
model = d2l.LeNet(lr = 0.1)

#调用data.get_dataloader(True)获取训练数据集的一个批量样本,
#然后将该批量样本作为参数调用model.apply_init方法,
#传入d2l.init_cnn函数,用于初始化LeNet模型的参数
model.apply_init([next(iter(data.get_dataloader(True)))[0]], d2l.init_cnn)
#使用trainer.fit方法训练模型
trainer.fit(model, data)

CNN具有更少的参数,但它们的计算成本可能比类似的深度MLPs更昂贵,因为每个参数都参与了更多的乘法。

访问GPU可以加速训练(d2l.Trainer 类处理所有细节,并在默认情况下初始化可用设备上的模型参数)。

通过对CNN基础的理解,我们研究了现代的CNN架构,它们也可以作为高级任务(分割、目标检测、风格转换)的特征生成器。

5.5 Modern convolutional neural networks  现代卷积神经网络

深度神经网络的概念很简单(将一堆层堆叠在一起),但性能因架构和超参数选择而不同。

AlexNet、VGG网络、网络网络(NiN)、谷歌网络和剩余网络(ResNet)是计算机视觉中流行的体系结构。

cnn在LeNet之后就广为人知了,但并没有立即主导该领域。在大数据集上训练cnn的可行性尚未建立,计算机视觉集中于手工工程特征提取管道。

神经网络训练的技巧(参数初始化,非压缩激活函数,有效的正则化,SGD变体)仍然缺失。

直到2012年,表示都是机械计算的,但一些研究人员认为,特征应该由多层分层组成,每个层都有可学习的参数。

对于图像来说,最低的层可以检测边缘、颜色和纹理,类似于动物的视觉系统处理其输入的方式。

5.6 Representation learning

5.6.1 Representation learning 表示学习

第一个现代CNN以其发明者之一亚历克斯·克里热夫斯基的名字命名为AlexNet ,是对LeNet的进化改进。它在2012年的ImageNet挑战中取得了优异的性能,并首次展示了学习到的特征可以超越手工设计的特征,打破了计算机视觉中的范式。

在最低层中,模型学习到了与传统过滤器相似的特征提取器。

更高的层次建立在这些表示形式之上,以代表更大的结构,比如眼睛、鼻子。

甚至更高的层次也代表了整个物体,如人、飞机、狗。

最终隐藏状态学习图像的紧凑表示,总结其内容,这样可以很容易地分离来自不同类别的数据。

AlexNet和LeNet有许多相同的架构元素,但AlexNet要大得多,接受了更多的数据和更快的gpu训练。

5.6.2 Missing ingredients 缺少成分

Data

具有许多层次的深度模型需要大量的数据才能显著优于传统方法(线性方法和核方法)。

鉴于20世纪90年代计算机的存储空间有限,研究依赖于微小的数据集。

ImageNet数据集于2009年发布,挑战研究人员从10^6个例子中学习模型,每个1000个来自1000个不同类别的物体的1000个。

这种规模是前所未有的,图像的高分辨率为224 x 224像素,具有更多的视觉细节,允许形成更高层次的特征。

相关竞赛(ImageNet大规模视觉识别)推动了计算机视觉和机器学习研究的向前发展。

Hardware
训练深度学习模型可能需要数百个时代。每次迭代都将数据通过多层计算成本昂贵的线性代数来传递。
gpu使深度学习成为可能。这些芯片(用于计算机游戏)为计算机图形任务所需的高通量矩阵向量产品进行了优化。这个数学方法类似于计算卷积层。
2004年,NVIDIA开始为一般计算操作优化gpu。
每个CPU核心都很强大,非常适合运行各种具有复杂控制流的程序,但构建成本很高。
相比之下,gpu有数千个小的处理元素,它们被分成更大的组。每个核心都很弱,但总的核心都没有。这种核心使gpu比cpu快几个数量级。
Krizhevesty等人(2012)在CNN中的硬件卷积和矩阵乘法实现并行化,实现了在gpu上运行的深度CNN,取得了重大突破。

5.6.4 AlexNet

AlexNet和LeNet的架构是相似的,但有显著的差异。

1.AlexNet比LeNet5更深,有8层:5个卷积层,2个完全连接的隐藏层(4096个单元)和1个完全连接的输出层。

2.AlexNet使用ReLU代替sigMIU作为激活函数。

在AlexNet的第一层中,卷积窗口是11 x 11,在第二层中减少到5 x 5,然后是3 x 3。
ImageNet中的图像比MNIST更高、更宽。因此,对象倾向于占据更多的像素,需要更大的卷积窗口来捕获对象。
在第1、第2和第5个卷积层之后,AlexNet添加了最大池化层,窗口为3 x 3,步幅为2。
AlexNet通过退出来控制全连接层的模型复杂度,而LeNet只使用权值衰减。
Activation functions
AlexNet将sigmoid激活函数更改为ReLU。
①ReLU的计算更简单,在sigmoid符号中没有指数化。
②ReLU使模型在不同参数初始化下的训练更容易。
③当sigmoid模型的输出非常接近于0或1时,梯度几乎为0,因此反向传播不能继续更新一些模型参数。因此,如果模型参数没有正确初始化,sigmoid函数的梯度几乎为0,模型无法有效训练。
④而ReLU在正区间内的梯度始终为1。
AlexNet的训练循环增加了大量的图像增强 image augmentation(翻转、剪切、颜色变化),使模型更加健壮。较大的样本量有效地减少了过拟合。
#定义了一个AlexNet模型,继承自d2l库中的Classifier类。
#AlexNet是一个经典的卷积神经网络模型,常用于图像分类任务。
class AlexNet(d2l.Classifier):
    def __init__(self, lr=0.1, num_classes=10):
    #在初始化方法__init__中,调用了父类的__init__方法,并使用save_hyperparameters保存了超参数。
        super().__init__()
        self.save_hyperparameters()
    #定义了一个包含多层卷积、激活函数、池化、全连接层和Dropout的网络结构
        self.net = nn.Sequential(
            #第一层卷积:96个输出通道,卷积核大小为11x11,步幅为4,填充为1
            nn.LazyConv2d(96, kernel_size=11, stride=4, padding=1),
            #ReLU激活函数;
            nn.ReLU(),
            #最大池化层:池化核大小为3x3,步幅为2
            nn.MaxPool2d(kernel_size=3, stride=2),
            #第二层卷积:256个输出通道,卷积核大小为5x5,填充为2
            nn.LazyConv2d(256, kernel_size=5, padding=2), 
            #ReLU激活函数
            nn.ReLU(),
            #最大池化层:池化核大小为3x3,步幅为2
            nn.MaxPool2d(kernel_size=3, stride=2),
            #第三层卷积:384个输出通道,卷积核大小为3x3,填充为1
            nn.LazyConv2d(384, kernel_size=3, padding=1), 
            #ReLU激活函数
            nn.ReLU(),
            #第四层卷积:384个输出通道,卷积核大小为3x3,填充为1
            nn.LazyConv2d(384, kernel_size=3, padding=1), 
            #ReLU激活函数
            nn.ReLU(),
            #第五层卷积:256个输出通道,卷积核大小为3x3,填充为1
            nn.LazyConv2d(256, kernel_size=3, padding=1), 
            #ReLU激活函数
            nn.ReLU(),
            #最大池化层:池化核大小为3x3,步幅为2
            nn.MaxPool2d(kernel_size=3, stride=2), 
            #将特征图展平为一维向量
            nn.Flatten(),
            #全连接层:4096个神经元
            nn.LazyLinear(4096), 
            #ReLU激活函数
            nn.ReLU(), 
            #Dropout:丢弃概率为0.5
            nn.Dropout(p=0.5),
            #全连接层:4096个神经元
            nn.LazyLinear(4096), 
            #ReLU激活函数
            nn.ReLU(),
            #Dropout:丢弃概率为0.5
            nn.Dropout(p=0.5),
            #全连接层:输出层,神经元数量为num_classes,即类别数
            nn.LazyLinear(num_classes))

我们构建了一个高度和宽度均为224的单通道数据示例来观察每一层的输出形状。
虽然AlexNet是在ImageNet上训练的,但我们在这里使用Fashion-MNIST来训练ImageNet模型,甚至在现代GPU上也需要几个小时/天的时间。
为了将AlexNet应用于Fashion-MNIST中的低分辨率图像,我们使用  d2l.FashionMNIST 中的 resize将它们从28×28上采样到224×224。这不是一个聪明的做法,因为它在不添加信息的情况下增加了计算的复杂性。
与LeNet相比,AlexNet训练的主要变化是使用更低的学习率和更慢的训练,这是由于更深更宽的网络,更高的图像分辨率和更昂贵的卷积。
#使用了定义的AlexNet模型在FashionMNIST数据集上进行训练。
#首先,创建了一个AlexNet模型对象model,并设置学习率为0.01。
model = AlexNet(lr=0.01)
#创建了一个FashionMNIST数据集对象data,设置批量大小为128,
#并调整图像大小为(224, 224)以适应AlexNet的输入尺寸要求。
data = d2l.FashionMNIST(batch_size=128, resize=(224, 224))
#创建了一个Trainer对象trainer,设置最大迭代次数为10,使用1个GPU进行训练。
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
#对模型进行训练。
trainer.fit(model, data)

 练习:

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

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

相关文章

javaweb学习day03(JS+DOM)

一、javascript入门 1 官方文档 地址: https://www.w3school.com.cn/js/index.asp离线文档: W3School 离线手册(2017.03.11 版).chm 2 基本说明 JavaScript 能改变 HTML 内容&#xff0c;能改变 HTML 属性&#xff0c;能改变 HTML 样式 (CSS)&#xff0c;能完成 页面的数据…

阿里云服务器租用价格2024年新版活动报价和租用收费标准

2024年最新阿里云服务器租用费用优惠价格表&#xff0c;轻量2核2G3M带宽轻量服务器一年61元&#xff0c;折合5元1个月&#xff0c;新老用户同享99元一年服务器&#xff0c;2核4G5M服务器ECS优惠价199元一年&#xff0c;2核4G4M轻量服务器165元一年&#xff0c;2核4G服务器30元3…

macOS 安装 conda

macOS 安装 conda 安装 conda参考 Conda是一个开源的软件包管理系统和环境管理系统&#xff0c;用于安装和管理软件包和其依赖项。 安装 conda mkdir miniconda3 cd miniconda3 bash Miniconda3-latest-MacOSX-x86_64.sh$ conda list参考 macOS 安装 conda开始使用conda

XSS数据接收平台

一.使用xss数据接收平台的好处&#xff1a; 正常执行反射型xss和存储型xss&#xff0c;反射型xss在执行poc时&#xff0c;会直接在页面弹出执行注入的poc代码&#xff1b;存储型则是&#xff0c;在将poc代码注入用户的系统中后&#xff0c;用户访问有存储型xss的地方&#xff…

前端工程化面试题 | 12.精选前端工程化高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

51单片机项目(31)——基于51单片机篮球计分器的proteus仿真

1.功能设计 可以通过两组按键&#xff0c;控制两个队伍的加减分&#xff0c;加分设置有&#xff0b;1分按键&#xff0c;&#xff0b;2分按键&#xff0c;&#xff0b;3分按键。减分设置有&#xff0d;1分按键。 设置有开始/暂停按键&#xff0c;按下开始&#xff0c;数码管便开…

LeetCode Python - 20.有效的括号

目录 题目答案运行结果 题目 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正…

php基础学习之作用域和静态变量

作用域 变量&#xff08;常量&#xff09;能够被访问的区域&#xff0c;变量可以在常规代码中定义&#xff0c;也可以在函数内部定义 变量的作用域 在 PHP 中作用域严格来说分为两种&#xff0c;但是 PHP内部还定义一些在严格意义之外的一种&#xff0c;所以总共算三种—— 局部…

人工智能专题:2024亚太地区生成式人工智能应用与监管报告

今天分享的是人工智能系列深度研究报告&#xff1a;《人工智能专题&#xff1a;2024亚太地区生成式人工智能应用与监管报告》。 &#xff08;报告出品方&#xff1a;德勤&#xff09; 报告共计&#xff1a;20页 来源&#xff1a;人工智能学派 知识更新&#xff1a;了解传统…

交通管理|交通管理在线服务系统|基于Springboot的交通管理系统设计与实现(源码+数据库+文档)

交通管理在线服务系统目录 目录 基于Springboot的交通管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、驾驶证业务管理 3、机动车业务管理 4、机动车业务类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计…

Python setattr函数

在Python编程中&#xff0c;setattr()函数是一个有用且灵活的内置函数&#xff0c;用于设置对象的属性值。它可以在运行时动态地设置对象的属性&#xff0c;无论是新建对象还是已有对象。本文将深入探讨setattr()函数的用法、语法、示例代码&#xff0c;并探讨其在实际编程中的…

Windows 连接共享文件夹 切换/退出账号操作

工作中遇到个问题&#xff0c;登录公司内部共享文件夹&#xff0c;使用自己的账号&#xff0c;但需要切换别人账号找东西时&#xff0c;没有发现登出的地方。在网上找了两种方法&#xff1a;通过命令行登出账号的方法 &#xff08;1&#xff09;打开cmd命令提示符&#xff0c;…

linux进程控制【程序替换】

目录 前言&#xff1a; 1.替换原理 ​编辑 2.替换函数 2.1函数 execl 2.2函数 execv 2.3函数 execlp 2.4函数 execvp 2.5函数 execle 2.6函数 execve 2.7函数 execvpe 前言&#xff1a; 前面我们介绍了进程控制中的创建&#xff0c;退出等待&#xff0c;本章节我们将…

H.264官方手册之帧间预测

一、 框架 只有解码 P和 B类型的宏块时才能调用该过程。 该过程的输出为当前宏块的帧间预测采样点&#xff0c;是一个16x16的亮度采样点 pred(Luma)。以及当ChromaArrayType不等于0时输出 pred(Cb)与pred(Cr) 如果mb_type为B_Skip或者B_Direct_16x16&#xff0c;mbPartIdx的范…

采购平台架构设计和实现的实战总结

当代企业日益重视采购管理的有效性和高效性&#xff0c;而采购平台的架构设计和实现则成为实现这一目标的关键。本文将探讨采购平台架构设计的重要性、关键原则以及实施过程中需要考虑的要点&#xff0c;帮助企业构建强大的采购平台&#xff0c;提升采购管理效率和效果。 ### 1…

嵌入式Linux系统开机启动脚本

前言 现代Linux系统通常用systemd管理进程&#xff0c; 但嵌入式Linux系统通常采用SystemV的模式&#xff0c;开机启动脚本保存在/etc/rcX.d目录下&#xff0c;X代表运行级别 运行级别 0&#xff1a;系统停机状态 1&#xff1a;单用户工作状态&#xff0c;也称为维护模式&am…

鸿蒙开发-HarmonyOS UI架构

初步布局Index 当我们新建一个工程之后&#xff0c;首先会进入Index页。我们先简单的做一个文章列表的显示 class Article {title?: stringdesc?: stringlink?: string }Entry Component struct Index {State articles: Article[] []build() {Row() {Scroll() {Column() …

设计风格:新拟态,一文掌握特征、应用场景、运用方法

Hello&#xff0c;我是大千UI工场&#xff0c;设计风格是我们新开辟的栏目&#xff0c;主要讲解各类UI风格特征、辨识方法、应用场景、运用方法等&#xff0c;包括新拟态、毛玻璃、奢华、新中式等等&#xff0c;有设计需求&#xff0c;我们也可以接单。 一、新拟态风格定义和发…

Vue练习1:组件开发1(头像组件)

样式预览 注释代码 <template><div class"img-box":style"{ //动态style必须为对象width: size rem,height: size rem}"><imgclass"avatar-img":src"url" //动态url/></div> </templ…

智慧公厕管理软件

随着城市化的不断推进&#xff0c;城市公共设施逐渐完善&#xff0c;其中智慧公厕的建设也在不断提速。智慧公厕作为城市基础设施的重要组成部分&#xff0c;对城市卫生水平提升有着不可忽视的作用。而智慧公厕管理软件更是智慧公厕管理的基础&#xff0c;是公共厕所智慧化管理…
最新文章