本文主要是實現了根據人臉識別性別的卷積神經網絡,並對卷積過程當中的提取特徵進行了可視化. python
Github地址:https://github.com/chenlinzho...git
從data目錄讀取數據,famale存放女性圖片,male存放男性圖片github
def read_img(list,flag=0): for i in range(len(list)-1): if os.path.isfile(list[i]): images.append(cv2.imread(list[i]).flatten()) labels.append(flag) read_img(get_img_list('male'),[0,1]) read_img(get_img_list('female'),[1,0]) images = np.array(images) labels = np.array(labels)
從新打亂算法
permutation = np.random.permutation(labels.shape[0]) all_images = images[permutation,:] all_labels = labels[permutation,:]
訓練集與測試集比例 8:2網絡
train_total = all_images.shape[0] train_nums= int(all_images.shape[0]*0.8) test_nums = all_images.shape[0]-train_nums #訓練集 images = all_images[0:train_nums,:] labels = all_labels[0:train_nums,:] #測試集 test_images = all_images[train_nums:train_total,:] test_labels = all_labels[train_nums:train_total,:]
train_epochs=3000 # 訓練輪數 batch_size= random.randint(6,18) # 每次訓練數據,隨機 drop_prob = 0.4 # 正則化,丟棄比例 learning_rate=0.00001 # 學習效率
輸入層爲輸入的灰度圖像尺寸: -1 x 112 x 92 x 3 第一個卷積層,卷積核的大小,深度和數量 (3, 3, 3, 16) 池化後的特徵張量尺寸: -1 x 56 x 46 x 16 第二個卷積層,卷積核的大小,深度和數量 (3, 3, 16, 32) 池化後的特徵張量尺寸: -1 x 28 x 23 x 32 第三個卷積層,卷積核的大小,深度和數量 (3, 3, 32, 64) 池化後的特徵張量尺寸: -1 x 14 x 12 x 64 全鏈接第一層權重矩陣: 10752 x 512 全鏈接第二層權重矩陣: 512 x 128 輸出層與全鏈接隱藏層之間: 128 x 2
# 權重初始化(卷積核初始化) # tf.truncated_normal()不一樣於tf.random_normal(),返回的值中不會偏離均值兩倍的標準差 # 參數shpae爲一個列表對象,例如[5, 5, 1, 32]對應 # 5,5 表示卷積核的大小, 1表明通道channel,對彩色圖片作卷積是3,單色灰度爲1 # 最後一個數字32,卷積核的個數,(也就是卷基層提取的特徵數量) def weight_init(shape): weight = tf.truncated_normal(shape,stddev=0.1,dtype=tf.float32) return tf.Variable(weight) #偏執初始化 def bias_init(shape): bias = tf.random_normal(shape,dtype=tf.float32) return tf.Variable(bias) #全鏈接矩陣初始化 def fch_init(layer1,layer2,const=1): min = -const * (6.0 / (layer1 + layer2)); max = -min; weight = tf.random_uniform([layer1, layer2], minval=min, maxval=max, dtype=tf.float32) return tf.Variable(weight) # 源碼的位置在tensorflow/python/ops下nn_impl.py和nn_ops.py # 這個函數接收兩個參數,x 是圖像的像素, w 是卷積核 # x 張量的維度[batch, height, width, channels] # w 卷積核的維度[height, width, channels, channels_multiplier] # tf.nn.conv2d()是一個二維卷積函數, # stirdes 是卷積核移動的步長,4個1表示,在x張量維度的四個參數上移動步長 # padding 參數'SAME',表示對原始輸入像素進行填充,卷積後映射的2D圖像與原圖大小相等 # 填充,是指在原圖像素值矩陣周圍填充0像素點 # 若是不進行填充,假設 原圖爲 32x32 的圖像,卷積和大小爲 5x5 ,卷積後映射圖像大小 爲 28x28 def conv2d(images,weight): return tf.nn.conv2d(images,weight,strides=[1,1,1,1],padding='SAME')
Paddingapp
#池化 卷積核在提取特徵時的動做成爲padding,它有兩種方式:SAME和VALID。卷積核的移動步長不必定可以整除圖片像素的寬度,因此在有些圖片的邊框位置有些像素不能被卷積。這種不越過邊緣的取樣就叫作 valid padding,卷積後的圖像面積小於原圖像。爲了讓卷積核覆蓋到全部的像素,能夠對邊緣位置進行0像素填充,而後在進行卷積。這種越過邊緣的取樣是 same padding。如過移動步長爲1,那麼獲得和原圖同樣大小的圖像。若是步長很大,超過了卷積核長度,那麼same padding,獲得的特徵圖也會小於原來的圖像。 def max_pool2x2(images,tname): return tf.nn.max_pool(images,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME',name=tname)
#images_input 爲輸入的圖片,labels_input爲輸入的標籤 images_input = tf.placeholder(tf.float32,[None,112*92*3],name='input_images') labels_input = tf.placeholder(tf.float32,[None,2],name='input_labels') #把圖像轉換爲112*92*3的形狀 x_input = tf.reshape(images_input,[-1,112,92,3])
第一層卷積+池化dom
# 卷積核3*3*3 16個 第一層卷積 w1 = weight_init([3,3,3,16]) b1 = bias_init([16]) conv_1 = conv2d(x_input,w1)+b1 relu_1 = tf.nn.relu(conv_1,name='relu_1') max_pool_1 = max_pool2x2(relu_1,'max_pool_1')
第二層卷積+池化ide
# 卷積核3*3*16 32個 第二層卷積 w2 = weight_init([3,3,16,32]) b2 = bias_init([32]) conv_2 = conv2d(max_pool_1,w2) + b2 relu_2 = tf.nn.relu(conv_2,name='relu_2') max_pool_2 = max_pool2x2(relu_2,'max_pool_2')
第三層卷積+池化函數
w3 = weight_init([3,3,32,64]) b3 = bias_init([64]) conv_3 = conv2d(max_pool_2,w3)+b3 relu_3 = tf.nn.relu(conv_3,name='relu_3') max_pool_3 = max_pool2x2(relu_3,'max_pool_3')
全鏈接第一層學習
#把第三層的卷積結果平鋪成一維向量 f_input = tf.reshape(max_pool_3,[-1,14*12*64]) #全鏈接第一層 31*31*32,512 f_w1= fch_init(14*12*64,512) f_b1 = bias_init([512]) f_r1 = tf.matmul(f_input,f_w1) + f_b1 #激活函數,relu隨機丟掉一些權重提供泛華能力 f_relu_r1 = tf.nn.relu(f_r1) # 爲了防止網絡出現過擬合的狀況,對全鏈接隱藏層進行 Dropout(正則化)處理,在訓練過程當中隨機的丟棄部分 # 節點的數據來防止過擬合.Dropout同把節點數據設置爲0來丟棄一些特徵值,僅在訓練過程當中, # 預測的時候,仍使用全數據特徵 # 傳入丟棄節點數據的比例 f_dropout_r1 = tf.nn.dropout(f_relu_r1,drop_prob)
全鏈接第二層
f_w2 = fch_init(512,128) f_b2 = bias_init([128]) f_r2 = tf.matmul(f_dropout_r1,f_w2) + f_b2 f_relu_r2 = tf.nn.relu(f_r2) f_dropout_r2 = tf.nn.dropout(f_relu_r2,drop_prob)
全鏈接輸出層
f_w3 = fch_init(128,2) f_b3 = bias_init([2]) f_r3 = tf.matmul(f_dropout_r2,f_w3) + f_b3 最後輸出結果,多是這樣的[[0.0001,0.99999] ,那個位置的結果大就屬於哪一個分類 f_softmax = tf.nn.softmax(f_r3,name='f_softmax')
損失函數
#交叉熵代價函數 cross_entry = tf.reduce_mean(tf.reduce_sum(-labels_input*tf.log(f_softmax))) #優化器,自動執行梯度降低算法 optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cross_entry)
計算準確率&損失
arg1 = tf.argmax(labels_input,1) arg2 = tf.argmax(f_softmax,1) #每一個樣本的預測結果是一個(1,2)的vector cos = tf.equal(arg1,arg2) # tf.cast把bool值轉換爲浮點數 acc = tf.reduce_mean(tf.cast(cos,dtype=tf.float32))
啓動會話開始訓練
init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) Cost = [] Accuracy=[] for i in range(train_epochs): idx=random.randint(0,len(train_data.images)-20) batch= random.randint(6,18) train_input = train_data.images[idx:(idx+batch)] train_labels = train_data.labels[idx:(idx+batch)] result,acc1,cross_entry_r,cos1,f_softmax1,relu_1_r= sess.run([optimizer,acc,cross_entry,cos,f_softmax,relu_1],feed_dict={images_input:train_input,labels_input:train_labels}) print acc1 Cost.append(cross_entry_r) Accuracy.append(acc1) # 代價函數曲線 fig1,ax1 = plt.subplots(figsize=(10,7)) plt.plot(Cost) ax1.set_xlabel('Epochs') ax1.set_ylabel('Cost') plt.title('Cross Loss') plt.grid() plt.show() # 準確率曲線 fig7,ax7 = plt.subplots(figsize=(10,7)) plt.plot(Accuracy) ax7.set_xlabel('Epochs') ax7.set_ylabel('Accuracy Rate') plt.title('Train Accuracy Rate') plt.grid() plt.show()
測試集驗證
#測試 arg2_r = sess.run(arg2,feed_dict={images_input:train_data.test_images,labels_input:train_data.test_labels}) arg1_r = sess.run(arg1,feed_dict={images_input:train_data.test_images,labels_input:train_data.test_labels}) #使用混淆矩陣,打印報告 print (classification_report(arg1_r, arg2_r))
驗證經過,保存模型
#保存模型 saver = tf.train.Saver() saver.save(sess, './model/my-gender-v1.0')
使用已訓練好的模型參考:gender_model_use.py
結果: 迭代3000次,模型的準確率達到93%
訓練交叉熵代價
訓練的準確率
訓練數據中的一個樣本
第一層卷積提取的特徵
2x2池化後特徵
第二層卷積提取的特徵
2x2池化後特徵
第三層卷積提取的特徵
2x2池化後特徵