没品星人
没品星人
6月前 · 7 人阅读

以神经网络为基础的深度学习,它最大的作用就是让计算机能求解那些没有明确规则或定义的问题,例如你根本无法制定出一系列明确的规则或步骤去让计算机识别一幅图像中的内容是什么,人工智能最大的强项就是让计算机能处理那些模糊不清,几乎无法用明确的规则或步骤来描述的问题。

一个受过大量数据训练的神经网络,给定领域内的图像表示什么内容,此时它就像一个黑盒子,把数据从一端输入,然后结果自动从另一端输出,你根本不知道他内部的运行机制。如果我们只在乎得到正确的结果,那么无论神经网络的内部机理如何复杂,我们都无需关心。如果我们想知道神经网络是如何学习输入数据,并总结出某种特定规律来,那么我们现在能知道的,就是网络会不断的调整链路上权值。

由于神经网络模拟的是大脑思维方式,人的大脑有意识,那神经网络是否也有自己的”意识“呢?原来神经网络的工作流程如下:
数字图片 -> 神经网络 -> 数字
如果我们反其道而行之,给定一个数字,让神经网络把该数字对应的”图片“给画出来,那么我们就可以窥探神经网络是如何通过自己的”意识“来认识这个世界了,也就是我们把上面流程改为:
数字图片<-神经网络<-数字
通过上面的逆流程,我们就可以大概了解世界在神经网络中的样子。
我们已经知道,神经网络得出的结果是先把输入信号与链路权重做乘机后求和,然后在对求和结果应用激活函数,所的到的结果就是神经节点输出的信号。反过来,我们拿到最终输出结果后,先做激活函数的逆运算,得到信号与权重的乘机和,然后再除以链路权重还原回各个信号分量,将这些信号分量合成一幅图像,我们就可以得知,神经网络是如何看待这个世界的。

我们知道网络节点的激活函数如下:

要把里面的x解出来,我们就需要下面的公式:

在python中,它对应的代码为scipy.special.logit(),于是利用这个公式,我们用如下代码把结果反解出对应的图片,相应的实现代码如下:

import scipy.special
import numpy

class  NeuralNetWork:
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        #初始化网络,设置输入层,中间层,和输出层节点数
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        
        #设置学习率
        self.lr = learningrate
        '''
        初始化权重矩阵,我们有两个权重矩阵,一个是wih表示输入层和中间层节点间链路权重形成的矩阵
        一个是who,表示中间层和输出层间链路权重形成的矩阵
        '''
        self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5
        self.who = numpy.random.rand(self.onodes, self.hnodes) - 0.5
        
        self.activation_function = lambda x:scipy.special.expit(x)
        
        #设置激活函数的反函数
        self.inverse_activation_function = lambda x:scipy.special.logit(x)
        pass
    def  train(self, inputs_list, targets_list):
        #根据输入的训练数据更新节点链路权重
        '''
        把inputs_list, targets_list转换成numpy支持的二维矩阵
        .T表示做矩阵的转置
        '''
        inputs = numpy.array(inputs_list, ndmin=2).T
        targets = numpy.array(targets_list, ndmin=2).T
        #计算信号经过输入层后产生的信号量
        hidden_inputs = numpy.dot(self.wih, inputs)
        #中间层神经元对输入的信号做激活函数后得到输出信号
        hidden_outputs = self.activation_function(hidden_inputs)
        #输出层接收来自中间层的信号量
        final_inputs = numpy.dot(self.who, hidden_outputs)
        #输出层对信号量进行激活函数后得到最终输出信号
        final_outputs = self.activation_function(final_inputs)
        
        #计算误差
        output_errors = targets - final_outputs
        hidden_errors = numpy.dot(self.who.T, output_errors)
        #根据误差计算链路权重的更新量,然后把更新加到原来链路权重上
        self.who += self.lr * numpy.dot((output_errors * final_outputs *(1 - final_outputs)),
                                       numpy.transpose(hidden_outputs))
        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1 - hidden_outputs)),
                                       numpy.transpose(inputs))
        
        pass
    def  query(self, inputs):
        #根据输入数据计算并输出答案
        #计算中间层从输入层接收到的信号量
        hidden_inputs = numpy.dot(self.wih, inputs)
        #计算中间层经过激活函数后形成的输出信号量
        hidden_outputs = self.activation_function(hidden_inputs)
        #计算最外层接收到的信号量
        final_inputs = numpy.dot(self.who, hidden_outputs)
        #计算最外层神经元经过激活函数后输出的信号量
        final_outputs = self.activation_function(final_inputs)
        return final_outputs
    def backQuery(self, targets_list):
         # 将结果向量转置以便反解出输入信号量
        final_outputs = numpy.array(targets_list, ndmin=2).T
        
        # 通过激活函数的反函数得到输出层的输入信号
        final_inputs = self.inverse_activation_function(final_outputs)

        # 获取中间层的输出信号
        hidden_outputs = numpy.dot(self.who.T, final_inputs)
        # 将信号量圆整到0.01和0.98之间
        hidden_outputs -= numpy.min(hidden_outputs)
        hidden_outputs /= numpy.max(hidden_outputs)
        hidden_outputs *= 0.98
        hidden_outputs += 0.01
        
        #通过激活函数的反函数计算中间层获得的输入信号量
        hidden_inputs = self.inverse_activation_function(hidden_outputs)
        
        # 计算输入层的输出信号量
        inputs = numpy.dot(self.wih.T, hidden_inputs)
        # 将信号量圆整到0.01和0.98之间
        inputs -= numpy.min(inputs)
        inputs /= numpy.max(inputs)
        inputs *= 0.98
        inputs += 0.01
        #input对应的就是输入神经网络的图片像素数组
        return inputs
       

上面代码跟以前不一样之处就在于多了一个backQuery函数,它接收结果向量,让后反解出向量对应的输入图片,有了上面神经网络后,我们先对其进行训练,得到相应的神经元链路权重:

#初始化网络
input_nodes = 784
hidden_nodes = 100
output_nodes = 10
learning_rate = 0.3
n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate)
#读入训练数据
#open函数里的路径根据数据存储的路径来设定
training_data_file = open("/Users/chenyi/Documents/人工智能/mnist_train.csv")
trainning_data_list = training_data_file.readlines()
print(len(trainning_data_list))
training_data_file.close()
#加入epocs,设定网络的训练循环次数
epochs = 7
print("begin trainning")

for e in range(epochs):
    #把数据依靠','区分,并分别读入
    for record in trainning_data_list:
        all_values = record.split(',')
        inputs = (numpy.asfarray(all_values[1:]))/255.0 * 0.99 + 0.01
        #设置图片与数值的对应关系
        targets = numpy.zeros(output_nodes) + 0.01
        targets[int(all_values[0])] = 0.99
        n.train(inputs, targets)
   
        
print("trainning complete")

有了合适的链路权值后,我们构造一个结果向量,将它输入到网络中,让网络把它认为的向量对应的图像输出来:

label = 8
targets = numpy.zeros(output_nodes) + 0.01
targets[label] = 0.99
print(targets)
image_data = n.backQuery(targets)
#print(image_data.reshape(28,28))
matplotlib.pyplot.imshow(image_data.reshape(28,28), cmap="Greys", interpolation="None")

上面代码构造了一个数字8对应的结果向量,然后传入神经网络看看网络眼中的数字8是什么样子的,上面代码执行后结果如下:

没错,上面模糊一片的图案就是神经网络对数组8的理解,我们慢慢观察黑色部分,发觉它确实跟数字8有点像。这个图案让我想起了两千年前古希腊哲学家柏拉图提出一个叫”理型“的哲学概念,它的意思是说,每一个种类的事物,无论其外形如何变幻,他们本身都包含着一种超越时空,永恒不变的抽象属性。举个例子,给一个孩子看一只黑马的图片,然后让他看一只白马的图片,他很容易能认出那是马,也就是说不管黑马白马的外形差异如何,两只马都具备相同的理型叫做”马“,人正是因为感受到马的”理型“,所以不管马的形态如何变幻,人总能认出它是马来,也就是说所有的马都具备同一种抽象的超越时空,永恒不变的性质,正是这个性质将它与其他事物区分开来。

道可道,非常道。理型的概念就是”道可道“中的第一个道,也就是永恒不变的规律,通常情况下,”道“是很难用语言或某种显著方式进行表达的。神经网络通过计算大量的手写数字图片,通过计算抽取出了这些同一类数字图片的共性,这个共性其实就是柏拉图所说的理型,也就是所有手写的数字”8“,都蕴含着某种不变的性质,神经网络就是把这个性质抽取出来的方式,上面那张模糊的图案,可以认为是所有手写数字8的理型,网络读取的图片数量越大,其对理型的把握就越准确。

如此一来”非常道“似乎就不成立了,神经网络的结构以及链路上的权重,就可以用来对”道“进行描述,或者说一切手写数字的”理型“可以用现在我们训练的神经网络来描述。

以神经网络为基础的深度学习模仿人的意识,在一定程度上也跟人的思维哲学有了交互之处,这就是技术发展与人文思想的交相辉映吧。至此我们对神经网络的基本原理说明就告一段落,从下一章开始,我们进入神经网络的实际应用层面。

更详细的讲解和代码调试演示过程,请点击链接

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:

收藏 0
self inputs numpy hidden outpu
评论 ( 0 )