精华内容
下载资源
问答
  • 说下废话:帮xxx同学写的手写数字识别保姆级代码。

    说下废话:帮一个刚学tensorflow2的同学写的手写数字识别基本流程代码,写完顺便整理成博客。

    1.导包

    原始代码如下,可根据实际情况进行修改。

    import  os
    os.environ["TF_MIN_CPP_LOG_LEVEL"]="2"  #屏蔽一些警告
    #os.environ["CUDA_VISIBLE_DEVICES"]='-1' #设置当前程序可见的设备范围,-1直接使用CPU
    import  tensorflow as tf
    from    tensorflow.keras import layers, optimizers, datasets, Sequential
    print(tf.config.experimental.list_physical_devices(device_type='GPU'))#打印看看GPU设备
    physical_devices = tf.config.experimental.list_physical_devices('GPU')#所有可用GPU
    assert len(physical_devices) > 0, "Not enough GPU hardware devices available"
    tf.config.experimental.set_memory_growth(physical_devices[0], True)#设置第一个张卡仅在需要时申请显存空间
    

    如果使用GPU的话,就直接运行,可以打印出可使用设备。
    在这里插入图片描述

    如果使用CPU的话,就可以设置os.environ[“CUDA_VISIBLE_DEVICES”]=’-1’,然后把打印下面的代码删掉,否则会报错没有可用GPU。
    隐藏了GPU,打印的GPU设备就为空了:
    在这里插入图片描述

    2.构建数据集

    # 预处理函数
    @tf.autograph.experimental.do_not_convert
    def preprocess(x, y):
        
        x = tf.cast(x, dtype=tf.float32) / 255.
        y = tf.cast(y, dtype=tf.int32)
        x=tf.expand_dims(x,-1)
    
        return x, y
    
    

    除以255将像素压缩到0~1.0,转为浮点数做运算。然后将x最后一个维度添加一维,因为只有四维你后面的卷积才能运算。

    (x,y), (x_test, y_test) = datasets.mnist.load_data()
    print(x.shape, y.shape, x_test.shape, y_test.shape)
    train_db = tf.data.Dataset.from_tensor_slices((x,y))
    train_db = train_db.shuffle(buffer_size=500).map(preprocess).batch(128)
    
    test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test))
    test_db = test_db.map(preprocess).batch(64)
    
    sample = next(iter(train_db))
    print('sample:', sample[0].shape, sample[1].shape,
          tf.reduce_min(sample[0]), tf.reduce_max(sample[0]))
    

    加载Mnist直接使用 datasets.mnist.load_data() 加载

    然后将把整个数据集切片,比如训练集有60000张图捆绑在一块,就把它切成60000个一张的图片的集合。

    shuffle的作用:
    从数据集中按顺序抽取buffer_size个样本放在buffer中,然后打乱buffer中的样本,
    buffer中样本个数不足buffer_size,继续从data数据集中按顺序填充至buffer_size,并再次打乱。
    map的作用:
    往里面放一个函数,数据就会被做输入喂进函数进行处理,然后返回新的数据。
    batch的作用:
    从buffer中抽batch_size个数据出来打包在一块。

    看看结果(训练集batch_size为128,这种东西可以随便设置,就看你电脑带得动不)
    训练集60000张图,大小为28*28,标签为60000个数字(0~9)
    测试集10000张图。

    打印经过上述处理过的一个batch数据(代码中的sample),
    可以看见第一维度为128,即batch_size ,二,三维为图片宽高,最后一维是经过preprocess后增加的,图片中像素值也已经压缩到0~1.0。
    在这里插入图片描述

    3.构建模型

    下面写了俩模型(推荐使用自定义的模型类),一个大的,用GPU跑好点,另一个适用于用CPU跑的同学

    第一个模型

    5个卷积块,3层全连接。
    输入:128,28,28,1
    unit1:128,14,14,64
    你padding=same只是确保stride=1时图片大小不变,stride=2就仍会对图片进行下采样。
    unit2:128,7,7,128
    unit3:128,4,4,256
    unit4:128,2,2,512
    unit5:128,1,1,512
    reshape 后:128,512
    fc1:128,256
    fc2:128,128
    fc3:128,10
    预测10个数字,到时候将10个输出取概率最大的作为最终预测结果就行了

    解释一下流程,要将图片从(batch_size,28,28,1)变到最终的(batch_size,10),卷积层部分完成的功能是提取feature map,然后经过reshape将特征图拉成一行,在这里就是(batch_size,512),最后再经过全连接层(分类器)得到输出(batch_size,10)。

    class CnnModel(tf.keras.Model):
        def __init__(self):
            super(CnnModel, self).__init__()
            # unit 1
            self.unit1=Sequential([
            layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.Conv2D(64, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),],name='unit1')
    
            # unit 2
            self.unit2=Sequential([
            layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.Conv2D(128, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),],name='unit2')
    
            # unit 3
            self.unit3=Sequential([
            layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.Conv2D(256, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),],name='unit3')
    
            # unit 4
            self.unit4=Sequential([
            layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),],name='unit4')
    
            # unit 5
            self.unit5=Sequential([
            layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.Conv2D(512, kernel_size=[3, 3], padding="same", activation=tf.nn.relu),
            layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same'),],name='unit5')
    
            #fc
            self.fc_net = Sequential([
                layers.Dense(256, activation=tf.nn.relu),
                layers.Dense(128, activation=tf.nn.relu),
                layers.Dense(10, activation=None),
            ],name='fc')
    
        def call(self, x):
            x1=self.unit1(x)
            
            x2=self.unit2(x1)
            
            x3=self.unit3(x2)
            
            x4=self.unit4(x3)
            
            x5=self.unit5(x4)
            
            x5_ = tf.reshape(x5, [-1, 512]) #其他维度给出固定值,-1会根据实际形状进行计算
            out=self.fc_net(x5_)
            return out
    

    下面创建一个模型:
    build:建立模型,并指明输入的维度及其形状.之后就可以用summary看看你的模型。

    之后设置的optimizer 是优化器,variables是模型中所有可训练的参数,checkpoint是为了等等保存自定义模型的信息(可以用来继续中断的训练),下面是我保存的是模型,优化器,以及epochs。

    tf.train.CheckpointManager 可以用于管理checkpoint,比如我下面设置的保存checkpoint,保存路径为 ./model_data/最大的保存个数为4

    cnnmodel=CnnModel()
    cnnmodel.build(input_shape=(None, 28, 28, 1))
    cnnmodel.summary()
    optimizer = optimizers.Adam(lr=1e-4)
    checkpoint_path='./model_data/'
    variables = cnnmodel.trainable_variables
    checkpoint = tf.train.Checkpoint(model=cnnmodel, optimizer=optimizer,epochs=tf.Variable(0))
    manager = tf.train.CheckpointManager(checkpoint,checkpoint_path , max_to_keep=4)
    

    在这里插入图片描述
    在这个数据集里,几百万参数算多了 ,下面一个epoch就97准确度了。。

    第二个模型

    只要确保卷积层后feature map 大小变为1*1就行了,也就是要5个stride=2。

    class CnnModel(tf.keras.Model):
        def __init__(self):
            super(CnnModel, self).__init__()
            
            self.conv_1=layers.Conv2D(64, kernel_size=[3, 3], strides=2, padding="same", activation=tf.nn.relu,name="conv_1")
            self.pool_1=layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same',name='pool_1')
            
            self.conv_2=layers.Conv2D(128, kernel_size=[3, 3],strides=2, padding="same", activation=tf.nn.relu,name='conv_2')
            self.conv_3=layers.Conv2D(128, kernel_size=[3, 3],strides=2, padding="same", activation=tf.nn.relu,name='conv_3')
            self.pool_2=layers.MaxPool2D(pool_size=[2, 2], strides=2, padding='same',name='pool_2')
           
            self.fc_net = Sequential([
                layers.Dense(128, activation=tf.nn.relu),
                layers.Dense(10, activation=None),
            ],name='fc')
    
        def call(self, x):
            x1=self.conv_1(x)
            x1_=self.pool_1(x1)
            x2=self.conv_2(x1_)
            x3=self.conv_3(x2)
            x4=self.pool_2(x3)
            
            x4_ = tf.reshape(x4, [-1, 128])
            out=self.fc_net(x4_)
            return out
    

    在这里插入图片描述

    4.模型训练并测试

    使用的是GradientTape梯度带来计算梯度,好处在于自定义程度高,可以对损失的计算过程、计算方式进行深度定制,而不是用model.train这种高级API(傻白甜)去进行单纯的训练。

    一个训练步

    def train_step():
        for step, (x,y) in enumerate(train_db):
                with tf.GradientTape() as tape:
                    logits = cnnmodel(x)
                    y = tf.one_hot(y, depth=10)
                    # compute loss
                    loss = tf.losses.categorical_crossentropy(y, logits, from_logits=True)
                    loss = tf.reduce_mean(loss)
    
                grads = tape.gradient(loss, variables)
                optimizer.apply_gradients(zip(grads, variables))
    
                if step %100 == 0:
                    print(f"epoch:{int(checkpoint.epochs)+1}  ,step:{step}", 'loss:', float(loss))
            
        
        
        total_num = 0
        total_correct = 0
        for x,y in test_db:
    
            logits= cnnmodel(x)
            prob = tf.nn.softmax(logits, axis=1)
            pred = tf.argmax(prob, axis=1)
            pred = tf.cast(pred, dtype=tf.int32)
            y=tf.cast(y, dtype=tf.int32)
            correct = tf.cast(tf.equal(pred, y), dtype=tf.int32)
            correct = tf.reduce_sum(correct)
    
            total_num += x.shape[0]
            total_correct += int(correct)
        print("*"*60)
        print("total,correct",total_num,total_correct,)
        acc = total_correct / total_num
       
        print("epoch:",int(checkpoint.epochs)+1, 'acc:', acc)
        checkpoint.epochs.assign_add(1)      
        save_path = manager.save()
        print(f"Saved checkpoint for epochs {int(checkpoint.epochs)} in {save_path}")
               
        print("*"*60)
        
        
    

    使用模型计算得到结果后,由于输出是10个,因此我们把真实标签y进行深度为10的one-hot编码,然后使用交叉熵计算误差。得到误差后,使用tape.gradient计算梯度,使用optimizer.apply_gradients来将梯度应用于参数更新。

    接着取测试集数据进行测试, logits为预测结果(为(64,10)测试集我batch_size取了64)。
    每个样本的形状为(1,10),用softmax转为将输出概率,axis=1是让它在第二个维度10上进行转概率,也就是对每个样本都进行概率。
    接着用argmax函数对每个样本取概率值最大的索引作为输出(因为一个样本10个输出,索引为0~9,刚好对应10个数字标签)
    再用tf.cast将输出转为int型,与真实标签进行比较,并统计一个step中正确的个数。

    后面的是对checkpoint的保存。
    保存后,用checkpoint.epochs.assign_add(1),将epochs的数值+1

    开始训练

    设置了是否加载继续训练,如果是的话就加载最新的checkpoint,没有的话就新训练一个。

    def main(resume_from_file=False):
        
       
        if resume_from_file is True:
             checkpoint.restore(manager.latest_checkpoint)
             if manager.latest_checkpoint:
                    print("Restored from {}".format(manager.latest_checkpoint))
        else:
            print("a new model will be trained")                 
        for epoch in range(2):
                train_step()
                
    
    if __name__ == '__main__':
        main()
    

    结果如下:
    在这里插入图片描述

    if __name__ == '__main__':
        main(True)
    

    在这里插入图片描述

    5.预测

    首先,用np.array(np.array(img)/255).reshape((1, 28, 28, 1)) 将图片格式改成模型输入的格式,并压缩到0~1.0.
    然后,用checkpoint.restore(manager.latest_checkpoint) 加载最新的checkpoint.
    接着,按着上面提到做测试的方法进行操作,得到最终的预测数字。

    import numpy as np
    import matplotlib.pyplot as plt
    from PIL import Image  
    import cv2
    @tf.autograph.experimental.do_not_convert
    def predict(image_path):
         
        img= Image.open(image_path).convert("L")
        img=np.array(np.array(img)/255).reshape((1, 28, 28, 1))
        img=tf.cast(img,dtype=tf.float64)
        #print(img)
        checkpoint.restore(manager.latest_checkpoint)
        logits=cnnmodel.predict(img)
        prob = tf.nn.softmax(logits, axis=1)
        pred = tf.argmax(prob, axis=1)
        pred = tf.cast(pred, dtype=tf.int32)
        print("the number is",int(pred[0]))
    
    
    

    下面,到了最开心的预测环节了。

    请拿出画图,大小设为28*28像素,然后背景填黑,用白笔写个数字。像这样
    在这里插入图片描述
    保存为 4.png,然后运行:

    predict("4.png")
    img=cv2.imread("4.png")
    plt.imshow(img)
    plt.show()
    

    最后,你将得到这个
    在这里插入图片描述
    你还可以用函数里加个**print(prob)**看看概率。0.96是0,这模型还挺自信的。。
    在这里插入图片描述
    8:0.86
    在这里插入图片描述

    接下来玩点花的试试吧。
    5: 0.99
    在这里插入图片描述
    7:0.99
    在这里插入图片描述
    旋转一下:
    2:0.49 好的,这宝儿开始不自信了。。。
    在这里插入图片描述
    如果我把4写成这样,二愣子模型就不知道了。。。
    在这里插入图片描述

    后记:
    谨以此篇献给刚学tensorflow2的小伙伴们或为实验报告发愁的同学。
    代码一段一段粘贴到jupyter或者整合在一块就能直接跑了。

    展开全文
  • 1. 手写数字识别简述 1.1. MNIST 7000 images per category train/test splitting: 60k vs 10k 1.2. Image [28,28,1] →[784] 1.3. Input and Output 1.4. Regression VS Classification ???? = ???? ∗ ???...

    1. 手写数字识别简述

    1.1. MNIST

    • 7000 images per category
    • train/test splitting: 60k vs 10k
      在这里插入图片描述

    1.2. Image

    • [28,28,1]
    • →[784]
      在这里插入图片描述

    1.3. Input and Output

    在这里插入图片描述

    1.4. Regression VS Classification

    • 𝑦 = 𝑤 ∗ 𝑥 + 𝑏
      • 𝑦 ∈ 𝑅𝑑
    • 𝑜𝑢𝑡 = 𝑋@𝑊 + b
      • out: [0.1, 0.8, 0.02, 0.08]
    • 𝑝𝑟𝑒𝑑 = 𝑎𝑟𝑔𝑚𝑎𝑥(𝑜𝑢𝑡)
      • pred: 1
      • pred: 2

    在这里插入图片描述

    1.5. Particularly

    在这里插入图片描述

    1.5. Compute Loss

    • 𝑜𝑢𝑡: [1, 10]
    • Y/label: 0~9
      • eg.: 1 → [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
      • eg.: 3 → [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
    • Euclidean Distance(欧式距离): 𝑜𝑢𝑡 → Label
      • MSE

    1.6. In a nutshell

    • 𝑜𝑢𝑡 = 𝑟𝑒𝑙𝑢{𝑟𝑒𝑙𝑢 𝑟𝑒𝑙𝑢 𝑋@𝑊1 + 𝑏1 @𝑊2 + 𝑏2 @𝑊3 + 𝑏3}
    • 𝑝𝑟𝑒𝑑 = 𝑎𝑟𝑔𝑚𝑎𝑥(𝑜𝑢𝑡)
    • 𝑙𝑜𝑠𝑠 = 𝑀𝑆𝐸(𝑜𝑢𝑡, 𝑙𝑎𝑏𝑒𝑙)
    • minimize 𝑙𝑜𝑠𝑠
      • [𝑊1, 𝑏1′, 𝑊2′, 𝑏2′, 𝑊3′ , 𝑏3′ ]

    2. We need TensorFlow

    在这里插入图片描述

    3. Code

    • X and Y
    • 𝑜𝑢𝑡 = 𝑟𝑒𝑙𝑢{𝑟𝑒𝑙𝑢 𝑟𝑒𝑙𝑢 𝑋@𝑊1 + 𝑏1 @𝑊2 + 𝑏2 @𝑊3 + 𝑏3}
    • Compute out&loss
    • Compute gradient and optimize
    • Loop
    import os
    import tensorflow as tf
    from tensorflow import keras
    from tensorflow.keras import layers, optimizers, datasets
    
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
    
    # X and Y
    (x, y), (X_val, y_val) = datasets.mnist.load_data()
    x = tf.convert_to_tensor(x, dtype=tf.float32) / 255
    y = tf.convert_to_tensor(y, dtype=tf.int32)
    y = tf.one_hot(y, depth=10)
    print(x.shape, y.shape)
    train_dataset = tf.data.Dataset.from_tensor_slices((x, y))
    train_dataset = train_dataset.batch(200)
    
    # for step, (x, y) in enumerate(train_dataset):
    #     print(step, x.shape, y, y.shape)
    
    # 𝑜𝑢𝑡 = 𝑟𝑒𝑙𝑢{𝑟𝑒𝑙𝑢 𝑟𝑒𝑙𝑢 𝑋@𝑊1 + 𝑏1 @𝑊2 + 𝑏2 @𝑊3 + 𝑏3}
    model = keras.Sequential([
        layers.Dense(512, activation='relu'),
        layers.Dense(256, activation='relu'),
        layers.Dense(10)
    ])
    
    optimizer = optimizers.SGD(learning_rate=0.001)
    
    
    def train_epoch(epoch):
        # loop
        for step, (x, y) in enumerate(train_dataset):
            with tf.GradientTape() as tape:
                # [b, 28, 28] => [b, 784]
                x = tf.reshape(x, (-1, 28 * 28))
                # compute output
                # [b, 784] => [b, 10]
                out = model(x)
                # compute loss
                loss = tf.reduce_sum(tf.square(out - y)) / x.shape[0]
    
            # optimize and update w1, w2, w3, b1, b2, b3
            grads = tape.gradient(loss, model.trainable_variables)
            # w' = w - lr * grad
            optimizer.apply_gradients((zip(grads, model.trainable_variables)))
    
            if step % 100 == 0:
                print(epoch, step, 'loss:', loss.numpy())
    
    
    def train():
        for epoch in range(300):
            train_epoch(epoch)
    
    
    if __name__ == '__main__':
        train()
    

    4. Pycharm无法对TensorFlow2.0中的Keras模块进行自动补全的解决办法

    • TensorFlow2.0之后,Keras作为其主要模块被官方推荐使用。但是在pycharm中使用tensorflow.keras总是无法弹出自动补全,导致编码效率过慢。其实原因很简单,这就是Pycharm的一个bug。下载使用Pycharm2019.3之后的版本就能解决。
    • 当前(2019年11月21日)2019.3版本还没有正式发布,可以使用Pycharm EAP版本,也就是测试版,链接在此:点我下载

    5. 需要全套课程视频+PPT+代码资源可以私聊我

    • 方式1:CSDN私信我!
    • 方式2:QQ邮箱:594042358@qq.com或者直接加我QQ: 594042358!
    展开全文
  • TensorFlow实现手写数字识别改进版

    千次阅读 2017-11-01 21:22:16
    TensorFlow实现手写数字识别这篇博客中,介绍了通过TensorFlow构造一个神经网络来实现手写数字识别,最后通过MNIST数据集,最后在测试集的识别率大约为91%左右。这篇博客主要对这个程序训练的模型进行优化和...

    TensorFlow实现手写数字的识别这篇博客中,介绍了通过TensorFlow构造一个神经网络来实现手写数字的识别,最后通过MNIST数据集,最后在测试集的识别率大约为91%左右。这篇博客主要对这个程序训练的模型进行优化和准确率的提升。在原来的基础上,增加了指数衰减学习率、L2正则化以及滑动平均模型的应用,关于这三种方式在之前的博客已经介绍过了。

    一、TensorFlow相关函数

    sparse_softmax_cross_entropy_with_logits(_sentinel=None,labels=None, logits=None, name=None)

    功能:计算稀疏的softmax交叉熵通过logits和labels参数,计算离散分类任务的错误的可能性,被分类的类别都是互相独立的。

    参数:

    labels:tensor,类型是int32、int64,它代表每一个正确类别的下标。如,下面的例子中,对于每一个图片都会有一个10维的向量,如[1,0,0,0,0,0,0,0,0,0]这个就代表这张图片对应的数字是0,也就是这个向量为1的下标。

    logits:神经网络的前向传播结果,不包括softmax层。

    返回值:tensor,与labels的大小相同,与logits的数据类型相同,是一个softmax的交叉熵损失值。

    reduce_mean(input_tensor,axis=None,keep_dims=False,name=None,reduction_indices=None)
    功能:根据张量的维度来计算张量的平均值。

    参数:

    input_tensor:需要计算平均值的输入tensor(张量),是一个数字类型的。

    axis:默认是None是对所有的元素求平均值,如果设置为0则是对列求平均值,如果为1则是对行求平均值。

    1、对张量的所有值求平均值

        a = tf.Variable(tf.constant([1.,2.,3.,4.,5.,6.],shape=[2,3]),dtype=tf.float32)
        sess = tf.Session()
        init = tf.initialize_all_variables()
        sess.run(init)
        result = tf.reduce_mean(a)
        print(a.eval(session=sess))
        '''
        [[ 1.  2.  3.]
         [ 4.  5.  6.]]
        '''
        print(result.eval(session=sess))
        #3.5
    2、对张量的列求平均值

        a = tf.Variable(tf.constant([1.,2.,3.,4.,5.,6.],shape=[2,3]),dtype=tf.float32)
        sess = tf.Session()
        init = tf.initialize_all_variables()
        sess.run(init)
        result = tf.reduce_mean(a,0)
        print(a.eval(session=sess))
        '''
        [[ 1.  2.  3.]
         [ 4.  5.  6.]]
        '''
        print(result.eval(session=sess))
        #[ 2.5  3.5  4.5]
    3、对张量的行求平均值

        a = tf.Variable(tf.constant([1.,2.,3.,4.,5.,6.],shape=[2,3]),dtype=tf.float32)
        sess = tf.Session()
        init = tf.initialize_all_variables()
        sess.run(init)
        result = tf.reduce_mean(a,1)
        print(a.eval(session=sess))
        '''
        [[ 1.  2.  3.]
         [ 4.  5.  6.]]
        '''
        print(result.eval(session=sess))
        #[ 2.  5.]
    二、神经网络结构介绍

    1、在之前写的使用神经网络实现手写数字的识别,之前的神经网络是由两层网络组成,第一层是线性层,一共由784*10=7840个权重和10个偏置组成,由于结构比较简单连激活函数也没有,然后通过第二层的softmax层,最后的准确率只有91.8%,我们通过改进这次的准确率可以达到98.4%
    2、这次改进后的结构是由三层结构组成的,第一层是线性层,由784*500个权重和500个偏置组成,然后再通过RELU激活层去线性化,第二层是由500*10个权重和10个偏置组成,然后通过RELU激活层,第三层也是softmax层,除了结构上有改进之外,我们还加了三种对模型的优化算法。

    三、TensorFlow代码实现

    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    
    
    #通过输入,神经网络的参数来进行输出
    def inference(input_tensor,avger,weight1,biase1,weight2,biase2):
        #判断是否使用滑动平均模型
        #不使用滑动平均模型
        if avger == None:
            #计算第一层神经网络的前向传播,并使用RELU激活函数
            layer1 = tf.nn.relu(tf.matmul(input_tensor,weight1) + biase1)
            #计算第二层的神经网络的前向传播
            return tf.matmul(layer1,weight2) + biase2
        #使用滑动平均模型
        else:
            #通过滑动平均模型更新参数,利用更新后的参数进行前向传播计算
            layer1 = tf.nn.relu(tf.matmul(input_tensor,avger.average(weight1))+avger.average(biase1))
            #计算第二层神经网络的前向传播
            return tf.matmul(layer1,avger.average(weight2)) + avger.average(biase2)
    
    
    if __name__ == "__main__":
        #定义第一层网络的输入节点数
        #输入为784是因为,每张手写数字的图片大小为28*28的矩阵,将它转成一维向量就是1*784
        input_node = 784
        #定义最后一层网络的输出节点数
        #输出为一个1*10的向量,正好可以表示0-9,10个数字
        output_node = 10
    
        #定义神经网络的结构
        #定义第一层隐藏层的节点数
        layer1_node = 500
        #定义每次训练图片的张数,可以有效防止内存溢出
        batch_size = 100
        #定义基础的学习率用于指数衰减的学习率中
        learning_rate_base = 0.8
        #设置学习率的衰减率
        learning_rate_decay = 0.99
        #设置L1正则化中,模型复杂度在损失函数中所占的比例
        regularization_rate = 0.0001
        #设置训练的轮数
        training_steps = 30000
        #设置滑动平均的衰减率
        moving_average_decay = 0.99
        #定义输入节点
        x = tf.placeholder(tf.float32,[None,input_node],name="x_input")
        #定义输出节点
        y_ = tf.placeholder(tf.float32,[None,output_node],name="y_output")
        #设置第一层神经网络的权重
        weight1 = tf.Variable(tf.truncated_normal([input_node,layer1_node],stddev=0.1))
        #设置第一层神经网络的偏置
        biase1 = tf.Variable(tf.constant(0.1,shape=[layer1_node]))
        #设置第二层神经网络的权重
        weight2 = tf.Variable(tf.truncated_normal([layer1_node,output_node],stddev=0.1))
        #设置第二层神经网络的偏置
        biase2 = tf.Variable(tf.constant(0.1,shape=[output_node]))
        #计算神经网络的前向传播结果
        #不适用参数的滑动平均值
        y = inference(x,None,weight1,biase1,weight2,biase2)
        #定义滑动平均的global_step
        global_step = tf.Variable(0,trainable=False)
        #初始化滑动平均
        averge = tf.train.ExponentialMovingAverage(moving_average_decay,global_step)
        #定义滑动平均所更新的列表,tf.trainable_variables()获取所有的列表
        variables_averages = averge.apply(tf.trainable_variables())
        #通过滑动平均,获取神经网络的前向传播参数
        averge_y = inference(x,averge,weight1,biase1,weight2,biase2)
        #使用交叉熵作为损失函数
        # cross_entropy = -tf.reduce_sum(y_*tf.log(y))
        cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.argmax(y_,1),logits=y)
        #计算交叉熵的平均值
        cross_entropy_mean = tf.reduce_mean(cross_entropy)
        #计算L2正则化损失函数
        regularizer = tf.contrib.layers.l2_regularizer(regularization_rate)
        #计算模型参数的L2正则化
        regularization = regularizer(weight1) + regularizer(weight2)
        #计算中的损失
        loss = cross_entropy_mean + regularization
        # 下载minist的手写数字的数据集
        mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
        #设置指数衰减学习率
        learning_rate = tf.train.exponential_decay(learning_rate_base,
                                                   global_step,mnist.train.num_examples/batch_size
                                                   ,learning_rate_decay)
        #随机梯度下降优化损失函数
        train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
        #每迭代一次需要更新神经网络中的参数
        train_op = tf.group(train_step,variables_averages)
        correct_prediction = tf.equal(tf.argmax(averge_y,1),tf.argmax(y_,1))
        #计算数据的准确率
        accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
        #初始化会话
        with tf.Session() as sess:
            #初始化参数
            tf.initialize_all_variables().run()
            # 验证数据
            validate_feed = {x: mnist.validation.images, y_: mnist.validation.labels}
            #迭代训练
            for i in range(training_steps):
                batch_x,batch_y = mnist.train.next_batch(batch_size)
                sess.run(train_op,feed_dict={x:batch_x,y_:batch_y})
                if i % 1000 == 0:
                    validate_acc = sess.run(accuracy,feed_dict=validate_feed)
                    print("After %d training step(s),validate accuracy using average"
                          "model is %g" % (i, validate_acc))
    
            # 测试数据
            test_feed = {x: mnist.test.images, y_: mnist.test.labels}
            #训练完成之后,测试测试集的准确率
            test_acc = sess.run(accuracy,feed_dict=test_feed)
            print("After %d training step(s),test accuracy using average"
                  "model is %g"%(training_steps,test_acc))
            #0.9841
            #不使用滑动平均模型的准确率
            #0.9838
            #不使用L2正则化
            #0.9845
            #不使用指数衰减
            #0.9681
    四、总结

    在使用三种优化算法对模型进行优化的时候发现,对模型使用三种优化算法的时候准确率为98.41%(每次运行结果可能不一样,因为模型训练过程的随机因素),只使用正则化和指数衰减算法的时候准确率为98.45%和同时使用三种优化算法的结果差不多。但,如果不是指数衰减算法你会发现在训练过程中,对于验证集的准确率是慢慢的提升上去的,而不是从一开始的10%左右,直接变为了97%。这个结果也能更好的解释了,指数衰减对于模型的作用。





    展开全文
  • 写在前面的话 ...并写了一些自己的认识 环境版本 tensorflow==1.3.0 ...手写数字识别的思路 1、首先,我们用tensorflow官方给出的mnist数据集来训练出一个模型 2、其次,我们用tensorflow官方给出的mnist数据集来测...

    写在前面的话

    文章总结自北京大学曹健老师的mooc,点击查看课程,通过学习,我自己撸了一遍代码,现在放在下面。并写了一些自己的认识

    环境版本

    tensorflow==1.3.0

    python==3.5.6

    操作系统为ubuntu16

    手写数字识别的思路

    1、首先,我们用tensorflow官方给出的mnist数据集来训练出一个模型
    2、其次,我们用tensorflow官方给出的mnist数据集来测试这个模型的精度
    3、将我们自己手写的数字图片喂入神经网络,得出预测结果

    代码思路

    1、我们先设计一个前向传播网络,这个py文件中定义神经络的输入、参数和输出,定义前向传播过程
    get_weight为神经元w参数生成函数
    get_bias为偏置b生成函数
    forward复现了网络的结构

    #0导入模块
    import tensorflow as tf
    
    INPUT_NODE = 784
    OUTPUT_NODE = 10
    LAYER1_NODE = 500
    
    # #定义神经络的输入、参数和输出,定义前向传播过程
    def get_weight(shape, regularizer):
    	w = tf.Variable(tf.truncated_normal(shape, stddev=0.1))#截断的产生正态分布的随机数,即随机数与均值的差值若大于两倍的标准差,则重新生成。stddev:标准差
    	if regularizer != None: tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))#正则化给每个w加权重
    	return w
    
    def get_bias(shape):
    	b = tf.Variable(tf.zeros(shape))
    	return b
    
    def forward(x, regularizer):
    	w1 = get_weight([INPUT_NODE, LAYER1_NODE], regularizer)
    	b1 = get_bias([LAYER1_NODE])
    	y1 = tf.nn.relu(tf.matmul(x, w1) + b1)#非线性函数relu的输出
    
    	w2 = get_weight([LAYER1_NODE, OUTPUT_NODE], regularizer)
    	b2 = get_bias([OUTPUT_NODE])
    	y = tf.matmul(y1, w2) + b2 #输出层不过激活函数,因为要保证概率分布的均匀?
    	return y
    
    

    2、在forward.py文件中,我们定义了神经网络的一些个参数,解释如代码注释,其中我们定义了代码的反向传播纠正参数的结构。定义了ckpt来实现断点续训,并在控制台输出了训练的情况即损失 值的大小。

    #0导入模块,生成模拟数据集
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    import mnist_forward
    import os
    
    BATCH_SIZE = 200#每轮训练喂入数据的量
    LEARNING_RATE_BASE = 0.1#学习率
    LEARNING_RATE_DECAY = 0.99#指数衰减率
    REGULARIZE = 0.0001#正则化权重
    STEPS = 50000
    MOVING_AVERAGE_DECAY = 0.99#衰减因子
    MODEL_SAVE_PATH = "./model/"
    MODEL_NAME = "mnist_model"
    
    def backward(mnist):
    	x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])
    	y_ = tf.placeholder(tf.float32, [None, mnist_forward.OUTPUT_NODE])
    	y = mnist_forward.forward(x, REGULARIZE)#复现网络结构,推算出预测值
    	global_step = tf.Variable(0, trainable=False)
    	#定义损失函数,引入了正则化的损失函数,并和交叉熵一起使用
    	ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))#计算logits和labels之间的稀疏softmax交叉熵
    	cem = tf.reduce_mean(ce)
    	loss = cem + tf.add_n(tf.get_collection('losses'))
    	#定义指数衰减学习率
    	learning_rate = tf.train.exponential_decay(
    		LEARNING_RATE_BASE,
    		global_step,
    		mnist.train.num_examples/BATCH_SIZE,
    		LEARNING_RATE_DECAY,
    		staircase=True)#如果staircase=True,那就表明每decay_steps次计算学习速率变化,更新原始学习速率,如果是False,那就是每一步都更新学习速率
    
    	#定义反向传播方法:包涵正则化
    	train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
    	#滑动平均值
    	ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    	ema_op = ema.apply(tf.trainable_variables())
    	with tf.control_dependencies([train_step, ema_op]):
    		train_op = tf.no_op(name='train')
    
    	saver = tf.train.Saver()
    
    	with tf.Session() as sess:
    		init_op = tf.global_variables_initializer()
    		sess.run(init_op)
    
    		ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
    		if ckpt and ckpt.model_checkpoint_path:
    			saver.restore(sess, ckpt.model_checkpoint_path)
    
    		for i in range(STEPS):
    			xs, ys = mnist.train.next_batch(BATCH_SIZE)
    			_, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs,y_: ys})
    			if i % 1000 == 0:
    				print("After %d training step(s), loss on training batch is %g."%(step, loss_value))
    				saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=global_step)
    
    def main():
    	mnist = input_data.read_data_sets("./data/", one_hot=True)
    	backward(mnist)
    
    if __name__ == '__main__':
    	main()
    

    3、以上神经网络的结构就算实现了,我们既然已经得到了这个模型,就肯定想知道这个模型是否可以解决我们现在要面临的问题,我们编写一个测试代码来检查神经网络的模型精度。测试集代码也是tensorflow官方给出的mnist数据集。我们复现这个网络,并测试效果,基本上一轮之后你就能观察到精确率达到了90%+。

    import time
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    import mnist_forward
    import mnist_backward
    TEST_INTNERVAL_SECS = 10
    
    def test(mnist):
    	with tf.Graph().as_default() as g:
    		x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])
    		y_ = tf.placeholder(tf.float32, [None, mnist_forward.OUTPUT_NODE])
    		y = mnist_forward.forward(x, None)
    
    		ema = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
    		ema_restore = ema.variables_to_restore()
    		saver = tf.train.Saver(ema_restore)
    
    		correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    		accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    
    		while True:
    			with tf.Session() as sess:
    				ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)
    				if ckpt and ckpt.model_checkpoint_path:
    					saver.restore(sess, ckpt.model_checkpoint_path)
    					global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
    					accuracy_score = sess.run(accuracy, feed_dict={x: mnist.test.images, y_:mnist.test.labels})
    					print("After %s training step(s), test accuracy = %g"%(global_step, accuracy_score))
    				else:
    					print('No checkpoint file found')
    					return
    			time.sleep(TEST_INTNERVAL_SECS)
    
    def main():
    	mnist = input_data.read_data_sets("./data/", one_hot=True)
    	test(mnist)
    
    if __name__ == '__main__':
    	main()
    

    4、最后,自己愉快地拍下一张照片,来看看这个亲儿子模型是不是好使。粘一下代码:

    import tensorflow as tf
    import numpy as np
    import mnist_forward
    import mnist_backward
    from PIL import Image
    
    
    def restore_model(testPicArr):
    	#创建一个默认图,在该图中执行以下操作(多数操作和train中一样)
    	with tf.Graph().as_default() as tg:
    		x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])
    		y = mnist_forward.forward(x, None)
    		preValue = tf.argmax(y, 1)#得到概率最大的预测值
    
    		variable_averages = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
    		variable_to_restore = variable_averages.variables_to_restore()
    		saver = tf.train.Saver(variable_to_restore)
    
    		with tf.Session() as sess:
    			#chevkpoint 文件定位到最新保存的模型
    			ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)
    			if ckpt and ckpt.model_checkpoint_path:
    				saver.restore(sess, ckpt.model_checkpoint_path)
    
    				preValue = sess.run(preValue, feed_dict={x:testPicArr})
    				return preValue
    			else:
    				print("No checkpoint file found'")
    				return -1
    
    
    def pre_pic(picName):
    	img = Image.open(picName)
    	reIm = img.resize((28,28), Image.ANTIALIAS)
    	im_arr = np.array(reIm.convert('L'))
    	threshold = 180#设定合理的阈值
    	for i in range(28):
    		for j in range(28):
    			im_arr[i][j] = 255 - im_arr[i][j]
    			if(im_arr[i][j] < threshold):
    				im_arr[i][j] = 0
    			else:
    				im_arr[i][j] = 255
    
    	nm_arr = im_arr.reshape([1, 784])
    	nm_arr = nm_arr.astype(np.float32)
    	img_ready = np.multiply(nm_arr, 1.0/255.0)
    
    	return img_ready
    
    def application():
    	# testNum = int(input("input the number of test pictures:"))
    	testNum = 1
    	for i in range(testNum):
    		# testPic = input("the path of test pictures:")
    		testPic = 'pic/1.jpg'
    		testPicArr = pre_pic(testPic)
    		preValue = restore_model(testPicArr)
    		print("The prediction number is : ", preValue)
    
    
    if __name__ == '__main__':
    	application()
    
    

    5、图片如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    识别结果如下:

    root@iZ2zef0icee95uw35ttpgmZ:/home/kai/mnist# python3 hand_write_app.py
    The prediction number is :  [2]
    root@iZ2zef0icee95uw35ttpgmZ:/home/kai/mnist# cd pic
    root@iZ2zef0icee95uw35ttpgmZ:/home/kai/mnist/pic# ls
    1.jpg
    root@iZ2zef0icee95uw35ttpgmZ:/home/kai/mnist/pic# cd ./
    root@iZ2zef0icee95uw35ttpgmZ:/home/kai/mnist/pic# cd ../
    root@iZ2zef0icee95uw35ttpgmZ:/home/kai/mnist# python3 hand_write_app.py
    The prediction number is :  [7]
    root@iZ2zef0icee95uw35ttpgmZ:/home/kai/mnist# python3 hand_write_app.py
    The prediction number is :  [5]
    
    

    6、分析:
    大家先只看[ ]里面的输出结果,因为中间我使用pscp拷贝替换了图片
    识别了三张图片,最后一张6识别成了5,其他两张识别正确,思考和心得体会见下文

    ---------- 代码已经结束了,就是上面的四个py文件,接下来你看到的是我的分析过程 ------

    心得体会

    分析一:这里我使用了三张图片,一开始都不能识别,后来我经过调试,发现是阈值 threshold 给的太低了,我一开始给的是50,然后一张也识别不了,代码是没有错的,应该就是在图像预处理这方面出了差错,我先打印输出了 1图片的灰度矩阵 和 2当阈值为50时的 图片灰度反转后的值 和 3当阈值为50时的 图片的样子,测试结果如下:
    1图片的灰度矩阵
    在这里插入图片描述
    2当阈值为50时的 图片灰度反转后的值 :明显看出阈值选择错误导致2的特征失真
    在这里插入图片描述
    3当阈值为50时的 图片的样子:
    自己脑补一下,反正全是黑的不能训练
    分析二:
    当阈值为180,我自己调的参数结果明显变好,全是明显的轮廓,所以可以用于训练。

    结论

    图像的预处理真的很重要,我们要保证图片的特征存在。

    展开全文
  • 这次我们要实现的是用一个两层的神经网络实现手写数字识别。样本的话网上一搜就有,样本包含了四个压缩文件,分别是六万张训练图片和标签,一万张测试图片和标签。 2、上代码 #实现手写数字识别,softmax分类(简单...
  • 本系列为应用TensorFlow实现手写数字识别应用的全过程的代码实现及细节讨论。按照实现流程,分为如下几部分: 1. 模型训练并保存模型 2. 通过鼠标输入数字并保存 2. 图像预处理 4. 读入模型对输入的图片进行识别...
  • TensorFlow - 手写数字识别 (卷积神经网络实现) 手写数字识别 (MNIST), 多类分类 (multiclass classification) 问题 flyfish ReLU dropout tf.nn.conv2d import tensorflow as tf import tensorflow.examples...
  • Tensorflow框架为深度学习工具的应用已经相当广泛,卷积神经网络是一类包含卷积运算且具有深度结构的前馈神经网络,采用反向传播(Back Propagation,BP)算法对模型进行学习训练,手写字体识别模型LeNet5诞生于1994...
  • 1、mnist数据集转图片 ...os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import tensorflow as tf import numpy as np from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets from ...
  • #import tensorflow as tf import tensorflow.compat.v1 as tf tf.disable_v2_behavior() #解决tf.placeholder报错问题 import matplotlib.pyplot as plt import input_data #使用的数据库是tensorflow内置数据库,...
  • 二、MLP算法实现手写数字识别 通过学习林大贵老师的《TensorFlow+Keras深度学习人工智能实践应用》,对图像处理的过程有了较浅薄的理解,在此与大家分享,同时由于上书中提供的代码下载页面失效,笔者按照书本中的...
  • tensorflow实现手写数字识别(使用深度神经网络) 一.MNIST 数据集是经典的手写体数字数据集。使用深度神经网络。 分类该数据集。测试精度。(此程序参考于网络平台上) 步骤:创建数据,搭建模型,计算误差,传播...
  • 本系列为应用TensorFlow实现手写数字识别应用的全过程的代码实现及细节讨论。按照实现流程,分为如下几部分: 1. 模型训练并保存模型 2. 通过鼠标输入数字并保存 2. 图像预处理 4. 读入模型对输入的图片进行识别...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 732
精华内容 292
关键字:

tensorflow2手写数字识别