一面
2021 年 7 月 29 日晚 20:00,只问了 38 分钟就结束了(捂脸。面试官人很好,很友善的样子,然后问的也都比较简单,都是我简历范围内的东西,也没深挖,所以结束的也很快。
首先面试官介绍了下 AML 部门(第一次面试紧张没咋听进去他在讲啥,就回答了个嗯嗯。。。)
然后是自我介绍:我叫 xxx,来自浙江,现在是xx学校研一的学生。我本科和研究生都是xx学校计算机科学与技术专业的。希望有机会来字节实习。然后我的项目主要是简历上写的天池的比赛,xxx分类,用到了数据增强、半监督学习(伪标签)、知识蒸馏、模型融合等技术。然后我还学过 GBDT、XGBoost 和 Transformer 等,对这些有一定的了解。以上就是我的自我介绍了。
面试官还问了我的导师是谁(捂脸,不知道是不是校友。
然后开始问简历上的项目:
- 你写的这个双图网络是什么?
- 数据增强用了哪些方法?
- 这个伪标签是什么意思?
知识蒸馏从 Resnet34 到 Resnet18,训练时间从多少减少到多少了吗?
回答说这个具体的运行时间不太记得了,但是评估指标 F1 score 提升了
这个模型变小了为什么评估指标会提升呢?
F1 score 怎么求?精确度和召回率怎么求?这个混淆矩阵的行和列的 N、P 分别代表什么呢?
在代码框里简单画了个混淆矩阵,然后说了下公式
这个投票机制是怎么做的呢?哦,只是对结果做了融合,没有针对模型是把?
- 这个是分类问题还是回归问题呢?
分类问题用的损失函数是什么呢?
交叉熵损失函数
介绍一下交叉熵损失函数
写了下公式,多分类的交叉熵
二分类的交叉熵呢?
XGBoost 这个广告分类器是干什么?数据集是哪里找的,特征有哪些?
- 介绍一些贝叶斯优化?
- 介绍一些 XGBoost
- 决策树怎么构建呢?
- 决策树怎么停止生长?
- AUC 怎么算?FPR、TPR 怎么算?
讲了 AUC 是 ROC 曲线下的面积,横轴是 FPR,纵轴是 TPR。又问 FPR、TPR 怎么算?
Transformer 的注意力机制介绍一下?
反问了下是讲注意力机制还是自注意力机制,面试官让讲自注意力机制
注意力机制和自注意力机制有什么区别吗?
答:本质上其实是一样的,只不过注意力是关注其它序列的上下文资讯,自注意力是关注自身序列的上下文资讯
其它还有什么问的记不清了
算法题:
最大公约数
感觉是大一就做过的题,应该是简单题,但我想不起来怎么做了,问能不能先暴力做,暴力昨晚跑了下测试样例应该没问题。面试官问怎么改进呢,没想出来,问面试官能不能给点提示,不知道是不是面试官也不知道,说没事换下一道题。。。
判断是否是合法二叉搜索树?
递归收缩上下界做的。问面试官要不要建个树跑一下,面试官说太麻烦了不用了,然后我讲了下我写的意思,就过了
最后,反问环节
问了面试官平时工作都做些什么
面试官说这个问题很好,讲了一下,巴拉巴拉
问面试官觉得我的表现怎么样,有什么不足和需要改进的地方?
面试官说还不错。问我平时用各种工具有没有深究? 我说我第一道算法题应该是简单题,但我忘了它应该怎么做了,只能用暴力解。 面试官说有些东西不记得了也正常,暴力做出来也可以
二面凉
7.30 下午 16:00 二面,总共面了 50 多分钟,问的问题比一面深不少,但感觉其实问的也不算很难吧,只是有些问题我确实不会,还是自己太菜了。
上来先做算法题:
给定两个单调非减的链表头节点,按照单调增(去重)的顺序【打印】出链表每个节点的
val- 单调非减意味着可能会有重复值
- 只要打印出来,类似于遍历,不要改原始链表
struct Node {int val;Node* next;}void merge_print(Node* l1, Node* l2){}
其实很简单的一道题,但是太粗心了,为了去重用了一个 pre 存之间的值,然后没考虑链表头节点为空的情况,感觉平时写题也会考虑一下特殊情况的,面试可能太紧张了大意了。面试官提示了之后处理了下头节点为空的情况,然后忘记了处理完特殊情况应该直接 return!!!最后面试官反馈说代码题 bug 太多,没有直接做到 bug free,挺减分的。。。
求第 k 大的数组,不用写代码,只用说思路
int topk(std::vector<int> &nums, size_t k)
说了下用快速选择做,问了时间复杂度,只知道是 O(N) 的,但是之前看分析求这个复杂度挺难的样子就没看,问怎么算的我不会。。。然后问了快速排序的时间复杂度,O(nlogn)怎么求,答每次找切分点,两边再分别排序,所以相当于二叉树,深度为 logn,每次求切分点遍历数组时间复杂度 O(n),所以是 nlogn
扩展:数组是
const,也就是数组不能改动,没法排序,也不能复制到其他数组,要求空间复杂度 O(1),怎么做?int const_topk(const std::vector<int> &nums, size_t k)
面试官说这是扩展题,答不上来也没关系,问有没有思路。想不出来。。。 实际上应该用二分去做,解答参见:求 const top k
问题:以下两种写法哪个更好?(两个 for 循环 vs 一个 for 循环)
std::vector<int> a(4096), b(4096);do_some_calc(&a, &b);// No.1int sum = 0;for (size_t idx = 0; idx < 4096; ++idx) {sum += a[idx];sum += b[idx];}// No.2int sum = 0;for (size_t idx = 0; idx < 4096; ++idx) sum += a[idx];for (size_t idx = 0; idx < 4096; ++idx) sum += b[idx];
面试的时候不会,没答上来 No.2 使用双数组遍历(两个 for 循环)会更快,因为 L1cache?网上没找到确切的答案
大概分析:(局部性) 参考:为什么二维数组中行遍历比列遍历快很多?
假设 cache 的大小为 4*16 字节
当第一次访问 a[0] 时,会将 a[0] ~ a[3] 这连续的 16 个字节读进 cache 的第一行,并造成一次 cache miss(访问 a[0] 的时候 cache 里没有)。当前 cache 如下:
| a[0] miss | a[1] hit | a[2] hit | a[3] hit |
|---|---|---|---|
那如果使用 No.2 的方法,接下去访问 a[1],a[2],a[3] 都命中,cache 命中率为 75%,后续每 4 个元素都是这样
而如果使用 No.1 的方法,访问 a[0] 后访问 b[0],cache 中没有需加载,之后访问 a[1],b[1]~a[3],b[3] 都命中,所以命中率也是 75%???
| a[0] miss | a[1] hit | a[2] hit | a[3] hit |
|---|---|---|---|
| b[0] miss | b[1] hit | b[2] hit | b[3] hit |
| a[4] miss | a[5] hit | a[6] hit | a[7] hit |
| b[4] miss | b[5] hit | b[6] hit | b[7] hit |
然后是问基础知识:
先是关于天池太阳黑子分类的项目的问题,先让介绍了这个项目
使用知识蒸馏是这个比赛对运行的时间有要求吗?
不是出于时间的考量,比赛的评估指标就是 F1 score,因此就是要提高 F1 score 的值。 之所以想到用知识蒸馏,是因为知识蒸馏同时使用了 soft loss 和 hard loss soft loss:使用带温度 T 的 softmax,输出的各类别的概率更加平滑,相对于原本的 softmax,能学习到类间的相似性,相当于 label 层面的数据增强 hard loss:使用 ground truth 一定程度上能抵消伪标签对教师模型带来的负面影响
为什么教师模型选择 resnet34,学生模型选择 resnet18?
实验对比表明效果好
那为什么不用 resnet34 本身作为学生模型呢?
实验发现效果没 resnet18 好。又追问了为什么 resnet34 作为学生模型不如 resnet 18?没答上来 按反馈,为什么用 resnet18 蒸馏 resnet34 这个问题没能做出原理解释性的回答,面试官不满意
知识蒸馏过程中还有用到哪些 tricks?
温度 T ,实验后发现 T 设为 10 比较合适 还有两个 loss 加权的权值 α,实验后发现 soft loss 的权值设为 0.95 比较好
为什么伪标签这里没有考虑 soft?
因为当时先用了伪标签来提升效果,也没想到后面会用知识蒸馏做,也就没想到用 soft,就伪标签直接做了
介绍一些用了哪些数据增强的方法?
- 用的 backbone 是预训练还是从头训练效果好?
使用预训练的 resnet34 进行微调的时候,调了几层(固定了哪些层的参数)?
没有固定,但是最后的全连接层 fc 的学习率设置为前面预训练过部分的 10 倍,从头训练。 初始学习率为 0.01(fc 初始 0.1),然后使用余弦学习率衰减,周期为 20 个 epoch,最小学习率为 5e-6
数据集的大小?
然后让介绍第二个项目:XGBoost 广告分类器
- 特征数有多少?
- 有做特征的处理吗?
- 介绍一下 GBDT
- GBDT 的决策树怎么做二分类?
- 用决策树做分类,最终的分是怎么合起来的,每个决策树都划到一个叶子节点,最后怎么判断到底属于哪个类别呢?分类时候的残差?
答不上来,说了加权,被反驳了,然后后来面试官的反馈说我对 GBDT 这块根本没理解。。。
写一下 logloss
就是交叉熵损失,写了二分类交叉熵损失函数的公式
为什么取 log
答:二分类用极大似然估计(MLE)推导的时候,似然函数是对所有训练集样本的概率的连乘,那么两边取 log 就变成了和的形式
logloss 和最大似然之间的关系
写了一下逻辑回归用极大似然估计推导出交叉熵损失的过程
为什么是所有训练集样本的概率相乘呢?
又追问了为什么可以相乘,回答大概是样本之间独立?了解的不清楚。然后后来面试官反馈里有一条就说我对最大似然估计的了解不够。。。
SGD,先介绍一下,再写一下公式
狭义上就是用单个样本的损失函数来近似目标函数,广义上小批量梯度下降法就是用m个训练样本损失函数的均值来近似目标函数 然后写了下梯度下降更新参数的公式
为什么是减去梯度?
答:用负梯度信息更细参数;追问:为什么用负梯度信息?没答上来。。。
对 RNN 了解吗?
不怎么了解
最大/均值池化等(
max/sum_pooling/vec * scalar/vec_a * vec_b)的梯度计算(还是啥问题记不清了),我不会梯度反向传播?
用链式法则来计算梯度
那为什么不可以直接去求第一层的梯度?
答:应该没法计算吧?要用链式法则连乘的形式来计算导数
为什么会产生梯度消失问题?
- 有什么方法可以缓解梯度消失问题?
残差连接、ReLU 激活函数
反问环节:
问了实习日常都做什么
面试官很认真的回答了,我还问了那边做的是推荐算法吧,如果没有学过相关的是不是也能跟着做,面试官说算法这些学的还是快的。总之回答的挺认真的,就搞得我还以为自己挺有戏的,结果就挂了。。。
问了这场面试我的不足和要改进的地方
- 一开始的算法没有 bug free 很减分(语言是门艺术,面试官说没有 bug free 原来是委婉的说法hhh,后来的面试反馈说代码题 bug 太多了。。。)
- GBDT 分类预测怎么做那块
