代码之家  ›  专栏  ›  技术社区  ›  devforfu

Keras(2.0.8)和Tensorflow(1.3)后端采用所有可用RAM

  •  3
  • devforfu  · 技术社区  · 6 年前

    我正在使用 keras 具有的库 tensorflow 后端和CUDA已启用。请参阅PIP软件包版本输出:

    Keras (2.0.8)
    tensorflow-gpu (1.3.0)
    tensorflow-tensorboard (0.1.8)
    

    我有以下代码创建 VGG16 模型和载荷图像净重:

    def create_vgg16_model(target_size: tuple, n_classes: int):
        base = VGG16(include_top=False,
                     input_shape=target_size,
                     weights='imagenet')
    
        x = base.output
        x = Flatten()(x)
        x = Dense(n_classes, activation='softmax', name='top')(x)
    
        model = Model(inputs=base.input, outputs=x)
        for layer in model.layers[:-1]:
            layer.trainable = False
    
        model.compile(optimizer='adam', loss='categorical_crossentropy')
        return model
    

    模特的训练进行得很顺利 nvidia-smi 显示根据需要使用GPU内存。但我检查了 top 命令,下面是我看到的:

      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                 
     1268 ck        20   0  166288  31964  12416 S  29.5  0.1  13:05.39 Xtightvnc                                                               
    32235 ck        30  10   32252   3700   3356 S   5.3  0.0   0:36.93 cwaves 
    ------------------------------------------------------------------------------    
    32212 ck        20   0 27.485g 1.184g 190404 S   2.3  3.8   0:35.44 python  
    ------------------------------------------------------------------------------                                                                
    26015 root      20   0       0      0      0 S   0.3  0.0   0:00.30 kworker/3:1                                                             
    31754 ck        20   0   43168   3904   3080 R   0.3  0.0   0:04.45 top                                                                     
        1 root      20   0  185644   6204   3984 S   0.0  0.0   0:10.44 systemd                                                                 
    

    我用调试器浏览了代码,并意识到内存是在以下函数中分配的 keras.backend.tensorflow_backed 这将创建 tf.Session 对象:

    def get_session():        
        global _SESSION
        if tf.get_default_session() is not None:
            session = tf.get_default_session()
        else:
            if _SESSION is None:
                if not os.environ.get('OMP_NUM_THREADS'):
                    config = tf.ConfigProto(allow_soft_placement=True)
                else:
                    num_thread = int(os.environ.get('OMP_NUM_THREADS'))
                    config = tf.ConfigProto(intra_op_parallelism_threads=num_thread,
                                            allow_soft_placement=True)
                    # next line allocates ~28GB of RAM
                    _SESSION = tf.Session(config=config)
            session = _SESSION
        if not _MANUAL_VAR_INIT:
            with session.graph.as_default():
                _initialize_variables()
        return session
    

    而且,所有可用模型都会发生这种情况,因为内存是在创建会话时分配的,在培训开始或变量初始化之前分配的。

    我知道TF分配所有可用的GPU内存(除非您重写 ConfigProto 和/或调整您的环境变量),但它对RAM的作用是否相同?一、 似乎框架正在分配我机器上的所有RAM,除了一个已经由其他进程分配的RAM。

    有人在不同版本的 张量流 凯拉斯 ?你认为有没有办法限制内存的使用量?


    更新1

    前一段时间,我的一个训练脚本在经过50-60次训练后,因内存不足错误被内核杀死。尽管易失性GPU内存使用统计数据显示它也在使用。(据我所知,不仅仅是分配)。


    更新2

    同意,虚拟内存不是有效的指标。但我发现,在模型的训练过程中,内存消耗几乎呈线性增长。我有以下训练循环:

    def train_model(model, x, y):
        loss = model.train_on_batch(x, y)
        return loss
    
    
    def train_model_42(model, x, y):
        # dummy function
        return 42.0
    
    
    def training_loop():
        # training parameters
        target_size = 224, 224, 3
        batch_size = 128
    
        # generator yielding batches of file paths
        files_stream = FilesStream(folder=TRAIN_IMAGES, batch_size=batch_size)
        files_source = files_stream()
    
        # list of generators loading images from persistent storage
        gens = [
            image_loader(),
            augment_images(horizontal_flip=True),
            shuffle_samples(),
            normalize_images(target_size=target_size)
        ]
    
        # Model from keras.applications with replaced top layer
        model = get_model('resnet50').build(n_classes=n_classes)
    
        for epoch in range(1, 1001):
            epoch_loss = []
            for _ in range(files_stream.steps_per_epoch):
                for gen in gens:
                    gen.send(None)
                processed = next(files_source)
                for gen in gens:
                    processed = gen.send(processed)
                x, y = processed
                loss = train_model_42(model, x, y) # <-- this shows pic. 1
                # loss = train_model(model, x, y)    <-- this shows pic. 2                  
                epoch_loss.append(loss)
            avg_loss = sum(epoch_loss) / len(epoch_loss)
            print('Epoch %03d: train loss = %2.4f' % (epoch, avg_loss))
    

    当我使用虚拟训练功能时,内存消耗图看起来如所示 pic 1 : enter image description here

    但是,在运行真正的培训过程时 pic 2 : enter image description here

    为什么在训练过程中内存消耗会增加?是否缓存了以前的数据批?模型/重量或其他任何东西是否应该占用越来越多的内存?

    我认为我的数据预处理管道可能有问题,但我有意将预处理函数编写为生成器。是否有某种默认的Keras回调应用于跟踪训练信息的模型,从而提高内存使用率?

    1 回复  |  直到 6 年前
        1
  •  2
  •   devforfu    6 年前

    我想我已经找到了问题的根源。当然,这与 tensorflow keras ,但我使用它们的方法。

    下面是一个类似于我的图像增强函数的函数:

    def augment_images():
        transformer = ImageDataGenerator()
        while True:
            x, y = yield
            generator = transformer.flow(x, y, batch_size=len(x), shuffle=False)
            transformed = next(generator)
            yield transformed
    

    它使用 keras.preprocessing.image.ImageDataGenerator 类以增强图像。但该类本身实例化 NumpyArrayIterator 对象 保留引用 x y 批处理和调用 ImageDataGenerator 作为代表。这就是内存泄漏的根源。这些对象似乎阻止了对数组进行垃圾收集。

    下面是一个显式使用迭代器的更新扩充函数:

    def augment_images(width_shift=0.2,
                       height_shift=0.2,
                       zoom=0.2,
                       rotation=30,
                       vertical_flip=False,
                       horizontal_flip=False):
    
        transformer = ImageDataGenerator()
        iterator = None
    
        while True:
            x, y = yield
            if iterator is None:
                iterator = NumpyArrayIterator(
                    x, y, transformer,
                    batch_size=len(x),
                    shuffle=False,
                    seed=None,
                    data_format=transformer.data_format)
            else:
                iterator.n = x.shape[0]
                iterator.x = x
                iterator.y = y
            transformed = next(iterator)
            yield transformed
    

    所以,问题出在我用来预处理数据的生成器包装中。(或者我会说,在我使用Keras的API和Python的生成器的方法中)。至少现在,当我替换了图像增强功能后,就不再有内存泄漏了。