1. 程式人生 > >斯坦福CS231n作業程式碼(漢化)Assignment 1

斯坦福CS231n作業程式碼(漢化)Assignment 1

[CS231N - Assignment1 - Q5 - Image features exercises]

編寫:郭承坤 觀自在降魔 Fanli SlyneD
校對:毛麗
總校對與稽核:寒小陽

我們已經看到,通過用輸入影象的畫素訓練的線性分類器對影象的分類問題已經取得了不錯的結果。在這個練習中我們會用對影象畫素進一步計算得來的特徵來訓練線性分類器從而提高效能。

抽取特徵(Extract Features)

對於每張圖,我們會計算梯度方向直方圖(HOG)特徵和用HSV(Hue色調,Saturation飽和度,Value明度)顏色空間的色調特徵。把每張圖的梯度方向直方圖和顏色直方圖特徵合併形成我們最後的特徵向量。

粗略的講呢,HOG應該可以捕捉到影象的紋理特徵而忽略了顏色資訊,顏色直方圖會表示影象的顏色特徵而忽略了紋理特徵(詳細見這篇)。所以我們預估把兩者結合起來得到的效果應該是比用其中一種得到的效果好。對於後面的bonus,驗證一下這個設想是不錯的選擇。

hog_featurecolor_histogram_hsv兩個函式都只對一張圖做操作並返回這張圖片的特徵向量。extract_features函式接收一堆圖片和一個list的特徵函式,然後用每個特徵函式在每張圖片上過一遍,把結果存到一個矩陣裡面,矩陣的每一都是一張圖片的所有特徵的合併。【注:題目中寫的column,但從實際結果上來看應該是行】

1. 程式碼解析

from cs231n.features import *

num_color_bins = 10 # Number of bins in the color histogram
feature_fns = [hog_feature, lambda img: color_histogram_hsv(img, nbin=num_color_bins)]
X_train_feats = extract_features(X_train, feature_fns, verbose=True)
X_val_feats = extract_features(X_val, feature_fns)
X_test_feats = extract_features(X_test, feature_fns)

print(X_train_feats.shape, X_val_feats.shape, X_test_feats.shape)

# 預處理:減掉每一列特徵的平均值
mean_feat = np.mean(X_train_feats, axis=0, keepdims=True) X_train_feats -= mean_feat X_val_feats -= mean_feat X_test_feats -= mean_feat # 預處理:每一列除以標準差,這確保了每個特徵都在一個數值範圍內 std_feat = np.std(X_train_feats, axis=0, keepdims=True) X_train_feats /= std_feat X_val_feats /= std_feat X_test_feats /= std_feat # 多加一個bias列 X_train_feats = np.hstack([X_train_feats, np.ones((X_train_feats.shape[0], 1))]) X_val_feats = np.hstack([X_val_feats, np.ones((X_val_feats.shape[0], 1))]) X_test_feats = np.hstack([X_test_feats, np.ones((X_test_feats.shape[0], 1))])

在features.py中寫了兩個特徵的計算方法,HOG是改寫了scikit-image的fog介面,並且首先要轉換成灰度圖。顏色直方圖是實現用matplotlib.colors.rgb_to_hsv的介面把圖片從RGB變成HSV,再提取明度(value),把value投射到不同的bin當中去。關於HOG的原理請谷歌百度。

可能會踩的坑

  1. “Import Error: cannot import name imread” 安裝或者重灌Pillow或PIL(pip intall PIL)。如果安裝提示已經安裝了,可以重灌,下載地址在這裡, 下載後,pip install xxxx.whl
  2. orientation_histogram[:,:,i] = uniform_filter(temp_mag, size=(cx, cy))[cx/2::cx, cy/2::cy].T這行報錯,“TypeError: slice indices must be integers or None or have an __index__ method”,可以把程式碼改成: orientation_histogram[:,:,i] = uniform_filter(temp_mag, size=(cx, cy))[int(cx/2)::cx, int(cy/2)::cy].T

SVM訓練(Train SVM on Features)

用前面作業中的多分類SVM來對上面抽取到的特徵進行訓練。這次應該會比之前直接在畫素上訓練的結果更好。

from cs231n.classifiers.linear_classifier import LinearSVM

#learning_rates = [1e-9, 1e-8, 1e-7]
#regularization_strengths = [5e4, 5e5, 5e6]

results = {}
best_val = -1
best_svm = None

#pass
learning_rates =[5e-9, 7.5e-9, 1e-8]
regularization_strengths = [(5+i)*1e6 for i in range(-3,4)]

################################################################################
# TODO:                                                                        #
# 用驗證集來調整learning rate和regularization的強度。                            #
# 這個應該和你之前做SVM做驗證是一樣的,把最好的結果儲存在best_svm。你也許想試        #
# 試不同的顏色直方圖的bin的個數。如果你調的夠仔細,應該可以在驗證集上得到            #
# 差不多0.44的正確率。                                                          #
################################################################################
for rs in regularization_strengths:
    for lr in learning_rates:
        svm = LinearSVM()
        loss_hist = svm.train(X_train_feats, y_train, lr, rs, num_iters=6000)
        y_train_pred = svm.predict(X_train_feats)
        train_accuracy = np.mean(y_train == y_train_pred)
        y_val_pred = svm.predict(X_val_feats)
        val_accuracy = np.mean(y_val == y_val_pred)
        if val_accuracy > best_val:
            best_val = val_accuracy
            best_svm = svm           
        results[(lr,rs)] = train_accuracy, val_accuracy
################################################################################
#                              END OF YOUR CODE                                #
################################################################################
# Print out results.
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)

建議這裡可以把learning rate和regularization_strengths開個大一點的區間,多試試。


# 想知道演算法是如何運作的很重要的方法是把它的分類錯誤視覺化。在這裡的視覺化中,我們
# 展示了我們系統錯誤分類的圖片。比如第一列展示的是實際label是飛機,但是被我們系統誤
# 標註成其它label的圖片。
examples_per_class = 8
classes = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
for cls, cls_name in enumerate(classes):
    idxs = np.where((y_test != cls) & (y_test_pred == cls))[0]
    idxs = np.random.choice(idxs, examples_per_class, replace=False)
    for i, idx in enumerate(idxs):
        plt.subplot(examples_per_class, len(classes), i * len(classes) + cls + 1)
        plt.imshow(X_test[idx].astype('uint8'))
        plt.axis('off')
        if i == 0:
            plt.title(cls_name)
plt.show()

Inline question 1:

描述一下你模型分錯類的結果。他們看起來有合理嗎?

Answer: 筆者表示看起來不怎麼合理….LOL。

用神經網路訓練圖片特徵

在前面的作業中我們看到直接在畫素上訓練兩層的神經網路結果比線性分類器的效果好。在這個notebook中我們已經看到線性分類器在圖片特徵上比在畫素上效果好。
為了完整性,我們應該試試在圖片特徵上用神經網路。這個方法應該比前面的方法都好:你應該在測試集上很容易得到一個55%的分類結果。我們最好的模型達到了60%的準確率。

from cs231n.classifiers.neural_net import TwoLayerNet

input_dim = X_train_feats.shape[1]
hidden_dim = 500
num_classes = 10

net = TwoLayerNet(input_dim, hidden_dim, num_classes)
best_net = None

################################################################################
# TODO: Train a two-layer neural network on image features. You may want to    #
# cross-validate various parameters as in previous sections. Store your best   #
# model in the best_net variable.                                              #
################################################################################
learning_rates = [1e-2 ,1e-1, 5e-1, 1, 5]
regularization_strengths = [1e-3, 5e-3, 1e-2, 1e-1, 0.5, 1]

for lr in learning_rates:
    for reg in regularization_strengths:
        net = TwoLayerNet(input_dim, hidden_dim, num_classes)
        # Train the network
        stats = net.train(X_train_feats, y_train, X_val_feats, y_val,
        num_iters=1500, batch_size=200,
        learning_rate=lr, learning_rate_decay=0.95,
        reg= reg, verbose=False)
        val_acc = (net.predict(X_val_feats) == y_val).mean()
        if val_acc > best_val:
            best_val = val_acc
            best_net = net         
        results[(lr,reg)] = val_acc

# Print out results.
for lr, reg in sorted(results):
    val_acc = results[(lr, reg)]
    print 'lr %e reg %e val accuracy: %f' % (
                lr, reg,  val_acc)

print 'best validation accuracy achieved during cross-validation: %f' % best_val
#pass
################################################################################
#                              END OF YOUR CODE                                #
################################################################################

這部分基本上覆用前面的程式碼就可以了,引數還是要多除錯。

Bonus: Design your own features!

你已經看到了簡單的圖片特徵可以提升分類效果。到目前為止我們嘗試了HOG和顏色直方圖,但是其他型別的特徵也許能得到更好的分類效果。設計一個新的特徵。把它用在CIFAR-10上。解釋你的特徵是如何運作的,你為什麼覺得它會對影象分類有用。在這個notebook中實現它,使用交叉驗證來調整超引數,並和HOG特徵+顏色直方圖的特徵的baseline做比較。

Bonus: Do something extra!

用這個作業中的資料和程式碼做點有趣的事。是否有我們應該問的其他問題?你在做這個作業的時候有其他很棒的想法嗎?做做吧!

這裡可以驗證上面提到過的把HOG特徵和顏色直方圖的特徵單獨拿出來效果是否變差。