机器学习:SVM、softmax、Dropout及最大池化max_pool介绍

一、利用线性SVM进行分类

train_data: (train_num, 3072)

训练流程

  1. 初始化权重W: (3072, 10) 梯度dW: (3072, 10)
  2. train_data和权重相乘得到score(10,)对应每个类别的分数
    2.1 对于每个score中的分数i,如果是正确的类别对应的score跳过
    2.2 如果是其他的类别,计算margin=score[i]-correct_score+1
    2.3 如果其他的margin大于零则loss+=margin; dW[:, i]+=X[i].T; dW[:, correct]-=X[i].T
  3. 得到平均的lossloss /= num_train; loss += 0.5 * reg * np.sum(W * W)
  4. 得到最终的梯度dW /= num_train; dW += reg * W

向量化上述过程

python 复制代码
scores = X.dot(W) # (num_train, num_class)
# 之前的correct类的下标是一个一个获取的,这里直接作为列向量
correct_class_scores = scores[range(num_train), list(y)].reshape(-1,1) #(num_train, 1)
# score和correct相减的时候会进行广播,这里要注意正确类别的margin也变成了1,而在上面的流程中是不计算的
margins = np.maximum(0, scores - correct_class_scores +1) # (num_train, num_class)
# 将正确类别的margin置为0
margins[range(num_train), list(y)] = 0
loss = np.sum(margins) / num_train + 0.5 * reg * np.sum(W * W)

# 用coeff_mat和训练数据矩阵相乘来得到梯度
coeff_mat = np.zeros((num_train, num_classes))
# 那些需要更新参数的位置的系数就是1,上面的流程中是dW[:, i]+=X[i].T,这里系数为1,然后下面再进行矩阵相乘,效果一样
coeff_mat[margins > 0] = 1
coeff_mat[range(num_train), list(y)] = 0
# 正确类别的梯度的是其他类别之和
coeff_mat[range(num_train), list(y)] = -np.sum(coeff_mat, axis=1)

dW = (X.T).dot(coeff_mat)
dW = dW/num_train + reg*W

问题

为什么在梯度检查的时候会出现个别较大的差错? 因为svm loss不是完全可导的,就像relu函数在0附近一样,越靠近0,分析梯度和数值梯度的差就越多。

将参数W进行可视化的结果是什么样的? W: (3072, 10), 重新reshape到(32, 32, 3, 10)最后的10代表10个分类器,前面的就是每个分类器可视化的结果,它像是每个类别的所有图像的一个模板(取了平均值,因为只有数值相近的时候平方才最大),如果某个类别的分数较高,那么它就越接近这个类图片的模板。

二、使用softmax进行分类

大体上和线性svm分类差不多,只是loss函数不一样。

使用循环来计算softmax的loss和梯度

python 复制代码
# 第i个数据
for i in xrange(num_train):
    scores = X[i].dot(W)
    shift_scores = scores - max(scores)
    # 这条数据计算出来的损失
    loss_i = - shift_scores[y[i]] + np.log(sum(np.exp(shift_scores)))
    loss += loss_i
    # 对于这条数据得到的score,每个类别的score都计算导数
    # 单个的score计算导数相当于更新这个类别对应的那个分类器的导数所以有[:, j]
    for j in xrange(num_classes):
        softmax_output = np.exp(shift_scores[j])/sum(np.exp(shift_scores))
        # 如果这个类别是正确的类别
        if j == y[i]:
            dW[:,j] += (-1 + softmax_output) *X[i] 
        else: 
            dW[:,j] += softmax_output *X[i] 

loss /= num_train 
loss +=  0.5* reg * np.sum(W * W)
dW = dW/num_train + reg* W 

使用矩阵来计算softmax的loss和梯度

python 复制代码
num_classes = W.shape[1]
num_train = X.shape[0]
# 计算得到每个训练数据每个类别的score
scores = X.dot(W) # (num_train, 10)
# 下面的reshape是为了让计算得到的max在和score相减的时候进行广播,每行的max都是一样的
shift_scores = scores - np.max(scores, axis = 1).reshape(-1,1) # (num_train, 10)
# 下面的reshape是为了能够进行广播
softmax_output = np.exp(shift_scores)/np.sum(np.exp(shift_scores), axis = 1).reshape(-1,1) # (num_train, 10)
loss = -np.sum(np.log(softmax_output[range(num_train), list(y)])) # 正确类别的占比的负数
loss /= num_train 
loss +=  0.5* reg * np.sum(W * W)
  
dS = softmax_output.copy()
# 正确类别的减一,其他的直接和X矩阵相乘
dS[range(num_train), list(y)] += -1
dW = (X.T).dot(dS)
dW = dW/num_train + reg* W 

其他问题

在刚初始化的时候,为什么希望计算出来的loss接近-log(0.1)? 因为刚初始化的时候,每个类别的概率都应该相同,所以正确类别的概率应该是0.1,那么loss就应该是-log(0.1)。

三、Dropout

Dropout(Improving neural networks by preventing co-adaptation of feature detectors)是一个regularization技术,随机让某些神经元进行失效来获得更好的效果。

Dropout前向传播

python 复制代码
def dropout_forward(x, dropout_param):
    """
    Inputs:
    - x: 输入的数据,可以是任何的shape
    - dropout_param: dict包含如下的键:
       - p: dropout概率,每个神经元被失活的概率
       - mode: 'test'/'train'如果是'test'则不进行失活
       - seed: 随机数生成种子,这个是为了梯度检验用,正常使用中不应该指定这个参数
    
    Outputs:
    - out: 输出数据shape同x
    - cache: (dropout_param, mask) 在'train'mode中,mask作用于输入x得到输出,在'test'mode中mask为None
    """
    p, mode = dropout['p'], dropout_param['mode']
    if 'seed' in deopout_param:
        np.random.seed(dropout_param['seed'])

    mask = None
    out = None
    if mode == 'train':
        # 注意/(1-p) 前向传播的时候均值得稳定
        mask = (np.random.rand(*x.shape)>=p)/(1-p)
        out = x*mask
    elif mode == 'test':
        out = x
    
    cache = (dropout_param, mask)
    out = out.astype(x.dtype, copy=False)
    return out, cache

Dropout反向传播

python 复制代码
def dropout_backward(dout, cache):
    """
    Inputs:
    - dout: 反向传播回来的导数
    - cache: (dropout_param, mask)

    Output:
    - dx: 导数
    """
    dropout_param, mask = cache
    mode = dropout_param['mode']

    dx = None
    if mode == 'train':
        # dloss/dx = dloss/dout * dout/dx = dloss/dout * mask
        # 被失活的神经元的mask处为0,其余为1
        dx = dout * mask
    elif mode == 'test':
        dx = dout
    return dx

Dropout的作用

Dropout可以有效地抑制过拟合,一般来说神经元失活的概率越大在训练集上和在验证集上的区别就越小,但是较大的失活概率会导致神经网络的容量下降,更难拟合数据。

四、最大池化max_pool

最大池化前向传播

在前向传播的过程中注意保存中间数据,为了反向传播的时候方便计算。

python 复制代码
def max_pool_forward_naive(x, pool_param):
    """MaxPool前向传播的一个简单实现版本
    Inputs:
    - x: (N, C, H, W)
    - pool_param: 包含最大池化参数的字典
       - 'pool_height': 池化区域的高度
       - 'pool_width': 池化区域的宽度
       - 'stride': 相邻池化区域的距离

    Returns:
    - out: 输出的数据
    - cache: (x, pool_param)
    """
    out = None
    N, C, H, W = x.shape
    HH, WW, stride = pool_param['pool_height'], pool_param['pool_width']
    H_out = (H-HH)/stride+1
    W_out = (W-WW)/stride+1
    out = np.zeros((N, C, H_out, W_out))
    # 先确定每个做最大池化的区域
    for i in xrange(H_out):
        for j in xrange(W_out):
            # 取出这个区域的数据
            x_masked = x[:, :, i*stride:i*stride+HH, j*stride:j*stride+WW] # (N, C, HH, WW)
            # 取最大值 (N, C)
            out[:, :, i, j] = np.max(x_masked, axis=(2,3))
    cache = (x, pool_param)
    return out, cache

最大池化反向传播

python 复制代码
def max_pool_backward_naive(dout, cache):
    """MaxPool反向传播的一个简单版本
    Inputs:
    - dout: 反向传播过来的导数
    - cache: (x, pool_param)

    Returns:
    - dx: 导数
    """
    dx = None
    x, pool_param = cache
    N, C, H, W = x.shape
    HH, WW, stride = pool_param['pool_height'], pool_param['pool_width'], pool_param['stride']
    H_out = (H-HH)/stride+1
    W_out = (W-WW)/stride+1
    # 最大值处的导数能够进行传播,其余的地方导数为0
    dx = np.zeros_like(x)

    # 先确定之前池化的每个区域
    for i in xrange(H_out):
        for j in xrange(W_out):
            # 取出池化这个区域的数据
            x_masked = x[:, :, i*stride:i*stride+HH, j*stride:j*stride+WW] # (N, C, HH, WW)
            # 取得最大值 (N,C)
            max_x_masked = np.max(x_masked, axis=(2,3))
            # 得到最大值的mask (N, C, HH, WW) 最大值为1 其余为0
            temp_binary_mask = (x_masked == (max_x_masked)[:,:,None,None])
            # 最大值处的导数能够进行传播,其余的地方导数为0
            dx[:, :, i*stride:i*stride+HH, j*stride:j*stride+WW] += temp_binary_mask * (dout[:,:,i,j])[:,:,None,None]
相关推荐
好喜欢吃红柚子2 分钟前
万字长文解读空间、通道注意力机制机制和超详细代码逐行分析(SE,CBAM,SGE,CA,ECA,TA)
人工智能·pytorch·python·计算机视觉·cnn
小馒头学python7 分钟前
机器学习是什么?AIGC又是什么?机器学习与AIGC未来科技的双引擎
人工智能·python·机器学习
神奇夜光杯16 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
正义的彬彬侠19 分钟前
《XGBoost算法的原理推导》12-14决策树复杂度的正则化项 公式解析
人工智能·决策树·机器学习·集成学习·boosting·xgboost
Debroon28 分钟前
RuleAlign 规则对齐框架:将医生的诊断规则形式化并注入模型,无需额外人工标注的自动对齐方法
人工智能
羊小猪~~35 分钟前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
AI小杨36 分钟前
【车道线检测】一、传统车道线检测:基于霍夫变换的车道线检测史诗级详细教程
人工智能·opencv·计算机视觉·霍夫变换·车道线检测
晨曦_子画41 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
道可云42 分钟前
道可云人工智能&元宇宙每日资讯|2024国际虚拟现实创新大会将在青岛举办
大数据·人工智能·3d·机器人·ar·vr
人工智能培训咨询叶梓1 小时前
探索开放资源上指令微调语言模型的现状
人工智能·语言模型·自然语言处理·性能优化·调优·大模型微调·指令微调