CIFAR-10 SVM方法

CIFAR-10 SVM方法

notebook代码


# import package
import numpy as np
import pickle
import matplotlib.pyplot as plt

# load train and test data
# batches_meta = open('F:\PycharmProjects\cs231n\homework_1_SVM\cifar-10-batches-py\\batches.meta','rb')
# batches_meat_object = pickle.load(batches_meta,encoding='bytes')
# print(type(batches_meat_object))   # 一个字典格式
# print(batches_meat_object)

train_data = []
train_label = []
# 加载训练数据集,每个batch中有10000条数据,分开放的,现在把他们合并起来
for i in range(1,6):
    file_object = open('work/CIFAR10/data_batch_'+str(i),'rb')
    data_object = pickle.load(file_object,encoding='bytes')   # 字典格式
    # print(type(data_object[b'data'][2][3]))
    for line in data_object[b'data']:
        train_data.append(line)
    for line in data_object[b'labels']:
        train_label.append(line)
# notice there,train_data and train_label are the structure of python's list,you should transport to numpy's array
# 这里注意数据集中给的是  整形数据,不注意的话后面会出现错误  使用numpy.array.astype('float')方法可以直接整体转换,还有注意将python list转换为numpy array型
train_data = np.array(train_data).astype("float")
train_label = np.array(train_label)
# print(train_label)
print("train_data shape:"+str(train_data.shape))
print("train_label shape:"+str(train_label.shape))


# 加载测试集数据
test_data = []
test_label = []
test_file = open('work/CIFAR10/test_batch','rb')
test_file_object = pickle.load(test_file,encoding='bytes')
# print(test_file_object)
for line in test_file_object[b'data']:
    test_data.append(line)
for line in test_file_object[b'labels']:
    test_label.append(line)
test_data = np.array(test_data).astype("float")
test_label = np.array(test_label)
print("test_data shape:"+str(test_data.shape))
print("test_label shape:"+str(test_label.shape))
# print(test_label.ndim)



# 数据预处理
# np.mean()  
mean_image = np.mean(train_data,axis=0)
train_data -=mean_image
# train_label -=mean_image    # TODO
test_data -=mean_image
# test_label -=mean_image

# 首先,np.ones()可以创建元素值为1的数组,几维都可以,二维的时候就是用[]来括起来,还可以利用第二个参数来指定元素的类型,默认创建的是float型
train_data = np.hstack((train_data,np.ones([train_data.shape[0],1])))   # np.hstack()值得熟悉一下怎么使用的  注意两个array要再用一个括号括起来
# train_label = np.hstack(train_label,np.ones([train_label.shape[0],1]))
test_data = np.hstack((test_data,np.ones([test_data.shape[0],1])))
# test_label = np.hstack(test_label,np.ones([test_label.shape[0],1]))
print(str(train_data.shape))

class LinearSVM:
    def __init__(self):
        self.W = None
    
    def loss(self, X, y, reg):
        """
        Structured SVM loss function, vectorized implementation.

        Inputs and outputs are the same as svm_loss_naive.
        """
        loss = 0.0
        dW = np.zeros(self.W.shape) # initialize the gradient as zero

        num_train = X.shape[0]
        scores = X.dot(self.W)
        # print("test:")
        # print(range(num_train))
        # print(list(y))
        # print(scores[range(num_train), list(y)])
        #这里的code不熟悉还是不太容易理解,
        # print("scores维度:"+str(scores.shape))
        # 下面这句代码,还真的挺难懂的,确实把numpy用的很熟练
        # scores是200*10的,y 是100*1 维的,他们都是numpy.array类型的,然后scores[range(num_train),list(y)],[]里面两个列表,看了半天,他是把scores这个二维数组中
        # 每行正确分类的分数给单独拿出来放到一维array中,这时候是1*200的,最后再通过一个reshape 将其转换成200*1的,后面和非正确的分数进行减法运算,太牛逼的表达了
        correct_class_score = scores[range(num_train), list(y)].reshape(-1,1) # (N,1)  (1,-1)是二维内部转换成一行,(-1,1)转换成1列
        margin = np.maximum(0, scores - correct_class_score + 1)
        margin[range(num_train), list(y)] = 0   # 正确分类的分数值在上面的运算之后都变成了1,现在把他们都变成0
        loss = np.sum(margin) / num_train + 0.5 * reg * np.sum(self.W * self.W)   #后面是正则化惩罚项
  
        num_classes = self.W.shape[1]
        inter_mat = np.zeros((num_train, num_classes))
        inter_mat[margin > 0] = 1
        inter_mat[range(num_train), list(y)] = 0
        inter_mat[range(num_train), list(y)] = -np.sum(inter_mat, axis=1) 

        dW = (X.T).dot(inter_mat)
        dW = dW/num_train + reg*self.W

        return loss, dW
        
    def train(self, X, y, learning_rate=1e-3, reg=1e-5, num_iters=100,
            batch_size=200, verbose=False):
        """
        Train this linear classifier using stochastic gradient descent.  SGD

        Inputs:
        - X: A numpy array of shape (N, D) containing training data; there are N
          training samples each of dimension D.
        - y: A numpy array of shape (N,) containing training labels; y[i] = c
          means that X[i] has label 0 <= c < C for C classes.
        - learning_rate: (float) learning rate for optimization.
        - reg: (float) regularization strength.
        - num_iters: (integer) number of steps to take when optimizing
        - batch_size: (integer) number of training examples to use at each step.
        - verbose: (boolean) If true, print progress during optimization.

        Outputs:
        A list containing the value of the loss function at each training iteration.
        """
        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):
            X_batch = None
            y_batch = None
            idx_batch = np.random.choice(num_train, batch_size, replace = False)   # 从num_train 中随机选择batch_size个出来,replace表示抽样之后是否放回,true为放回
            X_batch = X[idx_batch]
            y_batch = y[idx_batch]
             # evaluate loss and gradient
            loss, grad = self.loss(X_batch, y_batch, reg)
            loss_history.append(loss)

            self.W -=  learning_rate * grad

            if verbose and it % 100 == 0:
                print('iteration %d / %d: loss %f' % (it, num_iters, loss))

        return loss_history

    def predict(self, X):
        """
        Use the trained weights of this linear classifier to predict labels for
        data points.

        Inputs:
        - X: A numpy array of shape (N, D) containing training data; there are N
          training samples each of dimension D.

        Returns:
        - y_pred: Predicted labels for the data in X. y_pred is a 1-dimensional
          array of length N, and each element is an integer giving the predicted
          class.
        """
        y_pred = np.zeros(X.shape[0])
        scores = X.dot(self.W)
        y_pred = np.argmax(scores, axis = 1)
        return y_pred

svm = LinearSVM()

loss_hist = svm.train(train_data, train_label, learning_rate=1e-7, reg=2.5e4,
                      num_iters=1500, verbose=True)


plt.plot(loss_hist)
plt.xlabel('Iteration number')
plt.ylabel('Loss value')
plt.show()

y_train_pred = svm.predict(train_data)
print("train accuracy: %f" % (np.mean(train_label == y_train_pred)))
y_test_pred = svm.predict(test_data)
print('accuracy: %f' % (np.mean(test_label== y_test_pred)))


写代码好难啊,我好菜啊!这里面大多数代码是别人写的
我写不出来,大佬的代码中numpy用的好好啊,我看都看半天,下面在粘贴下自己测试numpy的代码,加深理解。

# 这里测试使用numpy ones和zeros的使用
import numpy as np
a = np.zeros(3)   # 默认为float64 位
b = np.zeros([2,3],int)  # int表示int 32位
c = np.zeros([3,3],dtype='float32')
d = np.zeros([3,4])
print(a,type(a[1]))
print(b,type(b[1][1]))
print(c,type(c[1][1]))
print(d,type(d[1][1]))

aa = np.ones(3)
print(aa,type(aa[1]))

bbn = np.ones([2,2],dtype='int32')
print(bbn,type(bbn[1][1]))

rs = np.array([[1,2,3],
               [2,4,7]])
rs1 = rs.reshape(-1,1)      # 内部所有数组成一列
rs2 = rs.reshape(1,-1)      # 内部所有数排成一行
# 相当于reshape(-1,1) or reshape(1,-1) 对内部数据的结构进行了转换
# reshape中的参数知道了,其实就是几行几列的意思,第一个如果为-1的话,那么表示的就是其中的元素个数列,也就是变成一列
# 如果是(1,-1)的话,也就是差不多,-1表示自动计算,但是计算出来要可以整除
print(rs1)
print(rs2)
rs3 = rs.reshape(-1,)   # 这里只写一个-1竟然变成了一个一维列表而不是二维的了
print(rs3)
rs4 = rs.reshape(2,-1)   #这里变换为2行,至于每行几列直接写一个 -1来让他自己计算,但是要能够整除
print(rs4)

add1 = np.array([[1],
                 [2],
                 [3]])
add2 = np.array([[1],
                 [4],
                 [3]])
print(add1-add2+1)  # 这里加一可以直接每个都加上去,之前在写knn的时候减法也是这样的
margin = np.maximum(0,add1-add2+1)   # 同理,这里的和0比较大小,也是分别去比较,好几把灵活啊
print(margin)

scores = np.array([[1,2,3,4]])
y = np.array([1,2,3
              ])
correct_class_score = scores[range(1), list(y)]
print(list(y))
print(str(y.shape))
print(correct_class_score)

想写好代码还是得多动手多写啊,加油

你可能感兴趣的:(SVM,CIFAR-10)