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框架的大牛,恰好看到了也不要笑话我写的稚嫩,纯粹是记录,增强记忆,博你一笑!哈哈哈,这下女朋友知道我在干嘛了吧!

  • 相关阅读:
    Python元组、列表、字典
    测试通过Word直接发布博文
    Python环境搭建(windows)
    hdu 4003 Find Metal Mineral 树形DP
    poj 1986 Distance Queries LCA
    poj 1470 Closest Common Ancestors LCA
    poj 1330 Nearest Common Ancestors LCA
    hdu 3046 Pleasant sheep and big big wolf 最小割
    poj 3281 Dining 最大流
    zoj 2760 How Many Shortest Path 最大流
  • 原文地址:https://www.cnblogs.com/kerwins-AC/p/9948841.html
Copyright © 2011-2022 走看看