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. 云图说|云数据库RDS跨区域备份

    摘要:云数据库RDS支持将备份文件存放到另一个区域存储,某一区域的实例故障后,可以在异地区域使用备份文件在异地恢复到新的RDS实例,用来恢复业务. 本文分享自华为云社区<云图说_云数据库RDS- ...

  2. 教你3种Kafka的指定副本作为Leader的实现方式

    摘要:因为在我们实际的运维过程中,需要指定某个副本为ISR,但是Kafka中的Leader选举策略并不支持这个功能,所以需要我们自己来实现它. 本文分享自华为云社区<Kafka的指定副本作为Le ...

  3. aPaaS将如何改变软件行业?

    摘要:当SaaS在云计算中的占比越来越高的时候,几乎所有软件厂商言必谈SaaS,各大云厂商.咨询机构也都将目光瞄准了SaaS.如此火爆的现象背后,真实情况如何呢? 本文分享自华为云社区<[开天a ...

  4. 【Java 进阶篇】使用 Stream 流和 Lambda 组装复杂父子树形结构(List 集合形式)

    目录 前言 一.以部门结构为例 1.1实体 1.2返回VO 1.3具体实现 1.4效果展示 二.以省市县结构为例 2.1实体 2.2返回VO 2.3具体实现 2.4效果展示 三.文章小结 前言 在最近 ...

  5. 压测工具 wrk

    wrk 是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 epoll,kqueue 等,通过多线程和事件模式,对目标机器产生大量的负 ...

  6. MAVEN 配置和基本使用

    Maven 安装配置 解压 apache-maven-3.6.1.rar 既安装完成 配置环境变量 MAVEN_HOME 为安装路径的 bin 目录 在 Path 下添加 %MAVEN_HOME%\b ...

  7. IDEA 2021.2 新建JavaWeb项目及Tomcat部署

    前文:JSP 简单入门与 IDEA 开发环境配置 参考链接: https://zhuanlan.zhihu.com/p/68133583 https://www.cnblogs.com/javabg/ ...

  8. Problem 330A - Cakeminator (思维)

    330A. Cakeminator https://codeforces.com/problemset/problem/330/A 题意很容易理解:给定一块蛋糕区域,但蛋糕上有几个不能吃的草莓,大胃王 ...

  9. jQuery位置 内容 大小 属性 文档的操作

    1. 位置 1. offset() 2. position() 2. 大小 1. 内容(content)>内填充(padding)>边框(border)>外边距(margin) 2. ...

  10. 如何在Python中的子进程获取键盘输入

    场景:在Python中使用multiprocessing模块的Process创建子进程,试图在子进程中获取键盘输入. 使用input() 在子进程中使用input()会弹出报错信息:EOFError: ...