如何使用 Keras,Python 和深度學習進行多 GPU 訓練

2021-03-02 AI有道

點擊上方「AI有道」,選擇「星標」公眾號

重磅乾貨,第一時間送達

作者:pyimagesearch

原文連結:https://www.pyimagesearch.com/2017/10/30/how-to-multi-gpu-training-with-keras-python-and-deep-learning/

編譯:AI算法與圖像處理

內容簡介

Keras簡單而優雅,類似於scikit-learn。然而,它非常強大,能夠實施和訓練最先進的深度神經網絡。

然而,我們對keras最感到受挫的一個原因,是在多GPU環境下使用,因為這是非常重要的。

如果你使用Theano,請忽略它——多GPU訓練,這並不會發生。

TensorFlow還是有使用的可能性,但它可能需要大量的樣板代碼和調整才能是你的網絡使用多個GPU進行訓練。

在使用多GPU訓練的時,我更喜歡用mxnet後端(或甚至直接是mxnet庫)而不是keras,但這會引入更多配置進行處理。

隨著François Chollet’s宣布tensorflow後端對多GPU的支持已經融入到keras v2.0.9時,所有這一切都發生了改變。大部分功勞歸功於 kuza55(ID)和他們的keras-extras回購。

我已經使用並測試了這個多GPU功能近一年,我非常高興能將它視為官方keras發行版的一部分。

在今天文章的其他部分中,我將演示如何使用keras,python和深度學習訓練圖像分類的CNN。

MiniGoogLeNet 深度學習框架

圖1:MiniGoogLeNet架構是它的大兄弟GoogLeNet / Inception的一個小版本。

在上面的圖1中,我們可以看到單個卷積(左),初始(中)和下採樣(右)模塊,然後是從這些模塊來構建MiniGoogLeNet架構(底部)。我們將在本文後面的多GPU實驗中使用MiniGoogLeNet架構。

在MiniGoogLeNet中的Inception是由Szegedy 等人設計的,是原始Inception模塊的變體。

我首先從@ericjang11 和 @pluskid 的推文中了解了這個「Miniception」模塊,它們精美地可視化模塊和相關的MiniGoogLeNet架構。

在做了一些研究後,我發現這張圖片來自張等人2017的文章https://arxiv.org/abs/1611.03530

然後我開始在keras和python中應用MiniGoogLe架構——甚至使用python進行計算機視覺深度學習這本書的一部分。

對MiniGoogLeNet實現全面的複習超出了本文的範圍,因此如果你對網絡的工作原理(以及如何編碼)感興趣,可以參閱這本書https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/

使用keras和多GPU訓練一個深層神經網絡

首先確保在環境中安裝和更新keras 2.09(或更高版本):

這裡,新建一個文件並命名為train.py,然後插入下面的代碼:

# 設置matplotlib後端,這樣子數字可以保存在後端(如果你使用的是headless server,請取消注釋下面的行)# import matplotlib# matplotlib.use("Agg") # 導入必要的包from pyimagesearch.minigooglenet import MiniGoogLeNetfrom sklearn.preprocessing import LabelBinarizerfrom keras.preprocessing.image import ImageDataGeneratorfrom keras.callbacks import LearningRateSchedulerfrom keras.utils.training_utils import multi_gpu_modelfrom keras.optimizers import SGDfrom keras.datasets import cifar10import matplotlib.pyplot as pltimport tensorflow as tfimport numpy as npimport argparse

如果你使用的是headless server,則需要通過取消注釋行來配置2-3行的matplotlib後端。這樣可以將matplotlib圖保存到磁碟。如果你沒有使用headless server(即,你的鍵盤+滑鼠+顯示器插入系統,則可以將線條注釋掉)。

這裡,我們導入這個腳本所需的包。

第6行從我的pyimagesearch模塊導入MiniGoogLeNet。

另一個值得注意的是12行的導入了CIFAR10數據集。這個輔助函數將使我們導入CIFAR-10數據集。

現在讓我們解析命令行參數:

# 構建解析參數ap = argparse.ArgumentParser()ap.add_argument("-o", "--output", required=True,  help="path to output plot")ap.add_argument("-g", "--gpus", type=int, default=1,  help="# of GPUs to use for training")args = vars(ap.parse_args()) # 獲取GPU的數量並將其存儲在一個傳輸變量中G = args["gpus"]

我們使用argparse去解析一個必要參數和一個可選參數:

--output:訓練完成後的輸出圖的路徑

--gpus:用於訓練的gpu數量

加載命令行參數後,為了方便起見,我們將GPU的數量存儲為G(10行)。

這裡,我們初始化用於配置我們的訓練過程的兩個重要遍歷,然後定義poly_decay,一個等同於caff的多項式學習速率衰減的學習率調度函數https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe:

# 定義要訓練的周期數以及初始學習率NUM_EPOCHS = 70INIT_LR = 5e-3 def poly_decay(epoch):  # 初始化最大周期數,基本學習率和多項式的冪次  maxEpochs = NUM_EPOCHS  baseLR = INIT_LR  power = 1.0   # 根據多項式衰減計算新的學習率  alpha = baseLR * (1 - (epoch / float(maxEpochs))) ** power   # 返回新的學習率  return alpha

我們設置 NUM_EPOCHS=70——這是我們訓練數據將要傳遞給網絡的次數(周期)

初始化學習率INIT_LR=5e-3,這是在之前的試驗中發現的值

這裡定義poly_decay函數,它相當於Caffe的多項式學習速率衰減。本質上,此功能可在訓練期間更新學習率,並在每個時期後有效減少學習率。設置power=1.0會將衰減從多項式變為線性。

接下來我們將加載我們的訓練+測試數據並將圖像數據從整數轉換為浮點數:

# 加載訓練和測試數據,將圖像從整數轉換為浮點數print("[INFO] loading CIFAR-10 data...")((trainX, trainY), (testX, testY)) = cifar10.load_data()trainX = trainX.astype("float")testX = testX.astype("float")

這裡,將對數據應用平均值相減:

mean = np.mean(trainX, axis=0)trainX -= meantestX -= mean

計算所有訓練圖像的平均值,然後從訓練和測試集中的每個圖像中減去平均值。

然後執行獨熱編碼(one-hot encoding):

# 構造用於數據增強的圖像生成器並構造一系列的回調函數aug = ImageDataGenerator(width_shift_range=0.1,  height_shift_range=0.1, horizontal_flip=True,  fill_mode="nearest")callbacks = [LearningRateScheduler(poly_decay)]

第2行構造用於數據增強的圖像生成器。

由於這些改變,網絡不斷地看到增強的示例 - 這使得網絡能夠更好地概括驗證數據,同時可能在訓練集上表現更差。在大多數情況下,這些權衡是值得的。

我們在第5行創建了一個回調函數,它允許我們的學習速率在每個周期後衰減 - 注意我們的函數名稱poly_decay。

我們接下來檢查GPU變量:

# 檢測我們是否只使用一個GPU進行編譯if G <= 1:  print("[INFO] training with 1 GPU...")  model = MiniGoogLeNet.build(width=32, height=32, depth=3,    classes=10)

如果GPU計數小於或等於1,我們通過.build函數初始化模型(第2-5行),否則我們將在訓練期間並行化模型:

# 否則,我們正在使用多個GPU進行編譯else:  print("[INFO] training with {} GPUs...".format(G))   # 我們將在* every * GPU上存儲模型的副本,然後將CPU上的漸變更新結果組合在一起  with tf.device("/cpu:0"):    # 初始化模型    model = MiniGoogLeNet.build(width=32, height=32, depth=3,      classes=10)    # 是模型並行  model = multi_gpu_model(model, gpus=G)

Keras中創建一個多GPU模型需要一些額外的代碼,但不多!

首先,您將在第6行注意到我們已指定使用CPU(而不是GPU)作為網絡上下文。

為什麼我們需要CPU?

CPU負責處理任何開銷(例如在GPU內存上移動和移動訓練圖像),而GPU本身則負擔繁重。

在這種情況下,CPU實例化基本模型。

然後我們可以在第12行調用multi_gpu_model。這個函數將模型從CPU複製到我們所有的GPU,從而獲得一個機,多個GPU數據並行性。

在訓練我們的網絡時,圖像將被批量分配到每個GPU。CPU將從每個GPU獲得梯度,然後執行梯度更新步驟。

然後我們可以編譯我們的模型並啟動訓練過程:

# 初始化優化器和模型print("[INFO] compiling model...")opt = SGD(lr=INIT_LR, momentum=0.9)model.compile(loss="categorical_crossentropy", optimizer=opt,  metrics=["accuracy"]) # 訓練網絡print("[INFO] training network...")H = model.fit_generator(  aug.flow(trainX, trainY, batch_size=64 * G),  validation_data=(testX, testY),  steps_per_epoch=len(trainX) // (64 * G),  epochs=NUM_EPOCHS,  callbacks=callbacks, verbose=2)  

第3行構建了一個隨機梯度下降(SGD)優化器。

隨後,我們使用SGD優化器和分類的交叉熵損失函數編譯模型。

現在準備訓練網絡了!

為了啟動訓練過程,我們調用model.fit_generator函數並提供必要的參數。

我們制定每個GPU上的batch大小64,因此batch_size=64*G

我們訓練將持續70個周期(前面已經制定)。

梯度更新的結果將在CPU上組合,然後在整個訓練過程中應用與每個GPU。

既然訓練和測試已經完成,讓我們畫出損失/準確率圖,以便可視化整個訓練過程。

# 獲取歷史對象字典H = H.history # 繪製訓練的loss和準確率的圖N = np.arange(0, len(H["loss"]))plt.style.use("ggplot")plt.figure()plt.plot(N, H["loss"], label="train_loss")plt.plot(N, H["val_loss"], label="test_loss")plt.plot(N, H["acc"], label="train_acc")plt.plot(N, H["val_acc"], label="test_acc")plt.title("MiniGoogLeNet on CIFAR-10")plt.xlabel("Epoch #")plt.ylabel("Loss/Accuracy")plt.legend() # 保存圖plt.savefig(args["output"])plt.close()

最後一塊僅使用matplotlib繪製訓練/測試的loss和準確率的曲線圖(6-15行),然後將曲線圖保存到磁碟中(18行)。

keras多GPU訓練結果

讓我們檢查一下辛勤的勞動成果。

首先,使用附帶連結中的代碼。然後,可以按照結果進行操作。

利用單個GPU進行訓練以獲取基準線(baseline):

$ python3 train.py [INFO] loading CIFAR-10 data...[INFO] training with 1 GPU...[INFO] compiling model...[INFO] training network...Epoch 1/70 - 64s - loss: 1.4323 - acc: 0.4787 - val_loss: 1.1319 - val_acc: 0.5983Epoch 2/70 - 63s - loss: 1.0279 - acc: 0.6361 - val_loss: 0.9844 - val_acc: 0.6472Epoch 3/70 - 63s - loss: 0.8554 - acc: 0.6997 - val_loss: 1.5473 - val_acc: 0.5592...Epoch 68/70 - 63s - loss: 0.0343 - acc: 0.9898 - val_loss: 0.3637 - val_acc: 0.9069Epoch 69/70 - 63s - loss: 0.0348 - acc: 0.9898 - val_loss: 0.3593 - val_acc: 0.9080Epoch 70/70 - 63s - loss: 0.0340 - acc: 0.9900 - val_loss: 0.3583 - val_acc: 0.9065Using TensorFlow backend. real    74m10.603suser    131m24.035ssys     11m52.143s

圖2 在單個GPU上使用Keras在CIFAR-10上訓練和測試MiniGoogLeNet網絡架構的實驗結果

對於這個實驗,我在我的NVIDIA DevBox上使用單個Titan X GPU進行了訓練。每個時期花費約63秒,總訓練時間為74分10秒。

然後我執行以下命令來訓練我的所有四個Titan X GPU:

$ python3 train.py [INFO] loading CIFAR-10 data...[INFO] training with 4 GPUs...[INFO] compiling model...[INFO] training network...Epoch 1/70 - 21s - loss: 1.6793 - acc: 0.3793 - val_loss: 1.3692 - val_acc: 0.5026Epoch 2/70 - 16s - loss: 1.2814 - acc: 0.5356 - val_loss: 1.1252 - val_acc: 0.5998Epoch 3/70 - 16s - loss: 1.1109 - acc: 0.6019 - val_loss: 1.0074 - val_acc: 0.6465...Epoch 68/70 - 16s - loss: 0.1615 - acc: 0.9469 - val_loss: 0.3654 - val_acc: 0.8852Epoch 69/70 - 16s - loss: 0.1605 - acc: 0.9466 - val_loss: 0.3604 - val_acc: 0.8863Epoch 70/70 - 16s - loss: 0.1569 - acc: 0.9487 - val_loss: 0.3603 - val_acc: 0.8877Using TensorFlow backend. real    19m3.318suser    104m3.270ssys     7m48.890s

圖3 在CIFAR10數據集上使用Keras和MiniGoogLeNet的多GPU培訓結果(4個Titan X GPU)。訓練結果類似於單GPU實驗,而訓練時間減少了約75%。

在這裡你可以看到訓練中的準線性加速:使用四個GPU,我能夠將每個時期減少到僅16秒。整個網絡在19分3秒內完成了訓練。

正如你所看到的,不僅可以輕鬆地使用Keras和多個GPU訓練深度神經網絡,它也是高效的!

注意:在這種情況下,單GPU實驗獲得的精度略高於多GPU實驗。在訓練任何隨機機器學習模型時,會有一些差異。如果你要在數百次運行中平均這些結果,它們將(大致)相同。

總結

在今天的博客文章中,我們學習了如何使用多個GPU來訓練基於Keras的深度神經網絡。

使用多個GPU使我們能夠獲得準線性加速。

為了驗證這一點,我們在CIFAR-10數據集上訓練了MiniGoogLeNet。

使用單個GPU,我們能夠獲得63秒的時間段,總訓練時間為74分10秒。

然而,通過使用Keras和Python的多GPU訓練,我們將訓練時間減少到16秒,總訓練時間為19m3s。

使用Keras啟用多GPU培訓就像單個函數調用一樣簡單 - 我建議儘可能使用多GPU培訓。在未來我想像multi_gpu_model將會發展並允許我們進一步定製哪些GPU應該用於訓練,最終還能實現多系統訓練。

重磅!AI 有道學術交流群成立啦

掃描下方二維碼,添加 AI有道小助手微信,可申請入林軒田機器學習群(數字 1)、吳恩達 deeplearning.ai 學習群(數字 2)。一定要備註:入哪個群(1 或 2 或 1+2)+ 地點 + 學校/公司 + 暱稱。例如:1+上海+復旦+小牛。 

長按掃碼,申請入群

(添加人數較多,請耐心等待)

 

最新 AI 乾貨,我在看 

相關焦點

  • 如何使用keras,python和深度學習進行多GPU訓練
    然而,它非常強大,能夠實施和訓練最先進的深度神經網絡。然而,我們對keras最感到受挫的一個原因,是在多GPU環境下使用,因為這是非常重要的。如果你使用Theano,請忽略它——多GPU訓練,這並不會發生。
  • 業界 | MXNet開放支持Keras,高效實現CNN與RNN的分布式訓練
    Keras-MXNet 深度學習後端進行 CNN 和 RNN 的訓練,安裝簡便,速度提升,同時支持保存 MXNet 模型。Keras 開發人員現在可以使用高性能的 MXNet 深度學習引擎展開卷積神經網絡(CNN)和循環神經網絡(RNN)的分布式訓練。通過更新幾行代碼,Keras 開發人員可以利用 MXNet 的多 GPU 分布式訓練功能來提高訓練速度。保存 MXNet 模型是該版本的另一個寶貴功能。
  • 經驗分享丨如何使用keras進行多主機分布式訓練
    tf.keras.Sequential API來構建和編譯一個簡單的卷積神經網絡 Keras 模型,用我們的 MNIST 數據集進行訓練。MultiWorkerMirroredStrategy 是同步多工作器訓練的推薦策略,將在本指南中進行演示。要訓練模型,請使用 tf.distribute.experimental.MultiWorkerMirroredStrategy 的實例。 MultiWorkerMirroredStrategy 在所有工作器的每臺設備上創建模型層中所有變量的副本。
  • 深度學習模型訓練時如何優化GPU顯存?(附TF和Paddle優化方式)
    不知道大家在訓練深度學習模型時有沒有遇見過這種情況:設置的batch_size明明不大,譬如32或者16,但是怎麼一跑模型,GPU的顯存就佔滿了呢?原來我使用Tensorflow的訓練的時候發現是這樣,後來我使用PaddlePaddle的時候也是這樣,我以為是框架本身出了問題,但是仔細研究後才發現,其實這兩種框架都是在跑模型的時候,默認設置會把你的GPU顯存佔滿,需要手動去調整。
  • 深度學習中的正則化技術概述(附Python+keras實現代碼)
    注意:本文假設你具備神經網絡及其在keras中實現神經網絡結構的基本知識。如果沒有,你可以先參考下面的文章。使用Keras進行深度學習:(一)Keras 入門目錄什麼是正則化? 這將導致出現一個極其簡單的線性網絡結構和略微訓練數據不足。
  • 使用Keras進行深度學習:(一)Keras 入門
    導語Keras是Python中以CNTK、Tensorflow或者Theano為計算後臺的一個深度學習建模環境。相對於其他深度學習的框架,如Tensorflow、Theano、Caffe等,Keras在實際應用中有一些顯著的優點,其中最主要的優點就是Keras已經高度模塊化了,支持現有的常見模型(CNN、RNN等),更重要的是建模過程相當方便快速,加快了開發速度。
  • 在TensorFlow和PaddleFluid中使用多塊GPU卡進行訓練
    前四篇文章我們介紹了 PaddleFluid 和 TensorFlow 的設計原理基本使用概念,分別通過在兩個平臺上實現完全相同的模型完成圖像分類,語言模型和序列標註三個任務,了解我們的使用經驗如何在兩個平臺之間遷移,以此來了解非序列模型和序列模型在兩個平臺之上設計和使用的差異。
  • Colab超火的Keras/TPU深度學習實戰,會點Python就能看懂的課程
    大數據文摘出品編譯:曹培信、周素雲、蔣寶尚想要真的了解深度學習,除了看視頻,拿數據和算力真槍實彈的練手可能比各種理論知識更重要。編程基礎不好?不會配置環境?本地GPU太貴配置太低?訓練速度達不到要求?這些可能都是阻礙你搭建第一個神經網絡的原因。
  • 基於tensorflow的深度學習MultiGPU訓練實戰
    進行深度學習模型訓練的時候,一般使用GPU來進行加速,當訓練樣本只有百萬級別的時候
  • 深度學習使用 Keras ,僅 20 行代碼完成兩個模型訓練和應用
    其大量封裝了一系列的複雜深度學習原理成為一個又一個簡潔的函數模塊,構建的時候即便基礎知識差一些也可以非常快的上手搭建工作,是一個對初學者非常友好的接口。不過其封裝的函數總量適用的對象遠遠不止初學者這麼簡單,其內部還有非常完整的高級功能,同時也滿足高級框架的搭建!
  • 使用google colab訓練YOLOv5模型
    軟硬體環境colab是什麼colab是google提供的一個jupyter notebook工具,支持google drive、tensorflow在內的google全家桶,主要用於機器學習的開發和研究
  • 手把手 | 教你在R中使用Keras和TensorFlow構建深度學習模型
    train_y, epochs = 100, batch_size = 128)#Evaluating model on the cross validation datasetloss_and_metrics <- model %>% evaluate(test_x, test_y, batch_size = 128)以上的代碼獲得了99.14%的訓練精度和
  • 獨家 | 教你在R中使用Keras和TensorFlow構建深度學習模型
    #loading keras librarylibrary(keras)#loading the keras inbuilt mnist datasetdata<-dataset_mnist()#separating train and test filetrain_x<-data$train$x
  • 深度學習訓練時GPU溫度過高?幾個命令,為你的GPU迅速降溫
    首先得到知乎上一位朋友的文章啟發,文章點擊這裡:從零開始組裝深度學習平臺(GPU散熱)。一、如果你有顯示器(X server)可以完全按照上面提到的這篇文章來設置:從零開始組裝深度學習平臺(GPU散熱 )https://zhuanlan.zhihu.com/p/27682206這裡貼出關鍵步驟為:1.
  • pytorch多gpu並行訓練
    1.2.如何平衡DataParallel帶來的顯存使用不平衡的問題1.3.torch.nn.parallel.DistributedDataParallel2.多機多gpu訓練2.1.初始化2.1.1.初始化backend2.1.2.初始化init_method2.1.2.1.使用TCP初始化2.1.2.2
  • Pytorch多GPU訓練
    model = model.cuda()model = nn.parallel.DistributedDataParallel(model)但是注意這裡要先將model加載到GPU, 然後才能使用DistributedDataParallel進行分發, 之後的使用和DataParallel就基本一樣了2.多機多gpu訓練在單機多gpu可以滿足的情況下
  • 在Keras和Tensorflow中使用深度卷積網絡生成Meme(表情包)文本
    為了加速訓練並降低模型的複雜性,僅使用48個最受歡迎的Meme(表情包)和每個Meme(表情包)準確的20,000個字幕,總計960,000個字幕作為訓練數據。每個角色都會有一個訓練示例在標題中,總計約45,000,000個訓練樣例。這裡選擇了角色級生成而不是單詞級別,因為Meme(表情包)傾向於使用拼寫和語法。
  • 第85講 Python深度學習之圖像識別
    Python在機器學習(人工智慧,AI)方面有著很大的優勢。
  • 深度學習必備---用Keras和直方圖均衡化---數據增強
    圖像增強是將已經存在於訓練數據集中的圖像進行處理,並對其進行處理以創建相同圖像的許多改變的版本。這既提供了更多的圖像來訓練,也可以幫助我們的分類器暴露在更廣泛的倆個都和色彩情況下,從而使我們的分類器更具有魯棒性,以下是imgaug庫中不同增強的一些示例
  • Keras訓練的h5文件轉pb文件並用Tensorflow加載
    一、背景為了快速的搭建神經網絡、訓練模型,使用了Keras框架來搭建網絡並進行訓練,得到訓練的h5模型文件後,需要將模型部署成服務