字节跳动面崩了,记录一下。看大家都在发面经,发个挂经反馈一下。
字节想了想面试了5次。 挂了2次, 也是有点惨。
大多数内容来源自网络搜集的答案,如果有没有附上的出处可以提醒我
祝愿大家都找到满意的offer
Deeplearning.ai的教程Initializing neural networks :
首先神经网络参数不能初始化为0或者任意相同的常量。如果网络参数都是相同常量,那个每个隐层节点对最终节点的贡献度一致,导致各个节点按照相同的方式更新。不能使不同神经元学习不同的东西。
考虑线性模型,初始权重过小导致梯度消失,过大梯度爆炸。需要寻找合适的参数,有两个假设为
假设某层的前传播公式为
对应假设为
一般建议使用 Xavier 初始化:
权重通过正态分布采样, 是上层神经元的个数。偏置初始化为0. 推导过程如下,假设网络激活函数为
其中:
目的需要找到两层间方差的对应关系,即 和 。首先注意tanh的性质: 另外就是在接近0的时候 。在初始化后,参数都是很小的值,有
考虑 ,对应的关系可以推导为
考虑每个元素的方差, 注意偏置项都是0,可以省略掉
先使用3个假设:
继续展开:
考虑方差展开式
注意输入和权重的期望是0,代入可以得到下个公式,这个公式是方差缩放公式。
上述等式成立的时候,需要有下列假设成立
同理要满足
那么要满足开始的假设
需要有
在实际过过程中,Xavier初始化方式有两种方差,如下
使用ReLu通常一般神经元输出为0,此时分布的方差为恒等函数时候的一半,此时考虑前向传播,理想方差为
采用高斯分布方差如上,如果采用区间为 均匀分布初始化参数,那么
Dropout来自论文 「Dropout: A Simple Way to Prevent Neural Networks from Overfitting」
在前向传播过程中,公式为
是概率1为 的伯努利分布生成的向量。在前向传播过程中,训练得到参数被更新
参考「百面机器学习」
L1 正则化使模型参数具有稀疏性。即很多权重参数都是0. 优点是可以自动做特征选择。 L2正则化对防止模型过拟合效果更好,因为网络倾向去使用所有的输入特征而不是严重依赖小部分特征。
考虑L1正则
最小化代价函数等价于
函数空间和解空间已经有了,最有参数为解空间和函数空间的交集中使得函数最小的点。「百面机器学习」绘制出了下图
最优解是解空间边缘和函数等高线的交点。L1棱形解空间更容易在尖角处与等高线碰撞得到稀疏解。
AUC时ROC曲线下的面积。 ROC通过FP(假阳性)和TP(真阳性)计算。 对于二分类需要考虑混淆矩阵
| 预测 | |||
|---|---|---|---|
| 真实类别 | TP | FN | |
| FP | TN |
ROC(receiver operating characteristic curve) 通过 TPR 和 FPR得到
通过FPR为横轴, TPR为纵轴,在不同分类置信度阈值下,可以绘制ROC曲线。如下图,ROC一定会经过(0, 0), (1, 1):
AUC是ROC曲线下的面积。ROC曲线有一个很好的性质,在测试集正负样本分布变化的时候,ROC曲线保持不变。AUC计算方式主要有两种:
公式中 和 分别为正负样本个数。是将样本按照置信度排序后,置信度最高的样本
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,如 "[[[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