zoukankan      html  css  js  c++  java
  • Tensorflow编程基础之Mnist手写识别实验+关于cross_entropy的理解

    好久没有静下心来写点东西了,最近好像又回到了高中时候的状态,休息不好,无法全心学习,恶性循环,现在终于调整的好一点了,听着纯音乐突然非常伤感,那些曾经快乐的大学时光啊,突然又慢慢的一下子出现在了眼前,不知道我大学的那些小伙伴们现在都怎么样了,考研的刚刚希望他考上,实习的菜头希望他早日脱离苦海,小瑞哥希望他早日出成果,范爷熊健研究生一定要过的开心啊!天哥也哥早日结婚领证!那些回不去的曾经的快乐的时光,你们都还好吗!

    最近开始接触Tensorflow,可能是论文里用的是这个框架吧,其实我还是觉得pytorch更方便好用一些,仔细读了最简单的Mnist手写识别程序,觉得大同小异,关键要理解Tensorflow的思想,文末就写一下自己看交叉熵的感悟,絮叨了这么多开始写点代码吧! 

      2 # -*- coding: utf-8 -*-
      
    """ 3 Created on Sun Nov 11 16:14:38 2018 4 5 @author: Yang 6 """ 7 8 import tensorflow as tf 9 from tensorflow.examples.tutorials.mnist import input_data 10 11 mnist = input_data.read_data_sets("/MNIST_data",one_hot=True) #从input_data中读取数据集,使用one_hot编码 12 13 import pylab #画图模块 14 15 tf.reset_default_graph()#重置一下图 图代表了一个运算过程,包含了许多Variable和op,如果不重置一下图的话,可能会因为某些工具重复调用变量而报错 16 17 x = tf.placeholder(tf.float32,[None,784])#占位符,方便用feed_dict进行注入操作 18 y = tf.placeholder(tf.float32,[None,10])#占位符,方便用feed_dict进行注入操作
    20 21 W = tf.Variable(tf.random_normal([784,10]))#要学习的参数统一用Variable来定义,这样方便进行调整更新 22 b = tf.Variable(tf.zeros([10])) 23 24 25 #construct the model 26 pred = tf.nn.softmax(tf.matmul(x,W) + b) #前向的计算过程 就这一句没错,就这一句,一个简单的函数来实现分类! 27 28 cost = tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),reduction_indices=1))#计算损失的过程,cost reduction_indices=1代表了按照行进行求和,这其实是人为实现的cross_entropy 29 30 learning_rate = 0.01#定义学习率 31 32 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost) #定义优化函数,利用GradienDescent来让cost最小化 33 34 #set parameters about thee model 35 training_epoch = 25 #训练迭代次数 epoch 36 batch_size = 100 #每次训练用多少的batch_size数据 37 display_step = 1 38 saver = tf.train.Saver() #创建一个用于保存模型的saver 39 model_path = "log/kerwinsmodel.ckpt" #模型保存的路径 40 41 #start the session start a session 开始一个会话,所有的变量只有在会话里才能流动起来,也就是定义的计算都是仅仅定义而已,只有session启动了才真正的开始分配给GPU进行计算 42 43 with tf.Session() as sess : 44 sess.run(tf.global_variables_initializer()) #先将所有的变量进行初始化一下,个人认为这就相当于在图里给各个变量上户口! 45 46 for epoch in range(training_epoch): #大的epoch迭代 47 avg_cost = 0 48 total_batch = int(mnist.train.num_examples/batch_size)#计算总共有多少个epoch 49 print(total_batch) 50 for i in range(total_batch): #一个batch 一个batch的开始迭代! 51 batch_xs,batch_ys = mnist.train.next_batch(batch_size)#取一个batch出来 52 53 _,c = sess.run([optimizer,cost],feed_dict={x:batch_xs,y:batch_ys})#开始计算optimizer和cost,真正的计算正是从这里开始的!因为优化得到的结果我们无所谓所以用_表示,c代表cost 54 55 avg_cost += c/ total_batch#这里我一开始没想明白,为什么一开始就用total_epoch进行相除?可能中间变量不准也没关系吧! 56 if (epoch +1 ) % display_step ==0: 57 print("Epoch:",'%04d' %(epoch+1),"cost=","{:.9f}".format(avg_cost)) #将每个epoch的loss和avg_cost输出来 58 59 print("Finish!")#这样训练就算结束了 60 61 correct_prediction = tf.equal(tf.argmax(pred,1),tf.argmax(y,1)) #利用当前学得的参数进行一个预测,判断和label是否相同 62 accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))#进行精确度的判断,tf.cast就指的是类型转换函数,reduce_mean就是求出这一个batch的平均 63 print("Accuracy:",accuracy.eval({x:mnist.test.images,y:mnist.test.labels}))#验证精确度 #这里果然有一个feed_dict进行注入!因为要不然没有办法进行测试啊!数据从哪里来呢?mnist.test 64 65 save_path = saver.save(sess,model_path) #模型的保存路径,将整个session保存下来,可以理解为将整个桌布包起来,菜肯定都在里面了 66 print("Model saved in file: %s" % save_path)#输出模型保存的路径 67 # 68 69 70 #读取模型程序 71 72 print("Starting 2nd session...")#读取模型 73 with tf.Session() as sess: 74 sess.run(tf.global_variables_initializer())#将所有的变量都初始化一遍 75 saver.restore(sess,model_path)#重载模型 76 77 #测试model 78 correct_prediction = tf.equal(tf.arg_max(pred,1),tf.argmax(y,1))#直接进行计算 79 #计算准确率 80 accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) 81 print("Accuracy:",accuracy.eval({x:mnist.test.images,y:mnist.test.labels}))#和刚才同样的方法,都是在测试数据集上进行计算精确度结果! 82 83 output = tf.argmax(pred,1) 将输出的labels得到 84 batch_xs,batch_ys = mnist.train.next_batch(2)从batch_size里面取两个 85 outputval,predv = sess.run([output,pred],feed_dict={x:batch_xs})计算输出和预测! 86 print(outputval,predv,batch_ys) #将输出的labels,整个预测的结果,和真实的labels全都输出来 87 88 im = batch_xs[0] 89 im = im.reshape(-1,28) 90 pylab.imshow(im) 91 pylab.show() #测试一下 92 93 im = batch_xs[1] 94 im = im.reshape(-1,28) 95 pylab.imshow(im) 96 pylab.show() 97 98 99 100

     到这里,整个Mnist识别的实验就做完了,可以看出其实不管是pytorch框架还是Tensorflow的框架,感觉在基础的实现上都是大同小异的,Tensorflow果然在编程上更复杂一些,好像pytorch就是没有那么多复杂繁琐的工作,就好像是两个画家在作画,比拼谁的实力更强,但是确实两个完全不同的绘画顺序,Tensorflow就像是画家画龙,整个龙都画完了也没有用,必须得点睛!而session就是龙的眼睛!但是pytorch就像是画家将龙的每一部分都画的生龙活虎,栩栩如生,画完爪子它就已经可以挠伤你了,哈哈哈,太形象了!

    最后用一个小小的实验解释一下tensorflow里面该如何正确的用好Softmax和cross_entropy:

    # -*- coding: utf-8 -*-
    """
    Created on Mon Nov 12 20:04:10 2018
    
    @author: Yang
    """
    import tensorflow as tf
    
    labels = [[0,0,1],[0,1,0]]
    logits = [[2,0.5,6],[0.1,0,3]]
    
    logits_scaled = tf.nn.softmax(logits)
    logits_scaled2 = tf.nn.softmax(logits_scaled)
    
    result1  =  tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits = logits)#直接用softmax_cross_entropy
    results2 =  tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits=logits_scaled)#softmax之后再用softmax_cross_entropy
    results3 =  -tf.reduce_sum(labels*tf.log(logits_scaled),1)
    
    with tf.Session() as sess:
        
        print("softmax之后的结果scaled=" ,sess.run(logits_scaled))
        print("两次softmax之后的结果:",sess.run(logits_scaled2))
        
        print("##############")
        print("直接用logits进行softmax_cross_entropy:",sess.run(result1),"
    ")
        print("softmax之后再用softmax_cross_entropy:",sess.run(results2),"
    ")
        print("自己实现的cross_entropy用softmax之后的结果",sess.run(results3))

    结果是这样的:

    softmax之后的结果scaled= [[0.01791432 0.00399722 0.97808844]
                  [0.04980332 0.04506391 0.90513283]]
    两次softmax之后的结果:

                [[0.21747023 0.21446465 0.56806517]
                [0.2300214 0.22893383 0.5410447 ]]
    #####################################################
    直接用logits进行softmax_cross_entropy: [0.02215516 3.0996735 ]

    softmax之后再用softmax_cross_entropy: [0.56551915 1.4743223 ]

    自己实现的cross_entropy用softmax之后的结果 [0.02215518 3.0996735 ]

    下面来解释下为什么会有这样的结果,softmax之前三个变量的求和明显是大于1的,经过了softmax之后求和的结果等于1了,变成了相对概率的形式,如果再进行一次softmax你会发现概率明显发生了较大的偏移,概率代表的label其实已经不那么明显了!所以两次softmax很明显是错误的结果!

    再看下面cross_entropy的调用:

    直接用logits进行softmax_cross_entropy的计算第一个结果较小,因为它的数据和它的labels差异较小,数据:[2,0.5,6] 而label:[0,0,1] 所以交叉熵较小,但是第二个数据和label的差异明显就比较大,所以对应它的交叉熵就比较大,所以直接用logtis数据带入到softmax_crossentropy里面其实是正确的结果!

    而下面就是将softmax的结果再带入到softmax_cross_entropy里面去,很明显后面的结果不如第一次的直观,因为差异变小了很多,为什么会这样,因为两次softmax之后概率发生了偏移,差异化变小所以cross_entropy得结果就相应的改变了!

    可能会有读者有疑问,那我如果已经进行了softmax,岂不是到了没有损失函数可以用的尴尬地步了?错,第三个结果告诉了我们答案,我们完全可以用自己实现的cross_entropy函数啊,不必非得调用现成的,就是一个-tf.reduce_sum(labels*tf.log(logits))就可以实现相同的结果了,可以发现第三个和第一个数据的结果都是相同的,不过一个调用了封装,一个是自己实现的,完全一样!

    好啦,简单的Tensorflow的介绍就结束了,如果您是Tensorflow框架的大牛,恰好看到了也不要笑话我写的稚嫩,纯粹是记录,增强记忆,博你一笑!哈哈哈,这下女朋友知道我在干嘛了吧!

  • 相关阅读:
    linux基础
    模块三、企业实战案例
    模块二、shell脚本逻辑结构
    模块一:shell 脚本基础
    三剑客、shell脚本
    定时任务、用户管理、磁盘介绍
    python笔记03
    文件属性、正则表达式、文件权限
    Linux系统目录结构介绍
    Linux基础及入门介绍
  • 原文地址:https://www.cnblogs.com/kerwins-AC/p/9948841.html
Copyright © 2011-2022 走看看