Ⅰ 如何在後台部署深度學習模型
搭建深度學習後台伺服器
我們的Keras深度學習REST API將能夠批量處理圖像,擴展到多台機器(包括多台web伺服器和Redis實例),並在負載均衡器之後進行循環調度。
為此,我們將使用:
KerasRedis(內存數據結構存儲)
Flask (Python的微web框架)
消息隊列和消息代理編程範例
本篇文章的整體思路如下:
我們將首先簡要討論Redis數據存儲,以及如何使用它促進消息隊列和消息代理。然後,我們將通過安裝所需的Python包來配置Python開發環境,以構建我們的Keras深度學習REST API。一旦配置了開發環境,就可以使用Flask web框架實現實際的Keras深度學習REST API。在實現之後,我們將啟動Redis和Flask伺服器,然後使用cURL和Python向我們的深度學習API端點提交推理請求。最後,我們將以對構建自己的深度學習REST API時應該牢記的注意事項的簡短討論結束。
第一部分:簡要介紹Redis如何作為REST API消息代理/消息隊列
測試和原文的命令一致。
第三部分:配置Python開發環境以構建Keras REST API
文章中說需要創建新的虛擬環境來防止影響系統級別的python項目(但是我沒有創建),但是還是需要安裝rest api所需要依賴的包。以下為所需要的包。
第四部分:實現可擴展的Keras REST API
首先是Keras Redis Flask REST API數據流程圖
讓我們開始構建我們的伺服器腳本。為了方便起見,我在一個文件中實現了伺服器,但是它可以按照您認為合適的方式模塊化。為了獲得最好的結果和避免復制/粘貼錯誤,我建議您使用本文的「下載」部分來獲取相關的腳本和圖像。
為了簡單起見,我們將在ImageNet數據集上使用ResNet預訓練。我將指出在哪裡可以用你自己的模型交換ResNet。flask模塊包含flask庫(用於構建web API)。redis模塊將使我們能夠與redis數據存儲介面。從這里開始,讓我們初始化將在run_keras_server.py中使用的常量.
我們將向伺服器傳遞float32圖像,尺寸為224 x 224,包含3個通道。我們的伺服器可以處理一個BATCH_SIZE = 32。如果您的生產系統上有GPU(s),那麼您需要調優BATCH_SIZE以獲得最佳性能。我發現將SERVER_SLEEP和CLIENT_SLEEP設置為0.25秒(伺服器和客戶端在再次輪詢Redis之前分別暫停的時間)在大多數系統上都可以很好地工作。如果您正在構建一個生產系統,那麼一定要調整這些常量。
讓我們啟動我們的Flask app和Redis伺服器:
在這里你可以看到啟動Flask是多麼容易。在運行這個伺服器腳本之前,我假設Redis伺服器正在運行(之前的redis-server)。我們的Python腳本連接到本地主機6379埠(Redis的默認主機和埠值)上的Redis存儲。不要忘記將全局Keras模型初始化為None。接下來我們來處理圖像的序列化:
Redis將充當伺服器上的臨時數據存儲。圖像將通過諸如cURL、Python腳本甚至是移動應用程序等各種方法進入伺服器,而且,圖像只能每隔一段時間(幾個小時或幾天)或者以很高的速率(每秒幾次)進入伺服器。我們需要把圖像放在某個地方,因為它們在被處理前排隊。我們的Redis存儲將作為臨時存儲。
為了將圖像存儲在Redis中,需要對它們進行序列化。由於圖像只是數字數組,我們可以使用base64編碼來序列化圖像。使用base64編碼還有一個額外的好處,即允許我們使用JSON存儲圖像的附加屬性。
base64_encode_image函數處理序列化。類似地,在通過模型傳遞圖像之前,我們需要反序列化圖像。這由base64_decode_image函數處理。
預處理圖片
我已經定義了一個prepare_image函數,它使用Keras中的ResNet50實現對輸入圖像進行預處理,以便進行分類。在使用您自己的模型時,我建議修改此函數,以執行所需的預處理、縮放或規范化。
從那裡我們將定義我們的分類方法
classify_process函數將在它自己的線程中啟動,我們將在下面的__main__中看到這一點。該函數將從Redis伺服器輪詢圖像批次,對圖像進行分類,並將結果返回給客戶端。
在model = ResNet50(weights="imagenet")這一行中,我將這個操作與終端列印消息連接起來——根據Keras模型的大小,載入是即時的,或者需要幾秒鍾。
載入模型只在啟動這個線程時發生一次——如果每次我們想要處理一個映像時都必須載入模型,那麼速度會非常慢,而且由於內存耗盡可能導致伺服器崩潰。
載入模型後,這個線程將不斷輪詢新的圖像,然後將它們分類(注意這部分代碼應該時尚一部分的繼續)
在這里,我們首先使用Redis資料庫的lrange函數從隊列(第79行)中獲取最多的BATCH_SIZE圖像。
從那裡我們初始化imageIDs和批處理(第80和81行),並開始在第84行開始循環隊列。
在循環中,我們首先解碼對象並將其反序列化為一個NumPy數組image(第86-88行)。
接下來,在第90-96行中,我們將向批處理添加圖像(或者如果批處理當前為None,我們將該批處理設置為當前圖像)。
我們還將圖像的id附加到imageIDs(第99行)。
讓我們完成循環和函數
在這個代碼塊中,我們檢查批處理中是否有圖像(第102行)。如果我們有一批圖像,我們通過模型(第105行)對整個批進行預測。從那裡,我們循環一個圖像和相應的預測結果(110-122行)。這些行向輸出列表追加標簽和概率,然後使用imageID將輸出存儲在Redis資料庫中(第116-122行)。
我們使用第125行上的ltrim從隊列中刪除了剛剛分類的圖像集。最後,我們將睡眠設置為SERVER_SLEEP時間並等待下一批圖像進行分類。下面我們來處理/predict我們的REST API端點
稍後您將看到,當我們發布到REST API時,我們將使用/predict端點。當然,我們的伺服器可能有多個端點。我們使用@app。路由修飾符以第130行所示的格式在函數上方定義端點,以便Flask知道調用什麼函數。我們可以很容易地得到另一個使用AlexNet而不是ResNet的端點,我們可以用類似的方式定義具有關聯函數的端點。你懂的,但就我們今天的目的而言,我們只有一個端點叫做/predict。
我們在第131行定義的predict方法將處理對伺服器的POST請求。這個函數的目標是構建JSON數據,並將其發送回客戶機。如果POST數據包含圖像(第137和138行),我們將圖像轉換為PIL/Pillow格式,並對其進行預處理(第141-143行)。
在開發這個腳本時,我花了大量時間調試我的序列化和反序列化函數,結果發現我需要第147行將數組轉換為C-contiguous排序(您可以在這里了解更多)。老實說,這是一個相當大的麻煩事,但我希望它能幫助你站起來,快速跑。
如果您想知道在第99行中提到的id,那麼實際上是使用uuid(通用唯一標識符)在第151行生成的。我們使用UUID來防止hash/key沖突。
接下來,我們將圖像的id和base64編碼附加到d字典中。使用rpush(第153行)將這個JSON數據推送到Redis db非常簡單。
讓我們輪詢伺服器以返回預測
我們將持續循環,直到模型伺服器返回輸出預測。我們開始一個無限循環,試圖得到157-159條預測線。從這里,如果輸出包含預測,我們將對結果進行反序列化,並將結果添加到將返回給客戶機的數據中。我們還從db中刪除了結果(因為我們已經從資料庫中提取了結果,不再需要將它們存儲在資料庫中),並跳出了循環(第163-172行)。
否則,我們沒有任何預測,我們需要睡覺,繼續投票(第176行)。如果我們到達第179行,我們已經成功地得到了我們的預測。在本例中,我們向客戶機數據添加True的成功值(第179行)。注意:對於這個示例腳本,我沒有在上面的循環中添加超時邏輯,這在理想情況下會為數據添加一個False的成功值。我將由您來處理和實現。最後我們稱燒瓶。jsonify對數據,並將其返回給客戶端(第182行)。這就完成了我們的預測函數。
為了演示我們的Keras REST API,我們需要一個__main__函數來實際啟動伺服器
第186-196行定義了__main__函數,它將啟動classify_process線程(第190-192行)並運行Flask應用程序(第196行)。
第五部分:啟動可伸縮的Keras REST API
要測試我們的Keras深度學習REST API,請確保使用本文的「下載」部分下載源代碼示例圖像。從這里,讓我們啟動Redis伺服器,如果它還沒有運行:
然後,在另一個終端中,讓我們啟動REST API Flask伺服器:
另外,我建議在向伺服器提交請求之前,等待您的模型完全載入到內存中。現在我們可以繼續使用cURL和Python測試伺服器。
第七部分:使用cURL訪問Keras REST API
使用cURL來測試我們的Keras REST API伺服器。這是我的家庭小獵犬Jemma。根據我們的ResNet模型,她被歸類為一隻擁有94.6%自信的小獵犬。
你會在你的終端收到JSON格式的預測:
第六部分:使用Python向Keras REST API提交請求
如您所見,使用cURL驗證非常簡單。現在,讓我們構建一個Python腳本,該腳本將發布圖像並以編程方式解析返回的JSON。
讓我們回顧一下simple_request.py
我們在這個腳本中使用Python請求來處理向伺服器提交數據。我們的伺服器運行在本地主機上,可以通過埠5000訪問端點/predict,這是KERAS_REST_API_URL變數(第6行)指定的。
我們還定義了IMAGE_PATH(第7行)。png與我們的腳本在同一個目錄中。如果您想測試其他圖像,請確保指定到您的輸入圖像的完整路徑。
讓我們載入圖像並發送到伺服器:
我們在第10行以二進制模式讀取圖像並將其放入有效負載字典。負載通過請求發送到伺服器。在第14行發布。如果我們得到一個成功消息,我們可以循環預測並將它們列印到終端。我使這個腳本很簡單,但是如果你想變得更有趣,你也可以使用OpenCV在圖像上繪制最高的預測文本。
第七部分:運行簡單的請求腳本
編寫腳本很容易。打開終端並執行以下命令(當然,前提是我們的Flask伺服器和Redis伺服器都在運行)。
使用Python以編程方式使用我們的Keras深度學習REST API的結果
第八部分:擴展深度學習REST API時的注意事項
如果您預期在深度學習REST API上有較長一段時間的高負載,那麼您可能需要考慮一種負載平衡演算法,例如循環調度,以幫助在多個GPU機器和Redis伺服器之間平均分配請求。
記住,Redis是內存中的數據存儲,所以我們只能在隊列中存儲可用內存中的盡可能多的圖像。
使用float32數據類型的單個224 x 224 x 3圖像將消耗602112位元組的內存。
Ⅱ 基於keras框架編寫的圖片分類模型,訓練結果識別率98%以上,為什麼單張識別圖片類型會出錯
預測時你是怎麼做的?一般來講你的model訓練好了之後,參數就已經固定好了,此時直接調用model.predict就是在用訓練好的模型做預測,如果你不重新跑訓練過程,參數是不會變的。或者你可以model.save下次再model.load載入也可以。至於你說有時訓練acc是0,一般是在什麼情況下出現的?
Ⅲ 如何用Keras自定義層
lambda層是沒有參數學習的功能的,你要做的就是將每張圖片上像素的最大值和最小值的函數包裝進lambda層。你的輸入是(batch,224,224,3),寫一個在每個通道上提取空間特徵的最大最小值的函數。假設為spatial_max(input)和spatial_min(input),那麼新層你可以直接寫為new_layer1=Lambda(spatial_max, x : x)(input)
new_layer2=Lambda(spatial_min, x : x)(input)
Ⅳ 求助keras的imagedatagenerator使用
一個稍微講究一點的辦法是,利用在大規模數據集上預訓練好的網路。這樣的網路在多數的計算機視覺問題上都能取得不錯的特徵,利用這樣的特徵可以讓我們獲得更高的准確率。
我們將使用vgg-16網路,該網路在ImageNet數據集上進行訓練,這個模型我們之前提到過了。因為ImageNet數據集包含多種「貓」類和多種「狗」類,這個模型已經能夠學習與我們這個數據集相關的特徵了。事實上,簡單的記錄原來網路的輸出而不用bottleneck特徵就已經足夠把我們的問題解決的不錯了。不過我們這里講的方法對其他的類似問題有更好的推廣性,包括在ImageNet中沒有出現的類別的分類問題。
VGG-16的網路結構如下:
我們的方法是這樣的,我們將利用網路的卷積層部分,把全連接以上的部分拋掉。然後在我們的訓練集和測試集上跑一遍,將得到的輸出(即「bottleneck feature」,網路在全連接之前的最後一層激活的feature map)記錄在兩個numpy array里。然後我們基於記錄下來的特徵訓練一個全連接網路。
我們將這些特徵保存為離線形式,而不是將我們的全連接模型直接加到網路上並凍結之前的層參數進行訓練的原因是處於計算效率的考慮。運行VGG網路的代價是非常高昂的,尤其是在CPU上運行,所以我們只想運行一次。這也是我們不進行數據提升的原因。
我們不再贅述如何搭建vgg-16網路了,這件事之前已經說過,在keras的example里也可以找到。但讓我們看看如何記錄bottleneck特徵。
generator = datagen.flow_from_directory(
'data/train',
target_size=(150, 150),
batch_size=32,
class_mode=None, # this means our generator will only yield batches of data, no labels
shuffle=False) # our data will be in order, so all first 1000 images will be cats, then 1000 dogs
# the predict_generator method returns the output of a model, given
# a generator that yields batches of numpy data
bottleneck_features_train = model.predict_generator(generator, 2000)
# save the output as a Numpy array
np.save(open('bottleneck_features_train.npy', 'w'), bottleneck_features_train)
generator = datagen.flow_from_directory(
'data/validation',
target_size=(150, 150),
batch_size=32,
class_mode=None,
shuffle=False)
bottleneck_features_validation = model.predict_generator(generator, 800)
np.save(open('bottleneck_features_validation.npy', 'w'), bottleneck_features_validation)
記錄完畢後我們可以將數據載入,用於訓練我們的全連接網路:
train_data = np.load(open('bottleneck_features_train.npy'))
# the features were saved in order, so recreating the labels is easy
train_labels = np.array([0] * 1000 + [1] * 1000)
validation_data = np.load(open('bottleneck_features_validation.npy'))
validation_labels = np.array([0] * 400 + [1] * 400)
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:]))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
model.fit(train_data, train_labels,
nb_epoch=50, batch_size=32,
validation_data=(validation_data, validation_labels))
model.save_weights('bottleneck_fc_model.h5')
因為特徵的size很小,模型在CPU上跑的也會很快,大概1s一個epoch,最後我們的准確率是90%~91%,這么好的結果多半歸功於預訓練的vgg網路幫助我們提取特徵。
下面是代碼:
[python] view plain
import os
import h5py
import numpy as np
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras.layers import Activation, Dropout, Flatten, Dense
import sys
defaultencoding = 'utf-8'
if sys.getdefaultencoding() != defaultencoding:
reload(sys)
sys.setdefaultencoding(defaultencoding)
# path to the model weights file.
weights_path = '../weights/vgg16_weights.h5'
top_model_weights_path = 'bottleneck_fc_model.h5'
# dimensions of our images.
img_width, img_height = 150, 150
train_data_dir = '../data/train'
validation_data_dir = '../data/validation'
nb_train_samples = 2000
nb_validation_samples = 800
nb_epoch = 50
def save_bottlebeck_features():
datagen = ImageDataGenerator(rescale=1./255)
# build the VGG16 network
model = Sequential()
model.add(ZeroPadding2D((1, 1), input_shape=(3, img_width, img_height)))
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
# load the weights of the VGG16 networks
# (trained on ImageNet, won the ILSVRC competition in 2014)
# note: when there is a complete match between your model definition
# and your weight savefile, you can simply call model.load_weights(filename)
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
f = h5py.File(weights_path)
for k in range(f.attrs['nb_layers']):
if k >= len(model.layers):
# we don't look at the last (fully-connected) layers in the savefile
break
g = f['layer_{}'.format(k)]
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
model.layers[k].set_weights(weights)
f.close()
print('Model loaded.')
generator = datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=32,
class_mode=None,
shuffle=False)
print('generator ok.')
bottleneck_features_train = model.predict_generator(generator, nb_train_samples)
print('predict ok.')
np.save(open('bottleneck_features_train.npy', 'wb'), bottleneck_features_train)
generator = datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=32,
class_mode=None,
shuffle=False)
bottleneck_features_validation = model.predict_generator(generator, nb_validation_samples)
np.save(open('bottleneck_features_validation.npy', 'wb'), bottleneck_features_validation)
print('save_bottlebeck_features ok')
def train_top_model():
train_data = np.load(open('bottleneck_features_train.npy'))
train_labels = np.array([0] * (nb_train_samples / 2) + [1] * (nb_train_samples / 2))
validation_data = np.load(open('bottleneck_features_validation.npy'))
validation_labels = np.array([0] * (nb_validation_samples / 2) + [1] * (nb_validation_samples / 2))
model = Sequential()
model.add(Flatten(input_shape=train_data.shape[1:]))
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
model.fit(train_data, train_labels,
nb_epoch=nb_epoch, batch_size=32,
validation_data=(validation_data, validation_labels))
model.save_weights(top_model_weights_path)
print('train_top_model ok')
save_bottlebeck_features()
train_top_model()
Ⅳ keras訓練完模型,為什麼對訓練集進行evaluate和訓練時的loss完全不一樣白訓練了嗎
問題簡述:
在keras框架下使用model.fit得到的訓練准確率和損失表現都非常好,但是在相同的訓練集上使用model.evaluate得到的准確率和損失都非常差
keras中的model.fit和model.evaluate在同樣的數據集上的准確率acc和損失值loss存在巨大的差異
https://github.com/keras-team/keras/issues/6977
上面的github鏈接討論了多種可能,
1.model.fit和model.evaluate的batch_size不匹配:model.fit時若指定了batch_size,在使用model.evaluate時的batch_size默認為16,而使用model.evaluate時並未設置與使用model.fit時同樣的batch_size。解釋大概為不同的batch_size的BatchNormalizaiton會產生不同的效果不同(當然在神經網路中存在BatchNormalization層時)
結果:匹配batch_size了也無效
2.dropout,batchnorm的影響:model.fit時的dropout層是設置dropout參數的,比如說0.5,而model.evaluate設置的dropout參數為1,keras在使用這兩個function的時候會呈現兩種模式
Ⅵ 如何修改keras已經訓練好的模型的input shape
對於一個預測圖片類別的模型來說,輸入必須是一個4D tensor,比如VGG16在訓練的時候輸入的數據格式為(batch size,224,224,3)。在用訓練好的VGG16模型預測一張圖片時,只不過batch size為1。下面是VGG16預測一張圖片時做的預處理,就是為輸入數據多擴展一個維度。
Ⅶ Python如何圖像識別
Python圖片文本識別使用的工具是PIL和pytesser。因為他們使用到很多的python庫文件,為了避免一個個工具的安裝,建議使用pythonxy
pytesser是OCR開源項目的一個模塊,在Python中導入這個模塊即可將圖片中的文字轉換成文本。pytesser調用了tesseract。當在Python中調用pytesser模塊時,pytesser又用tesseract識別圖片中的文字。pytesser的使用步驟如下:
首先,安裝Python2.7版本,這個版本比較穩定,建議使用這個版本。
其次,安裝pythoncv。
然後,安裝PIL工具,pytesser的使用需要PIL庫的支持。
接著下載pytesser
最後,將pytesser解壓,這個是免安裝的,可以將解壓後的文件cut到Python安裝目錄的Lib\site-packages下直接使用,比如我的安裝目錄是:C:\Python27\Lib\site-packages,同時把這個目錄添加到環境變數之中。
完成以上步驟之後,就可以編寫圖片文本識別的Python腳本了。參考腳本如下:
from pytesser import *
import ImageEnhance
image = Image.open('D:\\workspace\\python\\5.png')
#使用ImageEnhance可以增強圖片的識別率
enhancer = ImageEnhance.Contrast(image)
image_enhancer = enhancer.enhance(4)
print image_to_string(image_enhancer)
tesseract是谷歌的一個對圖片進行識別的開源框架,免費使用,現在已經支持中文,而且識別率非常高,這里簡要來個helloworld級別的認識
下載之後進行安裝,不再演示。
在tesseract目錄下,有個tesseract.exe文件,主要調用這個執行文件,用cmd運行到這個目錄下,在這個目錄下同時放置一張需要識別的圖片,這里是123.jpg
然後運行:tesseract 123.jpg result
會把123.jpg自動識別並轉換為txt文件到result.txt
但是此時中文識別不好
然後找到tessdata目錄,把eng.traineddata替換為chi_sim.traineddata,並且把chi_sim.traineddata重命名為eng.traineddata
ok,現在中文識別基本達到90%以上了
Ⅷ keras 如何輸出softmax分類結果屬於某一類的概率
softmax是用於單標簽輸出,模型訓練後,調用model.predict函數就可以輸出結果為[0.5,0.4,0.1](輸出數量為最後一層隱藏層的neuron數)這樣的矩陣,裡面即為你所需的預測概率值,值得注意的是,softmax會限制輸出的所有概率相加為1。
如果需要預測的是多個標簽而不是單個標簽,則需要使用sigmoid作為輸出激活函數,那麼輸出就不再強制相加為1,可以得到每個分類的實際預測值,此時只需要設置一個致信的threshold則可以得到多個分類預測值。
每個激活函數的詳細解釋看這里網頁鏈接
Ⅸ Python 用Keras訓練卷積網路,提取的特徵,如何保存,代碼如下
可以用
np.savez('xxx.npz',train_labels=train_labels)
載入時用
np.load('xxx.npz')
Ⅹ 如何通過Python進行深度學習
作者 | Vihar Kurama
編譯 | 荷葉
來源 | 雲棲社區
摘要:深度學習背後的主要原因是人工智慧應該從人腦中汲取靈感。本文就用一個小例子無死角的介紹一下深度學習!
人腦模擬
深度學習背後的主要原因是人工智慧應該從人腦中汲取靈感。此觀點引出了「神經網路」這一術語。人腦中包含數十億個神經元,它們之間有數萬個連接。很多情況下,深度學習演算法和人腦相似,因為人腦和深度學習模型都擁有大量的編譯單元(神經元),這些編譯單元(神經元)在獨立的情況下都不太智能,但是當他們相互作用時就會變得智能。
我認為人們需要了解到深度學習正在使得很多幕後的事物變得更好。深度學習已經應用於谷歌搜索和圖像搜索,你可以通過它搜索像「擁抱」這樣的詞語以獲得相應的圖像。-傑弗里·辛頓
神經元
神經網路的基本構建模塊是人工神經元,它模仿了人類大腦的神經元。這些神經元是簡單、強大的計算單元,擁有加權輸入信號並且使用激活函數產生輸出信號。這些神經元分布在神經網路的幾個層中。
inputs 輸入 outputs 輸出 weights 權值 activation 激活
人工神經網路的工作原理是什麼?
深度學習由人工神經網路構成,該網路模擬了人腦中類似的網路。當數據穿過這個人工網路時,每一層都會處理這個數據的一方面,過濾掉異常值,辨認出熟悉的實體,並產生最終輸出。
輸入層:該層由神經元組成,這些神經元只接收輸入信息並將它傳遞到其他層。輸入層的圖層數應等於數據集里的屬性或要素的數量。輸出層:輸出層具有預測性,其主要取決於你所構建的模型類型。隱含層:隱含層處於輸入層和輸出層之間,以模型類型為基礎。隱含層包含大量的神經元。處於隱含層的神經元會先轉化輸入信息,再將它們傳遞出去。隨著網路受訓練,權重得到更新,從而使其更具前瞻性。
神經元的權重
權重是指兩個神經元之間的連接的強度或幅度。你如果熟悉線性回歸的話,可以將輸入的權重類比為我們在回歸方程中用的系數。權重通常被初始化為小的隨機數值,比如數值0-1。
前饋深度網路
前饋監督神經網路曾是第一個也是最成功的學習演算法。該網路也可被稱為深度網路、多層感知機(MLP)或簡單神經網路,並且闡明了具有單一隱含層的原始架構。每個神經元通過某個權重和另一個神經元相關聯。
該網路處理向前處理輸入信息,激活神經元,最終產生輸出值。在此網路中,這稱為前向傳遞。
inputlayer 輸入層 hidden layer 輸出層 output layer 輸出層
激活函數
激活函數就是求和加權的輸入到神經元的輸出的映射。之所以稱之為激活函數或傳遞函數是因為它控制著激活神經元的初始值和輸出信號的強度。
用數學表示為:
我們有許多激活函數,其中使用最多的是整流線性單元函數、雙曲正切函數和solfPlus函數。
激活函數的速查表如下:
反向傳播
在網路中,我們將預測值與預期輸出值相比較,並使用函數計算其誤差。然後,這個誤差會傳回這個網路,每次傳回一個層,權重也會根絕其導致的誤差值進行更新。這個聰明的數學法是反向傳播演算法。這個步驟會在訓練數據的所有樣本中反復進行,整個訓練數據集的網路更新一輪稱為一個時期。一個網路可受訓練數十、數百或數千個時期。
prediction error 預測誤差
代價函數和梯度下降
代價函數度量了神經網路對給定的訓練輸入和預期輸出「有多好」。該函數可能取決於權重、偏差等屬性。
代價函數是單值的,並不是一個向量,因為它從整體上評估神經網路的性能。在運用梯度下降最優演算法時,權重在每個時期後都會得到增量式地更新。
兼容代價函數
用數學表述為差值平方和:
target 目標值 output 輸出值
權重更新的大小和方向是由在代價梯度的反向上採取步驟計算出的。
其中η 是學習率
其中Δw是包含每個權重系數w的權重更新的向量,其計算方式如下:
target 目標值 output 輸出值
圖表中會考慮到單系數的代價函數
initial weight 初始權重 gradient 梯度 global cost minimum 代價極小值
在導數達到最小誤差值之前,我們會一直計算梯度下降,並且每個步驟都會取決於斜率(梯度)的陡度。
多層感知器(前向傳播)
這類網路由多層神經元組成,通常這些神經元以前饋方式(向前傳播)相互連接。一層中的每個神經元可以直接連接後續層的神經元。在許多應用中,這些網路的單元會採用S型函數或整流線性單元(整流線性激活)函數作為激活函數。
現在想想看要找出處理次數這個問題,給定的賬戶和家庭成員作為輸入
要解決這個問題,首先,我們需要先創建一個前向傳播神經網路。我們的輸入層將是家庭成員和賬戶的數量,隱含層數為1, 輸出層將是處理次數。
將圖中輸入層到輸出層的給定權重作為輸入:家庭成員數為2、賬戶數為3。
現在將通過以下步驟使用前向傳播來計算隱含層(i,j)和輸出層(k)的值。
步驟:
1, 乘法-添加方法。
2, 點積(輸入*權重)。
3,一次一個數據點的前向傳播。
4, 輸出是該數據點的預測。
i的值將從相連接的神經元所對應的輸入值和權重中計算出來。
i = (2 * 1) + (3* 1) → i = 5
同樣地,j = (2 * -1) + (3 * 1) → j =1
K = (5 * 2) + (1* -1) → k = 9
Python中的多層感知器問題的解決
激活函數的使用
為了使神經網路達到其最大預測能力,我們需要在隱含層應用一個激活函數,以捕捉非線性。我們通過將值代入方程式的方式來在輸入層和輸出層應用激活函數。
這里我們使用整流線性激活(ReLU):
用Keras開發第一個神經網路
關於Keras:
Keras是一個高級神經網路的應用程序編程介面,由Python編寫,能夠搭建在TensorFlow,CNTK,或Theano上。
使用PIP在設備上安裝Keras,並且運行下列指令。
在keras執行深度學習程序的步驟
1,載入數據;
2,創建模型;
3,編譯模型;
4,擬合模型;
5,評估模型。
開發Keras模型
全連接層用Dense表示。我們可以指定層中神經元的數量作為第一參數,指定初始化方法為第二參數,即初始化參數,並且用激活參數確定激活函數。既然模型已經創建,我們就可以編譯它。我們在底層庫(也稱為後端)用高效數字型檔編譯模型,底層庫可以用Theano或TensorFlow。目前為止,我們已經完成了創建模型和編譯模型,為進行有效計算做好了准備。現在可以在PIMA數據上運行模型了。我們可以在模型上調用擬合函數f(),以在數據上訓練或擬合模型。
我們先從KERAS中的程序開始,
神經網路一直訓練到150個時期,並返回精確值。