numpy找到矩阵中不同元素的种类_基于NumPy和图像分类的人工神经网络构建
基于NumPy和圖像分類的人工神經(jīng)網(wǎng)絡構建
本文利用NumPy系統(tǒng)在Python中構建人工神經(jīng)網(wǎng)絡,以便為Fruits360數(shù)據(jù)集執(zhí)行圖像分類應用程序。
本文提及的所有內容(即圖像和源代碼,不包括Fruits360的圖片)均來自于Ahmed Fawzy Gad 著作《Practical Computer Vision Applications Using Deep Learning with CNNs》。
本書可以在以下網(wǎng)址查閱:
https://springer.com/us/book/9781484241660
本文中使用的源代碼可以在以下網(wǎng)址查閱:
https://github.com/ahmedfgad/NumPyANN
Fruits360數(shù)據(jù)集中有60類水果,如蘋果、番石榴、鱷梨、香蕉、櫻桃、棗、獼猴桃、桃子等。為了簡明扼要,本文只選定了四種分類,分別是蘋果、檸檬、芒果和覆盆子。每種分類大約有491個圖像用于操作,162個圖像用于測試。圖像大小為100x100像素。
1
特征提取
首先,選取一組合適的特征來保證分類的準確性。如下圖所示的4個類別的樣本圖像,這些水果的顏色不同,因此顏色特征適合用于特征提取的工作任務。
樣本圖像.jpg
RGB顏色空間不會將顏色信息與其他類型的信息(如亮度)區(qū)分開。因此,如果用RGB來表示圖像,會有3個通道參與到計算中。出于此原因,最好使用將顏色信息隔離成單個通道(如HSV)的顏色空間。在這種情況下,顏色通道即是色調通道(H)。下圖顯示了之前呈現(xiàn)的4個樣本的色調通道。我們可以注意到每個圖像的色調值與其他圖像的不同之處。
樣本色調通道.jpg
色調通道大小依舊為100x100。如果將整個通道應用于ANN,則輸入層將具有10,000個神經(jīng)元,網(wǎng)絡數(shù)據(jù)量過大。為了減少使用的數(shù)據(jù)量,我們可以使用直方圖來表示色調通道。直方圖具有360個區(qū)間,反映色調值的數(shù)據(jù)。
下圖是4個樣本圖像的直方圖,每種水果的色調值都落在直方圖的某些特定區(qū)間中。與使用RGB顏色空間中的任何通道相比,不同類別之間的重疊較少。例如,芒果的色調在直方圖中的區(qū)間為90~110,而蘋果的色調區(qū)間則為0~10。每個種類之間的邊距減少了分類的模糊性,從而提高了預測的準確性。
樣本圖像直方圖.jpg
以下是根據(jù)4個圖像計算色調通道直方圖的代碼
import numpy
import skimage.io, skimage.color
import matplotlib.pyplot
raspberry=skimage.io.imread(fname="raspberry.jpg",as_grey=False)
apple=skimage.io.imread(fname="apple.jpg",as_grey=False)
mango = skimage.io.imread(fname="mango.jpg", as_grey=False)
lemon = skimage.io.imread(fname="lemon.jpg", as_grey=False)
apple_hsv = skimage.color.rgb2hsv(rgb=apple)
mango_hsv = skimage.color.rgb2hsv(rgb=mango)
raspberry_hsv=skimage.color.rgb2hsv(rgb=raspberry)
lemon_hsv = skimage.color.rgb2hsv(rgb=lemon)
fruits = ["apple", "raspberry", "mango", "lemon"]
hsv_fruits_data = [apple_hsv, raspberry_hsv, mango_hsv, lemon_hsv]
idx = 0
for?hsv_fruit_data?in?hsv_fruits_data:
fruit = fruits[idx]
hist?=?numpy.histogram(a=hsv_fruit_data[:,?:,?0],?bins=360)
matplotlib.pyplot.bar(left=numpy.arange(360), height=hist[0])
matplotlib.pyplot.savefig(fruit+"-hue-histogram.jpg", bbox_inches="tight")
matplotlib.pyplot.close("all")
idx = idx + 1
通過循環(huán)使用4個圖像類中的所有圖像,我們可以從所有圖像中提取特征(參見下面的代碼)。根據(jù)4個分類中的圖像數(shù)量(1962)和從每個圖像中提取的特征向量長度(360),創(chuàng)建NumPy零數(shù)組并將其保存在dataset_features變量中。為了存儲每個圖像的類標簽,創(chuàng)建另一個名為outputs的NumPy數(shù)組。apple的類標簽為0,lemon為1,mango為2,raspberry為3。
通過代碼操作,使該數(shù)組在根目錄中運行,其中有4個文件夾根據(jù)名為fruits的列表中列出的水果名稱命名。該數(shù)組遍歷所有文件夾中的所有圖像,從每個圖像中提取色調直方圖,為每個圖像分配一個類標簽,最后使用pickle庫保存提取的特征和類標簽(也可以使用NumPy來保存生成的NumPy數(shù)組而不是pickle)。
從所有圖像中提取特征的Python代碼如下所示
import numpy
import skimage.io, skimage.color, skimage.feature
import os
import pickle
fruits = ["apple", "raspberry", "mango", "lemon"]
#492+490+490+490=1,962
dataset_features = numpy.zeros(shape=(1962, 360))
outputs = numpy.zeros(shape=(1962))
idx = 0
class_label = 0
for?fruit_dir?in?fruits:
? curr_dir = os.path.join(os.path.sep, fruit_dir)
? all_imgs = os.listdir(os.getcwd()+curr_dir)
??for?img_file?in?all_imgs:? fruit_data=skimage.io.imread(fname=os.getcwd()+curr_dir+img_file, as_grey=False)
?fruit_data_hsv=skimage.color.rgb2hsv(rgb=fruit_data)
????hist?=?numpy.histogram(a=fruit_data_hsv[:,?:,?0],?bins=360)
????dataset_features[idx,?:]?=?hist[0]
??? outputs[idx] = class_label
??? idx = idx + 1
? class_label = class_label + 1
with?open("dataset_features.pkl",?"wb")?as?f:
? pickle.dump("dataset_features.pkl", f)
with?open("outputs.pkl",?"wb")?as?f:
pickle.dump(outputs, f)
現(xiàn)在,用360個元素的特征向量來表示每個圖像。過濾這些元素是為了保留最相關的元素以區(qū)分4個類。減少的特征向量長度是102而不是360。使用更少的元素能夠更快地完成之前的操作。
dataset_features變量大小為1962x102。至此,相關數(shù)據(jù)(功能和類標簽)已準備就緒。接下來是使用Numpy實現(xiàn)神經(jīng)網(wǎng)絡構建(ANN)。
2
人工神經(jīng)網(wǎng)絡構建(ANN)
下圖展示了目標ANN結構。輸入層有102個數(shù)據(jù),2個隱藏層分別有150和60個神經(jīng)元,輸出層有4項(每個水果分類各一項)。
每個層的輸入向量乘以(矩陣乘法)權重矩陣,連接到下一層產(chǎn)生輸出向量。
這樣的輸出向量再次乘以權重矩陣,連接到下一層。該過程不斷重復,直到到達輸出層。矩陣乘法的總結如下圖所示。
大小為1×102的輸入向量乘以大小為102×150的第一個隱藏層的權重矩陣(矩陣乘法),得到輸出矩陣為1×150。然后將該輸出矩陣用作第二層隱藏層的輸入,乘以大小為150×60的權重矩陣,得到輸出矩陣1×60。
最后,將該輸出矩陣乘以60×4的權重矩陣,最終得到結果為1×4。這個結果向量中的每個元素都指向一個輸出類。輸入樣本按照得分最高的類別進行標記。
上述操作過程的Python代碼如下所示
import numpy
import pickle
def?sigmiod(inpt):
? return 1.0 / (1 + numpy.exp(-1 * inpt))
f = open("dataset_features.pkl", "rb")
data_inputs2 = pickle.load(f)
f.close()
features_STDs = numpy.std(a=data_inputs2, axis=0)
data_inputs?=?data_inputs2[:,?features_STDs?>?50]
f = open("outputs.pkl", "rb")
data_outputs = pickle.load(f)
f.close()
HL1_neurons = 150
input_HL1_weights = numpy.random.uniform(low=-0.1, high=0.1,
??? size=(data_inputs.shape[1], HL1_neurons))
HL2_neurons = 60
HL1_HL2_weights = numpy.random.uniform(low=-0.1, high=0.1,
??? size=(HL1_neurons, HL2_neurons))
output_neurons = 4
HL2_output_weights = numpy.random.uniform(low=-0.1, high=0.1,
??? size=(HL2_neurons, output_neurons))
H1_outputs?=?numpy.matmul(a=data_inputs[0,?:],?b=input_HL1_weights)
H1_outputs = sigmoid(H1_outputs)
H2_outputs = numpy.matmul(a=H1_outputs, b=HL1_HL2_weights)
H2_outputs = sigmoid(H2_outputs)
out_otuputs = numpy.matmul(a=H2_outputs, b=HL2_output_weights)
predicted_label = numpy.where(out_otuputs == numpy.max(out_otuputs))[0][0]
print("Predicted?class?:?",?predicted_label)
讀取先前保存的特征及輸出標簽,并過濾特征之后,應定義各層的權重矩陣,隨機賦予它們-0.1到0.1的值。例如,變量“input_HL1_weights”表示輸入層和第一隱藏層之間的權重矩陣,根據(jù)特征元素的數(shù)量和隱藏層中神經(jīng)元的數(shù)量來定義矩陣的大小。創(chuàng)建權重矩陣之后的下一步是應用矩陣乘法。
例如,變量“H1_outputs”代表給定樣本的特征向量乘以輸入層和第一隱藏層之間的權重矩陣所得到的輸出。
通常來說,激活函數(shù)應用于每個隱藏層的輸出,在輸入和輸出之間創(chuàng)建非線性關系。例如,sigmoid激活函數(shù)可以用于矩陣乘法的輸出。
在輸出層的輸出完成后,可以開始進行預測。預測的類標簽保存在“predict_label”變量中。對每個輸入樣本重復上述步驟。
適用于所有樣本的完整代碼如下所示
import numpy
import pickle
def?sigmoid(inpt):
? return 1.0 / (1 + numpy.exp(-1 * inpt))
def?relu(inpt):
? result = inpt
? result[inpt < 0] = 0
? return result
def?update_weights(weights,?learning_rate):
? new_weights = weights - learning_rate * weights
? return new_weights
def?train_network(num_iterations,?weights,?data_inputs,?data_outputs,?learning_rate,?activation="relu"):
??for?iteration?in?range(num_iterations):
??? print("Itreation ", iteration)
????for?sample_idx?in?range(data_inputs.shape[0]):
??????r1?=?data_inputs[sample_idx,?:]
??????for?idx?in?range(len(weights)?-?1):
?????? curr_weights = weights[idx]
?????? r1 = numpy.matmul(a=r1, b=curr_weights)
???????if?activation?==?"relu":
???????? r1 = relu(r1)
???????elif?activation?==?"sigmoid":
???????? r1 = sigmoid(r1)
??? curr_weights = weights[-1]
??? r1 = numpy.matmul(a=r1, b=curr_weights)
??? predicted_label = numpy.where(r1 == numpy.max(r1))[0][0]
??? desired_label = data_outputs[sample_idx]
????if?predicted_label?!=?desired_label:
????? weights = update_weights(weights,
??????? learning_rate=0.001)
? return weights
def?predict_outputs(weights,?data_inputs,?activation="relu"):
? predictions = numpy.zeros(shape=(data_inputs.shape[0]))
??for?sample_idx?in?range(data_inputs.shape[0]):
????r1?=?data_inputs[sample_idx,?:]
??????for?curr_weights?in?weights:
??????? r1 = numpy.matmul(a=r1, b=curr_weights)
??????if?activation?==?"relu":
??????? r1 = relu(r1)
??????elif?activation?==?"sigmoid":
??????? r1 = sigmoid(r1)
??? predicted_label = numpy.where(r1 == numpy.max(r1))[0][0]
??? predictions[sample_idx] = predicted_label
? return predictions
f = open("dataset_features.pkl", "rb")
data_inputs2 = pickle.load(f)
f.close()
features_STDs = numpy.std(a=data_inputs2, axis=0)
data_inputs?=?data_inputs2[:,?features_STDs?>?50]
f = open("outputs.pkl", "rb")
data_outputs = pickle.load(f)
f.close()
HL1_neurons = 150
input_HL1_weights=numpy.random.uniform(low=-0.1, high=0.1,
size=(data_inputs.shape[1], HL1_neurons))
HL2_neurons = 60
HL1_HL2_weights=numpy.random.uniform(low=-0.1, high=0.1,
size=(HL1_neurons, HL2_neurons))
output_neurons = 4
HL2_output_weights=numpy.random.uniform(low=-0.1, high=0.1,
size=(HL2_neurons, output_neurons))
weights = numpy.array([input_HL1_weights,
? HL1_HL2_weights,
? HL2_output_weights])
weights = train_network(num_iterations=10,
? weights=weights,
? data_inputs=data_inputs,
? data_outputs=data_outputs,
? learning_rate=0.01,
? activation="relu")
predictions = predict_outputs(weights, data_inputs)
num_flase?=?numpy.where(predictions?!=?data_outputs)[0]
print("num_flase ", num_flase.size)
“權重”變量包含整個網(wǎng)絡的所有權重。基于每個權重矩陣的大小,可以實現(xiàn)動態(tài)構建網(wǎng)絡結構。例如,如果“input_HL1_weights”變量的大小是102x80,那么我們可以推斷出第一個隱藏層有80個神經(jīng)元。
“train_network”是整個過程的核心功能,因為它通過循環(huán)遍歷所有樣本來構建網(wǎng)絡。每個樣本都要經(jīng)過迭代、特征提取、輸出標簽、權重矩陣乘法、學習速率和激活函數(shù)等過程。激活函數(shù)有兩種選擇,ReLU或者sigmoid。ReLU是一個閾值函數(shù),只要它大于零,就會返回相同的輸入。否則,ReLU歸零。
如果網(wǎng)絡對給定樣本做出錯誤預測,則使用“update_weights”函數(shù)更新權重。根據(jù)學習速率更新權重,準確率不超過45%。為了更高的準確性,可以使用優(yōu)化算法來更新權重。例如,可以在scikit-learn庫的ANN操作中找到梯度下降技術。
原文網(wǎng)址:
https://www.kdnuggets.com/2019/02/artificial-neural-network-implementation-using-numpy-and-image-classification.html
推薦閱讀:
動態(tài)不確定因果圖(DUCG)的起源與發(fā)展
使用離散時間貝葉斯網(wǎng)絡(DTBN)實現(xiàn)GO-FLOW方法對共因失效問題的建模
GO法—以成功為導向的系統(tǒng)可靠性建模方法
基于有環(huán)貝葉斯網(wǎng)的改進GO法及其在閉環(huán)反饋系統(tǒng)可靠性分析中的應用
融合FMECA的改進GO法
驚!每天都要坐的汽車,最可靠的竟然是他……
一種分析和評估系統(tǒng)可靠性的新方法
多波次連續(xù)密集任務條件下的集群選擇性維修決策方法
緬懷楊為民老師,重讀《Reliability System Engineering-Theory and Practice》
新型自修復互連線的制備與應用
模型化可視化故障模式及影響分析方法-故障鏈
IGBT功率器件及模塊熱管理(附全文)
使用Gamma過程實現(xiàn)隨機放電鋰離子電池剩余壽命在線預測
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的numpy找到矩阵中不同元素的种类_基于NumPy和图像分类的人工神经网络构建的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: a表两个字段都与b表一个字段关联_数据库
- 下一篇: com 组件调用不起来_一文读懂Eure