習為什麼需要那麼多的資料
影象增強方法最直接了當,但是為什麼需要那麼多的資料呢,從直觀上理解很簡單,和人相似,學習到足夠多的東西才能舉一反三。當然這裡指的足夠多的東西是一個數據集中包含多種多樣的資料,包含不同情況不同形態的儘可能豐富的資料。
資料集的分佈曲線應該平滑 如果你只學習到一個場景,這個場景的資料很多,很容易造成神經網路“過度學習”,也就是所謂的學的太過了,舉一反三的本領太強。舉個例子,在目標檢測的一個簡單的任務中,我們要識別一個木板(board)和參照物(reference),下圖就是一個正確的識別結果:
看看發生了什麼?我們訓練的這個神經網路太會舉一反三了,認為只要有這個參照物,參照物下面的總是木板,於是就出現了這樣的情況。想要消除這種情況,資料集中木板和參照物的資料必須多元化,足夠多,不能光滿足一種情況下的資料量,需要多種情況多種條件下的資料。
深度學習聖經有句話:常用的隱示"先驗"是平滑先驗或區域性不變性,這個先驗表明我們學習的函式不應該在小區域內發生很大的變化。也就是說學習的函式應該是平滑的,不應該“偏科”。另外,只要學習的真實函式的峰值和谷值處有足夠多的樣本,那麼平滑性假設和相關的無引數學習演算法的效果都非常好,這也就是資料量豐富的優勢。
但對於人工智慧領域這些比較複雜的演算法任務來說,我們想要獲得更好的結果的直接途徑,除了改進演算法,那就是擴充你的資料集了。
LeNet手寫數字識別網路中有一個對影象變化的簡單測試,利用普通的數字影象訓練好資料後,拿經過變換後的資料嘗試進行識別,
我們可以看到整個神經網路一共有7層(不包括輸入層),其中有兩個是池化層(pooling layer),LaNet-5使用的是平均池化方法,在網路中起到了降維的作用。
其實,為什麼神經網路也可以識別資料集中微小的變形呢?說白了是因為pooling操作在降維的同時起到了一定的(很微小)旋轉不變性的作用。
比如在我們檢測一個物體的時候,神經網路的activation層在這個物體的邊緣處發生了比較明顯的變化,當這個物體稍微旋轉一下,物體的邊緣稍稍移動時,由於max-pooling的緣故,這個物體的邊緣依然會刺激到我們的activation層,當然,max-pooling的核大小是很有限的,對於一般的影象旋轉,平移,max-pooling就無法發揮作用了。
quora上也有說法,大致意思是過濾層(卷積層)有不變性,但是全連線層只會對特定的啟用層產生反應,也就是如果啟用層地點發生了變化,那麼全連線層就檢測不到了。
class Model(object): def __init__(self, num_classes, *input_shape): self.model = None self.input_shape = input_shape[0] self.num_classes = num_classes def create_model(self, use_fully_connected=True): self.model = Sequential() self.model.add(Conv2D(64, (3, 3), activation='relu', input_shape=self.input_shape)) self.model.add(Conv2D(32, (3, 3), activation='relu')) self.model.add(MaxPooling2D((2, 2))) if use_fully_connected: self.model.add(Flatten()) self.model.add(Dense(128, activation='relu')) self.model.add(Dense(self.num_classes, activation='softmax')) else: self.model.add(Conv2D(16, (3, 3), activation='relu')) self.model.add(Flatten()) self.model.add(Dense(self.num_classes, activation='softmax')) def compile(self): self.model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adadelta(), metrics=['accuracy']) def train(self, train_x, train_y, num_epochs, batch_size): self.model.fit(train_x, train_y, verbose=1, epochs=num_epochs, batch_size=batch_size) def test(self, test_x, test_y): return self.model.evaluate(test_x, test_y)