首頁>技術>

在本節中,我們將重新討論手寫數字分類的問題(使用MNIST資料集),但這次使用的是深度神經網路,即使用兩個非常流行的深度學習庫TensorFlow和Keras來解決這個問題。TensorFlow(TF)是用於建立深度學習模型的著名的庫,它有一個非常龐大且令人驚豔的社群。然而,TensorFlow並不容易學會使用。而Keras是一個基於TensorFlow的高階應用程式介面(API),對底層結構的控制較少,但它比TF更友好且更易於使用。底層庫提供了更多的靈活性,因此TF可以相比Keras可以更多地調整,更靈活。

10.3.1 使用TensorFlow進行影象分類

從一個非常簡單的深度神經網路開始,它只包含一個全連線隱含層(ReLU啟用)和一個softmax(歸一化指數函式)全連線層,沒有卷積層。圖10-6所示的是顛倒的網路。輸入是一個包含28×28個輸入節點、隱含層為1024個節點和10個輸出節點的扁平化影象,對應於要分類的每個數字。

圖10-6 簡單的深度神經網路圖——顛倒的網路

現在用TF實現深度學習影象分類。首先,載入mnist資料集並將訓練影象分為兩部分,第一部分較大(使用50000張影象),用於訓練,第二部分(使用10000張影象)用於驗證;接著重新格式化標籤,用一個熱編碼的二進位制向量表示影象類;然後初始化tensorflow圖、變數、常量和佔位符張量,小批次隨機梯度下降(SGD)最佳化器將被用作批次大小為256的學習演算法,L2正則化器將被用來在兩個權重層上(具有超引數值λ1和λ2,且λ1=λ2= 1)最小化softmax互熵迴歸損失函式;最後,TensorFlow會話物件將以6000步(小批次)執行,並且執行前向/後向傳播以更新學習的模型(權重),隨後在驗證資料集上評估模型。可以看出,最終批次完成後獲得的準確率為96.5%。TF實現深度學習影象分類的程式碼如下所示:

%matplotlib inlineimport numpy as np# import datafrom keras.datasets import mnistimport tensorflow as tf# load data(X_train, y_train), (X_test, y_test) = mnist.load_data()np.random.seed(0)train_indices = np.random.choice(60000, 50000, replace=False)valid_indices = [i for i in range(60000) if i not in train_indices]X_valid, y_valid = X_train[valid_indices,:,:], y_train[valid_indices]X_train, y_train = X_train[train_indices,:,:], y_train[train_indices]print(X_train.shape, X_valid.shape, X_test.shape)# (50000, 28, 28) (10000, 28, 28) (10000, 28, 28)image_size = 28num_labels = 10def reformat(dataset, labels):dataset = dataset.reshape((-1, image_size *image_size)).astype(np.float32)# one hot encoding: Map 1 to [0.0, 1.0, 0.0 ...], 2 to [0.0, 0.0, 1.0 ...]labels = (np.arange(num_labels) == labels[:,None]).astype(np.float32)return dataset, labelsX_train, y_train = reformat(X_train, y_train)X_valid, y_valid = reformat(X_valid, y_valid)X_test, y_test = reformat(X_test, y_test)print('Training set', X_train.shape, X_train.shape)print('Validation set', X_valid.shape, X_valid.shape)print('Test set', X_test.shape, X_test.shape)# Training set (50000, 784) (50000, 784) # Validation set (10000, 784)(10000, 784) # Test set (10000, 784) (10000, 784)def accuracy(predictions, labels):return (100.0 * np.sum(np.argmax(predictions, 1) == np.argmax(labels, 1))/   predictions.shape[0])batch_size = 256num_hidden_units = 1024lambda1 = 0.1lambda2 = 0.1graph = tf.Graph()with graph.as_default():# Input data. For the training data, we use a placeholder that will be fed# at run time with a training minibatch.tf_train_dataset = tf.placeholder(tf.float32,shape=(batch_size, image_size *   image_size))tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size,num_labels))tf_valid_dataset = tf.constant(X_valid)tf_test_dataset = tf.constant(X_test)# Variables.weights1 = tf.Variable(tf.truncated_normal([image_size * image_size,num_hidden_units]))biases1 = tf.Variable(tf.zeros([num_hidden_units]))# connect inputs to every hidden unit. Add biaslayer_1_outputs = tf.nn.relu(tf.matmul(tf_train_dataset, weights1) +biases1)weights2 = tf.Variable(tf.truncated_normal([num_hidden_units,num_labels]))biases2 = tf.Variable(tf.zeros([num_labels]))# Training computation.logits = tf.matmul(layer_1_outputs, weights2) + biases2loss =tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=tf_train_labels, logits=logits) + \lambda1*tf.nn.l2_loss(weights1) + lambda2*tf.nn.l2_loss(weights2))# Optimizer.optimizer = tf.train.GradientDescentOptimizer(0.008).minimize(loss)# Predictions for the training, validation, and test data.train_prediction = tf.nn.softmax(logits)layer_1_outputs = tf.nn.relu(tf.matmul(tf_valid_dataset, weights1) +biases1)valid_prediction = tf.nn.softmax(tf.matmul(layer_1_outputs, weights2) +biases2)layer_1_outputs = tf.nn.relu(tf.matmul(tf_test_dataset, weights1) +biases1)test_prediction = tf.nn.softmax(tf.matmul(layer_1_outputs, weights2) +biases2)num_steps = 6001ll = []atr = []av = []import matplotlib.pylab as pylabwith tf.Session(graph=graph) as session:#tf.global_variables_initializer().run()session.run(tf.initialize_all_variables())print("Initialized")for step in range(num_steps):# Pick an offset within the training data, which has been randomized.# Note: we could use better randomization across epochs.offset = (step * batch_size) % (y_train.shape[0] - batch_size)# Generate a minibatch.batch_data = X_train[offset:(offset + batch_size), :]batch_labels = y_train[offset:(offset + batch_size), :]# Prepare a dictionary telling the session where to feed the minibatch.# The key of the dictionary is the placeholder node of the graph to be fed,# and the value is the numpy array to feed to it.feed_dict = {tf_train_dataset : batch_data, tf_train_labels :batch_labels}_, l, predictions = session.run([optimizer, loss, train_prediction],feed_dict=feed_dict)if (step % 500 == 0):ll.append(l)a = accuracy(predictions, batch_labels)atr.append(a)print("Minibatch loss at step %d: %f" % (step, l))print("Minibatch accuracy: %.1f%%" % a)a = accuracy(valid_prediction.eval(), y_valid)av.append(a)print("Validation accuracy: %.1f%%" % a)print("Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), y_test))# Initialized# Minibatch loss at step 0: 92091.781250# Minibatch accuracy: 9.0%# Validation accuracy: 21.6%## Minibatch loss at step 500: 35599.835938# Minibatch accuracy: 50.4%# Validation accuracy: 47.4%## Minibatch loss at step 1000: 15989.455078# Minibatch accuracy: 46.5%# Validation accuracy: 47.5%## Minibatch loss at step 1500: 7182.631836# Minibatch accuracy: 59.0%# Validation accuracy: 54.7%## Minibatch loss at step 2000: 3226.800781# Minibatch accuracy: 68.4%# Validation accuracy: 66.0%## Minibatch loss at step 2500: 1449.654785# Minibatch accuracy: 79.3%# Validation accuracy: 77.7%## Minibatch loss at step 3000: 651.267456# Minibatch accuracy: 89.8%# Validation accuracy: 87.7%## Minibatch loss at step 3500: 292.560272# Minibatch accuracy: 94.5%# Validation accuracy: 91.3%## Minibatch loss at step 4000: 131.462219# Minibatch accuracy: 95.3%# Validation accuracy: 93.7%## Minibatch loss at step 4500: 59.149700# Minibatch accuracy: 95.3%# Validation accuracy: 94.3%## Minibatch loss at step 5000: 26.656094# Minibatch accuracy: 94.9%# Validation accuracy: 95.5%## Minibatch loss at step 5500: 12.033947# Minibatch accuracy: 97.3%# Validation accuracy: 97.0%## Minibatch loss at step 6000: 5.521026# Minibatch accuracy: 97.3%# Validation accuracy: 96.6%## Test accuracy: 96.5%

緊接著,視覺化圖層1的每一步權值,如下面的程式碼所示:

images = weights1.eval()pylab.figure(figsize=(18,18))indices = np.random.choice(num_hidden_units, 225)for j in range(225):pylab.subplot(15,15,j+1)pylab.imshow(np.reshape(images[:,indices[j]], (image_size,image_size)),cmap='gray')pylab.xticks([],[]), pylab.yticks([],[])pylab.subtitle('SGD after Step ' + str(step) + ' with lambda1=lambda2='+ str(lambda1))pylab.show()

執行上述程式碼,輸出結果如圖10-7所示。上面的圖可視化了在4000步之後,網路全連層1中225個(隨機選擇的)隱藏節點的學習權值。可知權重已經從模型所訓練的輸入影象中獲得了一些特徵。

圖10-7 使用全連線網路TF實現深度學習影象分類

不同步驟的訓練精度和驗證精度如下面的程式碼所示:

pylab.figure(figsize=(8,12))pylab.subplot(211)pylab.plot(range(0,3001,500), atr, '.-', label='training accuracy')pylab.plot(range(0,3001,500), av, '.-', label='validation accuracy')pylab.xlabel('GD steps'), pylab.ylabel('Accuracy'), pylab.legend(loc='lower right')pylab.subplot(212)pylab.plot(range(0,3001,500), ll, '.-')pylab.xlabel('GD steps'), pylab.ylabel('Softmax Loss')pylab.show()

輸出結果如圖10-8所示。注意:一般來說,如果準確性不斷提高,但最終訓練精度和驗證精度幾乎保持不變,就意味著不再發生學習。

圖10-8 深度學習過程中的訓練精度、驗證精度及Softmax損失

10.3.2 使用Keras對密集全連線層進行分類

使用Keras實現手寫數字分類,再次僅使用密集全連線層。這次將再使用一個隱藏層和一個失活層。如下程式碼顯示瞭如何使用keras.models Sequential()函式通過幾行程式碼實現分類器。接著可以簡單地將圖層按順序新增到模型中。引入了幾個隱藏層,每個隱藏層有200個節點,中間有一個失活,失活率為15%。而這一次,使用Adam最佳化器(它使用動量來加速SGD)。用10個epochs(一次透過整個輸入資料集)擬合訓練資料集上的模型。可以看到,透過簡單的結構變化,MNIST測試影象的準確率為98.04%。

import kerasfrom keras.models import Sequentialfrom keras.layers import Dense, Flatten, Dropoutfrom keras.layers.convolutional import Conv2D, MaxPooling2Dfrom keras.utils import to_categorical# import datafrom keras.datasets import mnist# load data(X_train, y_train), (X_test, y_test) = mnist.load_data()print(X_train.shape, X_test.shape)# (60000, 28, 28) (10000, 28, 28)# reshape to be [samples][pixels][width][height]X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32')X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype('float32')X_train = X_train / 255 # normalize training dataX_test = X_test / 255 # normalize test datay_train = to_categorical(y_train) # to one-hot-encoding of the labelsy_test = to_categorical(y_test)num_classes = y_test.shape[1] # number of categoriesdef FC_model():# create modelmodel = Sequential()model.add(Flatten(input_shape=(28, 28, 1)))model.add(Dense(200, activation='relu'))model.add(Dropout(0.15))model.add(Dense(200, activation='relu'))model.add(Dense(num_classes, activation='softmax'))# compile modelmodel.compile(optimizer='adam', loss='categorical_crossentropy',metrics=['accuracy'])return model# build the modelmodel = FC_model()model.summary()# fit the modelmodel.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10,batch_size=200, verbose=2)# evaluate the modelscores = model.evaluate(X_test, y_test, verbose=0)print("Accuracy: {} \n Error: {}".format(scores[1], 100-scores[1]*100))# _________________________________________________________________# Layer (type) Output Shape Param ## =================================================================# flatten_1 (Flatten) (None, 784) 0# _________________________________________________________________# dense_1 (Dense) (None, 200) 157000# ________________________________________________________________# dropout_1 (Dropout) (None, 200) 0# ________________________________________________________________# dense_2 (Dense) (None, 200) 40200# ________________________________________________________________# dense_3 (Dense) (None, 10) 2010# =================================================================# Total params: 199,210# Trainable params: 199,210# Non-trainable params: 0# _________________________________________________________________# Train on 60000 samples, validate on 10000 samples# Epoch 1/10# - 3s - loss: 0.3487 - acc: 0.9010 - val_loss: 0.1474 - val_acc: 0.9562# Epoch 2/10# - 2s - loss: 0.1426 - acc: 0.9580 - val_loss: 0.0986 - val_acc: 0.9700# Epoch 3/10# - 2s - loss: 0.0976 - acc: 0.9697 - val_loss: 0.0892 - val_acc: 0.9721# Epoch 4/10# - 2s - loss: 0.0768 - acc: 0.9762 - val_loss: 0.0829 - val_acc: 0.9744# Epoch 5/10# - 2s - loss: 0.0624 - acc: 0.9806 - val_loss: 0.0706 - val_acc: 0.9774# Epoch 6/10# - 2s - loss: 0.0516 - acc: 0.9838 - val_loss: 0.0655 - val_acc: 0.9806# Epoch 7/10# - 2s - loss: 0.0438 - acc: 0.9861 - val_loss: 0.0692 - val_acc: 0.9788# Epoch 8/10# - 2s - loss: 0.0387 - acc: 0.9874 - val_loss: 0.0623 - val_acc: 0.9823# Epoch 9/10# - 2s - loss: 0.0341 - acc: 0.9888 - val_loss: 0.0695 - val_acc: 0.9781# Epoch 10/10# - 2s - loss: 0.0299 - acc: 0.9899 - val_loss: 0.0638 - val_acc: 0.9804# Accuracy: 0.9804# Error: 1.9599999999999937
1.視覺化網路

可以透過程式碼視覺化用Keras設計的神經網路架構。如下程式碼將允許將模型(網路)架構儲存在一幅影象中:

# pip install pydot_ng ## install pydot_ng if not already installedimport pydot_ng as pydotfrom keras.utils import plot_modelplot_model(model, to_file='../images/model.png')

執行上述程式碼,輸出圖10-9所示的神經網路架構。

圖10-9 神經網路架構

2.視覺化中間層的權值

現在,利用程式碼視覺化在中間層學到的權值。如下程式碼可視化了第一個密集層的前200個隱藏單元的權值:

from keras.models import Modelimport matplotlib.pylab as pylabimport numpy as npW = model.get_layer('dense_1').get_weights()print(W[0].shape)print(W[1].shape)fig = pylab.figure(figsize=(20,20))fig.subplots_adjust(left=0, right=1, bottom=0, top=0.95, hspace=0.05,wspace=0.05)pylab.gray()for i in range(200):pylab.subplot(15, 14, i+1), pylab.imshow(np.reshape(W[0][:, i],(28,28))), pylab.axis('off')pylab.suptitle('Dense_1 Weights (200 hidden units)', size=20)pylab.show()

執行上述程式碼,輸出結果如圖10-10所示。

圖10-10 第一個密集層的前200個隱藏單元的權值

圖10-11所示的是神經網路在輸出層看到的東西,程式碼的編寫留給讀者作為練習。

圖10-11 神經網路輸出層所見

10.3.3 利用Keras的卷積神經網路分類

現在,讀者可以用Keras實現一個卷積神經網路。這需要引入卷積、池化和扁平層。接下來,我們將再次展示如何實現並使用卷積神經網路對MNIST分類。正如讀者將看到的,測試資料集的準確度增加了。

1.對MNIST分類

這次介紹一個帶有64個濾波器的5×5卷積層,緊接著介紹步長為2的2×2極大池化層,接下來是其所需要的扁平層,然後是一個包含100個節點的隱藏密集層,隨後是softmax密集層。其實現程式碼如下所示。執行程式碼,可以看到,經過10次迭代的模型訓練,測試資料集的準確率提高到98.77%。

import kerasfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.utils import to_categoricalfrom keras.layers.convolutional import Conv2D # to add convolutional layersfrom keras.layers.convolutional import MaxPooling2D # to add pooling layersfrom keras.layers import Flatten # to flatten data for fully connected layers# import datafrom keras.datasets import mnist# load data(X_train, y_train), (X_test, y_test) = mnist.load_data()print(X_train.shape, X_test.shape)# (60000, 28, 28) (10000, 28, 28)# reshape to be [samples][pixels][width][height]X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32')X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype('float32')X_train = X_train / 255 # normalize training dataX_test = X_test / 255 # normalize test datay_train = to_categorical(y_train)y_test = to_categorical(y_test)num_classes = y_test.shape[1] # number of categoriesdef convolutional_model():# create modelmodel = Sequential()model.add(Conv2D(64, (5, 5), strides=(1, 1), activation='relu',input_shape=(28, 28, 1)))model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))model.add(Flatten())model.add(Dense(100, activation='relu'))model.add(Dense(num_classes, activation='softmax'))# compile modelmodel.compile(optimizer='adam', loss='categorical_crossentropy',metrics=['accuracy'])return model# build the modelmodel = convolutional_model()model.summary()# _________________________________________________________________# Layer (type) Output Shape Param ## =================================================================# conv2d_1 (Conv2D) (None, 24, 24, 64) 1664# _________________________________________________________________# max_pooling2d_1 (MaxPooling2D) (None, 12, 12, 64) 0# _________________________________________________________________# flatten_1 (Flatten) (None, 9216) 0# _________________________________________________________________# dense_1 (Dense) (None, 100) 921700# _________________________________________________________________# dense_2 (Dense) (None, 10) 1010# =================================================================# Total params: 924,374# Trainable params: 924,374# Non-trainable params: 0# _________________________________________________________________# fit the modelmodel.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10,batch_size=200, verbose=2)# evaluate the modelscores = model.evaluate(X_test, y_test, verbose=0)print("Accuracy: {} \n Error: {}".format(scores[1], 100-scores[1]*100))#Train on 60000 samples, validate on 10000 samples#Epoch 1/10# - 47s - loss: 0.2161 - acc: 0.9387 - val_loss: 0.0733 - val_acc: 0.9779#Epoch 2/10# - 46s - loss: 0.0611 - acc: 0.9816 - val_loss: 0.0423 - val_acc: 0.9865#Epoch 3/10# - 46s - loss: 0.0417 - acc: 0.9876 - val_loss: 0.0408 - val_acc: 0.9871#Epoch 4/10# - 41s - loss: 0.0315 - acc: 0.9904 - val_loss: 0.0497 - val_acc: 0.9824#Epoch 5/10# - 40s - loss: 0.0258 - acc: 0.9924 - val_loss: 0.0445 - val_acc: 0.9851#Epoch 6/10# - 39s - loss: 0.0188 - acc: 0.9943 - val_loss: 0.0368 - val_acc: 0.9890#Epoch 7/10# - 39s - loss: 0.0152 - acc: 0.9954 - val_loss: 0.0391 - val_acc: 0.9874#Epoch 8/10# - 42s - loss: 0.0114 - acc: 0.9965 - val_loss: 0.0408 - val_acc: 0.9884#Epoch 9/10# - 41s - loss: 0.0086 - acc: 0.9976 - val_loss: 0.0380 - val_acc: 0.9893#Epoch 10/10# - 47s - loss: 0.0070 - acc: 0.9980 - val_loss: 0.0434 - val_acc: 0.9877# Accuracy: 0.9877# Error: 1.230000000000004

圖10-12所示的是對於真相標籤為0的測試例項,輸出類為0的預測機率分佈。其實現程式碼留給讀者作為練習。

圖10-12 真相標籤為0的測試例項的預測機率

視覺化中間層

現在使用卷積層來學習這幾個影象的影象特徵(64個特徵與64個濾波器),並使之視覺化,其實現如下面的程式碼所示:

from keras.models import Modelimport matplotlib.pylab as pylabimport numpy as npintermediate_layer_model = Model(inputs=model.input,outputs=model.get_layer('conv2d_1').output)intermediate_output = intermediate_layer_model.predict(X_train)print(model.input.shape, intermediate_output.shape)fig = pylab.figure(figsize=(15,15))fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05,wspace=0.05)pylab.gray()i = 1for c in range(64):pylab.subplot(8, 8, c+1), pylab.imshow(intermediate_output[i,:,:,c]),pylab.axis('off')pylab.show()

圖10-13所示的是訓練資料集中標籤為0的手寫數字影象在卷積層學習得到的特徵圖。

圖10-13 標籤為0的手寫數字影象在卷積層學習得到的特徵圖

將訓練資料集中的影象索引值修改為2,再執行之前的程式碼,得到如下輸出結果:

i=2

圖10-14所示的是MNIST訓練資料集中標籤為4的手寫數字影象在卷積層學習得到的特徵圖。

圖10-14 標籤為4的手寫數字影象在卷積層學習得到的特徵圖

10.4 應用於影象分類的主流的深度卷積神經網路

在本節中,我們將討論一些應用於影象分類的主流的深度卷積神經網路(如VGG-18/19、ResNet和InceptionNet)。圖10-15所示的是提交給ImageNet挑戰的最相關條目的單季精度(top-1精度:由卷積神經網路預測為最高機率的正確標記次數),從最左端的AlexNet[亞歷克斯·克里澤夫斯基(AlexKrizhevsky)等,2012]至表現最好的Inception-v4[塞格德(Szegedy)等,2016]。

圖10-15 單季CNN預測的最高有效精度(top-1)

此外,還將用Keras訓練VGG-16 CNN,以對狗影象和貓影象分類。

VGG-16/19

VGG-16/19的主流卷積神經網路的架構如圖10-16所示。VGG-16網路有一個的顯著特點:它沒有那麼多的超級引數,而僅提供更為簡單的網路,使用者可以僅聚焦於步幅為1的3×3濾波器的卷積層,它總是使用相同的填充,並使所有2×2最大池化層的步幅為2。這是一個真正的深度網路。

圖10-16 VGG-16/19深度學習網路

VGG-16/19網路共有約1.38億個引數,如圖10-15所示。

1.用Keras中的VGG-16對貓/狗影象進行分類

在本節中,我們將使用Keras中的VGG-16實現對Kaggle狗vs. 貓比賽中的貓和狗影象進行分類。請讀者先下載訓練影象資料集和測試影象資料集,然後在訓練影象上從零開始訓練VGG-16網路。

(1)訓練階段。如下程式碼顯示瞭如何在訓練資料集中擬合模型。使用訓練資料集中的20000張影象訓練VGG-16模型並將5000張影象作為驗證資料集,用於在訓練時對模型進行評估。weights=None引數值必須傳遞給VGG16()函式,以確保從頭開始訓練網路。注意:如果不在GPU上執行,這將花費很長時間,所以建議使用GPU。

經過20次迭代,驗證資料集的精度達到78.38%。我們還可以透過調整超引數來進一步提高模型的精度,實現程式碼留給讀者作為練習。

import osimport numpy as npimport cv2from random import shufflefrom tqdm import tqdm # percentage bar for tasks.# download the cats/dogs images compressed train and test datasets fromhere: https://www.kaggle.com/c/dogs-vs-cats/data# unzip the train.zip images under the train folder and test.zip imagesunder the test foldertrain = './train'test = './test'lr = 1e-6 # learning rateimage_size = 50 # all the images will be resized to squaure images withthis dimensionmodel_name = 'cats_dogs-{}-{}.model'.format(lr, 'conv2')def label_image(image):word_label = image.split('.')[-3]if word_label == 'cat': return 0elif word_label == 'dog': return 1def create_training_data():training_data = []for image in tqdm(os.listdir(train)):path = os.path.join(train, image)label = label_image(image)image = cv2.imread(path)image = cv2.resize(image, (image_size, image_size))training_data.append([np.array(image),np.array(label)])shuffle(training_data)np.save('train_data.npy', training_data)return training_datatrain_data = create_training_data()#100%|████████████████████████████████████████████████████████████████████████████████████████| 1100/1100 [00:00<00:00,1133.86it/s]train = train_data[:-5000] # 20k images for trainingvalid = train_data[-5000:] # 5k images for validationX_train = np.array([i[0] for i in train]).reshape(-1,image_size,image_size,3)y_train = [i[1] for i in train]y_train = to_categorical(y_train)print(X_train.shape, y_train.shape)X_valid = np.array([i[0] for i in valid]).reshape(-1,image_size,image_size,3)y_valid = [i[1] for i in valid]y_valid = to_categorical(y_valid) # to one-hot encodingnum_classes = y_valid.shape[1] # number of categoriesmodel = VGG16(weights=None, input_shape=(image_size,image_size,3),classes=num_classes) # train VGG16 model from scratchmodel.compile(Adam(lr=lr), "categorical_crossentropy",metrics=["accuracy"]) # "adam"model.summary()# fit the model, it's going take a long time if not run on GPUmodel.fit(X_train, y_train, validation_data=(X_valid, y_valid), epochs=20,batch_size=256, verbose=2)# evaluate the modelscores = model.evaluate(X_valid, y_valid, verbose=0)print("Accuracy: {} \n Error: {}".format(scores[1], 100-scores[1]*100))# _______________________________________________________________#Layer (type) Output Shape Param# =================================================================# input_5 (InputLayer) (None, 50, 50, 3) 0# _________________________________________________________________# block1_conv1 (Conv2D) (None, 50, 50, 64) 1792# _________________________________________________________________# block1_conv2 (Conv2D) (None, 50, 50, 64) 36928# _________________________________________________________________# block1_pool (MaxPooling2D) (None, 25, 25, 64) 0# _________________________________________________________________# block2_conv1 (Conv2D) (None, 25, 25, 128) 73856# _________________________________________________________________# block2_conv2 (Conv2D) (None, 25, 25, 128) 147584# _________________________________________________________________# block2_pool (MaxPooling2D) (None, 12, 12, 128) 0# _________________________________________________________________# block3_conv1 (Conv2D) (None, 12, 12, 256) 295168# _________________________________________________________________# block3_conv2 (Conv2D) (None, 12, 12, 256) 590080# _________________________________________________________________# block3_conv3 (Conv2D) (None, 12, 12, 256) 590080# _________________________________________________________________# block3_pool (MaxPooling2D) (None, 6, 6, 256) 0# _________________________________________________________________# block4_conv1 (Conv2D) (None, 6, 6, 512) 1180160# _________________________________________________________________# block4_conv2 (Conv2D) (None, 6, 6, 512) 2359808# _________________________________________________________________# block4_conv3 (Conv2D) (None, 6, 6, 512) 2359808# _________________________________________________________________# block4_pool (MaxPooling2D) (None, 3, 3, 512) 0# _________________________________________________________________# block5_conv1 (Conv2D) (None, 3, 3, 512) 2359808# _________________________________________________________________# block5_conv2 (Conv2D) (None, 3, 3, 512) 2359808# _________________________________________________________________# block5_conv3 (Conv2D) (None, 3, 3, 512) 2359808# _________________________________________________________________# block5_pool (MaxPooling2D) (None, 1, 1, 512) 0# _________________________________________________________________# flatten (Flatten) (None, 512) 0# ________________________________________________________________# fc1 (Dense) (None, 4096) 2101248# _______________________________________________________________# fc2 (Dense) (None, 4096) 16781312# ________________________________________________________________# predictions (Dense) (None, 2) 8194# =================================================================# Total params: 33,605,442# Trainable params: 33,605,442# Non-trainable params: 0# _________________________________________________________________# Train on 20000 samples, validate on 5000 samples# Epoch 1/10# - 92s - loss: 0.6878 - acc: 0.5472 - val_loss: 0.6744 - val_acc: 0.5750# Epoch 2/20# - 51s - loss: 0.6529 - acc: 0.6291 - val_loss: 0.6324 - val_acc: 0.6534# Epoch 3/20# - 51s - loss: 0.6123 - acc: 0.6649 - val_loss: 0.6249 - val_acc: 0.6472# Epoch 4/20# - 51s - loss: 0.5919 - acc: 0.6842 - val_loss: 0.5902 - val_acc: 0.6828# Epoch 5/20# - 51s - loss: 0.5709 - acc: 0.6992 - val_loss: 0.5687 - val_acc: 0.7054# Epoch 6/20# - 51s - loss: 0.5564 - acc: 0.7159 - val_loss: 0.5620 - val_acc: 0.7142# Epoch 7/20# - 51s - loss: 0.5539 - acc: 0.7137 - val_loss: 0.5698 - val_acc: 0.6976# Epoch 8/20# - 51s - loss: 0.5275 - acc: 0.7371 - val_loss: 0.5402 - val_acc: 0.7298# Epoch 9/20# - 51s - loss: 0.5072 - acc: 0.7536 - val_loss: 0.5240 - val_acc: 0.7444# Epoch 10/20# - 51s - loss: 0.4880 - acc: 0.7647 - val_loss: 0.5127 - val_acc: 0.7544# Epoch 11/20# - 51s - loss: 0.4659 - acc: 0.7814 - val_loss: 0.5594 - val_acc: 0.7164# Epoch 12/20# - 51s - loss: 0.4584 - acc: 0.7813 - val_loss: 0.5689 - val_acc: 0.7124# Epoch 13/20# - 51s - loss: 0.4410 - acc: 0.7952 - val_loss: 0.4863 - val_acc: 0.7704# Epoch 14/20# - 51s - loss: 0.4295 - acc: 0.8022 - val_loss: 0.5073 - val_acc: 0.7596# Epoch 15/20# - 51s - loss: 0.4175 - acc: 0.8084 - val_loss: 0.4854 - val_acc: 0.7688# Epoch 16/20# - 51s - loss: 0.3914 - acc: 0.8259 - val_loss: 0.4743 - val_acc: 0.7794# Epoch 17/20# - 51s - loss: 0.3852 - acc: 0.8286 - val_loss: 0.4721 - val_acc: 0.7810# Epoch 18/20# - 51s - loss: 0.3692 - acc: 0.8364 - val_loss: 0.6765 - val_acc: 0.6826# Epoch 19/20# - 51s - loss: 0.3752 - acc: 0.8332 - val_loss: 0.4805 - val_acc: 0.7760# Epoch 20/20# - 51s - loss: 0.3360 - acc: 0.8586 - val_loss: 0.4711 - val_acc: 0.7838# Accuracy: 0.7838# Error: 21.61999999999999

如下程式碼使用前面程式碼的第二個卷積層中的前64個濾波器來視覺化狗影象的特徵:

intermediate_layer_model = Model(inputs=model.input,outputs=model.get_layer('block1_conv2').output)intermediate_output = intermediate_layer_model.predict(X_train)fig = pylab.figure(figsize=(10,10))fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05,wspace=0.05)pylab.gray()i = 3for c in range(64):pylab.subplot(8, 8, c+1), pylab.imshow(intermediate_output[i,:,:,c]),pylab.axis('off')pylab.show()

執行上述程式碼,輸出用模型學習得到的狗影象的特徵圖,如圖10-17所示。

圖10-17 利用VGG-16深度學習模型學習得到的狗影象,特徵

透過改變上述程式碼中的一行,讀者可以使用第二個塊的第二個卷積層中的前64個濾波器視覺化學習到的同一幅狗影象特徵:

intermediate_layer_model = Model(inputs=model.input,outputs=model.get_layer('block2_conv2').output)

圖10-18所示的是前述程式碼更改第一行後執行得到的輸出結果,即用模型學習得到的同樣的小狗影象特徵圖。

圖10-18 利用VGG-16深度學習模型的第二個卷積層學習所得到的狗影象特徵

2.測試(預測)階段

如下程式碼展示瞭如何使用學習到的VGG-16模型從測試影象資料集中預測影象是狗或是貓的機率:

test_data = process_test_data()len(test_data)X_test = np.array([i for i in test_data]).reshape(-1,IMG_SIZE,IMG_SIZE,3)probs = model.predict(X_test)probs = np.round(probs,2)pylab.figure(figsize=(20,20))for i in range(100):pylab.subplot(10,10,i+1), pylab.imshow(X_test[i,:,:,::-1]),pylab.axis('off')pylab.title("{}, prob={:0.2f}".format('cat' if probs[i][1] < 0.5 else'dog', max(probs[i][0],probs[i][1])))pylab.show()

圖10-19所示的是類預測了前100個測試影象以及預測機率。可以看到,雖然學習到的VGG-16模型也存在不少錯誤的預測,但大部分影象的標籤預測都是正確的。

圖10-19 學習後的VGG-16模型預測了前100個測試影象及其預測機率

3.InceptionNet

在卷積神經網路分類器的發展過程中,是一個非常重要的里程碑。在InceptionNet出現之前,卷積神經網路過去只是將卷積層疊加到最深處,以獲得更好的效能。InceptionNet則使用複雜的技術和技巧來滿足速度和準確性方面的效能。

InceptionNet不斷髮展,並帶來網路的多個新版本的誕生。一些流行的版本包括Inception-v1、Inception-v2、Inception-v3、Inception-v4和Inception-ResNet。由於突出部分和影象中資訊的位置可能存在巨大差異,因此針對卷積操作選擇正確的核心大小變得十分困難。對於分佈得更加全域性的資訊,首選更大的核心;而對於分佈得更加區域性的資訊,則優選較小的核心。深度神經網路遭受過擬合和梯度消失問題。單純疊加大型卷積運算將會產生大量的開銷。

InceptionNet透過新增在相同級別上操作的多個不同大小的濾波器來解決前面的所有問題,這導致網路變得更廣,而不是更深。圖10-20所示的是一個維度縮減的Inception模組,它使用3種不同大小的濾波器(1×1、3×3和5×5)和一個附加的最大池化層對輸入執行卷積。輸出被串接起來併發送到下一個Inception模組。為了使它更便宜,輸入通道的數量受到限制,在3×3和5×5卷積之前新增額外的1×1卷積。利用降維的Inception模組,建立了神經網路體系結構。這就是眾所周知的GoogleNetInception v1),其架構如圖10-19所示。GoogleNet有9個這樣的Inception模組線性堆疊,有22層深(27層,包括池化層),並在最後一個Inception模組的末尾使用全域性平均池

圖10-20 Inception深度學習網路架構

在編寫本文時,已經介紹了Inception的幾個版本(v2、v3和v4),它們都是對以前體系結構的擴充套件。Keras提供了Inception-v3模型,可以從頭開始訓練,也可以使用預訓練版本(使用在ImageNet上訓練獲得的權重)。

4.ResNet

簡單地疊加這些層並不一定會增加網路的深度。由於消失梯度問題(vanishing gradient problem),它們的訓練也比較困難。這是梯度被反向傳播到以前的圖層的問題,而且如果這種情況重複發生,梯度可能會變得無窮小。因此,隨著研究的深入,效能會受到嚴重影響。

ResNet代表殘差網路(Residual Network),它在網路中引入了快捷方式,我們稱之為標識快捷連線。快捷連線遵循它們的名稱,並執行跳過一個或多個層的任務,從而防止堆疊層降低效能。堆疊的標識層除了在當前網路上簡單地堆疊標識對映,什麼也不做。然後,其他體系結構可以按照預期的水平執行,這意味著較深的模型不會產生比較淺的模型更高的訓練錯誤率。

圖10-21所示的是一個34層的普通網路和殘差網路的例子。

圖10-21 普通網路與殘差網路

Keras提供了ResNet50模型,可以從零開始進行訓練,也可以載入預訓練的網路。還有一些架構,如AlexNet和MobileNet,鼓勵讀者去探索。

小結

在本章中,我們介紹了利用深度學習模型進行影象處理的最新進展。首先,討論深度學習的基本概念,它與傳統機器學習的不同之處,以及為什麼需要它;其次,引入卷積神經網路作為深度神經網路,專門用於解決複雜的影象處理問題和完成計算和視覺任務,並討論具有卷積層、池化層和全連線層的卷積神經網路體系結構;再次,介紹TensorFlow和Keras這兩個流行於Python中的深度學習庫,並向讀者展示如何使用卷積神經網路提高MNIST資料集對手寫數字分類的測試精度;最後,討論了一些流行的網路,如VGG-16/19、GoogleNet和ResNet。Kera的VGG-16模型是在Kaggle比賽的狗和貓影象上訓練的,向讀者展示了它如何在驗證影象資料集上以相當準確的方式執行。

本文摘自《Python影象處理實戰》

影象處理,計算機視覺人臉識別影象修復程式設計入門教程書籍零基礎,深度學習爬蟲用流行的Python影象處理庫、機器學習庫和深度學習庫解決影象處理問題。

本書介紹如何用流行的Python 影象處理庫、機器學習庫和深度學習庫解決影象處理問題。先介紹經典的影象處理技術,然後探索影象處理演算法的演變歷程,始終緊扣影象處理以及計算機視覺與深度學習方面的**進展。全書共12 章,涵蓋影象處理入門基礎知識、應用導數方法實現影象增強、形態學影象處理、影象特徵提取與描述符、影象分割,以及影象處理中的經典機器學習方法等內容。本書適合Python 工程師和相關研究人員閱讀,也適合對計算機視覺、影象處理、機器學習和深度學習感興趣的軟體工程師參考。

18
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 不翻牆、四個步驟、十分鐘搭建好K8S叢集