@@ -110,10 +110,13 @@ | |||||
}, | }, | ||||
"outputs": [], | "outputs": [], | ||||
"source": [ | "source": [ | ||||
"# 使用 nn.Conv2d\n", | |||||
"# 使用 nn.Conv2d (in_channels, out_channels, kernel_size)\n", | |||||
"conv1 = nn.Conv2d(1, 1, 3, bias=False) # 定义卷积\n", | "conv1 = nn.Conv2d(1, 1, 3, bias=False) # 定义卷积\n", | ||||
"\n", | "\n", | ||||
"sobel_kernel = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]], dtype='float32') # 定义轮廓检测算子\n", | |||||
"sobel_kernel = np.array(\n", | |||||
" [[-1, -1, -1], \n", | |||||
" [-1, 8, -1], \n", | |||||
" [-1, -1, -1]], dtype='float32') # 定义轮廓检测算子\n", | |||||
"sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出\n", | "sobel_kernel = sobel_kernel.reshape((1, 1, 3, 3)) # 适配卷积的输入输出\n", | ||||
"conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值\n", | "conv1.weight.data = torch.from_numpy(sobel_kernel) # 给卷积的 kernel 赋值\n", | ||||
"\n", | "\n", | ||||
@@ -203,7 +206,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"可以看到两种形式能够得到相同的效果,不同的地方在于使用 `nn.Conv2d()` 相当于直接定义了一层卷积网络结构,而使用 `torch.nn.functional.conv2d()` 相当于定义了一个卷积的操作,所以使用后者需要再额外去定义一个 weight,而且这个 weight 也必须是一个 Variable,而使用 `nn.Conv2d()` 则会帮我们默认定义一个随机初始化的 weight,如果我们需要修改,那么取出其中的值对其修改,如果不想修改,那么可以直接使用这个默认初始化的值,非常方便\n", | |||||
"可以看到两种形式能够得到相同的效果,不同的地方在于使用 `nn.Conv2d()` 相当于直接定义了一层卷积网络结构,而使用 `torch.nn.functional.conv2d()` 相当于定义了一个卷积的操作,所以使用后者需要再额外去定义一个 weight,而且这个 weight 也必须是一个 Variable,而使用 `nn.Conv2d()` 则会默认定义一个随机初始化的 weight,如果需要修改,那么取出其中的值对其修改,如果不想修改,那么可以直接使用这个默认初始化的值,非常方便。\n", | |||||
"\n", | "\n", | ||||
"**实际使用中我们基本都使用 `nn.Conv2d()` 这种形式**" | "**实际使用中我们基本都使用 `nn.Conv2d()` 这种形式**" | ||||
] | ] | ||||
@@ -213,9 +216,10 @@ | |||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"## 2. 池化层\n", | "## 2. 池化层\n", | ||||
"卷积网络中另外一个非常重要的结构就是池化,这是利用了图片的下采样不变性,即一张图片变小了还是能够看出了这张图片的内容,而使用池化层能够将图片大小降低,非常好地提高了计算效率,同时池化层也没有参数。池化的方式有很多种,比如最大值池化,均值池化等等,在卷积网络中一般使用最大值池化。\n", | |||||
"\n", | "\n", | ||||
"在 pytorch 中最大值池化的方式也有两种,一种是 `nn.MaxPool2d()`,一种是 `torch.nn.functional.max_pool2d()`,他们对于图片的输入要求跟卷积对于图片的输入要求是一样了,就不再赘述,下面我们也举例说明" | |||||
"卷积网络中另外一个非常重要的结构就是 `池化`,这是利用了图片的下采样不变性,即一张图片变小了还是能够看出了这张图片的内容,而使用池化层能够将图片大小降低,非常好地提高了计算效率,同时池化层也没有参数。池化的方式有很多种,比如最大值池化,均值池化等等,在卷积网络中一般使用最大值池化。\n", | |||||
"\n", | |||||
"在 PyTorch 中最大值池化的方式也有两种,一种是 `nn.MaxPool2d()`,一种是 `torch.nn.functional.max_pool2d()`,他们对于图片的输入要求跟卷积对于图片的输入要求是一样了,就不再赘述,下面举例说明。" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -245,7 +249,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"可以看到图片的大小减小了一半,那么图片是不是变了呢?我们可以可视化一下" | |||||
"可以看到图片的大小减小了一半,那么图片是不是变了呢?通过可视化确认一下。" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -343,7 +347,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"以上我们介绍了如何在 pytorch 中使用卷积网络中的卷积模块和池化模块,接下来我们会开始讲卷积网络中几个非常著名的网络结构" | |||||
"以上介绍了如何在 PyTorch 中使用卷积网络中的卷积模块和池化模块,接下来讲解卷积网络中几个非常著名的网络结构" | |||||
] | ] | ||||
} | } | ||||
], | ], | ||||
@@ -5,7 +5,10 @@ | |||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"# VGG\n", | "# VGG\n", | ||||
"计算机视觉是一直深度学习的主战场,从这里我们将接触到近几年非常流行的卷积网络结构,网络结构由浅变深,参数越来越多,网络有着更多的跨层链接,首先我们先介绍一个数据集 cifar10,我们将以此数据集为例介绍各种卷积网络的结构。\n" | |||||
"\n", | |||||
"计算机视觉是一直深度学习的主战场,从这里将学习近几年非常流行的卷积网络结构,网络结构由浅变深,参数越来越多,网络有着更多的跨层链接。\n", | |||||
"\n", | |||||
"VGG卷积神经网络是牛津大学在2014年提出来的模型。当这个模型被提出时,由于它的简洁性和实用性,马上成为了当时最流行的卷积神经网络模型。它在图像分类和目标检测任务中都表现出非常好的结果。在2014年的ILSVRC比赛中,VGG 在Top-5中取得了92.3%的正确率。" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -13,13 +16,15 @@ | |||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"## CIFAR 10\n", | "## CIFAR 10\n", | ||||
"cifar 10 这个数据集一共有 50000 张训练集,10000 张测试集,两个数据集里面的图片都是 png 彩色图片,图片大小是 32 x 32 x 3,一共是 10 分类问题,分别为飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。这个数据集是对网络性能测试一个非常重要的指标,可以说如果一个网络在这个数据集上超过另外一个网络,那么这个网络性能上一定要比另外一个网络好,目前这个数据集最好的结果是 95% 左右的测试集准确率。\n", | |||||
"\n", | "\n", | ||||
"\n", | |||||
"首先介绍一个数据集 CIFAR10,后续以此数据集为例介绍各种卷积网络的结构。\n", | |||||
"\n", | |||||
"CIFAR10 这个数据集一共有 50000 张训练集,10000 张测试集,两个数据集里面的图片都是 png 彩色图片,图片大小是 32 x 32 x 3,一共是 10 分类问题,分别为飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。这个数据集是对网络性能测试一个非常重要的指标,可以说如果一个网络在这个数据集上超过另外一个网络,那么这个网络性能上一定要比另外一个网络好,目前这个数据集最好的结果是 95% 左右的测试集准确率。\n", | |||||
"\n", | "\n", | ||||
"你能用肉眼对这些图片进行分类吗?\n", | |||||
"\n", | |||||
"\n", | "\n", | ||||
"cifar 10 已经被 pytorch 内置了,使用非常方便,只需要调用 `torchvision.datasets.CIFAR10` 就可以了" | |||||
"\n", | |||||
"CIFAR10 已经被 PyTorch 内置了,使用非常方便,只需要调用 `torchvision.datasets.CIFAR10` 就可以了" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -27,15 +32,35 @@ | |||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"## VGGNet\n", | "## VGGNet\n", | ||||
"vggNet 是第一个真正意义上的深层网络结构,其是 ImageNet2014年的冠军,得益于 python 的函数和循环,我们能够非常方便地构建重复结构的深层网络。\n", | |||||
"\n", | |||||
"vgg 的网络结构非常简单,就是不断地堆叠卷积层和池化层,下面是一个简单的图示(FIXME,换一个图)\n", | |||||
"VGGNet 是第一个真正意义上的深层网络结构,其是 ImageNet2014年的冠军,得益于 Python 的函数和循环,我们能够非常方便地构建重复结构的深层网络。\n", | |||||
"\n", | "\n", | ||||
"\n", | |||||
"VGG 的网络结构非常简单,就是不断地堆叠卷积层和池化层,下面是网络结构图:\n", | |||||
"\n", | "\n", | ||||
"vgg 几乎全部使用 3 x 3 的卷积核以及 2 x 2 的池化层,使用小的卷积核进行多层的堆叠和一个大的卷积核的感受野是相同的,同时小的卷积核还能减少参数,同时可以有更深的结构。\n", | |||||
"\n", | |||||
"\n", | "\n", | ||||
"vgg 的一个关键就是使用很多层 3 x 3 的卷积然后再使用一个最大池化层,这个模块被使用了很多次,下面我们照着这个结构来写一写" | |||||
"VGG整个结构只有3×3的卷积层,连续的卷积层后使用池化层隔开。虽然层数很多,但是很简洁。几乎全部使用 3 x 3 的卷积核以及 2 x 2 的池化层,使用小的卷积核进行多层的堆叠和一个大的卷积核的感受野是相同的,同时小的卷积核还能减少参数,同时可以有更深的结构。\n", | |||||
"\n" | |||||
] | |||||
}, | |||||
{ | |||||
"cell_type": "markdown", | |||||
"metadata": {}, | |||||
"source": [ | |||||
"VGG网络的特点:\n", | |||||
"* 小卷积核和连续的卷积层: VGG中使用的都是3×3卷积核,并且使用了连续多个卷积层。这样做的好处主要有,\n", | |||||
" - 使用连续的的多个小卷积核(3×3),来代替一个大的卷积核(例如(5×5)。使用小的卷积核的问题是,其感受野必然变小。所以,VGG中就使用连续的3×3卷积核,来增大感受野。VGG认为2个连续的3×3卷积核能够替代一个5×5卷积核,三个连续的3×3能够代替一个7×7。\n", | |||||
" - 小卷积核的参数较少。3个3×3的卷积核参数为3×3×=27,而一个7×7的卷积核参数为7×7=49\n", | |||||
" - 由于每个卷积层都有一个非线性的激活函数,多个卷积层增加了非线性映射。\n", | |||||
"* 小池化核,使用的是2×2\n", | |||||
"* 通道数更多,特征度更宽: 每个通道代表着一个FeatureMap,更多的通道数表示更丰富的图像特征。VGG网络第一层的通道数为64,后面每层都进行了翻倍,最多到512个通道,通道数的增加,使得更多的信息可以被提取出来。\n", | |||||
"* 层数更深: 使用连续的小卷积核代替大的卷积核,网络的深度更深,并且对边缘进行填充,卷积的过程并不会降低图像尺寸。仅使用小的池化单元,降低图像的尺寸。" | |||||
] | |||||
}, | |||||
{ | |||||
"cell_type": "markdown", | |||||
"metadata": {}, | |||||
"source": [ | |||||
"VGG 的一个关键就是使用很多层 3 x 3 的卷积然后再使用一个最大池化层,这个模块被使用了很多次,下面照着这个结构把网络用PyTorch实现出来:" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -64,7 +89,12 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"我们可以定义一个 vgg 的 block,传入三个参数,第一个是模型层数,第二个是输入的通道数,第三个是输出的通道数,第一层卷积接受的输入通道就是图片输入的通道数,然后输出最后的输出通道数,后面的卷积接受的通道数就是最后的输出通道数" | |||||
"为了代码的简洁和复用,可以定义一个 VGG 的 block,传入三个参数:\n", | |||||
"* 第一个是模型层数\n", | |||||
"* 第二个是输入的通道数\n", | |||||
"* 第三个是输出的通道数\n", | |||||
"\n", | |||||
"第一层卷积接受的输入通道就是图片输入的通道数,然后输出最后的输出通道数,后面的卷积接受的通道数就是最后的输出通道数" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -94,7 +124,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"我们可以将模型打印出来看看结构" | |||||
"将模型打印出来,可以看到网络的具体结构" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -147,7 +177,7 @@ | |||||
} | } | ||||
], | ], | ||||
"source": [ | "source": [ | ||||
"# 首先定义输入为 (1, 64, 300, 300)\n", | |||||
"# 首先定义输入为 (1, 64, 300, 300) (batch, channels, imgH, imgW)\n", | |||||
"input_demo = Variable(torch.zeros(1, 64, 300, 300))\n", | "input_demo = Variable(torch.zeros(1, 64, 300, 300))\n", | ||||
"output_demo = block_demo(input_demo)\n", | "output_demo = block_demo(input_demo)\n", | ||||
"print(output_demo.shape)" | "print(output_demo.shape)" | ||||
@@ -157,9 +187,9 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"可以看到输出就变为了 (1, 128, 150, 150),可以看到经过了这一个 vgg block,输入大小被减半,通道数变成了 128\n", | |||||
"可以看到输出就变为了 `(1, 128, 150, 150)` (batch, channels, imgH, imgW) ,可以看到经过了这一个 VGG block,输入大小被减半,通道数变成了 128\n", | |||||
"\n", | "\n", | ||||
"下面我们定义一个函数对这个 vgg block 进行堆叠" | |||||
"下面我们定义一个函数对这个 VGG block 进行堆叠" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -187,7 +217,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"作为实例,我们定义一个稍微简单一点的 vgg 结构,其中有 8 个卷积层" | |||||
"作为实例,我们定义一个稍微简单一点的 VGG 结构,其中有 8 个卷积层" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -259,7 +289,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"我们可以看到网络结构中有个 5 个 最大池化,说明图片的大小会减少 5 倍,我们可以验证一下,输入一张 256 x 256 的图片看看结果是什么" | |||||
"可以看到网络结构中有个 5 个 最大池化,说明图片的大小会减少 5 倍。可以验证一下,输入一张 256 x 256 的图片看看结果是什么" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -325,7 +355,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"然后我们可以训练我们的模型看看在 cifar10 上的效果" | |||||
"然后我们可以训练我们的模型看看在 CIFAR10 上的效果" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -404,7 +434,7 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"可以看到,跑完 20 次,vgg 能在 cifar 10 上取得 76% 左右的测试准确率" | |||||
"可以看到,跑完 20 次,VGG 能在 CIFAR10 上取得 76% 左右的测试准确率" | |||||
] | ] | ||||
} | } | ||||
], | ], | ||||
@@ -5,11 +5,12 @@ | |||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"# GoogLeNet\n", | "# GoogLeNet\n", | ||||
"前面我们讲的 VGG 是 2014 年 ImageNet 比赛的亚军,那么冠军是谁呢?就是我们马上要讲的 GoogLeNet,这是 Google 的研究人员提出的网络结构,在当时取得了非常大的影响,因为网络的结构变得前所未有,它颠覆了大家对卷积网络的串联的印象和固定做法,采用了一种非常有效的 inception 模块,得到了比 VGG 更深的网络结构,但是却比 VGG 的参数更少,因为其去掉了后面的全连接层,所以参数大大减少,同时有了很高的计算效率。\n", | |||||
"\n", | |||||
"前面讲的 VGG 是 2014 年 ImageNet 比赛的亚军,那么冠军是谁呢?就是接下来要讲的 GoogLeNet,这是 Google 的研究人员提出的网络结构,在当时取得了非常大的影响,因为网络的结构变得前所未有,它颠覆了大家对卷积网络的串联的印象和固定做法,采用了一种非常有效的 Inception 模块,得到了比 VGG 更深的网络结构,但是却比 VGG 的参数更少,因为其去掉了后面的全连接层,所以参数大大减少,同时有了很高的计算效率。\n", | |||||
"\n", | "\n", | ||||
"\n", | "\n", | ||||
"\n", | "\n", | ||||
"这是 googlenet 的网络示意图,下面我们介绍一下其作为创新的 inception 模块。" | |||||
"这是 googlenet 的网络示意图,下面我们介绍一下其作为创新的 Inception 模块。" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -17,9 +18,8 @@ | |||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"## Inception 模块\n", | "## Inception 模块\n", | ||||
"在上面的网络中,我们看到了多个四个并行卷积的层,这些四个卷积并行的层就是 inception 模块,可视化如下\n", | |||||
"\n", | "\n", | ||||
"\n" | |||||
"在上面的网络中,我们看到了多个四个并行卷积的层,这些四个卷积并行的层就是 Inception 模块\n" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -32,7 +32,7 @@ | |||||
"3. 一个 1 x 1 的卷积加上一个 5 x 5 的卷积,作用和第二个一样\n", | "3. 一个 1 x 1 的卷积加上一个 5 x 5 的卷积,作用和第二个一样\n", | ||||
"4. 一个 3 x 3 的最大池化加上 1 x 1 的卷积,最大池化改变输入的特征排列,1 x 1 的卷积进行特征提取\n", | "4. 一个 3 x 3 的最大池化加上 1 x 1 的卷积,最大池化改变输入的特征排列,1 x 1 的卷积进行特征提取\n", | ||||
"\n", | "\n", | ||||
"最后将四个并行线路得到的特征在通道这个维度上拼接在一起,下面我们可以实现一下" | |||||
"最后将四个并行线路得到的特征在通道这个维度上拼接在一起,下面是PyTorch的实现一下" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -70,7 +70,7 @@ | |||||
"outputs": [], | "outputs": [], | ||||
"source": [ | "source": [ | ||||
"# 定义一个卷积加一个 relu 激活函数和一个 batchnorm 作为一个基本的层结构\n", | "# 定义一个卷积加一个 relu 激活函数和一个 batchnorm 作为一个基本的层结构\n", | ||||
"def conv_relu(in_channel, out_channel, kernel, stride=1, padding=0):\n", | |||||
"def Conv_ReLU(in_channel, out_channel, kernel, stride=1, padding=0):\n", | |||||
" layer = nn.Sequential(\n", | " layer = nn.Sequential(\n", | ||||
" nn.Conv2d(in_channel, out_channel, kernel, stride, padding),\n", | " nn.Conv2d(in_channel, out_channel, kernel, stride, padding),\n", | ||||
" nn.BatchNorm2d(out_channel, eps=1e-3),\n", | " nn.BatchNorm2d(out_channel, eps=1e-3),\n", | ||||
@@ -91,28 +91,28 @@ | |||||
}, | }, | ||||
"outputs": [], | "outputs": [], | ||||
"source": [ | "source": [ | ||||
"class inception(nn.Module):\n", | |||||
"class Inception(nn.Module):\n", | |||||
" def __init__(self, in_channel, out1_1, out2_1, out2_3, out3_1, out3_5, out4_1):\n", | " def __init__(self, in_channel, out1_1, out2_1, out2_3, out3_1, out3_5, out4_1):\n", | ||||
" super(inception, self).__init__()\n", | " super(inception, self).__init__()\n", | ||||
" # 第一条线路\n", | " # 第一条线路\n", | ||||
" self.branch1x1 = conv_relu(in_channel, out1_1, 1)\n", | |||||
" self.branch1x1 = Conv_ReLU(in_channel, out1_1, 1)\n", | |||||
" \n", | " \n", | ||||
" # 第二条线路\n", | " # 第二条线路\n", | ||||
" self.branch3x3 = nn.Sequential( \n", | " self.branch3x3 = nn.Sequential( \n", | ||||
" conv_relu(in_channel, out2_1, 1),\n", | |||||
" conv_relu(out2_1, out2_3, 3, padding=1)\n", | |||||
" Conv_ReLU(in_channel, out2_1, 1),\n", | |||||
" Conv_ReLU(out2_1, out2_3, 3, padding=1)\n", | |||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
" # 第三条线路\n", | " # 第三条线路\n", | ||||
" self.branch5x5 = nn.Sequential(\n", | " self.branch5x5 = nn.Sequential(\n", | ||||
" conv_relu(in_channel, out3_1, 1),\n", | |||||
" conv_relu(out3_1, out3_5, 5, padding=2)\n", | |||||
" Conv_ReLU(in_channel, out3_1, 1),\n", | |||||
" Conv_ReLU(out3_1, out3_5, 5, padding=2)\n", | |||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
" # 第四条线路\n", | " # 第四条线路\n", | ||||
" self.branch_pool = nn.Sequential(\n", | " self.branch_pool = nn.Sequential(\n", | ||||
" nn.MaxPool2d(3, stride=1, padding=1),\n", | " nn.MaxPool2d(3, stride=1, padding=1),\n", | ||||
" conv_relu(in_channel, out4_1, 1)\n", | |||||
" Conv_ReLU(in_channel, out4_1, 1)\n", | |||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
" def forward(self, x):\n", | " def forward(self, x):\n", | ||||
@@ -144,7 +144,7 @@ | |||||
} | } | ||||
], | ], | ||||
"source": [ | "source": [ | ||||
"test_net = inception(3, 64, 48, 64, 64, 96, 32)\n", | |||||
"test_net = Inception(3, 64, 48, 64, 64, 96, 32)\n", | |||||
"test_x = Variable(torch.zeros(1, 3, 96, 96))\n", | "test_x = Variable(torch.zeros(1, 3, 96, 96))\n", | ||||
"print('input shape: {} x {} x {}'.format(test_x.shape[1], test_x.shape[2], test_x.shape[3]))\n", | "print('input shape: {} x {} x {}'.format(test_x.shape[1], test_x.shape[2], test_x.shape[3]))\n", | ||||
"test_y = test_net(test_x)\n", | "test_y = test_net(test_x)\n", | ||||
@@ -155,14 +155,14 @@ | |||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"可以看到输入经过了 inception 模块之后,大小没有变化,通道的维度变多了" | |||||
"可以看到输入经过了 Inception 模块之后,大小没有变化,通道的维度变多了" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
"cell_type": "markdown", | "cell_type": "markdown", | ||||
"metadata": {}, | "metadata": {}, | ||||
"source": [ | "source": [ | ||||
"下面我们定义 GoogLeNet,GoogLeNet 可以看作是很多个 inception 模块的串联,注意,原论文中使用了多个输出来解决梯度消失的问题,这里我们只定义一个简单版本的 GoogLeNet,简化为一个输出" | |||||
"下面我们定义 GoogLeNet,GoogLeNet 可以看作是很多个 Inception 模块的串联,注意,原论文中使用了多个输出来解决梯度消失的问题,这里只定义一个简单版本的 GoogLeNet,简化为一个输出" | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -177,40 +177,40 @@ | |||||
}, | }, | ||||
"outputs": [], | "outputs": [], | ||||
"source": [ | "source": [ | ||||
"class googlenet(nn.Module):\n", | |||||
"class GoogleNet(nn.Module):\n", | |||||
" def __init__(self, in_channel, num_classes, verbose=False):\n", | " def __init__(self, in_channel, num_classes, verbose=False):\n", | ||||
" super(googlenet, self).__init__()\n", | |||||
" super(GoogleNet, self).__init__()\n", | |||||
" self.verbose = verbose\n", | " self.verbose = verbose\n", | ||||
" \n", | " \n", | ||||
" self.block1 = nn.Sequential(\n", | " self.block1 = nn.Sequential(\n", | ||||
" conv_relu(in_channel, out_channel=64, kernel=7, stride=2, padding=3),\n", | |||||
" Conv_ReLU(in_channel, out_channel=64, kernel=7, stride=2, padding=3),\n", | |||||
" nn.MaxPool2d(3, 2)\n", | " nn.MaxPool2d(3, 2)\n", | ||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
" self.block2 = nn.Sequential(\n", | " self.block2 = nn.Sequential(\n", | ||||
" conv_relu(64, 64, kernel=1),\n", | |||||
" conv_relu(64, 192, kernel=3, padding=1),\n", | |||||
" Conv_ReLU(64, 64, kernel=1),\n", | |||||
" Conv_ReLU(64, 192, kernel=3, padding=1),\n", | |||||
" nn.MaxPool2d(3, 2)\n", | " nn.MaxPool2d(3, 2)\n", | ||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
" self.block3 = nn.Sequential(\n", | " self.block3 = nn.Sequential(\n", | ||||
" inception(192, 64, 96, 128, 16, 32, 32),\n", | |||||
" inception(256, 128, 128, 192, 32, 96, 64),\n", | |||||
" Inception(192, 64, 96, 128, 16, 32, 32),\n", | |||||
" Inception(256, 128, 128, 192, 32, 96, 64),\n", | |||||
" nn.MaxPool2d(3, 2)\n", | " nn.MaxPool2d(3, 2)\n", | ||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
" self.block4 = nn.Sequential(\n", | " self.block4 = nn.Sequential(\n", | ||||
" inception(480, 192, 96, 208, 16, 48, 64),\n", | |||||
" inception(512, 160, 112, 224, 24, 64, 64),\n", | |||||
" inception(512, 128, 128, 256, 24, 64, 64),\n", | |||||
" inception(512, 112, 144, 288, 32, 64, 64),\n", | |||||
" inception(528, 256, 160, 320, 32, 128, 128),\n", | |||||
" Inception(480, 192, 96, 208, 16, 48, 64),\n", | |||||
" Inception(512, 160, 112, 224, 24, 64, 64),\n", | |||||
" Inception(512, 128, 128, 256, 24, 64, 64),\n", | |||||
" Inception(512, 112, 144, 288, 32, 64, 64),\n", | |||||
" Inception(528, 256, 160, 320, 32, 128, 128),\n", | |||||
" nn.MaxPool2d(3, 2)\n", | " nn.MaxPool2d(3, 2)\n", | ||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
" self.block5 = nn.Sequential(\n", | " self.block5 = nn.Sequential(\n", | ||||
" inception(832, 256, 160, 320, 32, 128, 128),\n", | |||||
" inception(832, 384, 182, 384, 48, 128, 128),\n", | |||||
" Inception(832, 256, 160, 320, 32, 128, 128),\n", | |||||
" Inception(832, 384, 182, 384, 48, 128, 128),\n", | |||||
" nn.AvgPool2d(2)\n", | " nn.AvgPool2d(2)\n", | ||||
" )\n", | " )\n", | ||||
" \n", | " \n", | ||||
@@ -261,7 +261,7 @@ | |||||
} | } | ||||
], | ], | ||||
"source": [ | "source": [ | ||||
"test_net = googlenet(3, 10, True)\n", | |||||
"test_net = GoogleNet(3, 10, True)\n", | |||||
"test_x = Variable(torch.zeros(1, 3, 96, 96))\n", | "test_x = Variable(torch.zeros(1, 3, 96, 96))\n", | ||||
"test_y = test_net(test_x)\n", | "test_y = test_net(test_x)\n", | ||||
"print('output: {}'.format(test_y.shape))" | "print('output: {}'.format(test_y.shape))" | ||||
@@ -301,7 +301,7 @@ | |||||
"test_set = CIFAR10('../../data', train=False, transform=data_tf)\n", | "test_set = CIFAR10('../../data', train=False, transform=data_tf)\n", | ||||
"test_data = torch.utils.data.DataLoader(test_set, batch_size=128, shuffle=False)\n", | "test_data = torch.utils.data.DataLoader(test_set, batch_size=128, shuffle=False)\n", | ||||
"\n", | "\n", | ||||
"net = googlenet(3, 10)\n", | |||||
"net = GoogleNet(3, 10)\n", | |||||
"optimizer = torch.optim.SGD(net.parameters(), lr=0.01)\n", | "optimizer = torch.optim.SGD(net.parameters(), lr=0.01)\n", | ||||
"criterion = nn.CrossEntropyLoss()" | "criterion = nn.CrossEntropyLoss()" | ||||
] | ] | ||||
@@ -0,0 +1,17 @@ | |||||
# 深度学习 | |||||
深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。 | |||||
区别于传统的浅层学习,深度学习的不同在于: | |||||
* 强调了模型结构的深度,通常有5层、6层,甚至10多层的隐层节点; [ | |||||
* 明确了特征学习的重要性。也就是说,通过逐层特征变换,将样本在原空间的特征表示变换到一个新特征空间,从而使分类或预测更容易。与人工规则构造特征的方法相比,利用大数据来学习特征,更能够刻画数据丰富的内在信息。 | |||||
通过设计建立适量的神经元计算节点和多层运算层次结构,选择合适的输人层和输出层,通过网络的学习和调优,建立起从输入到输出的函数关系,虽然不能100%找到输入与输出的函数关系,但是可以尽可能的逼近现实的关联关系。使用训练成功的网络模型,就可以实现我们对复杂事务处理的自动化要求。 | |||||
典型的深度学习模型有[卷积神经网络(convolutional neural network)](1_CNN)、深度置信网络(Deep Belief Network, DBN)、堆栈自编码网络(stacked auto-encoder network)、循环神经网络(Recurrent Neural Network)、对抗生成网络(Generative Adversarial Networks,GAN)等。 | |||||
## 参考资料 | |||||
* [深度学习 – Deep learning](https://easyai.tech/ai-definition/deep-learning/) | |||||
* [深度学习](https://www.jiqizhixin.com/graph/technologies/01946acc-d031-4c0e-909c-f062643b7273) | |||||