tf.GPUOptions, которые не применяются с set_session () в Keras - PullRequest
2 голосов
/ 03 апреля 2019

Я пытаюсь инкриминировать значение per_process_gpu_memory_fraction в моем tf.GPUOptions() и затем изменить сеанс Keras с помощью set_session(), однако доля памяти фактически никогда не изменяется. После первого запуска цикла while резервируется 319 МБ, как показано в nvidia-smi, что

a) никогда не освобождается при вызове clear_session() и

b) не поднимается на следующей итерации цикла while.

import GPUtil
import time

import tensorflow as tf
import numpy as np

from keras.backend.tensorflow_backend import set_session, clear_session, get_session
from tensorflow.python.framework.errors_impl import ResourceExhaustedError, UnknownError
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import to_categorical


def model_trainer():
    y_pred = None
    errors = 0
    total_ram = GPUtil.getGPUs()[0].memoryTotal
    total_ram_allowed = GPUtil.getGPUs()[0].memoryTotal * 0.90
    mem_amount = 0.005 # intentionally allocated a small amount so it needs to
                       # increment the mem_amount

    x_train = np.empty((10000, 100))
    y_train = np.random.randint(0, 9, size=10000)
    y_train = to_categorical(y_train, 10)

    while y_pred is None:
        print("mem", mem_amount)
        if total_ram_allowed > total_ram * mem_amount and GPUtil.getGPUs()[0].memoryFree > total_ram * mem_amount:
            gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=mem_amount)
            config = tf.ConfigProto(
                intra_op_parallelism_threads=2,
                inter_op_parallelism_threads=2,
                gpu_options=gpu_options)

            sess = tf.Session(config=config)
            set_session(sess)
            model = Sequential()
            model.add(Dense(units=64, activation='relu', input_dim=100))
            model.add(Dense(units=1024, activation='relu'))
            model.add(Dense(units=1024, activation='relu'))
            model.add(Dense(units=1024, activation='relu'))
            model.add(Dense(units=1024, activation='relu'))
            model.add(Dense(units=1024, activation='relu'))
            model.add(Dense(units=10, activation='softmax'))
            model.compile(loss='categorical_crossentropy',
                          optimizer='sgd',
                          metrics=['accuracy'])

            try:
                print(sess)

                model.fit(x_train, y_train, epochs=5, batch_size=32)
                y_pred = model.predict(x_train)

            except (ResourceExhaustedError, UnknownError) as e:
                if mem_amount > 1.0:
                    raise ValueError('model too large for vram')
                else:
                    mem_amount += 0.05

                clear_session()
                errors += 1
                pass
        else:
            clear_session()


if __name__ == "__main__":
    model_trainer()

Загадочная вещь в том, что Керас охотно берет новый сеанс (как показано при вызове get_session()), но не применяет новый GPUOptions.

В дополнение к приведенному выше примеру я попытался сделать:

clear_session()
del model
clear_session()
del model
gc.collect()

Ничто из этого не сработало при выпуске VRAM.

Моя общая цель - использовать метод проб и ошибок до тех пор, пока у процесса не будет достаточно VRAM для обучения, так как, кажется, нет хорошего способа выяснить, сколько VRAM необходимо для модели Keras, не просто запустив ее, поэтому что я могу запустить несколько моделей параллельно на одном графическом процессоре. Когда происходит ResourceExhaustedError, я хочу выпустить VRAM , который хранится в Keras и , а затем повторить попытку с большим количеством VRAM . Есть ли способ сделать это?

1 Ответ

1 голос
/ 11 апреля 2019

После поиска некоторое время я обнаружил, что Tensorflow будет принимать только VRAM и никогда не будет выпускать ее до тех пор, пока она не умрет, даже если используется del model, clear_session (). Я также попробовал метод, показанный здесь (https://github.com/keras-team/keras/issues/9379),, который использует:

from keras import backend as K
K.clear_session()

from numba import cuda
cuda.select_device(0)
cuda.close()

Это привело к ошибке для меня, так как когда Tensorflow снова пытался получить доступ к графическому процессору, его указатель на пространство памяти был недействительным (так как он был уничтожен с помощью cuda.close ()). Таким образом, единственный способ обойти это - использовать процессы, а не потоки (пробовал тоже, что и раньше).

Другая вещь, которую я обнаружил, состоит в том, что, хотя есть способы попытаться оценить количество VRAM, которое будет использовать модель Keras, это не очень точный способ сделать это. (см .: Как определить необходимую память для модели Keras? ) Я также пытался вычислять напрямую из слоев Keras, и это сильно варьировалось, так что это тоже было неточно. Так что на самом деле вы только оставляете пробную ошибку, перехватывая ResourceExhaustedError и повторяя попытку.

Ниже приведен мой код для запуска нескольких моделей Keras на одном графическом процессоре.

import GPUtil
import time
import multiprocessing

import tensorflow as tf
import numpy as np

from keras.backend.tensorflow_backend import set_session, clear_session, get_session
from tensorflow.python.framework.errors_impl import ResourceExhaustedError, UnknownError
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import to_categorical


def model_trainer():
    mem_amount = 0.05

    x_train = np.empty((100000, 100))
    y_train = np.random.randint(0, 9, size=100000)
    y_train = to_categorical(y_train, 10)

    manager = multiprocessing.Manager()
    return_dict = manager.dict()

    def worker(mem_amount, return_dict):
        gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=mem_amount)
        config = tf.ConfigProto(
            intra_op_parallelism_threads=2,
            inter_op_parallelism_threads=2,
            gpu_options=gpu_options)
        sess = tf.Session(config=config)
        set_session(sess)

        model = Sequential()
        model.add(Dense(units=64, activation='relu', input_dim=100))
        model.add(Dense(units=1024, activation='relu'))
        model.add(Dense(units=1024, activation='relu'))
        model.add(Dense(units=2048, activation='relu'))
        model.add(Dense(units=10, activation='softmax'))
        model.compile(loss='categorical_crossentropy',
                      optimizer='sgd',
                      metrics=['accuracy'])

        try:
            get_session()

            model.fit(x_train, y_train, epochs=5, batch_size=1000)

            return_dict["valid"] = True

        except (ResourceExhaustedError, UnknownError) as e:
            return

    while "valid" not in list(return_dict.keys()):
        print("mem", mem_amount)

        total_ram = GPUtil.getGPUs()[0].memoryTotal
        total_ram_allowed = GPUtil.getGPUs()[0].memoryTotal * 0.90

        # can add in a for loop to have multiple models
        if total_ram_allowed > total_ram * mem_amount and GPUtil.getGPUs()[0].memoryFree > total_ram * mem_amount:
            p = multiprocessing.Process(target=worker, args=(mem_amount, return_dict))
            p.start()
            p.join()

            print(return_dict.values())

            if "valid" not in list(return_dict.keys()):
                if mem_amount > 1.0:
                    raise ValueError('model too large for vram')
                else:
                    mem_amount += 0.05
            else:
                break
        else:
            time.sleep(10)


if __name__ == "__main__":
    model_trainer()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...