环境介绍:
Balabalabala
任何东西的起步都是把它的环境给搭建好,关于tensorflow的环境搭建网上一众博客这里就不多说了,自己使用的是Anaconda那套安装流程。这次代码还需要的一些其他python库,大家可以在跑的时候发现哪个no moudle了在install即可。
总的来说代码的大致情况如下:
1.搭建工具:windows +tensorflow 1.4.0 + python 3.5 + opencv3
2.训练代码:test3.py
训练的代码cmd运行就好了,你要做的就是双手离开键盘睡一觉第二天就能跑完。训练后的模型保存为ckpt1 文件夹,里面有四种文件
3.识别代码:hahaha.py(不要在意我丢死人的文件名)
在cmd 窗口运行hahaha.py。
cmd 窗口显示让你选择识别图片(G)或者视频流(V)识别。
①选择图片识别
输入图片路径,自动弹出识别框,人脸部分画框,cmd 窗口显示学号。
②选择摄像头视频流识别
按下英文字母“s”,会进行识别,画人脸框,cmd 窗口显示学号。
按下英文字母“q”,结束识别。
注:如果像素过低,此时不会在人脸部分画框,而是识别整个画面。如果像素不低,会在人脸部分画框。
废话不多说来看代码吧(最后会给出完整源码):
训练代码test3.py:
# -*- coding: utf-8 -*-
from skimage import io,transform
import glob
import os
import tensorflow as tf
import numpy as np
import time
导包不多说,有报moudle XXX没有的去Anaconda环境里装上就好
接下来是一系列准备工作,我们的训练集是由60个同学每人500张经过裁剪的128*128的jpg图片构成的,每个人的500张照片都装在由其学号构成的文件夹中(如下图)
所以我们的准备工作分为两部分:
1.练集目录下读取60*500张照片resize统一一下大小,并且更重要的是,伴随着打开每一个子文件夹,我们要为其设置一个labels,一个文件夹的500张照片对应一个label,共60个label,这是后面检验acc的唯一指标,即是否能把测试集的照片通过我们的网络输出到指定出口得到正确的label。
path='D:/code/python/Anaconda3/envs/faces'
#将所有的图片resize成100*100
w=128
h=128
c=3
#读取图片
def read_img(path):
cate=[path+'/'+x for x in os.listdir(path) if os.path.isdir(path+'/'+x)]
imgs=[]
labels=[]
for idx,folder in enumerate(cate):
for im in glob.glob(folder+'/*.png'):
print('reading the images:%s'%(im))
img=io.imread(im)
img=transform.resize(img,(w,h,c))
imgs.append(img)
labels.append(idx)
return np.asarray(imgs,np.float32),np.asarray(labels,np.int32)
data,label=read_img(path)
当然,为了我们后边批量拿数据时候不会只拿到同一个人的几十张图片而尽量是几十个人的不同图片,我们借用np的一些函数将他们打乱一下顺序。
#打乱顺序
num_example=data.shape[0]
arr=np.arange(num_example)
np.random.shuffle(arr)
data=data[arr]
label=label[arr]
2.第二个步骤就是在这30000张照片里二八分成验证集和训练集
#将所有数据分为训练集和验证集
ratio=0.8
s=np.int(num_example*ratio)
x_train=data[:s]
y_train=label[:s]
x_val=data[s:]
y_val=label[s:]
这里需要定义一个函数,为了最后训练时候一批一批的传入数据而不是几万张一起丢
#定义一个函数,按批次取数据
def minibatches(inputs=None, targets=None, batch_size=None, shuffle=False):
assert len(inputs) == len(targets)
if shuffle:
indices = np.arange(len(inputs))
np.random.shuffle(indices)
for start_idx in range(0, len(inputs) - batch_size + 1, batch_size):
if shuffle:
excerpt = indices[start_idx:start_idx + batch_size]
else:
excerpt = slice(start_idx, start_idx + batch_size)
yield inputs[excerpt], targets[excerpt]
之后进入正式的构建CNN的步骤,首先是两个占位符,使用占位符的原因教程说的很清楚了,为了不使网络过于庞大二设计的
#-----------------构建网络----------------------
#占位符
x=tf.placeholder(tf.float32,shape=[None,w,h,c],name='x')
y_=tf.placeholder(tf.int32,shape=[None,],name='y_')
四个卷积层按照tesorflow1.0以后的版本按照参数要求填入对应的数值即可,具体每个参数的要求大家看看官方教程对应了解。同理几个全连接层也是如此。
def CNNlayer():
#第一个卷积层(128——>64)
conv1=tf.layers.conv2d(
inputs=x,
filters=32,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool1=tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)
#第二个卷积层(64->32)
conv2=tf.layers.conv2d(
inputs=pool1,
filters=64,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool2=tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)
#第三个卷积层(32->16)
conv3=tf.layers.conv2d(
inputs=pool2,
filters=128,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool3=tf.layers.max_pooling2d(inputs=conv3, pool_size=[2, 2], strides=2)
#第四个卷积层(16->8)
conv4=tf.layers.conv2d(
inputs=pool3,
filters=128,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
pool4=tf.layers.max_pooling2d(inputs=conv4, pool_size=[2, 2], strides=2)
re1 = tf.reshape(pool4, [-1, 8 * 8 * 128])
#全连接层
dense1 = tf.layers.dense(inputs=re1,
units=1024,
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.