tensorflow使用GPU训练

1. 查看gpu的使用详情:

(1)查看gpu使用情况

nvidia-smi.exe # windows上
nvidia-smi -l #linux服务器上
# 显示的结果中 Volatile GPU-Util:浮动的GPU利用率;

(2)linux上查看进程占用gpu的情况:

##实用技巧:

##如果你在linux终端运行深度学习python脚本文件,运行中发现占用多个GPU和内存资源,则请先查看占用资源##的进程归属方是谁:
$ps -f PID号

##然后确认该进程可以kill掉情况下建议:
$kill -9 PID号
#ctrl+Z指令只能强制结束当前流程,无法退出进程,所以发现有问题后用ctrl+Z后还需要kill进程

2. 使用指定的GPU:

# 其中参数:

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

方式1. 在python中指定GPU

# 方式1. 直接在python文件最开始指定GPU
import os
# os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"  # 默认,不需要这句
os.environ["CUDA_VISIBLE_DEVICES"] = "0" # 选择ID为0的GPU

# 方式2. 通过ID选择GPU
def selectGpuById(id):
    os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
    os.environ["CUDA_VISIBLE_DEVICES"] = "{}".format(id)

## 方式3. session中指定GPU
with tf.Session() as ses:
    with tf.device("/gpu:1"):
        # 训练model的代码
## 字符说明:
##"/cpu:0"	The CPU of your machine
##"/gpu:0"	The GPU of yout machine ,if you have one

方式2. 在终端shell运行程序时指定GPU

命令行输入:

# 指定采用1号GPU运行*.py
CUDA_VISIBLE_DEVICES=1 python *.py

3. 设置tensorflow使用GPU显存大小

函数tf.ConfigProto()的参数:

log_device_placement=True : 是否打印设备分配日志

allow_soft_placement=True : 如果你指定的设备不存在,允许TF自动分配设备

tf.ConfigProto(log_device_placement=True,allow_soft_placement=True)

在构造tf.Session()时可通过tf.GPUOptions作为可选配置参数的一部分来显示地指定需要分配的显存比例。

per_process_gpu_memory_fraction指定了每个GPU进程中使用显存的上限,但它只能均匀地作用于所有GPU,无法对不同GPU设置不同的上限。

(1)定量设置显存

# 分配给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设置使用举例:

config = tf.ConfigProto(allow_soft_placement=True)
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.9)
config.gpu_options.allow_growth = True

with tf.Session(config=config) as sess:
    #训练model的代码

4.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)

参考:https://blog.csdn.net/c20081052/article/details/82345454?utm_source=blogxgwz8

           https://www.cnblogs.com/YSPXIZHEN/p/11416843.html

发布了10 篇原创文章 · 获赞 2 · 访问量 7722

猜你喜欢

转载自blog.csdn.net/ftfy123/article/details/104663102