[AI 笔记] SVM

[AI 笔记] SVM


参考资料:
CS231n

线性分类

线性分类简单来说就是将一个样本输入一个线性函数,输出为这个样本在各个类别上的得分,取得分高的类别作为其分类结果。

如下图所示,猫为待分类的样本,f(x,W)为一个线性函数,将样本输入后就得到了它在十个类别上的得分。
在这里插入图片描述
其中dog这一类的得分最高,为8.02分,所以分类器将这个样本分类为dog,显然分类错误了。
在这里插入图片描述

SVM

支持向量机,用来计算分类损失。其公式如图。

其中 i 代表第 i 个训练样本;yi 代表这个样本的标签,即真实分类;S 代表得分,Sj 即这个样本在 j 这个类别上的得分,Syi 即这个样本在 yi (其自身的真实类别)这个类别上的得分。
在这里插入图片描述
其中的 Sj - Syi + 1 最好是写作 Sj + 1 - Syi,这样比较好理解。其中的 1 其实是无关紧要的,作为 Sj 与 Syi 之间距离的一个预留量。

参照下图,结合SVM的公式,如果你把 Sj + 1 看作一个整体,记作 S’,那么第 i 个样本在 j 这个类别上的损失其实就是 S’ 与 Syi 的差值。当然,当这个差值小于零的时候,损失为零。(说明第 i 个样本在 yi 上的得分远大于在 j 上的得分,这里的远大于即公式中预留的距离 1,所以说这个预留的距离是按需可变的)

而后将这第 i 个样本在各个类别(除去它本身真实类别)上的损失进行累加,即得到了这个样本最终的损失。
在这里插入图片描述
把所有样本的损失都计算完成之后,取它们的加权平均,即为这一次训练所得到的损失。如下图所示:
在这里插入图片描述
在得到了训练损失之后,就可以利用梯度下降算法来更新权重,进行迭代训练了。

代码实现

#SVM_object.py
import numpy as np


class SVM(object):
    def __init__(self):
        self.W = None
        self.reg = 3.5e+4
        self.num_classes = 10
        self.learning_rate = 7.5e-8


    def svm_loss_vectorized(self, W, X, y, reg):

        loss = 0.0
        dW = np.zeros(W.shape) # 初始化梯度为0

        scores = X.dot(W)      # 计算得分    N×10

        num_train = X.shape[0]    # N

        scores_correct = scores[np.arange(num_train), y]     # 整形数组访问方式
        scores_correct = np.reshape(scores_correct, (num_train, -1)) # N×1
        margins = scores - scores_correct + 1            # SVM的loss计算公式
        margins = np.maximum(0, margins)
        margins[np.arange(num_train), y] = 0             # 正确分类处的损失置零
        loss += np.sum(margins) / num_train              # 计算均值损失
        loss += 0.5 * reg * np.sum(W * W)                # 正则化

        margins[margins > 0] = 1              # 布尔型数组访问方式
        row_sum = np.sum(margins, axis=1)  # N×1
        margins[np.arange(num_train), y] = -row_sum
        dW += np.dot(X.T, margins) / num_train + reg * W     # 计算梯度

        return loss, dW

    def train(self, X, y, num_classes=10, learning_rate=7.5e-8, reg=3.5e+4, num_iters=100,
              batch_size=200, verbose=False):
        """
         使用随机梯度下降来训练这个分类器
         输入:
         -X :一个numpy数组,维数为(N,D)
         -Y : 一个numpy数组,维数为(N,)
         -learning rate: float ,优化的学习率
         -reg : float,正则化强度
         -num_iters: integer, 优化时训练的步数
         -batch_size:integer, 每一步使用的训练样本数
         -ver bose : boolean, 若为真,优化时打印过程

         输出:
         一个存储每次训练的损失函数值的List
        """
        num_train, dim = X.shape
        self.num_classes = num_classes


        if self.W is None:
            self.W = 0.001 * np.random.randn(dim, num_classes) # 初始化W

        # 使用随机梯度下降优化W
        loss_history = []
        for it in range(num_iters):
            X_batch = None
            y_batch = None
            """
            从训练集中采样batch_size个样本和对应的标签,在这一轮梯度下降中使用。
            把数据存储在X_batch中,把对应的标签存储在y_batch中
            采样后,X_batch的形状为(dim,batch_size),y_batch的形状为(batch_size,)
            """
            batch_inx = np.random.choice(num_train, batch_size)
            X_batch = X[batch_inx, :]
            y_batch = y[batch_inx]

            loss, grad = self.svm_loss_vectorized(
                self.W, X_batch, y_batch, reg)
            loss_history.append(loss)

            """
            使用梯度和学习率更新权重
            """
            self.W = self.W - learning_rate * grad
            if verbose and it % 10 == 0:
                print('iteration %d / %d: loss %f' % (it, num_iters, loss))

        return loss_history

    def predict(self, X):

        y_pred = np.zeros(X.shape[0])
        scores = X.dot(self.W)
        y_pred = np.argmax(scores, axis=1)    # 返回每一行最大值的序号
        return y_pred
#SVM_run.py
from SVM_object import SVM
import time
import numpy as np


def unpickle(file):
    import pickle
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict


dataTrain = []
labelTrain = []
for i in range(1, 6):
    dic = unpickle(
        "D:/Desktop/论文及算法实现/DATA_SETS/cifar-10-batches-py/data_batch_"+str(i))
    for item in dic[b"data"]:
        # print(item.shape)
        item = item.tolist()
        item.append(1)
        dataTrain.append(item)
    for item in dic[b"labels"]:
        labelTrain.append(item)

dataTest = []
labelTest = []
dic = unpickle("D:/Desktop/论文及算法实现/DATA_SETS/cifar-10-batches-py/test_batch")

for item in dic[b"data"]:
    item = item.tolist()
    item.append(1)
    dataTest.append(item)
for item in dic[b"labels"]:
    labelTest.append(item)

dataTr = np.asarray(dataTrain)
dataTs = np.asarray(dataTest)
labelTr = np.asarray(labelTrain)
labelTs = np.asarray(labelTest)
print('dataTr.shape: {}'.format(dataTr.shape))

svm = SVM()
tic = time.time()
loss_hist = svm.train(dataTr, labelTr, num_classes=10, learning_rate=7.5e-8, reg=3.5e+4,
                      num_iters=1000, batch_size=1000, verbose=True)
toc = time.time()
print('That took %fs' % (toc - tic))


# 测试
y_train_pred = svm.predict(dataTr)
print('training accuracy: %f' % (np.mean(labelTr == y_train_pred), ))
y_val_pred = svm.predict(dataTs)
print('validation accuracy: %f' % (np.mean(labelTs == y_val_pred), ))
iteration 960 / 1000: loss 9.890029
iteration 970 / 1000: loss 9.573637
iteration 980 / 1000: loss 9.638673
iteration 990 / 1000: loss 8.619956
That took 44.813690s
training accuracy: 0.259320
validation accuracy: 0.254400
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值