Python / ML / CV 助记笔记
Python、机器学习、CV 三块面试常问题目的助记整理。
~/posts/python-ml-cv-notes $ cat post.md
Python
什么是 Monkey Patching(猴子补丁)?
指在函数声明之后改写它的行为。常用于 mock 测试,生产环境应该尽量避免。
*args 和 **kwargs
* 收集额外的位置参数,** 收集命名参数:
def hello(a, b, *args, **kwargs):
...
a 和 b 之后的位置参数进 args,xxx=xxx 形式的进 kwargs。
Python 的原生多线程是怎么实现的,是个好主意吗?
Python 原生不支持真正的并行多线程。threading 包存在,但不是用来提升同步代码的运行速度——Global Interpreter Lock (GIL) 会确保多线程下任何时刻只有一个线程在跑 Python 字节码。
需要 IO 并发(比如多线程下载)时多线程仍然有用;要靠多线程加速 CPU 密集型计算,Python 不是好选择。
正确姿势:
- 用 C 实现热点,再从 Python 调用,绕开 GIL。
- 换引擎——比如 Spark、Hadoop 在外部开多进程跑 Python 代码,曲线救国实现并行。
Python 的垃圾回收
- 引用计数:每次引用关系变化时检查,计数为 0 立刻销毁。
- 周期性扫描循环引用:让相互持有的两个对象在没有外部引用时被回收。注意 Python 处理超过两个对象的循环引用时表现一般,尽量避免。
- 分代回收:每个对象创建时分到一个 generation,较新的对象优先回收,是一种启发式策略。
机器学习
Logistic Regression 和 Naive Bayes 的区别
朴素贝叶斯有一个非常强的前提:条件独立假设——所有特征之间相互独立。在这个前提下,写出一个逻辑公式、把特征输进去算后验概率、超过阈值就归为某类——这就是朴素贝叶斯分类。
贝叶斯公式 + 条件独立假设 = 朴素贝叶斯
Logistic Regression 实际上是用线性回归模型的预测结果去逼近后验概率的 log-odds(逻辑发生比),等价于把概率式写成多项式。
两者求出来的权重不同,根源就在朴素贝叶斯的条件独立假设。NB 不需要梯度下降,可以直接通过统计每个特征的发生比作为权重;LR 不假设独立,靠梯度下降找特征之间的耦合,从而得到对应权重。
优化目标也不同:
- LR 优化后验 likelihood
p(y|x)——判别模型。 - NB 优化联合 likelihood
p(x, y)——生成模型。
判别模型和生成模型
判别模型:用已知输入 x 预测未知 y,基于条件概率 P(y|x) 建模。不考虑 x 和 y 的联合分布。对分类、回归这类任务通常表现更好。大部分判别模型本身是监督学习模型,不易扩展到无监督场景。
生成模型:建模联合分布 P(x, y),可以用来生成观测数据,也可以通过贝叶斯定理推出条件概率。在复杂依赖关系的任务上比判别模型更灵活。
常见的判别模型:
- Logistic Regression
- Linear Regression
- Support Vector Machine
- Boosting:通过组合一组”弱学习者”(结果只比随机分类略好的分类器)形成一个”强学习者”,思路来自 Michael Kearns 的提问。
- Conditional Random Field:一种判别式概率模型,是随机场的一种,常用于序列数据的标注或分析(自然语言、生物序列)。
- 人工神经网络(Artificial Neural Network, ANN):模仿生物神经网络结构的数学模型,通过大量人工神经元的连接来近似函数。
- Random Forest:包含多棵决策树的分类器,输出由各棵树的众数决定。
LR 和 SVM 的区别
- 都能处理非线性问题;起点都是二分类。
- SVM 最大化分类间隔;LR 用最大似然估计。SVM 只输出类别,不直接给出分类概率。
- 损失函数不同。LR 可解释性更强;SVM 自带(带约束的)正则化。
CV
如何在程序里放大缩小图片?
用插值算法(Interpolation):
- 最近邻:最简单也最糊。
- 双线性:更平滑。
- Lanczos:更锐利。
二维 Lanczos 插值会在左右、上下各取一定范围内的相邻点做加权和——相当于从一个 8×8 的描述子里取加权和。
OpenCV 中默认的颜色通道顺序是 BGR 还是 RGB?
BGR。历史遗留,没什么深入解释的必要。
HOG(Histogram of Oriented Gradient)是什么
HOG 是用于物体检测的特征描述子,通过统计图像局部区域的梯度方向直方图构成特征。配合 SVM 分类器在行人检测里有过非常好的应用。
主要思想:图像中局部目标的外观和形状可以由梯度或边缘的方向密度分布很好地描述(本质上靠的就是边缘处梯度的统计信息)。
实现步骤:
- 把图像分成小的连通区域(cell)。
- 统计每个 cell 内各像素的梯度方向直方图。
- 把这些直方图组合起来构成特征描述符。
优点:
- 在局部小方格上操作,对几何变形和光照变化有较强不变性——这两类形变只会出现在更大的空间尺度上。
- 粗空域抽样 + 细方向抽样 + 强局部归一化的组合下,行人保持直立姿势时小幅肢体动作不会显著影响检测。
Canny 边缘检测的步骤
- 图像降噪:梯度算子放大边缘也放大噪声,需要先去噪(典型做法是高斯模糊)。
- 计算梯度,得到候选边缘:梯度大的地方可能是边缘,也可能不是,但所有边缘点都在这个集合里。
- 非极大值抑制:在每个像素的梯度方向上只保留局部最大的那一个,把”胖边缘”压成”瘦边缘”,剔除大部分非边缘点。
- 双阈值筛选:设低阈值
low和高阈值high。大于high的像素是强边缘,小于low的剔除,介于之间的是弱边缘——如果它附近有强边缘则保留,否则剔除。