一行一行讲解深度学习代码(一)保姆级教程!!!如何看懂一个开源深度学习项目的代码

您所在的位置:网站首页 歌曲谱怎么看懂图片 一行一行讲解深度学习代码(一)保姆级教程!!!如何看懂一个开源深度学习项目的代码

一行一行讲解深度学习代码(一)保姆级教程!!!如何看懂一个开源深度学习项目的代码

2024-07-12 13:08| 来源: 网络整理| 查看: 265

在这里插入图片描述

欲练阅读源码之功,需读此宝典,全篇共五式,读罢必功力大增。此宝典历经千年风霜,如今才得以重见天日,在此赠与各位看官… …(扯)

学习深度学习,必备技能就是读懂开源深度学习项目代码,然而对于深度学习来说,代码结构是没有一个统一标准的。 一方面,代码结构取决于开发者自身的编程观念和水平,另一方面,不同规模的项目,本身需要的结构也是很不一样的。深度学习项目代码,小到几百行的测试demo,大到成千万行的开源项目,读起来方法肯定各有不同。 因此,想要读懂一个深度学习项目的代码,并非一件易事。 那么,本文就带大家一起学习,如何快速看懂一个深度学习项目代码,至少是能够大致了解项目是如何搭建和运行的,这对于我们弄懂项目有很大帮助。

文章目录 第一式——开门大吉:高效获取源码(一)找到Github地址1.源码网站2.其他方法 (二)Github下载源码1.方法一:使用 “Download ZIP” 按钮2.方法二:使用 Git 克隆项目(推荐)3.方法三:使用 GitHub Desktop 第二式——通览全局:了解项目结构(一)擒贼先擒王:关键之处(二)一例胜千言:一个例子 第三式——虎口掏心:找到入口文件(一)呼朋唤友:引入模块(二)添砖加瓦:参数设置1.创建一个解析器——创建 ArgumentParser() 对象2.添加参数——调用 add_argument() 方法添加参数3.解析参数——使用 parse_args() 解析添加的参数4.例子 (三)高屋建瓴:主程序运行 第四式——庖丁解牛:分层解析代码(一)第一层:训练、测试、预测,一应俱全1.初始化类(`__init__`)2.构建模型(`_build_model`)3.获取数据(`_get_data`)4.选择优化器(`_select_optimizer`)5.选择损失函数(`_select_criterion`)6.验证(`vali`)7.训练(`train`)8.测试(`test`)9.预测(`predict`)10.一批数据输入(`_process_one_batch`) (一)第二层:数据、模型、工具,多多益善1.数据(`data`)2.模型(`models`)3.工具(`utils`)4.选择优化器(`_select_optimizer`) 第五式——拨云见日:一键运行代码(一)龟速前进:本地Pycharm运行1.配置环境:巧妇难为无锅之炊2.输入参数:星星一火可以燎原 (二)一飞冲天:GPU服务器运行(谷歌Colab)1.上传谷歌云盘2.创建Notebook3.环境配置4.运行代码 (三)剑斩乱麻:遇见Bug怎么办? 附录:源码资源

第一式——开门大吉:高效获取源码

找源码是一门技术,有的项目或者论文直接给出了Github地址,这无疑是最好的,不过有的论文并没有给出源码,有可能是未开源项目,也有可能是需要咱们自己找。接下来,就为大家分享一下获取源码的方法。

(一)找到Github地址 1.源码网站

这里分享两个寻找论文源码的网站: (1)https://paperswithcode.com/ 网站左上角输入名字,便会出来结果,然后点击code部分即可。 (2)https://www.catalyzex.com/paper/arxiv:1701.04099 和第一个网站类似的操作。

2.其他方法

如果是经典文章,那可以在源码网上进行搜索,如果是比较新的文章,可以采用如下三种方法: (1)在google搜索该论文的名称或者第一作者的姓名,找到该作者的个人学术主页。在他的主页上看看他是否公开了论文的代码。 (2) 在google搜索该论文中算法的名字+code或者是某种语言,如python等。这是因为阅读这篇论文的科研人员不少,有的人读完会写代码并公布出来。 (3)邮件联系第一作者。

(二)Github下载源码 1.方法一:使用 “Download ZIP” 按钮

(1)打开你想要下载代码的 GitHub 项目页面。 (2)点击项目主页右上方的绿色按钮,上面标有 “Code”。 在这里插入图片描述 (3)选择 “Download ZIP”。 (4)下载将以 ZIP 文件的形式开始。一旦下载完成,你可以解压该 ZIP 文件,并在本地使用代码。

2.方法二:使用 Git 克隆项目(推荐)

使用Git的详细方法,可以参考一篇博客:http://t.csdnimg.cn/ZhEOb ,下面做简要介绍:

(1)首先,确保本地已经安装了 Git。如果你没有安装 Git,请从 https://git-scm.com/downloads 进行下载并安装。 (2)打开命令行终端或者 Git Bash 终端(如果你使用的是 Windows)。 (3)移动到你想要将代码下载到的文件夹中,使用以下命令:

cd /path/to/your/desired/directory

上述路径选择,cd 后面是你想要保存下载文件的具体路径,当然,还有一种方法是直接在你要存储的文件夹右键然后选择Open Git bash here。 (4)在 GitHub 项目页面中,点击 “Code” 按钮,并复制项目的 URL。 在这里插入图片描述 (5)回到终端,输入以下命令来克隆代码库:

git clone https://github.com/czasg/pywss.git

运行效果如下图: 在这里插入图片描述 然后Git 将会将代码库中的内容下载到你刚才指定的文件夹中。 在这里插入图片描述 一般网速比较好的时候是选择方法一,如果方法一下载存在困难,则方法二是最佳选择!

3.方法三:使用 GitHub Desktop

(1)如果你喜欢使用图形界面的软件,你可以安装 GitHub Desktop。 (2)打开 GitHub Desktop,登录你的 GitHub 账户。 (3)点击 “File” > “Clone Repository”,然后选择你要下载的项目,并选择一个本地文件夹来保存项目的代码。

第二式——通览全局:了解项目结构 (一)擒贼先擒王:关键之处

我们在阅读一些典型论文或者项目的代码时,常常摸不到头脑,因为项目结构看起来非常的复杂,代码结构组织的方式各不相同,但是,总的来说,一个深度学习项目代码所囊括的无非就是这几个方面:

1. 数据集读取、预处理与加载 2. 模型与网络层定义 3. 模型训练、测试与保存

这些是项目中最重要之处,除此之外,还会有配置、检查点、优化、日志之类的内容。

(二)一例胜千言:一个例子

一个常用的项目结构如下:

--project_name/ :项目名 ----data/:数据集 --------__init__.py ----datasets/:数据相关操作,如加载数据 --------__init__.py --------data_loader.py:加载数据 ----layers/:网络模型层 --------__init__.py --------layer1.py:第1层 --------layer2.py:第2层 ----models/:backbone模型 --------__init__.py --------a_model.py:a模型 --------b_model.py:b模型 ----exp/:包含定义、训练、验证、测试和预测方法 --------__init__.py --------exp_main.py:包含定义、训练、验证、测试和预测方法 ----configs/:配置文件 --------__init__.py --------config.py:方便超参数搜索等 ----utils/:用到的功能函数,可以是日志、评价指标计算等等 --------__init__.py --------utils.py:功能函数 --------metrics.py:评价指标计算 ----logs/:日志文件 --------__init__.py ----scripts/:脚本文件 --------__init__.py ----checkpoints/:保存的模型权重 --------__init__.py --------checkpoints.pt:保存的模型权重文件 ----model_hub/:预训练模型权重 --------__init__.py --------basic_model.pt:预训练好的模型权重文件 ----main.py:主程序 ----requirements.txt:需要的python依赖 ----environment.yml:环境信息 ----readme.md:项目说明

要点说明:

__init__.py:一个目录如果包含了__init__.py文件,那么它就变成了一个包。该文件可以为空,也可以定义包的属性和方法,但它必须存在。datasets:数据相关操作,比如用Dataset封装数据集,再用Dataloader实现数据并加载。layers:layers文件夹放的是模型所需要的层,不同model可能需要同样的网络层,为了保证模型代码的简洁性,单独列一个文件夹定义。models:一般而言,核心的代码都是以model命名,或者就是以它这个模型的名字命名。可以有多个模型,一个模型一个.py文件。exp:包含定义、训练、验证、测试、保存和预测方法,这些也可以放到main中,但是为了main的简洁性,单独设置一个文件夹进行定义。关于模型保存,Pytorch可以通过torch.save()函数将训练的模型保存为.pth/.pt/.pkl文件,Keras中训练的模型可以保存为.h5文件configs:包含了一些预定义的配置文件,用于训练和测试深度学习模型。这些配置文件包含了模型架构、损失函数、优化器、训练和测试的超参数等,通过修改这些配置文件,可以方便地调整模型的参数和超参数,如将需要配置的参数均放在这个文件中,比如batchsize,transform,epochs,lr等超参数,以满足不同的需求和任务。utils:通常是存放深度学习中常用的工具函数或类的文件夹,这些工具函数或类可以被多个深度模型共用,提高代码的复用性与可维护性,通常包括数据预处理函数、模型评估函数、损失函数等。scripts:脚本文件集合,脚本文件是函数命令的集合。针对不同的任务,可以运行不同的脚本文件。checkpoints:断点保存,保存模型权重,防止程序突然终止丢失权重文件。model_hub:预训练好的模型权重, 是一个通过大量数据上进行训练并被保存下来的网络。可以将其通俗的理解为前人为了解决类似问题所创造出来的一个模型,有了前人的模型,当我们遇到新的问题时,便不再需要从零开始训练新模型,而可以直接用这个模型入手,进行简单的学习便可解决该新问题。main.py:主程序,解析命令行传递超参数,执行exp中的训练、验证、测试、预测方法。requirements.txt:需要的python依赖,可以在terminal中输入pip install -r requirements.txt命令快速在所使用环境中安装依赖。environment.yml:用于定义和创建 Conda 环境的配置文件。它通常包含了项目所需的所有依赖项及其版本信息。可以使用该文件快速配置conda环境,具体使用方法可见:如何使用environment.yml文件配置conda环境readme.md:一种说明文件,通常随着一个软件而发布,里面记载有软件的描述或注意事项。一般来说,开源项目的readme里作者都会写明如何使用代码和进行部署,这可以帮助我们实现这个项目。

不同项目之间的代码架构不同,所以这个结构只是一个样例供大家参考,还是要根据具体项目分析其架构。

不过了解了一个深度学习项目代码所囊括的几个方面,就能以不变应万变,正所谓孙悟空遇上如来佛祖——纵有七十二般变化,也难逃手掌心。

第三式——虎口掏心:找到入口文件

从现在开始,我们的讲解全部基于一个具体的项目:基于Informer预测股票价格,这个项目的源码我放在文章的最后,大家有需要的请自取~

打开项目以后,从运行入口开始阅读,一般来说,项目入口都是在第一层目录中的,带有main或者run字眼的,找到入口,我们就开始分析入口文件具体的内容。

(一)呼朋唤友:引入模块

在本项目中,入口文件是main_informer.py,打开该文件,首先看到的是各种import。

#导入命令行选项、参数和子命令解析器模块,供接下来的参数定义 import argparse #导入toch模块,深度学习项目必用模块 import torch #导入informer模块,提供接下来的训练、测试、预测方法 from exp.exp_informer import Exp_Informer (二)添砖加瓦:参数设置

在训练卷积神经网络时需要预定义很多参数,例如batch_size, backbone,dataset,dataset_root等等,这些参数多而且特别零散;如果我们最初不把这些参数定义,到时候修改是一件特别麻烦的事情,需要逐个修改;所以这个时候用到了python的add_argument()很好的规避了这些问题。接下来,对argparse使用步骤进行讲解:

1.创建一个解析器——创建 ArgumentParser() 对象

使用 argparse 的第一步是创建一个 ArgumentParser 对象,大多数对 ArgumentParser 构造方法的调用都会使用 description= 关键字参数。这个参数简要描述这个程序做什么以及怎么做。

parser = argparse.ArgumentParser(description='test') 2.添加参数——调用 add_argument() 方法添加参数

给一个 ArgumentParser 添加程序参数信息是通过调用 add_argument() 方法完成的。通常,这些调用指定 ArgumentParser 如何获取命令行字符串并将其转换为对象。这些信息在 parse_args() 调用时被存储和使用。

parser.add_argument('--sparse', action='store_true', default=False, help='GAT with sparse version or not.') parser.add_argument('--seed', type=int, default=72, help='Random seed.') parser.add_argument('--epochs', type=int, default=10000, help='Number of epochs to train.')

该方法的参数定义如下:

ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])

name or flags :选项字符串的名字或者列表,例如 foo 或者 -f, --foo。 action :命令行遇到参数时的动作,默认值是 store。如果action=‘store_true’,只要运行时该变量有传参就将该变量设为True。 store_const:表示赋值为const。 append:将遇到的值存储成列表,也就是如果参数重复则会保存多个值。 append_const:将参数规范中定义的一个值保存到一个列表。 count:存储遇到的次数;此外,也可以继承 argparse.Action 自定义参数解析。 nargs:应该读取的命令行参数个数,可以是具体的数字,或者是?号,当不指定值时对于 Positional argument 使用 default,对于 Optional argument 使用 const;或者是 * 号,表示 0 或多个参数;或者是 + 号表示 1 或多个参数。 const:action 和 nargs 所需要的常量值。 default:不指定参数时的默认值。 type:命令行参数应该被转换成的类型。 choices:输入值的范围,如add_argument(“–gb”, choices=[‘A’, ‘B’, ‘C’, 0])。 required:默认False, 若为 True, 表示必须输入该参数。 help:参数作用解释,如add_argument(“a”, help=“params means”) metavar:在 usage 说明中的参数名称,对于必选参数默认就是参数名称,对于可选参数默认是全大写的参数名称。 dest:解析后的参数名称,默认情况下,对于可选参数选取最长的名称,中划线转换为下划线。

在学习这一块的时候,我有一个问题,就是为什么参数名的定义前要有一个--,不知道大家有没有这样的问题,那么关于add_argument参数名的定义,我们一起来看一下解释:

#add_argument 说明 不带'--'的参数 是位置参数,调用脚本时必须输入值,且参数输入的顺序与程序中定义的顺序一致 '-'的参数 是可选参数,如add_argument("-a"),只能是1个字符,区分大小写,通常用于表示单字符的命令行选项,也称为短选项。短选项通常用于表示简单的开关或标志。例如,“-v” 可以表示启用详细输出。 '--'参数 参数别名,是可选参数,通常用于表示完整的命令行选项,也称为长选项。长选项通常用于提供更具描述性的选项名称和更丰富的配置选项。例如,“–verbose” 可以表示启用详细输出。

其实只要记住一点,带’- -‘的参数可以不提供输入(可选的),并且给值时候必须要声明参数名(相反地,不带’- -'的参数不用提供参数名,但必须但需输入值)。

如果不懂的话,请看下面这两个例子:

例一(不带’- -'):

import argparse parser = argparse.ArgumentParser(description='test') parser.add_argument('seed', type=int, default=72, help='Random seed.') parser.add_argument('epochs', type=int, default=10000, help='Number of epochs to train.') args = parser.parse_args() print(args.seed) print(args.epochs)

执行命令与运行结果

PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py usage: 00test.py [-h] seed epochs 00test.py: error: the following arguments are required: seed, epochs PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py 1 2 1 2 PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py 2 1 1 2 PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py seed 1 usage: 00test.py [-h] seed epochs 00test.py: error: argument seed: invalid int value: 'seed'

可见不带’- -'的参数必须要给出输入,是位置参数,必须按序输入,且不能指定变量名。

例二(带’- -'):

import argparse parser = argparse.ArgumentParser(description='test') parser.add_argument('--seed', type=int, default=72, help='Random seed.') parser.add_argument('--epochs', type=int, default=10000, help='Number of epochs to train.') args = parser.parse_args() print(args.seed) print(args.epochs)

执行命令与运行结果

PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py 72 10000 PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py 1 2 usage: 00test.py [-h] [--seed SEED] [--epochs EPOCHS] 00test.py: error: unrecognized arguments: 1 2 PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py --seed 1 1 10000 PS C:\Users\86185\PycharmProjects\DeepLearningModel> python 00test.py --epochs 2 --seed 1 1 2

可见带’- -'的参数可以不给出输入(会输出default值),是关键词参数,不用按序输入,必须指定变量名进行赋值。

通过这些讲解,相信大家一定对argparse添加参数有了更深的认知 ~

3.解析参数——使用 parse_args() 解析添加的参数

ArgumentParser 通过 parse_args() 方法解析参数。它将检查命令行,把每个参数转换为适当的类型然后调用相应的操作。在脚本中,通常 parse_args() 会被不带参数调用,而 ArgumentParser 将自动从 sys.argv 中确定命令行参数。

args = parser.parse_args() 4.例子

接下来通过一个例子感受下argparse添加参数的整体流程:

import argparse parser = argparse.ArgumentParser(description='test') parser.add_argument('--sparse', action='store_true', default=False, help='GAT with sparse version or not.') parser.add_argument('--seed', type=int, default=72, help='Random seed.') parser.add_argument('--epochs', type=int, default=10000, help='Number of epochs to train.') args = parser.parse_args() print(args.sparse) print(args.seed) print(args.epochs)

输出

False 72 10000 (三)高屋建瓴:主程序运行

好啦,过了参数这一关,我们终于来到了主函数 ~ 让我们一起看一下这段代码:

Exp = Exp_Informer for ii in range(args.itr): # setting record of experiments setting = '{}_{}_ft{}_sl{}_ll{}_pl{}_dm{}_nh{}_el{}_dl{}_df{}_at{}_fc{}_eb{}_dt{}_mx{}_{}_{}'.format(args.model, args.data, args.features, args.seq_len, args.label_len, args.pred_len, args.d_model, args.n_heads, args.e_layers, args.d_layers, args.d_ff, args.attn, args.factor, args.embed, args.distil, args.mix, args.des, ii) exp = Exp(args) # set experiments print('>>>>>>>start training : {}>>>>>>>>>>>>>>>>>>>>>>>>>>'.format(setting)) exp.train(setting) print('>>>>>>>testing : {}>>predicting : {}


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3