记录一次失败的字节跳动面试「算法」

记录一次失败的字节跳动面试「算法」文章目录记录一次失败的字节跳动面试「算法」简介神经网络参数如何初始化Xavier 初始化He 初始化Dropout在forward里面怎么做L1和L2正则化的区别AUC是什么,写一下代码编程题,类似实现 ndarray.shape简介字节跳动面崩了,记录一下。神经网络参数如何初始化Deeplearning.ai的教程Initializing neural networks :首先神经网络参数不能初始化为0或者任意相同的常量。如果网络参数都是相同常量,那个每个隐层
摘要由CSDN通过智能技术生成

记录一次失败的字节跳动面试「算法」

简介

字节跳动面崩了,记录一下。

神经网络参数如何初始化

Deeplearning.ai的教程Initializing neural networks :

首先神经网络参数不能初始化为0或者任意相同的常量。如果网络参数都是相同常量,那个每个隐层节点对最终节点的贡献度一致,导致各个节点按照相同的方式更新。不能使不同神经元学习不同的东西。

考虑线性模型,初始权重过小导致梯度消失,过大梯度爆炸。需要寻找合适的参数,有两个假设为

  1. 激活函数输出后的均值为0
  2. 每激活函数输出的方差应该在层与层间保持相同

假设某层的前传播公式为
a [ l − 1 ] = g [ l − a ] ( z [ l − 1 ] ) z [ l ] = W [ l ] a [ l − 1 ] + b [ l ] a [ l ] = g [ l ] ( z [ l ] ) \begin{aligned} a^{[l - 1]} &= g^{[l - a]}(z^{[l - 1]})\\ z^{[l]} &= W^{[l]}a^{[l-1]} + b^{[l]}\\ a^{[l]} &= g^{[l]}(z^{[l]}) \end{aligned} a[l1]z[l]a[l]=g[la](z[l1])=W[l]a[l1]+b[l]=g[l](z[l])
对应假设为
E [ a [ l − 1 ] ] = E [ a [ l ] ] V a r ( a [ l − 1 ] ) = V a r ( a [ l ] ) \begin{aligned} E\left[a^{[l - 1]}\right] &= E\left[a^{[l]}\right]\\ Var\left(a^{[l - 1]}\right) &=Var\left(a^{[l]}\right) \end{aligned} E[a[l1]]Var(a[l1])=E[a[l]]=Var(a[l])

Xavier 初始化

一般建议使用 Xavier 初始化:
W [ l ] ∼ N ( μ = 0 , σ 2 = 1 n [ l − 1 ] ) b [ l ] = 0 \begin{aligned} W^{[l]} &\sim \mathcal{N}(\mu=0,\sigma^2=\frac{1}{n^{[l- 1]}})\\ b^{[l]} &=0 \end{aligned} W[l]b[l]N(μ=0,σ2=n[l1]1)=0
权重通过正态分布采样, n [ l − 1 ] n^{[l-1]} n[l1] 是上层神经元的个数。偏置初始化为0. 推导过程如下,假设网络激活函数为 t a n h tanh tanh
z [ l ] = W [ l ] a [ l − 1 ] + b [ l ] a [ l ] = t a n h ( z [ l ] ) \begin{aligned} z^{[l]} &= W^{[l]}a^{[l-1]} + b^{[l]}\\ a^{[l]} &= tanh(z^{[l]}) \end{aligned} z[l]a[l]=W[l]a[l1]+b[l]=tanh(z[l])
其中:
t a n h ( x ) = 1 − e − 2 x 1 + e − 2 x tanh(x)=\frac{1-e^{-2x}}{1 + e ^{-2x}} tanh(x)=1+e2x1e2x
目的需要找到两层间方差的对应关系,即 V a r ( a [ l − 1 ] ) Var(a^{[l-1]}) Var(a[l1]) V a r ( a [ l ] ) Var(a^{[l]}) Var(a[l]) 。首先注意tanh的性质: t a n h ( − x ) = − t a n h ( x ) tanh(-x) = -tanh(x) tanh(x)=tanh(x) 另外就是在接近0的时候 t a n h ( x ) ≈ x tanh(x)\approx x tanh(x)x 。在初始化后,参数都是很小的值,有
V a r ( a [ l ] ) = V a r ( t a n h ( z [ l ] ) ) ≈ V a r ( z [ l ] ) Var(a^{[l]}) = Var(tanh(z^{[l]}))\approx Var(z^{[l]}) Var(a[l])=Var(tanh(z[l]))Var(z[l])
考虑 z [ l ] = W [ l ] a [ l − 1 ] + b [ l ] = v e c t o r ( z 1 [ l ] , z 2 [ l ] , ⋯   , z 3 [ l ] ) z^{[l]} = W^{[l]}a^{[l-1]}+b^{[l]}=vector(z^{[l]}_1,z^{[l]}_2,\cdots,z^{[l]}_3) z[l]=W[l]a[l1]+b[l]=vector(z1[l],z2[l],,z3[l]),对应的关系可以推导为
z k [ l ] = ∑ j = 1 n [ l − 1 ] w k j [ l ] a j [ l − 1 ] + b k [ l ] z^{[l]}_k = \sum_{j=1}^{n^{[l-1]}}w^{[l]}_{kj}a_j^{[l-1]} +b_k^{[l]} zk[l]=j=1n[l1]wkj[l]aj[l1]+bk[l]
考虑每个元素的方差, 注意偏置项都是0,可以省略掉
V a r ( a k [ l ] ) = V a r ( z k [ l ] ) = V a r ( ∑ j = 1 n [ l − 1 ] w k j [ l ] a j [ l − 1 ] ) Var(a_k^{[l]}) = Var(z_k^{[l]}) = Var\left(\sum_{j=1}^{n^{[l-1]}}w_{kj}^{[l]}a_{j}^{[l-1]}\right) Var(ak[l])=Var(zk[l])=Varj=1n[l1]wkj[l]aj[l1]
先使用3个假设:

  1. 权重独立同分布
  2. 输入独立同分布
  3. 权重和输入相互独立

继续展开:
V a r ( a k [ l ] ) = V a r ( z k [ l ] ) = V a r ( ∑ j = 1 n [ l − 1 ] w k j [ l ] a j [ l − 1 ] ) = ∑ j = 1 n [ l − 1 ] V a r ( w k j [ l ] a j [ l − 1 ] ) Var(a_k^{[l]}) = Var(z_k^{[l]}) = Var\left(\sum_{j=1}^{n^{[l-1]}}w_{kj}^{[l]}a_{j}^{[l-1]}\right) = \sum_{j=1}^{n^{[l-1]}}Var(w_{kj}^{[l]}a_j^{[l-1]}) Var(ak[l])=Var(zk[l])=Varj=1n[l1]wkj[l]aj[l1]=j=1n[l1]Var(wkj[l]aj[l1])
考虑方差展开式
V a r ( w i x i ) = E [ w i ] 2 V a r ( x i ) + E [ x i ] 2 V a r ( w i ) + V a r ( w i ) V a r ( x i ) Var(w_ix_i)=E[w_i]^2Var(x_i) + E[x_i]^2Var(w_i) +Var(w_i)Var(x_i) Var(wixi)=E[wi]2Var(xi)+E[xi]2Var(wi)+Var(wi)Var(xi)

注意输入和权重的期望是0,代入可以得到下个公式,这个公式是方差缩放公式。
V a r ( z k [ l ] ) = ∑ j = 1 n [ l − 1 ] V a r ( w k j [ l ] ) V a r ( a j [ l − 1 ] ) = n [ l − 1 ] V a r ( W [ l ] ) V a r ( a [ l − 1 ] ) Var(z^{[l]}_k) = \sum_{j=1}^{n^{[l-1]}}Var(w_{kj}^{[l]})Var(a_j^{[l-1]}) = n^{[l-1]}Var(W^{[l]})Var(a^{[l-1]}) Var(zk[l])=j=1n[l1]Var(wkj[l])Var(aj[l1])=n[l1]Var(W[l])Var(a[l1])
上述等式成立的时候,需要有下列假设成立
V a r ( w k j [ l ] ) = V a r ( w 11 [ l ] ) = V a r ( w 12 [ l ] ) = ⋯ = V a r ( W [ l ] ) Var(w_{kj}^{[l]}) = Var(w_{11}^{[l]}) = Var(w_{12}^{[l]})=\cdots=Var(W^{[l]}) Var(wkj[l])=Var(w11[l])=Var(w12[l])==Var(W[l])
同理要满足
V a r ( z [ l ] ) = V a r ( z k [ l ] ) Var(z^{[l]}) = Var(z_k^{[l]}) Var(z[l])=Var(zk[l])
那么要满足开始的假设
V a r ( a [ l ] ) = n [ l − 1 ] V a r ( W [ l ] ) V a r ( a [ l − 1 ] ) = V a r ( a [ l − 1 ] ) Var(a^{[l]}) = n^{[l-1]} Var(W^{[l]})Var(a^{[l-1]})= Var(a^{[l-1]}) Var(a[l])=n[l1]Var(W[l])Var(a[l1])=Var(a[l1])
需要有
V a r ( W [ l ] ) = 1 n [ l − 1 ] Var(W^{[l]}) = \frac{1}{n^{[l-1]}} Var(W[l])=n[l1]1
在实际过过程中,Xavier初始化方式有两种方差,如下
W [ l ] ∼ N ( 0 , 1 n [ l − 1 ] ) W [ l ] ∼ N ( 0 , 2 n [ l − 1 ] + n [ l ] ) \begin{aligned} W^{[l]}&\sim\mathcal{N}(0, \frac{1}{n^{[l-1]}})\\ W^{[l]}&\sim\mathcal{N}(0, \frac{2}{n^{[l-1]}+n^{[l]}}) \end{aligned} W[l]W[l]N(0,n[l1]1)N(0,n[l1]+n[l]2)

He 初始化

使用ReLu通常一般神经元输出为0,此时分布的方差为恒等函数时候的一半,此时考虑前向传播,理想方差为
V a r ( w [ l ] ) = 2 n [ l − 1 ] Var(w^{[l]}) = \frac{2}{n^{[l-1]}} Var(w[l])=n[l1]2
采用高斯分布方差如上,如果采用区间为 [ − r , r ] [-r, r] [r,r] 均匀分布初始化参数,那么 r = 6 n [ l − 1 ] r=\sqrt{\frac{6}{n^{[l-1]}}} r=n[l1]6

Dropout在forward里面怎么做

Dropout来自论文 「Dropout: A Simple Way to Prevent Neural Networks from Overfitting」

在前向传播过程中,公式为
r j ( l ) ∼ Bernoulli ( p ) y ~ ( l ) = r ( l ) ∗ y ( l ) z i ( l + 1 ) = w i ( l + 1 ) y ~ ( l ) + b i ( l + 1 ) y i ( l + 1 ) = f ( z i ( l + 1 ) ) \begin{aligned} r_j^{(l)} &\sim \text{Bernoulli}(p)\\ \widetilde{\mathbf{y}}^{(l)} &= \mathbf{r}^{(l)}*\mathbf{y}^{(l)}\\ z_i^{(l + 1)} &= \mathbf{w}_i^{(l + 1)}\widetilde{\mathbf{y}}^{(l)} + b_i^{(l + 1)}\\ y_i^{(l + 1)} &= f(z_i^{(l + 1)}) \end{aligned} rj(l)y (l)zi(l+1)yi(l+1)Bernoulli(p)=r(l)y(l)=wi(l+1)y (l)+bi(l+1)=f(zi(l+1))
r \mathbf{r} r 是概率1为 p p p 的伯努利分布生成的向量。在前向传播过程中,训练得到参数被更新 W t e s t ( l ) = p W ( l ) W_{test}^{(l)} = pW^{(l)} Wtest(l)=pW(l)

L1和L2正则化的区别

参考「百面机器学习」

L1 正则化使模型参数具有稀疏性。即很多权重参数都是0. 优点是可以自动做特征选择。 L2正则化对防止模型过拟合效果更好,因为网络倾向去使用所有的输入特征而不是严重依赖小部分特征。

考虑L1正则
J ( w ) = 1 n ∥ y − X w ∥ 2 + λ ∥ w ∥ J(\mathbf{w}) = \frac{1}{n}\| \mathbf{y - Xw}\|^2 + \lambda\|\mathbf{w}\| J(w)=n1yXw2+λw
最小化代价函数等价于
min ⁡ w 1 n ∥ y − X w ∥ 2 s . t . ∥ w ∥ ≤ C \begin{aligned} &\min_\mathbf{w} \frac{1}{n}\|\mathbf{y - Xw}\|^2\\ &s.t.\quad\|w\|\le C \end{aligned} wminn1yXw2s.t.wC
函数空间和解空间已经有了,最有参数为解空间和函数空间的交集中使得函数最小的点。「百面机器学习」绘制出了下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6OyMkUaZ-1603715157073)(https://raw.githubusercontent.com/lih627/MyPicGo/master/imgs/20201025180543.png)]

最优解是解空间边缘和函数等高线的交点。L1棱形解空间更容易在尖角处与等高线碰撞得到稀疏解。

AUC是什么,写一下代码

Probabilistic interpretation of AUC

The Probabilistic Interpretation of AUC

AUC时ROC曲线下的面积。 ROC通过FP(假阳性)和TP(真阳性)计算。 对于二分类需要考虑混淆矩阵

预测
y ^ = c \hat{y}=c y^=c y ^ ≠ c \hat{y} \neq c y^=c
真实类别 y = c y=c y=cTPFN
y ≠ c y\neq c y=cFPTN

ROC(receiver operating characteristic curve) 通过 TPR 和 FPR得到

T P R = T P T P + F N TPR = \frac{TP}{TP + FN} TPR=TP+FNTP

F P R = F P F P + T N FPR=\frac{FP}{FP + TN} FPR=FP+TNFP
通过FPR为横轴, TPR为纵轴,在不同分类置信度阈值下,可以绘制ROC曲线。如下图,ROC一定会经过(0, 0), (1, 1):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zg2xVqRW-1603715157103)(https://raw.githubusercontent.com/lih627/MyPicGo/master/imgs/20201026153624.png)]

AUC是ROC曲线下的面积。ROC曲线有一个很好的性质,在测试集正负样本分布变化的时候,ROC曲线保持不变。AUC计算方式主要有两种:

  • 从预测的置信度排序,按照排序后由高到低选择选择阈值,计算对应TPR和 FPR 绘制曲线
  • AUC具有概率学上的意义:随机选取一个正样本和一个负样本,分类器给正样本打分大于分类器给负样本打分的概率。使用组合数学求解

A U C = ∑ i ∈ p o s i t i v e C l a s s r a n k i − M ( 1 + M ) 2 M × N AUC = \frac{\sum_{i\in positiveClass} rank_i - \frac{M(1+M)}{2}}{M\times N} AUC=M×NipositiveClassranki2M(1+M)

公式中 M M M N N N 分别为正负样本个数。 r a n k rank rank是将样本按照置信度排序后,置信度最高的样本 r a n k = M + N rank=M+N rank=M+N

python 代码如下, 来自AUC曲线计算方法及代码实现

import numpy as np
from sklearn.metrics import roc_auc_score


def calc_auc(y_labels, y_scores):
    f = list(zip(y_scores, y_labels))
    rank = [values2 for values1, values2 in sorted(f, key=lambda x: x[0])]
    rankList = [i + 1 for i in range(len(rank)) if rank[i] == 1]
    pos_cnt = np.sum(y_labels == 1)
    neg_cnt = np.sum(y_labels == 0)
    auc = (np.sum(rankList) - pos_cnt * (pos_cnt + 1) / 2) / (pos_cnt * neg_cnt)
    return auc


def get_score():
    # 随机生成100组label和score
    y_labels = np.zeros(100)
    y_scores = np.zeros(100)
    for i in range(100):
        y_labels[i] = np.random.choice([0, 1])
        y_scores[i] = np.random.random()
    return y_labels, y_scores


if __name__ == '__main__':
    y_labels, y_scores = get_score()
    print('sklearn AUC:', roc_auc_score(y_labels, y_scores))
    print(calc_auc(y_labels, y_scores))

编程题,类似实现 ndarray.shape

以字符串形式给出一个 ndarray,如 “[[[7,7,7],[8,8,8]]]”,请写一个程序,输出它的 shape,以上面的例子为例,输出:(1,2,3)。

输入:"[[[0.7,7,7],[8,8,8]]]",输出:(1,2,3).
输入:"[[[7],[7],[7]],[[8],[8],[8]]]”, 输出:(2,3,1)
输入:"[[[7],[7],[]]]”, 输出:error

代码如下,面试没写出来,递归来统计,从内层到外层一次统计。

def _count_shape(strs):
    cnt = 0
    for idx, c in enumerate(strs):
        if c == '[':
            cnt += 1
        else:
            break
    if cnt == 0:
        return False, [-1]
    if cnt == 1:
        nums = strs[1:-1].split(',')
        try:
            nums = list(map(float, nums))
        except Exception as E:
            return False, [-1]
        if len(nums) == 0:
            return False, [-1]
        return True, [len(nums)]
    else:
        splits = []
        pre = ''
        cur_cnt = 0
        idx = 1
        while idx < len(strs) - 1:
            c = strs[idx]
            if c == '[':
                cur_cnt += 1
            elif c == ']':
                cur_cnt -= 1
            pre += c
            idx += 1
            if cur_cnt == 0:
                splits.append(pre)
                pre = ''
                while idx < len(strs) - 1 and strs[idx] != '[':
                    idx += 1
        ret = [_count_shape(_strs) for _strs in splits]
        if not ret:
            return False, [-1]
        isvalid, r = ret[0]
        if not isvalid:
            return False, [-1]
        for ci, cr in ret[1:]:
            if not ci or r != cr:
                return False, [-1]
        return True, r + [len(ret)]


def shape(strs):
    ret, shape = _count_shape(strs)
    if ret:
        return shape[::-1]
    else:
        print('error')
        return -1


if __name__ == '__main__':
    print(shape("[[[0.7,7,7],[8,8,8]]]"))
    print(shape("[[[7],[7],[7]],[[8],[8],[8]]]"))
    print(shape("[[[7],[7],[]]]"))

运行结果

[1, 2, 3]
[2, 3, 1]
error
-1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值