• CNN-手写数字识别


    一、用CNN实现手写数字识别

    import tensorflow as tf
    import numpy as np
    from sklearn.datasets import load_digits
    
    import time
    print( time.ctime() )
    
    digits = load_digits()
    X_data = digits.data.astype(np.float32)
    Y_data = digits.target.astype(np.float32).reshape(-1, 1)
    
    def generatebatch(X, Y, n_examples, batch_size):
        for batch_i in range(n_examples // batch_size):
            start = batch_i * batch_size
            end = start + batch_size
            batch_xs = X[start:end]
            batch_ys = Y[start:end]
            yield batch_xs, batch_ys # 生成每一个batch
            
    from sklearn.preprocessing import MinMaxScaler
    scaler = MinMaxScaler()
    
    X_data = scaler.fit_transform(X_data)
    
    from sklearn.preprocessing import OneHotEncoder
    Y = OneHotEncoder().fit_transform(Y_data).todense()#todense返回矩阵
    
    #转换为图片格式(batch, height, width, channels)
    X = X_data.reshape(-1, 8, 8, 1)
    
    batch_size = 8 #使用MBGD算法,batch_size=8
    
    tf.reset_default_graph()#tf.reset_default_graph函数用于清除默认图形堆栈并重置全局默认图形。
    #输入层
    tf_X = tf.placeholder(tf.float32, [None, 8, 8, 1])
    tf_Y = tf.placeholder(tf.float32, [None, 10])
    
    #卷积层,创建权重变量和偏置变量,其中的四维矩阵代表了filters的深度,即10个filter,其中每个filter的深度是1,若是RGB则每个filter深度为3
    conv_filter_w1 = tf.Variable( tf.random_normal([3, 3, 1, 10]) )#3*3的filter,每个filter深度是1,共10个filter
    #conv_filter_w1 = tf.get_variable( 'weights', [3, 3, 1, 10], initializer=tf.truncated_normal_initializer(stddev=0.1) )
    
    conv_filter_b1 = tf.Variable( tf.random_normal([10]) )#10个filter对应10个bias
    #conv_filter_b1 = tf.get_variable( 'biases', [10], initializer=tf.constant_initializer(0.1) )
    
    #tf.nn.conv2d提供了方便的函数来实现卷积层的前向传播算法
    #函数的第一个输入为当前层的节点矩阵,注意这个是四维矩阵即tf_X
    #其中(tf_X)后面三维对应一个节点矩阵,第一维对应一个输入batch,比如在输入层
    #input[0, :, :, :]表示第一张图,input[1, :, :, :]表示第二张图,input[2, :, :, :]表示第三张图,以此类推
    #tf.nn.conv2d第二个参数提供了卷积层权重,第三个参数是不同维度上的步长,长度为4的数组,第一维和最后一维数字要求一定是1
    #最后一个参数是padding,SAME表示添加全0填充,VALID表示不添加
    conv = tf.nn.conv2d( tf_X, conv_filter_w1, strides=[1, 1, 1, 1], padding='SAME')
    
    #tf.nn.bias_add提供了一个方便的函数给每个节点加上偏置项
    #注意这里不能直接使用加法,因为矩阵上不同位置上的节点都需要加上同样的偏置项,也就是下面第二种直接加法是错误的
    bias = tf.nn.bias_add( conv, conv_filter_b1 )
    #bias = conv + conv_filter_b1这是错误的做法
    
    #ReLU激活函数去线性化
    relu_feature_maps1 = tf.nn.relu( bias )
    print(relu_feature_maps1)
    #Tensor("Relu:0", shape=(?, 8, 8, 10), dtype=float32)
    
    # 池化层,tf.nn.max_pool实现了最大池化层的前向传播过程,参数和tf.nn.conv2d函数类似
    #ksize提供了filter的尺寸,strides提供了步长,padding提供是否使用全0填充
    max_pool1 = tf.nn.max_pool( relu_feature_maps1, ksize=[1,3,3,1], strides=[1,2,2,1], padding='SAME')
    
    print(max_pool1)
    #Tensor("MaxPool:0", shape=(?, 4,4,10), dtype=float32)
    
    # 卷积层2
    conv_filter_w2 = tf.Variable( tf.random_normal([3, 3, 10, 5]) )#因为上一层的卷积层深度是10,即有10个输出,这里一个filter深度就是10,而用5个filter
    conv_filter_b2 =  tf.Variable( tf.random_normal([5]) )
    conv2 = tf.nn.conv2d(relu_feature_maps1, conv_filter_w2, strides=[1, 2, 2, 1], padding='SAME')
    
    conv_out2 = tf.nn.bias_add( conv2, conv_filter_b2 )
    print(conv_out2)
    #Tensor("BiasAdd_1:0", shape=(?, 4, 4, 5), dtype=float32)
    
    # BN归一化层+激活层
    #批标准化(batch normalization,BN)一般用在激活函数之前,使结果各个维度均值为0,方差为1。
    #通过规范化让激活函数分布在线性区间,让每一层的输入有一个稳定的分布会有利于网络的训练。
    batch_mean, batch_var = tf.nn.moments( conv_out2, axes=[0, 1, 2], keep_dims=True )
    #axes:表示在哪个维度上求解,是个list,例如 [0, 1, 2]
    #keep_dims:是否保持维度
    
    shift = tf.Variable(tf.zeros([5]))
    scale = tf.Variable(tf.ones([5]))
    epsilon = 1e-3
    #•tf.nn.batch_normalization(x, mean, variance, offset, scale, variance_epsilon, name=None)
    #https://blog.csdn.net/lanchunhui/article/details/70792458
    
    BN_out = tf.nn.batch_normalization( conv_out2, batch_mean, batch_var, shift, scale, epsilon )
    print(BN_out)
    #Tensor("batchnorm/add_1:0", shape=(?, 4, 4, 5), dtype=float32)
    
    relu_BN_maps2 = tf.nn.relu(BN_out)
    
    # 池化层
    max_pool2 = tf.nn.max_pool( relu_BN_maps2, ksize=[1,3,3,1], strides=[1,2,2,1], padding='SAME' )
    print(max_pool2)
    #Tensor("MaxPool_1:0", shape=(?, 2, 2, 5), dtype=float32)
    
    # 将特征图进行展开
    max_pool2_flat = tf.reshape( max_pool2, [-1, 2*2*5] )
    
    # 全连接层
    fc_w1 = tf.Variable( tf.random_normal([2*2*5,50]) )
    fc_b1 =  tf.Variable( tf.random_normal([50]) )
    fc_out1 = tf.nn.relu( tf.matmul(max_pool2_flat, fc_w1) + fc_b1 )
    
    # 输出层
    out_w1 = tf.Variable( tf.random_normal([50,10]) )
    out_b1 = tf.Variable( tf.random_normal([10]) )
    pred = tf.nn.softmax( tf.matmul(fc_out1, out_w1) + out_b1 )
    
    loss = -tf.reduce_mean( tf_Y * tf.log( tf.clip_by_value(pred,1e-11,1.0) ) )
    
    train_step = tf.train.AdamOptimizer(1e-3).minimize(loss)
    
    y_pred = tf.arg_max(pred,1)
    bool_pred = tf.equal( tf.arg_max(tf_Y,1), y_pred )
    
    accuracy = tf.reduce_mean( tf.cast(bool_pred,tf.float32) ) # 准确率
    
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        
        for epoch in range(1000): # 迭代1000个周期
            for batch_xs, batch_ys in generatebatch(X, Y, Y.shape[0], batch_size): # 每个周期进行MBGD算法
                sess.run( train_step, feed_dict={tf_X:batch_xs, tf_Y:batch_ys} )
                
            if(epoch%100 == 0):
                res = sess.run(accuracy,feed_dict={ tf_X:X,tf_Y:Y} )
                print (epoch, res)
                
        res_ypred = y_pred.eval(feed_dict={tf_X:X,tf_Y:Y}).flatten() # 只能预测一批样本,不能预测一个样本
        print (res_ypred)
        
    from sklearn.metrics import  accuracy_score
    print ( accuracy_score( Y_data,res_ypred.reshape(-1,1) ))
    
    print( time.ctime() )
    

      

  • 相关阅读:
    c# 类中使用ResolveUrl
    IIS7日志中时间与系统时间不一致的原因
    IIS日志-网站运维的好帮手
    精通 JS正则表达式
    word 标题序号
    rtx 二次开发,查找所有部门
    【云计算】Docker容器时间同步如何配置?
    【云计算】Docker多进程管理方案-cfengine && supervisord
    【Python】装饰器实现日志记录
    【云计算】k8s相关资料
  • 原文地址:https://www.cnblogs.com/always-fight/p/10033264.html
Copyright © 2020-2023  润新知