從0到1實現基於Tornado和Tensorflow的人臉、年齡、性別識別(1)

Prerequisites

TensorFlow 0.12
Python2.7
OpenCV3.0
Centos7

從第三方Face++系統方案到第三方的算法方案

因爲要快速實現一個Demo,所以剛開始沒想到要做算法方案,業內聽說Face++這家創業公司做的算法還可以,阿里巴巴似乎也用了他們的方案。
以下是他們官網的產品介紹,似乎做的不做的樣子
Face++實現的功能
他們已經實現了人臉檢測(這個比較容易,openCV實現起來很快),人臉比對(這個也比較容易,有不少開源方案),人臉搜索(似乎有點難,關鍵是這個集合有多大,例如咱們南京以前的銀行門口殺人案,據說全南京的警察都在看監控,人肉搜索),人臉關鍵點(嗯,有點難度了),人臉屬性(似乎也是深度學習實現的,具體怎麼實現呢沒時間思考啦)
那麼我們來感受一下,這個公司的官網提供了網頁版本的服務演示(很自信啊),找個美女試一試,相信都知道是誰吧,來自南京的美女
人臉測試

openCV人臉識別算法的實現原理

人臉識別算法綜述

可以將人臉檢測的方法分爲四類:
1. 基於知識的方法( Knowledge-based)
例如人臉的輪廓可近似地被看成一個橢圓, 則人臉檢測可以通過檢測橢圓來完成。 對任意一幅圖像, 首先進行邊緣檢測, 並對細化後的邊緣提取曲線特徵, 然後計算各曲線組合成人臉的評估函數來檢測人臉。
雖然人臉因人而異,但都遵循一些普遍適用的規則,即五官分佈的幾何規則。檢測圖像中是否有人臉, 即是否存在滿足這些規則的圖像塊。 這種方法一般是先對人臉的器官或器官的組合建立模板, 然後檢測圖像中幾個器官可能分佈的位置, 對這些位置點分別組合, 用器官分佈的知識規則進行篩選, 從而找到可能存在的人臉。
這裏寫圖片描述
基於知識的方法是一種自上而下的方式。它其中一個困難是如何將人類知識轉化成爲有效的規則: 如果規則制定得太細, 那麼可能有許多人臉無法通過規則的驗證; 如果規則制定得太寬泛, 那麼可能許多非人臉會被誤判爲人臉。
2. 特徵不變量方法( Feature invariant)
這個方法的目標是尋找那些即使當姿勢、視角和光線條件變化時仍然存在的結構特徵, 並利用這些特徵來定位人臉。 由於人類能夠毫不費勁地“ 看到” 在不同光線和姿態下的人臉和物體, 因此研究人員認爲有一個潛在的假設: 存在一些關於人臉的不依賴於外在條件的屬性或者特徵。有許多方法就是按照這個潛在假設, 首先去尋找這種臉部特徵( 通過大量樣本學習的方法), 然後用尋找到的特徵去檢測人臉。 對比基於知識的自上而下的方法, 這種基於特徵的方法是自下而上的。
基於Haar特徵的AdaBoost算法就是這一類的。
3. 模板匹配的方法( Template matching)
模板匹配法是一種經典的模式識別方法。 其處理過程如下:
- 進行預處理手動地預定義或者參數化一個標準人臉圖案。 預處理要做尺度歸一化和灰度歸一化的工作。 最簡單的模板將人臉看成橢圓, 更復雜的人臉模板參見下圖;
這裏寫圖片描述
- 計算輸入圖像與標準人臉圖案的相關值, 這個相關值大都是獨立計算臉部輪廓、 眼鏡、 鼻子和嘴各自的匹配程度後得出的綜合描述。 對於圖中的模板, 則是按照劃分的 16 個區域和這些區域間的 23 種關係來計算這
個相關值;
- 根據相關值和預先設定的閾值來確定圖像中是否有人臉。
4. 基於表象的方法( Appearance-based)
一般而言,基於表象的方法利用統計分析和機器學習的技術來尋找人臉和非人臉圖像的有關特性。 學習而來的特性總結成分佈模型或者判別函數, 再利用這些分佈模型或者判別函數來檢測人臉。 一般, 爲了計算的效率和檢測的效益, 都會先降低圖像的維數。
許多基於表象的方法都可以在概率論的框架中理解。特徵向量可以看成是隨機變量 x,這個隨機變量被分類條件密度函數 p(x | faces) 和 p(x | nonfaces ) 分別描述成人臉和非人臉。
圖 像 中 備 選 的 人 臉 或 者 非 人 臉 位 置 可 以 用 貝 葉 斯 判 決 規 則 (Bayesian classification)或者最大概似法(maximum likelihood)來判別。 不幸地, 簡單地應用貝葉斯判決是不可行的, 這是因爲:
- x 是高維的;
- p(x | faces) 和 p(x | nonfaces ) 是多態的(multimodal);
- p(x | faces) 和 p(x | nonfaces ) 的自然參數化形式(natural parameterized
forms)還沒有弄清楚。
因此, 基於表象的方法中的許多工作都涉及到用經驗來驗證 p(x | faces) 和p(x | nonfaces ) 參數和非參數的近似的問題。
另一種方法利用了人臉和非人臉類的判別函數( 比如決策面、 分離超平面、閾函數等): 圖像圖案先被投射到低維或者高維空間, 之後使用判別函數來進行分類。例如PCA+SVM處理。

Haar人臉檢測算法

說是人臉檢測,其實這種方法廣泛用於各種目標檢測算法中
最早的Haar特徵由Papageorgiou C.等提出(《A general framework for object detection》),後來Paul Viola和Michal Jones提出利用積分圖像法快速計算Haar特徵的方法(《Rapid object detection using a boosted cascade of simple features》)。之後,Rainer Lienhart 和 Jochen Maydt用對角特徵對Haar特徵庫進行了擴展(《An extended set of Haar-like features for rapid object detection》)。OpenCV的Haar分類器就是基於擴展後的特徵庫實現的。
Haar特徵本身並不複雜,就是用圖中黑色矩形所有像素值的和減去白色矩形所有像素值的和。
這裏寫圖片描述
臉部的一些特徵可以由矩形特徵簡單地描繪
這裏寫圖片描述
上圖中兩個矩形特徵,表示出人臉的某些特徵。比如中間一幅表示眼睛區域的顏色比臉頰區域的顏色深,右邊一幅表示鼻樑兩側比鼻樑的顏色要深。同樣,其他目標,如眼睛等,也可以用一些矩形特徵來表示。使用特徵比單純地使用像素點具有很大的優越性,並且速度更快。
在給定有限的數據情況下,基於特徵的檢測能夠編碼特定區域的狀態,而且基於特徵的系統比基於象素的系統要快得多。
矩形特徵對一些簡單的圖形結構,比如邊緣、線段,比較敏感,但是其只能描述特定走向(水平、垂直、對角)的結構,因此比較粗略。如上圖,臉部一些特徵能夠由矩形特徵簡單地描繪,例如,通常,眼睛要比臉頰顏色更深;鼻樑兩側要比鼻樑顏色要深;嘴巴要比周圍顏色更深。
對於一個 24×24 檢測器,其內的矩形特徵數量超過160,000 個,必須通過特定算法甄選合適的矩形特徵,並將其組合成強分類器才能檢測人臉。
那麼如何計算160000+個特徵,也就是像素值的和,也成了個問題

積分圖

由於Haar特徵是矩形中黑色區域所有像素值的和減去白色區域所有像素值的和。,24*24的圖片中,有160000+個特徵,遠遠大於其像素個數。如果計算每個特徵的像素和,計算量會非常大,而且很多次運算是重複的。
Paul Viola提出一種利用積分圖像法快速計算Haar特徵的方法(《Rapid object detection using a boosted cascade of simple features》)。簡單說來,就是先構造一張“積分圖”(Integral image),也叫Summed Area Table,之後任何一個Haar矩形特徵都可以通過查表的方法(Look Up Table)和有限次簡單運算得到,大大減少了運算次數。
這個其實很好理解。

AdaBoost算法

AdaBoost,是英文”Adaptive Boosting”(自適應增強)的縮寫,由Yoav Freund和Robert Schapire在1995年提出。它的自適應在於:前一個基本分類器分錯的樣本會得到加強,加權後的全體樣本再次被用來訓練下一個基本分類器。同時,在 每一輪中加入一個新的弱分類器,直到達到某個預定的足夠小的錯誤率或達到預先指定的最大迭代次數。
具體說來,整個Adaboost 迭代算法就3步:
- 初始化訓練數據的權值分佈。如果有N個樣本,則每一個訓練樣本最開始時都被賦予相同的權值:1/N;
- 訓練弱分類器。具體訓練過程中,如果某個樣本點已經被準確地分類,那麼在構造下一個訓練集中,它的權值就被降低;相反,如果某個樣本點沒有被準確地分類,那麼它的權值就得到提高。然後,權值更新過的樣本集被用於訓練下一個分類器,整個訓練過程如此迭代地進行下去;
- 將 各個訓練得到的弱分類器組合成強分類器。各個弱分類器的訓練過程結束後,加大分類誤差率小的弱分類器的權重,使其在最終的分類函數中起着較大的決定作用, 而降低分類誤差率大的弱分類器的權重,使其在最終的分類函數中起着較小的決定作用。換言之,誤差率低的弱分類器在最終分類器中佔的權重較大,否則較小。
可參考 《Adaboost 算法的原理與推導》http://blog.csdn.net/v_july_v/article/details/40718799

openCV的相關函數

這裏直接上檢測人臉的代碼,可以通過pycharm在ubuntu或MAC系統中查看源碼

def detectface(filename):
    files = []
    print('Using face detector %s' % FLAGS.face_detection_model)
    face_detect = FaceDetector('haarcascade_frontalface_default.xml')
    face_files, rectangles = face_detect.run(filename)
    files += face_files
    if (len(files)>0) :
        return 1
    else:
        return 0

主要是FaceDetector類的run函數實現了人臉檢測,run函數會返回人臉的文件、以及矩形區域
我們把FaceDetector類的實現代碼貼出來

class FaceDetector(object):

    def __init__(self, model_name, basename = 'frontal-face', tgtdir = '.'):
        self.tgtdir = tgtdir
        self.basename = basename
        self.face_cascade = cv2.CascadeClassifier(model_name)

    def run(self, image_file, min_height_dec = 20, min_width_dec = 20, min_height_thresh=50, min_width_thresh=50):
        print(image_file)
        img = cv2.imread(image_file)
        min_h = int(max(img.shape[0] / min_height_dec, min_height_thresh))
        min_w = int(max(img.shape[1] / min_width_dec, min_width_thresh))
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        faces = self.face_cascade.detectMultiScale(gray, 1.3, minNeighbors=5, minSize=(min_h,min_w))

        images = []
        for i, (x,y,w,h) in enumerate(faces):
            images.append(self.sub_image('%s/%s-%d.jpg' % (self.tgtdir, self.basename, i+1), img, x, y, w, h))

        print('%d faces detected' % len(images))

        for (x,y,w,h) in faces:
            self.draw_rect(img, x, y, w, h)
            # Fix in case nothing found in the image
        outfile = '%s/%s.jpg' % (self.tgtdir, self.basename)
        cv2.imwrite(outfile, img)

        return images, outfile

    def sub_image(self, name, img, x, y, w, h):
        upper_cut = [min(img.shape[0], y+h+FACE_PAD), min(img.shape[1], x+w+FACE_PAD)]
        lower_cut = [max(y-FACE_PAD, 0), max(x-FACE_PAD, 0)]
        roi_color = img[lower_cut[0]:upper_cut[0], lower_cut[1]:upper_cut[1]]
        cv2.imwrite(name, roi_color)
        return name

    def draw_rect(self, img, x, y, w, h):
        upper_cut = [min(img.shape[0], y+h+FACE_PAD), min(img.shape[1], x+w+FACE_PAD)]
        lower_cut = [max(y-FACE_PAD, 0), max(x-FACE_PAD, 0)]
        cv2.rectangle(img, (lower_cut[1],lower_cut[0]),(upper_cut[1],upper_cut[0]), (255,0,0), 2)

FaceDetector類有init初始化函數來初始化顯式變量,是可變長參數
我們第一段代碼中只是傳了模型參數

more haarcascade_frontalface_default.xml 

打開模型配置文件,發現是一堆xml配置參數

  <stages>
    <_>
      <maxWeakCount>9</maxWeakCount>
      <stageThreshold>-5.0425500869750977e+00</stageThreshold>
      <weakClassifiers>
        <_>
          <internalNodes>
            0 -1 0 -3.1511999666690826e-02</internalNodes>
          <leafValues>
            2.0875380039215088e+00 -2.2172100543975830e+00</leafValues></_>
        <_>
          <internalNodes>
            0 -1 1 1.2396000325679779e-02</internalNodes>
          <leafValues>
            -1.8633940219879150e+00 1.3272049427032471e+00</leafValues></_>
        <_>
          <internalNodes>
            0 -1 2 2.1927999332547188e-02</internalNodes>
          <leafValues>
            -1.5105249881744385e+00 1.0625729560852051e+00</leafValues></_>
        <_>
          <internalNodes>
            0 -1 3 5.7529998011887074e-03</internalNodes>
          <leafValues>
            -8.7463897466659546e-01 1.1760339736938477e+00</leafValues></_>
        <_>
          <internalNodes>
            0 -1 4 1.5014000236988068e-02</internalNodes>
          <leafValues>
            -7.7945697307586670e-01 1.2608419656753540e+00</leafValues></_>
        <_>
          <internalNodes>

這是從openCV源碼那邊拷貝過來的,是別人訓練好的haar分類器模型,可以看到起到主要作用的函數是
detectMultiScale
人臉檢測主要用到的是CascadeClassifier這個類,以及該類下的detectMultiScale函數。

函數原型是:

void CascadeClassifier::detectMultiScale(InputArray image, vector<Rect>& objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())

總共有7個參數,分別是

第一個參數image: 要檢測的圖片,一般爲灰度圖

第二個參數objects: Rect型的容器,存放所有檢測出的人臉,每個人臉是一個矩形

第三個參數scaleFactor: 縮放因子,對圖片進行縮放,默認爲1.1

第四個參數minNeighbors: 最小鄰居數,默認爲3

第五個參數flags: 兼容老版本的一個參數,在3.0版本中沒用處。默認爲0

第六個參數minSize: 最小尺寸,檢測出的人臉最小尺寸

第七個參數maxSize: 最大尺寸,檢測出的人臉最大尺寸

這裏關注第六和第七個參數,由之前的代碼看出

        min_h = int(max(img.shape[0] / min_height_dec, min_height_thresh))
        min_w = int(max(img.shape[1] / min_width_dec, min_width_thresh))

img.shape[0]和img.shape[1]分別是圖片的高、寬,然後除以20的整數,和預設的min_height_thresh、min_width_thresh作比較後,取最大值的整數。
也就是理論上說可以最小檢測到圖片1/20的人臉
可以看到這裏沒有傳遞最大的值。
具體的參數配置可參考這篇csdn博友的文章http://blog.csdn.net/delltdk/article/details/9186875

前世今生——深度學習神經網絡的特徵發現

前饋神經網絡

例如BP神經網絡
這是一類有一個輸入層、一個輸出層和一個或多個隱藏層的神經網絡。前饋神經網絡帶來好的泛逼近器(映射任何輸入到任何輸出的函數),常用於構建多用途的模型。
此類神經網絡可以用於分類和遞歸。例如,如果使用前饋網絡針對輸出層上的若干神經元進行分類,則和針對若干類別是一樣的。從概念上講,輸出神經元第一次決定的類別是網絡預測出來的。更精確地說,每個輸出神經元返回一個該記錄匹配該類的可能性,然後把可能性最高的類別選做模型的輸出分類。
多層感知器之類的前饋神經網絡的好處是易於使用,比其他類型網絡的複雜度要低,可以找到各種各樣的實例。

卷積神經網絡

卷積神經網絡與前饋神經網絡類似,至少在網絡上傳送數據的方式是一樣的。它們從形式上粗略模仿了虛擬的大腦皮質。卷積神經在一個底層圖像上移動幾個像放大鏡之類的濾波器。這些濾波器專注於圖像子集(碎片或貼片)的特徵識別,然後在像場上的一系列貼片中重複這個過程。每個濾波器尋找可視化數據中的不同模式;例如,有的可能尋找的是水平線,有的可能尋找的是對角線,還有的可能尋找的是垂直線。這些線是已知的特徵,濾波器在圖像上經過,他們構造特徵圖譜定位每種線每次在圖像中出現的不同方位。
圖像中不同的對象(小貓、波音747、轉動中的榨汁機)形成不同的特徵圖譜,這些圖譜最終可用於圖像分類。在圖像和視頻識別領域已證明卷積網絡非常有用,因爲聲音可以以聲譜圖的形式可視化表示出來,所以卷積網絡同樣可以廣泛應用於語音識別和機器轉錄的任務上。

卷積與前饋網絡在圖像處理方面的對比

兩種網絡類型都可以分析圖像,但它們的分析方式是不同的。因爲卷積神經網絡是一步步通過圖像的重疊區域訓練學着識別每個區域的特徵的,而前饋神經網絡是在整個圖像上訓練的。前饋神經網絡在特徵總是處於特定位置或方向的圖像上進行訓練,如果特徵出現在一個不常見的位置可能就識別不到了,而得到充分訓練的卷積神經網絡是可以做到的。
卷積神經網絡不但可用於諸如圖像、視頻、聲音和語音識別之類的任務,還可以用於做自動駕馭汽車。

年齡段識別算法的實現

我們爲什麼要講源碼,show算法

其實對於一個互聯網碼農來說,講源碼,show算法似乎真的沒什麼必要,事實是這樣的嗎?
我就是一把梭子啊梭子
其實說真的國內大部分碼農包括我自己,讀書讀到了碩士,結果出來做的事,一個大專生都能做,可能學歷好一點做得更好吧!
What’s the fuck!
這個問題是個矛盾的問題,如果你辛辛苦苦看算法導論,刷lettcode,然後經過高大上的白板測試,高談闊論各種算法的時間複雜度,其實進了公司,可能你做得活就是增刪改查什麼的,有人說啊,就是低端的活也能做出樣子啊
我只能說呵呵。
你真的不知道機會的重要性。
那麼到底應不應該講源碼,show算法?
其實是應該的!因爲作爲碼農,你必須提升自己的逼格,以備各種公開場合裝逼,當然也能對自己的工作有些幫助。
似乎tmd扯遠了……
來來來,寂寞的碼農,來看年齡段算法的實現。
年齡段算法是通過tensorflow實現的,我沒本事實現這種算法,但是我也會複製啊!
github是個好東西啊!
找一找啊找一找,來看看這個github工程,我fork下來了。
https://github.com/nanpian/rude-carnie
原作者的項目網址是
https://github.com/dpressel/rude-carnie
那麼既然是一把可以裝逼的刷子,那麼不僅僅要複製粘貼,也要知道怎麼實現的。
貼代碼,開幹!別跟老夫說什麼量子學、宇稱不守恆定律、超級計算機,只要你是pm項目經理,給我一個造核導彈和航空母艦的任務,給個deadline,排期,我也能敏捷開發!

代碼源

https://github.com/dpressel/rude-carnie

模型下載

You can find a pre-trained age checkpoint for inception here:
https://drive.google.com/drive/folders/0B8N1oYmGLVGWbDZ4Y21GLWxtV1E
因爲被牆,在這提供百度網盤下載鏈接,下載後解壓到本地工程裏面的22801目錄
http://pan.baidu.com/s/1mhLBIHy

實驗運行步驟

python2.7 guess.py --model_type inception --model_dir ./22801 --filename test1.jpg

test1.jpg是拍的人像數據
需要安裝python2.7、openCV3.0、tensorFlow1.0環境。
Ubuntu環境爲14.04LTS
如果沒有安裝openCV環境,則會出現以下問題:

  Traceback (most recent call last):
      File "guess.py", line 12, in <module>
      from utils import ImageCoder, make_batch, FaceDetector
      File "/home/david/work/tensorflow/rude-carnie/utils.py", line 7, in <module>
      import cv2
      ImportError: No module named cv2

運行結果

~/work/tensorflow/rude-carnie$ python2.7 guess.py --model_type inception --model_dir ./22801 --filename   test1.jpg 
Executing on /cpu:0
selected (fine-tuning) inception model
./22801/checkpoint-14999
Running file test1.jpg
Running multi-cropped image
Guess @ 1 (4, 6), prob = 0.99
Guess @ 2 (8, 12), prob = 0.01

年齡段識別模型的訓練過程

訓練集和驗證集列表文件F1下載
git clone https://github.com/GilLevi/AgeGenderDeepLearning
訓練集和驗證集圖片文件F2下載
http://www.openu.ac.il/home/hassner/Adience/data.html
首先要對訓練集進行預處理
官方的處理方法如下,這個目錄要根據你的實際目錄進行調整

python2.7 preproc.py --fold_dir ../AgeGenderDeepLearning/Folds/train_val_txt_files_per_fold/test_fold_is_0 --train_list age_train.txt --valid_list age_val.txt --data_dir ~/work/AgeGenderDeepLearning/aligned --output_dir  ../AgeGenderDeepLearning/Folds/tf/age_test_fold_is_0

主要是 fold_dir、train_list、valid_list、data_dir、output_dir參數
fold_dir:訓練集和驗證集的F1基目錄
train_list:訓練集
valid_list:驗證集
data_dir:圖片文件目錄,這裏選的是aligned目錄,也就是F2文件夾
output_dir:輸出目錄
我們先翻看下訓練集的目錄結構
這裏寫圖片描述
注意aligned、faces文件夾是zip解壓縮的,這部分要預先解壓縮,否則後面會找不到文件。
打開主目錄的txt文件
這裏寫圖片描述
可以看到裏面主要是標註數據。
來看看age_train.txt的內容
這裏寫圖片描述
那麼preproc.py究竟做了哪些處理呢,上代碼

def main(unused_argv):
    assert not FLAGS.train_shards % FLAGS.num_threads, (
        'Please make the FLAGS.num_threads commensurate with FLAGS.train_shards')
    assert not FLAGS.valid_shards % FLAGS.num_threads, (
        'Please make the FLAGS.num_threads commensurate with '
        'FLAGS.valid_shards')
    print('Saving results to %s' % FLAGS.output_dir)

    if os.path.exists(FLAGS.output_dir) is False:
        print('creating %s' % FLAGS.output_dir)
        os.makedirs(FLAGS.output_dir)

    # Run it!,主要就運行這兩個函數,採樣抽取訓練集和驗證集
    valid, valid_outcomes = _process_dataset('validation', '%s/%s' % (FLAGS.fold_dir, FLAGS.valid_list), FLAGS.data_dir,
                     FLAGS.valid_shards)
    train, train_outcomes = _process_dataset('train', '%s/%s' % (FLAGS.fold_dir, FLAGS.train_list), FLAGS.data_dir,
                     FLAGS.train_shards)

    if len(valid_outcomes) != len(valid_outcomes | train_outcomes):
        print('Warning: unattested labels in training data [%s]' % (', '.join(valid_outcomes | train_outcomes) - valid_outcomes))

    output_file = os.path.join(FLAGS.output_dir, 'md.json')


    md = { 'num_valid_shards': FLAGS.valid_shards, 
           'num_train_shards': FLAGS.train_shards,
           'valid_counts': valid,
           'train_counts': train,
           'timestamp': str(datetime.now()),
           'nlabels': len(train_outcomes) }
    with open(output_file, 'w') as f:
        json.dump(md, f)

主要起作用的是_process_dataset函數,繼續跟下去

def _process_dataset(name, filename, directory, num_shards):
    """Process a complete data set and save it as a TFRecord.
    Args:
    name: string, unique identifier specifying the data set.
    directory: string, root path to the data set.
    num_shards: integer number of shards for this data set.
    labels_file: string, path to the labels file.
    """
    filenames, labels = _find_image_files(filename, directory)
    _process_image_files(name, filenames, labels, num_shards)
    unique_labels = set(labels)
    return len(labels), unique_labels

主要是是通過_find_image_files函數得到相關的文件名filenames以及標註數據labels,
跟一下_find_image_files函數

def _find_image_files(list_file, data_dir):
    print('Determining list of input files and labels from %s.' % list_file)
    files_labels = [l.strip().split(' ') for l in tf.gfile.FastGFile(
        list_file, 'r').readlines()]

    labels = []
    filenames = []

    # Leave label index 0 empty as a background class.
    label_index = 1

    # Construct the list of JPEG files and labels.
    for path, label in files_labels:
        jpeg_file_path = '%s/%s' % (data_dir, path)
        if os.path.exists(jpeg_file_path):
            filenames.append(jpeg_file_path)
            labels.append(label)

    unique_labels = set(labels)
    # Shuffle the ordering of all image files in order to guarantee
    # random ordering of the images with respect to label in the
    # saved TFRecord files. Make the randomization repeatable.
    shuffled_index = range(len(filenames))
    random.seed(12345)
    random.shuffle(shuffled_index)

    filenames = [filenames[i] for i in shuffled_index]
    labels = [labels[i] for i in shuffled_index]

    print('Found %d JPEG files across %d labels inside %s.' %
          (len(filenames), len(unique_labels), data_dir))
    return filenames, labels

其中 files_labels = [l.strip().split(’ ‘) for l in tf.gfile.FastGFile(
list_file, ‘r’).readlines()]
這一句比較重要,讀取每行,通過空格分割,得到每行的標籤數組,
最終通過 shuffled_index = range(len(filenames))
random.seed(12345)
random.shuffle(shuffled_index)
進行數據清洗(shuffle:洗牌)
然後做些什麼呢?繼續看_process_image_files函數

    # Break all images into batches with a [ranges[i][0], ranges[i][1]].
    spacing = np.linspace(0, len(filenames), FLAGS.num_threads + 1).astype(np.int)
    ranges = []
    threads = []
    for i in xrange(len(spacing) - 1):
        ranges.append([spacing[i], spacing[i+1]])

其中np.linspace是採樣函數,起點是0,終點是文件個數,採樣點個數是線程數加1,也就是3;
如果文件個數是6,那麼
[0 3 6],ranges就[[0,3],[3,6]]
後面

    # tensorflow線程協調器
    coord = tf.train.Coordinator()

    coder = ImageCoder()

    threads = []
    for thread_index in xrange(len(ranges)):
        args = (coder, thread_index, ranges, name, filenames, labels, num_shards)
        t = threading.Thread(target=_process_image_files_batch, args=args)
        t.start()
        threads.append(t)

可以看到起了兩個線程,通過
_process_image_files_batch函數來把原圖片文件生成TFRecords文件。
一個TFRecords 文件爲一個字符串序列。這種格式並非隨機獲取,它比較適合大規模的數據流,而不太適合需要快速分區或其他非序列獲取方式。
時間不多,我們還是繼續看看,怎麼訓練模型吧,忙活了半天,正題纔剛剛開始…

(待續)

年齡段識別的預測過程

性別識別算法的實現

性別識別模型的訓練過程

性別識別的預測過程

引申——怎麼實現人臉顏值打分?

Centos7環境安裝步驟

1.安裝Centos7
2.安裝TensorFlow 0.12
下載安裝包到Centos7上安裝
3.安裝openCV3.0
下載安裝包到Centos7上編譯安裝
下載地址https://codeload.github.com/Itseez/opencv/zip/3.0.0
主要安裝步驟參考http://www.cnblogs.com/asmer-stone/p/4592421.html
4.Python2.7自帶Tornado

SOA服務源代碼和解析

Tornado簡介——一分鐘搭建web服務的神器

Tornado 和現在的主流 Web 服務器框架(包括大多數 Python 的框架)有着明顯的區別:它是非阻塞式服務器,而且速度相當快。得利於其 非阻塞的方式和對 epoll 的運用,Tornado 每秒可以處理數以千計的連接,這意味着對於實時 Web 服務來說,Tornado 是一個理想的 Web 框架。
這裏就不得不對epoll、poll、select三種模型做一下介紹,不是本文的主要目的,大家有興趣的看文章吧
http://www.cnblogs.com/Anker/p/3265058.html

軟件流程圖

源碼解析

啓動服務方法

準確率較低的反思和改進方法

調參方法

優化方法

訓練集

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章