11.用深度學習方法為影象中的物體進行分類
阿新 • • 發佈:2018-12-16
這幾個庫現在更新了,用書上的會出錯,未解決,建議直接學新的
# -*- coding: utf-8 -*- """ Created on Sun Oct 14 09:09:58 2018 @author: asus """ #11 用深度學習方法為影象中的物體進行分類 import os batch1_filename = os.path.join( "E:\\books\Python資料探勘入門與實踐\用深度學習方法為影象中的物體進行分類", "cifar-10-batches-py", "data_batch_1") def unpickle(file): import pickle with open(file, 'rb') as fo: dict = pickle.load(fo, encoding='bytes') return dict batch1 = unpickle(batch1_filename) #這一批影象檔案讀進來後為一個字典結構,包含numpy陣列形式的影象資料、影象類別、檔名 #以及該批檔案的簡短說明(training batch 1 of 5 表示訓練集共五批,這是第一批)。 #提取一張影象 image_index = 100 image = batch1[b'data'][image_index] #影象資料格式與matplotlib(繪製圖像)所使用的有所不同,因此,要改變陣列形狀,對矩陣進行 #轉換。 image = image.reshape((32, 32, 3), order='F') import numpy as np image = np.rot90(image, -1) #之後,就可以用matplotlib繪製圖像 %matplotlib inline from matplotlib import pyplot as plt plt.imshow(image) #11.3 深度神經網路 #深度神經網路和基本神經網路的差別在於規模大小。至少包含兩層隱含層的神經網路被稱為深度 #神經網路。實際工作者遇到的深度神經網路通常規模很大,每層神經元數量和層次都非常多。 #神經網路接收很基礎的特徵作為輸出——就計算機視覺而言,輸入為簡單的畫素值。神經網路演算法 #把這些資料整合起來向網路中傳輸,在這個過程中,基本的特徵組合為複雜的特徵。計算機依靠 #它們進行分類。 #11.3.3 Theano簡介 #Theano使用來建立和執行數學表示式的工具。在Theano中,我們定義函式要做什麼而不是怎麼做 #這樣才能以最佳的方式對錶達式進行求值。 #我們可以用Theano來定義函式,處理標量、陣列和矩陣以及其他數學表示式。如我們可以建立計 #算直角三角形斜邊長度的函式。 import theano from theano import tensor as T a = T.dscalar() #標量 b = T.dscalar() c = T.sqrt(a ** 2 + b ** 2) #c是一個表示式,即不是函式,也不是數值 f = theano.function([a,b], c) #函式 f(3,4) #這個函式接收a、b,返回經過計算得到的結果,也就是輸出值c #11.3.4 Lasagne簡介 #該庫是專門用來構建神經網路的,實踐了幾種比較新的神經網路層和組成這些層的模組 #內建網路層(Network-in-network layers):這些小神經網路比傳統的神經網路層更容易解釋。 #刪除層(Dropout layers):訓練過程隨機刪除神經元,放置產生神經網路常見的過擬合問題。 #噪音層(Noise layers):為神經元引入噪音,也是為了解決過擬合問題。 #本章使用卷積層(convolution layers, 層級結構模擬人類視覺工作原理)。卷積層使用少量的 #相互連線的神經元,分析一部分輸入值,便於神經網路實現對資料的標準轉換,比如對影象資料 #的轉換。視覺分析實驗,就是用卷積層對影象進行轉換。 #用第一章的Iris資料集測試卷積神經網路 from sklearn.datasets import load_iris iris = load_iris() X = iris.data.astype(np.float32) y_true = iris.target.astype(np.int32) #Lasagne對資料型別有特殊要求,因此,需要把類別值轉換為int32型別(在原始資料集中用int64 #型別儲存)。 #把資料集分為訓練集和測試集兩部分 from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y_true, random_state=14) #接著,分別建立卷積神經網路各層。 #首先,建立輸入層,其神經元數量跟資料集特徵數量相同。可以指定每一批輸入的數量(設定為10) #這樣Lasagne可以在訓練階段做些優化。 import lasagne input_layer = lasagne.layers.InputLayer(shape=(10, X.shape[1])) #接著建立隱含層。該層從輸入層接收輸入(由第一個引數指定),該層一共有12個神經元,使用非 #線性的sigmoid函式。 hidden_layer = lasagne.layers.DenseLayer( input_layer, num_units=12, nonlinearity=lasagne.nonlinearities.sigmoid) #接著建立輸出層,它接受來自隱含層的輸入,輸出層共有三個神經元,使用非線性的softmax函 #數主要用於神經網路的最後一層。 output_layer = lasagne.layers.DenseLayer(hidden_layer, num_units=3,nonlinearity =lasagne.nonlinearities.softmax) #為了訓練剛建立的網路,我們需要定義幾個Theano訓練函式。在這之前,需要定義一個Theano表 #達式和函式。我們先來為神經網路的輸入資料、輸入結果和實際輸出結果宣告變數。 import theano.tensor as T net_input = T.matrix('net_input') net_output = output_layer.get_output(net_input) true_output = T.ivector('true_output') #接著定義損失函式,訓練函式如何提升網路效果需要參考它的返回值——訓練神經網路時,我們以 #最小化損失函式的返回值為前提。我們用類別交叉熵表示損失,這是一種衡量分類資料分類效果 #好壞的標準。損失函式表示的是網路的期望輸出和實際輸出兩者之間的差距。 loss = T.mean(T.nnet.categorical_crossentropy(net_output, true_output)) #接著定義修改網路權重的函式。我們獲取到網路的所有引數,建立調整權重的函式,使損失降低 #到最小。 all_params = lasagne.layers.get_all_params(output_layer) updates = lasagne.updates.sgd(loss, all_params, learning_rate=0.1) #最後,建立兩個Theano函式,先是訓練網路,然後獲取網路的輸出,以用於後續測試。 import theano train = theano.function([net_input, true_output], loss, updates=updates) get_output = theano.function([net_input], net_output) #然後呼叫訓練函式,在訓練集上進行一輪迭代,接收訓練資料,預測類別,與給定類別作比較, #更新特徵權重,以最小化損失。然後再進行1000次迭代,逐漸改進神經網路。 for n in range(1000): train(X_train, y_train) #接著,對輸出計算F值,以評估分類效果。 y_output = get_output(X_test) import numpy as np y_pred = np.argmax(y_output, axis=1) from sklearn.metrics import f1_score print(f1_score(y_test, y_pred)) #11.3.5 用nolearn實現神經網路 import numpy as np from PIL import Image, ImageDraw, ImageFont from skimage.transform import resize from skimage import transform as tf from skimage.measure import label, regionprops from sklearn.utils import check_random_state from sklearn.preprocessing import OneHotEncoder from sklearn.cross_validation import train_test_split def create_captcha(text, shear=0, size=(100, 24)): im = Image.new("L", size, "black") draw = ImageDraw.Draw(im) font = ImageFont.truetype(r"Coval.otf", 22) draw.text((2, 2), text, fill=1, font=font) image = np.array(im) affine_tf = tf.AffineTransform(shear=shear) image = tf.warp(image, affine_tf) return image / image.max() def segment_image(image): labeled_image = label(image > 0) subimages = [] for region in regionprops(labeled_image): start_x, start_y, end_x, end_y = region.bbox subimages.append(image[start_x:end_x,start_y:end_y]) if len(subimages) == 0: return [image,] return subimages random_state = check_random_state(14) letters = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ") shear_values = np.arange(0, 0.5, 0.05) def generate_sample(random_state=None): random_state = check_random_state(random_state) letter = random_state.choice(letters) shear = random_state.choice(shear_values) return create_captcha(letter, shear=shear, size=(20, 20)), letters.index(letter) dataset, targets = zip(*(generate_sample(random_state) for i in range(3000))) dataset = np.array(dataset, dtype='float') targets = np.array(targets) onehot = OneHotEncoder() y = onehot.fit_transform(targets.reshape(targets.shape[0],1)) y = y.todense().astype(np.float32) dataset = np.array([resize(segment_image(sample)[0], (20, 20)) for sample in dataset]) X = dataset.reshape((dataset.shape[0], dataset.shape[1] * dataset.shape[2])) X = X / X.max() X = X.astype(np.float32) X_train, X_test, y_train, y_test = \ train_test_split(X, y, train_size=0.9, random_state=14) #神經網路由一系列的層組成。在nolearn中實現神經網路,只徐定義它由Lasagne哪幾種類型的層 #組成就行,跟PyBrain做法大同小異。 from lasagne import layers layers=[ ('input', layers.InputLayer), ('hidden', layers.DenseLayer), ('output', layers.DenseLayer), ] from lasagne import updates from nolearn.lasagne import NeuralNet from lasagne.nonlinearities import sigmoid, softmax net1 = NeuralNet(layers=layers, input_shape=X.shape, hidden_num_units=100, output_num_units=26, hidden_nonlinearity=sigmoid, output_nonlinearity=softmax, hidden_b=np.zeros((100,), dtype=np.float64), update=updates.momentum, update_learning_rate=0.9, update_momentum=0.1, regression=True, max_epochs=1000, ) net1.fit(X_train, y_train) y_pred = net1.predict(X_test) y_pred = y_pred.argmax(axis=1) assert len(y_pred) == len(X_test) if len(y_test.shape) > 1: y_test = y_test.argmax(axis=1) print(f1_score(y_test, y_pred)) #11.4 GPU優化 #11.6 應用 #用CIFAR影象建立資料集。保留畫素結構——畫素的行列號。 import os import numpy as np batches = [] for i in range(1, 6): batch_filename = os.path.join( "E:\\books\Python資料探勘入門與實踐\用深度學習方法為影象中的物體進行分類", "cifar-10-batches-py", "data_batch_{}".format(i)) batches.append(unpickle(batch_filename)) break #把每批次的影象檔案一次新增到資料裡。 X = np.vstack([batch[b'data'] for batch in batches]) #然後,把畫素歸一化,並將其強制轉換為32位浮點型資料(GPU進行計算的虛擬機器唯一支援的資料 #型別)。 X = np.array(X) / X.max() X = X.astype(np.float32) #類別的處理方法相同,只不過我們使用hstack,它為陣列末尾追加一列資料。然後使用 #OneHotEncoder把它轉換為只含有一維有效編碼的陣列。 from sklearn.preprocessing import OneHotEncoder y = np.hstack(batch[b'labels'] for batch in batches).flatten() y = OneHotEncoder().fit_transform(y.reshape(y.shape[0],1)).todense() y = y.astype(np.float32) #把資料集切分為訓練集和測試集。 from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) #調整陣列形狀以保留原始影象的資料結構。影象原本是32畫素見方,每個畫素由三個值組成(分別 #表示紅、綠、藍的顏色值)。 #11.6.2 建立神經網路 #建立神經網路的各層 from lasagne import layers layers = [ ('input', layers.InputLayer), ('conv1', layers.Conv2DLayer), ('pool1', layers.MaxPool2DLayer), ('conv2', layers.Conv2DLayer), ('pool2', layers.MaxPool2DLayer), ('conv3', layers.Conv2DLayer), ('pool3', layers.MaxPool2DLayer), ('hidden4', layers.DenseLayer), ('hidden5', layers.DenseLayer), ('output', layers.DenseLayer), ] #最後三層使用密集層,但是前面使用三組卷積層和池化層。此外,我們必須以輸入層開始。這樣 #一共有10層。輸入資料跟資料集同型,而不只跟輸入層的神經元數量相同,輸入層和輸出層的大 #小仍由資料集來定。 #開是建立神經網路 import theano import lasagne from nolearn.lasagne import NeuralNet from lasagne.nonlinearities import sigmoid, softmax nnet = NeuralNet(layers=layers, input_shape=(None, 3, 32, 32), conv1_num_filters=32, conv1_filter_size=(3, 3), conv2_num_filters=64, conv2_filter_size=(2, 2), conv3_num_filters=128, conv3_filter_size=(2, 2), pool1_ds=(2,2), pool2_ds=(2,2), pool3_ds=(2,2), hidden4_num_units=500, hidden5_num_units=500, output_num_units=10, output_nonlinearity=softmax, updata_learning_rate=0.01, update_momentum=0.9, regression=True, max_epochs=3, verbose=1) #11.6.3 組裝起來 nnet.fit(X_train, y_train) from sklearn.metrics import f1_score y_pred = nnet.predict(X_test) print(f1_score(y_test.argmax(axis=1), y_pred.argmax(axis=1)))