numpy找到矩阵中不同元素的种类_基于NumPy和图像分类的人工神经网络构建
基于NumPy和圖像分類(lèi)的人工神經(jīng)網(wǎng)絡(luò)構(gòu)建
本文利用NumPy系統(tǒng)在Python中構(gòu)建人工神經(jīng)網(wǎng)絡(luò),以便為Fruits360數(shù)據(jù)集執(zhí)行圖像分類(lèi)應(yīng)用程序。
本文提及的所有內(nèi)容(即圖像和源代碼,不包括Fruits360的圖片)均來(lái)自于Ahmed Fawzy Gad 著作《Practical Computer Vision Applications Using Deep Learning with CNNs》。
本書(shū)可以在以下網(wǎng)址查閱:
https://springer.com/us/book/9781484241660
本文中使用的源代碼可以在以下網(wǎng)址查閱:
https://github.com/ahmedfgad/NumPyANN
Fruits360數(shù)據(jù)集中有60類(lèi)水果,如蘋(píng)果、番石榴、鱷梨、香蕉、櫻桃、棗、獼猴桃、桃子等。為了簡(jiǎn)明扼要,本文只選定了四種分類(lèi),分別是蘋(píng)果、檸檬、芒果和覆盆子。每種分類(lèi)大約有491個(gè)圖像用于操作,162個(gè)圖像用于測(cè)試。圖像大小為100x100像素。
1
特征提取
首先,選取一組合適的特征來(lái)保證分類(lèi)的準(zhǔn)確性。如下圖所示的4個(gè)類(lèi)別的樣本圖像,這些水果的顏色不同,因此顏色特征適合用于特征提取的工作任務(wù)。
樣本圖像.jpg
RGB顏色空間不會(huì)將顏色信息與其他類(lèi)型的信息(如亮度)區(qū)分開(kāi)。因此,如果用RGB來(lái)表示圖像,會(huì)有3個(gè)通道參與到計(jì)算中。出于此原因,最好使用將顏色信息隔離成單個(gè)通道(如HSV)的顏色空間。在這種情況下,顏色通道即是色調(diào)通道(H)。下圖顯示了之前呈現(xiàn)的4個(gè)樣本的色調(diào)通道。我們可以注意到每個(gè)圖像的色調(diào)值與其他圖像的不同之處。
樣本色調(diào)通道.jpg
色調(diào)通道大小依舊為100x100。如果將整個(gè)通道應(yīng)用于ANN,則輸入層將具有10,000個(gè)神經(jīng)元,網(wǎng)絡(luò)數(shù)據(jù)量過(guò)大。為了減少使用的數(shù)據(jù)量,我們可以使用直方圖來(lái)表示色調(diào)通道。直方圖具有360個(gè)區(qū)間,反映色調(diào)值的數(shù)據(jù)。
下圖是4個(gè)樣本圖像的直方圖,每種水果的色調(diào)值都落在直方圖的某些特定區(qū)間中。與使用RGB顏色空間中的任何通道相比,不同類(lèi)別之間的重疊較少。例如,芒果的色調(diào)在直方圖中的區(qū)間為90~110,而蘋(píng)果的色調(diào)區(qū)間則為0~10。每個(gè)種類(lèi)之間的邊距減少了分類(lèi)的模糊性,從而提高了預(yù)測(cè)的準(zhǔn)確性。
樣本圖像直方圖.jpg
以下是根據(jù)4個(gè)圖像計(jì)算色調(diào)通道直方圖的代碼
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
通過(guò)循環(huán)使用4個(gè)圖像類(lèi)中的所有圖像,我們可以從所有圖像中提取特征(參見(jiàn)下面的代碼)。根據(jù)4個(gè)分類(lèi)中的圖像數(shù)量(1962)和從每個(gè)圖像中提取的特征向量長(zhǎng)度(360),創(chuàng)建NumPy零數(shù)組并將其保存在dataset_features變量中。為了存儲(chǔ)每個(gè)圖像的類(lèi)標(biāo)簽,創(chuàng)建另一個(gè)名為outputs的NumPy數(shù)組。apple的類(lèi)標(biāo)簽為0,lemon為1,mango為2,raspberry為3。
通過(guò)代碼操作,使該數(shù)組在根目錄中運(yùn)行,其中有4個(gè)文件夾根據(jù)名為fruits的列表中列出的水果名稱(chēng)命名。該數(shù)組遍歷所有文件夾中的所有圖像,從每個(gè)圖像中提取色調(diào)直方圖,為每個(gè)圖像分配一個(gè)類(lèi)標(biāo)簽,最后使用pickle庫(kù)保存提取的特征和類(lèi)標(biāo)簽(也可以使用NumPy來(lái)保存生成的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個(gè)元素的特征向量來(lái)表示每個(gè)圖像。過(guò)濾這些元素是為了保留最相關(guān)的元素以區(qū)分4個(gè)類(lèi)。減少的特征向量長(zhǎng)度是102而不是360。使用更少的元素能夠更快地完成之前的操作。
dataset_features變量大小為1962x102。至此,相關(guān)數(shù)據(jù)(功能和類(lèi)標(biāo)簽)已準(zhǔn)備就緒。接下來(lái)是使用Numpy實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)構(gòu)建(ANN)。
2
人工神經(jīng)網(wǎng)絡(luò)構(gòu)建(ANN)
下圖展示了目標(biāo)ANN結(jié)構(gòu)。輸入層有102個(gè)數(shù)據(jù),2個(gè)隱藏層分別有150和60個(gè)神經(jīng)元,輸出層有4項(xiàng)(每個(gè)水果分類(lèi)各一項(xiàng))。
每個(gè)層的輸入向量乘以(矩陣乘法)權(quán)重矩陣,連接到下一層產(chǎn)生輸出向量。
這樣的輸出向量再次乘以權(quán)重矩陣,連接到下一層。該過(guò)程不斷重復(fù),直到到達(dá)輸出層。矩陣乘法的總結(jié)如下圖所示。
大小為1×102的輸入向量乘以大小為102×150的第一個(gè)隱藏層的權(quán)重矩陣(矩陣乘法),得到輸出矩陣為1×150。然后將該輸出矩陣用作第二層隱藏層的輸入,乘以大小為150×60的權(quán)重矩陣,得到輸出矩陣1×60。
最后,將該輸出矩陣乘以60×4的權(quán)重矩陣,最終得到結(jié)果為1×4。這個(gè)結(jié)果向量中的每個(gè)元素都指向一個(gè)輸出類(lèi)。輸入樣本按照得分最高的類(lèi)別進(jìn)行標(biāo)記。
上述操作過(guò)程的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)
讀取先前保存的特征及輸出標(biāo)簽,并過(guò)濾特征之后,應(yīng)定義各層的權(quán)重矩陣,隨機(jī)賦予它們-0.1到0.1的值。例如,變量“input_HL1_weights”表示輸入層和第一隱藏層之間的權(quán)重矩陣,根據(jù)特征元素的數(shù)量和隱藏層中神經(jīng)元的數(shù)量來(lái)定義矩陣的大小。創(chuàng)建權(quán)重矩陣之后的下一步是應(yīng)用矩陣乘法。
例如,變量“H1_outputs”代表給定樣本的特征向量乘以輸入層和第一隱藏層之間的權(quán)重矩陣所得到的輸出。
通常來(lái)說(shuō),激活函數(shù)應(yīng)用于每個(gè)隱藏層的輸出,在輸入和輸出之間創(chuàng)建非線性關(guān)系。例如,sigmoid激活函數(shù)可以用于矩陣乘法的輸出。
在輸出層的輸出完成后,可以開(kāi)始進(jìn)行預(yù)測(cè)。預(yù)測(cè)的類(lèi)標(biāo)簽保存在“predict_label”變量中。對(duì)每個(gè)輸入樣本重復(fù)上述步驟。
適用于所有樣本的完整代碼如下所示
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)
“權(quán)重”變量包含整個(gè)網(wǎng)絡(luò)的所有權(quán)重。基于每個(gè)權(quán)重矩陣的大小,可以實(shí)現(xiàn)動(dòng)態(tài)構(gòu)建網(wǎng)絡(luò)結(jié)構(gòu)。例如,如果“input_HL1_weights”變量的大小是102x80,那么我們可以推斷出第一個(gè)隱藏層有80個(gè)神經(jīng)元。
“train_network”是整個(gè)過(guò)程的核心功能,因?yàn)樗ㄟ^(guò)循環(huán)遍歷所有樣本來(lái)構(gòu)建網(wǎng)絡(luò)。每個(gè)樣本都要經(jīng)過(guò)迭代、特征提取、輸出標(biāo)簽、權(quán)重矩陣乘法、學(xué)習(xí)速率和激活函數(shù)等過(guò)程。激活函數(shù)有兩種選擇,ReLU或者sigmoid。ReLU是一個(gè)閾值函數(shù),只要它大于零,就會(huì)返回相同的輸入。否則,ReLU歸零。
如果網(wǎng)絡(luò)對(duì)給定樣本做出錯(cuò)誤預(yù)測(cè),則使用“update_weights”函數(shù)更新權(quán)重。根據(jù)學(xué)習(xí)速率更新權(quán)重,準(zhǔn)確率不超過(guò)45%。為了更高的準(zhǔn)確性,可以使用優(yōu)化算法來(lái)更新權(quán)重。例如,可以在scikit-learn庫(kù)的ANN操作中找到梯度下降技術(shù)。
原文網(wǎng)址:
https://www.kdnuggets.com/2019/02/artificial-neural-network-implementation-using-numpy-and-image-classification.html
推薦閱讀:
動(dòng)態(tài)不確定因果圖(DUCG)的起源與發(fā)展
使用離散時(shí)間貝葉斯網(wǎng)絡(luò)(DTBN)實(shí)現(xiàn)GO-FLOW方法對(duì)共因失效問(wèn)題的建模
GO法—以成功為導(dǎo)向的系統(tǒng)可靠性建模方法
基于有環(huán)貝葉斯網(wǎng)的改進(jìn)GO法及其在閉環(huán)反饋系統(tǒng)可靠性分析中的應(yīng)用
融合FMECA的改進(jìn)GO法
驚!每天都要坐的汽車(chē),最可靠的竟然是他……
一種分析和評(píng)估系統(tǒng)可靠性的新方法
多波次連續(xù)密集任務(wù)條件下的集群選擇性維修決策方法
緬懷楊為民老師,重讀《Reliability System Engineering-Theory and Practice》
新型自修復(fù)互連線的制備與應(yīng)用
模型化可視化故障模式及影響分析方法-故障鏈
IGBT功率器件及模塊熱管理(附全文)
使用Gamma過(guò)程實(shí)現(xiàn)隨機(jī)放電鋰離子電池剩余壽命在線預(yù)測(cè)
與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的numpy找到矩阵中不同元素的种类_基于NumPy和图像分类的人工神经网络构建的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: a表两个字段都与b表一个字段关联_数据库
- 下一篇: c++矩阵作为函数输入变量_C++实现矩