分布式训练(一)——GPU设置

目录

1. GPU设置

2. GPU设置的API列表

3.GPU设置实战

3.1 对每个GPU设置内存自增长

3.2 设置可见GPU

3.3给GPU做逻辑切分

3.4 手动指定的方式使用多GPU环境

1. GPU设置

(1)默认用全部GPU并且内存全部占满(why GPU或者内存会全部占满?

(2)如何不浪费内存和计算资源?

       内存自增长:即弹性内存机制,内存自增长。需要多少内存,就用多少内存。

      虚拟设备机制:类似于windows中的磁盘(系统中一般只有一个磁盘,单windows会将其分成好几个盘,比如C盘,D盘,E盘,每个盘放不同的东西)虽然只有一个GPU,但可以将其切分成多个逻辑上的GPU

(3)多GPU使用

虚拟GPU & 实际GPU

手工设置 & 分布式机制

手工设备,指定某一层,在哪个GPU上去计算,或者使用tensorflow框架所支持的分布式机制。

2. GPU设置的API列表

(1)tf.debugging.set_log_device_placement

用来打印一些信息:某个变量,分配在哪个设备上

(2)tf.config.experimental.set_visible_devices

用于设置对于本进程可见的设备。比如一个机器上有4个GPU,只设置1个对本进程可见,故本进程就不能使用其他设备。

(3)tf.config.experimental.list_logical_devices

获取所有的逻辑设备。物理设备即一整块儿物理磁盘,逻辑设备即物理磁盘上的分区。

(4)tf.config.experimental.list_physical_devices

获取所有物理设备的列表。

(5)tf.config.experimental.set_memory_devices

设置内存自增长,内存用多少就占多少,而不是一下子把内存都占满。

(6)tf.config.experimental.VirtualDeviceConfiguration

用来在物理设备上建立逻辑分区

(7)tf.config.set_soft_device_placement

手动指定某一个计算在哪一个设备上执行,这个设备可以是CPU,GPU或者是其他的设备,但是手动指定的方式很容易出错。故可用Set_soft_device_placement自动地将某个计算分配到某个设备上去,这种分配是可以保证正确性的。某个设备支持某个计算,才会将某个计算分配到某个设备上。

3.GPU设置实战

以cnn对fashion_minist数据集分类为例

载入要使用的模块

import os
import sys
import time

import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow import keras

加载数据

fashion_mnist = keras.datasets.fashion_mnist
(x_train_all, y_train_all), (x_test, y_test) = fashion_mnist.load_data()

x_valid, x_train = x_train_all[:5000], x_train_all[5000:]
y_valid, y_train = y_train_all[:5000], y_train_all[5000:]

对数据进行归一化处理

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
# x_train [None, 28, 28] --> [None, 784]
x_train_scaler = scaler.fit_transform(x_train.reshape(-1, 784)).reshape(-1, 28, 28, 1) # 最后一维 1,表示1个通道
x_valid_scaler = scaler.transform(x_valid.reshape(-1, 784)).reshape(-1, 28, 28, 1)
x_test_scaler = scaler.transform(x_test.reshape(-1, 784)).reshape(-1, 28, 28, 1)

构造dataset

def make_dataset(images, labels, epochs, batch_size, shuffle=True):
    dataset = tf.data.Dataset.from_tensor_slices((images, labels))
    if shuffle:
        dataset = dataset.shuffle(10000)
    
    # prefetch:表示从数据中预先取出来多少个,来给生成数据作准备。为什么说是用来加速的一个函数?
    dataset = dataset.repeat(epochs).batch(batch_size).prefetch(50) 
    return dataset

batch_size = 128
epochs = 100
train_dataset = make_dataset(x_train_scaler, y_train, epochs, batch_size)

构造一个20层的模型

model = keras.models.Sequential()
model.add(keras.layers.Conv2D(filters=32, kernel_size=3,
                              padding='same',
                              activation='selu',
                              input_shape=(28, 28, 1)))
model.add(keras.layers.SeparableConv2D(filters=32, kernel_size=3,
                                       padding='same',
                                       activation='selu'))
model.add(keras.layers.MaxPool2D(pool_size=2))

# 一般每进行一次pooling层,图像的大小就会缩小,中间的数据就会大大减少,为减少这种信息的损失,故将filters翻倍。
model.add(keras.layers.SeparableConv2D(filters=64, kernel_size=3,
                                       padding='same',
                                       activation='selu'))
model.add(keras.layers.SeparableConv2D(filters=64, kernel_size=3,
                                       padding='same',
                                       activation='selu'))
model.add(keras.layers.MaxPool2D(pool_size=2))

model.add(keras.layers.SeparableConv2D(filters=128, kernel_size=3,
                                       padding='same',
                                       activation='selu'))
model.add(keras.layers.SeparableConv2D(filters=128, kernel_size=3,
                                       padding='same',    
                                       activation='selu'))
model.add(keras.layers.MaxPool2D(pool_size=2))

# 展平
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(128, activation='selu')) # 全链接层
model.add(keras.layers.Dense(10, activation="softmax")) # 全链接层

model.compile(loss=keras.losses.SparseCategoricalCrossentropy(), 
              optimizer=keras.optimizers.SGD(), 
              metrics=["accuracy"])

model.summary()

训练

history = model.fit(train_dataset, 
                    steps_per_epoch = x_train_scaler.shape[0] // batch_size,
                    epochs=10)

训练过程中查看内存及gpu使用情况

命令行输入:nvidia-smi

可以看到,不做任何处理,基本将第一个gpu的内存全部占满 

命令行:watch -n 0.1 -x nvidia-smi (-n 表示刷新的时间间隔,-x表示监控的是哪条命令)

3.1 对每个GPU设置内存自增长

tf.debugging.set_log_device_placement(True)
gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)

logical_gpus = tf.config.experimental.list_logical_devices('GPU')

print("the num of gpu", len(gpus))
print("the num of logical gpu", len(logical_gpus))

note:memory growth must be set at program startup

再训练模型

可以看到,设置内存自增长之后,占用的内存明显的变少了呢

3.2 设置可见GPU

设置第4个gpu可见,即可使用第4个gpu

tf.debugging.set_log_device_placement(True)
gpus = tf.config.experimental.list_physical_devices('GPU')
# 设置GPU可见
tf.config.experimental.set_visible_devices(gpus[3], 'GPU')
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)

logical_gpus = tf.config.experimental.list_logical_devices('GPU')

print("the num of gpu", len(gpus))
print("the num of logical gpu", len(logical_gpus))

训练模型

发现是在使用第4个gpu哦

3.3给GPU做逻辑切分

在第2个gpu上,划分两个逻辑磁盘,每个磁盘的内存上限为3G

tf.debugging.set_log_device_placement(True)
gpus = tf.config.experimental.list_physical_devices('GPU')
# 设置GPU可见
tf.config.experimental.set_visible_devices(gpus[0], 'GPU')

# 对GPU进行切分
tf.config.experimental.set_virtual_device_configuration(
    gpus[0],
    [tf.config.LogicalDeviceConfiguration(memory_limit=3072),
     tf.config.LogicalDeviceConfiguration(memory_limit=3072)]
)

logical_gpus = tf.config.experimental.list_logical_devices('GPU')

print("the num of gpu", len(gpus))
print("the num of logical gpu", len(logical_gpus))

训练模型

可以看到有两个1号gpu

3.4 手动指定的方式使用多GPU环境

tf.debugging.set_log_device_placement(True)
gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)

logical_gpus = tf.config.experimental.list_logical_devices('GPU')

print("the num of gpu", len(gpus))
print("the num of logical gpu", len(logical_gpus))

测试代码

c = []
for gpu in logical_gpus:
    print(gpu.name)
    with tf.device(gpu.name):
        a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
        b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
        c.append(tf.matmul(a, b))

with tf.device('/cpu:0'):
    matmul_sum = tf.add_n(c)

print(matmul_sum)

将tf.device() 用在训练模型上,不同的层在不同的gpu上运行

model = keras.models.Sequential()
with tf.device(logical_gpus[0].name):
    model.add(keras.layers.Conv2D(filters=32, kernel_size=3,
                                padding='same',
                                activation='selu',
                                input_shape=(28, 28, 1)))
    model.add(keras.layers.SeparableConv2D(filters=32, kernel_size=3,
                                        padding='same',
                                        activation='selu'))
    model.add(keras.layers.MaxPool2D(pool_size=2))

    # 一般每进行一次pooling层,图像的大小就会缩小,中间的数据就会大大减少,为减少这种信息的损失,故将filters翻倍。
    model.add(keras.layers.SeparableConv2D(filters=64, kernel_size=3,
                                        padding='same',
                                        activation='selu'))
    model.add(keras.layers.SeparableConv2D(filters=64, kernel_size=3,
                                        padding='same',
                                        activation='selu'))
    model.add(keras.layers.MaxPool2D(pool_size=2))


with tf.device(logical_gpus[1].name):
    model.add(keras.layers.SeparableConv2D(filters=128, kernel_size=3,
                                        padding='same',
                                        activation='selu'))
    model.add(keras.layers.SeparableConv2D(filters=128, kernel_size=3,
                                        padding='same',    
                                        activation='selu'))
    model.add(keras.layers.MaxPool2D(pool_size=2))

    # 展平
    model.add(keras.layers.Flatten())

with tf.device(logical_gpus[2].name):
    model.add(keras.layers.Dense(128, activation='selu')) # 全链接层
    model.add(keras.layers.Dense(10, activation="softmax")) # 全链接层

model.compile(loss=keras.losses.SparseCategoricalCrossentropy(), 
              optimizer=keras.optimizers.SGD(), 
              metrics=["accuracy"])

model.summary()

把不同的测层次放在不同的GPU上:这样做的好处——当模型比较大时,1个GPU放不下的时候,可通过此种方式让模型能够被放下,能够被训练。但其并没有达到并行化的效果哦,仍然是在串行。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Keras中设置分布式训练可以使用TensorFlow的tf.distribute.Strategy API。这个API提供了多种分布式策略,可以根据不同的使用场景选择适合的策略。其中,对于单机多卡训练,可以使用MirroredStrategy。\[1\] 使用MirroredStrategy时,需要在代码中引入tf.distribute.MirroredStrategy,并在创建模型之前实例化该策略。然后,将模型的创建和编译放在strategy.scope()的上下文中,以确保模型在所有可用的GPU上进行复制和训练。\[2\] 下面是一个设置分布式训练的示例代码: ```python import tensorflow as tf from tensorflow import keras # 实例化MirroredStrategy strategy = tf.distribute.MirroredStrategy() # 在strategy.scope()的上下文中创建和编译模型 with strategy.scope(): model = keras.Sequential(\[...\]) # 创建模型 model.compile(\[...\]) # 编译模型 # 加载数据集 train_dataset = mnist_train.map(scale).cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE) eval_dataset = mnist_test.map(scale).batch(BATCH_SIZE) # 在分布式环境下训练模型 model.fit(train_dataset, epochs=10, validation_data=eval_dataset) ``` 在上述代码中,MirroredStrategy会自动将模型复制到所有可用的GPU上,并在每个GPU上进行训练。这样可以充分利用多个GPU的计算资源,加快模型训练的速度。\[1\] 需要注意的是,分布式训练需要有多个GPU才能发挥作用。如果只有单个GPU,使用分布式训练可能不会带来性能上的提升。另外,分布式训练还需要适当调整batch size和学习率等超参数,以获得最佳的训练效果。 #### 引用[.reference_title] - *1* [【Keras】TensorFlow分布式训练](https://blog.csdn.net/qq_36643449/article/details/124592521)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Keras 的分布式训练](https://blog.csdn.net/weixin_39693193/article/details/111539493)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Tensorflow2.0进阶学习-Keras 的分布式训练 (九)](https://blog.csdn.net/u010095372/article/details/124547254)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值