一个单层的基础神经网络实现手写字识别

39

先上代码

import tensorflow
from tensorflow.examples.tutorials.mnist import input_data
import matplotlib.pyplot as plt

# 普通的神经网络学习
# 学习训练类
class Normal:

    weight = []
    biases = []

    def __init__(self):
        self.times = 1000
        self.mnist = []
        self.session = tensorflow.Session()
        self.xs = tensorflow.placeholder(tensorflow.float32, [None, 784])
        self.ys = tensorflow.placeholder(tensorflow.float32, [None, 10])
        self.save_path = 'learn/result/normal.ckpt'

    def run(self):
        self.import_data()
        self.train()
        self.save()

    def _setWeight(self,weight):
        self.weight = weight

    def _setBiases(self,biases):
        self.biases = biases

    def _getWeight(self):
        return self.weight

    def _getBiases(self):
        return self.biases
    # 训练
    def train(self):

        prediction = self.add_layer(self.xs, 784, 10, activation_function=tensorflow.nn.softmax)

        cross_entropy = tensorflow.reduce_mean(
            -tensorflow.reduce_sum(
                self.ys * tensorflow.log(prediction)
                , reduction_indices=[1])
        )
        train_step = tensorflow.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

        self.session.run(tensorflow.global_variables_initializer())

        for i in range(self.times):
            batch_xs, batch_ys = self.mnist.train.next_batch(100)
            self.session.run(train_step, feed_dict={self.xs: batch_xs, self.ys: batch_ys})
            if i % 50 == 0:
                # images 变换为 labels,images相当于x,labels相当于y
                accurary = self.computer_accurary(
                    self.mnist.test.images,
                    self.mnist.test.labels,
                    prediction
                )

    # 数据导入
    def import_data(self):
        self.mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

    # 数据保存
    def save(self):
        saver = tensorflow.train.Saver()
        path = saver.save(self.session,self.save_path)

    # 添加隐藏层
    def add_layer(self,inputs,input_size,output_size,activation_function=None):

        weight = tensorflow.Variable(tensorflow.random_normal([input_size,output_size]),dtype=tensorflow.float32,name='weight')

        biases = tensorflow.Variable(tensorflow.zeros([1,output_size]) + 0.1,dtype=tensorflow.float32,name='biases')
        Wx_plus_b = tensorflow.matmul(inputs,weight) + biases

        self._setBiases(biases)
        self._setWeight(weight)

        if activation_function is None:
            outputs = Wx_plus_b
        else:
            outputs = activation_function(Wx_plus_b,)

        return outputs


    # 计算结果数据与实际数据的正确率
    def computer_accurary(self,x_data,y_data,tf_prediction):

        prediction = self.session.run(tf_prediction,feed_dict={self.xs:x_data,self.ys:y_data})

        # 返回两个矩阵中最大值的索引号位置,然后进行相应位置的值大小比较并在此位置设置为True/False
        correct_predition = tensorflow.equal(tensorflow.argmax(prediction,1),tensorflow.argmax(y_data,1))

        # 进行数据格式转换,然后进行降维求平均值
        accurary = tensorflow.reduce_mean(tensorflow.cast(correct_predition,tensorflow.float32))

        result = self.session.run(accurary,feed_dict={self.xs:x_data,self.ys:y_data})

        return result

# 识别类
class NormalRead(Normal):

    input_size = 784
    output_size = 10

    def run(self):
        self.import_data()
        self.getSaver()
        origin_input = self._getInput()
        output = self.recognize(origin_input)

        self._showImage(origin_input)
        self._showOutput(output)
        pass

    # 显示识别结果
    def _showOutput(self,output):
        number = output.index(1)
        print('识别到的数字:',number)

    # 显示被识别图片
    def _showImage(self,origin_input):
        data = []
        tmp = []
        i = 1
        # 原数据转换为可显示的矩阵
        for v in origin_input[0]:
            if i %28 == 0:
                tmp.append(v)
                data.append(tmp)
                tmp = []
            else:
                tmp.append(v)
            i += 1

        plt.figure()
        plt.imshow(data, cmap='binary')  # 黑白显示
        plt.show()


    def _setBiases(self,biases):
        self.biases = biases
        pass

    def _setWeight(self,weight):
        self.weight = weight
        pass

    def _getBiases(self):
        return self.biases

    def _getWeight(self):
        return self.weight

    # 获取训练模型
    def getSaver(self):
        weight = tensorflow.Variable(tensorflow.random_normal([self.input_size, self.output_size]), dtype=tensorflow.float32,name='weight')

        biases = tensorflow.Variable(tensorflow.zeros([1, self.output_size]) + 0.1, dtype=tensorflow.float32, name='biases')

        saver = tensorflow.train.Saver()
        saver.restore(self.session,self.save_path)

        self._setWeight(weight)
        self._setBiases(biases)

    def recognize(self,origin_input):
        input = tensorflow.placeholder(tensorflow.float32,[None,784])
        weight = self._getWeight()
        biases = self._getBiases()

        result = tensorflow.matmul(input,weight) + biases
        resultSof = tensorflow.nn.softmax(result,) # 把结果集使用softmax进行激励
        resultSig = tensorflow.nn.sigmoid(resultSof,) # 把结果集以sigmoid函数进行激励,用于后续分类
        output = self.session.run(resultSig,{input:origin_input})

        output = output[0]

        # 对识别结果进行分类处理
        output_tmp = []
        for item in output:
            if item < 0.6:
                output_tmp.append(0)
            else :
                output_tmp.append(1)

        return output_tmp

    def _getInput(self):
        inputs, y = self.mnist.train.next_batch(100);
        return [inputs[50]]

以上是程序,整个程序基于TensorFlow来实现的,具体的TensorFlow安装我就不说了。
整个训练过程不做多说,我发现网上关于训练的教程很多,但是训练结果的教程很少。

整个程序里,通过tensorflow.train.Saver()save进行训练结果模型进行存储,然后再用tensorflow.train.Saver()restore进行模型恢复然后取到训练好的weight和baises。

这里要注意的一个地方是因为一次性随机取出100张手写图片进行批量训练的,我在取的时候其实也是批量随机取100张,但是我传入识别的是一张,通过以下这段程序:

def _getInput(self):
        inputs, y = self.mnist.train.next_batch(100);
        return [inputs[50]]

注意一下return这里的数据结构,其实是取这批量的第50张,实际上这段程序写成:

def _getInput(self):
        inputs, y = self.mnist.train.next_batch(1);
        return [inputs[0]]

会更好。
因为识别的时候是需要用到训练的隐藏层来进行的,所以在此我虽然识别的是一张图片,但是我必须要传入一个批量数据的这样一个结构。

然后再识别的地方,我使用了两个激励函数:

resultSof = tensorflow.nn.softmax(result,) # 把结果集使用softmax进行激励
resultSig = tensorflow.nn.sigmoid(resultSof,) # 把结果集以sigmoid函数进行激励,用于后续分类

这里的话,第一个softmax激励后的数据我发现得到的是以e为底的指数形式,转换成普通的浮点数来看,不是很清楚到底是什么,那么我在做识别数字判断的时候就不方便,所以再通过了一次sigmoid的激励。

后续我通过一个循环判断进行一次实际上的分类,这个原因首先要说到识别结果形式:

[0,0,0,0,0,0,0,0,1,0]

像以上这个数据,表示的是8,也就是说,数组下表第几位为1就表示是几,如0的表示:

[1,0,0,0,0,0,0,0,0,0]

而sigmoid函数在这个地方其实就是对每个位置的数据进行了分类,我发现如果分类值小于0.52这样的数据其实代表的是否,也就是说此位置的值对应的是0,大于0.52应该对应的是真,也就是1;而我在程序里取的是0.6为界限做判断。

实际上,这个界限值应该是在神经网络训练的时候取的,而不是看识别结果来进行凭感觉取的(虽然训练的时候的参数也是凭感觉取的)

这篇文章是我根据个人的一些理解来写的,后续如果发现有错误,我会在新文章说出来,但这篇文章不做保留,方便后续检查思考记录的时候知道到底怎么踩坑的。

以下是我上次写的sigmoid函数的文章:

https://segmentfault.com/a/11...

关于其他激励函数,可以网上找资料进行了解,很多基础性的数学知识,放到一些比较具体的应用,会显得非常的有意思。


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

14 条评论
DevTTL · 2017年12月27日

大佬可不可以把注释写全点,给渣渣们指指路

+6 回复

3

后面有时间我会写全的,包括每个函数的作用。还有里面的一些误区。

kumfo 作者 · 2017年12月27日
0

感谢大佬

DevTTL · 2017年12月28日
0

@DevTTL 哈哈,还不算大佬,刚入门,这么说我怪不好意思的

kumfo 作者 · 2017年12月28日
tf_study · 2017年12月27日

楼主,有个问题请教下, 在recognize识别的时候用了softmax为什么还要用sigmod函数,这样结果只是0或1了吧

+2 回复

1

这是一个分类问题,sigmoid很有意思的,x从0开始,x小于0相当于分为一类,大于0相当于分为了一类,sigmoid转化后的数据我发现看起来更好懂一些。softmax我想最后得到的结果应该和sigmoid类似,但是我print看了之后,是具有以e为底数的指数形式,具体值应该是什么不是很清楚。但我用sigmoid后发现看起来就很清楚了。我程序里,以小于0.6分为否,大于0.6分为true,其实应该再0.52以上这样的一个范围内。

kumfo 作者 · 2017年12月27日
0

嗯 明白了, softmax已经完成了非线性变换,其实加不加sigmoid对结果应该差别不大

tf_study · 2017年12月28日
0

@tf_study 对,就是这个理

kumfo 作者 · 2017年12月28日
Panda · 2017年12月27日

不错??

+1 回复

Honwhy · 2017年12月27日

好厉害

回复

1

☺️☺️☺️也是整了好久才想明白里面的一些东西。

kumfo 作者 · 2017年12月27日
0

@kumfo 反正我是看不懂,好高大上

Honwhy · 2017年12月28日
载入中...