基于NumPy和图像分类的人工神经网络构建

本文利用NumPy系统在Python中构建人工神经网络,以便为Fruits360数据集执行图像分类应用程序。

本文提及的所有内容(即图像和源代码,不包括Fruits360的图片)均来自于Ahmed Fawzy Gad 著作《Practical Computer Vision Applications Using Deep Learning with CNNs》。

本书可以在以下网址查阅:

https://springer.com/us/book/9781484241660

本文中使用的源代码可以在以下网址查阅:

https://github.com/ahmedfgad/NumPyANN

Fruits360数据集中有60类水果,如苹果、番石榴、鳄梨、香蕉、樱桃、枣、猕猴桃、桃子等。为了简明扼要,本文只选定了四种分类,分别是苹果、柠檬、芒果和覆盆子。每种分类大约有491个图像用于操作,162个图像用于测试。图像大小为100x100像素。

1

特征提取

首先,选取一组合适的特征来保证分类的准确性。如下图所示的4个类别的样本图像,这些水果的颜色不同,因此颜色特征适合用于特征提取的工作任务。

样本图像.jpg

RGB颜色空间不会将颜色信息与其他类型的信息(如亮度)区分开。因此,如果用RGB来表示图像,会有3个通道参与到计算中。出于此原因,最好使用将颜色信息隔离成单个通道(如HSV)的颜色空间。在这种情况下,颜色通道即是色调通道(H)。下图显示了之前呈现的4个样本的色调通道。我们可以注意到每个图像的色调值与其他图像的不同之处。

样本色调通道.jpg

色调通道大小依旧为100x100。如果将整个通道应用于ANN,则输入层将具有10,000个神经元,网络数据量过大。为了减少使用的数据量,我们可以使用直方图来表示色调通道。直方图具有360个区间,反映色调值的数据。

下图是4个样本图像的直方图,每种水果的色调值都落在直方图的某些特定区间中。与使用RGB颜色空间中的任何通道相比,不同类别之间的重叠较少。例如,芒果的色调在直方图中的区间为90~110,而苹果的色调区间则为0~10。每个种类之间的边距减少了分类的模糊性,从而提高了预测的准确性。

样本图像直方图.jpg

以下是根据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

通过循环使用4个图像类中的所有图像,我们可以从所有图像中提取特征(参见下面的代码)。根据4个分类中的图像数量(1962)和从每个图像中提取的特征向量长度(360),创建NumPy零数组并将其保存在dataset_features变量中。为了存储每个图像的类标签,创建另一个名为outputs的NumPy数组。apple的类标签为0,lemon为1,mango为2,raspberry为3。

通过代码操作,使该数组在根目录中运行,其中有4个文件夹根据名为fruits的列表中列出的水果名称命名。该数组遍历所有文件夹中的所有图像,从每个图像中提取色调直方图,为每个图像分配一个类标签,最后使用pickle库保存提取的特征和类标签(也可以使用NumPy来保存生成的NumPy数组而不是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)

现在,用360个元素的特征向量来表示每个图像。过滤这些元素是为了保留最相关的元素以区分4个类。减少的特征向量长度是102而不是360。使用更少的元素能够更快地完成之前的操作。

dataset_features变量大小为1962x102。至此,相关数据(功能和类标签)已准备就绪。接下来是使用Numpy实现神经网络构建(ANN)。

2

人工神经网络构建(ANN)

下图展示了目标ANN结构。输入层有102个数据,2个隐藏层分别有150和60个神经元,输出层有4项(每个水果分类各一项)。

每个层的输入向量乘以(矩阵乘法)权重矩阵,连接到下一层产生输出向量。

这样的输出向量再次乘以权重矩阵,连接到下一层。该过程不断重复,直到到达输出层。矩阵乘法的总结如下图所示。

大小为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”表示输入层和第一隐藏层之间的权重矩阵,根据特征元素的数量和隐藏层中神经元的数量来定义矩阵的大小。创建权重矩阵之后的下一步是应用矩阵乘法。

例如,变量“H1_outputs”代表给定样本的特征向量乘以输入层和第一隐藏层之间的权重矩阵所得到的输出。

通常来说,激活函数应用于每个隐藏层的输出,在输入和输出之间创建非线性关系。例如,sigmoid激活函数可以用于矩阵乘法的输出。

在输出层的输出完成后,可以开始进行预测。预测的类标签保存在“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)

“权重”变量包含整个网络的所有权重。基于每个权重矩阵的大小,可以实现动态构建网络结构。例如,如果“input_HL1_weights”变量的大小是102x80,那么我们可以推断出第一个隐藏层有80个神经元。

“train_network”是整个过程的核心功能,因为它通过循环遍历所有样本来构建网络。每个样本都要经过迭代、特征提取、输出标签、权重矩阵乘法、学习速率和激活函数等过程。激活函数有两种选择,ReLU或者sigmoid。ReLU是一个阈值函数,只要它大于零,就会返回相同的输入。否则,ReLU归零。

如果网络对给定样本做出错误预测,则使用“update_weights”函数更新权重。根据学习速率更新权重,准确率不超过45%。为了更高的准确性,可以使用优化算法来更新权重。例如,可以在scikit-learn库的ANN操作中找到梯度下降技术。

原文网址:

https://www.kdnuggets.com/2019/02/artificial-neural-network-implementation-using-numpy-and-image-classification.html

推荐阅读:

动态不确定因果图(DUCG)的起源与发展

使用离散时间贝叶斯网络(DTBN)实现GO-FLOW方法对共因失效问题的建模

GO法—以成功为导向的系统可靠性建模方法

基于有环贝叶斯网的改进GO法及其在闭环反馈系统可靠性分析中的应用

融合FMECA的改进GO法

惊!每天都要坐的汽车,最可靠的竟然是他……

一种分析和评估系统可靠性的新方法

多波次连续密集任务条件下的集群选择性维修决策方法

缅怀杨为民老师,重读《Reliability System Engineering-Theory and Practice》

新型自修复互连线的制备与应用

模型化可视化故障模式及影响分析方法-故障链

IGBT功率器件及模块热管理(附全文)

使用Gamma过程实现随机放电锂离子电池剩余寿命在线预测

numpy找到矩阵中不同元素的种类_基于NumPy和图像分类的人工神经网络构建相关推荐

  1. 查找python矩阵中最大元素_找出矩阵中最大的元素

    当提示输入矩阵中的行数,然后提示输入这些行的元素时,我需要找到矩阵中最大的元素并返回其位置(行和列).在 例如,如果输入2行,如下所示: [1 3 7] [4 8 1] 最大元素的位置将是(1,1), ...

  2. python找出值为nan_Python Numpy:找到list中的np.nan值方法

    这个问题源于在训练机器学习的一个模型时,使用训练数据时提示prepare的数据中存在np.nan 报错信息如下: ValueError: np.nan is an invalid document, ...

  3. numpy找到数组中符合条件的数

    numpy找到数组中符合条件的数 import numpy as nparr = np.array([1, 1, 1, 134, 45, 3, 46, 45, 65, 3, 23424, 234, 1 ...

  4. 一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵

    题目描述: 一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积) 输入: 每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K 接下 ...

  5. matlab 连通域数量,【Matlab】找到矩阵中每个连通域的最小值

    [Matlab]找到矩阵中每个连通域的最小值 [Matlab]找到矩阵中每个连通域的最小值 连通域在我浅薄的图像处理知识中,一直是很神圣的存在.最近想在Matlab里实现的时候,发现竟然一个函数就解决 ...

  6. 矩阵乘法,矩阵中各元素对应相乘及其梯度计算;

    矩阵乘法:x=([x1,x2]) w=([w1,w2],[w3,w4]) torch.matmul(x,w)=([x1w1+x2w3,x1w2+x2+w4]) x.grad=(w1+w2,w3+w4) ...

  7. Matlab中矩阵的平方和矩阵中每个元素的平方

    设 t = [2 4 4 2] 则 >> t.^2 ans = 4 16 4 16 这里网上的似乎是错的,正确的应该是 ans = 4 16 16 4 而 >> t^2 ans ...

  8. 求矩阵中所有元素的最大值

    题目信息: 有一个3 * 4的矩阵,求矩阵中所有元素的最大值.有函数处理. 代码如下: #include <iostream> using namespace std; int main( ...

  9. c语言 输入n*n矩阵,C语言函数 编程输入一个n*n矩阵中各元素的值,找出两条对角线上的元素之和...

    题目: C语言函数 编程输入一个n*n矩阵中各元素的值,找出两条对角线上的元素之和 用函数怎么写 解答: #include #define N 5 void main() { \x09int matr ...

最新文章

  1. 2018五大人工智能趋势,你知道多少?
  2. [实变函数]4.4 依测度收敛
  3. TCP/IP总结(1)分层
  4. python中的wheel有什么用_什么是Python Wheels?为什么要学Python Wheels
  5. 政府门户升级改版要点
  6. 抢占乡镇渠道 中国手机厂商比苹果有经验
  7. mysql权限层级体系_MySQL权限体系介绍
  8. 使用Stack进行递归
  9. unet网络python代码详解_python网络编程详解
  10. 深入剖析Android音频之AudioPolicyService
  11. tomcat是一个应用服务器
  12. 2050:技术未必会使我们摆脱愚昧,有时正相反(下)
  13. Vue 电商管理系统
  14. 网站做渗透测试服务的步骤
  15. office2010卸载不掉解决办法
  16. 【波导】——理解群速度和相速度
  17. VOIP技术连载之一 VOIP简介
  18. Cesium场景导出为图片功能
  19. 指纹登录 TouchID FaceID
  20. 从 ADNI 的 XML 文件中读取临床信息

热门文章

  1. [转载]模糊系统:挑战与机遇并存——十年研究之感悟 王立新
  2. 转载:介绍几本专业的书籍,一起学习
  3. CCF OJ 1113-括号匹配[栈]
  4. JZOJ__Day 5:【普及模拟】num
  5. python机器学习库_Python机器学习库 Top 10,你值得拥有!
  6. 微信小程序中嵌套html_微信小程序:web-view嵌套H5实现微信支付功能解决方案及填坑...
  7. 项目进度计划表_十大项目管理工具模版~
  8. 第五章 初始jQuery
  9. Nginx+tomcat集群的session共享问题
  10. 网络流24题 魔术球问题