此文档已更新完毕

你可以通过右下角的齿轮切换夜间模式和阅读模式

《深度学习入门:基于Python的理论与实现》由日本作者斋藤康毅撰写,2020年3月经人民邮电出版社引入中国出版,是一部面向初学者的深度学习技术专著 。该书以Python3为核心工具,旨在通过数学理论与代码实践结合的方式,帮助读者系统性掌握深度学习基础知识。


Markdown学习

文档

探索Markdown

数学

  1. 乘法 $x\times y $
  2. 除法 $y\div x $
  3. 上标 $x^2 $
  4. 下标 log2xlog_2 x
  5. 分数 1x\frac{1}{x}
  6. 开方 x\sqrt{x}
  7. 积分 $$
  8. 极限 limx1x=0\lim_{x\to\infin}\frac{1}{x} = 0
  9. 块公式格式 limx\displaystyle \lim_{x\to\infin},\displaystyle可以让行内公式显示多行,如果不用这个指令,显示出来的公式会被压缩成单行。
  10. 积分 12f(x)=1\int_{-1}^{2}f(x) = 1

Anaconda学习

conda操作

  1. conda信息
    1
    conda info

环境操作

  1. 新建环境
    1
    2
    3
    conda create -n [环境名] python=[版本]
    conda create -n myenv
    conda create -n myenv python=3.11.4
  2. 激活环境
    1
    2
    conda activate [环境名]
    conda activate myenv
  3. 退出环境
    1
    conda deactivate
  4. 查看已创建的环境
    1
    conda env list
  5. 卸载环境
    -n其实就是–name
    -v其实就是–version
    1
    2
    conda env remove -n [name]
    conda env remove -n myenv

包操作

  1. 安装包(在环境中)
    1
    2
    3
    4
    conda install [name]
    conda install numpy
    conda install pandas=1.3.5
    conda install jupyter matplotlib scikit-learn (用空格分隔)
  2. 更新包(在环境中)
    1
    2
    conda update numpy
    conda update --all
  3. 卸载包(在环境中)
    1
    2
    conda uninstall [name]
    conda uninstall numpy
  4. 查看已下载的包
    全局环境就查看pkgs的包
    激活环境就查看当前环境的包
    1
    2
    conda list
    conda list -n myenv
  5. 搜索包
    1
    conda search numpy
  6. 清除包
    此命令可清除未使用的pkgs中的包,即清理缓存
    –all可以清理缓存
    1
    2
    conda clean --packages
    conda clean --all

Python学习

Python本体

  1. 类的操作
    创建类的方法的时候,在各方法中的第一个参数self(表示自己)是python的一个特色
    特殊的方法__init__叫做构造函数,会在生成类的实例时被调用一次
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Man:
    def __init__(self, name):
    self.name = name
    print("Initialized!")

    def hello(self):
    print("Hello "+self.name+"!")

    def goodbye(self):
    print("Goodbye "+self.name+"!")

    m = Man("David")
    m.hello()
    m.goodbye()

此处定义了新类Man,并用Man生成了实例m
类Man的构造函数会接收参数name,然后会用这个参数初始化实例变量self.name实例变量是存储在各个实例的变量。可以在self后面添加属性名来生成或访问实例变量

1
2
m.age = 21
print(m.age)

可以新增实例的属性,而不会报错

numpy学习

  1. numpy数组
  • 可以使用np.array([列表])来新建数组,类为numpy.ndarray
    数组内数据只能为同一个类型,而python的list可以有多个类型
    内含一个浮点数则为浮点型数组
  • 同化定理: 往浮点数数组里插入整形数,整形数会变为浮点数
    往整型数数组里插入浮点数,浮点数会被截断 100.9->100
    1
    2
    3
    4
    5
    6
    import numpy as np

    x = np.array([1,2.2,3,4])
    y = x / 2
    print(type(x))
    >><class 'numpy.ndarray'>
  1. 数组的运算
  • element-wise运算
    1
    2
    3
    4
    x = np.array([1,2,3])
    y = np.array([4,5,6])

    z = x + y
  1. 数组类型转换
    使用.astype()方法可以改变数组类型,但不改变原数组的类型

    1
    2
    3
    4
    5
    6
    7
    8
    import numpy as np

    x = np.array([1,2,3,4,5])
    y = x.astype(float)
    z = x.astype(bool)

    print(x.dtype,y.dtype,z.dtype)
    >int64 float64 bool

    共同改变定理: 只有当数组内全部元素都改变时,数组的数据类型才会改变

  2. 广播运算
    当向量和行列矩阵与矩阵做运算时,会被广播
    有可能会适配不了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import numpy as np

    a = np.array([[1,2],[3,4]])
    b = np.array([10,20])
    c = a*b

    print(c)
    >[[10 40]
    [30 80]]
    1
    2
    3
    arr1 = np.arange(3).reshape((3,1))
    arr2 = np.ones((3,5))
    arr3 = arr1*arr2
  3. N维数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import numpy as np

    a = np.array([[1,2],[3,4]])

    print(type(a))
    print(a.shape)
    print(a.dtype)

    ><class 'numpy.ndarray'>
    >(2, 2)
    >int64
  4. reshape方法
    reshape方法可以用于同维数组改变形状,也可以用于改变维度

    1
    2
    3
    4
    arr1 = np.arange(10)
    arr2 = arr1.reshape(5,2)
    arr3 = arr2.reshape(-1)
    print(arr1,arr2,arr3)
  5. arange函数
    arange是指array_range,可以用来创建递增的数组

    1
    2
    3
    arr1 = np.arange(10.0) #0.,1.,2.,3.,4.,5.,6.,7.,8.,9.
    arr2 = np.arange(10,20) #10,11,12,13,14,15,16,17,18,19
    arr2 = np.arange(1,21,2) #1,3,5,7,9,11,13,15,17,19
  6. ones和zeros函数
    shape的class为tuple(元组)
    注意ones和zeros生成的数组都为浮点数数组

    1
    2
    arr1 = np.ones(4)
    arr2 = np.zeros((1,2))
  7. 随机数组

    1
    2
    3
    4
    5
    arr1 = np.random.random((2,5)) #参数是形状,生成0-1均匀分布的浮点型数组。可以通过线性变换来实现任意范围
    arr2 = np.random.randint(10,100,(2,5))#范围和形状,这个用来生成整数的随机数组
    arr3 = np.random.normal(0,1,(2,3))#均值,标准差,形状,正态分布
    arr4 = np.random.randn((2,3))#形状,标准正态分布(即均值=0,标准差=1的正态分布)
    arr5 = np.random.choice([1,2,3,4],size = 3,replace = False)#replace为false时不会重复出现
  8. 矩阵切片
    用这个方法可以获得子式

    1
    2
    3
    4
    5
    6
    7
    arr1 = np.arange(1,21).reshape(4,5)
    arr2 = arr1[1:3,1:-1]#行切片,列切片
    arr3 = arr1[::3,::2]#跳跃采样
    arr4 = arr1[1,:]#采样第一行,列全都要,等于arr1[1],并且输出是一维数组
    arr5 = arr1[,2] #注意,这是错误的,正确的采样列的方法参考下面两个
    arr6 = arr1[:,2]#输出的是一维数组
    arr7 = arr1[:,2:3] #可以写两个冒号,也可以写一个,此时就输出的是矩阵了

    注意:数组切片仅是视图 修改arr2-arr7时,原数组arr1也会被修改

  9. copy方法

    1
    2
    arr1 = arange(10)
    arr2 = arr1[:3].copy()

    copy会创建新数组,这时修改arr2就不会修改arr1了

  10. 数组相等仅为绑定

    1
    2
    arr1 = arange(10)
    arr2 = arr1

    此时修改arr2,arr1会跟着变
    如果不想跟着变,可以使用copy方法

    1
    2
    arr1 = arange(10)
    arr2 = arr1.copy()
  11. 矩阵的转置
    转置方法仅仅对 矩阵(二维数组) 有效

    1
    2
    3
    arr1 = np.arange(1,4)
    arr2 = arr1.reshape((1,-1))
    arr3 = arr2.T
  12. 矩阵的翻转
    使用 np.flipud()np.fliplr()进行翻转操作
    对于一维数组,只能使用np.flipud()

  13. 数组的拼接
    可以使用np.concatenate([arr1,arr2,...])函数进行数组的拼接

    1
    2
    3
    4
    5
    arr1 = np.array([[1,2,3],[4,5,6]])
    arr2 = np.array([[7,8,9],[10,11,12]])

    arr3 = np.concatenate([arr1,arr2]) #默认axis=0,此时变为4行3列数组
    arr4 = np.concatenate([arr1,arr2],axis = 1) #此时变为2行6列数组 1,2,3,7,8,9

    矩阵和向量不能拼接,必须将向量升维

  14. 数组分割

    1
    2
    3
    4
    5
    6
    7
    arr = np.arange(10,100,10)

    arr1,arr2,arr3 = arr.split(arr,[2,6])#第二个参数为分割点
    #会被分割为:arr[0],arr[1]
    #arr[2],arr[3],arr[4],arr[5]
    #arr[6],arr[7],arr[8]

  15. 矩阵乘积
    混有向量的时候,结果一定为向量
    使用np.dot() 方法

    1. 两个向量相乘 在numpy中是合法的,最后会输出标量,由于混有向量,因此输出为一个向量,而不是(5,1)*(1,5)=(5,5)的矩阵
    1
    2
    3
    a = np.arange(5)
    b = np.arange(5)
    c = np.dot(a,b) #class:numpy.int64
    1. 向量和矩阵相乘
    1
    2
    3
    a = np.arange(5) #1x5
    b = np.arange(21).reshape(5,4) #5x4
    c = np.dot(a,b) #1x4
    1. 矩阵相乘
      正常运算即可
  16. 数学函数

    1. 绝对值函数: np.abs() ,参数可以是多维数组
    2. 三角函数: np.sin() np.cos() np.tan()
    3. 指数函数: np.exp()
    4. 对数函数: np.log() np.log2() np.log10()
    1
    2
    3
    4
    x = arange(0,10.1,0.1)
    y1 = np.log(x) #y1 = ln(x)
    y2 = np.log(x)/np.log(2) #y2=log2(x) 换底公式
    y3 = np.log(x)/np.log(10) #y3=log10(x)
  17. 聚合函数

    1. np.max()
    1
    2
    3
    4
    arr = np.random.random((2,3)) #arr为(2,3)的0-1随机数组
    arr1 = np.max(arr,axis = 0) #arr1为(1,3)
    arr2 = np.max(arr,axis = 1) #arr2为(1,2)
    arr3 = np.max(arr) #arr3 为标量
    1. 求和函数 np.sum() 求积函数 np.prod()
    1
    2
    3
    4
    arr = np.arange(10).reshape(2,5)
    arr1 = np.sum(arr,axis = 0) #(1,5)
    arr2 = np.sum(arr,axis = 1) #(1,2)
    arr3 = np.sum(arr) #标量
    1. 均值函数 np.mean() 标准差函数 np.std()
    2. 如果有缺失值,可以在函数名前加nan,np.nansum(),可以忽略缺失值
  18. 布尔型数组
    可用运算符>,>=,==,!=,<,<=,&,|,~ 。当布尔型数组作为同纬度的数组的索引时,可以用来筛选数组,结果为一维向量

    1. np.sum() 用在布尔型数组上时,作用为统计True的数量
    1
    2
    3
    arr = np.random.normal(0,1,10000)
    result = np.sum(np.abs(arr) < 1)
    #其中np.abs可以换成(arr>-1)&(arr<1)
    1. np.any(): 只要布尔型数组有一个True,就返回True
    1
    2
    3
    arr1 = np.arange(1,10)
    arr2 = np.flipud(arr1)
    print(np.any(arr1 == arr2))
    1. np.all(): 只有布尔型数组所有元素都是True,返回True
  19. np.where()实际上也利用了布尔型数组

    1
    2
    3
    arr = np.random.normal(500,70,1000)
    print(np.where(arr>650)[0])
    print(np.where(arr == np.max(arr))[0])#输出是一个元组,第一个元素是位置列表,第二个元素数据类型
  20. np.argmax() 可以获取数组的最大值的索引

  21. 花式索引

    1
    2
    3
    arr1 = np.arange(1,17).reshape((4,-1))
    print(arr1[[0,1],[0,1]]) #输出为一维向量

Matplotlib学习

  1. 基本的画图
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import numpy as np
    import matplotlib.pyplot as plt

    date_list = [1,2,3,4]
    stock1 = [4,8,2,6]
    stock2 = [10,12,5,3]

    Fig1 = plt.figure()
    plt.plot(date_list,stock1)
    plt.plot(date_list,stock2)
    plt.show()

深度学习

感知机

  1. AND门、OR门和NAND门
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    def AND(x1,x2):
    x = np.array([x1,x2])
    w = np.array([0.5,0.5])
    b = -0.7
    tmp = x*w + b
    if tmp <= 0:
    return 0
    elif tmp > 0 :
    return 1

    def OR(x1,x2):
    x = np.array([x1,x2])
    w = np.array([0.5,0.5])
    b = -0.3
    tmp = x*w + b
    if tmp <= 0:
    return 0
    elif tmp > 0 :
    return 1

    def NAND(x1,x2):
    x = np.array([x1,x2])
    w = np.array([-0.5,-0.5])
    b = 0.7
    tmp = x*w + b
    if tmp <= 0:
    return 0
    elif tmp > 0 :
    return 1
  2. XOR门
    1
    2
    3
    4
    5
    def XOR(x1,x2):
    s1 = NAND(x1,x2)
    s2 = OR(x1,x2)
    y = AND(s1,s2)
    return y

神经网络

一般而言,输出层的激活函数:回归问题用恒等函数,分类问题用softmax函数

  1. sigmoid函数

    H(x)=11+exH(x)=\frac{1}{1+e^{-x}}

    sigmoid激活函数是一个平滑的曲线,形状如下图
    特性为输入小时,输出接近0。输入大时,输出接近1。且值域为(0,1)
    sigmoid函数

    1
    2
    def sigmoid(x):
    return 1 / (1 + np.exp(-x))
  2. LeRU函数

    h(x)={x,(x>0)0,(x<0)h(x)=\begin{cases} x,(x>0)\\ 0,(x<0)\\ \end{cases}

    1
    2
    def ReLU(x):
    return np.maximum(0,x) #np.maximum会比较并输出较大的那个值
  3. 一个2,3,2,2的三层神经网络的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    def init_network(): #初始化网络
    network = {}
    network['W1'] = np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
    network['b1'] = np.array([0.1,0.2,0.3])
    network['W2'] = np.array([[0.1,0.4],[0.2,0.5],[0.3,0.6]])
    network['b2'] = np.array([0.1,0.2])
    network['W3'] = np.array([[0.1,0.3],[0.2,0.4]])
    network['b3'] = np.array([0.1,0.2])
    return network

    def forward(network,x): #前向函数
    W1,W2,W3 = network['W1'],network['W2'],network['W3']
    b1,b2,b3 = network['b1'],network['b2'],network['b3']

    a1 = np.dot(x,W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1,W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2,W3) + b3
    z3 = identity_function(a3)
    y = z3
    return y

    network = init_network()
    x = np.array([1,0.5])
    y = forward(network,x)

    print(y)
  4. softmax激活函数

    yk=eaki=1neaiy_k = \frac{e^{a_k}}{\sum_{i=1}^{n}e^{a_i}}

    1
    2
    3
    4
    def softmax(x):
    exp_x = np.exp(x)
    sum_exp_x = np.sum(exp_x)
    return (exp_x/sum_exp_x)
  5. 改进softmax函数(防止溢出问题)
    经过softmax后的数据总和为1,因此可以把softmax函数的输出解释为“概率”

    yk=eak+ci=1neai+cy_k = \frac{e^{a_k+c}}{\sum_{i=1}^{n}e^{a_i+c}}

    1
    2
    3
    4
    5
    def softmax(x):
    c = np.max(x)
    exp_x = np.exp(x - c)
    sum_exp_x = np.sum(exp_x)
    return (exp_x/sum_exp_x)
  6. 损失函数

    1. 均方误差(Mean Squared Error)

    E=12k(yktk)2yk:神经网络的输出tk:监督数据E = \frac{1}{2}\sum_k(y_k-t_k)^2\\ y_k:神经网络的输出\\ t_k:监督数据

    1
    2
    3
    4
    5
    def mean_squared_error(y,t):
    return 0.5 * np.sum((y-t)**2)

    y = [0.2,0.3,0.5]
    t = [0,0,1] #one-hot表示
    1. 交叉熵误差(Cross Entropy Error)

    E=ktkln(yk)=lnycyk:神经网络的输出tk:监督数据yctc=1对应的ycE = -\sum_kt_kln(y_k)=-lny_c\\ y_k:神经网络的输出\\ t_k:监督数据\\ y_c:t_c = 1对应的y_c

    E=1Nnktnklog(ynk)E=-\frac{1}{N}\sum_n\sum_kt_{nk}log(y_{nk})

    1
    2
    3
    4
    def cross_entropy_error(y,t):
    delta = 1e-7
    return -np.sum(t*np.log(y+delta))
    #delta 防止np.log(0) = -inf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #mini-batch的交叉熵误差
    def cross_entropy_error_onehot(y,t):
    delta = 1e-7
    if y.ndim == 1:
    y = y.reshape((1,-1)) #将一维向量变为二维的一行矩阵
    t = t.reshape((1,-1))
    batch_size = y.shape[0]
    return -np.sum(t*np.log(y+delta)) / batch_size

    def cross_entropy_error_notonehot(y,t):
    delta = 1e-7
    if y.ndim == 1:
    y = y.reshape((1,-1))
    t = t.reshape((1,-1))
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size),t] + delta))/batch_size
  7. 数值微分

    1
    2
    3
    def numerical_diff(f,x):#使用中心差分
    h = 1e-4
    return (f(x+h)-f(x-h))/(2*h)
  8. 数值梯度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def numerical_grad(f,x):
    h = 1e-4
    x = x.astype(float)
    #当x[i]=x_val+h时,由于int型数组不能接纳浮点数,所以需要将x改变为float型
    grad = np.zeros(x.shape)
    for i in range(x.size):
    x_val = x[i]
    x[i] = x_val + h
    f_1 = f(x)
    x[i] = x_val - h
    f_2 = f(x)
    x[i] = x_val
    grad[i] = (f_1-f_2)/(2*h)
    return grad
  9. 梯度下降法

    xn=xnηfxnx_n=x_n-\eta\frac{\partial f}{\partial x_n}

    1
    2
    3
    4
    5
    6
    7
    8
    def grad_desent(f,init_x,lr=0.01,step_num=100):
    x = init_x

    for i in range(step_num):
    grad = numerical_grad(f,x)
    x = x - lr * grad

    return x
  10. 乘法层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class MulLayer:
    def __init__(self):
    self.x = None
    self.y = None

    def forward(self,x,y):
    self.x = x
    self.y = y
    return x*y

    def backward(self,out_direct):
    x_direct = out_direct*self.y
    y_direct = out_direct*self.x

    return x_direct,y_direct
  11. 加法层

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class addLayer:
    def __init__(self):
    self.x = None
    self.y = None

    def forward(self,x,y):
    self.x = x
    self.y = y
    return x+y

    def backward(self,dout):
    return dout,dout
  12. 激活函数层

    1. ReLU函数

x,(x>0)\
0,(x<=0)\
\end{cases}

\frac{\partial h(x)}{\partial x}=\begin{cases}
1,(x>0)\
0,(x<=0)\
\end{cases}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ReLULayer:
def __init__(self):
self.mask = None

def forward(self,x):
self.mask = (x<=0)
out = x.copy()
out[self.mask] = 0

return out

def backward(self,dout):
dout[self.mask] = 0
return dout
2.Sigmoid函数
1
2
3
4
5
6
7
8
9
10
11
12
class sigmoidLayer:
def __init__(self):
self.out = None

def forward(self,x):
out = 1 / (1 + np.exp(-x))
self.out = out
return out

def backward(self,dout):
dx = dout * self.out * (1.0 - self.out)
return dx
3. Affine层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Affine:
def __init__(self, W, b):
self.W = W
self.b = b
self.x = None
self.dW = None
self.db = None

def forward(self, x):
self.x = x
out = np.dot(self.x, self.W) + self.b
return out

def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.dot(self.x.T, dout)
self.db = np.sum(dout, axis = 0)

return dx
4. Softmax With Loss 层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class softmaxWithLoss:
def __init__(self):
self.loss = None
self.y = None
self.x = None

def forward(self,x,t):
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error_onehot(y,t)

return self.loss

def backward(self, dout = 1):
batch_size = self.t.shape[0]
dx = (self.y - self.t) / batch_size

return dx
13. 使用反向传播计算梯度的2层神经网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class newTwoLayerNet:
def __init__(self,inputSize,outputSize,hiddenSize,weightInitStd = 0.1):

self.param = {}
self.param['W1'] = weightInitStd * np.random.randn((inputSize,hiddenSize))
self.param['b1'] = weightInitStd * np.zeros((hiddenSize))
self.param['W2'] = weightInitStd * np.random.randn((hiddenSize,outputSize))
self.param['b2'] = weightInitStd * np.zeros((outputSize))

self.layers = OrderedDict()
self.layers['Affine1'] = Affine(self.param['W1'],self.param['b1'])
self.layers['Relu1'] = ReLULayer()
self.layers['Affine2'] = Affine(self.param['W2'],self.param['b2'])

self.lastLayer = softmaxWithLoss()

def predict(self, x):
for layer in self.layers.values():
x = layer.forward(x)

return x #没有经过lastLayer,及x为得分

def loss(self, x, t):
y = self.predict(x)
return self.lastLayer.forward(y, t)

def accuracy(self, x, t):
y = self.predict(x)
if y.ndim != 1:
y = np.argmax(y, axis = 1)
elif y.ndim == 1:
y = np.argmax(y)

if t.ndim != 1:
t = np.argmax(t, axis = 1)
elif t.ndim == 1:
t = np.argmax(t)

return np.sum(y == t) / float(x.shape[0])

def gradient(self, x, t):

dout = 1
dout = self.lastLayer.backward(dout)

layers = list(self.layers.values()).reverse()
for layer in layers:
layer.backward(dout)

grads = {}
grads['W1'] = self.layers['Affine1'].dW
grads['b1'] = self.layers['Affine1'].db
grads['W2'] = self.layers['Affine2'].dW
grads['b2'] = self.layers['Affine2'].db

return grads

### 第六章 与学习相关的技巧 #### 6.1 参数的更新 1. SGD(stochastic gradient decent)随机梯度下降法 $$W\leftarrow W - \eta \frac{\partial L}{\partial W}

1
2
3
4
5
6
7
class SGD:
def __init__(self, lr = 0.1):
self.lr = lr

def update(self,params,grads):
for key in params.keys
params[key] -= self.lr * grads[key]
  1. Momentum法
    Momentum是动量的意思

    vαvηLWv\leftarrow \alpha v - \eta \frac{\partial L}{\partial W}

    WW+vW \leftarrow W + v

    WW表示要更新的权重参数,LW\frac{\partial L}{\partial W}表示损失函数关于W的梯度,η\eta表示学习率。vv对应物理上的速度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Momentum:
    def __init__(self, lr = 0.01, momentum = 0.9):
    self.lr = lr
    self.momentum = momentum
    self.v = None

    def update(self, params, grads):
    if self.v is None:
    self.v = {}
    for key, val in params.items():
    self.v[key] = np.zeros_like(val)

    for key in params.keys():
    self.v[key] = self.momentum * self.v[key] - self.lr * grads[key]
    params[key] += self.v[key]
  2. AdaGrad
    Ada来自Adaptive,意为“适当的”,采用学习率衰减的思想。

    hh+LW×LWh \leftarrow h +\frac{\partial L}{\partial W} \times \frac{\partial L}{\partial W}

    WWη1hLWW \leftarrow W - \eta \frac{1}{h} \frac{\partial L}{\partial W}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class AdaGrad:
    def __init__(self, lr = 0.01):
    self.lr = lr
    self.h = None

    def update(self, params, grads):
    if self.h is None:
    for key,val in params.items():
    self.h[key] = np.zeros_like(val)

    for key in params.keys():
    self.h[key] = self.h[key] + grads[key] * grads[key]
    params[key] -= params[key] - self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

6.2 权重的初始值

  1. 使用Sigmoid激活函数
    推荐使用Xavier初始值,使用标准差为1n\frac{1}{\sqrt{n}}的高斯分布
  2. 使用ReLU激活函数
    推荐使用Kaiming He初始值,使用标准差为2n\frac{2 }{\sqrt{n}}的高斯分布

6.3 Batch Normalization

Batch Norm就是以进行学习的Mini-Batch为单位,按Mini-Batch进行正规化。就是使数据分布的均值为0,方差为1的正规化。

μB1mi=1mxi\mu_B \leftarrow \frac{1}{m} \sum^m_{i=1}x_i

σB21mi=1m(xiμB)2\sigma^2_B\leftarrow \frac{1}{m} \sum^m_{i=1} (x_i-\mu _B)^2

x^ixiμBσB2+ϵ\hat{x}_i \leftarrow \frac{x_i-\mu _B}{\sqrt{\sigma^2_B+\epsilon}}

这里对mini-batch的m个输入数据B={x1,x2,...,xm}B=\{x_1,x_2,...,x_m\}求均值μB\mu_B和方差σB2\sigma^2_B
然后在对输入数据进行均值为0,方差为1的正规化。其中ϵ\epsilon是一个微小值(比如1e-7),是为了防止出现除以0的情况。

6.4 正则化

解决过拟合这个问题

  1. 过拟合发生的主要原因:

    • 模型拥有大量参数、表现力强
    • 训练数据少
  2. 权值衰减

  3. DropOut方法

6.5 超参数的验证

第七章 卷积神经网络

7.1 整体结构

7.2 卷积层

  1. 卷积运算
    卷积运算相当于图像处理中的“滤波器运算”

    OH=H+2PFHS+1OH=\frac{H+2P-FH}{S}+1

    OW=W+2PFWS+1OW=\frac{W+2P-FW}{S}+1

    输入大小为(H,W),滤波器大小为(FH,FW),输出大小为(OH,OW),填充为P,步幅为S输入大小为(H,W),滤波器大小为(FH,FW),输出大小为(OH,OW),填充为P,步幅为S

7.3 池化层

7.4 卷积层和池化层的运用

  1. 基于im2col的展开
    im2col是指image to column,就是从图像到一行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    """

    Parameters
    ----------
    input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据
    filter_h : 滤波器的高
    filter_w : 滤波器的长
    stride : 步幅
    pad : 填充

    Returns
    -------
    col : 2维数组
    """
    N, C, H, W = input_data.shape
    out_h = (H + 2*pad - filter_h)//stride + 1
    out_w = (W + 2*pad - filter_w)//stride + 1

    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
    col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))

    for y in range(filter_h):
    y_max = y + stride*out_h
    for x in range(filter_w):
    x_max = x + stride*out_w
    col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

    col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
    return col