Keras同时用多张显卡训练网络

正文共4542个字,预计阅读时间12分钟。


Author: Zongwei Zhou | 周纵苇
Weibo: @MrGiovanni
Email: zongweiz@asu.edu


References


官方文档:multi_gpu_model(https://keras.io/utils/#multi_gpu_model)以及Google。


误区


目前Keras是支持了多个GPU同时训练网络,非常容易,但是靠以下这个代码是不行的。


os.environ["CUDA_VISIBLE_DEVICES"] = "1,2"


当你监视GPU的使用情况(nvidia-smi -l 1)的时候会发现,尽管GPU不空闲,实质上只有一个GPU在跑,其他的就是闲置的占用状态,也就是说,如果你的电脑里面有多张显卡,无论有没有上面的代码,Keras都会默认的去占用所有能检测到的GPU。


这行代码在你只需要一个GPU的时候时候用的,也就是可以让Keras检测不到电脑里其他的GPU。假设你一共有三张显卡,每个显卡都是有自己的标号的(0, 1, 2),为了不影响别人的使用,你只用其中一个,比如用gpu=1的这张,那么


os.environ["CUDA_VISIBLE_DEVICES"] = "1"


然后再监视GPU的使用情况(nvidia-smi -l 1),确实只有一个被占用,其他都是空闲状态。所以这是一个Keras使用多显卡的误区,它并不能同时利用多个GPU。


目的


为什么要同时用多个GPU来训练?


单个显卡内存太小 -> batch size无法设的比较大,有时甚至batch_size=1都内存溢出(OUT OF MEMORY)


从我跑深度网络的经验来看,batch_size设的大一点会比较好,相当于每次反向传播更新权重,网络都可以看到更多的样本,从而不会每次iteration都过拟合到不同的地方去Don't Decay the Learning Rate, Increase the Batch Size。当然,我也看过有论文说也不能设的过大,原因不明... 反正我也没有机会试过。我建议的batch_size大概就是64~256的范围内,都没什么大问题。


但是随着现在网络的深度越来越深,对于GPU的内存要求也越来越大,很多入门的新人最大的问题往往不是代码,而是从Github里面抄下来的代码自己的GPU太渣,实现不了,只能降低batch_size,最后训练不出那种效果。


解决方案两个:一是买一个超级牛逼的GPU,内存巨大无比;二是买多个一般般的GPU,一起用。


第一个方案不行,因为目前即便最好的NVIDIA显卡,内存也不过十几个G了不起了,网络一深也挂,并且买一个牛逼显卡的性价比不高。所以、学会在Keras下用多个GPU是比较靠谱的选择。


实现


非常简洁


from model import unet G = 3 # 同时使用3个GPUwith tf.device("/gpu:0"):

 M = unet(input_rows, input_cols, 1) model = keras.utils.training_utils.multi_gpu_model(M, gpus=G) model.compile(optimizer=Adam(lr=1e-5), loss='binary_crossentropy', metrics = ['accuracy']) model.fit(X_train, y_train, batch_size=batch_size*G, epochs=nb_epoch, verbose=0, shuffle=True, validation_data=(X_valid, y_valid)) model.save_weights('/path/to/save/model.h5')


问题

3.1  Compile the model


如果是普通的网络结构,那么没有问题,像上述的编译代码即可(model.compile(optimizer=Adam(lr=1e-5), loss='binary_crossentropy', metrics = ['accuracy']))   。不过,如果是Multi-task的网络,例如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})


3.2 save the model


用多个GPU训练的模型有一个问题Keras没有解决,就是model.save()保存的时候报错


TypeError: can't pickle module objects


或是


RuntimeError: Unable to create attribute (object header message is too large)


原因是:


In https://keras.io/utils/#multi_gpu_model it clearly stated that the model can be used like the normal model, but it cannot be saved, very funny. I can't even perform reinforced training just because I cannot save the previous model trained with multiple GPUs. If trained with single GPU, the rest of my invested GPUs will become useless. Please urge the developer to look into this bug ASAP.


正常情况下Keras给你提供了自动保存最好的网络的函数(keras.callbacks.ModelCheckpoint()),它的内部是用model.save()来保存的,所以不能用了,你需要自己设计函数CustomModelCheckpoint()来保存最好的模型。


class CustomModelCheckpoint(keras.callbacks.Callback): def __init__(self, model, path):        

self.model = model        

self.path = path        

self.best_loss = np.inf    

def on_epoch_end(self, epoch, logs=None): val_loss = logs['val_loss']      

 if val_loss < self.best_loss: print("\nValidation loss decreased from {} to {}, saving model".format(self.best_loss, val_loss))            

self.model.save_weights(self.path, overwrite=True)            

self.best_loss = val_loss model.fit(X_train, y_train, batch_size=batch_size*G, epochs=nb_epoch, verbose=0, shuffle=True, validation_data=(X_valid, y_valid), callbacks=[CustomModelCheckpoint(model, '/path/to/save/model.h5')])


即便如此,要是模型还是太大,就需要下面的方法了,保存成npy格式而不是hdf5格式。


RuntimeError: Unable to create attribute (Object header message is too large)

  • model.get_weights(): returns a list of all weight tensors in the model, as Numpy arrays.

  • model.set_weights(weights): sets the values of the weights of the model, from a list of Numpy arrays. The arrays in the list should have the same shape as those returned by get_weights().


# save model

weight = self.model.get_weights() np.save(self.path+'.npy', weight)

# load model

weight = np.load(load_path) model.set_weights(weight)


3.3 Load the model


同样道理,当读入用多个显卡一起训练的网络文件.h的时候,也会报错


ValueError: You are trying to load a weight file containing 3 layers into a model with 1 layers.


原因是.h内部和单个GPU训练的存储不太一样,因此在读的时候也需要套一下keras.utils.training_utils.multi_gpu_model()这个函数。


from model import unetwith tf.device("/cpu:0"): M = unet(input_rows, input_cols, 1) model = keras.utils.training_utils.multi_gpu_model(M, gpus=G) model.load_weights(load_path)


然后就没问题啦。


原文链接:https://www.jianshu.com/p/db0ba022936f


查阅更为简洁方便的分类文章以及最新的课程、产品信息,请移步至全新呈现的“LeadAI学院官网”:

www.leadai.org


请关注人工智能LeadAI公众号,查看更多专业文章

大家都在看

LSTM模型在问答系统中的应用

基于TensorFlow的神经网络解决用户流失概览问题

最全常见算法工程师面试题目整理(一)

最全常见算法工程师面试题目整理(二)

TensorFlow从1到2 | 第三章 深度学习革命的开端:卷积神经网络

装饰器 | Python高级编程

今天不如来复习下Python基础

### 同时训练个神经网络以进行预测 在分布式系统环境中,同时训练个神经网络可以显著提高计算效率并加速模型收敛过程。通过利用深度神经网络(deep neural networks)的强大表达能力以及分布式系统的高效资源管理特性[^1],可以在不同设备上分别部署独立的神经网络实例。 为了实现这一目标,通常采用以下几种方法: #### 方法一:数据并行化 在这种策略下,整个数据集被分割成若干子集,并分配给不同的神经网络副本。每个神经网络仅处理其对应的子集部分,在完成局部更新后,再通过参数服务器或其他同步机制共享权重信息。这种方法能够充分利用核处理器的优势,从而加快整体训练速度。 ```python import tensorflow as tf strategy = tf.distribute.MirroredStrategy() with strategy.scope(): model = create_model() # 创建模型函数 optimizer = tf.keras.optimizers.Adam() model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy']) ``` 上述代码片段展示了基于 TensorFlow 的一种简单实现方式,其中 `MirroredStrategy` 被用来支持单机上的 GPU 数据并行训练。 #### 方法二:模型并行化 当单一神经网络规模过大以至于无法完全加载到某一块显卡内存中时,则可考虑将其拆分为更小的部分,并分布于不同的硬件单元之上运行。此时每台机器只负责计算自己所拥有的那一层或者几层结构中的前向传播与反向梯度传递操作。 对于更加复杂的场景比如跨数据中心之间的协作学习任务来说,还需要额外解决诸如通信延迟等问题带来的挑战[^2]。 #### 自监督学习的应用扩展 另外值得注意的是,在某些特定领域内还可以引入自监督预训练技术来增强最终效果。例如视觉特征提取方面已有研究表明通过设计合适的代理任务可以让未标注图像同样参与到优化过程中去,进而提升泛化性能表现[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值