基於英偉達GPU訓練TensorFlow模型


NVIDIA顯卡選型

顯卡性能天梯圖:http://www.mydrivers.com/zhuanti/tianti/gpu/

根據顯卡天梯圖划分的等級排名,對比GTX1060+,GTX1060顯卡應當屬於高性級別顯卡,GTX1070開始才算最高性能級顯卡 

 

Tensorflow-GPU環境配置

安裝tensoflow-gpu

要求:python是64位的 - python位數確定:

安裝 - 通過pip安裝

pip install tensorflow-gpu

cuda配置

運行import TensorFlow as tf提示:

ImportError: Could not find 'cudart64_100.dll'. TensorFlow requires that this DLL be installed in a directory that is named in your %PATH% environment variable. Download and install CUDA 10.0 from this URL: https://developer.nvidia.com/cuda-90-download-archive(https://developer.nvidia.com/cuda-10.0-download-archive)

說明Tensorflow-gpu要求使用cuda 9.0.dll/cuda 10.0.dll的內容 --> 下載cuda 9.0對應window10的版本的安裝文件(https://developer.nvidia.com/cuda-90-download-archive)- 下載界面:

 

Installer Type選項:exe(network)是在線安裝版 - 你執行安裝程序需要聯網;exe(local)是離線安裝版 - 文件比較大

選完后,點擊下面Base 的Download進行下載

 

下載完成后,雙擊exe運行文件 

選擇OK

等進度條走完,就會進入安裝界面

 

安裝加載界面(V9.0版本不匹配 - 安裝V10.0)

檢查系統兼容性(如果檢測通過,表示顯卡可以安裝CUDA,如果沒有通過,說明顯卡不支持tensorflow-gpu加速,則只能pip unistall tensorflow-gpu,然后執行pip install tensorflow,切換為TensorFlow的CPU版本)

 

點擊同意並繼續

如果不清楚要安裝什么,那么請勾選精簡

勾選精簡,然后點擊下一步

等待安裝完成

選擇 下一步

全部勾選,點擊關閉

 

file:///C:/Program%20Files/NVIDIA%20GPU%20Computing%20Toolkit/CUDA/v9.0/doc/html/index.html file:///C:/Program%20Files/NVIDIA%20GPU%20Computing%20Toolkit/CUDA/v10.0/doc/html/index.html

 

添加環境變量CUDA_PATH=C:\ProgramData\NVIDIA Corporation\CUDA Samples\v9.0 / C:\ProgramData\NVIDIA Corporation\CUDA Samples\v10.0

cuDNN配置

對於tensorflow而言,真正實現加速的是cuDNN,然后cuDNN調用的是CUDA顯卡驅動 - 要配置cuDNN模塊

cuDNN的全稱為NVIDIA CUDA® Deep Neural Network library,是NVIDIA專門針對深度神經網絡(Deep Neural Networks)中的基礎操作而設計基於GPU的加速庫。cuDNN為深度神經網絡中的標准流程提供了高度優化的實現方式,例如convolution、pooling、normalization以及activation layers的前向以及后向過程。

cuDNN只是NVIDIA深度神經網絡軟件開發包中的其中一種加速庫。https://developer.nvidia.com/deep-learning-software全面介紹了NVIDIA深度神經網絡加速庫中的其他包

1)下載 - https://developer.nvidia.com/cudnn

點擊Download cuDNN(需要注冊/登錄 - 支持微信/QQ登錄 - 郵箱驗證)

勾選I Agree(下載前填寫一份調查即可訪問下載頁面)

點擊Proceed To Downloads(下載cuDNN相應版本的壓縮包)

選擇 Download cuDNN v7.6.3 (August 23, 2019), for CUDA 9.0 / 

 

下載 cuDNN Library for Windows 10

解壓,得到解壓后的文件夾名cuda,文件夾中包含三個文件夾:一個為include,另一個為lib64,還有一個是bin,將三個文件復制到CUDA_PATH對應的CUDA安裝目錄下

添加環境變量(將解壓后的文件中的bin和lib/x64文件夾關聯到環境變量的path全局變量中):

檢測

# 運行tensorflow-gpu
#coding=utf-8 import tensorflow as tf import numpy as np hello=tf.constant('hhh') sess=tf.Session() print (sess.run(hello))

如果運行沒有報錯,即表示安裝成功!

查看GPU-ID

CMD輸入:

nvidia-smi

觀察到存在序號為0的GPU ID

觀察到存在序號為0、1、2、3的GPU ID

在終端運行代碼時指定GPU

如果電腦有多個GPU,Tensorflow默認全部使用。如果想只使用部分GPU,可以設置CUDA_VISIBLE_DEVICES

命令行輸入:

# 指定采用1號GPU運行*.py
CUDA_VISIBLE_DEVICES=1 python *.py
Environment Variable Syntax      Results

CUDA_VISIBLE_DEVICES=1           Only device 1 will be seen
CUDA_VISIBLE_DEVICES=0,1         Devices 0 and 1 will be visible
CUDA_VISIBLE_DEVICES="0,1"       Same as above, quotation marks are optional
CUDA_VISIBLE_DEVICES=0,2,3       Devices 0, 2, 3 will be visible; device 1 is masked
CUDA_VISIBLE_DEVICES=""          No GPU will be visible

在Python代碼中指定GPU

import os
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = "0" # 選擇ID為0的GPU
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "2"
# 通過ID選擇GPU
def selectGpuById(id):
    os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
    os.environ["CUDA_VISIBLE_DEVICES"] = "{}".format(id)

如果存在多個GPU,需要明確op操作在哪個GPU上調用 - 可以使用with ... Device語句明確指定那個CPU或GPU將被調用:

with tf.Session() as ses:
    with tf.device("/gpu:1"):
        matrix1=tf.constant([[3.,3.]])
        matrix2=tf.constant([[2.],[2.]])
        product=tf.matmul(matrix1,matrix2)
字符 對應的操作
"/cpu:0" The CPU of your machine
"/gpu:0" The GPU of yout machine ,if you have one

查看TensorFlow是CPU還是GPU版本

Python環境中輸入:

import numpy
import tensorflow as tf
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
c = tf.matmul(a, b)
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
print(sess.run(c))
# 顯示詳細信息
Device mapping:
/job:localhost/replica:0/task:0/device:GPU:0 -> device: 0, name: GeForce GTX 1060, pci bus id: 0000:01:00.0, compute capability: 6.1
2019-08-27 11:08:16.462966: I tensorflow/core/common_runtime/direct_session.cc:296] Device mapping:
MatMul: (MatMul): /job:localhost/replica:0/task:0/device:GPU:0
/job:localhost/replica:0/task:0/device:GPU:0 -> device: 0, name: GeForce GTX 1060, pci bus id: 0000:01:00.0, compute capability: 6.1
a: (Const): /job:localhost/replica:0/task:0/device:GPU:0
b: (Const): /job:localhost/replica:0/task:0/device:GPU:0
2019-08-27 11:08:16.463885: I tensorflow/core/common_runtime/placer.cc:54] MatMul: (MatMul)/job:localhost/replica:0/task:0/device:GPU:0
2019-08-27 11:08:16.464145: I tensorflow/core/common_runtime/placer.cc:54] a: (Const)/job:localhost/replica:0/task:0/device:GPU:0
2019-08-27 11:08:16.464394: I tensorflow/core/common_runtime/placer.cc:54] b: (Const)/job:localhost/replica:0/task:0/device:GPU:0
[[22. 28.]
 [49. 64.]] 

禁止使用GPU

CUDA_VISIBLE_DEVICES=""

設置Tensorflow使用的顯存大小

(1)定量設置顯存

默認tensorflow是使用GPU盡可能多的顯存。可以通過下面的方式,來設置使用的GPU顯存:

# 分配給Tensorflow的GPU顯存大小為:GPU實際顯存*0.7
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.7) sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))

(2)按需設置顯存

# 如果想按需分配,可以使用allow_growth參數
gpu_options = tf.GPUOptions(allow_growth=True)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))  

限制GPU使用率

Tensorflow為了加速代碼的運行速率,在運行的時候會占用一切能用的GPU資源,導致其他程序無法使用GPU

采用tf.ConfigProto(),在創建session的時候對GPU使用率進行參數配置

  • tf.ConfigProto(log_device_placement=True):記錄設備的指派情況(運行時,獲取操作或張量在哪個設備上運行,在終端輸出指派的情況)
  • tf.ConfigProto(allow_soft_placement=True):自動選擇適合的可用的設備(無需指派)

限制代碼的GPU使用 - 存在兩種限制方法:

(1)第一種是代碼在運行的時候動態的申請資源,需要多少拿多少

# 使用最小的GPU資源
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
self.sess=tf.Session(config=config)

(2)第二種是限制GPU的使用率

config = tf.ConfigProto() 
config.gpu_options.per_process_gpu_memory_fraction = 0.4 # 占用GPU40%的顯存 
session = tf.Session(config=config)

Keras多GPU訓練

Keras 2.X版本后可以很方便的支持使用多GPU進行訓練了,使用多GPU可以提高我們的訓練過程,比如加速和解決內存不足問題。有多張GPU卡可用時,使用TnesorFlow后端。

多GPU其實分為兩種使用情況:

  • 數據並行
  • 設備並行

數據並行

數據並行將目標模型在多個設備上各復制一份,並使用每個設備上的復制品處理整個數據集的不同部分數據。Keras在 keras.utils.multi_gpu_model 中提供有內置函數,該函數可以產生任意模型的數據並行版本,最高支持在8片GPU上並行。

數據並行是指將模型放到多個GPU上去跑,來處理數據集的不同部分,Keras的keras.utils.multi_gpu_model支持任意模型的數據並行,最多支持8個GPU。大多數時候要用到的都是數據並行,參考utils中的multi_gpu_model文檔。 下面是一個例子:
from keras.utils import multi_gpu_model

# Replicates `model` on 8 GPUs.
# This assumes that your machine has 8 available GPUs.
parallel_model = multi_gpu_model(model, gpus=8)
parallel_model.compile(loss='categorical_crossentropy', optimizer='rmsprop')

# This `fit` call will be distributed on 8 GPUs.
# Since the batch size is 256, each GPU will process 32 samples.
parallel_model.fit(x, y, epochs=20, batch_size=256)

數據並行利用多塊GPU同時訓練多個batch數據,運行在每塊GPU上的模型為同一個神經網絡,網絡結構完全一樣,並且共享模型參數。

from keras.utils.training_utils import multi_gpu_model   #導入keras多GPU函數

model = get_model()
parallel_model = multi_gpu_model(model, gpus=2) # 設置使用2個gpu,該句放在模型compile之前
parallel_model.compile(loss='categorical_crossentropy', optimizer=Adam(), metrics=['accuracy'])
hist = parallel_model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs_num, validation_data=(x_test, y_test), verbose=1, callbacks=callbacks)

還可以指定要哪幾個GPU來跑:

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "3,5"

 使用命令“nvidia-smi”可以查看各GPU的使用情況和序號,上面代碼就是指定用序號為3和5的兩個GPU來跑訓練。

報錯1:ValueError: Variable batch_normalization_1/moving_mean/biased already exists, disallowed. Did you mean to set reuse=True in VarScope? Originally defined at:
解決:使用單GPU訓練的時候沒有問題,改成多GPU后出現這個問題。這個問題好解決,將Tensorflow升級到1.4即可。
報錯2:TypeError: can't pickle ...(different text at different situation) objects
解決:查找資料后,發現可能源於callbacks.ModelCheckpoint() 並進行多 gpu 並行計算時,使用姿勢不對導致callbacks 函數報錯。在代碼中為了保存最優的訓練模型,加了這個callback:
checkpoint = ModelCheckpoint(filepath='./cifar10_resnet_ckpt.h5', monitor='val_acc', verbose=1,save_best_only=True)
而在改為多GPU訓練后,每次回調存儲的模型變成了parallel_model,這會導致報錯,只需要改成依然保存原本的model即可,所以需要改一下:
class ParallelModelCheckpoint(ModelCheckpoint):
    def __init__(self,model,filepath, monitor='val_loss', verbose=0,
                 save_best_only=False, save_weights_only=False,
                 mode='auto', period=1):
        self.single_model = model
        super(ParallelModelCheckpoint,self).__init__(filepath, monitor, verbose,save_best_only, save_weights_only,mode, period)

    def set_model(self, model):
        super(ParallelModelCheckpoint,self).set_model(self.single_model)

checkpoint = ParallelModelCheckpoint(model, filepath='./cifar10_resnet_ckpt.h5', monitor='val_acc', verbose=1, save_best_only=True) # 解決多GPU運行下保存模型報錯的問題
其余的不變,也就是改為依然存儲原本的model即可。

設備並行

是在不同設備上運行同一個模型的不同部分,當模型含有多個並行結構,例如含有兩個分支時,這種方式很適合。 這種並行方法可以通過使用TensorFlow device scopes實現,下面是一個例子:

# Model where a shared LSTM is used to encode two different sequences in parallel
input_a = keras.Input(shape=(140, 256))
input_b = keras.Input(shape=(140, 256))

shared_lstm = keras.layers.LSTM(64)

# Process the first sequence on one GPU
with tf.device_scope('/gpu:0'):
    encoded_a = shared_lstm(tweet_a)
# Process the next sequence on another GPU
with tf.device_scope('/gpu:1'):
    encoded_b = shared_lstm(tweet_b)

# Concatenate results on CPU
with tf.device_scope('/cpu:0'):
    merged_vector = keras.layers.concatenate([encoded_a, encoded_b], axis=-1)

多任務輸出數據並行

在Keras版的Faster-RCNN,它由多個輸出支路,也就是多個loss,在網絡定義的時候一般會給命名,然后編譯的時候找到不同支路layer的名字即可,就像這樣:

model.compile(optimizer=optimizer, 
              loss={'main_output': jaccard_distance_loss, 'aux_output': 'binary_crossentropy'},
              metrics={'main_output': jaccard_distance_loss, 'aux_output': 'acc'},
              loss_weights={'main_output': 1., 'aux_output': 0.5})

其中main_output和aux_output就是認為定義的layer name,但是如果用了keras.utils.training_utils.multi_gpu_model()以后,名字就自動換掉了,變成默認的concatenate_1, concatenate_2等等,因此你需要先model.summary()一下,打印出來網絡結構,然后弄明白哪個輸出代表哪個支路,然后重新編譯網絡,如下:

from keras.optimizers import Adam, RMSprop, SGD
model.compile(optimizer=RMSprop(lr=0.045, rho=0.9, epsilon=1.0), 
              loss={'concatenate_1': jaccard_distance_loss, 'concatenate_2': 'binary_crossentropy'},
              metrics={'concatenate_1': jaccard_distance_loss, 'concatenate_2': 'acc'},
              loss_weights={'concatenate_1': 1., 'concatenate_2': 0.5})

而且在Keras版的Faster-RCNN中,每個batch里,對RPN進行訓練,測試后的結果作為檢測網絡的輸入,來訓練,最后把2個模型對參數的訓練結果作為一個模型保存下來。

分布式

Keras的分布式是利用TensorFlow實現的,要想完成分布式的訓練,你需要將Keras注冊在連接一個集群的TensorFlow會話上:

server = tf.train.Server.create_local_server()
sess = tf.Session(server.target)

from keras import backend as K
K.set_session(sess)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM