快速上手深度学习项目(一)

原博客连接:https://zhouyifan.net/2022/04/23/DLS-note-1/
github代码链接:https://github.com/SingleZombie/DL-Demos
原本的内容是这位大佬记录的吴恩达《深度学习专项》笔记以及代码。原内容是按照课程内容来的,内容很扎实,但是对于有了一点点深度学习的基础知识,要开始做项目的高年级本科或者研究生同学来说有点长了,所以我这里简单记录一下我学习之后觉得实战中比较有用的知识,对前面提到的人群来说可以起到一个快速上手的作用。同时原博客作者的代码写的很好,可以帮助我们理解pytorch等框架为什么这么设计,每一步都发生了什么。
基础知识
深度学习的基本概念这里不会介绍,基本概念不理解的建议先去看看科普视频,包括训练集,验证集,测试集,损失函数,常见损失函数表达式,神经网络,激活函数,常见激活函数表达式,梯度下降法。
数学知识这里也不会做介绍,包括基本的代数知识如矩阵、向量的运算,文章中不同函数梯度的求法等等。
这里会介绍以下python基础知识,但基本只做一个复习用,不会太细。
首先介绍深度学习项目的架构,一般深度学习项目由以下几个部分组成
- 数据预处理
- 定义网络结构
- 定义损失函数
- 定义优化策略
- 编写训练流程(一般就是前向传播,计算梯度,梯度回传三步)
- 测试模型精度
其中,我个人认为最复杂的地方在于数据预处理,因为其他步骤其实我们用pytorch等框架的话很好实现。而数据处理,需要对高维数据的变换以及python中数据处理的api比较熟练。这里先介绍常用的api
python元组、列表、集合、字典基本操作
元组、列表、集合和字典是python常用的内置容器,元组和列表是有序容器,集合和字典是无序容器。这些python容器都是有自己的数据结构和算法的,不是类C语言中底层的数组,这一点要注意,不要用数组这种原始的数据结构去理解这些高度封装的容器。这些容器由于其用法灵活但是速度慢,一般用于数据预处理早期组织样本数据,真正参与神经网络运算时都是使用numpy或者深度学习框架提供的矩阵(或者叫张量)。
列表
列表是一种有序可变的集合,可对其进行增删改查。注意列表中的元素不一定是同类型的,还是那句话,不要用类C语言中提供的底层数组去理解这种高度封装的容器。列表的符号是[]
,用[]
框起来的数据就是一个列表
列表的初始化有以下几种方法
1 | list = [] # 空列表初始化 |
列表的常用方法如下,以下方法基本囊括了常用的增删改操作,注意调用下列方法会改变列表自身的值,如果要得到一个新值而不改变原列表的值应该使用切片操作,或者调用别的函数而不是调用容器自身方法。
1 | list.append(obj) #末尾添加元素 |
列表中的元素可以使用[]
加下标访问,并且[]
也支持切片操作,切片操作的基本格式为
1 | list[start:end:step] |
表示切片的范围为step
。其中start
,end
,step
都可以是负数,前两者是负数时表示倒数第几个元素,-1
是倒数第一个元素,step
是负数时表示反向切片,即切片得到的新列表的排列顺序是从end
到start
,步长依然是step
绝对值
最后要介绍列表常用的脚本操作符
操作符 | 表达式 | 结果 | 描述 |
---|---|---|---|
+ | [1, 2, 3] + [4, 5, 6] | [1, 2, 3, 4, 5, 6] | 组合 |
* | ['Hi!'] * 4 | ['Hi!', 'Hi!', 'Hi!', 'Hi!'] | 重复 |
in | 3 in [1, 2, 3] | True | 元素是否存在于列表中 |
for...in... | for x in [1, 2, 3]: print x | 1 2 3 | 迭代 |
元组
元组是一种有序不可变的集合,用()
表示,其初始化方法有
1 | tup = () # 空元组初始化 |
元组其他的操作除了增删改以外,都和列表一致,不做过多赘述
字典
字典是可变容器,可存储任意类型对象; 包括键和值。可类比其他语言中的map,键不能重复,向字典中添加键相同的键值对, 后者的值会覆盖前者。键必须不可变, 一般用数字或者字符串,使用其他类做键需要这个类有__hash__
方法,这一点和java是一致的。字典用{}
表示,每个元素是一个键值对
字典的常见初始化方法有
1 | dict = {} # 空元组初始化 |
字典常见的方法有
1 | dict.clear() #删除字典内所有元素 |
更新或者添加键值对可以直接用[]
进行,例如
1 | tinydict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} |
集合
集合中的元素是无序的,不重复的,一般就用来去重,用{}
表示,初始化方法有以下几种。注意不能直接用{}
初始化空集合,这是初始化空字典用的。
1 | set = set() # 创建空集合必须用这种方式 |
集合支持数学上的集合操作,包括交并补以及对称差,运算符分别为&
|
-
^
1 | set('abracadabra') a = |
用in
判断一个元素是否在元组中。由于集合一般用的比较少,其他操作不过多赘述。
numpy基本操作
下面的副标题都是我自己瞎编的,好分类整理内容,不是什么官方名称。pytorch的Tensor用法与ndarray大差不差,有部分函数的名称不同而已
创建
NumPy的主要对象是同构多维数组,即ndarray
。在计算任务中需要使用矩阵或者向量运算时一般都使用numpy。创建np.array
的常用方法有以下几种,其中的order
参数指行优先和列优先,一般不用管
1 | numpy.array(a, dtype = None, order = None) #从已有数组创建(a可以是列表),当a是ndarray时该方法会克隆一个新的数组 |
上面是比较常用的创建方法,除此之外还有以下会见到的生成数组的方法,
1 | np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) #返回在[start,stop]区间内均匀分布的num个数字,endpoint表示返回数字中包含stop,retstep控制是否返回数字之间的间隔(公差) |
ndarray
常用的属性包括ndim
和shape
,ndim
表示数组的秩,返回一个数,一维数组(向量)返回1,二维数组(矩阵)返回2,三维数组返回3,以此类推。shape
返回数组的维度,是一个元组,元组的每一个元素代表一个轴(axis
)。对于矩阵来说,就是几行几列,行是第0个轴,列是第1个轴。
切片与索引
numpy的在每个维度上的切片操作与列表的切片操作一致,即arr[start:end:step]
,不同维度之间用逗号隔开,某个维度上用省略号表示该维度上不操作。以二维数组为例
1 | import numpy as np |
numpy还提供一些语法糖,支持更加高级的索引,比如整数索引、布尔索引,可以取出特定的元素或者特定的行、列。名字起的花里胡哨,但是只要记住索引的基本用法(中括号表示索引,逗号分割维度)就能看懂,这里不过多介绍。
数组操作
numpy常见的数组操作有修改形状、修改维度、翻转、连接和分割,并且有很多函数可以实现这些功能,这里介绍一些常用的方法,下面的方法没有特殊说明的话都是不改变原始数组的,但是生成的新数组可能和原数组公用一块内存空间,即当执行下面的操作时
1 | a = ap.array([1,2,3,4,5,6]) |
a[0]
的值也会改变,所以尽量不要去修改数值,如果要修改应该先查一下文档,或者试验一下。
方法是ndarray
自带的方法,可以用arr.f()
的方式调用,函数则是numpy某个模块函数,使用numpy.f(arr,...)
的形式调用。一般而言,数组的方法都会对应一个模块函数,后面介绍的方法或函数也是,具体我也没有考证,我这里只介绍我用着顺手的形式。
修改形状可以使用数组的reshape
和flatten
方法
1 | # arr.reshape(newshape, order='C') |
修改维度可以使用expand_dims
和squeeze
函数,注意这两个函数都不修改数据,只是单纯增加一个维度用来对齐数据。
1 | #expand_dims原型numpy.expand_dims(arr, axis) |
翻转一般就用转置,可以使用数组的T
方法或者np.transpose
函数
1 | #效果就是转置,注意T不用括号 |
连接数组可以使用concatenate
和stack
函数,用这两个函数不建议去看结果,容易绕进去,应该关注维度的变化
1 | # concatenate原型numpy.concatenate((a1, a2, ...), axis=0) |
分割数组可以使用切片或者split
函数
1 | # split原型为numpy.split(ary, indices_or_sections, axis=0) |
当然numpy数组也可以做一般的对单个元素增删查改,但是深度学习里面很少对单个元素操作,一般都是以矩阵的形式操作数据
统计操作
numpy求最值、求和、求平均、求中位数分别为np.amin
np.amax
np.sum
np.average
np.mean
np.median
,这些函数的用法可以归类为
1 | np.f(a, axis=None, keepdims=<no value>) |
a是待操作的数组
axis指定在哪一个轴上进行统计操作,为None是对整个数组a进行操作
keepdims,如果为True,将保持结果数组的维度数目与输入数组相同。如果为False(默认值),则会去除计算后维度为1的轴。
对于 np.average
,他还有个weights
参数用以计算加权平均数
注意上面是我总结的用法,并不是说这几个函数的原型如此。他们都还有一些其他参数
numpy排序操作如下
1 | # 原型sort(axis, kind='quicksort', order=None) |
大多数时候我们不需要对数组进行排序,而是只需要知道最大值和最小值,可以使用np.argmax(a,axis=0)
和np.argmin(a,axis=0)
函数,返回指定轴上最大(小)值的下标(数组)。
np.where
函数可以统计满足特定条件的元素的下标。除此之外,np.where
还可以用来打mask
用法如下
1 | #原型为np.where(condition, x, y),condition中需要包含一个待处理的ndarray(这里记为A),那么对于A中的每个元素,如果满足条件,则将这个元素替换为x,否则,将这个元素替换为y |
计算操作
numpy支持相同shape的数组进行+
-
*
/
**
运算,都是逐元素进行运算
numpy支持数组与标量进行+
-
*
/
**
运算,结果是标量与数组的每个元素进行运算
numpy中包含一些列数学函数,如三角函数、取整函数等,这些函数都是np.f(a)
形式作用于a
的每一个元素
numpy还支持以下线性代数计算
函数 | 描述 |
---|---|
dot | 两个数组的点积,即元素对应相乘。 |
vdot | 两个向量的点积 |
inner | 两个数组的内积 |
matmul | 两个数组的矩阵积 |
linalg.det | 数组的行列式 |
linalg.solve | 求解线性矩阵方程 |
linalg.inv | 计算矩阵的乘法逆矩阵 |
- Title: 快速上手深度学习项目(一)
- Author: Yizumi Konata
- Created at : 2024-07-13 12:05:26
- Updated at : 2024-07-15 23:47:56
- Link: https://zz12138zz.github.io/2024/07/13/dl1/
- License: This work is licensed under CC BY-NC-SA 4.0.