文章目录

  • 前言
  • 一、问题描述
  • 二、前置知识和模型架构
    • 1.残差网络的基本知识
    • 2.模型架构
  • 二、编程实现
    • 1.Dataloader加载数据
    • 2.残差块的封装
    • 3.残差网络ResNets
    • 4.主控函数
  • 四、结果

前言

  本博客只是记录一下本人在深度学习过程中的学习笔记和编程经验,大部分代码是参考了【中文】【吴恩达课后编程作业】Course 4 - 卷积神经网络 - 第二周作业这篇博客,对其代码实现了复现,但是原博客中代码使用的是tensorflow,而我在学习中主要用到的是pytorch,所以此次作业我使用pytorch框架来完成。代码或文字表述中还存在一些问题,请见谅,之前的博客也是主要参考这个大佬。下文中的完整代码已经上传到百度网盘中,提取码:0qse。
  所以开始作业前,请大家安装好pytorch的环境,我代码是在服务器上利用gpu加速运行的,但是cpu版本的pytorch也能运行,只是速度会比较慢。

一、问题描述

  此次作业的主要目的是使用残差网络实现深层卷积神经网络完成分类问题,这次作业提供了两个分类问题的数据集,一个是二分类,一个是多分类,其实分类问题的解决思路都大同小异,这篇博客主要通过讲述多分类问题来对代码进行讲解。
  多分类问题也还是之前的识别手势代表的数字,这里就不再过多的描述。

  原博客中使用50层的残差网络,本博客使用的是34层的残差网络,pytorch代码主要参考博客:从头学pytorch(二十):残差网络resnet 。

二、前置知识和模型架构

1.残差网络的基本知识


  残差网络的基本原理和计算规则其实挺容易理解的,我们以一个残差块为基本单位进行研究:

  对于一个残差块而言,它与基本的神经网络的区别在于,残差块最后通过非线性函数激活输出的时候需要加上残差块最开始的输入,明白这一点后用编程实现起来其实并不复杂。

2.模型架构

  模型架构问题我并没有深究,这里主要通过论文中的两张图来进行简单的说明一下:

  上图来自原论文:Deep Residual Learning for Image Recognition 中截取下来,图中绘制了三种神经网络的基本结构:VGG-19,传统的卷积网络(Plain)和残差网络(ResNets),从结构来看,残差网络只是在传统的卷积网络中添加了跳跃连接(skip connection),我们可以以残差块为基本单元构造神经网络。

  论文中还给出了不同层数的残差网络对应的一个具体结构,这也是我编写代码的一个基本标准。以34层的残差网络为例,主要分为五个部分(最后还有全连接层等操作):

1.conv1:基本的卷积层,无残差操作,卷积核大小为7, 卷积核个数为64,步长为2
2.conv2_x:一个最大池化层和三个残差块,要求最后输出的通道数为64
3.conv3_x:四个残差块,最后输出的通道数为128
4.conv4_x:六个残差块,最后输出的通道数为256
5.conv5_x:三个残差块,最后输出的通道数为512

二、编程实现

1.Dataloader加载数据

import h5py
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
import matplotlib.pyplot as pltclass Image_Data(Dataset):def __init__(self, data_path):super(Image_Data, self).__init__()# 读取数据集dataset = h5py.File(data_path, "r")if data_path == "datasets/train_happy.h5" or data_path == "datasets/train_signs.h5":data_set_x_orig = np.array(dataset["train_set_x"][:])data_set_y_orig = np.array(dataset["train_set_y"][:])else:data_set_x_orig = np.array(dataset["test_set_x"][:])data_set_y_orig = np.array(dataset["test_set_y"][:])data_set_x_orig = data_set_x_orig.astype("float32") / 255data_set_y_orig = data_set_y_orig.astype("float32")self.x_data = torch.from_numpy(data_set_x_orig)self.y_data = torch.from_numpy(data_set_y_orig)self.len = self.y_data.size()[0]def __getitem__(self, item):return self.x_data[item], self.y_data[item]def __len__(self):return self.lendef get_shape(self):return self.x_data.size(), self.y_data.size()

  我这里使用通过继承Dataset类对数据进行了简单的封装操作,每个人的编程习惯不同,可以做相应的调整。

2.残差块的封装

class Residual(torch.nn.Module):def __init__(self, in_channels, out_channels, stride=1):super(Residual, self).__init__()self.stride = stride# 卷积层使用same填充,由于pytorch没有提供自动填充的操作,需要手算填充的大小self.conv1 = torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)self.bn1 = torch.nn.BatchNorm2d(out_channels)self.relu1 = torch.nn.ReLU(inplace=True)self.conv2 = torch.nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)self.bn2 = torch.nn.BatchNorm2d(out_channels)# 输入和输出通道数不同时,需要通过1x1卷积改变输入数据的通道数if in_channels != out_channels:self.conv1x1 = torch.nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride)else:self.conv1x1 = Nonedef forward(self, x):out1 = self.relu1(self.bn1(self.conv1(x)))out2 = self.bn2(self.conv2(out1))if self.conv1x1:x = self.conv1x1(x)out = self.relu1(out2 + x)return out

  残差块的大致结构为:

1.卷积conv1
2.Batch Normalization层
3.Relu
4.卷积conv2
5.Batch Normalization层
6.Relu(代码中复用了Relu,所以只定义了一个)

  残差块初始化时我们需要传入输入通道数,输出通道数和步长,输入通道数为你输入数据的通道数,输出通道数为想要输出的通道数,输出通道数的设置按照论文中给出的标准来实现。
  需要注意的是残差块的输入和输出的通道数可能不同,但是残差块内部的计算一般是不会改变数据的维度,所以第二个卷积函数初始化时输入和输出的通道数都为 out_channels 。
  在经过最后的Relu时,我们需要将当前的计算结果加上最开始的输入,这就要保证这两个值的维度相同,所以当输入和输出的通道数不同时我们需要利用1x1卷积改变输入数据的通道数:

 if in_channels != out_channels:self.conv1x1 = torch.nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride)else:self.conv1x1 = None

3.残差网络ResNets

class ResNet(torch.nn.Module):def __init__(self, in_channels, num_classes):super(ResNet, self).__init__()self.conv1 = torch.nn.Sequential(torch.nn.Conv2d(in_channels, 64, kernel_size=7, stride=2, padding=3),torch.nn.BatchNorm2d(64),torch.nn.ReLU(inplace=True))self.conv2 = torch.nn.Sequential(torch.nn.MaxPool2d(kernel_size=3, stride=2, padding=1),Residual(64, 64),Residual(64, 64),Residual(64, 64))self.conv3 = torch.nn.Sequential(Residual(64, 128, stride=2),Residual(128, 128),Residual(128, 128),Residual(128, 128),Residual(128, 128))self.conv4 = torch.nn.Sequential(Residual(128, 256, stride=2),Residual(256, 256),Residual(256, 256),Residual(256, 256),Residual(256, 256),Residual(256, 256))self.conv5 = torch.nn.Sequential(Residual(256, 512, stride=2),Residual(512, 512),Residual(512, 512))self.avg_pool = torch.nn.AdaptiveAvgPool2d(1)self.fc = torch.nn.Linear(512, num_classes)def forward(self, x):out = self.conv1(x)out = self.conv2(out)out = self.conv3(out)out = self.conv4(out)out = self.conv5(out)out = self.avg_pool(out)out = out.view(out.size()[0], -1)out = self.fc(out)return out

  设计残差网络主体的五个部分严格按照论文中给出的参数来设计,关于残差网络的初始化需要告知输入数据的通道数和多分类的类别个数。在经过五部分处理后,将输出进行平均池化,池化完成后展开成一维,并输入到一个全连接层中。

4.主控函数

import torchdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")from data_utils import Image_Data
from resnet_model import ResNet
import matplotlib.pyplot as plt
from torch.utils.data import DataLoadertrain_happy_data_path = "datasets/train_happy.h5"
train_signs_data_path = "datasets/train_signs.h5"test_happy_data_path = "datasets/test_happy.h5"
test_signs_data_path = "datasets/test_signs.h5"if __name__ == "__main__":# 初始化训练要使用到的参数num_epoch = 50learning_rate = 0.01batch_size = 32costs = []classes = 6# 加载数据train_data = Image_Data(train_signs_data_path)train_data_loader = DataLoader(train_data, shuffle=True, batch_size=batch_size)test_data = Image_Data(test_signs_data_path)test_data_loader = DataLoader(test_data, shuffle=True, batch_size=batch_size)# 初始化网络,图像的通道数为3m = ResNet(3, num_classes=classes)m = m.to(device)# 定义交叉熵损失函数loss_fn = torch.nn.CrossEntropyLoss()# 定义优化器optimizer = torch.optim.Adam(m.parameters(), lr=learning_rate)# 开始训练for epoch in range(num_epoch):cost = 0for i, data in enumerate(train_data_loader):img_data, img_label = dataimg_data = img_data.permute(0, 3, 1, 2)img_data = img_data.to(device)img_label = img_label.to(device)optimizer.zero_grad()y_pred = m.forward(img_data)loss = loss_fn(y_pred, img_label.long())loss.backward()optimizer.step()cost = cost + loss.cpu().detach().numpy()costs.append(cost / (i + 1))if epoch % 5 == 0:print("epoch=" + str(epoch) + ":  " + "loss=" + str(cost / (i + 1)))plt.plot(costs)plt.ylabel("cost")plt.xlabel('iterations (per tens)')plt.title("Learning rate =" + str(learning_rate))plt.show()

  当把模型封装完成后训练模型的代码其实千篇一律,我个人的处理习惯为:初始化训练参数,加载数据集,初始化模型,定义损失函数,定义优化器,开始训练,绘制损失曲线图。
  在模型内部我并未定义预测函数,训练完成后,在训练集和标签集上做预测时,需要将模型的计算结果再通过一个softmax层。

四、结果



  从结果来看,通过残差网络加深神经网络后,模型的表现效果变得非常好。

吴恩达深度学习课程第四章第二周编程作业(pytorch实现)相关推荐

  1. 吴恩达深度学习 | (24) 序列模型专项第二周学习笔记

    课程视频 吴恩达深度学习专项课程共分为五个部分,本篇博客将介绍第五部分序列模型专项的第二周课程:自然语言处理与词嵌入. 目录 1. 词汇表征 2. 使用词嵌入 3. 词嵌入的特性 4. 嵌入矩阵 5. ...

  2. Operations on word vectors-v2 吴恩达老师深度学习课程第五课第二周编程作业1

    吴恩达老师深度学习课程第五课(RNN)第二周编程作业1, 包含答案 Operations on word vectors Welcome to your first assignment of thi ...

  3. 吴恩达深度学习课程笔记之卷积神经网络(2nd week)

    0 参考资料 [1]  大大鹏/Bilibili资料 - Gitee.com [2] [中英字幕]吴恩达深度学习课程第四课 - 卷积神经网络_哔哩哔哩_bilibili [3]  深度学习笔记-目录 ...

  4. 吴恩达深度学习课程笔记(四):卷积神经网络2 实例探究

    吴恩达深度学习课程笔记(四):卷积神经网络2 实例探究 吴恩达深度学习课程笔记(四):卷积神经网络2 实例探究 2.1 为什么要进行实例探究 2.2 经典网络 LeNet-5 AlexNet VGG- ...

  5. github标星8331+:吴恩达深度学习课程资源(完整笔记、中英文字幕视频、python作业,提供百度云镜像!)...

    吴恩达老师的深度学习课程(deeplearning.ai),可以说是深度学习入门的最热门课程,我和志愿者编写了这门课的笔记,并在github开源,star数达到8331+,曾经有相关报道文章.为解决g ...

  6. 吴恩达深度学习课程的漫画版来了!(漫画、视频、笔记都可以下载了!)

    吴恩达深度学习课程,个人认为是对初学者最友好的课程,非常系统.初学者如果希望快速入门,建议从这门课开始.由于是视频课,除了课程笔记之外,可以先看看课程漫画,更有助于理解. 尽管是英文版,但英文水平达到 ...

  7. 360题带你走进深度学习!吴恩达深度学习课程测试题中英对照版发布

    吴恩达的深度学习课程(deepLearning.ai)是公认的入门深度学习的宝典,本站将课程的课后测试题进行了翻译,建议初学者学习.所有题目都翻译完毕,适合英文不好的同学学习. 主要翻译者:黄海广 内 ...

  8. 花书+吴恩达深度学习(二四)蒙特卡罗方法(重要采样,MCMC)

    文章目录 0. 前言 1. 重要采样 2. 马尔可夫链蒙特卡罗 MCMC 3. 不同峰值之间的混合挑战 如果这篇文章对你有一点小小的帮助,请给个关注,点个赞喔,我会非常开心的~ 花书+吴恩达深度学习( ...

  9. 花书+吴恩达深度学习(十四)卷积神经网络 CNN 之经典案例(LetNet-5, AlexNet, VGG-16, ResNet, Inception Network)

    目录 0. 前言 1. LeNet-5 2. AlexNet 3. VGG-16 4. ResNet 残差网络 5. Inception Network 如果这篇文章对你有一点小小的帮助,请给个关注, ...

  10. 神经网络隐藏层个数怎么确定_含有一个隐藏层的神经网络对平面数据分类python实现(吴恩达深度学习课程1第3周作业)...

    含有一个隐藏层的神经网络对平面数据分类python实现(吴恩达深度学习课程1第3周作业): ''' 题目: 建立只有一个隐藏层的神经网络, 对于给定的一个类似于花朵的图案数据, 里面有红色(y=0)和 ...

最新文章

  1. 2022-2028年中国无菌手套产业发展动态及投资趋势预测报告
  2. 优秀!这位70后硕士,入围中国工程院院士候选人!
  3. pandas读取csv文件,变换文件格式,并转换成numpy数组,取出数据
  4. DevOps \u0026 SRE 必备技能清单
  5. 1.1.4 错题知识整理(机器语言、汇编语言、正则语言、解释程序、编译、汇编)
  6. SAP Spartacus的Lock Focus Directive单元测试实现
  7. 中国自主可控的全数字实时仿真软件SkyEye支持龙芯CPU指令级仿真
  8. IP数量就是计算机数量吗,如何利用bash/python计算IP子网容纳计算机数量
  9. python-简单邮件报警
  10. FZU 2129 子序列个数 (递推dp)
  11. 反地理编码 高德地图_由中文地址返回点位坐标-地理编码脚本分享
  12. android 简单锁屏代码,【简单代码】默认锁屏代码第二弹~
  13. linux 下载git源码,在linux系统下Git源码系统的文件下载
  14. 记一次jstack线程诊断
  15. 【AI初识境】从头理解神经网络-内行与外行的分水岭
  16. 群晖NAS教程(二十二)、利用Docker安装minio
  17. IT男需要学习文哲史
  18. oracle 建分区索引_Oracle的分区表和Local索引创建与维护
  19. 光纤验收测试标准、参数及常用设备
  20. cocos2dx3.2打包apk

热门文章

  1. 计算机网络第七版-《软件工程》试题(第4套含答案)
  2. 伍德里奇计量经济学导论之计算机操作题的R语言实现(多元回归:估计)
  3. 计算机音乐与制谱,电脑音乐编辑、制谱与视唱练耳一本通
  4. wms开发语言c 还是java,专业WMS和普通WMS之间差异有什么呢?
  5. 搭建Hadoop环境(超详细)
  6. 分享一个NI软件卸载工具
  7. SFTP服务器文件下载
  8. Win10常用命令:定时关机(shutdown命令)
  9. archive.php 不起作用,PHP ZipArchive在Laravel中不起作用
  10. win10下安装Vm15添加虚拟机的总结