[鱼书笔记]深度学习⼊门:基于Python的理论与实现个⼈笔记分享为了完成毕设, 最近开始⼊门深度学习.
在此和⼤家分享⼀下本⼈阅读鱼书时的笔记,若有遗漏,欢迎斧正!
若转载请注明出处!
⼀、感知机
感知机(perceptron)接收多个输⼊信号,输出⼀个信号。
如图感知机,其接受两个输⼊信号。其中θ为阈值,超过阈值神经元就会被激活。
感知机的局限性在于,它只能表⽰由⼀条直线分割的空间,即线性空间。多层感知机可以实现复杂功能。
⼆、神经⽹络
神经⽹络由三部分组成:输⼊层、隐藏层、输出层
1. 激活函数
激活函数将输⼊信号的总和转换为输出信号,相当于对计算结果进⾏简单筛选和处理。
如图所⽰的激活函数为阶跃函数。
1) sigmoid 函数
sigmoid函数是常⽤的神经⽹络激活函数。
其公式为:
h(x)=
1
1+e−x
如图所⽰,其输出值在 0到 1 之间。
2) ReLU 函数
ReLU(Rectified Linear Unit)函数是最近常⽤的激活函数。
3) tanh 函数
2. 三层神经⽹络的实现
该神经⽹络包括:输⼊层、2 个隐藏层和输出层。
def forward(network, x): # x为输⼊数据
# 第1个隐藏层的处理,点乘加上偏置后传⾄激活函数
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
# 第2个隐藏层的处理
a2 = np.dot(z1, W2) + b2
z2 = sigmoid(a2)
#输出层处理 identidy_function原模原样输出a3
a3 = np.dot(z2, W3) + b3
y = identify_function(a3)
return y # y为最终结果
3. 输出层激活函数
⼀般来说,回归问题选择恒等函数,分类问题选择softmax函数。softmax函数的公式:
y k=
e a k ∑n i=1e a i
假设输出层有n个神经元,计算第k个神经元的输出y k。
softmax函数的输出值的总和为 1。因此我们可以将它的输出解释为概率。
输出层神经元数量⼀般和设定类别数量相等。
4. ⼿写数字识别
使⽤ MNIST 数据集。
使⽤ pickle 包序列化与反序列化所需数据,可以加快读取速度。
正规化 Normalization:将数据限定到某个范围内。
批处理 Batch
将输⼊数据成批次打包,可以⼀次处理多张图⽚。
batch_size = 100
for in range(0, len(x), batch_size) # x为输⼊数据
x_batch = x[i:i+batch_size] # 切⽚处理,⼀次取batch_size张图⽚
y_batch = predict(network, x_batch)
p = np.argmax(y_batch, axis = 1)
三、神经⽹络的学习
学习是指从训练过程中⾃动获取最优权重参数的过程。
1. 数据驱动⽅式
从图像中提取特征量(SIFT、SURF 或 HOG),使⽤这些特征量将图像数据转换为向量,然后对转换后的向量使⽤机器学习中的 SVM、KNN 等分类器进⾏学习。
2. 损失函数
神经⽹络将损失函数作为指标来寻最优权重参数。
神经⽹络学习的⽬的就是尽可能地降低损失函数的值。
我们⼀般使⽤均⽅误差和交叉熵误差函数。
1) 均⽅误差
Mean Squared Error。
E=1
2
∑
k(y k−t k)2
y k表⽰神经⽹络的输出结果,t k表⽰正确解标签,k表⽰数据维度。one-hot表⽰:正确解标签表⽰为 1,其他标签表⽰为 0。
如:
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0] # 假设在进⾏数字识别,数字“2”为正确结果y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
2) 交叉熵误差
Cross Entropy Error
Processing math: 100%
E=−∑
k t k log y k
y k表⽰神经⽹络的输出结果,t k表⽰正确解标签。
3) mini-batch 学习
如果我们要求所有训练数据的平均损失函数,以交叉熵误差为例,则为:
E=−1
N
∑
n
∑
k t nk log y nk
我们可以从全部数据中选出⼀部分,作为全部数据的代表。这⼀部分就是 mini-batch。
好⽐抽样调查。
train_size = x_train.shape[0] # 训练集的全部数据个数
batch_size = 10 #mini-batch的⼤⼩
batch_mask = np.random.choice(train_size, batch_size)#该函数从train_size个数字随机挑选batch_size个数x_batch = x_train[batch_mask]学编程可以自己做软件吗
t_batch = t_train[batch_mask]
3. 数值微分
1) 导数
使⽤中⼼差分来近似求解导数。
def numerical_diff(f, x) #求函数f(x)在x处的导数
h = 1e-4 #微⼩值
return (f(x+h)-f(x-h)) / (2 * h)
2) 梯度
由全部变量的偏导数汇总成的向量称为梯度。
如,对于函数f(x,y)=x2+y2 ,其在 (x,y) 处的梯度为 (∂f
∂x,
∂f
∂y)
其 Python 实现如下所⽰:
def numerical_gradient(f, x):
h = 1e-4
grad = np.zeros_like(x) #⽣成和变量组x⼤⼩相同的空数组存放梯度 for idx in range(x.size):
tmp_val = x[idx]
# f(x+h)
x[idx] = tmp_val + h
fxh1 = f(x)
# f(x-h)
x[idx] = tmp_val - h
fxh2 = f(x)
# 计算x[idx]的偏导数
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 还原值
梯度指向各点处的函数值减少最多的⽅向。
3) 梯度下降法
我们通常沿着梯度⽅向,使⽤梯度下降法循环寻损失函数的最⼩值。以上⾯提到的函数为例,⽤下⾯的式⼦不断更新梯度值:
x=x−η∂f
∂x y=y−η
∂f
∂y
η是⼀个更新量,称为学习率。学习率的初始值⼀般为 0.01 或 0.001⽤Python实现梯度下降法如下:
# f为函数,init_x为初始的变量组,学习率0.01,循环100次
def gradient_descent(f, init_x, learning_rate = 0.01, step_num = 100): x = init_x
for i in range(step_num):
grad = numerical_gradient(f, x)
x = x - lr*grad
return x
4. 神经⽹络的梯度
神经⽹络的学习要求损失函数关于权重参数的梯度。
⽐如⼀个 2*3 的权重参数W,损失函数为L ,则梯度∂L
∂W为:
W=(
w11w12w13
w21w22w23
)
∂L
∂W=(
∂L
∂w11
∂L
∂w12
∂L
∂w13
∂L
∂w21
∂L
∂w22
∂L
∂w23
)
5. 学习算法的实现
动态调整权重和偏置以拟合训练数据过程称为学习。共有四个步骤:
mini-batch:挑选mini-batch数据,⽬标是减少其损失函数的值。随机梯度下降法 SGD。计算梯度:计算各个权重参数的梯度
更新参数:将权重沿梯度⽅向进⾏微⼩更新
重复以上步骤
假设⼀个神经⽹络有两个权重参数W1 和W2,两个偏置参数b1,b2 :
class TwoLayerNet:
# 计算并返回⽹络输出值
def predict(self, x):
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
return y
# 计算损失值 t为正确解标签
def loss(self, x, t):
y = self.predict(x)
return cross_entropy_error(y, t)
# 计算梯度
def count_gradient(self, x, t):
loss_W = lambda W: self.loss(x, t)
# 计算梯度其他参数省略号
grads['W1'] = numerical_gradient(loss_W, params['W1'])
mini-batch的实现:
# 超参数
iters_num = 10000 # 下降次数
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
network = TwoLayerNetwork(input_size = 784, hidden_size = 50, output_size = 10)
for i in range(iters_num):
# 获取mini-batch
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 计算梯度
grad = unt_gradient(x_batch, t_batch)
# 更新参数
for key in ('W1','b1','W2','b2'):
network.params[key] -= leraning_rate * grad[key]
⼀个 epoch 表⽰学习中所有训练数据均被使⽤过的⼀次时的更新次数。
四、误差反向传播法 BP
使⽤误差反向传播法能够快速计算权重参数的梯度。
其基于链式法则。
加法结点的反向传播将上游的值原封不动地输出到下游。
乘法结点的反向传播乘以输⼊信号的翻转值。
1. 激活函数层的实现
1) ReLU
class Relu:
def __init__(self):
self.mask = None
# 前向传播
def forward(self, x):
self.mask = (x <= 0)
out = x.copy()
out[self.mask] = 0
return out
# 反向传播css动画无限循环
def backward(self,dout):
dout[self.mask] = 0
dx = dout
return dx
2) sigmoid
class Sigmoid:
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 * (1.0 - self.out) * self.out
return dx
2. Affine/Softmax 层的实现
1) Affine
神经⽹络正向传播的流程是根据输⼊数据和权重、偏置计算加权和,经过激活函数后输出⾄下⼀层。
其中进⾏的矩阵的乘积运算在⼏何学领域被称为仿射变换,因此我们将进⾏仿射变换的处理实现为Affine层。
class Affine:
def __init__(self, W, b):
self.W = W
self.b = b
最好的python入门教材self.x = None
self.dW = None
self.db = None
# 前向传播
def forward(self, x):
self.x = x
out = np.dot(x, self.W) + self.b
return out
# 反向传播
def backward(self, dout):
dx = np.dot(dout, self.W.T)
self.dW = np.T, dout)
self.db = np.sum(dout, axis = 0)
年轻人说的flex什么意思return dx
2) Softmax
softmax函数将输⼊值正规化后输出。考虑到这⾥也包含作为损失函数的交叉熵误差,因此称为 Softmax-with-Loss层。
class SoftmaxWithLoss:
def __init__(self):
self.loss = None
self.y = None
self.t = None
# 前向传播
def forward(self, x, t):
self.t = t
self.y = softmax(x)
self.loss = cross_entropy_error(self.y, self.t)
return self.loss
# 反向传播
def backward(self, dout = 1):
batch_size = shape[0]
dx = (self.y - self.t) / batch_size
return dx
五、与学习相关的技巧
1. 参数的更新
神经⽹络的学习⽬的是到使损失函数的值尽可能⼩的参数,这个过程被称为最优化 Optimization 常⽤⽅法有SGD、Momentum、AdaGrad和Adam等。
1) SGD
随机梯度下降法。
W←W−η∂L ∂W
class SGD:
def __init__(self, lr = 0.01):
self.lr = lr
def update(self, params, grads):
for key in params.keys():
params[key] -= self.lr * grads[key]
2) Momentum
SGD⽅法的缺点在于梯度的⽅向并没有志向最⼩值的⽅向。Momentum 是动量的意思。其数学式如下:
v←αv−η∂L
∂W W←W+v
表⽰物体在梯度⽅向上受⼒。
class Momentum:
def __init__(self, lr = 0.01, momentum = 0.9):
self.lr = lr
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] = um * self.v[key] - self.lr * grads[key]
params[key] += self.v[key]
3) AdaGrad
AdaGrad ⽅法保留了之前所有梯度值的平⽅和,会为参数的每个元素适当调整学习率。Ada 表⽰ Adaptive
h←h+∂L
∂W⨀
∂L
∂W W←W−η
1
√h
∂L
∂W
class AdaGrad:
def __init__(self, lr = 0.01):
self.lr = lr
self.h = None
def update(self, params, grads):
if self.h is None:
self.h = {}
for key, val in params.items():
self.h[key] = np.zeros_like(val)
for key in params.keys():
self.h[key] += grads[key] * grads[key]
params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7) 4) Adam
Adam是最近出现的⼀种参数更新⽅法,它会设置三个超三处。
2. 权重的初始值
各层的激活值的分布要求有适当的⼴度,否则可能会出现梯度消失现象。
1) Xavier 初始值
在⼀般的深度学习框架中, Xavier初始值已被作为标准使⽤。
在 Xavier 初始值中,如果前⼀层的节点数为n,则初始值使⽤标准差为
1
√n的分布。
node_num = 100
w = np.random.randn(node_num, node_num) / np.sqrt(node_num)
2) ReLU 的 He 初始值
当激活函数使⽤ ReLU 时,⼀般使⽤ He 初始值。如果前⼀层的节点数为 n ,则初始值使⽤标准差为
2
n 的⾼斯分布。
3. Batch Normalization
为了使各层的激活值的分布有适当的⼴度,使⽤ Batch Normalization ⽅法进⾏强制调整。
因此,我们需要在 Affine 层和激活函数层之间插⼊⼀个 Batch Norm 层。以进⾏学习时的 mini-batch 为单位进⾏正则化。
excel函数公式大全讲解 图表µB ←1
m m
∑
i =1x i σ2B ←1
m m
∑
i =1(x i −µB )2^
x i ←
x i −µB
σ
2
B +ε
对 mini-batch 的 n 个输⼊数据的集合 B =x 1,x 2,...,x m 求均值 µB 和 ⽅差 σ2
B 。
4. 过拟合的抑制
机器学习中,过拟合是⼀个很常见的问题。过拟合指的是只能拟合训练数据,但不能很好地拟合不包含在训练数据中的其他数据的状态。因此我们需要⼀些⽅法来抑制过拟合。权值衰减是⽅法之⼀。1) 权值衰减
对于所有权重,权值衰减⽅法都会为损失函数加上 1
2λW 2,即权重的 L 2 范数。
因此在求权重梯度的计算中,要为之前的误差反向传播法的结果加上正则化项的导数 λW 。2) Dropout
⽹络模型复杂时,使⽤Dropout ⽅法抑制过拟合。
Dropout 是⼀种在学习过程中删除神经元的⽅法。训练时,随机选出隐藏层的神经元并将其删除。被删除的神经元不再进⾏信号的传递。class Dropout:
def __init__(self, dropout_ratio = 0.5): self.dropout_ratio = dropout_ratio self.mask = None
def forward(self, x, train_flg = True): if train_flg:
self.mask = np.random.rand(*x.shape) > self.dropout_ratio return x * self.mask else:
return x * (1.0 - self.dropout_ratio)
def backward(self, dout): return dout * self.mask 5. 超参数的验证
超参数有神经元数量、batch ⼤⼩、学习率等。
我们不能使⽤测试数据评估超参数的性能,否则会造成过拟合
调整超参数时,必须使⽤超参数专⽤的确认数据,称为验证数据 validation data 六、卷积神经⽹络
CNN 的结构可以像积⽊⼀样进⾏组装。其中出现了卷积层 Convolution 和池化层 Pooling 。在 CNN 中,层的连接顺序是 :Convolution - ReLU - Pooling.Pooling 有时被省略。1. 卷积层
在全连接层中,数据的形状被忽略了。⽽卷积层可以保持形状不变。当输⼊数据是图像时,卷积层以 3 维数据的形式接收输⼊数据,并同样以 3 维数据的形式输出⾄下⼀次。
卷积层的输⼊输出数据称为特征图 Feature Map 。1) 卷积运算
卷积运算相当于过滤器。滤波器即输出中的权重W 。
滤波器会提取边缘或斑块等原始信息。
如图,输⼊数据⼤⼩是 (5,5),滤波器⼤⼩是 (3,3),输出⼤⼩是 (3,3)。2) 填充 Padding
在进⾏卷积层处理前,有时要像输⼊数据的周围填⼊固定数据来扩充数据。使⽤填充主要是为了调整输出的⼤⼩。
3) 步幅 Stride
应⽤滤波器的位置间隔称为步幅。
增⼤步幅后,输出表⼩;增⼤填充后,步幅变化。
假设输⼊⼤⼩为 (H ,W ) ,滤波器⼤⼩为 (FH ,FW ),输出⼤⼩为 (OH ,OW ),填充为 P ,步幅为 S 。则输出⼤⼩为:
OH =H +2P −FH S +1OW =W +2P −FW
S +1
4) 三维数据的卷积运算
以 3 通道 RGB 图像为例,其纵深⽅向上的特征图增加了。通道⽅向上有多个特征图时,会按通道进⾏输⼊数据和滤波器的卷积运算,并将结果相加。输⼊数据的通道数和滤波器的通道数要相同。
当有多个滤波器时,输出特征图同样有多层。2. 池化层
池化是缩⼩⾼、长⽅向上的空间运算。简单来说,池化⽤来精简数据。Max 池化上获取最⼤值的运算。⼀般来说,池化窗⼝⼤⼩会和步幅相同。3. 卷积层和池化层的实现
⼀个关键的函数为 im2col 。它将输⼊的三维数据展开为⼆维矩阵以适合滤波器。1) 卷积层
class Convolution:
def __init__(self, W, b, stride = 1, pad = 0): self.W = W self.b = b
self.stride = stride
√
√
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论