Deep learning学习笔记

news2024/11/26 9:31:12

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.coloradmin.cn/o/1451249.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全防御保护 Day5

今天的任务如下 要求一的解决方法&#xff1a; 前面这些都是在防火墙FW1上的配置。 首先创建电信的NAT策略 这里新建转换后的地址池 移动同理&#xff0c;不过地址池不一样 要求二的解决方法&#xff1a; 切换至服务器映射选项&#xff0c;点击新建&#xff0c;配置外网通过…

JDBC 核心 API

引入 mysql-jdbc 驱动 驱动 jar 版本的选择&#xff1a;推荐使用 8.0.25&#xff0c;省略时区设置java 工程导入依赖 项目创建 lib 文件夹导入驱动依赖 jar 包jar 包右键 - 添加为库 JDBC 基本使用步骤 注册驱动获取连接创建发送 sql 语句对象发送 sql 语句&#xff0c;并获…

讲解用Python处理Excel表格

我们今天来一起探索一下用Python怎么操作Excel文件。与word文件的操作库python-docx类似&#xff0c;Python也有专门的库为Excel文件的操作提供支持&#xff0c;这些库包括xlrd、xlwt、xlutils、openpyxl、xlsxwriter几种&#xff0c;其中我最喜欢用的是openpyxl&#xff0c;这…

LEETCODE 315. 计算右侧小于当前元素的个数(归并)

class Solution { public: // 将count声明为publicvector<int> count; vector<int> indexs,tmp;public:vector<int> countSmaller(vector<int>& nums) {//归并int left0;int rightnums.size()-1;//计数// vector<int> count(nums.size()); …

题解37-42

101. 对称二叉树 - 力扣&#xff08;LeetCode&#xff09; 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,nul…

【C++】友元、内部类和匿名对象

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 1. 友元 1.1 友元函数 1.2 友元类 2. 内部类 2.1 成员内部类 2.2 局部内部类 3. 匿名对象 3.1 基本概念 3.1 隐式转换 1…

(10)Hive的相关概念——文件格式和数据压缩

目录 一、文件格式 1.1 列式存储和行式存储 1.1.1 行存储的特点 1.1.2 列存储的特点 1.2 TextFile 1.3 SequenceFile 1.4 Parquet 1.5 ORC 二、数据压缩 2.1 数据压缩-概述 2.1.1 压缩的优点 2.1.2 压缩的缺点 2.2 Hive中压缩配置 2.2.1 开启Map输出阶段压缩&…

threejs之使用shader实现雷达扫描

varying vec2 vUv; uniform vec3 uColor; uniform float uTime;mat2 rotate2d(float _angle){return mat2(cos(_angle),-sin(_angle),sin(_angle),cos(_angle)); }void main(){vec2 newUv rotate2d(uTime*6.18)*(vUv-0.5);float angle atan(newUv.x,newUv.y);// 根据uv坐标获…

那些杠鸿蒙的现在怎么样了?

别杠&#xff0c;要杠就是你对。 一个纯血鸿蒙就已经打了那些杠精的嘴&#xff0c;以前是套壳Android&#xff0c;大家纷纷喷鸿蒙。现在鸿蒙已经全栈自研&#xff0c;并且已经展开各大企业生态合作。不管什么独立系统&#xff0c;都是一定要走一遍套壳Android的道路的&#xf…

幻兽帕鲁云服务器搭建零基础教程,新手小白一看就会

以下教程基于阿里云服务器ECS 来搭建幻兽帕鲁游戏服务器&#xff0c;通过一键部署的方式&#xff0c;最快1分钟即可完成部署。 阿里云一键部署幻兽帕鲁的活动地址&#xff1a;1分钟畅玩&#xff01;一键部署幻兽帕鲁联机服务器 首先&#xff0c;打开阿里云的这个游戏服务器活…

laravel_进程门面_简单介绍

文章目录 Facade是什么&#xff1f;Facade能干什么Facade有哪些方法&#xff1f;怎么使用Facade呢&#xff1f;详细的代码解释Symfony Process是什么&#xff1f;介绍Symfony总结 Facade是什么&#xff1f; 在 Laravel 框架中&#xff0c;Facade 是一种设计模式。 它提供了一…

Javaweb基础-会话

会话&#xff1a; 会话管理&#xff1a;Cookie和Session配合解决 cookie是在客户端保留少量数据的技术,主要通过响应头向客户端响应一些客户端要保留的信息 session是在服务端保留更多数据的技术,主要通过HttpSession对象保存一些和客户端相关的信息 cookie和session配合记录…

奇异递归模板模式应用3-克隆对象

需求&#xff1a;希望某些类提供拷贝自身对象的功能&#xff0c;实现如下 template <typename T> class A { public:T *clone() {return new T(static_cast<T &>(*this));}private:friend T;A() default; };class B : public A<B> { public:B(int valu…

基于Java (spring-boot)和微信小程序的奶茶点餐小程序

一、项目介绍 基于Java (spring-boot)和微信小程序的奶茶点餐小程序功能&#xff1a;客户端登录、个人中心、点餐、选规格、去结算、取餐、我的信息、管理员登录、管理员首页、用户管理、商品管理、商品编辑、商品种类、订单管理、订单处理、等等等。 适用人群&#xff1a;适合…

全网首发 vsol光猫v2802rh光猫配置及IPTV组播教程

写在前面&#xff0c;首先感谢恩山的前辈们&#xff01;在农村老家没有10GPON但是GPON线路可以完成最高2.5G带宽&#xff0c;因此在重庆联通的基础上&#xff0c;配合V2802RH出这个教程&#xff08;图片都是一样我直接借用网上展示一下光猫后台&#xff09;。 提前准备一个VSO…

Unity 2D Spine 外发光实现思路

Unity 2D Spine 外发光实现思路 前言 对于3D骨骼&#xff0c;要做外发光可以之间通过向法线方向延申来实现。 但是对于2D骨骼&#xff0c;各顶点的法线没有向3D骨骼那样拥有垂直于面的特性&#xff0c;那我们如何做2D骨骼的外发光效果呢&#xff1f; 理论基础 我们要知道&a…

蒙特卡罗模拟 python Monte Carlo Simulation

1. 蒙特卡罗模拟 与普通预测模型不同&#xff0c;蒙特卡罗模拟根据估计值范围与一组固定输入值来预测一组结果。换句话说&#xff0c;蒙特卡洛模拟通过利用概率分布&#xff08;例如均匀分布或正态分布&#xff09;&#xff0c;为任何具有固有不确定性的变量构建可能结果的模型…

leetcode hot 100最小花费爬楼梯

本题和之前的爬楼梯类似&#xff0c;但是需要考虑到花费的问题&#xff01;**注意&#xff0c;只有在爬的时候&#xff0c;才花费体力&#xff01;**那么&#xff0c;我们还是按照动态规划的五部曲来思考。 首先我们要确定dp数组的含义&#xff0c;那么就是我们爬到第i层所花费…

基于蓄电池和飞轮混合储能系统的SIMULINK建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 蓄电池储能原理 4.2 飞轮储能原理 4.3 混合储能系统原理 5.完整工程文件 1.课题概述 基于蓄电池和飞轮混合储能系统的SIMULINK建模与仿真。蓄电池和飞轮混合储能&#xff0c;蓄电池可以用SIMULINK…

【C++】类和对象(五)友元、内部类、匿名对象

前言&#xff1a;前面我们说到类和对象是一个十分漫长的荆棘地&#xff0c;今天我们将走到终点&#xff0c;也就是说我们对于&#xff23;算是正式的入门了。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23;学习 &…