OpenCV3-Python人工神经网络(ANN)简介
人工神经网络 (ANN,Artificial Neural Network)采取的实现方法是将任务分派给许多神经元(也称为节点),且每一个神经元都能够“近似”生成输入函数。所谓的“近似”是指用一个比较简单的函数去表示一个更复杂的函数。此外,如果神经元能够以一定精度近似非线性函数,该网络通常可认为是神经网络。
1. 神经元与感知机
感知机的概念可以追溯到20世纪50年代,感知机是一个可接受许多输入并输出一个值的函数。
每个输入都有一个与之相关联的权重,用来表示函数中输入的重要特性。如,Sigmoid函数:
Sigmoid函数用来指示该函数输出的值为0或1,判断条件是一个阈值,如果输入的权重和大于某一个阈值,感知器会输出1,否则为0。
2. 人工神经网络
如图所示,神经网络有三个不同的层:输入层、隐藏层(或中间层)和输出层。通常一个隐藏层就能够解决现实生活中的大部分问题。
(1)输入层
输入层定义了网络的输入数目。例如,创建一个人工神经网络,使其根据给定的动物属性描述来判断是哪种动物。这些动物属性分别为体重、长度和牙齿。因此,对应这三个属性,网络就需要三个输入节点。
(2)输出层
输出层数据与定义的类别数相同。比如,用来进行动物分类的网络,若已知要分类的动物为狗、秃鹰、海豚和龙,则任意设定输出层的数目为4;如果输入的动物非这些类别,则网络将返回与这4种动物最相似的类别。
(3)隐藏层
隐藏层包含感知器,如前所述,大部分问题只需要一个隐藏层。如何确定隐藏层的神经元数?在实际应用中,并没有严格准则,通常使用经验方法。
3. 创建ANN
创建ANN最常见的规则:
(1)隐藏层神经元数应该介于输入层的大小与输出层大小之间。根据经验,如果输入层大小与输出层的大小相差很大,则隐藏层的神经元数目最好与输出层数接近。
(2)对于相对较小的输入层,隐藏层神经元数最好是输入层和输出层大小之和的三分之二,或者小于输入层大小的两倍。
除此之外,需要注意一个重要现象:过拟合(overfitting)。当待分类训练数据提供的信息没有什么意义,而隐藏层又含有太多信息时就会发生过拟合。
(1)程序示例:
import cv2 import numpy as np from random import randint #通过调用OpenCV函数创建ANN animals_net = cv2.ml.ANN_MLP_create() #ANN_MLP_RPROP和ANN_MLP_BACKPROP都是反向传播算法,此处设置相应的拓扑结构 animals_net.setLayerSizes(np.array([3, 6, 4])) animals_net.setTrainMethod(cv2.ml.ANN_MLP_RPROP | cv2.ml.ANN_MLP_UPDATE_WEIGHTS) animals_net.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM) #指定ANN的终止条件 animals_net.setTermCriteria(( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )) """Input arrays weight, length, teeth """ """Output arrays dog, eagle, dolphin and dragon """ def dog_sample(): return [randint(10, 20), 1, randint(38, 42)] def dog_class(): return [1, 0, 0, 0] def condor_sample(): return [randint(3,10), randint(3,5), 0] def condor_class(): return [0, 1, 0, 0] def dolphin_sample(): return [randint(30, 190), randint(5, 15), randint(80, 100)] def dolphin_class(): return [0, 0, 1, 0] def dragon_sample(): return [randint(1200, 1800), randint(30, 40), randint(160, 180)] def dragon_class(): return [0, 0, 0, 1] def record(sample, classification): return (np.array([sample], dtype=np.float32), np.array([classification], dtype=np.float32)) ''' 为了提高精度,大多数ANN会迭代多个周期;一些常见的ANN示例,会对数据进行数百次迭代。 ''' records = [] RECORDS = 5000 for x in range(0, RECORDS): records.append(record(dog_sample(), dog_class())) records.append(record(condor_sample(), condor_class())) records.append(record(dolphin_sample(), dolphin_class())) records.append(record(dragon_sample(), dragon_class())) EPOCHS = 2 for e in range(0, EPOCHS): print ("Epoch %d:" % e) for t, c in records: animals_net.train(t, cv2.ml.ROW_SAMPLE, c) TESTS = 100 dog_results = 0 for x in range(0, TESTS): clas = int(animals_net.predict(np.array([dog_sample()], dtype=np.float32))[0]) print ("class: %d" % clas) if (clas) == 0: dog_results += 1 condor_results = 0 for x in range(0, TESTS): clas = int(animals_net.predict(np.array([condor_sample()], dtype=np.float32))[0]) print ("class: %d" % clas) if (clas) == 1: condor_results += 1 dolphin_results = 0 for x in range(0, TESTS): clas = int(animals_net.predict(np.array([dolphin_sample()], dtype=np.float32))[0]) print ("class: %d" % clas) if (clas) == 2: dolphin_results += 1 dragon_results = 0 for x in range(0, TESTS): clas = int(animals_net.predict(np.array([dragon_sample()], dtype=np.float32))[0]) print ("class: %d" % clas) if (clas) == 3: dragon_results += 1 print ("Dog accuracy: %f%%" % (dog_results)) print ("condor accuracy: %f%%" % (condor_results)) print ("dolphin accuracy: %f%%" % (dolphin_results)) print ("dragon accuracy: %f%%" % (dragon_results))
(2)运行结果: