CS231n-Assignment1

Posted by Hux Blog on May 1, 2018

kNN部分

学习到的新函数

  • plt.imshow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Display an image on the axes.

Parameters
----------
X : array_like, shape (n, m) or (n, m, 3) or (n, m, 4)
    Display the image in `X` to current axes.  `X` may be an
    array or a PIL image. If `X` is an array, it
    can have the following shapes and types:

    - MxN -- values to be mapped (float or int)
    - MxNx3 -- RGB (float or uint8)
    - MxNx4 -- RGBA (float or uint8)

    The value for each component of MxNx3 and MxNx4 float arrays should  
    be in the range 0.0 to 1.0. MxN arrays are mapped to colors based on
    the `norm` (mapping scalar to scalar) and the `cmap`  
    (mapping the normed scalar to a color).

输入可以有两种形式,一种PI另一种数组。当是数组的时候有三种shape,(n, m)、(n, m, 3)、(n, m, 4)。需要注意三种shape的数据类型以及范围。尤其是如果是0-255的float,记得data.astype(‘uint8’)。

  • python3与python2
1
2
3
# python2中 / 是截断除法;在python3中 / 是精确除法, //是截断除法。导入后,/变为精确除法
from __future__ import division
from __future__ import absolute_import

对于第二条命令,如果你在main.py中写import string,那么在Python 2.4或之前, Python会先查找当前目录下有没有string.py, 若找到了,则引入该模块,然后你在main.py中可以直接用string了。如果你是真的想用同目录下的string.py那就好,但是如果你是想用系统自带的标准string.py呢?那其实没有什么好的简洁的方式可以忽略掉同目录的string.py而引入系统自带的标准string.py。这时候你就需要from _future_ import absolute_import了。这样,你就可以用import string来引入系统的标准string.py, 而用from pkg import string来引入当前目录下的string.py了

参考

  • ipython 自动重载模块
1
2
3
4
# Some more magic so that the notebook will reload external python modules;
# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython
%load_ext autoreload
%autoreload 2
  • 利用subplot画超屌的展示集
1
2
3
4
5
6
7
8
9
10
11
12
13
14
classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
num_classes = len(classes)
samples_per_class = 7
for y, cls in enumerate(classes):    #y is idx
    idxs = np.flatnonzero(y_train == y)
    idxs = np.random.choice(idxs, samples_per_class, replace=False)
    for i, idx in enumerate(idxs):
        plt_idx = i * num_classes + y + 1
        plt.subplot(samples_per_class, num_classes, plt_idx)  #plt_idx从1开始
        plt.imshow(X_train[idx].astype('uint8'))
        plt.axis('off')
        if i == 0:
            plt.title(cls)
plt.show()

  • 用F-norm(F范数)验证两个矩阵的同一性
1
2
difference = np.linalg.norm(dists - dists_one, ord='fro')
#当difference很小时,人为两个矩阵相等

\(||A||_{F} = \sqrt{\sum_{i,j}a_{i,j}^{2}}\)

  • 计时模块
1
2
3
4
5
6
7
8
9
10
11
12
def time_function(f, *args):
    """
    Call a function f with args and return the time (in seconds) that it took to execute.
    """
    import time
    tic = time.time()
    f(*args)
    toc = time.time()
    return toc - tic

two_loop_time = time_function(classifier.compute_distances_two_loops, X_test)
print('Two loop version took %f seconds' % two_loop_time)
  • 画errorbar图
1
2
3
4
5
6
7
8
9
10
11
12
for k in k_choices:
    accuracies = k_to_accuracies[k]
    plt.scatter([k] * len(accuracies), accuracies) # 散点图,同一个横坐标扩展为len(accuracies)个

# plot the trend line with error bars that correspond to standard deviation
accuracies_mean = np.array([np.mean(v) for k,v in sorted(k_to_accuracies.items())])
accuracies_std = np.array([np.std(v) for k,v in sorted(k_to_accuracies.items())])
plt.errorbar(k_choices, accuracies_mean, yerr=accuracies_std)
plt.title('Cross-validation on k')
plt.xlabel('k')
plt.ylabel('Cross-validation accuracy')
plt.show()


其实就是每个超参数下运行多次得到了多个结果,然后对结果取均值,标准差即可。

  • 取出k近邻
1
2
3
closest_y = self.y_train[np.argsort(dists[i])[:k]]
# self.y_train是训练数据label,np.argsort(dists[i])是第i行距离的升序index,取出前k个。
# 注意,y_train[list]这种用法前提是type(y_train)=np.ndarray,通过list中的索引直接取出y_train对应元素
  • np.array_split 交叉验证分割
1
2
3
4
5
6
7
Split an array into multiple sub-arrays.
Examples
--------
>>> x = np.arange(8.0)
>>> np.array_split(x, 3)
    [array([ 0.,  1.,  2.]), array([ 3.,  4.,  5.]), array([ 6.,  7.])]
# 最后如果不是整除,剩几个取几个
  • ndarray拼接
1
2
3
4
X_val_train = np.vstack(X_train_folds[:i]+X_train_folds[i+1:]) # 垂直拼接
# eg a=[[1,2,3]] b=[[4,5,6]] X_val_train = [[1,2,3],[4,5,6]]
y_val_train = np.hstack(y_train_folds[:i]+y_train_folds[i+1:]) # 水平拼接
# eg a=[[1,2,3]] b=[[4,5,6]] y_val_train = [[1,2,3,4,5,6]]

注意上面的数组相加,如果是整体为np.array,那么是对应元素相加;但由于np.array_split的的结果是[np.array,np.array],即多个np.array组成的list,因此这是的相加是简单拼接。

  • np.linalg.norm计算各种距离

虽然欧式距离等可以自己实现,但是有轮子肯定要用啊。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Matrix or vector norm.

This function is able to return one of eight different matrix norms(可以计算8种范数,  
因此如果计算距离,需要输入x-y作为范数求解),  
or one of an infinite number of vector norms (described below), depending  
on the value of the ``ord`` parameter.


The following norms can be calculated:  

=====  ============================  ==========================  
ord    norm for matrices             norm for vectors  
=====  ============================  ==========================  
None   Frobenius norm                2-norm  
'fro'  Frobenius norm                --  
'nuc'  nuclear norm                  --  
inf    max(sum(abs(x), axis=1))      max(abs(x))  
-inf   min(sum(abs(x), axis=1))      min(abs(x))  
0      --                            sum(x != 0)  
1      max(sum(abs(x), axis=0))      as below  
-1     min(sum(abs(x), axis=0))      as below  
2      2-norm (largest sing. value)  as below  
-2     smallest singular value       as below  
other  --                            sum(abs(x)**ord)**(1./ord)  
=====  ============================  ==========================  
  • diction的遍历
1
2
3
4
d = {'person': 2, 'cat': 4, 'spider': 8}
for animal, legs in d.items():
   print('A %s has %d legs' % (animal, legs))
# Prints "A person has 2 legs", "A cat has 4 legs", "A spider has 8 legs

注意不是使用enumerate,而是items!

CIFAR10的数据处理

数据库介绍

1
2
3
# X原本为(10000,3072),3072=3*32*32,即RGB相邻存储。
# 通过transpose可以得到第一个三原色X[0][0][0][i],i=0,1,2
X = X.reshape(10000, 3, 32, 32).transpose(0,2,3,1)

矩阵距离的向量化计算

好长,还不想看。TODO refer to link

@2018.5.2

SVM部分

学习到的新函数

  • np.random.choice抽样序列

  • 一些lr的生成函数
  • colorbar图的画法

初始W的均值对SVM-loss初始值的定量分析

1
self.W = 10^()-n) * np.random.randn(dim, num_classes)

W的初始方式采用如上代码,也就是说W的每一个元素的量级是10^(-n)。考虑到np.dot(X,W),其中W因为随机初始化,因此正负值数量相对均衡;X是像素值,量级10^2,因此np.dot(X,W)的每个元素的量级是10^(2-n)。又因为SVM-loss对于每一个样本的loss值需要乘以类别数,故每个样本的loss贡献为量级 10^(2-n)*class。又因为总体loss需要加和再平均,因此量级一样。
具体到本例中,class=10,故初始loss的量级 10^(3-n)。同时同理论分析可知,SVM的初始loss(W很小,使得所有WX元素基本为0)理论值为class-1,本例中为loss=9。

  • 当W的初始均值很小时,np.dot(X,W)的每一项元素基本都为0,因此loss达到理论值为class-1,即9。
  • 当W的初始均值过大,其导致loss量级为10^(3-n)。
    • 若n=3,即均值0.001,loss量级1,因此误差是个位的误差,当然由于一定程度是定性分析,也有可能导致误差扩散到十位。实验中,这种情况的loss初始值在20左右。
    • 若n=4,均值0.01,loss量级10,误差为十位误差,实验中loss初值为150左右。
  • 因为,为了保证W的初值不影响初始loss的理论值(由于误差使得WX的初始值不为0),10^(3-n)应该为10^(-1)量级,因为理论loss为10^0~10^1量级,故n至少为4,即均值0.0001。实际上,该操作只用于check代码,如果没有问题,可以吧均值放大,loss同样会快速下降