GeorgeYang'Blog

my technology blog

python3使用tensorflow构建CNN卷积神经网络识别实践

阅读:1929 创建时间:2018-04-13 22:56:59 tags:[None]

前言

鄙人菜鸟,最近在做一个人脸分类的项目,由于不是专业,所以搞这个东西遇到不少坑,在这里做个记录,方便自己检索和搜索寻找相关答案的人。


卷积神经网络(Convolutional Neural Network,CNN)是一种前馈神经网络,是多层感知机(MLP)的变种,由详细介绍得知,它在图片识别方面做到在即使物体有位移或轻微变形的时候,也能完成识别。

卷积神经网络相关代码及注意事项

  • 基本代码

csdn有一片搜索排名比较高的比较好用的cnn训练代码:https://www.cnblogs.com/denny402/p/6931338.html 它是简单的花种分类识别,通过理解cnn码的含义,很容易就可以做出水果种类识别、动物种类分类等等(当然前提有足够的数据喂给机器)

  • 保存模型

假设你已经掌握了上面的代码,可以训练花种,也知道如何训练动物分类,甚至知道如何修改参数,更改模型,那么既然懂得训练了,就要在训练完成之后保存模型,以便取出训练结果对训练图片数据外的图片等资源进行分类识别,所以你需要用到保存模型的代码:

 saver = tf.train.Saver()#默认保存所有的变量
 save_path = saver.save(sess, path + "saveNet.ckpt")
 print("Save to path: ", save_path)


 也可以指定需要保存的变量:
 saver = tf.train.Saver(var_list=lst_vars)
 也可以增加变量
 详细操作看:https://stackoverflow.com/questions/48161147/error-restoring-model-in-tensorflow-after-changing-the-optimizer-paramter/48212514#48212514


 如果训练次数很多,可以使用定期保存
 aver = tf.train.Saver(...variables...)
 sess = tf.Session()
 for step in xrange(999999999):
     sess.run(...)
     if step % 1000 == 0:
         # 1000步保存一次模型
         saver.save(sess, 'saveNet.ckpt', global_step=step)

- 恢复使用模型

保存成功之后会生成*.ckpt,使用如下代码进行模型恢复

 saver=tf.train.Saver()
 sess=tf.Session()
 sess.run(tf.global_variables_initializer())
 if os.path.exists(model_path+'.ckpt.meta'):
     #保存时用.kept,保存成功后生成了多个文件,加载*.kept.meta文件即可
     saver.restore(sess,model_path)
     print('restore')

模型保存成功后,要使用模型,如果保存模型的时候有预先存储:logits的话:

     #.......restore code....
     graph = tf.get_default_graph()
     x = graph.get_tensor_by_name("x:0")
     feed_dict = {x:data}

     logits = graph.get_tensor_by_name("logits_eval:0")

     classification_result = sess.run(logits,feed_dict)

     #打印出预测矩阵
     print(classification_result)
     #打印出预测矩阵每一行最大值的索引
     print(tf.argmax(classification_result,1).eval())
     #根据索引通过字典对应花的分类
     output = []
     output = tf.argmax(classification_result,1).eval()
     for i in range(len(output)):
         print("第",i+1,"朵花预测:"+flower_dict[output[i]])

参考:https://blog.csdn.net/Enchanted_ZhouH/article/details/74116823 这篇文章的代码可以存储模型和恢复模型进行预测,但是没有讲到如果对模型进行再次训练。

  • 继续训练

使用模型继续训练代码如下:

 #-----------------构建网络----------------------
 #占位符
 x=tf.placeholder(tf.float32,shape=[None,w,h,c],name='x')
 y_=tf.placeholder(tf.int32,shape=[None,],name='y_')


 #---------------------------网络结束---------------------------
 regularizer = tf.contrib.layers.l2_regularizer(0.0001)
 logits = cnnNet.inference(x,False,regularizer)

 #(小处理)将logits乘以1赋值给logits_eval,定义name,方便在后续调用模型时通过tensor名字调用输出tensor
 b = tf.constant(value=1,dtype=tf.float32)
 logits_eval = tf.multiply(logits,b,name='logits_eval')

 loss=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y_)
 train_op=tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
 correct_prediction = tf.equal(tf.cast(tf.argmax(logits,1),tf.int32), y_)
 acc= tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

 n_epoch=2000
 batch_size=32
 saver=tf.train.Saver()
 sess=tf.Session()
 sess.run(tf.global_variables_initializer())
 if os.path.exists(model_path+'.meta'):
     saver.restore(sess,model_path)
     print('restore')
 else:
     print('没找到可恢复的模型,开始训练第一份')
 for epoch in range(n_epoch):
     start_time = time.time()

     #training
     train_loss, train_acc, n_batch = 0, 0, 0
     for x_train_a, y_train_a in minibatches(x_train, y_train, batch_size, shuffle=True):
         _,err,ac=sess.run([train_op,loss,acc], feed_dict={x: x_train_a, y_: y_train_a})
         train_loss += err; train_acc += ac; n_batch += 1
     print("   train loss: %f" % (np.sum(train_loss)/ n_batch))
     print("   train acc: %f" % (np.sum(train_acc)/ n_batch))

     #validation
     val_loss, val_acc, n_batch = 0, 0, 0
     for x_val_a, y_val_a in minibatches(x_val, y_val, batch_size, shuffle=False):
         err, ac = sess.run([loss,acc], feed_dict={x: x_val_a, y_: y_val_a})
         val_loss += err; val_acc += ac; n_batch += 1
     print("   validation loss: %f" % (np.sum(val_loss)/ n_batch))
     print("   validation acc: %f" % (np.sum(val_acc)/ n_batch))
 saver.save(sess,model_path)
 sess.close()
  • 实践:在opencv上使用摄像头取人脸进行性别识别

    import time from PIL import Image, ImageFont, ImageDraw import tensorflow as tf import numpy as np import os import cv2 import glob from tf import cnnNet

    #cv 初始化

    face_cascade = cv2.CascadeClassifier('......./OpenCV/haarcascades/haarcascade_frontalface_alt.xml') font = ImageFont.truetype("......ttf", 20, encoding="utf-8")

    #数据集地址 path='/Volumes/SDCard/img/sex/' #模型保存地址 model_path = path + "model.ckpt"

    sex_dict = {0:'男',1:'女'}

    w=100 h=100 c=3

    x_=tf.placeholder(tf.float32,shape=[None,w,h,c],name='x') y_=tf.placeholder(tf.int32,shape=[None,],name='y_')

    regularizer = tf.contrib.layers.l2_regularizer(0.0001) logits = cnnNet.inference(x_,False,regularizer)

    loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y_, name='loss')

    train_op=tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)

    correct_prediction = tf.equal(tf.cast(tf.argmax(logits,1),tf.int32), y_) acc= tf.reduce_mean(tf.cast(correct_prediction, tf.float32),name="accuracy",)

    lst_vars = [] for v in tf.global_variables(): lst_vars.append(v)

    saver = tf.train.Saver(var_list=lst_vars)

    with tf.Session() as sess: sess.run(tf.global_variables_initializer())

     print(os.listdir(path))
     lastCheckPoint = tf.train.latest_checkpoint(path+"/")
     if not lastCheckPoint:
         lastCheckPoint = model_path + ".meta"
     print(lastCheckPoint)
     saver.restore(sess,lastCheckPoint)
    
     cap = cv2.VideoCapture(0)
     cap.set(3, 640)  # 设置分辨率
     cap.set(4, 480)
     while (True):
         ret, frame = cap.read()
         faceRects = face_cascade.detectMultiScale(
             frame,
             scaleFactor=1.15,
             minNeighbors=5,
             minSize=(32, 32)
         )
    
         if len(faceRects) > 0:  # 大于0则检测到人脸
             for faceRect in faceRects:  # 单独框出每一张人脸
                 x, y, w, h = faceRect
                 cv2.rectangle(frame, (x - 10, y - 10), (x + w + 10, y + h + 10), (0, 255, 0), 3)  # 5控制绿色框的粗细
                 img = Image.fromarray(frame[y:y + h, x:x + w])
                 imgData = img.resize((100, 100), Image.ANTIALIAS)
                 # data = [np.array(imgData).astype('float')]
                 data = [np.asarray(imgData,dtype=np.float32)]
                 # cv2.imshow("frame", data)#测试
    
                 feed_dict = {x_: data}
                 classification_result = sess.run(logits, feed_dict)
    
                 # 打印出预测矩阵
                 # print(classification_result)
                 # 打印出预测矩阵每一行最大值的索引
                 # print(tf.argmax(classification_result, 1).eval())
                 # 根据索引通过字典对应花的分类
                 output = []
                 output = tf.argmax(classification_result, 1).eval()
                 if output[0]<1 :
                     print(classification_result)
    
                 text = ""
                 for i in range(len(output)):
                     # print("性别识别结果:" + sex_dict[output[i]])
                     text = sex_dict[output[i]]
    
                 pil_im = Image.fromarray(frame)
                 draw = ImageDraw.Draw(pil_im)
    
                 fontSize = font.getsize(text)
                 draw.text((x + w / 2 - fontSize[0] / 2, y), text, (0, 0, 255), font=font)
                 frame = cv2.cvtColor(np.array(pil_im), cv2.COLOR_RGBA2RGB)
             cv2.imshow("test", frame)
         else:
             cv2.imshow('test', frame)
    
         if cv2.waitKey(1) & 0xFF == ord('q'):
             break
    

    # When everything done, release the capture cap.release() cv2.destroyAllWindows()

该代码使用opencv识别人脸后,在剪裁人脸成100*100矩形给tensorflow做cnn分类,把分类结果标注在人脸框内的上方事实输出显示。挺有意思的一个程序。

代码已经上传到csdn: https://download.csdn.net/download/u010499721/10347651