是貓是狗,遛一遛

額,,深度學習,機器學習的文章看的多瞭,但是好像並不知道實際上有啥卵用!!!這次咱們就整點兒實際的,來識別一下圖片當中的東西咋樣(狗呀,貓呀,當然還可以識別美女咯)

是貓是狗,遛一遛

谷歌相冊可以識別出來圖片裡面的風景!相似的,iPhone相冊也可以識別出圖片裡面的動物,人,美食等等,都是自動對其進行打標簽的!

他們的原理到底是啥吶,這些大廠,一定是技術相當成熟瞭,才把這種功能用於用戶體驗的,所以讓我們一探究竟吧!

是貓是狗,遛一遛

相信小孩子(3歲左右就成)看見上面的圖片一下子就知道,“哇,鳥!”

以前,但是如果讓計算機去理解圖片當中有一隻鳥,emmm,估計你要把電腦砸瞭,然後把自己裝進去才成!

這麼多年過去瞭,多虧瞭廣大的學者朋友們,給我們提供瞭一種好用又簡單的方法用於目標檢測和識別!–深度卷積神經網絡

let`s do it,~

我們識別鳥之前,讓我們做點兒簡單的功課!“機器不學習系列-機器學習是個啥”說的“手寫數字識別”大傢還記得吧!再結合我們在上一篇說的神經網絡的知識,我們來改造一下咱們的神經網絡讓其能夠進行手寫數字識別!

說過很多遍,機器學習的前提是:數據,大量的訓練數據,好在手寫數字識別有相應的訓練集MNIST^_^,

MNIST data set of handwritten numbers

裡面有60000張手寫數字的圖像,並且每張圖像都是18*18。

是貓是狗,遛一遛

看看這密密麻麻的數字8,是不是有的還很像你的字跡!

咳咳咳,回到正題, 記住,在計算機的世界裡面全都是以數值進行表征的!在上一篇房屋銷售的例子中,我們單純用數字來表征臥室的個數,房間的大小等等,如果我們想解決我們現在手寫數字識別的問題,我們應該怎麼做吶?

其實答案非常的簡單,因為圖像在計算機當中是以像素點進行存儲的!我們可以將圖片轉化為像素值,然後將其輸入到神經網絡當中去!

是貓是狗,遛一遛

將上面所有的數值展開,得到如下的數組!

是貓是狗,遛一遛

其包括324個輸入,我們可以依照此輸入來調整我們的神經網絡模型!

是貓是狗,遛一遛

這時候我們的輸出包含兩個,一個是預測結果是8,一個是預測結果不是8

通過這樣的分類算法,我們就可以對輸入的圖片進行辨識瞭!

比起上一篇而言,我們的神經網絡模型復雜瞭很多,但是這對於計算機而言,都是小case!

接下來,我們就可以開始訓練我們的神經網絡模型瞭,讓機器學會辨識圖像裡面的數字,當我們輸入一個手寫數字為8的圖像時,我們告訴機器,你聽好瞭這是8,當我們輸入一個手寫數字不是8的圖像時,我們告訴機器,你也聽好瞭,這不是8。

是貓是狗,遛一遛

如圖所示,是我們部分訓練集!包含0-9手寫數字。

這個是TensorFlow的入門課程,這裡我就不仔細說下去咯。

傳送門┏ (゜ω゜)=☞

https://github.com/gzdaijie/tensorflow-tutorial-samples

很簡單是不是!機器學習是不是也不是那麼的難!

是貓是狗,遛一遛

但是好像又不是那麼的簡單!

是貓是狗,遛一遛

上面的圖片和下面的圖片區別在於:數字不居中

但是這樣在現實世界中好像不合理!寫字很可能就寫偏瞭是不!

讓我們來想一想解決方案:

方案一:使用滑動窗口搜索

目前我們的模型已經可以識別手寫數字8瞭,現在我們要做的隻是想讓手寫數字8居於區域的中間,我們可不可以采用滑動窗口平移我們的待識別區域,使得數字8剛好落在識別區域的中間!

是貓是狗,遛一遛

這種方式稱為滑窗法!在有限作用域的情況下,可以很好的工作!但是效率比較低!需要在一幅圖片上進行不斷的嘗試!

方案二:使用更多的訓練數據進行訓練

因為我們在初始訓練的時候,我們的訓練集中隻包含瞭手寫數字8位於正中間的圖像,如果我們的訓練集中包含更多一些手寫數字8不位於正中間的圖像,那麼訓練出來的模型就可以更好的work瞭!

我們甚至都不需要重新制作新的手寫圖像,我們可以通過簡單的平移放縮和旋轉就可以生成所需要的數據集!

是貓是狗,遛一遛

但是於此同時,我們又需要更復雜的網絡結構來擬合這些數據。

是貓是狗,遛一遛

上述的結構,在原來單層神經網絡的基礎上又增加瞭幾層,姑且就稱之為:“深度神經網絡”吧!

之前,訓練很復雜的神經網絡如果單使用CPU的話超級慢,好在學者們發現顯卡可用於加速計算,推動瞭現在深度神經網絡的高速發展!

是貓是狗,遛一遛

但是縱觀我們有瞭很先進的設備,但是總不能一直將神經網絡一層一層的堆疊下去吧!我們需要一些其他的解決方案!

我們繼續回想手寫數字識別這個問題!

現在模型的問題在於:位置的偏差導致模型不work!

好在科學傢們比較厲害!解決辦法就是:卷積

是貓是狗,遛一遛

優秀的你,是不是一眼就看出來這幅圖片裡面有個小孩子騎著一個玩具馬!不管周圍的環境多麼的復雜,我們都可以一眼就辨識出來這個小孩就在這副圖片裡面!

但是我們現有的模型肯定就分辨不出來,它竟然認為事物的本質與其所處的位置有關系!

我們需要讓我們的模型理解:事物其平移不變型的特征!8就是8,不管處在什麼位置,它都是8!我就是我,不管在哪兒,我還是我!(哈哈哈)

所以,我們需要借助:無論物體出現在圖片的任何地方,它總是一致的。這一思想來解決這個問題!

第一步:我們將圖片進行分割,然後采用跟上述滑窗思想類似的手段,讓滑動窗口在分割出來的小圖片上進行滑動!

是貓是狗,遛一遛

第二步:我們對每個小圖片進行模型計算

是貓是狗,遛一遛

在這個過程中,中間的小神經網絡對於所有的小圖片都是一樣的,我們對每個小圖片都一視同仁!

第三步:我們將每個小圖片的輸出結果進行保存!並且輸出結果的排列方式與原圖像中小圖片的排列方式一樣!

是貓是狗,遛一遛

換句話說,我們將原圖像通過模型計算,將其轉化為瞭信息更為簡化的數組,這個數組裡面保存著原圖像中最有意義的信息!

第四步:采樣

在第三步得到的數組好像還是太過於冗餘瞭,信息量還是太大瞭,我們可以繼續對其進行簡化!

是貓是狗,遛一遛

是貓是狗,遛一遛

我們采用的是max pooling的思想,即隻選擇指定區域裡面最大的值作為該區域的信息表征!

最後一步:我們就可以使用我們改造後的模型進行預測瞭!

我們將上述通過采樣得到的數據作為我們上篇提到的單層神經網絡(其名為全連接神經網絡)的輸入,最後對結果進行判定即可!

整個網絡模型如下圖所示:

是貓是狗,遛一遛

過程包括為:卷積層、池化層、全連接層等!

在解決實際問題的時候,上述結構可以任意的進行堆疊,達到模型效果!其中卷積的個數越多,卷積層的數量越多,原圖像中信息提取的就越豐富,就可以進行更為復雜的目標檢測或識別任務!

比如:第一個卷積可以用於識別貓的耳朵,第二個卷積用於識別貓的嘴巴等。

看看下面一個較為復雜的網絡結構。

是貓是狗,遛一遛

你就知道卷積的厲害之處瞭吧!

你可能會說,好簡單哦,但是往往事情本身還是比較復雜滴!

想要訓練得到一個較為優秀的卷積神經網絡,不僅參數調優還需要結構調整,機器學習的過程需要不斷的嘗試!

來點兒實際的吧!!!

鳥類識別器走起~

首先數據報告一下,

CIFAR10 data set

6,000 pictures of birds and 52,000 pictures.

Caltech-UCSD Birds-200–2011 data set

12,000 bird pics.

是貓是狗,遛一遛

是貓是狗,遛一遛

講道理哈,咱們的數據量還是很小很小的!想谷歌類似的企業其數據量都是千萬級別億級別的!

In machine learning, having more data is almost always more important that having better algorithms.

# -*- coding: utf-8 -*-
"""
Based on the tflearn example located here:
https://github.com/tflearn/tflearn/blob/master/examples/images/convnet_cifar10.py
"""
from __future__ import division, print_function, absolute_import

# Import tflearn and some helpers
import tflearn
from tflearn.data_utils import shuffle
from tflearn.layers.core import input_data, dropout, fully_connected
from tflearn.layers.conv import conv_2d, max_pool_2d
from tflearn.layers.estimator import regression
from tflearn.data_preprocessing import ImagePreprocessing
from tflearn.data_augmentation import ImageAugmentation
import pickle

# Load the data set
X, Y, X_test, Y_test = pickle.load(open("full_dataset.pkl", "rb"))

# Shuffle the data
X, Y = shuffle(X, Y)

# Make sure the data is normalized
img_prep = ImagePreprocessing()
img_prep.add_featurewise_zero_center()
img_prep.add_featurewise_stdnorm()

# Create extra synthetic training data by flipping, rotating and blurring the
# images on our data set.
img_aug = ImageAugmentation()
img_aug.add_random_flip_leftright()
img_aug.add_random_rotation(max_angle=25.)
img_aug.add_random_blur(sigma_max=3.)

# Define our network architecture:

# Input is a 32x32 image with 3 color channels (red, green and blue)
network = input_data(shape=[None, 32, 32, 3],
data_preprocessing=img_prep,
data_augmentation=img_aug)

# Step 1: Convolution
network = conv_2d(network, 32, 3, activation='relu')

# Step 2: Max pooling
network = max_pool_2d(network, 2)

# Step 3: Convolution again
network = conv_2d(network, 64, 3, activation='relu')

# Step 4: Convolution yet again
network = conv_2d(network, 64, 3, activation='relu')

# Step 5: Max pooling again
network = max_pool_2d(network, 2)

# Step 6: Fully-connected 512 node neural network
network = fully_connected(network, 512, activation='relu')

# Step 7: Dropout - throw away some data randomly during training to prevent over-fitting
network = dropout(network, 0.5)

# Step 8: Fully-connected neural network with two outputs (0=isn't a bird, 1=is a bird) to make the final prediction
network = fully_connected(network, 2, activation='softmax')

# Tell tflearn how we want to train the network
network = regression(network, optimizer='adam',
loss='categorical_crossentropy',
learning_rate=0.001)

# Wrap the network in a model object
model = tflearn.DNN(network, tensorboard_verbose=0, checkpoint_path='bird-classifier.tfl.ckpt')

# Train it! We'll do 100 training passes and monitor it as it goes.
model.fit(X, Y, n_epoch=100, shuffle=True, validation_set=(X_test, Y_test),
show_metric=True, batch_size=96,
snapshot_epoch=True,
run_id='bird-classifier')

# Save model when training is complete to a file
model.save("bird-classifier.tfl")
print("Network trained and saved as bird-classifier.tfl!")

隨著訓練次數的增加,模型的精度也會逐漸變優!差不多50輪迭代之後,可以到達95.5%左右!

現在就可以使用我們的模型來辨識小鳥咯。

 # -*- coding: utf-8 -*-
from __future__ import division, print_function, absolute_import

import tflearn
from tflearn.layers.core import input_data, dropout, fully_connected
from tflearn.layers.conv import conv_2d, max_pool_2d
from tflearn.layers.estimator import regression
from tflearn.data_preprocessing import ImagePreprocessing
from tflearn.data_augmentation import ImageAugmentation
import scipy
import numpy as np
import argparse

parser = argparse.ArgumentParser(description='Decide if an image is a picture of a bird')
parser.add_argument('image', type=str, help='The image image file to check')
args = parser.parse_args()


# Same network definition as before
img_prep = ImagePreprocessing()
img_prep.add_featurewise_zero_center()
img_prep.add_featurewise_stdnorm()
img_aug = ImageAugmentation()
img_aug.add_random_flip_leftright()
img_aug.add_random_rotation(max_angle=25.)
img_aug.add_random_blur(sigma_max=3.)

network = input_data(shape=[None, 32, 32, 3],
data_preprocessing=img_prep,
data_augmentation=img_aug)
network = conv_2d(network, 32, 3, activation='relu')
network = max_pool_2d(network, 2)
network = conv_2d(network, 64, 3, activation='relu')
network = conv_2d(network, 64, 3, activation='relu')
network = max_pool_2d(network, 2)
network = fully_connected(network, 512, activation='relu')
network = dropout(network, 0.5)
network = fully_connected(network, 2, activation='softmax')
network = regression(network, optimizer='adam',
loss='categorical_crossentropy',
learning_rate=0.001)

model = tflearn.DNN(network, tensorboard_verbose=0, checkpoint_path='bird-classifier.tfl.ckpt')
model.load("bird-classifier.tfl.ckpt-50912")

# Load the image file
img = scipy.ndimage.imread(args.image, mode="RGB")

# Scale it to 32x32
img = scipy.misc.imresize(img, (32, 32), interp="bicubic").astype(np.float32, casting='unsafe')

# Predict
prediction = model.predict([img])

# Check the result.
is_bird = np.argmax(prediction[0]) == 1

if is_bird:
print("That's a bird!")
else:
print("That's not a bird!")

可是采用上面的腳本對模型進行檢驗,相信大傢訓練模型的時候,都懂得規矩吧!

訓練集-驗證集-測試集(當然你還可以有自己的劃分方式,隻要確保你進行測試的數據沒有在訓練過程中使用到即可)

(訓練集(80%數據)用於訓練模型-驗證集(10%數據)用於檢驗模型訓練效果-測試集(10%數據)用於測試模型最終性能)

使用測試集進行測試得到的模型準確率為95%左右!

結果好像非常的棒!但是事實真的是這樣嘛!如果我們的測試集裡面一共1000張照片,裡面有50張鳥的照片,950張不是鳥的照片,模型隻要都將圖片判定為不是鳥,就可以達到95%的準確率瞭!但是這樣的模型沒有任何的意義!

所以我們采用另外一種評定模型性能的方式。

  1. 圖像中是鳥並且模型識別為也是鳥:稱其為真陽性
  2. 圖像中不是鳥並且模型識別不是鳥:稱其為真陰性
  3. 圖像中不是鳥但是模型偏識別為鳥:稱其為假陽性
  4. 圖像中是鳥但是模型識別為不是鳥:稱其為假陰性

我們將測試集中的鳥類的圖片按照上述的評定方式進行統計:

是貓是狗,遛一遛

之所以這樣做,是因為很多事情犯錯的成本或者成功的收益往往是不對等的!比如說:癌癥檢測,假陰性比假陽性要壞的多;人臉識別,假陽性比假陰性要壞的多!

采用這種方式,我們就可以計算出模型的精準率和召回率,而不是單單采用模型準確率來對模型進行評判!

精準率告訴我們模型有97%的概率能夠猜對是鳥!

召回率告訴我們模型隻能找到數據集中91%的鳥!

是貓是狗,遛一遛


Published in News by Awesome.

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *