很全了!社招CV岗面试知识点笔记

作者 | chen212  编辑 | 计算机视觉算法随笔

点击下方卡片,关注“自动驾驶之心”公众号

ADAS巨卷干货,即可获取

点击进入→自动驾驶之心【求职交流】技术交流群

本文只做学术分享,如有侵权,联系删文

全文篇幅较长, 建议mark后预留充足时间, 辨证学习+思考!

一、python

二、C++ 

三、linux

四、pytorch

五、DL 基础

六、模型部署/压缩

七、传统视觉

八、项目思维, 模型优化

九、智力/code题

一、python

  1. import 加不加点

    加点是绝对导入, c2 import 了c1, c3 再来import c2的话, 也可顺利使用到c1

    不加点, 则只是相对导入, c3 import c2, 会出现找不到c1的问题. 

2. is更严格, 检查value和地址是否一致, ==仅检查value是否一致

3. 装饰器: 

def logger(func):

    def wrapper(*args, **kw):

        print('主人, 我准备开始执行: {} 函数了:'.format(func.__name__))

        func(*args, **kw)

        print('主人, 我执行完啦.')

    return wrapper

@logger

def func(a,b):

    print("{}+{}={}".format(a,b,a+b)) 

func(100, 20)

装饰器: 不改变源函数的情况下添加功能, 场景: 插入日志, 计时.

迭代器: __iter__(), __next__()两个方法: 返回对象本身, 返回下一个对象. (迭代器就是每个元素依次计算出,有前后顺序. 下一个值依赖上一个值)

生成器: 特殊的迭代器, 使用yield关键字一个个"吐"出元素

4. return 和 yield 

yield 针对list等循环数据, 可依次一一返回数据; 

return只能在循环结束后一次性返回所有结果. (类似py2中的xrange和range, xrange是一个个的生成, range是一口气生成. python3合并了这俩统一为range, 内存更友好了.)

5. map(): 参数1: 函数or数据类型, 可对参数2做对应的函数运算or数据类型变换.   py2的map()直接返回(可迭代)结果, py3则返回一个迭代器.(得手动list一下才可看到具体结果.)

6. transpose(): 矩阵转置; reshape(): 打散再重排, 重排规则可指定(最内维度开始还是最外维度开始)

7. python常见数据结构: list, tuple, set(), dict(), numpy的Ndarray, Matrix, pandas的DataFrame.  dict按value排序: sorted(dict.items(), reverse=True, key=lambda x:x[1]) [reverse=True降序, False升序]

8. * 星号: 

    1. * 单星号: 任意长度的可迭代数据

    2. ** 双星号: 函数传参; 合并俩字典

9. python深浅拷贝: 都会生成一个看起来相同的对象, 区别: 拷贝出的对象的地址, 是否和原址一样. 体现于, 有两层地址时, 

浅拷贝: 最外层地址变了, 内层的可变对象(地址不变但值会变)的地址没变(内层新旧会一起变)   深拷贝: 两层地址均会变, 则不出现新旧一起变.  

10. Python的内存管理: 引用计数; 垃圾回收; 内存池  

    1. 内存池: (预先申请一块空间,有内存需求则往这里使用,不够了再申请新的块. 避免零碎的内存申请需求.)

    2. 垃圾回收: 回收无用的内存空间(没对象指向的内存, 视为无用的内存空间). python  解释器来做这个事. 具体做法:

    1. 引用计数  为0了就是无对象指向了, 就是垃圾, 回收这块内存!

    2. 标记清除: 内存快占满时, python会暂停所有程序, 然后从0开始对所有内存中的数据扫码打标记, 并一次性删除被标记上的数据.

    3. 分代回收: 新, 青, 老

    新创建的对象都放在新, so创建前都会查新满没满; (满了就会开始启动垃圾回收, 新里面剩下没被回收的, 就放入青. 青到老的维护也是一样)

11. python 的 print加不加括号

    python3加, 因为print是一个内置函数,有多个参数

    python2不加, 因为print是一个语法结构

12. python list的底层: 是一个数组, 其中存放着PyObject类型的指针

13. python new 和 init 区别:

    1. new: 实例创建前, 调用, 返回此实例对象.  

    2. init: 实例创建后, 调用, 给一些初始值做初始化. 

14. 下划线:

    1. _a: 前单下划线: 保护内容, 仅允许内部使用or子类继承, from xx import xx时不可被导入

    2. __a: 前双下划线: 较之1更严格, 连子类都不可继承, 私有仅本类使用.

    3. __a__: 前双下划线: 为python的特殊方法

    4. a_: 后单下划线: 避免和python关键词冲突, 无其他含义.

15. lambda x: 2*x+1

16. global 关键字修饰 全局变量

17. python sort函数实现原理: Timsort 

    1. 先找到list已排好序的块

    2. 合并这些块

18. callable: 检查是否可被调用

19. 正则表达式:re.match(pattern, string, flags = 0)

20. GIL全局锁: cpython的特性, 保证一个进程(processing)中同一时刻只有一个线程在执行(避免多个线程间数据干扰, 垃圾回收等带来执行错误.) 

    线程释放GIL:

    1. 线程进入IO操作之前会主动释放, 所以io密集型任务适合用多线程

    2. 解释器不间断的运行了1000字节码(py2)或 15毫秒(py3) 后会释放GIL

21. 多线程/多进程: 

    1. 线程threading   cpu io密集场景下使用.   m个cpu, 线程数可: m+1、2m、io操作很多的话可10m

   2. 进程: from multiprocessing import Process  计算/cpu密集型场景

python多线程怎么占满核? (不可实现, 需要多进程,且尽量每个cpu分一个进程)

线程, 进程, 怎么通信?

    1. 多进程通信: queue()进程间做通信, pipe()单个进程内通信,两端分别负责,读写.

    2. 多线程通信: 一般线程池写个循环, 然后.start()开启各个线程. 

通信内容包括: 锁: lock(), rlock(); .event()设置线程等待; .main_thread()返回主线程

二、C++

1. const,  #define宏定义

const定义常量有数据类型, #define则无.

数据类型安全检查只对const有用, define无法查数据可能引发错误.

2. malloc和new 

new创建对象, 无需指定内存大小, 返回对象的指针, 对象类型明确.

malloc创建对象, 要指定内存大小, 返回void *, 后续还需自行转换类型. 

3. 虚函数 和 纯虚函数 virtual  

纯虚函数: 没有被实现, 只是被定义好了

虚函数: 当基类指针指向一个子类对象a, 同时基类中也有a(父子中出现重名).

基类声明了虚函数,则调用子的a, 否则调用基的a. [基中声明virtual,则子中的同名对象可被基使用.]      虚继承: 为了实现多重继承 (不常用)

4. 结构体与类的区别: class与struct

struct默认权限为 public

class默认权限为 private

5. C++多线程(thread)通信: 共享内存, 互斥锁, 死锁, 

共享内存出现在: 多线程间涉及共同操作某数据, 则需对数据做"保护". so引入"互斥锁": lock(), unlock    死锁: 出现>=2个互斥量, 均在等待释放而无法工作.

6. 全局变量: 用extern修饰(也可不用), 定义在'{}'外面

7. 内存泄露: 该delete的变量用完后没del, 导致泄露. 

可去检测程序运行时内存耗用情况, 出现长期占用或耗用贼大, 则debug排查是否泄露.

8. 构造/ 析构函数: 

构造函数: 定义对象后自动执行, 无需用户调用, 无返回类型, 用户也可自行重写构造函数并传参进来;   初始化顺序: 基类 -> 成员类 -> 派生类

析构函数: 完成对象生命周期结束后的, 清理工作. 用户未定义则系统自动实现, 用户定义了则可自行加一些别的功能(如输出一些信息);   初始化顺序: 派生 -> 成员 -> 基类 

析构函数 不是必须是 虚函数:  父的析构定义为虚,则父删除某资源子也会删除. 否则父中删除子不变化.  构造函数可以是私有的.

10. static

修饰局部变量时, 出函数体变量仍有效;

声明函数, 则此函数不可被其他文件引用;

修饰全部变量: 则是为了让重名但来自不同文件的变量不共享冲突. (类似修饰函数,static后在其他文件中就不可见了.)

11. 引用和指针: 

引用: 不可为空, 一定要初始化(因为它是某个对象的别名), 不可变

指针: 可变, 可为空, 本身是个对象有自己的地址, 它的内容是: 某一对象的内存位置.

智能指针:  自动在对象生命周期结束后, 释放内存. (防止内存管理出错,泄露之类)

一个智指例子: shared_ptr 引用型共享指针

    1. 指向内存内的一块资源, 不同指针可指向同一份资源

    2. 内部使用引用计数机制, 引用为0则析构函数释放本块资源.(这就完成自动del了)

12. vector和数组的区别, vector扩容?

    初始化时: 数组长度需指定,后续不可变, vector无需指定,后续长度可变

    名字: 数组名表示数组的首地址,不仅是名字还是个指针, vector的名就只是个名

STL中vector的: 插入, 读取. 时间复杂度,实现原理

    1. 连续空间存储, 支持指针访问; 两个迭代器:start, finish 指向首尾  (end_of_storage指向当前可使用空间的最尾部)

    2. 插入: push_back 另配置一块空间(原空间大小*2), 然后将原内容拷贝(从0index开始). 再放置新元素, 并随后拷贝插入点后的原元素. 完成后再释放原vector的空间. (so对vector的任何引起空间重配操作, 均会使得指向原vector的迭代器失效) (动态数组也是这样完成插入元素的)

    3. 删除: pop_back() 销毁最后一个元素, 不会做内存释放

13. 数组与链表

数组内存连续, 链表内存不连续(存当前节点和下一节点信息)

数组优于链表的点: 

    1. 省内存,不用每个元素存下一元素的信息;

    2. 访问快且可随机访问, 因为是连续内存存放, 根据首地址+index计算就可访问. O(1)

   (链表则需要从0开始, 逐步依次走到想要访问的位置)

链表较之数组的优点:

    1. 插入删除快, 只涉及修改节点一处的信息变化. (但数组, 插入的话,插入点后的数组都需要移动内存位置,删除也是. 除非修改位置在最尾部才也比较快)

    2. 内存利用更灵活. 数组插入,需要重新申请原内存*2的空间, 这较容易带来内存不足. 链表零散灵活的放,不会出现这个隐患.

14. 矩阵怎么在内存中保存

    1. txt: vector push和fout.open

    2. opencv(.xml): cv::Mat矩阵 

15. 内存对齐

以4为倍数内存开始读写 (计算机以字节为单位, 分4 8 16 32等, so需要以4为单位对齐)

对齐规则:

    1.基本类型的对齐值就是其sizeof值;

    2.结构体的对齐值是其成员的最大对齐值;

    3.编译器可以设置一个最大对齐值, 实际对齐值是该类型的对齐值与默认对齐值取最小

16. 散列表(哈希表)的实现原理 (python的dict()的底层也是散列表, 平均查找时复:O(n)) 

每个结构体包含: key, value, next(指向下一发生散列冲突的记录)

17. 虚拟地址和物理内存

物理内存: 有限, 全部进程都放物理上会不够, 故引出虚拟空间(虚拟的,用户把部分内容放虚拟空间, 使用则需排序调度到物理上)

虚拟地址: 防止一个进程可直接访问另一进程地址空间. 每个进程有4G大小虚拟地址空间, 均是从0编址, 程序直接操作的是虚拟地址空间, so即使相同编址指向的内容也不一样. 保护到了. 

18. 栈(先进后出)

栈支持动态扩容 (用支持扩容的数据实现, 栈满时则申请更大的数据, 并做数据搬移)

19. C++的面向对象: 封装, 继承, 多态

    1. 多态:允许不同类的对象对同一消息做出响应  (发送消息=函数调用)

   通过判断所引用对象的实际类型, 选择调用哪个方法. 

    2. 多态存在的三个必要条件: 

        1. 有继承 (有父子关系);  2. 有重写(父子中同函数名实现不同功能, 参数相同); 3. 父类引用指向子类对象(父的参数给到子中的函数)

20. 重载 和 重写

    1. 重写出现在父子间, 重载出现在同一个类内,方法名相同但参数不同(个数顺序类型均可不同)

    2. 重写要求: 重写方法的修饰范围大于被重写的范围; 重载没这个要求

21. gcc编译过程:

    1. 预处理生成.i文件

    2. .i转为汇编语言生成.s

    3. 汇编编程机器代码, 生成.o

    4. .o生成可执行文件 .exe之类的.

三、linux 

1. nohup python3 __main__.py >log.log 2>&1 &  [后台挂命令并写入log]

2. 查看CPU使用率: atop

3. 显示磁盘使用情况: df -lh

四、pytorch

1. 点乘: a * b  or torch.mul(a,b) 

2. 矩阵乘法: torch.mm(a, b)  带batch维度的矩阵乘法: (b*m*n) * (b*n*p) -> (b*m*p): torch.bmm(a, b)

3. torch.nn.SyncBatchNorm多卡BN同步(单张卡的batch size很小时, 使用SBN起到扩大网络batch size作用)

4. 初始化: 

torch.nn.init.kaiming_normal_ : conv 

torch.nn.init.constant_  : bias值 or bn,focal loss之类的需学参数是alpah, beta, gamma

torch.nn.init.xavier_normal_(layer.weight) : 线性层

5. 分布式训练: 

model = nn.DataParallel(model) 单机多卡, 主卡算梯度再同步, 主卡负载高;

nn.DistributedDataParallel: 支持单机多卡, 多机多卡: 每个gpu独立进程算梯度, distributed.init_process_group 做各进程间通信

7. 转置: torch.t(tensor) or tensor.T

8. 多进程读数据:

torch.utils.data.DataLoader(dataset,batch_size=,shuffle=,sampler=,batch_sampler) 

sampler,batch_sampler: 默认都是None, 生成一系列index. 可自定义sample函数来读取数据并生成index.  

dataset完成: 根据index读数据和标签;

DataLoader完成: 可迭代数据装载 

9. detach(): 梯度截断,且返回一个无梯度新变量

detach_(): 截断且直接改变本结点(带_下划线的都是原地修改操作)

.data: 类似引用, 获取数据value

10. nn.functional/nn.Module: 

nn.functional无需实例化, 创建无参数的layer: 如relu pooling之类的

nn.Module需要学参数的话得手动加: params=xxx, need_grad=True

nn.Module: 继承nn.Module父类, 创建有参数的layer: 如conv. 自动实现forward()

11. torch.Tensor 和 torch.tensor 区别

    1. torch.Tensor(data)是类, tensor是ta的实例   (可创建一个空tensor, torch.tensor()不可会报错)

    2. torch.tensor(data)是函数, 可把data转为指定的dype类型(or遵从data的类型). (torch.FloatTensor、torch.LongTensor、torch.DoubleTensor等)

12. torch.no_grad 和 required_grad=False 区别

    1. torch.no_grad: 是一个上下文管理器,禁止梯度计算. 用在网络推断,减少计算内存

    2. required_grad=False: 用来冻结部分网络层不参与梯度/参数更新  (一个是推理时不计算, 一个是训练时不更新)  

13. squeeze()删除维度1, unsqueeze()添加维度1. 

14. model.train()开启训练, forward() backward()都是自动的  

15. PyTorch显存: 参数, 梯度, 网络中间结果, 优化器状态 (显存占用量约为参数量x4)

    1. torch.cuda.memory_allocated()  所有tensor占用的显存和

    2. torch.cuda.max_memory_allocated() 调用函数起来达到的最大显存占用字节数

第一次优化器状态, 会增加x2显存开销

五、DL 基础:

1. ROI Align: 原图的box整数坐标下采样n倍后变float, 取value则只能坐标取整, 取整后映射回原图位置就偏了.  so(双)线性插值, 获取float位置处的value, 解决坐标往回映射的偏移问题.

2. 小目标检测的改进:

    1. FPN多尺度, 深浅特征融合

    2. 不同大小的目标自适应的选择在哪一层feature map检出(cvpr18的PAN结构, 深至浅融合+浅至深融合, 然后各种concat到一起, 自适应让网络挑选)

    3.扩大输入尺寸  

    4. 多一些全局信息, 加入attention. 让网络能有更多的上下文, 这对大小目标出现遮挡的场景, 也有比较好的目标检出效果.  (DETR中做了可视化展示.)

3. 全连接层fc和Conv层的区别: fc输入尺寸不可变, conv可变; 如cls/seg的最后一层数=类别+1, 用conv比fc方便.  

4. fl: = -alpha*(1-pt)^gamma * log(pt); CE = -log(pt)

5. softmax = e^xi / sum(e^xj)j=1~k 

6. CE交叉熵可作为损失函数的原因: CE是KL散度的一部分, 而KL可量化两个分布相似度. 

7. relu为啥比sigmoid好: 

    1. sigmoid的导数使得网络的梯度容易陷入: 消失和饱和,使训练困难. relu导数则不会. 

    2. relu计算简单快, 且可给网络带来一定参数稀疏性(负值直接置0,又快又稀疏)

leaky relu和relu:

    relu: 小于0的值直接置0, 会导致部分神经元在训练中被"杀死", 但这个特点也达到: 特征稀疏的作用. 

    leaky relu: 负数值scale下: -10 变 -5. 没有绝对的好坏, 这俩激活函数, 根据场景而定.

8. 1x1卷积的作用: 

    1. 升降维(channel变化)

    2. 增加非线性

    3. 可做为一种残差连接方式 

9. 上采样有哪些方法? 

    1. 各种插值(如双线性,近邻,三线性等) 

    2. 转置卷积(即:反卷积)

    3. 空格处填0或复制同样的值(反pooling操作)

转置卷积棋盘格效应: 像素不平滑不连续, 一块块的像棋盘. (kernel不被stride整除,出现棋盘)   why: 当stride>1, 反卷积会在图像间隙中补0. 举例kernel=3, 则连续两次卷积,实际计算的是: 2个0+1个原像素; 1个0+2个原像素.   插入0且0的个数不等, 带来了"明暗"不稳定效果, 也即棋盘效应. 

怎么缓解棋盘效应?

    1. kernel size设计为能被stride整除

    2. 补0还是有点粗糙, 可先对原图做(双邻三)线性插值, 然后再遵循1.的尺寸设计, 效果会好很多! 

下采样: pooling和卷积均可. (设置好stride就行了.)

10. 欠拟合表现: 模型不收敛, 验证集效果差. (优化办法: 网络加深, 优化器, 初始化, 激活函数等调整)

11. 轻量网络:

    1. mobilev1: 深度可分离卷积; 分辨率scale; channel scale

    2. shufflenetv2: 提倡cint=cout; 适当使用分组卷积; 提高网络并行度; 合并多个"逐元素"计算

12. 缓解过拟合:  (train loss小但val loss大)

    1. L1会使得一些w趋近1实现特征稀疏; L2会使一些w value变小(参数太大太敏感)

    2. 剪枝网络结构(net太大参数太多, 数据不够训)

    3. 补充数据, 加强数据增强

    4. Dropout, early stop

13. 稀疏卷积: 对输入输出不为空的数据建立位置哈希表和RuleBook(类似im2col), 只对有效数据计算卷积减少计算量!

14. 陷入局部最优如何解决? (关于怎么判断, 大概就是换一批同分布但不同的数据,模型结果不稳定)

    1. 继续训, 看能否跳出(对应的合理设置lr)

    2. 重新开启训练, 注意调整lr策略, 优化器, 初始化方式, 激活函数等.

15. batch size过大会怎样?

容易陷入局部最优; 小batch or batch=1可认为是人为加入噪声, 使模型走出鞍点在更大范围内寻找收敛点.  建议: 训练早期大batch size加速收敛, 训练后期小batch引入噪声, (即做纯SGD慢慢把error磨低)

16. 常用数据增强:

    1. 几何变换: 平移, 旋转, 翻转, 剪裁, 缩放, 扭曲形变 等

    2. 颜色变换: 颜色空间转换, 亮度调整, 模糊(随机加噪), 灰度化 等 

    3. 一些针对性的, 如目标检测中: cutout, mixup, 随机mask遮挡擦除 等

    4. Color Jitter扰动: 对比度, 亮度, 饱和度, 色度 等 调整   

    5. 项目中: 先用base的aug方法训模型, 然后针对fail case(太小,太大,光照暗亮,形态特殊等原因导致未检出)性设计aug方法

    6. 还有些auto aug的库可使用, 但一般项目不会直接用, 训行业大模型时候可实验使用试试 

17. 样本/类别不平衡:

    1. 一个batch内, 做类别均等采样(保证每个类别都采样到, 每个类别数量多少可自行设计.量不够的类做sample重采样)

    2. 对loss weight做权重设置

    3. focal loss, OHEM之类的

18. Map计算方法: mean average precision

    1. 基于每个recall计算最大的precision, 取所有p的均值, 即ap

19. AUC: 给一个正例,一个负例. 模型预测值 Ptp > Pfp 的可能性.

20. 优化器: 

    1. SGD: batch(minbatch)内样本的梯度, 结合学习率, 更新权重值

    2. SGD+动量: 在SGD的基础上, 不仅仅看当前梯度, 还考虑历史更新方向.

        v = alpha*v + beta*diff; wi = wj+v  [diff当前梯度, v记录历史更新方向]

    3. Adam: 自适应调整学习率. 考虑梯度的一阶二阶信息. 

    4. AdamW: 理论上: AdamW=Adam+Weight Decay (搭配大点的weight decay效果不错. ssa中甚至开到了0.01, 0.05)

21. loss nan 处理:

先查数据是否有问题; 再code bug,网络层写错啥之类的; 再是训练方式:初始化方式不当,bn没加,学习率过大,损失函数不当等; 最后: 可能除以了0, 考虑是网络过程中出现了0值, 定位到0去改; 

22. 7*7卷积 3个3*3卷积:

    1. 7x7大卷积, 可作为大图的特征提取conv, 常在网络的第一层使用. 感受野一下子就上来了. (ConvNeXt, resnet的第一层)

    2. 多几个3x3可近似7x7, 计算量更少(中间的激活次数还更多增强非线性)

23. 目标检测:

    1. two-stage效果比one-stage好的原因:

        1. 一定程度在RPN中, 先解决了部分样本不平衡问题(正负的个数, 难度差异)

        2. 有点cascade的意思, RPN筛选了一遍好的proposal, 然后还ROI pooling, 再做cls类别细分和reg. (cls细分相对one-stage也会精度更好些的.)

        3. two的小目标效果会更好(one的input size开太大容易OOM吃不住, 这直接就影响了小目标的精度. 把输入放大是有助于小目标检出!)

    2. 回归函数为啥是 L1 smooth, L1,L2差在哪?

        1. L2差在, gt和pred>1时, 平方一下loss太大容易爆炸

        2. L1 smooth较之L1的优势是: gt和pred的误差以1为分界点, <1则平方(让梯度足够小,慢慢小步优化), >1则L1(绝对值差, 不像L2平方下爆炸).

24. Transformer:

    1. attention如何计算: kq三个向量做"相关性"计算, 再加权到v上.

    2. self attention除以根号k: 为了scale!!! : 

        1. 内积值可能很大, 不normalize的话, 计算量大, 内存占用大, 且有溢出风险; 

        2. 内积值太大送给softmax,可能导致梯度很小. 

        softmax的梯度函数: (a: S(xi)*(1-S(xi) or b: (-S(xi)*S(xj))). 先看a, xi太大了, S(xi)趋近于1, 则a值趋近0; 再看b, 当各xi,j间方差很大, 则xi与xj要么一个0要么一个1, b值仍会趋于0.  除以sqrt(dk), 把内积方差值化为1, 就可解决上面俩"隐患".

    3. 用 LN(layer norm):

       因为样本长度不一致, 用BN需要把各个句子padding到size一致, 添加太多冗余信息.

       另外, 一个句子在内部做统计量抓取就可了, 单条句子本身就有独立性和分布特性, 无需跨越不用样本(尤其样本间差异很大时更没必要) 

    4. swin transformer: 

        1. 在局部小window内做attention, 计算量从图像分辨率的平方倍优化至线性倍; 

        2. 使用shifted层级结构+patch merging, 实现多层级多感受野目的(这也是为分割,检测等密集型预测任务做的关键性优化)

    5.  transformer编码顺序信息: 

        用sin, cosin实现每个句子中词index等价线性, 不受句子长度影响. 4个词的句子和10个词的句子, index=2处的编码力度一致.

    6. transformer一般用什么优化器:

        建议选择Adamw(搭配大点的learning rate decay), Adam, 毕竟数据需求大且显存要求高.  理论上: AdamW=Adam+Weight Decay

六、模型部署/压缩

1. 算子融合(计算图优化)

    1. chong重参处理: 

        1. 为何可重参: 

           1. 卷积的同质性: 一个系数乘在卷积核里, 和卷积后再乘, 作用一样.

           2. 相加性: 两个卷积分别处理后再相加, == 卷积核相加, 再做一次conv计算即可)

    2. RepVGG (使得部署结构简化且加速, 降低硬件支持需求.)

    将并联的带BN的3x3conv,1x1conv,残差结构(可看做1x1的Depthwise conv), 转换为一个3x3conv.

    3. 其他重参处理:

        1. 多个conv后的结果在维度上concat, 转为: 直接多个卷积的weight,bais concat, 再做一次conv计算即可.

        2. average-pooling 转为: conv, conv value为 1/nxn. n是wind大小. 计算更快. 

        3. 1x1Conv+1x3Conv+3x1Conv(并联)->Conv. 利用conv的相加性.

        4. conv和bn融合: cbr -> (cb)r  内存使用和推理速度都好.  

2. 低精度推理

    一般backward才会涉及高精度防止太小的梯度被抹掉. 推理阶段只forward不back,so可做低精度处理, 加速且省显存, 牺牲一点点精度.

3. 优化卷积/矩阵计算:

    1. 工程上: 

        1. im2col 转化为矩阵乘法然后可继续优化矩阵运算(如gemm)

        2. Winograd算法(卷积计算中某些值是一样的在重复计算, so可在conv前计算一次缓存起来, 砍掉冗余计算: https://zhuanlan.zhihu.com/p/74567600)

    2. 设计结构上: 

        1. 多个小卷积代替一个大卷积   (3个3x3 -> 1个7x7)

        2. 深度可分离卷积 (转为depth-wise和point-wise)

   计算量: depth: cin x h x w x k1 x k2, point: cin x cout x 1x1 x h x w

   normal conv: cin x cout x h x w x k1 x k2 

        3. 1x3 + 3x1 代替3x3. (参数减少但可能带来一些性能下降)

4. 浮点数在计算机中的表示方式: M x 2^E  (M: 尾数; E: 阶码) 

    1. float32位: 1符号 + 8E + 23M

    2. double64位: 1符号 + 11E + 52M 

5. 量化: 线性量化: 均匀(线性)量化; 非线性量化: 如log量化 

    对参数x, 做 线性 or log 映射截断 (截掉过多的浮点位)

6. 知识蒸馏:  

    让student的输出p和teacher的输出q近似, 仅更新student的参数.

    loss = CE(y, p) + alpha * CE(p, q)

    温度系数T(loss中使用):

    知识蒸馏提出softmax-T: exp(zi/T) / sum(expzj/T)

    T=1为softmax, T接近0,分布近似one-hot, T越大分布越平缓,起保留相似信息作用. 

    T怎么取: 

    T的作用有点类似标签软化, sharpness的one-hot到平滑些的分布(类似label smooth)

    训好的teacher预测值q是偏硬的, 加上T则可软化,从而提供更多信息给student(最大值仍指向真类别, 其他维度上值小点,可告诉网络此sample与一些非真类别有相似处)  [so想要平滑程度越大, T取值就越大. 蒸馏过程中对T逐渐降温(值减小)到最终T=1]

7. 剪枝: 

    1. 砍 全连接层的冗余参数

    2. 去除 value趋于0的神经元

    3. 神经元的梯度过小, 也可被剪

一般: 训好大模型, 剪枝, 微调后, 再让slim model train一会数据, 适应下.

七、传统视觉:

1. 均值/高斯 滤波: nxn转为: (1xn) * (nx1), 计算量由 HWnn 降低为 2nHW.

2. 透射变换, 仿射变换: 

    1. 仿射: 旋转, 平移, 缩放 等处理.

    2. 透射: 2D矩阵 转 3D空间效果, 全景拼接, 等处理. 

区别: 仿射是透视的子集, 放射后平行的仍平行, 透射则不一定. 

3. 图片去水印: 一般白色阴影水印(且像素值稳定,和背景有融合), 设置像素阈值命中替换value即可. 

4. 图像降噪方法:  滤波(均值,中值,高斯,双边) 

5. 边缘检测算子: Roberts, Sobel(差分,平滑两部分)

6. 图像锐化: 使模糊图像变清晰. 可用Sobel, Laplace算子等实现 

7. canny边缘检测: 一阶偏导计算梯度的幅值和方向, 再用双阈值筛选把边缘连起来.

八、项目思维, 模型优化: 

    1. 竞品调研(确定大方向, 熟悉这个事已有的解决方案是怎样的: 分割检测做? 已有方案的速度精度等)

    2. 数据调研(收集数据, 最好是线上的(or客户的真实数据), 和项目场景一致的开源数据也可; 准备label)

    3. 论文调研(看经典的基础论文先了解这个领域, 再追新论文看是否可用到项目上)

    4. 项目分析: 

        1. 分析数据的[统计信息], 根据信息设计数据前处理(检测里anchor和gt匹配, 项目的各类别train数据比例)

    2. 分析bad case: 光照条件下效果差, 运动条件下效果差, 目标不全情况下效果差等. 根据具体原因, 做数据优化增强.

    5. 数据有噪声: 

        1. 用类似label smooth这样的loss,减轻对噪声的过拟合;

        2. symmetric cross entropy 对称交叉熵, 有对称性的函数可抗噪干扰

九、智力/code题:

    1. 25匹5赛道,top3 or top5: 7 or 8

    https://zhuanlan.zhihu.com/p/362775051

    2. 二维矩阵01连通域个数

    3. code.txt[1]   常考code和题集, 【方便给个start啊】

Links:  

[1]https://github.com/jiachen0212/hope_better_job.git

① 全网独家视频课程

BEV感知、毫米波雷达视觉融合、多传感器标定、多传感器融合、3D目标检测、目标跟踪、Occupancy、cuda与TensorRT模型部署、协同感知、语义分割、自动驾驶仿真、传感器部署、决策规划、轨迹预测等多个方向学习视频(扫码免费学习)

很全了!社招CV岗面试知识点笔记_第1张图片 视频官网:www.zdjszx.com

② 国内首个自动驾驶学习社区

近2000人的交流社区,涉及30+自动驾驶技术栈学习路线,想要了解更多自动驾驶感知(2D检测、分割、2D/3D车道线、BEV感知、3D目标检测、Occupancy、多传感器融合、多传感器标定、目标跟踪、光流估计)、自动驾驶定位建图(SLAM、高精地图、局部在线地图)、自动驾驶规划控制/轨迹预测等领域技术方案、AI模型部署落地实战、行业动态、岗位发布,欢迎扫描下方二维码,加入自动驾驶之心知识星球,这是一个真正有干货的地方,与领域大佬交流入门、学习、工作、跳槽上的各类难题,日常分享论文+代码+视频,期待交流!

很全了!社招CV岗面试知识点笔记_第2张图片

③【自动驾驶之心】技术交流群

自动驾驶之心是首个自动驾驶开发者社区,聚焦目标检测、语义分割、全景分割、实例分割、关键点检测、车道线、目标跟踪、3D目标检测、BEV感知、Occupancy、多传感器融合、大模型、SLAM、光流估计、深度估计、轨迹预测、高精地图、NeRF、规划控制、模型部署落地、自动驾驶仿真测试、产品经理、硬件配置、AI求职交流等方向。扫码添加汽车人助理微信邀请入群,备注:学校/公司+方向+昵称(快速入群方式)

很全了!社招CV岗面试知识点笔记_第3张图片

你可能感兴趣的:(笔记)