svm.ipynb

  • 为SVM实现一个完全矢量化的损失函数
  • 为其解析梯度实现完全矢量化表达式
  • 使用数值梯度检查实现结果
  • 使用验证集调整学习率和正则化
  • 使用 SGD 优化损失函数
  • 可视化最终学习权重

第一部分

1. 一些配置和库的导入

# Run some setup code for this notebook.
import random
import numpy as np
from cs231n.data_utils import load_CIFAR10 # 该函数用于加载CIFAR-10数据集。
import matplotlib.pyplot as plt # 导入matplotlib.pyplot库,并命名为plt,用于绘图 # This is a bit of magic to make matplotlib figures appear inline in the
# notebook rather than in a new window.
# 在Jupyter Notebook中将绘制的图形显示在笔记本中而不是弹出新窗口 %matplotlib inline
plt.rcParams['figure.figsize'] = (10.0, 8.0) # set default size of plots 绘图默认大小
plt.rcParams['image.interpolation'] = 'nearest' # 设置了图像的插值方式为最近邻插值
plt.rcParams['image.cmap'] = 'gray' # 颜色映射为灰度

2. 导入数据集路径,删除之前冗余的训练集和测试集并重新载入,输出例如Training data shape: (50000, 32, 32, 3),代表训练数据集包含50,000个样本,每个样本的维度是32x32像素,具有3个通道(RGB颜色通道)。

3. 为部分样本的可视化。

4. 训练集、验证集和测试集的划分,并创建了一个小的dev集作为训练数据的子集

mask = range(num_training, num_training + num_validation)
X_val = X_train[mask]
y_val = y_train[mask]
# 选择train中num_training到num_training + num_validation范围的样本作验证集 mask = range(num_training)
X_train = X_train[mask]
y_train = y_train[mask]
# 选择train中的前num_training个样本作训练集 mask = np.random.choice(num_training, num_dev, replace=False)
X_dev = X_train[mask]
y_dev = y_train[mask]
# 从train中随机选择了num_dev个样本作为dev集
# np.random.choice函数用于从num_training个样本中选择num_dev个样本
# replace=False表示不允许重复选择。 mask = range(num_test)
X_test = X_test[mask]
y_test = y_test[mask]
# 从原始test中选择了前num_test个样本作为测试集

5. 将图像数据转化为行向量

X_train = np.reshape(X_train, (X_train.shape[0], -1))
# (X_train.shape[0], -1)表示将数组的第一个维度保持不变(即样本数量),而将后面的维度展平为一维。
# -1的使用是为了自动计算展平后的维度,以保持总元素数量不变。
# 即每个样本的图像数据展为一个长度为32*32*3的行向量

6. 减去图像平均值,注意train,val,test,dev数据集减去的都是train的平均值

并为train、val、test、dev集分别添加一列1向量作为SVM的偏置

# third: append the bias dimension of ones (i.e. bias trick) so that our SVM
# only has to worry about optimizing a single weight matrix W.
X_train = np.hstack([X_train, np.ones((X_train.shape[0], 1))])
X_val = np.hstack([X_val, np.ones((X_val.shape[0], 1))])
X_test = np.hstack([X_test, np.ones((X_test.shape[0], 1))])
X_dev = np.hstack([X_dev, np.ones((X_dev.shape[0], 1))])

第二部分 SVM Classifier

主要完成 cs231n/classifiers/linear_svm.py 当中的svm_loss_naive和svm_loss_vectorized两个函数。
 
1. 带循环的svm loss函数svm_loss_naive
对N个样本的小批量进行操作,数据维度为D,共有C个类别。
输入为权重矩阵W(大小为C*D),小批量数据数组X(大小为N*D),训练标签数组y(大小为N*1),浮点数reg表示正则化强度。
返回为一个元组,包括以单个浮点数表示的损失值,和以与W形状相同的数组表示的相对于权重W的梯度。
在逐图计算损失函数之前预赋值:
dW = np.zeros(W.shape)  # initialize the gradient as zero
# compute the loss and the gradient
num_classes = W.shape[1] # 权重矩阵W(D, C)的列数,即类别的数量C
num_train = X.shape[0] # 数据X(N, D)的行数,即训练样本的数量N
loss = 0.0

计算损失函数并调整dW

for i in range(num_train):
scores = X[i].dot(W) # 第i张图各类别的score
correct_class_score = scores[y[i]] # 正确类别的得分
for j in range(num_classes):
if j == y[i]:
continue # 跳过正确类别
margin = scores[j] - correct_class_score + 1 # note delta = 1
if margin > 0:
loss += margin
dW[:, j] += X[i] #对于错误类别j,将X[i]的特征向量添加到dW的第j列,以增加与非正确类别j相关的梯度
dW[:, y[i]] -= X[i]
# Right now the loss is a sum over all training examples, but we want it
# to be an average instead so we divide by num_train.
loss /= num_train
dW /= num_train
# Add regularization to the loss.
loss += reg * np.sum(W * W)
dW += 2 * reg * W return loss, dW

此时使得svm.py中 naive implementation of the loss 输出结果约为9,检查数值梯度与解析梯度,输出为:

numerical: -5.307963 analytic: -5.307963, relative error: 6.594235e-11
numerical: -0.682609 analytic: -0.682609, relative error: 2.391609e-10
numerical: -13.345338 analytic: -13.345338, relative error: 6.576081e-12
numerical: 14.802119 analytic: 14.802119, relative error: 4.652609e-12
numerical: 10.270928 analytic: 10.270928, relative error: 1.109950e-11
numerical: -8.296183 analytic: -8.296183, relative error: 3.013113e-11
numerical: 16.433458 analytic: 16.433458, relative error: 8.212111e-12
numerical: -6.156451 analytic: -6.156451, relative error: 8.508562e-12
numerical: 16.405473 analytic: 16.405473, relative error: 2.345135e-11
numerical: 18.069155 analytic: 18.069155, relative error: 9.391046e-12
numerical: -4.456779 analytic: -4.456779, relative error: 7.112725e-11
numerical: 11.308422 analytic: 11.308422, relative error: 1.921026e-11
numerical: 14.150021 analytic: 14.150021, relative error: 7.236039e-12
numerical: -19.405984 analytic: -19.405984, relative error: 1.218480e-11
numerical: -2.109591 analytic: -2.109591, relative error: 1.329375e-10
numerical: 3.450493 analytic: 3.450493, relative error: 5.982507e-11
numerical: -7.641039 analytic: -7.641039, relative error: 2.339206e-11
numerical: -22.684454 analytic: -22.684454, relative error: 9.529207e-12
numerical: -8.240884 analytic: -8.240884, relative error: 4.336906e-11
numerical: 11.273042 analytic: 11.273042, relative error: 2.986500e-11

(这个有没有正则化的差异我也没搞懂怎么看)

2. 向量化的的svm loss函数svm_loss_vectorized

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

    loss = 0.0
dW = np.zeros(W.shape) # initialize the gradient as zero num_train = X.shape[0]
scores = X.dot(W)
correct_class_scores = scores[np.arange(num_train), y].reshape(-1, 1)
margins = np.maximum(0, scores - correct_class_scores + 1)
margins[np.arange(num_train), y] = 0
loss = np.sum(margins) / num_train + reg * np.sum(W * W) binary = margins
binary[margins > 0] = 1
row_sum = np.sum(binary, axis=1)
binary[np.arange(num_train), y] = -row_sum
dW = X.T.dot(binary) / num_train + 2 * reg * W return loss, dW

第三部分 Stochastic Gradient Descent

 cs231n/classifiers/linear_classifier.py
 首先完成SGD LinearClassifier.train():
输入为:
数据数组X(大小为N*D)
训练标签数组y(大小为N*1)
浮点数learning rate 为优化学习率
浮点数reg表示正则化强度
整数num_iters为优化步数
整数batch_size为每步训练样本数量
布尔变量verbose表示是否打印过程
输出为:
一个包含每次训练迭代损失函数值的列表
class LinearClassifier(object):
def __init__(self):
self.W = None def train(
self,
X,
y,
learning_rate=1e-3,
reg=1e-5,
num_iters=100,
batch_size=200,
verbose=False,
):
num_train, dim = X.shape
num_classes = (
np.max(y) + 1
) # assume y takes values 0...K-1 where K is number of classes
if self.W is None:
# lazily initialize W
self.W = 0.001 * np.random.randn(dim, num_classes) # Run stochastic gradient descent to optimize W
loss_history = []
for it in range(num_iters)
indices = np.random.choice(num_train, batch_size, replace=True)
X_batch = X[indices]
y_batch = y[indices] # evaluate loss and gradient
loss, grad = self.loss(X_batch, y_batch, reg)
loss_history.append(loss) # perform parameter update
self.W -= learning_rate * grad
if verbose and it % 100 == 0: #每一百步打印一次
print("iteration %d / %d: loss %f" % (it, num_iters, loss)) return loss_history

输出为

iteration 0 / 1500: loss 785.501628
iteration 100 / 1500: loss 287.509919
iteration 200 / 1500: loss 107.628805
iteration 300 / 1500: loss 41.988279
iteration 400 / 1500: loss 18.835256
iteration 500 / 1500: loss 9.834987
iteration 600 / 1500: loss 6.770916
iteration 700 / 1500: loss 6.600116
iteration 800 / 1500: loss 5.691690
iteration 900 / 1500: loss 5.231099
iteration 1000 / 1500: loss 5.708499
iteration 1100 / 1500: loss 5.363125
iteration 1200 / 1500: loss 4.935640
iteration 1300 / 1500: loss 5.723507
iteration 1400 / 1500: loss 5.441428
That took 8.358134s

绘制为图像

然后完成LibearSVM.predict函数

输入X输出y

    def predict(self, X):
y_pred = np.zeros(X.shape[0])
scores = X.dot(self.W)
y_pred = np.argmax(scores, axis=1) #np.argmax()可以返回数组中最大元素的索引。
return y_pred

接下来的任务是调整超参数使得准确率上升到0.39左右(刚刚仅有0.37-0.38)

results = {}
best_val = -1 # The highest validation accuracy that we have seen so far.
best_svm = None # The LinearSVM object that achieved the highest validation rate.

为了减少训练时间,先把步数设得比较小,找到合适的参数再调整得大一些

learning_rates = [1.5e-7,1.4e-7,1.3e-7,1.2e-7]#调整超参数
regularization_strengths = [2.5e4,3e4] for lr in learning_rates:
for reg in regularization_strengths:
svm = LinearSVM()
svm.train(X_train, y_train, learning_rate=lr, reg=reg, num_iters=500) # 使用较小的 num_iters 进行训练 # 计算训练集和验证集上的准确率
train_accuracy = np.mean(y_train == svm.predict(X_train))
val_accuracy = np.mean(y_val == svm.predict(X_val)) # 将准确率存储在 results 字典中
results[(lr, reg)] = (train_accuracy, val_accuracy) # 更新最高验证准确率和对应的 LinearSVM 对象
if val_accuracy > best_val:
best_val = val_accuracy
best_svm = svm for lr, reg in sorted(results):
train_accuracy, val_accuracy = results[(lr, reg)]
print('lr %e reg %e train accuracy: %f val accuracy: %f' % (
lr, reg, train_accuracy, val_accuracy)) print('best validation accuracy achieved during cross-validation: %f' % best_val)

最后调出来差不多这样:(1500num_iters)

lr 1.400000e-07 reg 2.100000e+04 train accuracy: 0.368980 val accuracy: 0.374000
lr 1.400000e-07 reg 2.200000e+04 train accuracy: 0.372510 val accuracy: 0.387000
lr 1.400000e-07 reg 2.500000e+04 train accuracy: 0.366163 val accuracy: 0.393000
lr 1.400000e-07 reg 2.700000e+04 train accuracy: 0.364918 val accuracy: 0.384000
lr 1.400000e-07 reg 3.000000e+04 train accuracy: 0.351837 val accuracy: 0.353000
best validation accuracy achieved during cross-validation: 0.393000
 也可用用随机的:(不太会调这个,效果都不怎么好)
np.random.seed(7)

learning_rates = 10**(np.random.rand(5) * 1.5 - 7.5)#[1.4e-7]
regularization_strengths = 10**(np.random.rand(5) * 2 + 3)#[2.1e4,2.2e4,2.5e4,2.7e4,3e4]

绘散点图

在测试集上输出结果

# Evaluate the best svm on test set
y_test_pred = best_svm.predict(X_test)
test_accuracy = np.mean(y_test == y_test_pred)
print('linear SVM on raw pixels final test set accuracy: %f' % test_accuracy)

最后做了一个权重可视化,需要rescale the weights to be between 0 and 255

 
 

CS231N Assignment1 SVM 笔记的更多相关文章

  1. cs231n assignment1 KNN

    title: cs231n assignment1 KNN tags: - KNN - cs231n categories: - 机器学习 date: 2019年9月16日 17:03:13 利用KN ...

  2. SVM 笔记整理

    支持向量机 一.支持向量机综述 1.研究思路,从最特殊.最简单的情况开始研究 基本的线性的可分 SVM 解决二分类问题,是参数化的模型.定义类标记为 \(+1\) 和 \(-1\)(区别于感知机,感知 ...

  3. 笔记:CS231n+assignment1(作业一)

    CS231n的课后作业非常的好,这里记录一下自己对作业一些笔记. 一.第一个是KNN的代码,这里的trick是计算距离的三种方法,核心的话还是python和machine learning中非常实用的 ...

  4. 【cs231n】神经网络笔记笔记2

    ) # 对数据进行零中心化(重要) cov = np.dot(X.T, X) / X.shape[0] # 得到数据的协方差矩阵 数据协方差矩阵的第(i, j)个元素是数据第i个和第j个维度的协方差. ...

  5. 【cs231n】最优化笔记

    ): W = np.random.randn(10, 3073) * 0.0001 # generate random parameters loss = L(X_train, Y_train, W) ...

  6. cs231n官方note笔记

    本文记录官方note中比较新颖和有价值的观点(从反向传播开始) 一 反向传播 1 “反向传播是一个优美的局部过程.在整个计算线路图中,每个门单元都会得到一些输入并立即计算两个东西:1. 这个门的输出值 ...

  7. [基础]斯坦福cs231n课程视频笔记(三) 训练神经网络

    目录 training Neural Network Activation function sigmoid ReLU Preprocessing Batch Normalization 权重初始化 ...

  8. CS231n 2017 学习笔记01——KNN(K-Nearest Neighbors)

    本博客内容来自 Stanford University CS231N 2017 Lecture 2 - Image Classification 课程官网:http://cs231n.stanford ...

  9. SVM笔记

    1.前言 SVM(Support Vector Machine)是一种寻求最大分类间隔的机器学习方法,广泛应用于各个领域,许多人把SVM当做首选方法,它也被称之为最优分类器,这是为什么呢?这篇文章将系 ...

  10. 【cs231n】图像分类笔记

    前言 首先声明,以下内容绝大部分转自知乎智能单元,他们将官方学习笔记进行了很专业的翻译,在此我会直接copy他们翻译的笔记,有些地方会用红字写自己的笔记,本文只是作为自己的学习笔记.本文内容官网链接: ...

随机推荐

  1. HDC.Cloud2021|开发者们都在谈的云原生到底长什么样?

    摘要:云原生数据库基于存储与计算分离架构,与传统数据库相比,具备高性能.高扩展.一致性.易管理和多云支持等特性,在海量数据处理.智能存储.业务应用等方面表现出了强大的生命力. 近几年,云原生的风越刮越 ...

  2. GaussDB (for Cassandra) 数据库治理:大key与热key问题的检测与解决

    摘要:GaussDB(for Cassandra) 提供了大key和热key的实时检测,以帮助业务进行合理的schema设计,规避业务稳定性风险. 本文分享自华为云社区<GaussDB (for ...

  3. 总结vue3 的一些知识点:MySQL 排序

    MySQL 排序 我们知道从 MySQL 表中使用 SQL SELECT 语句来读取数据. 如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段 ...

  4. Solon2 之 Kotlin 语言开发后端项目,很爽

    今天也学别人用 Solon 框架写个 Kotlin 后端项目.自己搞配置还是有点难的,需要借助 "Solon Initializr" 生成个项目模板. 1.生成项目模板 打开&qu ...

  5. MyBatis batchInsert 批量插入数据

    mybatis 是一个 Java 的持久层框架,它支持定制化 SQL.存储过程以及高级映射.通过 MyBatis,开发者可以直接编写原生态 SQL,避免了 JDBC 代码的繁琐. 如何在 MyBati ...

  6. Java Bean 注册对象

    注册对象 POM.xml <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-al ...

  7. print('Hello World!')的新玩法

    相信很多同学入门Python的第一行代码都是print('Hello World!') print是初学者最先接触的Python函数,但是很多人可能到现在也不完全清楚它的用法. print(*obje ...

  8. Android RxJava 异常时堆栈信息显示不全(不准确),解决方案都在这里了

    现象 大家好,我是徐公,今天为大家带来的是 RxJava 的一个血案,一行代码 return null 引发的. 前阵子,组内的同事反馈说 RxJava 在 debug 包 crash 了,捕获到的异 ...

  9. LVS Nginx HAProxy区别

    LVS 抗负载能力强,性能高,能达到F5硬件的60%,对内存和cpu资源消耗比较低 工作在四层仅作分发之用,通过vrrp协议转发,具体流量由linux内核处理,没有流量的产生 稳定性.可靠性好,自身有 ...

  10. 洛谷P2678:跳石头(贪心 + 二分)

    题目背景 一年一度的"跳石头"比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间 ...