机器学习、深度学习总结

机器学习、深度学习总结

目前包括:
输入归一化、参数初始化、批归一化、Dropout、全连接层、激励函数、卷积层、池层、ResNet 、Inception网络、损失函数、正则化、多分类、梯度下降、SVM等

输入归一化

  • 为了减少迭代的次数,使用输入归一化,将输入改写成均值为0,范围一致的分布形式。
$\mu = \frac{1}{m}\sum_i x^{(i)}$ $\sigma^2 = \frac{1}{m}\sum_i (x_i - \mu)^2$ $x^{(i)}_{norm} = \frac{z^{(i)}-\mu}{\sqrt{\sigma^2 + \varepsilon}}$
- **图像归一化**,在TensorFlow中一般使用以下函数进行图像归一化以便于将每一个图片转换成均值为0方差为1:
tf.image.per_image_standardization(image)
#image:An n-D Tensor with at least 3 dimensions, the last 3 of which are the dimensions of each image.
$x = \frac{x - mean}{adjusted\_stddev}$
其中,$adjusted\_stddev = max(stddev, \frac{1}{\sqrt{N}})$,N为x的数目,stddev是x的标准差,使用$adjusted\_stddev$的目的是以防x为均分分布使得标准差为0。下面是方法的源码:
def per_image_standardization(image):
  """Linearly scales each image in `image` to have mean 0 and variance 1.
  For each 3-D image `x` in `image`, computes `(x - mean) / adjusted_stddev`,
  where
  - `mean` is the average of all values in `x`
  - `adjusted_stddev = max(stddev, 1.0/sqrt(N))` is capped away from 0 to
    protect against division by 0 when handling uniform images
    - `N` is the number of elements in `x`
    - `stddev` is the standard deviation of all values in `x`
  Args:
    image: An n-D Tensor with at least 3 dimensions, the last 3 of which are the
      dimensions of each image.
  Returns:
    A `Tensor` with same shape and dtype as `image`.
  Raises:
    ValueError: if the shape of 'image' is incompatible with this function.
  """
  with ops.name_scope(None, 'per_image_standardization', [image]) as scope:
    image = ops.convert_to_tensor(image, name='image')
    image = _AssertAtLeast3DImage(image)

    # Remember original dtype to so we can convert back if needed
    orig_dtype = image.dtype
    if orig_dtype not in [dtypes.float16, dtypes.float32]:
      image = convert_image_dtype(image, dtypes.float32)

    num_pixels = math_ops.reduce_prod(array_ops.shape(image)[-3:])
    image_mean = math_ops.reduce_mean(image, axis=[-1, -2, -3], keepdims=True)

    # Apply a minimum normalization that protects us against uniform images.
    stddev = math_ops.reduce_std(image, axis=[-1, -2, -3], keepdims=True)
    min_stddev = math_ops.rsqrt(math_ops.cast(num_pixels, image.dtype))
    adjusted_stddev = math_ops.maximum(stddev, min_stddev)

    image -= image_mean
    image = math_ops.div(image, adjusted_stddev, name=scope)
    return convert_image_dtype(image, orig_dtype, saturate=True)

参数初始化

  • 0初始化:
    • 所谓0初始化就是将所有的参数都初始化为零,但是由于初始化的值是一样的,它将不能破坏对称,以至于所有同源的参数的值将永远一样。
    • 具有相同激活函数的两个隐藏单元连接到相同单元,那么这些单元必须具有不同的初始参数。一旦他们具有相同的初始参数,然后应用到确定性损失和模型的确定性学习算法将一直以相同的方式更新这两个
  • 随机初始化:
    • 梯度爆炸: \(W>I\)
    • 梯度消失:\(W<I\)
  • Xavier初始化:根据前向传播公式\(z = \sum w_i x_i\)\(w\)\(x\)独立分布,我们可以求出方差\(Var(z) = n_xVar(w_i)Var(x_i)\), 如果我们希望\(Var(z) = Var(x)\),那么需要使\(n_xVar(w) = 1\)即,\(Var(w) = \frac{1}{n_x}\);在反向传播中\(dA^{[l-1]} = W^{[l]T}dZ^{[l]}\),设激励函数为线性且导数为1,那么\(Var(dz^{[l-1]}) = n_l Var(w) Var(dz^{[l]})\)。因此我们可以看出,在前向传播中,我们希望\(Var(w) = \frac{1}{n_{l-1}}\),在反向传播中我们希望\(Var(w) = \frac{1}{n_{l}}\)因此,在Xavier初始化中,我们令\(Var(w) = \frac{2}{n_{l-1} + n_l}\),即在均分分布(\(Var = \frac{(b-a)^2}{12}\))中
$w \sim U[-\frac{\sqrt{6}}{\sqrt{n_{l-1}+\sqrt{n_l}}}, \frac{\sqrt{6}}{\sqrt{n_{l-1}+\sqrt{n_l}}}]$
同样不可忽视的一点是,Xavier初始化中默认激励函数为线性 - He(MSRA)初始化:He初始化是在随机初始化的基础上,使得每一层的参数$W^{[l]}$经过缩放,使得$A^{[l]}$与X的均值类似,因此随机初始化的方差应为:$\sqrt{\frac{2}{n^{l-1}}}$,即默认激励函数为Relu 在一般情况下,我们不默认均值和方差是多少,由正向传播公式$z = \sum w_i a_i$可知:
$Var(z^{[l]}) = Var(\sum w_i a_i)$ $=n_l Var(w_i a_i)$ $=n_l E(\sum w_i a_i - E(\sum w_i a_i))^2$ $=n_l (E((\sum w_i a_i)^2 - 2(\sum w_i a_i)E(\sum w_i a_i) + ((\sum w_i a_i))^2))$ $=n_l(E(\sum w_i^2 a_i^2) - 2E(\sum w_i a_i)E(\sum w_i a_i) + (E(\sum w_i a_i))^2)$ $=n_l (E(\sum w_i^2 a_i^2) - (E(\sum w_i a_i))^2)$ $=n_l(E(w_i^2)E(a_i^2) - E(w_i)^2E(a_i)^2)$ $=n_l (E(a_i)^2(E(w_i^2) - E(w_i)^2))$ $=n_l E(a_i)^2Var(w_i)$
由Relu公式可知$a_i = max(0, z^{[l-1]})$
$E(a_i^2) = \frac{1}{2}E(z^{[l-1]2})$
又因为$E(z^{[l-1]}) = 0$
$E(a_i^2) = \frac{1}{2}E(z^{[l-1]2})=\frac{1}{2}E(z^{[l-1]2}) - E(z^{[l-1]})$ $E(a_i^2) = \frac{1}{2}Var(z^{[l-1]})$ $Var(z^{[l]}) = \frac{n_l}{2}Var(z^{[l-1]})Var(w_i)$
若使$Var(z^{[l]}) = Var(z^{[l-1]})$,则:
$Var(w_i) = \frac{2}{n_l}$
因此,W应该初始化为均值为0,方差为$\frac{2}{n_l}$的高斯分布:
$w \sim G[0, \sqrt{\frac{2}{n^{l-1}}}]$
  • W = 1的参数初始化还有什么?

批归一化(Batch Normalization-BN)

在隐藏层中的优化

$\mu = \frac{1}{m}\sum_i z^{(i)}$ $\sigma^2 = \frac{1}{m}\sum_i (z_i - \mu)^2$ $z^{(i)}_{norm} = \frac{z^{(i)}-\mu}{\sqrt{\sigma^2 + \varepsilon}}$ $\tilde{z}^{(i)} = \gamma z^{(i)}_{norm} + \beta$
  • 在TensorFlow的实现:计算:\(\frac{\gamma(x-\mu)}{\sigma}+\beta\)
tf.nn.batch_normalization(
    x, mean, variance, offset, scale, variance_epsilon, name=None
)

其中mean和variance由函数tf.nn.moments(..., keepdims=False)得到,这也是tf里计算mean和variance的函数。

  • BN global(除了输入限制为4D没发现什么重要的区别)
  • BN keras(还没看懂)

Dropout

Dropout是正则化的一种方式,由名字退出(drop out)可以看出,它是以随机除去神经元来使得减少某个神经元的依赖程度,达到可以使用正则化的方式。在应用过程中,我们设置一个新的变量\(D^{[l]}=[d^{[l](1)}...d^{[l](m)}]\)用以表示第l个隐藏层的D,其中每一个d(i)表示在第i个数据下的d,而d表示的是该神经元是否隐藏。因此它将是一个由0和1组成的向量。使用\(d^{[l](i)}=np.random.rand(a^{[l](i)}.shape)<keep\_prob\)来设置d和D。之后为了使得输出结构的均值保持不变,在使用了Dropout的隐藏层在正向传播求得\(A^{[ l ]}\) 之后还要再除以\(keep\_prob\)。并且在反向传播时也要将\(dA = \frac{dA}{keep\_prob}\)

全连接层

  • 前项传播
$Z^{[l]} = W^{[l]}A^{[l-1]} + b$ $A^{[l]} = g^{[l]}(Z^{[l]})$
- 反向传播
$dA^{[L]} = \frac{\partial loss}{\partial A^{[L]}}$ $dZ^{[l]} = dA^{[l]}\dot{g(Z^{[l]})}$ $dA^{[l-1]} = W^{[l]T}dZ^{[l]}$ $\frac{\partial L}{\partial W^{[l]}} = \frac{1}{m}\frac{\partial L}{\partial Z^{[l]}}A^{[l-1]T}$ $\frac{\partial L}{\partial b^{[l]}} = \frac{1}{m} \sum_{i = 1}^{m} dZ^{[l] (i)}$

卷积层

层数公式:

$n^{[l]} = \lfloor \frac{n^{[l-1]} + 2p^{[l]}-f^{[l]}}{s^{[l]}} +1 \rfloor$

1x1卷积层: 可以降维或者升维,一般用于减少参数

  • 空间卷积、反卷积、转置卷积?

Pool层

分为average pooling和max pooling

$n^{[l]} = \lfloor \frac{n^{[l-1]} + 2p^{[l]}-f^{[l]}}{s^{[l]}} +1 \rfloor$
- GAP与FC的关系: - Global average pooling:GAP的目的是替代FC用以解决FC层参数过多而产生的overfitting问题(GAP不需要参数),同时减少了从feature maps到FC的过渡,即提出了FC的黑箱特性,赋予了每层实际的意义。
Fig. FC vs GAP
GPA的数学模型很简单,是将一个$h\times w \times d$的三维特征,平均为$1 \times 1 \times d$的向量,即是将$h \times w$层平均为一个数。在Keras中的函数为:
tf.keras.layers.GlobalAveragePooling2D(
    data_format=None, **kwargs
)
Fig. FC vs GAP vs GMP
上图是FC、GAP、GMP的对比图,我们可以看出一开始GAP收敛速度慢,但是在40epoch之后由于overfitting的问题FC的准确率降低,而GAP准确率不受影响。

参考:

  1. Global average pooling--
  2. Global Average Pooling是否可以替代全连接层?
  3. tf.keras.layers.GlobalAveragePooling2D

ResNet Model

由于在神经网络很深的时候,会出现性能翻转的问题,即随着层数的增加,training error反而会增大(degradation problem),因此引用了ResNet。假设在一种网络A的后面添加几层形成新的网络B,如果增加的层级只是对A的输出做了个恒等映射(identity mapping),即A的输出经过新增的层级变成B的输出后没有发生变化,这样网络A和网络B的错误率就是相等的,也就证明了加深后的网络不会比加深前的网络效果差。

$a^{[l+2]} = g(z^{[l+2]} + a^{[l]})$
  • 在TensorFlow中的实现:
Fig. Resnet(v1) vs resnet(v2)

Resnet(v1)的特点是几个块,除第一个块内第一层stride=1,其它块内第一层stride=2,每深一块深度\(\times 2\),并使用相同stride的1x1卷积层将输入也改变为同深度的tensor。块内的卷积层相同,切没个两层有一个shotcut用以实现ResNet。本例每个块内有\(3 \times 2 = 6\)层,一共有\(3 \times 3 \times 2 + 2 = 20\)

    for stack in range(3):#number of stack, each stack contain 6 layers
        for res_block in range(num_res_blocks):
            strides = 1
            #can be seen in the resual block, the first layer(except the first stack) stride = 2
            if stack > 0 and res_block == 0:  # first layer but not first stack
                strides = 2  # downsample
            y = resnet_layer(inputs=x,
                             num_filters=num_filters,
                             strides=strides)
            #why there is an additional y here?,because we need to add the shotcut term, and notice that we donot use strides here
            y = resnet_layer(inputs=y,
                             num_filters=num_filters,
                             activation=None)
            if stack > 0 and res_block == 0:  # first layer but not first stack
                # linear projection residual shortcut connection to match
                # changed dims
                x = resnet_layer(inputs=x,
                                 num_filters=num_filters,
                                 kernel_size=1,
                                 strides=strides,
                                 activation=None,
                                 batch_normalization=False)
            x = tensorflow.keras.layers.add([x, y])
            x = Activation('relu')(x)
        num_filters *= 2

Resnet(v2):第一个捷径使用Conv2D(1), 之后的不经过卷积层。每个阶段开始,feature map将被步长为的卷积层减半,filters的数量增倍,在每个阶段中,每个卷积层有相同数目的filters和filters size。即:

  • Conv1:(32,32);16
  • Stage 0:(32,32);64
  • Stage 1:(16,16);128
  • Stage 2:(8,8);256
    for stage in range(3):
        for res_block in range(num_res_blocks):
            activation = 'relu'
            batch_normalization = True
            strides = 1
            if stage == 0:#first stage(block)
                num_filters_out = num_filters_in * 4
                if res_block == 0:  # first layer and first stage
                    activation = None
                    batch_normalization = False
            else:
                num_filters_out = num_filters_in * 2
                if res_block == 0:  # first layer but not first stage
                    strides = 2    # downsample

            # bottleneck residual unit
            y = resnet_layer(inputs=x,
                             num_filters=num_filters_in,
                             kernel_size=1,
                             strides=strides,
                             activation=activation,
                             batch_normalization=batch_normalization,
                             conv_first=False)
            y = resnet_layer(inputs=y,
                             num_filters=num_filters_in,
                             conv_first=False)
            y = resnet_layer(inputs=y,
                             num_filters=num_filters_out,
                             kernel_size=1,
                             conv_first=False)
            if res_block == 0:
                # linear projection residual shortcut connection to match
                # changed dims
                x = resnet_layer(inputs=x,
                                 num_filters=num_filters_out,
                                 kernel_size=1,
                                 strides=strides,
                                 activation=None,
                                 batch_normalization=False)
            x = tensorflow.keras.layers.add([x, y])

        num_filters_in = num_filters_out

Inception网络

使用多个相同长宽(可能不同深度)进行叠加,形成Inception网络。
-和ResNet的联系,实战?

损失函数

机器学习分为监督学习和无监督学习,他们之间的区别在于监督学习有数据和真实值,即X,Y;而监督学习只有数据,没有真实值,即X。其中监督学习分为线性回归和分类,而无监督学习只有分类。
线性回归主要是做预测,即使用数据集和真实值(以后已训练集来代替)用线性拟合来形成一条曲线。主要使用的损失函数式MSE(均方误差),即:

$loss = (h_{\theta}(x) - y)^2$ or $(\hat{y} - y)^2$
而分类问题有叫做逻辑回归主要用以区分类别,其中包含二分类和多分类是使用交叉熵(cross-entropy)来做损失函数,即:
$loss = -ylog\hat{y} - (1-y)log(1-\hat{y})$

损失函数问题:而为什么在线性回归中使用MSE而在逻辑回归中使用交叉熵作为损失函数:

  1. 从MSE和交叉熵的目的来说,MSE表示真值与预测值之间的距离;交叉熵表示预测概率分布与真实概率分布的问题,对于分类来说使用概率分布更加的合理。且对于线性回归问题有负数,log(-1.5)无法计算
  2. 在分类问题中,开始会使用Sigmoid函数作为激励函数,而如果将sigmoid函数带入到交叉熵之中的时候,会产生非凸函数,即有多个极点的函数,这是梯度下降所无法解决的问题。

激励函数

激励函数问题:sigmoid, Tanh, Relu的区别:

Fig. 1 sigmoid, tanh, relu
Sigmoid函数:$\delta(x) = \frac{1}{1+e^{-x}}$ 特点:函数取值在0-1之间,方便实现二分类,即(>0.5为1,否则为0) 缺点: 1. 正负值大的时候后有软饱和问题,即梯度小 2. exp计算量大 3. 只有与训练值的同号输出,有ziggle问题 - $\frac{dL}{dw_i} = \frac{dL}{dy}\frac{dy}{dw_i}$ $= \frac{dL}{dy}\frac{dy}{dz}\frac{dz}{dw_i}$ $= \frac{dL}{dy}y(1-y)xi$ 因此$dw_i$将于$x_i$同号

Tanh函数:\(tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}\)
特点:比起sigmoid来说优点是其中心对称
缺点:还是有软饱和问题;exp计算量大的问题
Relu函数:\(max(0,x)\)
特点:正数不饱和,负数硬饱和;比sigmoid和tanh比计算量小
缺点:非中心对称

正则化

正则化:在使用损失函数构建成本函数的时候有一项很重要的就是正则化。一般来说正则化分为两种:L1正则化和L2正则化

  • L1正则化:\(J_{\theta R_1} = J_{\theta} + \lambda \sum \|\theta_j\|\)
  • L2正则化:\(J_{\theta R_2} = J_{\theta} + \lambda \sum \theta_j^2\)
  • L1正则化目的是使参数更加稀疏,通俗来讲是是参数为0的项更多;L2正则化目的是减少参数的权重

二分类与多分类

输出之前
在说到逻辑回归问题时,它有二分类问题和多分类问题,那么他们的区别和联系是:

  • 一般使用sigmoid来处理二分类问题:\(\delta(x) = \frac{1}{1+e^{-x}}\)
  • 使用softmax函数来处理多分类问题:\(S(x_j) = \frac{e^{x_j}}{\sum^K_{k=1} e^{x_k}}\), j = 1 ... K

梯度下降

梯度下降:梯度下降是求解机器学习/深度学习问题的基础但是由于批梯度下降处理速度慢、计算量下降因此引入了mini-batch梯度下降之后出现了收敛震荡的问题,引出以下三种方法用以做梯度下降的加速。

  • Momentum:使用指数权重平均,为dw和db做平均
$V_{dw} = \beta V_{dw} + (1-\beta)dw$ $V_{db} = \beta V_{db} + (1-\beta)db$ $w = w - \alpha V_{dw}$ $b = b - \alpha V_{db}$
- RMSprop:Momentum是将$dw$,$db$做指数权重平均,而RMSprop是将$dw^2$和$db^2$做指数平均,而在迭代时,使用$\frac{dw}{\sqrt{\bar{dw^2}}+\varepsilon}$作为步进实现加速。
$S_{dw} = \beta S_{dw} + (1-\beta)dw^2$ $V_{db} = \beta S_{db} + (1-\beta)db^2$ $w = w - \alpha \frac{dw}{\sqrt{S_{dw}}+\varepsilon}$ $b = b - \alpha \frac{db}{\sqrt{S_{db}}+\varepsilon}$
- Adam(Momentum + RMSprop):Adam是将上述综合起来,但是由于指数平均初始几个指误差较大因此有做修改:
$V_{dw}^{correct} = \frac{V_{dw}}{1-\beta_1^t}$, $V_{db}^{correct} = \frac{V_{db}}{1-\beta_1^t}$ $S_{dw}^{correct} = \frac{S_{dw}}{1-\beta_2^t}$, $S_{db}^{correct} = \frac{S_{db}}{1-\beta_2^t}$ $w = w - \alpha \frac{V_{dw}^{correct}}{\sqrt{S_{dw}^{correct}}+\varepsilon}$ $b = b - \alpha \frac{V_{db}^{correct}}{\sqrt{S_{db}^{correct}}+\varepsilon}$

SVM

SVM(support vecter machine)支持向量机:SVM是从逻辑回归变化而来的,由于逻辑回归的损失函数为:

$loss = -ylog\hat{y} - (1-y)log(1-\hat{y})$
SVM中,将log函数改变为cost函数使得降低运算量方便之后kernel的使用且不适用激励函数,因此在svm中的损失函数为:
$loss= ycost_1(\theta^Tx) + (1-y)cost_2(\theta^Tx)$
由于损失函数,svm的决策边界是最大间隔分类器:由于输入$\theta^Tx$可以看做两个向量的点积,即向量$x$在向量$\theta$的投影乘$\|\theta\|$,即$p\|\theta\|$,当p越大的时候,$\|\theta\|$可以越小,因此为最大间隔分类。 在SVM中,除了直接使用$\theta^Tx$还可以使用$\theta^Tf$,其中f被称为kernel,它可以使线性的,也可以是非线性的。非线性一般使用高斯kernel,即:
$f = similarity(x,l) = exp(-\frac{\|x - l\|}{2\sigma^2})$
1. n>>m时,一般使用逻辑回归或svm线性 2. n小,m中等时,使用svm高斯 3. n小m大,一般使用逻辑回归或svm线性
posted @ 2020-02-28 10:43  x1aoo  阅读(346)  评论(0)    收藏  举报