实现minst手写识别算法 的 tensorflow关于cnn层的封装, 以及keras

本文共有6752个字,关键词:

学习了cnn神经网络,深刻理解算法后,使用tensorflow对cnn的各层封装
如下是识别mnist手写算法的例子,过程中为了深刻理解,做了很详细的备注

import tensorflow as tf

class Mytf:
    sess = tf.Session()
    keep_prob = tf.placeholder(tf.float32)
    prediction = []
    Optimizer = None
    train_step = None

    def __init__(self, in_size, out_size):
        print('新建神经网络, 特征数量', in_size, ', 结果类型数量', out_size)
        self.prediction.append(tf.placeholder(tf.float32, [None, in_size]))
        self.train_out = tf.placeholder(tf.float32, [None, out_size])

    # 添加 卷积 层
    # patch_size 卷积核大小
    # step_size 移动步长
    # step_size <= patch_size 步长要小于等于核大小,否则有扫不到的地方
    def add_conv_layer(self, patch_size, step_size, out_size, padding='SAME', ac_fun=tf.nn.relu):
        in_size = int(self.prediction[-1].shape[-1])
        weight = self.variable_weight([patch_size, patch_size, in_size, out_size])
        bias = self.variable_bias([out_size])
        # input         输入图像                  [batch, in_height, in_width, in_channels]
        # filter/weight 卷积核                    [filter_height, filter_width, in_channels, out_channels]
        # strides       卷积核每一步移动长度步长     [batch?, x方向步长, y方向步长, 1通道?]
        # padding       VALID保证全部在图片内部,宽度不够丢弃,可能小一圈 SAME步长超过图片补零,保证结果和原图一样大
        conv = tf.nn.conv2d(self.prediction[-1], weight, strides=[1, step_size, step_size, 1], padding=padding) + bias
        self.prediction.append(ac_fun(conv))
        print('添加卷积层', self.prediction[-2].shape, '=>', self.prediction[-1].shape,
              '\t卷积核大小{patch_size}\t移动步长{step_size}'.format(**locals()))

    # 添加 池化 层
    # pool_size 池化窗口大小
    # step_size 移动步长
    # 一般pool_size == step_size
    def add_pool_layer(self, pool_size, step_size, padding='SAME'):
        after_pool = tf.nn.max_pool(self.prediction[-1], ksize=[1, pool_size, pool_size, 1],
                                    strides=[1, step_size, step_size, 1], padding=padding)
        self.prediction.append(after_pool)
        print('添加池化层', self.prediction[-2].shape, '=>', self.prediction[-1].shape)

    # fully connected layer
    def add_fc_layer(self, out_size, ac_fun=lambda f: f):
        in_size = int(self.prediction[-1].shape[-1])
        weight = self.variable_weight([in_size, out_size])
        bias = self.variable_bias([out_size])
        after_matmul = tf.matmul(self.prediction[-1], weight) + bias
        self.prediction.append(ac_fun(after_matmul))
        print('添加神经层', self.prediction[-2].shape, '=>', self.prediction[-1].shape)

    def reshape_fc(self):
        wd = 1
        for _ in self.prediction[-1].shape[1:]:
            wd *= _
        self.reshape([-1, wd])

    def reshape(self, shape):
        after_reshape = tf.reshape(self.prediction[-1], shape)
        self.prediction.append(after_reshape)
        print('数据变形', self.prediction[-2].shape, '=>', self.prediction[-1].shape)

    def dropout(self):
        print('随机丢弃神经元')
        after_dropout = tf.nn.dropout(self.prediction[-1], self.keep_prob)
        self.prediction.append(after_dropout)

    # 返回 新生成权重 变量, 输入形状 初始随机分布0.1
    @staticmethod
    def variable_weight(shape, stddev=0.1):
        return tf.Variable(tf.truncated_normal(shape, stddev=stddev))

        # 返回 新生成偏置 变量 输入形状 默认全为0.1

    @staticmethod
    def variable_bias(shape, default=0.1):
        return tf.Variable(tf.constant(default, shape=shape))

    # 最后循环跑这个
    def run_cnn(self, train_in, train_out, keep_prob):
        if not self.Optimizer:
            self.Optimizer = tf.train.AdamOptimizer(1e-4).minimize(
                tf.reduce_mean(-tf.reduce_sum(self.train_out * tf.log(self.prediction[-1]), reduction_indices=[1]))
            )
            self.sess.run(tf.global_variables_initializer())
        self.sess.run(self.Optimizer, feed_dict={
            self.prediction[0]: train_in,
            self.train_out: train_out,
            self.keep_prob: keep_prob
        })

    # 用模型计算测试输出,返回准确率
    def test(self, test_in, test_out):
        # 用测试数据输入,得到基于训练的测试输出结果 结果是 hot-space 形式
        train_test_out = self.sess.run(self.prediction[-1],
                                       feed_dict={self.prediction[0]: test_in, self.keep_prob: 1})
        # 用 基于训练的测试输出结果 和真实测试输出 对比 得到真实预测 bool类型
        correct_prediction = tf.equal(tf.argmax(train_test_out, 1), tf.argmax(test_out, 1))
        # 转化 bool 类型结果为 float 然后取平均数
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
        # 运算得到 accuracy 的值 不要'calc_out': v_ys可不可以??? self.prediction[0]: test_in,不要可不可以???
        result = self.sess.run(accuracy)
        return result


if __name__ == '__main__':
    from tensorflow.examples.tutorials.mnist import input_data

    mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
    # 定义输入特征数量784,输出特征数量10
    mytf = Mytf(784, 10)
    # 输入的[None,784],把784增加到维度上,分别是n行,28*28像素*1通道颜色
    mytf.reshape([-1, 28, 28, 1])
    # 卷积 图片尺寸不变, 特征层数从1到32
    mytf.add_conv_layer(5, 1, 32)
    # 池化 图片尺寸从 28*28 变为 14*14
    mytf.add_pool_layer(2, 2)
    # 卷积 图片尺寸不变, 特征层数从32到64
    mytf.add_conv_layer(5, 1, 64)
    # 池化 图片尺寸从 14*14 变为 7*7
    mytf.add_pool_layer(2, 2)

    # 维度恢复到2维,为全连接提取特征, 尺寸为 n行* 7*7像素* 64层特征
    mytf.reshape_fc()
    # 隐藏层 从7 * 7 * 64特征数减少到 1024
    mytf.add_fc_layer(1024, tf.nn.relu)
    # 随机丢弃部分神经元
    mytf.dropout()
    # 隐藏层 从1024特征数减少到 10
    mytf.add_fc_layer(10, tf.nn.softmax)

    for i in range(100000):
        _train_in1, _train_out = mnist.train.next_batch(100)
        mytf.run_cnn(_train_in1, _train_out, 0.5)
        if i % 50 == 0:
            print(mytf.test(mnist.test.images[:1000], mnist.test.labels[:1000]))

    # 准确率可达99%

后来发现tensorflow里面有个keras,已经实现了我上面的封装功能.直接使用就好, 上面的封装就当做对tensorfow和cnn的深刻理解的学习,附上同样功能的keras写法

import tensorflow as tf
from tensorflow import keras

mnist = keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = keras.models.Sequential([
    keras.layers.Reshape((28, 28, 1)),
    keras.layers.Conv2D(32, 1, 1),
    keras.layers.MaxPool2D(),
    keras.layers.Conv2D(64, 1, 1),
    keras.layers.MaxPool2D(),

    keras.layers.Flatten(),
    keras.layers.Dense(1024, activation=tf.nn.relu),
    keras.layers.Dense(64, activation=tf.nn.relu),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation=tf.nn.softmax),
])

# model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

「一键投喂 软糖/蛋糕/布丁/牛奶/冰阔乐!」

pch18

(๑>ڡ<)☆谢谢老板~

使用微信扫描二维码完成支付

版权声明:如无特别说明,本文为作者原创,如需转载须联系作者本人同意,未经作者本人同意不得擅自转载。
添加新评论
暂无评论