圖像分類 Image Classification

原文鏈接:http://cs231n.github.io/classification/

Example示例
例如骗露,在下面的圖像中寿冕,圖像分類模型采用一張圖像,并將概率分配給4個標簽{ cat椒袍,dog驼唱,hat,mug }驹暑。 如圖所示玫恳,對于計算機來說,圖像是由一個大型的三維數(shù)組表示的优俘。 在本例中京办,貓圖像寬248像素,高400像素帆焕,有三個顏色通道 Red惭婿、 Green、 Blue (簡稱 RGB)叶雹。 因此财饥,圖像由248 x 400 x 3個數(shù)字組成,即總共297,600個數(shù)字折晦。 每個數(shù)字都是一個從0(黑色)到255(白色)的整數(shù)钥星。 我們的任務(wù)是把這25萬個數(shù)字變成一個單一的標簽,比如“貓”满着。

圖像分類的任務(wù)是為給定的圖像預(yù)測單個標簽(或標簽上的分布谦炒,如圖所示)贯莺。 圖像是由0到255的整數(shù)組成的三維數(shù)組,大小為寬度 x 高度 x 3宁改。 3代表紅缕探、綠、藍三色通道

Challenges. 挑戰(zhàn)

由于識別一個視覺概念(比如貓)對于人類來說相對一些挑戰(zhàn)時还蹲,請記住圖像的原始表示為亮度值的3d 數(shù)組):

Viewpoint variation.視點變化
對于攝像機來說撕蔼,一個對象的單個實例可以通過多種方式進行導(dǎo)向。

Scale variation.尺度變化
視覺類經(jīng)常顯示其大小的變化(在現(xiàn)實世界中的大小秽誊,而不僅僅是其在圖像中的范圍)

Deformation.變形
許多感興趣的物體不是剛體鲸沮,可以在極端的方式下變形。

Occlusion.
感興趣物體可以被遮擋锅论。有時只能看到對象的一小部分(只有很少的像素)

Illumination conditions.光照條件
光照對像素級別的影響是劇烈的讼溺。

Background clutter.背景雜亂
感興趣物體可能會融入他們的環(huán)境,使得他們難以識別最易。

Intra-class variation.類內(nèi)變異
興趣類別通常比較廣泛怒坯,比如“椅子”。有許多不同類型的對象藻懒,每個都有自己的外觀剔猿。

一個好的圖像分類模型必須對所有這些變化的叉積保持不變,同時保持類間變化的敏感性嬉荆。

##########################################################

Data-driven approach 數(shù)據(jù)驅(qū)動方法

向計算機提供每個類別的許多例子归敬,然后開發(fā)學(xué)習算法,觀察這些例子并了解每個類別的視覺外觀鄙早。 這種方法被稱為數(shù)據(jù)驅(qū)動的方法汪茧,因為它依賴于首先累積一個標記圖像的訓(xùn)練數(shù)據(jù)集。 下面是一個數(shù)據(jù)集的一個例子:

四個視覺類別的示例訓(xùn)練集限番。在實際中舱污,可能有成千上萬的類別,每個類別有成千上萬的圖像弥虐。

The Image classification pipeline 圖像分類管道

圖像分類的任務(wù)是用一個像素數(shù)組表示單個圖像扩灯,并為其分配標簽。整個通道定義如下:
Input:輸入有一組n個圖像組成霜瘪,每個圖像都由K個不同的類別中的一個做為標簽珠插。將這些數(shù)據(jù)稱為訓(xùn)練集(training set)
Learning:任務(wù)是利用訓(xùn)練集學(xué)習每個類別的樣子。將這一步稱為訓(xùn)練分類器或者學(xué)習模型粥庄。
Evaluation:最后丧失,評估分類器的質(zhì)量豺妓,要求它預(yù)測一組之前沒有見過的新的圖像惜互。將這些圖像的真實標簽和分類器預(yù)測的標簽進行比較布讹。直觀地說,希望大量的預(yù)測和真實答案是相吻合的(稱之為基本事實ground truth)训堆。

##########################################################

Nearest Neighbor Classifier 最近鄰分類器

這種分類器與卷積神經(jīng)網(wǎng)絡(luò)沒有任何關(guān)系描验,在實際應(yīng)用中也很少使用,但它可以讓我們對圖像分類問題的基本方法有所了解坑鱼。

圖像分類示例數(shù)據(jù)集:CIFAR-10

這個數(shù)據(jù)集由60,000張高和寬都是32像素的小圖片組成膘流。 每個圖像都被標記為10個類中的一個(例如“ airplane,automobile鲁沥,bird呼股,etc”)。 這60,000張圖像被分割成一個包含50,000張圖像的訓(xùn)練集和一個包含10,000張圖像的測試集画恰。 在下面的圖片中彭谁,是來自10個類的10幅隨機圖片:

左邊:CIFAR-10的示例圖像。 右邊: 第一列顯示了一些測試圖像允扇,在每個圖像的旁邊缠局,我們根據(jù)像素級別的差異顯示了訓(xùn)練集中最近的10個鄰居。

CIFAR-10:http://www.cs.toronto.edu/~kriz/cifar.html

假設(shè)現(xiàn)在得到了包含50,000張圖像的 CIFAR-10訓(xùn)練集(每張標簽有5,000張圖像) 考润,希望標記其余的10,000張圖像狭园。 最近鄰分類器將獲取一個測試圖像,將其與每一個訓(xùn)練圖像進行比較糊治,并預(yù)測最近訓(xùn)練圖像的標簽唱矛。 在上面的圖片的右邊的圖像中,可以看到這個過程用于10個示例測試圖像的示例結(jié)果井辜。 注意揖赴,在10個示例中,只有3個檢索到同一類的圖像抑胎,而在其他7個示例中燥滑,情況并非如此。 例如阿逃,在第8行距離馬頭最近的訓(xùn)練圖像是一輛紅色的汽車铭拧,大概是由于強烈的黑色背景。 因此恃锉,在這種情況下搀菩,馬的圖像會被錯誤地貼上汽車的標簽。

你可能已經(jīng)注意到破托,我們沒有具體說明如何比較兩個圖像肪跋,在本例中,這兩個圖像只是32 x 32 x 3的兩個塊土砂。 最簡單的方法之一就是逐個像素地比較圖像州既,然后把所有的差異加起來谜洽。 換句話說,給定兩幅圖像并將它們表示為矢量 I1吴叶,I2阐虚,比較它們的合理選擇可能是 L1距離(L1 distance):



這里的求和是用所有像素來表示的,下面是可視化的過程:

使用像素級差異比較兩個圖像與 L1距離的例子(在這個例子中為一個顏色通道)蚌卤。 分別減去兩幅圖像实束,然后將所有差異合計為一個數(shù)字。 如果兩幅圖像相同逊彭,則結(jié)果為零咸灿。 但是,如果圖像非常不同侮叮,結(jié)果將是巨大的

如何在代碼中實現(xiàn)分類器析显。 首先,將 CIFAR-10數(shù)據(jù)用4個數(shù)組加載到內(nèi)存中: the training data/labels 和 the test data/labels签赃。 在下面的代碼中谷异,Xtr (大小為50,000 x 32 x 32 x 3)保存訓(xùn)練集中的所有圖像,相應(yīng)的一維數(shù)組 Ytr (長度為50,000)保存訓(xùn)練標簽(從0到9) :

Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide
# flatten out all images to be one-dimensional
Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072
Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072

現(xiàn)在已經(jīng)將所有的圖像延伸成行锦聊,下面是如何訓(xùn)練和評估分類器的方法:

nn = NearestNeighbor() # create a Nearest Neighbor classifier class
nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels
Yte_predict = nn.predict(Xte_rows) # predict labels on the test images
# and now print the classification accuracy, which is the average number
# of examples that are correctly predicted (i.e. label matches)
print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )

作為一個評估標準歹嘹,使用精確度(accuracy)是很常見的,它度量了預(yù)測正確的比例孔庭。 請注意尺上,我們將構(gòu)建的所有分類器都滿足這一個通用 API: 它們有一個 train (x,y)函數(shù)圆到,該函數(shù)接受數(shù)據(jù)和標簽以供學(xué)習怎抛。 在內(nèi)部,類應(yīng)該構(gòu)建標簽的某種模型芽淡,以及如何從數(shù)據(jù)中預(yù)測它們马绝。 然后還有一個預(yù)測(x)函數(shù),它接受新的數(shù)據(jù)并預(yù)測標簽下面是一個簡單的L1距離最近鄰分類器的實現(xiàn)挣菲,它滿足這個模板:

import numpy as np

class NearestNeighbor(object):
  def __init__(self):
    pass

  def train(self, X, y):
    """ X is N x D where each row is an example. Y is 1-dimension of size N """
    # the nearest neighbor classifier simply remembers all the training data
    self.Xtr = X
    self.ytr = y

  def predict(self, X):
    """ X is N x D where each row is an example we wish to predict label for """
    num_test = X.shape[0]
    # lets make sure that the output type matches the input type
    Ypred = np.zeros(num_test, dtype = self.ytr.dtype)

    # loop over all test rows
    for i in xrange(num_test):
      # find the nearest training image to the i'th test image
      # using the L1 distance (sum of absolute value differences)
      distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
      min_index = np.argmin(distances) # get the index with smallest distance
      Ypred[i] = self.ytr[min_index] # predict the label of the nearest example

    return Ypred

如果運行這段代碼富稻,您將看到這個分類器只能在 CIFAR-10上達到38.6% 。 這比隨機猜測準確(由于有10個類別白胀,猜測的準確率為10%) 椭赋,但是遠遠不及人類的表現(xiàn)(估計約為94%)也沒有接近最先進的卷積神經(jīng)網(wǎng)絡(luò)(達到95% 的準確率,與人類的準確率相當(參見最近在 CIFAR-10上舉辦的 Kaggle 競賽的排行榜))或杠。

距離選擇
計算向量之間的距離還有許多其他方法哪怔。 另一個常見的選擇可能是使用L2距離,它具有計算兩個向量之間的歐幾里得度量的幾何解釋。 距離的形式是:

換句話說认境,我們將像以前一樣計算像素差胚委,但是這次我們將它們平方,加起來元暴,最后得到平方根篷扩。 在 numpy 中兄猩,使用上面的代碼只需要替換一行代碼茉盏。 計算距離的那行:

distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1))

請注意,在上面包含了 np.sqrt 調(diào)用枢冤,但在實際的最近鄰應(yīng)用程序中鸠姨,可以省略平方根操作,因為平方根是單調(diào)函數(shù)淹真。 也就是說讶迁,它縮放了距離的絕對大小,但保留了排序核蘸,因此有或沒有排序的最近鄰是相同的巍糯。 如果在 CIFAR-10上用這個距離運行最近鄰分類器,將獲得35.4% 的準確率(略低于 L1距離結(jié)果)客扎。
L1 vs. L2. 考慮這兩個指標之間的差異是很有趣的祟峦。 特別是,當涉及到兩個矢量之間的差異時徙鱼,L2距離比 L1距離更加無情宅楞。 也就是說,相對于一個大的分歧袱吆,L2距離更傾向于多個中等程度的分歧厌衙。 L1和 L2距離(或相當于一對圖像之間差異的 L1 / L2范數(shù))是 p 范數(shù)最常用的特殊情況。

Nearest Neighbor Classifier for CIFAR-10 完整代碼

import pickle as p
import matplotlib.pyplot as plt
import numpy as np


# NearestNeighbor class
class NearestNeighbor(object):
    def __init__(self):
        pass

    def train(self, X, y):
        """ X is N x D where each row is an example. Y is 1-dimension of size N """
        # the nearest neighbor classifier simply remembers all the training data
        self.Xtr = X
        self.ytr = y

    def predict(self, X):
        """ X is N x D where each row is an example we wish to predict label for """
        num_test = X.shape[0]
        # lets make sure that the output type matches the input type
        Ypred = np.zeros(num_test, dtype=self.ytr.dtype)

        # loop over all test rows
        for i in range(num_test):
            # find the nearest training image to the i'th test image
            # using the L1 distance (sum of absolute value differences)
            distances = np.sum(np.abs(self.Xtr - X[i, :]), axis=1)
            min_index = np.argmin(distances)  # get the index with smallest distance
            Ypred[i] = self.ytr[min_index]  # predict the label of the nearest example

        return Ypred


def load_CIFAR_batch(filename):
    """ load single batch of cifar """
    with open(filename, 'rb')as f:
        datadict = p.load(f, encoding='latin1')
        X = datadict['data']
        Y = datadict['labels']
        Y = np.array(Y)  # 字典里載入的Y是list類型绞绒,把它變成array類型
        return X, Y


def load_CIFAR_Labels(filename):
    with open(filename, 'rb') as f:
        label_names = p.load(f, encoding='latin1')
        names = label_names['label_names']
        return names
# load data
label_names = load_CIFAR_Labels("cifar-10-batches-py/batches.meta")
imgX1, imgY1 = load_CIFAR_batch("cifar-10-batches-py/data_batch_1")
imgX2, imgY2 = load_CIFAR_batch("cifar-10-batches-py/data_batch_2")
imgX3, imgY3 = load_CIFAR_batch("cifar-10-batches-py/data_batch_3")
imgX4, imgY4 = load_CIFAR_batch("cifar-10-batches-py/data_batch_4")
imgX5, imgY5 = load_CIFAR_batch("cifar-10-batches-py/data_batch_5")
Xte_rows, Yte = load_CIFAR_batch("cifar-10-batches-py/test_batch")

Xtr_rows = np.concatenate((imgX1, imgX2, imgX3, imgX4, imgX5))
Ytr_rows = np.concatenate((imgY1, imgY2, imgY3, imgY4, imgY5))

nn = NearestNeighbor()  # create a Nearest Neighbor classifier class
nn.train(Xtr_rows[:5000,:], Ytr_rows[:5000])  # train the classifier on the training images and labels
Yte_predict = nn.predict(Xte_rows[:1000,:])  # predict labels on the test images
# and now print the classification accuracy, which is the average number
# of examples that are correctly predicted (i.e. label matches)
# print(Yte_predict)
print('accuracy: %f' % (np.mean(Yte_predict == Yte[:1000]))) # Yte_predict==Yte時分類正確婶希,求正確的概率

# show a picture
image=imgX1[9,0:1024].reshape(32,32)
print(image.shape)
plt.imshow(image)
plt.imshow(image,cmap=plt.cm.gray)
plt.axis('off')    #去除圖片邊上的坐標軸
plt.show()

##########################################################

K-Nearest Neighbor Classifier K-最近鄰分類器

當進行預(yù)測時,只使用最近圖像的標簽是很奇怪的蓬衡。 事實上饲趋,通過使用 k- 最近鄰分類器,幾乎總是可以做得更好撤蟆。 這個想法非常簡單: 不需要在訓(xùn)練集中找到最接近的圖像奕塑,而是找到最接近的 k 個圖像,然后讓他們對測試圖像的標簽進行投票家肯。 特別是龄砰,當 k=1時,恢復(fù)最近鄰分類器。 直觀上换棚,k 值越高式镐,分類器對異常值的抵抗能力就越強:

最近鄰和5-最近鄰分類器之間差異的示例,使用2維點和3個有色區(qū)域(紅色固蚤,藍色娘汞,綠色)顯示由具有L2距離的分類器引起的**決策邊界(decision boundaries)**。 白色區(qū)域顯示模糊分類的點(即夕玩,類別投票與至少兩個類別相關(guān)聯(lián))你弦。 請注意,在最近鄰分類器的情況下燎孟,異常數(shù)據(jù)點(例如藍點云中間的綠點)會產(chǎn)生可能不正確預(yù)測的小島禽作,而5-最近鄰分類器會平滑這些不規(guī)則性,可能會導(dǎo)致在測試數(shù)據(jù)上更好的泛化(未顯示)揩页。 還要注意旷偿,5-NN圖像中的灰色區(qū)域是由最近鄰居之間的投票關(guān)系引起的(例如,2個鄰居是紅色爆侣,接下來的兩個鄰居是藍色萍程,最后一個鄰居是綠色)。

k的值如何選擇呢兔仰? 接下來我們談?wù)勥@個問題茫负。

Validation sets for Hyperparameter tuning 用于超參數(shù)調(diào)優(yōu)的驗證集

K-最近鄰分類器需要 k 的設(shè)置。 但是什么數(shù)字最有效呢斋陪? 此外朽褪,有許多不同的距離函數(shù),可以使用: L1標準无虚,L2標準缔赠,還有許多其他的選擇,甚至還沒有考慮(如點積)友题。 這些選擇被稱為超參數(shù)(hyperparameters)嗤堰,它們經(jīng)常出現(xiàn)在許多從數(shù)據(jù)中學(xué)習的機器學(xué)習算法的設(shè)計中。 應(yīng)該選擇什么樣的值 / 設(shè)置通常并不明顯度宦。

你可能會建議嘗試許多不同的值踢匣,看看哪個最有效。這是一個好主意戈抄,這確實是我們將要做的离唬,但這必須非常小心。特別是划鸽,不能使用測試集來調(diào)整超參數(shù)输莺。每當設(shè)計機器學(xué)習算法時戚哎,應(yīng)該把測試集看作是一個非常寶貴的資源,理想情況下嫂用,直到最后一次才接觸到它型凳。否則,真正的危險是嘱函。調(diào)整后的超參數(shù)能過很好的在測試集上工作甘畅,但是當要部署模型時,可能會看到性能顯著降低往弓。在實踐中疏唾,稱作過擬合測試集。另一種看法是亮航,如果在測試集上調(diào)整超參數(shù)荸实,那么相當于把測試集當作訓(xùn)練集匀们,因此缴淋,在部署模型時,其上實現(xiàn)的性能對于實際觀察到的內(nèi)容會過于樂觀泄朴。但是如果只在最后使用一次測試集重抖,它仍然是衡量分類器泛化(generalization)的一個很好的代理。

??Evaluate on the test set only a single time, at the very end.
在測試集上只評估一次祖灰,在最后一次钟沛。

K-Nearest Neighbor Classifier for CIFAR-10 完整代碼

import pickle as p
import matplotlib.pyplot as plt
import numpy as np


# NearestNeighbor class
class NearestNeighbor(object):
    def __init__(self):
        pass

    def train(self, X, y):
        """ X is N x D where each row is an example. Y is 1-dimension of size N """
        # the nearest neighbor classifier simply remembers all the training data
        self.Xtr = X
        self.ytr = y

    def predict(self, X):
        """ X is N x D where each row is an example we wish to predict label for """
        num_test = X.shape[0]
        # lets make sure that the output type matches the input type
        Ypred = np.zeros(num_test, dtype=self.ytr.dtype)

        # loop over all test rows
        for i in range(num_test):
            # find the nearest training image to the i'th test image
            # using the L1 distance (sum of absolute value differences)
            distances = np.sum(np.abs(self.Xtr - X[i, :]), axis=1)
            sort_id = distances.argsort()
            # min_index = np.argmin(distances)  # get the index with smallest distance
            # print(min_index)
            dic = {}
            for j in range(20):
                vlable = self.ytr[sort_id[j]]  # 為對應(yīng)的標簽記數(shù)
                dic[vlable] = dic.get(vlable, 0) + 1
                # 尋找vlable代表的標簽,如果沒有返回0并加一局扶,如果已經(jīng)存在返回改鍵值對應(yīng)的值并加一
            max = 0
            # print(dic.items())
            for index, v in dic.items():  # .items  返回所有的鍵值對
                if v > max:
                    max = v
                    maxIndex = index
                Ypred[i] = maxIndex # predict the label
        print(Ypred)


        return Ypred


def load_CIFAR_batch(filename):
    """ load single batch of cifar """
    with open(filename, 'rb')as f:
        datadict = p.load(f, encoding='latin1')
        X = datadict['data']
        Y = datadict['labels']
        Y = np.array(Y)  # 字典里載入的Y是list類型恨统,把它變成array類型
        return X, Y


def load_CIFAR_Labels(filename):
    with open(filename, 'rb') as f:
        label_names = p.load(f, encoding='latin1')
        names = label_names['label_names']
        return names
# load data
label_names = load_CIFAR_Labels("cifar-10-batches-py/batches.meta")
imgX1, imgY1 = load_CIFAR_batch("cifar-10-batches-py/data_batch_1")
imgX2, imgY2 = load_CIFAR_batch("cifar-10-batches-py/data_batch_2")
imgX3, imgY3 = load_CIFAR_batch("cifar-10-batches-py/data_batch_3")
imgX4, imgY4 = load_CIFAR_batch("cifar-10-batches-py/data_batch_4")
imgX5, imgY5 = load_CIFAR_batch("cifar-10-batches-py/data_batch_5")
Xte_rows, Yte = load_CIFAR_batch("cifar-10-batches-py/test_batch")

Xtr_rows = np.concatenate((imgX1, imgX2, imgX3, imgX4, imgX5))
Ytr_rows = np.concatenate((imgY1, imgY2, imgY3, imgY4, imgY5))

nn = NearestNeighbor()  # create a Nearest Neighbor classifier class
nn.train(Xtr_rows[:5000,:], Ytr_rows[:5000])  # train the classifier on the training images and labels
Yte_predict = nn.predict(Xte_rows[:1000,:])  # predict labels on the test images
# and now print the classification accuracy, which is the average number
# of examples that are correctly predicted (i.e. label matches)
# print(Yte_predict)
print('accuracy: %f' % (np.mean(Yte_predict == Yte[:1000]))) # Yte_predict==Yte時分類正確,求正確的概率

# show a picture
image=imgX1[9,0:1024].reshape(32,32)
print(image.shape)
plt.imshow(image)
plt.imshow(image,cmap=plt.cm.gray)
plt.axis('off')    #去除圖片邊上的坐標軸
plt.show()

幸運的是三妈,有一種調(diào)優(yōu)超參數(shù)的正確方法畜埋,不涉及測試集。想法是:把訓(xùn)練集分成兩部分:一部分比較小的訓(xùn)練集稱為“驗證集(validation set)”畴蒲。以 CIFAR-10為例悠鞍,我們可以使用49,000個訓(xùn)練圖像進行訓(xùn)練,并留下1,000個圖像進行驗證模燥。 這個驗證集實質(zhì)上是一個偽測試集咖祭,用來調(diào)整超參數(shù)。

以下是 CIFAR-10的情況:

在這個過程結(jié)束時蔫骂,可以繪制一個圖表么翰,顯示哪個 k 值工作得最好。 然后辽旋,使用這個值浩嫌,在實際測試集上進行一次計算。

??把訓(xùn)練集分成訓(xùn)練集和驗證集。 使用驗證集優(yōu)化所有超參數(shù)固该。 最后在測試集上運行一次并報告性能锅减。

Cross-validation交叉驗證

如果訓(xùn)練數(shù)據(jù)的大小(以及驗證數(shù)據(jù))可能很小伐坏,人們有時會使用更復(fù)雜的技術(shù)進行超參數(shù)調(diào)整怔匣,稱為交叉驗證。 使用我們之前的示例桦沉,我們的想法是每瞒,不是任意選擇前1000個數(shù)據(jù)點作為驗證集和靜態(tài)訓(xùn)練集,而是通過迭代來獲得更好且噪聲更小的估計k的某個值的工作效果纯露。 驗證集并平衡這些性能剿骨。 例如,在5倍交叉驗證中埠褪,我們將訓(xùn)練數(shù)據(jù)分成5個相等的folds浓利,其中4個用于訓(xùn)練,1個用于驗證钞速。 然后我們將迭代哪個fold是驗證折疊贷掖,評估性能,最后平均不同fold的性能渴语。

例如參數(shù)k為5-fold的交叉驗證苹威。 對于k的每個值,我們在4folds上訓(xùn)練并在第5個上進行評估驾凶。 因此牙甫,對于每個k,我們在驗證fold上獲得5個精度(精度是y軸调违,每個結(jié)果是一個點)窟哺。 趨勢線通過每個k的結(jié)果的平均值繪制,誤差條表示標準偏差。 請注意,在此特定情況下暖夭,交叉驗證表明約k = 7的值最適合此特定數(shù)據(jù)集(對應(yīng)于圖中的峰值)泉蝌。 如果我們使用超過5folds,我們可能會看到更平滑(即噪聲較小)的曲線。

實際上實際上,更傾向于避免使用交叉驗證黄绩,而是使用單一的驗證分割(a single validation split),因為使用交叉驗證驗證可能會耗費大量計算時間玷过。 人們傾向于使用50%-90% 的訓(xùn)練數(shù)據(jù)用于訓(xùn)練爽丹,剩余的用于驗證筑煮。 但是,這取決于多個因素: 例如粤蝎,如果超參數(shù)的數(shù)量很大真仲,可能傾向于使用更大的驗證分割。 如果驗證集中的示例數(shù)量很少(可能只有幾百個左右) 初澎,那么使用交叉驗證更安全秸应。 在實踐中,通潮纾可以看到3-fold软啼、5-fold甚至10-fold的交叉驗證。

常見數(shù)據(jù)分割延柠。給定訓(xùn)練集和測試集祸挪。訓(xùn)練及被分成幾個folds(例如這里采用5 folds)。folds 1-4 作為訓(xùn)練集贞间。一個fold(如圖中fold5被標黃)作為驗證fold贿条,并用于調(diào)整參數(shù)。交叉驗證更進一步迭代選擇哪個fold是驗證fold榜跌,與1-5分開闪唆。這就是5-fold交叉驗證盅粪。最后模型訓(xùn)練完畢钓葫,所有最佳超參數(shù)被確定后,對測試數(shù)據(jù)進行一次評價(紅色)

K-Nearest Neighbor Classifier for CIFAR-10 交叉驗證完整代碼

import pickle as p
import matplotlib.pyplot as plt
import numpy as np

# NearestNeighbor class
class NearestNeighbor(object):
    def __init__(self):
        pass

    def train(self, X, y):
        """ X is N x D where each row is an example. Y is 1-dimension of size N """
        # the nearest neighbor classifier simply remembers all the training data
        self.Xtr = X
        self.ytr = y

    def predict(self, X,k):
        """ X is N x D where each row is an example we wish to predict label for """
        num_test = X.shape[0]
        # lets make sure that the output type matches the input type
        Ypred = np.zeros(num_test, dtype=self.ytr.dtype)

        # loop over all test rows
        for i in range(num_test):
            # find the nearest training image to the i'th test image
            # using the L1 distance (sum of absolute value differences)
            distances = np.sum(np.abs(self.Xtr - X[i, :]), axis=1)
            sort_id = distances.argsort()
            # min_index = np.argmin(distances)  # get the index with smallest distance
            # print(min_index)
            dic = {}
            for j in range(k):
                vlable = self.ytr[sort_id[j]]  # 為對應(yīng)的標簽記數(shù)
                dic[vlable] = dic.get(vlable, 0) + 1
                # 尋找vlable代表的標簽票顾,如果沒有返回0并加一础浮,如果已經(jīng)存在返回改鍵值對應(yīng)的值并加一
            max = 0
            print(dic.items())
            for index, v in dic.items():  # .items  返回所有的鍵值對
                if v > max:
                    max = v
                    maxIndex = index
                Ypred[i] = maxIndex # predict the label
        print(Ypred)


        return Ypred

def load_CIFAR_batch(filename):
    """ load single batch of cifar """
    with open(filename, 'rb')as f:
        datadict = p.load(f, encoding='latin1')
        X = datadict['data']
        Y = datadict['labels']
        Y = np.array(Y)  # 字典里載入的Y是list類型,把它變成array類型
        return X, Y

def load_CIFAR_Labels(filename):
    with open(filename, 'rb') as f:
        label_names = p.load(f, encoding='latin1')
        names = label_names['label_names']
        return names
# load data
label_names = load_CIFAR_Labels("cifar-10-batches-py/batches.meta")
imgX1, imgY1 = load_CIFAR_batch("cifar-10-batches-py/data_batch_1")
imgX2, imgY2 = load_CIFAR_batch("cifar-10-batches-py/data_batch_2")
imgX3, imgY3 = load_CIFAR_batch("cifar-10-batches-py/data_batch_3")
imgX4, imgY4 = load_CIFAR_batch("cifar-10-batches-py/data_batch_4")
imgX5, imgY5 = load_CIFAR_batch("cifar-10-batches-py/data_batch_5")
Xte_rows, Yte = load_CIFAR_batch("cifar-10-batches-py/test_batch")

Xtr_rows = np.concatenate((imgX1, imgX2, imgX3, imgX4, imgX5))
Ytr_rows = np.concatenate((imgY1, imgY2, imgY3, imgY4, imgY5))

nn = NearestNeighbor()  # create a Nearest Neighbor classifier class

nn.train(Xtr_rows[:5000,:], Ytr_rows[:5000])  # train the classifier on the training images and labels
Xval_rows = Xtr_rows[:1000, :]  # take first 1000 for validation
Yval = Ytr_rows[:1000]
Xtr_rows = Xtr_rows[1000:, :]  # keep last 49,000 for train
Ytr_rows = Ytr_rows[1000:]

# find hyperparameters that work best on the validation set
validation_accuracies = []
for k in [1, 3, 5, 10, 20, 50, 100]:
    # use a particular value of k and evaluation on validation data
    nn = NearestNeighbor()
    nn.train(Xtr_rows, Ytr_rows)
    # here we assume a modified NearestNeighbor class that can take a k as input
    Yval_predict = nn.predict(Xval_rows, k=k)
    acc = np.mean(Yval_predict == Yval)
    print('accuracy: %f' % (acc,))

    # keep track of what works on the validation set
    validation_accuracies.append((k, acc))

##########################################################

最近鄰分類器優(yōu)缺點

Pros:
1.實現(xiàn)和理解非常簡單奠骄。
2.分類器不需要時間訓(xùn)練豆同,只需要存儲并索引訓(xùn)練數(shù)據(jù)。

Cons:
1.測試時需要支付計算成本含鳞。因為測試示例分類需要與每個單獨的訓(xùn)練數(shù)據(jù)進行比較影锈。(實踐中,更關(guān)心測試時間的效率而不是訓(xùn)練時間的效率)

最近鄰分類器的計算復(fù)雜度是一個非巢醣粒活躍的研究領(lǐng)域鸭廷,現(xiàn)有的一些近似最近鄰算法(Approximate Nearest Neighbor ,ANN)和庫可以加速數(shù)據(jù)集中的最近鄰查找(例如 FLANN)熔吗。 這些算法允許在檢索過程中權(quán)衡最近鄰檢索的正確性與其空間 / 時間復(fù)雜度辆床,通常依賴于預(yù)處理 / 索引階段,該階段包括構(gòu)建 kdtree 或運行 k-means 算法桅狠。

最近鄰分類器在某些設(shè)置(特別是低維數(shù)據(jù))中可能是一個不錯的選擇讼载,但它很少適用于實際的圖像分類設(shè)置轿秧。 一個問題是,圖像是高維對象(即它們通常包含許多像素) 咨堤,在高維空間中的距離可能是非常違反直覺的菇篡。 下面的圖片說明了我們上面提到的基于像素的L2相似性與視覺上的相似性是非常不同的:

基于高維數(shù)據(jù)(尤其是圖像)的像素距離可能非常不直觀。 一個原始圖像(左)和它旁邊的其他三個圖像一喘,都是同樣遠離它的基礎(chǔ)上 L2像素距離逸贾。 顯然,像素級距離與視覺或語義相似度完全不對應(yīng)

這里還有一個可視化的例子津滞,使用像素差異來比較圖像是不夠的铝侵。 使用一種稱為 t-SNE 的可視化技術(shù)來獲取 CIFAR-10圖像,并將它們嵌入到二維空間中触徐,以便最好地保存它們的(局部)成對距離咪鲜。 在這個可視化中,根據(jù)我們上面展示的 L2像素距離撞鹉,附近顯示的圖像被認為是非常接近的:

用 t-SNE 嵌入二維 CIFAR-10圖像疟丙。 基于 L2像素的距離,這張圖片上附近的圖片被認為是近距離的鸟雏。 注意背景的強烈影響享郊,而不是語義類別的差異

更大的可視化版本:http://cs231n.github.io/assets/pixels_embed_cifar10_big.jpg0

特別要注意的是,相互鄰近的圖像更多的是圖像的一般色彩分布的函數(shù)孝鹊,或背景的類型炊琉,而不是它們的語義特征。 例如又活,一只狗可以看到非常接近青蛙苔咪,因為兩者碰巧都在白色的背景上。 理想情況下柳骄,希望所有10個類的圖像形成它們自己的集群团赏,以便同一類的圖像彼此鄰近,而不考慮不相關(guān)的特征和變化(例如背景)耐薯。 但是舔清,要獲得這個屬性,必須超越原始像素曲初。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末体谒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子复斥,更是在濱河造成了極大的恐慌营密,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件目锭,死亡現(xiàn)場離奇詭異评汰,居然都是意外死亡纷捞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門被去,熙熙樓的掌柜王于貴愁眉苦臉地迎上來主儡,“玉大人,你說我怎么就攤上這事惨缆∶又担” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵坯墨,是天一觀的道長寂汇。 經(jīng)常有香客問我,道長捣染,這世上最難降的妖魔是什么骄瓣? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮耍攘,結(jié)果婚禮上榕栏,老公的妹妹穿的比我還像新娘。我一直安慰自己蕾各,他們只是感情好扒磁,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著式曲,像睡著了一般妨托。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上检访,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天始鱼,我揣著相機與錄音,去河邊找鬼脆贵。 笑死,一個胖子當著我的面吹牛起暮,可吹牛的內(nèi)容都是我干的卖氨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼负懦,長吁一口氣:“原來是場噩夢啊……” “哼筒捺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起纸厉,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤系吭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后颗品,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肯尺,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡沃缘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了则吟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片槐臀。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖氓仲,靈堂內(nèi)的尸體忽然破棺而出水慨,到底是詐尸還是另有隱情,我是刑警寧澤敬扛,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布晰洒,位于F島的核電站,受9級特大地震影響啥箭,放射性物質(zhì)發(fā)生泄漏欢顷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一捉蚤、第九天 我趴在偏房一處隱蔽的房頂上張望抬驴。 院中可真熱鬧,春花似錦缆巧、人聲如沸布持。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽题暖。三九已至,卻和暖如春捉超,著一層夾襖步出監(jiān)牢的瞬間胧卤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工拼岳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留枝誊,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓惜纸,卻偏偏與公主長得像叶撒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耐版,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容