【DeepLearning】Basic Conceptions

2019-12-11  本文已影响0人  乞力马扎罗的雪人

Deep Learning

本文是学习深度学习入门时系统笔记。

参考资料:《deep learning》 MIT出版社和图灵参考丛书《深度学习入门(基于python的理论与实现)》。

[TOC]

Perception

多输入单输出逻辑元。两个过程:计算-->激活

典型逻辑电路AND,OR,NOT均可以表示为单层感知器,具有以下要素:

并有
y=z(wx+b)=perception(x)
根据真值表设定w,b后代码如下

def AND(x):
    w=np.array([0.5,0.5])
    theta=-0.7
    y=np.sum(x*w)+theta
    if y>0:
        return 1
    elif y<0:
        return 0

A simple network

Softmax

用于分类的输出层,输出0-1的实数而且所有的函数值之和为1,作为输出属于某类别的概率
y_k=\frac{exp(a_k)}{\sum_{i=1}^nexp(a_i)}
注意:softmax进行了e函数计算,容易发生溢出错误

改进为
y_k=\frac{exp(a_k+logC)}{\sum_{i=1}^nexp(a_i+log C)}

Loss function

衡量预测值与真值差距的性能指标,一般用均方差(mean squared error)或者交叉熵(Cross entropy error)
MSE=\frac{1}{2}\sum_k(y_k-t_k)^2

CEE=-\sum_k{t_k}log\ {y_k}

def mean_square_error(y,t):
    return(np.sum((y-t)^2)/2)

def cross_entropy_error(y,t):
    delta=1e-10# avoid log(0)
    return(np.sum(t*np.log(y+delta)))

def cross_entropy_error_batch(y,t,):
    if y.ndim=1:
        t=t.reshape(1,t.size)
        y=y.reshape(1,y.size)
batch_num=y.shape[0]
return(np.sum(t*np.log(y+1e-10))/batch_num)

为什么设定损失函数而不是识别精度作为指标?

识别精度是离散的,而损失函数是连续的,离散函数作为优化目标导致导数大部分为0,无法使用梯度相关的算法优化。

activiation function

表示计算值使得神经元被激活(由计算值到output)的方式。

Functions:

激活函数可以写成一个类,如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

    def backward(self, dout):
        dout[self.mask] = 0
        dx = dout

        return dx
    
    
# sigmoid
class Sigmoid:
    def __init__(self):
        self.out = None

    def forward(self, x):
        out = sigmoid(x)
        self.out = out
        return out

    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out

        return dx

Gradient

即数值微分在多元情况下。

# 求近似微分
def numerical_diff(f, x):
    h = 1e-4 # 0.0001
    return (f(x+h) - f(x-h)) / (2*h)

def numerical_grad(f,x):
    h=1e-4
    grad=np.zeros_like(x)
    
    for i in range(x.size):
        fx1=(float(x[i])+h)
        fx2=(float(x[i])-h)
        grad[i]=(fx1-fx2)/(2*h)
 
    return grad

def numerical_grad_batch(f, X):
    if x.ndim ==1:
        return numerical_grad(f,X)
    else:
        grad =np.zeros_like(X)
        for i,x in enumerate(X):
            grad[i]=numerical_grad(f,x)
        
    return grad

Gradient descent

x_0=x_0-\eta\frac{\partial{f}}{\partial{x_0}} \\ x_1=x_1-\eta\frac{\partial{f}}{\partial{x_1}}

计算步骤:

def gradient_descent(f,learn_rate):
    x=np.array([np.random.rand(),np.random.rand()])
    x_history=[]
    x_new=x-learn_rate*gd.numerical_grad(f,x)
    
    while ((x_new-x).all()>1e-5):
        x=x_new
        x_new=x-learn_rate*gd.numerical_grad(f,x)
        x_history.append(x_new.copy())

    return x_new,x_history

Gradient in DL

指的是损失函数关于权重的梯度
\frac{\partial{L}}{\partial{W}}=\left( \matrix{ \frac{\partial{L}}{\partial{W_{11}}}, \frac{\partial{L}}{\partial{W_{12}}}, \frac{\partial{L}}{\partial{W_{13}}}\\ \frac{\partial{L}}{\partial{W_{21}}}, \frac{\partial{L}}{\partial{W_{22}}}, \frac{\partial{L}}{\partial{W_{23}}} }\right)

Backforward

链式法则向后传播求取导数

此处应有计算图

Simple Layer

将神经网络层实现为一个单位。

Multiplelayer:

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

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

    def backward(self, dout):
        dx = dout * self.y
        dy = dout * self.x
        return dx, dy

Addlayer

加法层无需特别的初始化。

Affline

仿射变换:矩阵的乘积运算。

在affline层中务必注意变量的Shape。

完成的是y=wx+b操作。

class Affine:
    def __init__(self, W, b):
        self.W =W
        self.b = b
        
        self.x = None
        self.original_x_shape = None
        # 权重和偏置参数的导数
        self.dW = None
        self.db = None

    def forward(self, x):
        # 对应张量
        self.original_x_shape = x.shape
        x = x.reshape(x.shape[0], -1)
        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)
        
        dx = dx.reshape(*self.original_x_shape)  # 还原输入数据的形状(对应张量)
        return dx

SoftmaxwithLoss

带交叉熵损失层的softmax反向传播可以得到漂亮的结果
\frac{\partial{L}}{\partial{a_k}}=y_k-t_k
可见,反向传播中该结果直接衡量了与t标签的差距,即误差传播法。

[图片上传失败...(image-5945d8-1576044079302)]

Optimization

优化器一般定义为一个optimizer父类,在父类下定义不同的更新方法Update(grad,param),在神经网络中选取不同optimizer优化。

Stochastic gradient descent

随机梯度下降=在随机选取的mini-batch数据中实行梯队下降优化,即最简单的方法。

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] 

Momentum

v = \alpha v-\eta \frac{\partial{L}}{\partial{W}} \\ W=W+v

v表示速度,在梯度方向受力的动量增加

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]

AdaGrad

自适应学习率的优化方法,更新参数时除h能减少变动较大的元素学习率。
h=h+\frac{\partial{L}}{\partial{W}}*\frac{\partial{L}}{\partial{W}} \\ W=W-\eta\frac{1}{\sqrt{h}}\frac{\partial{L}}{\partial{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)

Adam

融合了momemum和adagrad(adaptive momemum),MIT DL教材189,论文来自

衰减矩估计来自适应学习。g为梯度,上面为有偏估计,下面是无偏修正。
s=\rho_1s+(1-\rho_1)g \ \ \ r=\rho_2r+(1-\rho_2)g \\ \hat{s}=\frac{s}{1-\rho_{1}^{t}} \ \ \hat{r}=\frac{r}{1-\rho_{2}^{t}}

class Adam:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None
        
    def update(self, params, grads):
        if self.m is None:
            self.m, self.v = {}, {}
            for key, val in params.items():
                self.m[key] = np.zeros_like(val)
                self.v[key] = np.zeros_like(val)
        
        self.iter += 1
        lr_t  = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)         
        
        for key in params.keys():
            self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
            self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])
            
            params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)
            

Regularization

过拟合可能来自于过大权值、数据量过少等等。

防止过拟合的措施

Dropout

随机删除(前向传播时x删除比例,后向传播时不返回值)部分隐藏层神经元。

weight decay

对较大的权值进行惩罚(在损失函数中加上惩罚项L2范数),L2范数即所有项的平方和。
Loss'=Loss+\frac{1}{2}\lambda W^2
其中\lambda 为衰减率。

Batch-Normalization

上一篇下一篇

猜你喜欢

热点阅读