• SIFT+SVM图像分类
千次阅读
2021-01-13 23:02:17
import os
import numpy as np
import cv2
import glob
import sklearn.svm as svm
import joblib

def calcSiftFeature(img):
#设置图像sift特征关键点最大为200
sift = cv2.xfeatures2d.SURF_create()
#计算图片的特征点和特征点描述
keypoints, features = sift.detectAndCompute(img, None)
return features

#计算词袋
def learnVocabulary(features):
wordCnt = 50
#criteria表示迭代停止的模式   eps---精度0.1，max_iter---满足超过最大迭代次数20
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.1)
#得到k-means聚类的初始中心点
flags = cv2.KMEANS_RANDOM_CENTERS
# 标签，中心 = kmeans(输入数据（特征)、聚类的个数K,预设标签，聚类停止条件、重复聚类次数、初始聚类中心点
compactness, labels, centers = cv2.kmeans(features, wordCnt, None,criteria, 20, flags)
return centers

#计算特征向量
def calcFeatVec(features, centers):
featVec = np.zeros((1, 50))
for i in range(0, features.shape[0]):
#第i张图片的特征点
fi = features[i]
diffMat = np.tile(fi, (50, 1)) - centers
#axis=1按行求和，即求特征到每个中心点的距离
sqSum = (diffMat**2).sum(axis=1)
dist = sqSum**0.5
#升序排序
sortedIndices = dist.argsort()
#取出最小的距离，即找到最近的中心点
idx = sortedIndices[0]
#该中心点对应+1
featVec[0][idx] += 1
return featVec

#建立词袋
def build_center(path):
cate=[path+'/'+x for x in os.listdir(path) if os.path.isdir(path+'/'+x)]
features = np.float32([]).reshape(0, 64)#存放训练集图片的特征
for idx,folder in enumerate(cate):
for im in glob.glob(folder+'/*.jpg'):
# print(im)
#获取图片sift特征点
img_f = calcSiftFeature(img)
#特征点加入训练数据
features = np.append(features, img_f, axis=0)
#训练集的词袋
centers = learnVocabulary(features)
#将词袋保存
filename = "./svm_centers.npy"
np.save(filename, centers)
print('词袋:',centers.shape)

#计算训练集图片特征向量
def cal_vec(path):
data_vec = np.float32([]).reshape(0, 50)#存放训练集图片的特征
labels = np.float32([])
cate=[path+'/'+x for x in os.listdir(path) if os.path.isdir(path+'/'+x)]
for idx,folder in enumerate(cate):
for im in glob.glob(folder+'/*.jpg'):
# print(im)
#获取图片sift特征点
img_f = calcSiftFeature(img)
img_vec = calcFeatVec(img_f, centers)
data_vec = np.append(data_vec,img_vec,axis=0)
labels = np.append(labels,idx)
print('data_vec:',data_vec.shape)
print('image features vector done!')
return data_vec,labels

#训练SVM分类器
def SVM_Train(data_vec,labels):
#设置SVM模型参数
clf = svm.SVC(decision_function_shape='ovo')
#利用x_train,y_train训练SVM分类器，获得参数
clf.fit(data_vec,labels)
joblib.dump(clf, "./svm_model.m")

#SVM分类器测试测试集正确率
def SVM_Test(path):
#读取SVM模型
#读取词袋
#计算每张图片的特征向量
data_vec,labels = cal_vec(path)
res = clf.predict(data_vec)
num_test = data_vec.shape[0]
print(num_test)
acc = 0
for i in range(num_test):
if labels[i] == res[i]:
acc = acc+1
print('acc: ' + str(acc) + '/' + str(num_test) + '=' + str(acc/num_test))
return acc/num_test,res

if __name__ == "__main__":
# train_path = './big/train_big'
# test_path = './big/val_big'
train_path = './TrainSet'
test_path = './TestSet'
#建立词袋
build_center(train_path)
#构建训练集特征向量
data_vec,labels = cal_vec(train_path)
#将特征向量和标签输入到SVM分类器中
SVM_Train(data_vec,labels)
# print(x_train.shape)
# print(y_train)
#计算测试集的正确率
acc,res = SVM_Test(test_path)
# print(acc)
print(res)


其中

    train_path = './TrainSet'
test_path = './TestSet'


为训练和测试集所在文件夹，格式都为一个类别一个文件夹

更多相关内容
• 下载后，安装好版本匹配的python3.6,numpy,scipy,matplot,sklearn,skimage等包，后直接可以运行，无需修改代码。运行后输入y，就可以实习自带的图像分类（小鸡，小鸭，蛇，猫等分类）。
• 利用SVM进行图像分类，可以有效的进行图像的分类，效果还可以
• ## opencv SVM图像分类工程文件

千次下载 热门讨论 2015-07-30 08:37:40
这是opencv svm图像分类的整个工程代码，在VS2010下打开即可。整个工程文件以及我的所有训练的图片存放在这里，需要的可以下载，自己在找训练图片写代码花了很多时间，下载完后自行解压，训练图片和测试图片可以从这...
• 使用CNN进行图像分类，并且附录了SIFT+BOG+SVM多分类器的机器学习分类模型
• 这是一个博主自己做的数据集，来源于网上，可用于学习博主的一篇svm算法进行图像分类，无侵权行为
• SVM_svm图像分类_svm图像分类_SVM_svm图像分类_图像分类.zip
• SVM_svm图像分类_svm图像分类_SVM_svm图像分类_图像分类_源码.zip
• SVM图像分类论文：基于SVM的离线图像目标分类算法、基于SVM的食物图像分类算法的研究
• SVM分类，可以实现对图像分类，主要用于理解支持向量机
• 简单的svm高光谱图像分类用于分类高光谱图像
• 基于HOG+SVM图像分类算法，训练集和测试集根据自己的需要自行创立
• ## svm图像分类python代码实现续

千次阅读 热门讨论 2021-05-31 17:41:32
svm图像分类python代码实现续 这篇博客诗接上前面一篇svm图像分类得一篇续集 svm分类代码如下 #os.system("pause") #Svm 训练： import sys import os import cv2 import numpy as np from sklearn.svm import ...

## svm图像分类python代码实现续

这篇博客诗接上前面一篇svm图像分类得一篇续集
svm分类代码如下


#os.system("pause")

#Svm 训练：
import sys
import os
import cv2
import numpy as np
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
import time
import pickle
#help(SVC)

SHAPE = (30, 30)
def getImageData(directory):
s = 1
feature_list = list()
label_list   = list()
num_classes = 0
for root, dirs, files in os.walk(directory):
for d in dirs:
num_classes += 1
images = os.listdir(root+d)
for image in images:
s += 1
label_list.append(d)
feature_list.append(extractFeaturesFromImage(root + d + "/" + image))

return np.asarray(feature_list), np.asarray(label_list)

def extractFeaturesFromImage(image_file):
img = cv2.resize(img, SHAPE, interpolation = cv2.INTER_CUBIC)
img = img.flatten()
img = img / np.mean(img)
return img

if __name__ == "__main__":

directory ="C:/learn_data/2021_car/image/"

feature_array, label_array = getImageData(directory)

X_train, X_test, y_train, y_test = train_test_split(feature_array, label_array, test_size = 0.2, random_state = 42)

if os.path.isfile("svm_model.pkl"):
else:
svm = SVC(kernel='rbf',gamma=0.001)
svm.fit(X_train, y_train)
pickle.dump(svm, open("C:/learn_data/2021_car/svm_model.pkl", "wb"))

print("Testing...\n")

right = 0
total = 0
for x, y in zip(X_test, y_test):
x = x.reshape(1, -1)
prediction = svm.predict(x)[0]
if y == prediction:
right += 1
total += 1

accuracy = float(right) / float(total)

print (str(accuracy) + "% accuracy")
print ("Manual Testing\n")
print("success")

os.system("pause")



## 标题

那么数据集是什么样的呢
这里我要说一下了，这一次做的三分类，数据集的文件结构如下：

也就是说，这里的image就是我们的训练集，里面分为三个子文件夹，这三个子文件夹里只能有图片，其他的任何文件都不能有

好的，那么对于文件没是没有要求的，那么如果你现在想要进行二分类，三分类，也就改变image下的子文件数量，这里应该能听懂

如果调用模型，在上一篇博客有着介绍可以参考。
博客链接在这里
这次的数据集已上传到我的资源，是三类车牌号数据。

展开全文
• 西电数据挖掘作业_SVM图像分类实验报告
• 为了提高图像分类性能，提出了一种结合了CNN和并行SVM图像分类新方法。 该方法利用基于CNN的深度神经网络提取图像特征。 提取的特征将输入到基于MapReduce的并行SVM中以进行图像分类。 可以显着提高分类的准确性...
• SVM图像分类论文1：超像素词包模型与SVM分类的图像标注、多特征筛选与支持向量机相融合的图像分类模型等
• opencv使用SVM实现图像分类识别，代码已测试通过，能帮助我们更好理解SVM和opencv编程的使用。
• SVM图像分类论文：基于LatentSVM的人体目标检测与跟踪方法研究、基于LBP和SVM的工件图像特征识别研究、基于MATLAB的遥感图像SVM分类系统实现等
• 对高分辨率遥感影像基于光谱的svm分类aaaaaaaaaaaaaaaaaaa
• opencv+svm实现图像分类代码+训练图片，新建opencv工程，导入两个文件就可以了。
• SVM图像分类论文：基于SVM_KNN的特征自适应加权自然图像分类研究、基于SVM的多时相极化SAR影像土地覆盖分类方法研究等
• 本篇文章主要是先从理论的角度对图像进行讲解，主要代码的讲解请关注下一篇博文：opencv中的svm图像分类（二）http://blog.csdn.net/always2015/article/details/47107129 一、图像分类概述 本模块是用在图像内容...

本篇文章主要是先从理论的角度对图像进行讲解，主要代码的讲解请关注下一篇博文：opencv中的svm图像分类（二）http://blog.csdn.net/always2015/article/details/47107129

## 一、图像分类概述

本模块是用在图像内容识别的部分，图像分类是利用计算机对图像进行定量分析，把图像中的每个像元或区域划归为若干个类别中的一种，以代替人工视觉判读的技术。从目视角度来说，对图像进行提高对比度、增加视觉维数、进行空间滤波或变换等处理的目的就是使人们能够凭借知识和经验，根据图像亮度、色调、位置、纹理和结构等特征，准确地对图像景物类型或目标做出正确的判读和解释。
特征提取是计算机视觉和图像处理中的一个概念。它指的是使用计算机提取图像信息，决定每个图像的点是否属于一个图像特征。特征提取的结果是把图像上的点分为不同的子集，这些子集往往属于孤立的点、连续的曲线或者连续的区域。根据各自在图像信息中所反映的不同特征，把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析，把图像或图像中的每个像元或区域划归为若干个类别中的某一种，以代替人的视觉判读。

## 二、本模块完成的主要功能

该模块作用是先对一些已经归类好的图片作为输入,再对一些未知类别的图片进行预测分类。本模块在该项目中可以分出二维码、logo、以及文字 。例如一给定图像，检测并读取其中所有的条码、logo、文字，即使他们处于任意的位置及角度，如果图像中可能有任意数量及格式的条码、logo和文字，输出所有的条码、logo和文字（1个或多个）。

## 三、svm图像分类的基本流程

1. 数据获取
比如摄像机或视频头的输出，通过采样获得数据，也可以是一般的统计数据集，其中的数据以向量或矩阵形式表示，或者是已经准备好的待检测的图片
2. 训练图片特征提取和选择
特征提取是指从对象本身获取各种对于分类有用的度量或属性。特征选择是指如何从描述对象的多种特征中找出那些对于分类最有效的特征。特征提取我们用到了surf算法。Surf具有比sift快的检测速度。
对某一类模式的识别，其关键在于对模式特征的描述以及如何去提取这些特征。征描述直接影响到特征提取以及特征向量库的建立，并影响到最后分类识图像的特征提取和分类别精度的高低 从理论上讲，个体的特征是唯一的，这是因为不存在完全相同的两个个体。但是由于客观条件限制的存在，往往使得选取的特征并不是描述个体的特征全集，而只是特征的一个子集。因此，确定物体的本质特征是识别任务成功的关键。为了提高特征提取时计算的鲁棒性，往往又要求用尽可能少的特征来描述物体，这使得在实际应用中特征描述的不完全性是不可避免的。
3. 将这些feature聚成n类。这n类中的每一类就相当于是图片的“单词”，所有的n个类别构成“词汇表”。我的实现中n取1000，如果训练集很大，应增大取值。
4. 对训练集中的图片构造bag of words，就是将所有训练图片中的feature归到不同的类中，然后统计每一类的feature的频率。这相当于统计一个文本中每一个单词出现的频率。
5. 分类器的设计（也就是训练分类器）
利用样本数据来确定分类器的过程称为分类器设计。训练一个多类分类器，将每张图片的bag of words作为feature vector，将该张图片的类别作为label。支持向量机（Support Vector Machines,SVM）应用发热典型流程是首先提取图形的局部特征所形成的特征单词的直方图来作为特征，最后被通过SVM进行训练得到模型。
在图像分类中用到了一种模型叫做BOW (bag of words) 模型。Bag of words模型最初被用在文本分类中，将文档表示成特征矢量。它的基本思想是假定对于一个文本，忽略其词序和语法、句法，仅仅将其看做是一些词汇的集合，而文本中的每个词汇都是独立的。简单说就是讲每篇文档都看成一个袋子（因为里面装的都是词汇，所以称为词袋，Bag of words即因此而来），然后看这个袋子里装的都是些什么词汇，将其分类。如果文档中猪、马、牛、羊、山谷、土地、拖拉机这样的词汇多些，而银行、大厦、汽车、公园这样的词汇少些，我们就倾向于判断它是一篇描绘乡村的文档，而不是描述城镇的。
最后通过训练好的模型，再次读取未经分类的图片，就可以对其分类。
流程图如图所示：

## 四、所用到的技术方法

1. 特征提取算法surf
有关surf算法的介绍网上有很多，在这里我就不一一介绍，大家也可以参考下面的文章:http://blog.csdn.net/yujiflying/article/details/8203511

2. 聚类算法：Kmeans算法
k-means 算法接受参数 k ；然后将事先输入的n个数据对象划分为 k个聚类以便使得所获得的聚类满足：同一聚类中的对象相似度较高；而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”（引力中心）来进行计算的。
K-means算法是最为经典的基于划分的聚类方法，是十大经典数据挖掘算法之一。K-means算法的基本思想是：以空间中k个点为中心进行聚类，对最靠近他们的对象归类。通过迭代的方法，逐次更新各聚类中心的值，直至得到最好的聚类结果。
假设要把样本集分为c个类别，算法描述如下：
（1）适当选择c个类的初始中心；
（2）在第k次迭代中，对任意一个样本，求其到c各中心的距离，将该样本归到距离最短的中心所在的类；
（3）利用均值等方法更新该类的中心值；
（4）对于所有的c个聚类中心，如果利用（2）（3）的迭代法更新后，值保持不变，则迭代结束，否则继续迭代。
该算法的最大优势在于简洁和快速。算法的关键在于初始中心的选择和距离公式。
该算法流程首先从n个数据对象任意选择 k 个对象作为初始聚类中心；而对于所剩下其它对象，则根据它们与这些聚类中心的相似度（距离），分别将它们分配给与其最相似的（聚类中心所代表的）聚类；然后再计算每个所获新聚类的聚类中心（该聚类中所有对象的均值）；不断重复这一过程直到标准测度函数开始收敛为止。一般都采用均方差作为标准测度函数. k个聚类具有以下特点：各聚类本身尽可能的紧凑，而各聚类之间尽可能的分开。

3. Bag of words（BOW）模型
最初的Bag of words，也叫做“词袋”，在信息检索中，Bag of words model假定对于一个文本，忽略其词序和语法，句法，将其仅仅看做是一个词集合，或者说是词的一个组合，文本中每个词的出现都是独立的，不依赖于其他词 是否出现，或者说当这篇文章的作者在任意一个位置选择一个词汇都不受前面句子的影响而独立选择的。
现在Computer Vision中的Bag of words来表示图像的特征描述也是很流行的。大体思想是这样的，假设有5类图像，每一类中有10幅图像，这样首先对每一幅图像划分成patch（可以是刚性分割也可以是像Surf基于关键点检测的），这样，每一个图像就由很多个patch表示，每一个patch用一个特征向量来表示，咱就假设用SURF表示的，一幅图像可能会有成百上千个patch，每一个patch特征向量的维数128。
接下来就要进行构建Bag of words模型了，假设Dictionary词典的Size为1000，即有1000个词。那么咱们可以用K-means算法对所有的patch进行聚类，k=1000，我们知道，等k-means收敛时，我们也得到了每一个cluster最后的质心，那么这1000个质心（维数128）就是词典里的1000个词了，词典构建完毕。
对于bag of words 和K-means算法这一篇文章也挺容易理解的http://www.cnblogs.com/v-July-v/archive/2011/06/20/2091170.html

4. svm分类器
支持向量机 (SVM) 是一个类分类器，正式的定义是一个能够将不同类样本在样本空间分隔的超平面。 换句话说，给定一些标记(label)好的训练样本 (监督式学习), SVM算法输出一个最优化的分隔超平面（分类面）。具体可以参考文章：http://blog.csdn.net/sunanger_wang/article/details/7887218

## 五、算法的分析

SURT采用henssian矩阵获取图像局部最值还是十分稳定的，但是在求主方向阶段太过于依赖局部区域像素的梯度方向，有可能使得找到的主方向不准确，后面的特征向量提取以及匹配都严重依赖于主方向，即使不大偏差角度也可以造成后面特征匹配的放大误差，从而匹配不成功；另外图像金字塔的层取得不足够紧密也会使得尺度有误差，后面的特征向量提取同样依赖相应的尺度，发明者在这个问题上的折中解决方法是取适量的层然后进行插值。
Bag of words方法没有考虑特征点的相对位置，而每类物体大都有自己特定的结构，这方面的信息没有利用起来。用上面一贯的类比，就好像搜索引擎只使用了单词频率，而没有考虑句子一样，没有结构的分析。
SVM有两个不足：
(1) SVM算法对大规模训练样本难以实施
由于SVM是借助二次规划来求解支持向量，而求解二次规划将涉及m阶矩阵的计算（m为样本的个数），当m数目很大时该矩阵的存储和计算将耗费大量的机器内存和运算时间。针对以上问题的主要改进有有J.Platt的SMO算法、T.Joachims的SVM、C.J.C.Burges等的PCGC、张学工的CSVM以及O.L.Mangasarian等的SOR算法
(2) 用SVM解决多分类问题存在困难
经典的支持向量机算法只给出了二类分类的算法，而在数据挖掘的实际应用中，一般要解决多类的分类问题。可以通过多个二类支持向量机的组合来解决。主要有一对多组合模式、一对一组合模式和SVM决策树；再就是通过构造多个分类器的组合来解决。主要原理是克服SVM固有的缺点，结合其他算法的优势，解决多类问题的分类精度。如：与粗集理论结合，形成一种优势互补的多类问题的组合分类器。

图像分类的理论就讲解到这里，对于这个图像分类的代码的讲解请参考下一篇文章。

展开全文
• 斯坦福CS231n assignment1：SVM图像分类原理及实现SVM模型原理SVM的一种直观解释损失函数损失函数加入正则化项梯度下降和梯度检验图像预处理小批量数据梯度下降（Mini-batch gradient descent）代码实现 本文Github...

### 斯坦福CS231n assignment1：SVM图像分类原理及实现

本文Github代码

斯坦福CS231n课程讲解了实现图像分类的方法，从传统的KNN，SVM，到CNN，LSTM模型，讲解的非常专业精准。同时该课程提供了相应的习题来检验和巩固讲授的知识，如果能按部就班的完成，对神经网络将会有深刻的体会和理解。本文将结合代码实现讲解其中的SVM方法实现图像分类的原理和方法，以及需要注意的知识细节。

# SVM模型原理

SVM通过平面将空间中的实例划分到不同的类别，从而实现分类。这里的空间包括二维空间，三维空间，一直到高维空间，具体的维数等于实例的特征数量，如果我们待分类的图片是32*32*3（长宽分别是32个像素，RGB3个颜色通道）维的，那么图片所处的空间就是3072维的空间。在这个高维空间，我们通过由权重向量W和偏置项b确定的一个（实际上是一组）超平面来将图片进行分类。为了可视化，我们将多维空间压缩到二维空间，那么就是下面的图像：

这里每一个平面都将整个高维空间划分成两部分，平面的一侧是某一类图片，另一侧是这个类别之外的其他图片。比如红色的平面一侧是汽车这个类别，另一侧是非汽车类别。每一个类别都对应一个平面，这些平面互相之间不存在关联，利用SVM模型进行分类的目的就是确定这样一组平面，使得同一类尽可能划分在该类对应的平面的一侧，其他类尽可能在另一侧，而且两种类别离平面的距离越大越好（平面尽可能把两类分的更开），这是SVM模型的思路。

所有这些类别对应的平面通过下面的矩阵唯一确定：

其中改变W可以使平面旋转，而改变b使平面平移。如果b为0，此时W*0=0,那么平面会经过原点。

# SVM的一种直观解释

SVM模型用于图像分类可以看做给每一种图像的类别生成一个图像模板，然后拿待分类的图像和这个图像模板做内积，计算他们的相似度，相似度最高的类别就是分类类别。根据这个思想，生成的权重向量可视化如下：

可以看出，这些图像模板比较能够代表某种类别的共性，比如car类别是一辆红色的车的形象，而horse类型是左右两匹马的形象，这些是集合了所有训练样本得出的模板。从这个角度，SVM可以看做KNN模型的一种简化，KNN模型对一张图片分类时需要和所有训练样本做比较，而SVM只需要和抽象出来的每个类别下的一个图像模板做比较即可，显然更高效。

# 损失函数

SVM模型有多种不同的实现，区别主要体现在损失函数的定义上，可以根据实现分为：

1. 经典SVM
2. Structured SVM

其中经典SVM模型核心思路是找一个超平面将不同类别分开，同时使得离超平面最近的点的距离最大，这样能保证即使是最难区分的点，也有较大的确信度将它们分开，可以通过数学方法证明这样的超平面是唯一存在的（参考《统计学习方法》）。

而Structured SVM可以看做是对经SVM模型的泛化，则是通过事先构造损失函数来求解一个统计上的最优解，该方式避免了经典SVM简单粗暴的惩罚方式(比如分错惩罚1，分对惩罚0)，对分类错误程度不同的样本进行程度不同的惩罚，对实际训练数据中噪音数据具有更大的容错性，分类效果也更好。

Structured SVM模型中我们使用折页损失函数（hinge loss function）来计算损失值。折页损失函数可以有不同的表示，我们使用如下的表示：

某个样本经过f映射后会得到N个分值，对应为N个类别的得分。这N个类别中只有一个类别是这个样本的实际类别，用yi表示。类别yi的分值用Syi表示，其他不正确的类别得分用Sj表示，Δ是一个距离阈值。从这个折页损失函数的定义可以看出，这个样本在N个类别上的得分，有些会产生损失，有些不会：

1. 得分比正确类别yi高的类别肯定会产生损失，对于这些类别Sj>Syi，所以Sj-Syi+Δ>0，这说明正确分类的分值应该是最高的。
2. 得分比正确类别yi低的那些类别也有可能会产生损失，如果Sj<Syi，但是他们的距离太近，小于一个Δ值，也就是Syi-Sj<Δ，此时Sj-Syi+Δ>0，也会贡献损失。这说明我们不仅希望错误类别得分比正确类别低，而且要至少低一个Δ值

# 损失函数加入正则化项

损失函数数值的大小跟权重参数W成正比，对于同一个样本，成倍的扩大权重向量W会导致损失值成倍增加，这是损失值的变化没有意义的，为了约束这种变化，我们在损失函数中添加一个正则化项，L2正则化项定义如下：

这样，当权重扩大的时候会导致损失扩大，然后通过反向传递作用回权重矩阵W，从而对过大的权重加以修正，避免了权重向量的单向增大。

在数据损失(data loss)的基础上，添加了L2正则化损失(regularization loss)项的损失函数如下：

举个例子，假设输入向量x=[1, 1, 1, 1], 权重向量W1=[1, 0, 0, 0]，权重向量 W2=[0.25, 0.25, 0.25, 0.25]，W1*x = 1，W2*x=1，可以看到两个内积是一样的。但是W1的L2惩罚是1，而W2的L2惩罚是0.25，所以会更倾向于选择W2。直观上解释就是L2惩罚希望各个权重分量是比较均衡的，而不是某些分量权重一支独大，因为这样更能利用起样本中各个特征，而避免过度依赖某几个特征。

展开损失函数：

这里Δ和λ是两个超参数，它们的值是如何确定的？
实际上Δ控制的是损失函数中数据损失部分，λ控制正则化损失部分，这两个变量对损失的贡献是正相关的，实际上它们两个共同控制着损失函数中数据损失和正则化损失的权衡，所以同时调整两个值是没意义的。实际使用中，我们一般设置Δ=1为固定值，而通过交叉验证的方式调整λ值。也就是选择不同的λ，通过训练数据进行模型训练，在验证集上验证，然后调整λ，看看结果是不是更优，最终选择一个最优的λ，确定最优的模型。

# 梯度下降和梯度检验

定义好损失函数后，我们就可以通过梯度下降的方法利用训练集来更新权重参数，也就是模型训练的过程。

SVM模型中有两个参数，权重矩阵W和偏移量b，我们可以将这两个变量合并起来训练，将b作为一列添加在W后面，同时在输入向量X里添加一行，值为1，这样就可以值训练一个合并后的矩阵：

梯度下降的核心就是计算损失函数对各个权重分量的梯度，然后根据梯度更新各个权重。

对SVM损失函数进行梯度计算，根据损失函数定义，一个样本梯度的计算分为正确分类权重对应行和不正确分类权重对应的行两种情况，数据损失项的梯度为下面两个公式：

正则化损失项的梯度很简单，2Wij，可以在正则化损失前面添加一个参数0.5，这样可以将正则化损失项的梯度变为Wij，在代码中会讲到这一点。

这样我们就得到了梯度的解析解，在利用梯度进行权重更新之前，我们还需要验证一下这个梯度解析解是不是正确，方法就是利用梯度的定义求解权重向量分量的梯度的数值解，比较数值解和解析解，如果两者的差距非常小，说明解析解是正确的，否则说明有误，需要查找错误。

梯度数值解的计算很简单，根据下面梯度的公式，在给定的样本和权重矩阵下，计算输出，然后让权重矩阵的变量发生微小的变化，再计算输出，两次输出的差值除以变化量就是权重矩阵的梯度：

检验没问题后，就可以进行训练了。

# 图像预处理

通常我们会将所有图片，包括训练数据和待分类数据，减去图片每个位置像素的均值，使得数据中心化，这样可以提高模型的效果。同时，也可以对中心化后的数据归一化处理，使其分布在[-1, 1]区间，进一步优化模型效果。

相比于每次拿一个样例数据进行梯度更新，每次使用一个小批量数据进行梯度更新能够更好的避免单个样本数据的扰动，可以显著提高模型训练的效率，损失的变化更加平滑，使得模型更快的收敛。具体操作方法是一次计算一个批量的数据的结果，如256个样本，计算每个结果下权重矩阵每个变量的梯度。对于每个权重分量，累加256个梯度值，求均值作为该分量的梯度，更新该分量。

# 代码实现

完整的代码在github，包括训练数据，测试数据的获取，图像预处理等，这里只给出计算损失和梯度的关键代码：

def svm_loss_vectorized(W, X, Y, reg):
"""
:param X: 200 X 3073
:param Y: 200
:param W: 3073 X 10
:return: reg: 正则化损失系数（无法通过拍脑袋设定，需要多试几个值，交叉验证，然后找个最优的）
"""
delta = 1.0
num_train = X.shape[0]

patch_X = X  # 200 X 3073
patch_Y = Y  # 200

patch_result = patch_X.dot(W)  # 200 X 3073 3073 X 10 -> 200 X 10

sample_label_value = patch_result[[xrange(patch_result.shape[0])], patch_Y]  # 1 X 200 切片操作，将得分array中标记位置的得分取出来作为新的array
loss_array = np.maximum(0, patch_result - sample_label_value.T + delta)  # 200 X 10 计算误差
loss_array[[xrange(patch_result.shape[0])], patch_Y] = 0  # 200 X 10 将label值所在的位置误差置零

loss = np.sum(loss_array)

loss /= num_train  # get mean

# regularization: 这里给损失函数中正则损失项添加了一个0.5参数，是为了后面在计算损失函数中正则化损失项的梯度时和梯度参数2进行抵消
loss += 0.5 * reg * np.sum(W * W)

# 将loss_array大于0的项（有误差的项）置为1，没误差的项为0
loss_array[loss_array > 0] = 1  # 200 X 10

# 没误差的项中有一项是标记项，计算标记项的权重分量对误差也有共享，也需要更新对应的权重分量
# loss_array中这个参数就是当前样本结果错误分类的数量
loss_array[[xrange(patch_result.shape[0])], patch_Y] = -np.sum(loss_array, 1)

# patch_X:200X3073  loss_array:200 X 10   -> 10*3072
dW = np.dot(np.transpose(patch_X), loss_array)  # 3073 X 10
dW /= num_train  # average out weights
dW += reg * W  # regularize the weights

return loss, dW


该模型的准确率在38%左右，所以SVM模型分类效果还是比较差的，通过更复杂的神经网络，或者CNN等模型，可以实现95%以上的准确率。不过SVM是神经网络的基础，理解了SVM的原理，再学习神经网络就比较容易触类旁通。

本文Github代码

展开全文
• 可直接编译成功
• ## sift+svm图像分类

千次阅读 2018-04-11 15:26:09
svm = cv2.SVM() svm.train(np.array(train_desc), np.array(train_labels)) i=0 j=0 confusion = np.zeros((2,2)) def classify(pth):  feature = feature_extract(pth)  p = svm.predict...
• svmmaster_SVM_svmimage_svm图像分类_高光谱分类_lastdgw_源码.zip
• svmmaster_SVM_svmimage_svm图像分类_高光谱分类_lastdgw_源码.rar
• 改动点1：图像输入自定义，不再固定名称改动点2：解决找不到sift、svm组件类型问题改动点3：解决svm训练的标签错误问题改动点4：解决导入不了svm模型问题等注意：SVM.train中标签一定要为整数类型代码如下：import ...
• ## matlab版hog+svm图像二分类

千次下载 热门讨论 2016-12-20 14:29:42
该代码实现的是图像的二分类，hog用于图像的特征提取，svm表示的是对特征的分类。解压缩后，在添加到matlab的工作目录后，需要在代码中修改一下资源文件的路径（比如正负样本的图片路径），才可以正确运行。
• 本代码是hog+svm分类实例，对于新手入门图像处理是个很好的实例，要运行本代码，需在代码同一级目录下建pos和neg文件夹，还有网上找几张图片，就可以运行了。还有更改一下路径就可以了。

...