
WeThinkIn
2022/10/09阅读:36主题:橙心
【三年面试五年模拟】算法工程师的独孤九剑秘籍(第十式)

Rocky Ding
公众号:WeThinkIn

写在前面
【三年面试五年模拟】栏目专注于分享CV算法与机器学习相关的经典&&必备&&高价值的面试知识点,并向着更实战,更真实,更从容的方向不断优化迭代。也欢迎大家提出宝贵的意见或优化ideas,一起交流学习💪
大家好,我是Rocky。
本文是“三年面试五年模拟”之独孤九剑秘籍的第十式,之前我们将独孤九剑秘籍前六式进行汇总梳理成汇总篇,并制作成pdf版本,大家可在公众号后台 【精华干货】菜单或者回复关键词“三年面试五年模拟” 进行取用。由于本系列都是Rocky在工作之余进行整理总结,难免有疏漏与错误之处,欢迎大家对可优化的部分进行指正,我将在后续的优化迭代版本中及时更正。
在【人人都是算法工程师】算法工程师的“三年面试五年模拟”之独孤九剑秘籍(先行版)中我们阐述了这个program的愿景与规划。本系列接下来的每一篇文章都将以独孤九剑秘籍框架的逻辑展开,考虑到易读性与文章篇幅,一篇文章中只选取每个分支技能树中的2-3个经典&&高价值知识点和面试问题,并配以相应的参考答案(精简版),供大家参考。
希望独孤九剑秘籍的每一式都能让江湖中的英雄豪杰获益。

So,enjoy(与本文的BGM一起食用更佳哦):
干货篇
----【目录先行】----
深度学习基础:
-
深度学习中有哪些经典的优化器?
-
有哪些提高GAN训练稳定性的Tricks?
经典模型&&热门模型:
-
U-Net模型的结构和特点?
-
RepVGG模型的结构和特点?
机器学习基础:
-
Accuracy、Precision、Recall、F1 Scores的相关概念?
-
梯度爆炸和梯度消失产生的原因及解决方法?
Python/C/C++知识:
-
Python中的None代表什么?
-
Python中 和 的区别?
-
C/C++中面向对象和面向过程的区别?
模型部署:
-
主流AI端侧硬件平台有哪些?
-
主流AI端侧硬件平台一般包含哪些模块?
图像处理基础:
-
图像噪声的种类?
-
Python中OpenCV和PIL的区别?
计算机基础:
-
Git,GitLab,SVN的相关知识
-
协程的相关概念
开放性问题:
-
如何保持数据持续稳定的支持业务?
-
如何分辨demo业务,一次性业务以及外包业务?
----【深度学习基础】----
【一】深度学习中有哪些经典的优化器?
SGD(随机梯度下降)
随机梯度下降的优化算法在科研和工业界是很常用的。
很多理论和工程问题都能转化成对目标函数进行最小化的数学问题。
举个例子:梯度下降(Gradient Descent)就好比一个人想从高山上奔跑到山谷最低点,用最快的方式奔向最低的位置。
SGD的公式:

动量(Momentum)公式:

基本的mini-batch SGD优化算法在深度学习取得很多不错的成绩。然而也存在一些问题需解决:
-
选择恰当的初始学习率很困难。 -
学习率调整策略受限于预先指定的调整规则。 -
相同的学习率被应用于各个参数。 -
高度非凸的误差函数的优化过程,如何避免陷入大量的局部次优解或鞍点。
AdaGrad(自适应梯度)
AdaGrad优化算法(Adaptive Gradient,自适应梯度),它能够对每个不同的参数调整不同的学习率,对频繁变化的参数以更小的步长进行更新,而稀疏的参数以更大的步长进行更新。
AdaGrad公式:


表示t时刻的 梯度。
表示t时刻参数 的梯度平方和。
与SGD的核心区别在于计算更新步长时,增加了分母:梯度平方累积和的平方根。此项能够累积各个参数 的历史梯度平方,频繁更新的梯度,则累积的分母逐渐偏大,那么更新的步长相对就会变小,而稀疏的梯度,则导致累积的分母项中对应值比较小,那么更新的步长则相对比较大。
AdaGrad能够自动为不同参数适应不同的学习率(平方根的分母项相当于对学习率α进进行了自动调整,然后再乘以本次梯度),大多数的框架实现采用默认学习率α=0.01即可完成比较好的收敛。
优势: 在数据分布稀疏的场景,能更好利用稀疏梯度的信息,比标准的SGD算法更有效地收敛。
缺点: 主要缺陷来自分母项的对梯度平方不断累积,随时间的增加,分母项越来越大,最终导致学习率收缩到太小无法进行有效更新。
RMSProp
RMSProp结合梯度平方的指数移动平均数来调节学习率的变化。能够在不稳定的目标函数情况下进行很好地收敛。
计算t时刻的梯度:

计算梯度平方的指数移动平均数(Exponential Moving Average), 是遗忘因子(或称为指数衰减率),依据经验,默认设置为0.9。

梯度更新的时候,与AdaGrad类似,只是更新的梯度平方的期望(指数移动均值),其中 ,避免除数为0。默认学习率 。

优势: 能够克服AdaGrad梯度急剧减小的问题,在很多应用中都展示出优秀的学习率自适应能力。尤其在不稳定(Non-Stationary)的目标函数下,比基本的SGD、Momentum、AdaGrad表现更良好。
Adam
Adam优化器结合了AdaGrad和RMSProp两种优化算法的优点。对梯度的一阶矩估计(First Moment Estimation,即梯度的均值)和二阶矩估计(Second Moment Estimation,即梯度的未中心化的方差)进行综合考虑,计算出更新步长。
Adam的优势:
-
实现简单,计算高效,对内存需求少。 -
参数的更新不受梯度的伸缩变换影响。 -
超参数具有很好的解释性,且通常无需调整或仅需很少的微调。 -
更新的步长能够被限制在大致的范围内(初始学习率)。 -
能自然地实现步长退火过程(自动调整学习率)。 -
很适合应用于大规模的数据及参数的场景。 -
适用于不稳定目标函数。 -
适用于梯度稀疏或梯度存在很大噪声的问题。
Adam的实现原理:

计算t时刻的梯度:

然后计算梯度的指数移动平均数, 初始化为0。
类似于Momentum算法,综合考虑之前累积的梯度动量。
系数为指数衰减率,控制动量和当前梯度的权重分配,通常取接近于1的值。默认为0.9。

接着,计算梯度平方的指数移动平均数, 初始化为0。
系数为指数衰减率,控制之前的梯度平方的影响情况。默认为0.999。
类似于RMSProp算法,对梯度平方进行加权均值。

由于 初始化为0,会导致 偏向于0,尤其在训练初期阶段。
所以,此处需要对梯度均值 进行偏差纠正,降低偏差对训练初期的影响。

同时 也要进行偏差纠正:

最后总的公式如下所示:

其中默认学习率 , 避免除数变为0。
从表达式中可以看出,对更新的步长计算,能够从梯度均值和梯度平方两个角度进行自适应地调节,而不是直接由当前梯度决定。
Adam的不足:
虽然Adam算法目前成为主流的优化算法,不过在很多领域里(如计算机视觉的图像识别、NLP中的机器翻译)的最佳成果仍然是使用带动量(Momentum)的SGD来获取到的。
【二】有哪些提高GAN训练稳定性的Tricks?
1.输入Normalize
-
将输入图片Normalize到 之间。 -
生成器最后一层的输出使用Tanh激活函数。
Normalize非常重要,没有处理过的图片是没办法收敛的。图片Normalize一种简单的方法是(images-127.5)/127.5,然后送到判别器去训练。同理生成的图片也要经过判别器,即生成器的输出也是-1到1之间,所以使用Tanh激活函数更加合适。
2.替换原始的GAN损失函数和标签反转
-
原始GAN损失函数会出现训练早期梯度消失和Mode collapse(模型崩溃)问题。可以使用Earth Mover distance(推土机距离)来优化。
-
实际工程中用反转标签来训练生成器更加方便,即把生成的图片当成real的标签来训练,把真实的图片当成fake来训练。
3.使用具有球形结构的随机噪声 作为输入
-
不要使用均匀分布进行采样

-
使用高斯分布进行采样
4.使用BatchNorm
-
一个mini-batch中必须只有real数据或者fake数据,不要把他们混在一起训练。 -
如果能用BatchNorm就用BatchNorm,如果不能用则用instance normalization。

5.避免使用ReLU,MaxPool等操作引入稀疏梯度
-
GAN的稳定性会因为引入稀疏梯度受到很大影响。 -
最好使用类LeakyReLU的激活函数。(D和G中都使用) -
对于下采样,最好使用:Average Pooling或者卷积+stride。 -
对于上采样,最好使用:PixelShuffle或者转置卷积+stride。
最好去掉整个Pooling逻辑,因为使用Pooling会损失信息,这对于GAN训练没有益处。
6.使用Soft和Noisy的标签
-
Soft Label,即使用 和 两个区间的随机值来代替正样本和负样本的Hard Label。 -
可以在训练时对标签加一些噪声,比如随机翻转部分样本的标签。
7.使用Adam优化器
-
Adam优化器对于GAN来说非常有用。 -
在生成器中使用Adam,在判别器中使用SGD。
8.追踪训练失败的信号
-
判别器的损失=0说明模型训练失败。 -
如果生成器的损失稳步下降,说明判别器没有起作用。
9.在输入端适当添加噪声
-
在判别器的输入中加入一些人工噪声。 -
在生成器的每层中都加入高斯噪声。
10.生成器和判别器差异化训练
-
多训练判别器,尤其是加了噪声的时候。
11.Two Timescale Update Rule (TTUR)
对判别器和生成器使用不同的学习速度。使用较低的学习率更新生成器,判别器使用较高的学习率进行更新。
12. Gradient Penalty (梯度惩罚)
使用梯度惩罚机制可以极大增强 GAN 的稳定性,尽可能减少mode collapse问题的产生。
13. Spectral Normalization(谱归一化)
Spectral normalization可以用在判别器的weight normalization技术,可以确保判别器是K-Lipschitz连续的。
14. 使用多个GAN结构
可以使用多个GAN/多生成器/多判别器结构来让GAN训练更稳定,提升整体效果,解决更难的问题。
----【经典模型&&热门模型】----
【一】U-Net模型的结构和特点?
U-Net网络结构如下所示:

U-Net网络的特点:
-
全卷积神经网络:使用 卷积完全取代了全连接层,使得模型的输入尺寸不受限制。 -
左半部分网络是收缩路径(contracting path):使用卷积和max pooling层,对feature map进行下采样。 -
右半部分网络是扩张路径(expansive path):使用转置卷积对feature map进行上采样,并将其与收缩路径对应层产生的特征图进行concat操作。上采样可以补充特征信息,加上与左半部分网络收缩路径的特征图进行concat(通过crop操作使得两个特征图尺寸一致),这就相当于在高分辨率和高维特征当中做一个融合折中。 -
U-Net提出了让人耳目一新的编码器-解码器整体结构,让U-Net充满了生命力与强适应性。
U-Net在医疗图像,缺陷检测以及交通场景中有非常丰富的应用,可以说图像分割实际场景,U-Net是当仁不让的通用Baseline。
U-Net的论文地址:U-Net
【二】RepVGG模型的结构和特点?
RepVGG模型的基本架构由20多层 卷积组成,分成5个stage,每个stage的第一层是stride=2的降采样,每个卷积层用ReLU作为激活函数。
RepVGG的主要特点:
-
卷积在GPU上的计算密度(理论运算量除以所用时间)可达1x1和5x5卷积的四倍. -
直筒型单路结构的计算效率比多路结构高。 -
直筒型单路结构比起多路结构内存占用少。 -
单路架构灵活性更好,容易进一步进行模型压缩等操作。 -
RepVGG中只含有一种算子,方便芯片厂商设计专用芯片来提高端侧AI效率。
那么是什么让RepVGG能在上述情形下达到SOTA效果呢?
答案就是结构重参数化(structural re-parameterization)。

在训练阶段,训练一个多分支模型,并将多分支模型等价转换为单路模型。在部署阶段,部署单路模型即可。这样就可以同时利用多分支模型训练时的优势(性能高)和单路模型推理时的好处(速度快、省内存)。
更多结构重参数化细节知识将在后续的篇章中展开介绍,大家尽情期待!
----【机器学习基础】----
【一】Accuracy、Precision、Recall、F1 Scores的相关概念?
首先Rocky介绍一下相关名词:
-
TP(True Positive): 预测为正,实际为正 -
FP(False Positive): 预测为正,实际为负 -
TN(True Negative):预测为负,实际为负 -
FN(false negative): 预测为负,实际为正
Accuracy、Precision、Recall、F1 Scores的公式如下所示:

Accuracy(准确率):分类正确的样本数占样本总数的比例。
Precision(精准度/查准率):当前预测为正样本类别中被正确分类的样本比例。
Recall(召回率/查全率):预测出来的正样本占正样本总数的比例。
F1-score是Precision和Recall的综合。F1-score越高,说明分类模型越稳健。
【二】梯度爆炸和梯度消失产生的原因及解决方法?
梯度爆炸和梯度消失问题
一般在深层神经网络中,我们需要预防梯度爆炸和梯度消失的情况。
梯度消失(gradient vanishing problem)和梯度爆炸(gradient exploding problem)一般随着网络层数的增加会变得越来越明显。
例如下面所示的含有三个隐藏层的神经网络,梯度消失问题发生时,接近输出层的hiden layer3的权重更新比较正常,但是前面的hidden layer1的权重更新会变得很慢,导致前面的权重几乎不变,仍然接近初始化的权重,这相当于hidden layer1没有学到任何东西,此时深层网络只有后面的几层网络在学习,而且网络在实际上也等价变成了浅层网络。

产生梯度爆炸和梯度消失问题的原因
我们来看看看反向传播的过程:
(假设网络每一层只有一个神经元,并且对于每一层 )

可以推导出:

而sigmoid的导数 如下图所示:

可以知道, 的最大值是 ,而我们初始化的权重 通常都小于1,因此 ,而且链式求导层数非常多,不断相乘的话,最后的结果越来越小,趋向于0,就会出现梯度消失的情况。
梯度爆炸则相反, 时,不断相乘结果变得很大。
梯度爆炸和梯度消失问题都是因为网络太深,网络权重更新不稳定造成的,本质上是梯度方向传播的连乘效应。
梯度爆炸和梯度消失的解决方法
-
使用预训练加微调策略。 -
进行梯度截断。 -
使用ReLU、LeakyReLU等激活函数。 -
引入BN层。 -
使用残差结构。 -
使用LSTM思想。
----【Python/C/C++知识】----
【一】Python中的None代表什么?
None是一个特殊的常量,表示空值,其和False,0以及空字符串不同,它是一个特殊Python对象, None的类型是NoneType。
None和任何其他的数据类型比较返回False。
>>> None == 0
False
>>> None == ' '
False
>>> None == None
True
>>> None == False
False
我们可以将None复制给任何变量,也可以给None赋值。
【二】Python中 和 的区别?
和 主要用于函数定义。我们可以将不定数量的参数传递给一个函数。
这里的不定的意思是:预先并不知道函数使用者会传递多少个参数, 所以在这个场景下使用这两个关键字。
是用来发送一个非键值对的可变数量的参数列表给一个函数。
我们直接看一个例子:
def test_var_args(f_arg, *argv):
print("first normal arg:", f_arg)
for arg in argv:
print("another arg through *argv:", arg)
test_var_args('hello', 'python', 'ddd', 'test')
-----------------结果如下-----------------------
first normal arg: hello
another arg through *argv: python
another arg through *argv: ddd
another arg through *argv: test
允许我们将不定长度的键值对, 作为参数传递给一个函数。如果我们想要在一个函数里处理带名字的参数, 我们可以使用 。
我们同样举一个例子:
def greet_me(**kwargs):
for key, value in kwargs.items():
print("{0} == {1}".format(key, value))
greet_me(name="yasoob")
-----------结果如下-------------
name == yasoob
【三】C/C++中面向对象和面向过程的区别?
面向对象(Object Oriented Programming,OOP)编程模型首先抽象出各种对象(各种类),并专注于对象与对象之间的交互,对象涉及的方法和属性都封装在对象内部。
面向对象的编程思想是一种依赖于类和对象概念的编程方式,一个形象的例子是将大象装进冰箱:
-
冰箱是一个对象,大象也是一个对象。 -
冰箱有自己的方法,打开、存储、关闭等;大象也有自己的方法,吃、走路等。 -
冰箱有自己的属性:长、宽、高等;大象也有自己的属性:体重、高度、体积等。
面向过程(Procedure Oriented Programming,POP)编程模型是将问题分解成若干步骤(动作),每个步骤(动作)用一个函数来实现,在使用的时候,将数据传递给这些函数。
面向过程的编程思想通常采用自上而下、顺序执行的方式进行,一个形象的例子依旧是将大象装进冰箱:
-
打开冰箱。 -
把大象装进冰箱。 -
关闭冰箱。
面向对象和面向过程的区别:
-
安全性角度。面向对象比面向过程安全性更高,面向对象将数据访问隐藏在了类的成员函数中,而且类的成员变量和成员函数都有不同的访问属性;而面向过程并没有办法来隐藏程序数据。
-
程序设计角度。面向过程通常将程序分为一个个的函数;而面向对象编程中通常使用一个个对象,函数通常是对象的一个方法。
-
逻辑过程角度。面向过程通常采用自上而下的方法;而面向对象通常采用自下而上的方法。
-
程序扩展性角度。面向对象编程更容易修改程序,更容易添加新功能。
----【模型部署】----
【一】主流AI端侧硬件平台有哪些?
-
英伟达 -
海思 -
寒武纪 -
比特大陆 -
昇腾 -
登临 -
联咏 -
安霸 -
耐能 -
爱芯 -
瑞芯
【二】主流AI端侧硬件平台一般包含哪些模块?
-
视频编解码模块 -
CPU核心处理模块 -
AI协处理器模块 -
GPU模块 -
DSP模块 -
DDR内存模块 -
数字图像处理模块
----【图像处理基础】----
【一】图像噪声的种类?
常规噪声
-
高斯噪声 -
脉冲噪声 -
泊松噪声 -
乘性噪声 -
瑞利噪声 -
伽马噪声 -
指数噪声 -
均匀噪声 -
椒盐噪声 -
散粒噪声 -
泊松噪声
对抗噪声
-
白盒对抗噪声 -
黑盒查询对抗噪声 -
黑盒迁移噪声 -
物理对抗噪声
【二】Python中OpenCV和PIL的区别?
-
在读取图片时,OpenCV按照BGR的色彩模式渲染通道,而PIL按照RGB的色彩模式渲染通道。 -
OpenCV性能较优,可以作为算法与工程的必备模块。
OpenCV的一些常用操作:
import cv2 # 导入OpenCV库
import numpy as np
img = cv2.imread('xxx.jpg', 0) # 读取图片:灰度模式
img = cv2.imread('xxx.jpg', -1) # 读取图片:BGRA模式(BGR+Alpha通道)
img = cv2.imread('xxx.jpg', 1) # 读取图片:BGR模式
img = cv2.imread('xxx.jpg') # 读取图片:第二参数默认为1,BGR模式
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 将颜色通道从BGR转为RGB
if img == None: # 读取图片失败
print('image failed to load')
cv2.imshow('src', img) # 图片源src为img
print(img.shape) # 输出图片(高度h,宽度w,通道c)
print(img.size) # 像素总数目
print(img.dtype) # 输出图片类型,uint8为[0-255]
print(img) # 输出所有像素的RGB值
cv2.waitKey() # 按键关闭窗口
# waitKey(delay)函数的功能是不断刷新图像,频率时间为delay,单位为ms,返回值为当前键盘按键值
# waitKey() 是在一个给定的时间内(单位ms)等待用户按键触发; 如果用户没有按下键,则接续等待(循环)
imgL = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 读取img灰度图
cv2.imshow('gray',imgL) # 图片源gray为imgL
cv2.imwrite('imgL.jpg',imgL) # 将imgL储存名为imgL.jpg的图片
img = img.transpose(2,0,1) # 图片矩阵变换为(通道c,高度h,宽度w)
img = np.expand_dims(img, axis=0) # 图片矩阵扩展维度添加在第一维
print(img.shape) # (1,通道c,高度h,宽度w)
print(img[10,10]) # 访问图片img像素[10,10],输出 [0-255 0-255 0-255]
print(imgL[10,10]) # 访问灰色图片img像素[10,10],输出 0-255
img[10,10] = [255,255,255] # 修改图片img像素点[10,10]为[255,255,255]
imgL[10,10] = 255 # 修改灰色图片img像素点[10,10]为255
img[:,:,2] = 0 # 将R通道全部修改为0
roi = img[200:550,100:450,:] # ROI操作,坐标(高度范围,宽度范围,通道范围)
cv2.imshow('roi',roi) # 图片源roi为roi
PIL的一些常用操作:
from PIL import Image #导入PIL库
import numpy as np
img = Image.open('../xx.jpg') # 读取图片
imgL = Image.open('../xx.jpg').convert('L') # 读取图片灰度图
imgL.show() # 展示灰度图
img1 = img.copy() # 复制图片
print(img.format) # 输出图片格式
print(img.size) # 输出图片(宽度w,高度h)
print(img.mode) # 输出图片类型,L为灰度图,RGB为真彩色,RGBA为RGB+Alpha透明度
im.show() # 展示画布
imgData = np.array(img) # 将对象img转化为RGB像素值矩阵
print(imgData.shape) # 输出图片(宽度w,高度h,通道c)
print(imgData.dtype) # 输出图片类型,uint8为[0-255]
print(imgData) # 输出所有像素的RGB值
imgN = Image.fromarray(imgData) # 将RGB像素值矩阵转化为对象imgN
imgN.save('xxx.jpg') # 储存为文件xxx.jpg
r ,g ,b = img.split() # 分离通道
img = Image.merge("RGB", (b, g, r)) # 合并通道
# ROI(region of interest),只对ROI区域操作
roi = img.crop((0, 0, 300, 300)) # (左上x,左上y,右下x,右下y)坐标
roi.show() # 展示ROI区域
#捕捉异IOError,为读取图片失败
try:
img = Image.open('xxx.jpg')
except IOError:
print('image failed to read')
----【计算机基础】----
【一】Git,GitLab,SVN的相关知识
Git
Git是当前主流的一种开源分布式版本控制系统,可以有效、快速的进行项目版本管理。
Git没有中央服务器,不同于SVN这种需要中央服务器的集中式版本控制系统。
Git的功能:版本控制(版本管理,远程仓库,分支协作)
Git的工作流程:

Git的常用命令:
git init 创建仓库
git clone 克隆github上的项目到本地
git add 添加文件到缓存区
git commit 将缓存区内容添加到仓库中
GitLab
GitLab是一个基于Git实现的在线代码仓库软件,可以基于GitLab搭建一个类似于GitHub的仓库,但是GitLab有完善的管理界面和权限控制,有较高的安全性,可用于企业和学校等场景。
SVN
SVN全名Subversion,是一个开源的版本控制系统。不同于Git,SVN是集中式版本控制系统。
SVN只有一个集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。
SVN的特点是安全,效率,资源共享。
SVN的常用操作:
Checkout 检出代码
Update 更新代码
Commit 提交代码
Add 提交新增文件
Revert to this version + commit 撤销已经提交的代码
【二】协程的相关概念
协程(Coroutine,又称微线程)运行在线程之上,更加轻量级,协程并没有增加线程总数,只是在线程的基础之上通过分时复用的方式运行多个协程,大大提高工程效率。
协程的特点:
-
协程类似于子程序,但执行过程中,协程内部可中断,然后转而执行其他的协程,在适当的时候再返回来接着执行。协程之间的切换不需要涉及任何系统调用或任何阻塞调用。 -
协程只在一个线程中执行,发生在用户态上的一个逻辑。并且是协程之间的切换并不是线程切换,而是由程序自身控制,协程相比线程节省线程创建和切换的开销。 -
协程中不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

协程适用于有大量I/O操作业务的场景,可以到达很好的效果,一是降低了系统内存,二是减少了系统切换开销,因此系统的性能也会提升。
在协程中尽量不要调用阻塞I/O的方法,比如打印,读取文件等,除非改为异步调用的方式,并且协程只有在I/O密集型的任务中才会发挥作用。
----【开放性问题】----
这些问题基于我的思考提出,希望除了能给大家带来面试的思考,也能给大家带来面试以外的思考。这些问题没有标准答案,我相信每个人心中都有自己灵光一现的创造,你的呢?
【一】如何保持数据持续稳定的支持业务?
在“CV兵器”基本上都是开源的情况下,数据成为了支持业务迭代最重要的一部分,如何建立数据护城河,形成业务与数据双向正反馈,是AI行业从业者必须要面对的课题。
【二】如何分辨demo业务,一次性业务以及外包业务?
这个问题不仅可以考察面试者,面试者也可以用来反向判断面试官及其背后公司的运行逻辑。陷入demo业务,一次性业务以及外包业务的循环中是无法成长的,也不利于建立业务/产品的护城河。知道了这一点,那么如何去选择部门,如何去选择公司,如何去看需求,就变成了非常值得研究的事情。
精致的结尾
最后,感谢大家读完这篇文章,希望能给大家带来帮助~后续Rocky会持续撰写“三年面试五年模拟”之独孤九剑的系列文章,大家敬请期待!
Rocky一直在运营技术交流群(WeThinkIn-技术交流群),这个群的初心主要聚焦于技术话题的讨论与学习,包括但不限于CV算法,算法,开发,IT技术以及工作经验等。群里有很多人工智能行业的大牛,欢迎大家入群一起学习交流~(请添加小助手微信Jarvis8866,拉你进群~)
作者介绍
