计算机视觉
数据驱动方法
def train(imges, labels):
# Machine learning
return model
def predict(model, test_image):
# use model to predict labels
retrun test_labels
Nearest Neighboor
数据集例子 CIFAR10
十个种类,50000张训练图片,10000测试图片,每张图片32*32*3
定义图片的距离
L1 distance 曼哈顿距离
$$
d_1(I_1, I_2) = sum_p |I_1^p - I_2^p|
$$
每个对格子相减取绝对值之后求和
算法实现
class Nearest Neighbor:
def __init(self):
pass
def train(self, X, Y):
self.Xtr = X;
self.Ytr = Y;
def predict(self, X):
num_test = X.shape[0];
Ypred = np.zeros(num_test, dtype=self.ytr.dtype)
for i in xrange(num_test):
distances = np.sum(np.abs(self.Xtr - x[i,:]), axis=1)
min_index = np.argmin(distances)
Ypred[1] = self.ytr[min_index]
return Ypred;
Q: 训练时间和测试时间
Train O(1)
predict O(N)
但我们的实际目标是为了让测试时间尽可能短,因此该算法不是很合适的一个算法
分类结果空间划分图
情况并不是很好,因为对于这样的结果,中心位置的值很有可能是失真或是噪声所导致的结果,我们更希望是绿色
K-Nearest Neighboor Algorithm(KNN)
基于上述方法的问题,我们提出k临近算法
算法概述
对于每个测试点,取出其邻近的K个点,并且由这K个点的类别进行投票,经过某种投票方式(最简单的方式是多数为胜,事实上该方式也较为合理),得出该测试点的类别。
第二种测量距离的方法 欧式距离
$$ L2 d_2(I_1, I_2) = sqrt{ sum_p{(I_1^p - I_2p)2 } } $$
距离的选择
对于不同的距离选择,事实上是对你的样本空间的不同假设
L1 距离取决于你的坐标系,当你的坐标系发生变化时,L1距离变化,而L2不变
如果对于向量中某个值,如果其比较重要,则可以使用L1, 而若其没有什么太大区别,或是不知道其含义,则可以使用L2
事实上,对于距离的选择主要取决于特殊情况下特殊意义,若在某些情况下L1能更好描述该问题的特征向量在其空间中的意义,则可以使用L1
应用
假设你希望在其他地方使用KNN, 事实上只要你指定距离计算方式,例如在文本上,比较两句话的区别,则你可以将两句话进行文本距离的计算,然后使用KNN进行聚类,所以可以在测试中,首先使用这个算法进行尝试
可以尝试该网站进行k的不同选择尝试
超参数(hyperparameters):
如K与distance这两种算法无法从数据中直接学习到的内容,需要人为在算法运行前设定。
超参数的设定是更多取决于你对所解决问题的了解,对于特定问题进行设定,因此许多人会在某个问题上尝试很多参数以寻找到最好的。
最好的方法是都去试一试
参数设置好坏的判定
-
直接通过其在测试数据上的好坏进行判断 ==》 不可行
-
将数据划分为训练与测试两部分 ==》不可行,不能判断在新的数据集上会不会出现更坏的情况
-
一般的做法是将数据划分为训练,验证和测试三部分
===》选取大部分数据作为训练集,首先在选择参数训练,并且放入验证集中测试,
===》经过多次参数选择,选出在验证集上效果最好的一组,之后放入测试集中进行测试,得出的数据是最终评估结果,可以写入论文,到最后才可以使用测试集,应该严格控制测试集
-
交叉验证:留出测试集,将剩余数据划分为多份(例如5份)之后每次选取一份作为验证集,剩余作为训练集,(例如循环5次), 每次训练都需要把选取一份作为训练集,且进行若干次(例如上述例子中为5次)
在深度学习上基本不适用上述方法,因为过于消耗时间
测试集是否能很好的代表真实数据
对于测试集,我们进行抽取的时候,就应用了数据之间应该相互独立且服从一定分布,来自同一概率分布,以此为假设作为抽取数据能合理代表真实世界的依据
为了防止坏情况发生,在收集数据的时候应该采取一定的行动
例如使用同种手段获取大量数据后,再进行打乱
若你例如将早期数据作为测试集,晚些时候的数据集作为训练,则更有可能出现偏差
KNN在图像识别上的问题
- 太慢
- 无法分辨丢失信息或者变换后的图片
- 例如对图像进行遮挡一个部分,移动几个像素,加深整体颜色
- 这些都会使得L2失效,因此不合适
- 维度灾难
- 当使用图片越大时,为了覆盖整个空间,使得空间中每个位置都具有一定的样本,需要指数级增长的图片数量,
- 例如在一维空间我们需要4个点,则二位空间则需要$4^2$个点
- 但由于无法拥有和使用如此多的数据,因此不可行
Linear Classifiers
如果把卷积模型比作是玩乐高,线性模型就是最小的积木块
假设输入图像是 32 * 32 * 3(一共3027维) 的一张图片,输出是10个类别,则有公式
$$
f(x, W) = Wx + b
$$
其中 x是一个3072*1的输入向量,而W是一个10 * 3027的一个矩阵,则经过上述公式可以得到10个分类的输出值,并且b(bias)是一个大小为10的向量,用于表示每个类别的独立偏好
假设在这组数据中猫的图片更多,可能猫对应的b可能就会更大一些
进一步思考:模板观点
该模型相当于是给出每个像素对于每个分类的贡献值,并且相加,这是一种模板匹配的观点,即对于每一个可能结果(即W的每一行)生成一个模板,用于检测该图片是否是该模板所对应的类。
W的每一行可以重新排列成图像的样子并进行可视化,方便了解其中的情况
单模板局限
线性模型每次对于每种类别只赋予一个模板,因此对于识别真正的情况可能不太合适,如果输入的相同类别的东西发生了变换,该模板可能会失效,之后的模型将会产生多个模板以防止该情况发生。
另一种解释
线性模型相当于是在特征向量对应的高维空间上作了多个个分界线,通过多个分界线把整个界面划分成多个部分。
失效情况
对于在平面上无法通过直线进行划分的
例如在一个二维直角坐标系内,类型1处于第一第三象限内(均有,等同),类型2处于第二第四象限内(均有,等同),因此这两个类型无法用直线划分。
且该模型无法处理多模态,多类别情况,例如同一类别出现在多个背景之下,或是有较为复杂的动作
选择参数 loss function and optimization
对于制定的W和b,我们可以得到该图片对应每种类别的得分,但是怎么保证这个得分在对应类别下最大?即如何让W选取最优?
多类别SVM 损失函数
损失函数是用于检验当前分类器如何。
给定一个数据集
$${{(x_i,y_i)}}_{i=1}^N$$
其中$x_i$是输入数据(图片),$y_i$是标签(整数表示,如果十类可以1到10也可以0到9)
对于一个数据集的损失函数就是对于每个类别所有损失函数的和,设$L_i$是某个类别的损失函数,则有方程
$$
L = frac{1}{N} sum_i{L_i(f(x_i, W), y_i)}
$$
考虑单个类别的$L_i$
计算方法如下:
仍然有假设$(x_i, y_i)$的数据,且$y_i$是一个整数标签
假设由该模型得出的结果为 $s = f(x_i, W)$ 其中s是一个向量,$s_j$是s在对应类别上的分数
有如下公式
$$
L_i = sum_{j
eq y_i}
egin{cases}
0 & s_{y_i} ge s_j+1
s_j-s_{y_i}+1 & otherwise
end{cases}
=sum_{j
eq y_i} max(0, s_j-s_{y_i} + 1)
$$
其计算过程即为
- 对于每一个不等于正确类别的值($j eq y_i$) ,
- 若对正确类别的分类的得分值大于在该类别下的得分值,或是该类别下的得分值加上某一阈值,则$L_i$为0
- 否则$L_i$为该类别分值减去正确类别分值加上该阈值
补充:在这里 这个+1只是相当于对整个W进行缩放,因此其本身对这个模型没有太大的作用(有详细推导)。
稍微更深入的理解:
-
该损失函数关注于对应正确分数应该大于其他分数1的值(1为本次选择的阈值)
-
该函数的最大值为正无穷,而最小值为0
-
在初始训练时,初始化W时,我们可以使用随机的小的均匀分布,使得W的值在开始时趋向于接近,若你得所有S都近乎为0,或者差不多相等,则最后$L_i$的值会接近类别数C-1,因为我们时遍历每个类别,并且每个类别均为$s_j-s_{y_i}+1$ ,存在1的阈值
-
对于3而言,若在开始训练时,你的损失函数结果不是C-1,那么你的程序可能有bug需要修补,这是一个有用的结论。
-
对于最后的$L$ 不管是取求和或是求均值结果相同,仅仅是对于损失函数乘上一个一定倍数。
-
若在此处公式的max之后的结果取平方,则结果与现在不同,但这是一个会使用的技巧
-
对于6,平方后对于大的错误会增幅,对于小的错误则会减小,因此损失函数的选取是你希望告诉你的分类器你所关心的错误是什么,针对不同应用需要选取不一样的想法。
-
使得最终L为0的W的值不唯一,事实上若W为0,2W时候L也为0
代码片段
def L_i_vectorized(x, y, W):
scores = W.dot(x);
margins = np.maximum(0, scores-scores[y]+1)
margins[y] = 0 # 此处使用了一个技巧,使用向量化计算之后,再将需要置0的值置零,使得代码更简洁
loss_i = np.sum(margins)
return loss_i
hinge loss 合页函数
对于两个值取max的函数,由于其形状,因此称之为合页函数。如下
Regularization 正则化
奥卡姆剃刀定律(Occam's Razor, Ockham's Razor)
“如无必要,勿增实体”,即“简单有效原理”。
若有多个假设可以满足你的需求,选取最简单的是最好的
- 数据在训练过程中总是试图去完全拟合训练数据
- 但是事实上我们关心的并不是模型在训练数据上的情况,而是测试数据上的情况
- 为了更好地解决这个问题,我们需要让数据拟合之后不会那么的完美
- 因此我们使用正则化使得整个数据更趋向于简单的结果
- 此处的简单是对特定任务和结果所示
- 这样使得模型最终在测试数据上表现更好
- 更简单的模型也能支持未来更好解释其行为
根据上述需求,我们得出W的一项补充项如下所示:
$$
L = frac{1}{N} sum_i{L_i(f(x_i, W), y_i)} + lambda R(W)
$$
这一项的作用可以使得原本更多曲折的模型降低阶数,使其更加平滑。
正则化的种类
正则化有许多种,其中较为常用的有L2, L1, 弹性网络(Elastic net)
$$
L2 Regularization R(W) = sum_k{sum_l{W_{l,k}^2}}
L1 Regularization R(W) = sum_k{sum_l{|W_{l,k}|}}
Elastic net (L_1 + L_2) R(W) = sum_k{sum_l{eta W_{l,k}^2 + |W_{l,k}|}}
Max norm regularization
Dropout
Fancier: Batch normalization, stochastic depth
$$
举例:向量正则化效果
例如我们有一个5维向量 $x = [1 1 1 1 0] ^T$, 以及两个$W$(单个分类): $W_1 = [1 0 0 0 0] $, $W_2 = [0.25 0.25 0.25 0.25 0.25] $
在线性模型下,实质上是$x$ 与 $W$ 的点乘,因此两者结果相同,但是在L2正则下,$W_2$相对较好,因此在这种条件下,L2以一种较为粗糙的方式反应好坏。
在本例中,L2对于模型复杂度的考量,更多的是强调在特定w下每个x对应生成的值的影响,
即L2更考虑整体W中每一个值的影响,而非单个的好坏
而在本例中L1则会使得模型选择$W1$ , 因为L1正则化评估模型复杂度的时候,在本例中则是考虑0的数量更多,
L1更喜欢稀疏解,更倾向于让趋近于0的项更多,允许少量值偏差更大
因此选择正则化是取决于问题,以及其复杂性的判断
补充:贝叶斯学派 - Bayesian - Maximum A Posteriori (MAP,最大后验估计)
贝叶斯学派下,L2正则化可以得到非常好的解释
L2 正则化对应在W中使用高斯先验的MAP推导
再次强调
正则化带来的惩罚项的目的是为了减轻模型的复杂度,而不是试图去拟合数据
Softmax Classifier 多项逻辑回归
(Multinomial Logistic Regression)
对于SVM损失函数,我们仅仅给出分数,并认为较高分数更优,却未给予这些分数以实际含义