本周主要讲解了卷积神经网络的基础知识,首先介绍了深度学习的平台,主要有TensorFlow和Pytorch。
TensorFlow是由Google开发的开源机器学习框架,它的目标是为机器学习和深度学习提供一个高效而灵活的平台。TensorFlow可以在多种平台上运行,包括CPU、GPU和TPU等,支持多种编程语言,如Python、C++和Java等。
以下是TensorFlow的一些特点和优势:
- 静态计算图:TensorFlow使用静态计算图,这意味着在运行过程中无法修改神经网络的结构。这使得TensorFlow的执行效率更高,同时也能够更好地支持分布式计算。
- 张量操作:TensorFlow提供了丰富的张量操作,这使得开发者可以方便地实现各种各样的神经网络结构。
- 自动求导:TensorFlow提供了自动求导功能,这使得开发者可以更轻松地实现反向传播算法。
- 大量的预训练模型:TensorFlow拥有大量的预训练模型,包括各种各样的卷积神经网络和循环神经网络,可以方便地进行迁移学习。
- 易用性和可扩展性:TensorFlow具有非常好的易用性和可扩展性,可以轻松地在大规模分布式计算环境中运行。
- 社区支持:TensorFlow拥有一个庞大的社区,拥有丰富的教程和资源,开发者可以轻松地获取帮助和学习。
PyTorch是一个基于Python的科学计算库,主要用于机器学习和深度学习任务,是深度学习框架中较为流行的一个。它由Facebook于2016年发布,并在不断更新和改进。PyTorch可以在GPU和CPU上运行,可以高效地处理大规模数据集和复杂的神经网络。
以下是PyTorch的一些特点和优势:
- 动态计算图:PyTorch使用动态计算图,这意味着在运行过程中可以修改神经网络的结构。这使得调试和试验非常容易,同时也提供了更高的灵活性。
- 张量操作:PyTorch提供了丰富的张量操作,这使得开发者可以方便地实现各种各样的神经网络结构。
- 自动求导:PyTorch提供了自动求导功能,这使得开发者可以更轻松地实现反向传播算法。
- 大量的预训练模型:PyTorch拥有大量的预训练模型,包括各种各样的卷积神经网络和循环神经网络,可以方便地进行迁移学习。
- 社区支持:PyTorch有一个庞大的社区,拥有丰富的教程和资源,开发者可以轻松地获取帮助和学习。
接下来介绍了神经网络的进化史:
- 早期的神经元模型(1943-1958年):神经网络最早的概念可以追溯到1943年,由Warren McCulloch和Walter Pitts提出的神经元模型。这个模型将人脑神经元的结构和功能模拟了出来,被认为是神经网络的起点。
- 感知器模型(1958-1969年):感知器是一种最早的神经网络模型,它由Frank Rosenblatt在1958年提出。感知器由多个输入节点和一个输出节点组成,可以用于分类任务。然而,感知器只能解决线性可分问题。
- 多层感知器模型(1970-1980年):为了解决感知器只能解决线性可分问题的限制,科学家开始尝试构建多层感知器模型,即多层神经网络。这些模型包括了多个隐层,能够解决更加复杂的问题。
- 反向传播算法(1980-1990年):1986年,David Rumelhart等人提出了反向传播算法,这个算法能够自动计算神经网络的权重和偏置,从而实现了神经网络的自动学习。
- 深度学习(2006年至今):深度学习是一种以深层神经网络为基础的机器学习技术,它利用多层次的非线性特征变换,可以处理大规模、高维度的数据集,目前已经在图像识别、语音识别、自然语言处理等领域取得了很大的进展。
接下来介绍了卷积神经网络中卷积、填充、步长、池化等的概念。
卷积是一种在数字信号处理和图像处理中常见的数学操作,它可以通过滑动一个小的窗口(也称为卷积核或滤波器)来提取信号或图像中的特征。在卷积神经网络(Convolutional Neural Network, CNN)中,卷积操作是非常重要的一部分,被用来从输入图像中提取特征,例如边缘、线条和纹理等等。
卷积操作的核心思想是将卷积核与输入图像进行逐元素相乘,然后将所有乘积相加得到一个标量值,作为输出的一个像素值。卷积核的大小通常比输入图像小,因此在进行卷积操作时,卷积核需要在输入图像上滑动,对每个位置进行卷积操作,从而得到一个输出的特征图。
在卷积神经网络中,通常会使用多个卷积核来提取不同的特征,并将它们的输出连接在一起形成一个更高维度的特征图。这些特征图将作为下一层的输入,并继续进行卷积操作,以提取更复杂的特征。卷积操作可以通过反向传播算法来优化卷积核的权重,从而使得卷积神经网络可以自动学习输入图像中的特征,从而实现对图像的分类、识别和分割等任务。
在卷积神经网络中,填充(Padding)是指在输入图像周围添加一定数量的像素,以便更好地处理边缘像素。填充可以让卷积操作在图像边缘处产生的信息损失减少,使得输出特征图与输入特征图的大小保持一致。卷积神经网络中通常使用两种填充方式:零填充和边界填充。
- 零填充(Zero Padding):在输入图像周围添加一圈像素值为零的像素,以扩展输入图像的大小。零填充常用于保持卷积层之间的特征图大小一致,这样可以更方便地进行后续的卷积操作和池化操作。
- 边界填充(Border Padding):在输入图像周围添加与边缘像素值相同的像素,以扩展输入图像的大小。边界填充通常用于保持输入和输出的特征图大小一致,以便在卷积神经网络的最后一层进行分类或回归等任务。
填充的大小通常由卷积核大小和步幅决定。当卷积核大小为奇数时,可以在输入图像的周围添加相同数量的填充像素,从而保持输出特征图的大小与输入特征图相同。当卷积核大小为偶数时,需要在输入图像的周围添加不同数量的填充像素,以保持输出特征图的大小与输入特征图相同。填充的大小可以通过调整卷积层的超参数来控制。
在卷积神经网络中,步长(Stride)是指卷积核在输入特征图上滑动的步长。步长的大小决定了输出特征图的大小和空间分辨率。
当步长为1时,卷积核每次移动一个像素,输出特征图的大小与输入特征图相同。当步长为2时,卷积核每次移动两个像素,输出特征图的大小通常是输入特征图大小的一半。步长的大小越大,输出特征图的大小就越小,但是它能够更快地减少特征图的大小,从而降低模型的复杂度。
在实际应用中,步长通常与填充一起使用,以控制输出特征图的大小和分辨率。使用较小的步长可以提高特征图的分辨率,但是会增加计算量和内存消耗;使用较大的步长可以减少计算量和内存消耗,但是会降低特征图的分辨率。因此,在设计卷积神经网络时,需要根据具体的应用场景和计算资源的限制,选择适当的步长大小。
在神经网络中,池化(pooling)是一种常用的操作,其主要目的是减小特征图的大小,同时提高模型的鲁棒性和泛化能力。
池化操作通常应用于卷积层输出的特征图上,它可以将特征图中某个区域内的像素值合并为一个值,从而降低特征图的空间分辨率。常见的池化操作包括最大池化(max pooling)和平均池化(average pooling)。
最大池化的操作是选取输入区域内的最大值作为输出,这样可以保留最明显的特征。而平均池化则是计算输入区域内像素值的平均值,并将该平均值作为输出。这种方式可以降低特征图中的噪声和冗余信息。
通常,池化操作在卷积层之后进行,它可以使特征图的大小减半,从而降低计算量和内存需求,同时也可以提高模型的鲁棒性和泛化能力。不过,过多的池化会导致信息的丢失,因此需要根据具体应用情况进行调整。
之后讲解了卷积神经网络的结构:
CNN主要由以下几个层组成:
- 卷积层(Convolutional layer):卷积层是CNN的核心层之一,它通过在输入数据上滑动一个卷积核(也称为滤波器),从而提取出输入数据中的特征。卷积核可以看作是一组可学习的参数,用于对输入数据进行卷积操作,从而得到输出特征图。
- 激活函数层(Activation layer):激活函数层对卷积层的输出进行非线性变换,以增强网络的表达能力。常用的激活函数包括ReLU、Sigmoid、Tanh等。
- 池化层(Pooling layer):池化层用于减小特征图的大小,并增强对输入数据的不变性。常用的池化操作包括最大池化(Max pooling)、平均池化(Average pooling)等。
- 全连接层(Fully connected layer):全连接层将卷积层输出的特征图拉成一维向量,并通过一系列全连接操作,最终将其映射到输出层,实现分类、回归等任务。
- Dropout层(Dropout layer):在训练过程中,为防止过拟合,可以添加Dropout层,随机地将一定比例的神经元输出置为0。
之后介绍了一下LeNet5的网络结构如下:
- 输入层:输入为32乘32的灰度图像。
- C1层:卷积层,使用6个5_5的卷积核对输入图像进行卷积操作,得到6个28_28的特征图。同时,每个特征图上的像素值经过sigmoid函数激活。
- S2层:池化层,对C1层的输出进行2_2的最大池化操作,将每个特征图的大小缩小一半,得到6个14_14的特征图。
- C3层:卷积层,使用16个5_5的卷积核对S2层的输出进行卷积操作,得到16个10_10的特征图。同时,每个特征图上的像素值经过sigmoid函数激活。
- S4层:池化层,对C3层的输出进行2_2的最大池化操作,将每个特征图的大小缩小一半,得到16个5_5的特征图。
- C5层:卷积层,使用120个5_5的卷积核对S4层的输出进行卷积操作,得到120个1_1的特征图。同时,每个特征图上的像素值经过sigmoid函数激活。
- F6层:全连接层,将C5层的120个特征图拉成一维向量,经过一系列全连接操作后,最终将其映射到10个输出节点,用于实现手写数字的分类。
使用pytorch实现LeNet5网络代码如下:
import torch
import torch.nn as nn
class LeNet5(nn.Module):
def __init__(self):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
self.avgpool1 = nn.AvgPool2d(kernel_size=2, stride=2)
self.conv2 = nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5)
self.avgpool2 = nn.AvgPool2d(kernel_size=2, stride=2)
self.fc1 = nn.Linear(in_features=16*5*5, out_features=120)
self.fc2 = nn.Linear(in_features=120, out_features=84)
self.fc3 = nn.Linear(in_features=84, out_features=10)
def forward(self, x):
x = self.avgpool1(torch.relu(self.conv1(x)))
x = self.avgpool2(torch.relu(self.conv2(x)))
x = x.view(-1, 16*5*5)
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x