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
# 這裏注意數據集中給的是 <class 'numpy.uint8'> 整形數據,不注意的話後面會出現錯誤  使用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)

想寫好代碼還是得多動手多寫啊,加油

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章