【tf.keras】在 cifar 上训练 AlexNet,数据集过大导致 OOM

cifar-10 每张图片的大小为 32×32,而 AlexNet 要求图片的输入是 224×224(也有说 227×227 的,这是 224×224 的图片进行大小为 2 的 zero padding 的结果),所以一种做法是将 cifar-10 数据集的图片 resize 到 224×224。

此时遇到的问题是,cifar-10 resize 到 224×224 时,32G 内存都将无法完全加载所有数据,在归一化那一步(即每个像素点除以 255)就将发生 OOM(out of memory)。

那么此时的做法有:
1)将 resize 作为模型的一部分,如设置一个 layer 来对一个 batch 的图像进行 resize,这样 32×32 的 cifar-10 仍然可以完全加载到内存中;
2)一种通用的方法,每次只加载一部分数据到内存中,其余数据等到需要的时候再加载到内存。

注:本文 AlexNet 结构与 PyTorch 中一致。AlexNet in pytorch/vision

方法 1:加上一个 Lambda 层,对输入图片进行 resize

import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.python.keras import backend as K

K.clear_session()
config = tf.ConfigProto()
config.gpu_options.allow_growth = True  # 不全部占满显存, 按需分配
K.set_session(tf.Session(config=config))

# 超参数
learning_rate = 0.001
epochs = 120
batch_size = 32

cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()

x_train = x_train.astype(np.float32)
x_test = x_test.astype(np.float32)

x_train = x_train / 255
x_test = x_test / 255

model = tf.keras.models.Sequential([
    # Lambda 层,对输入图片进行 resize,以下是将图片扩大了 7 倍
    # resize 时,默认使用最近邻插值,想要用其它插值方式,需要直接修改 K.resize_images 方法的源代码。
    layers.Lambda(lambda img: K.resize_images(img, 7, 7, data_format='channels_last'), input_shape=(32, 32, 3)),
    layers.ZeroPadding2D(padding=(2, 2)),
    layers.Conv2D(64, (11, 11), strides=(4, 4), padding='valid', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)),

    layers.Conv2D(192, (5, 5), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)),

    layers.Conv2D(384, (3, 3), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)),

    layers.Flatten(),

    layers.Dense(4096, activation='relu', kernel_initializer='he_uniform'),
    layers.Dropout(drop_rate),
    layers.Dense(4096, activation='relu', kernel_initializer='he_uniform'),
    layers.Dropout(drop_rate),
    layers.Dense(num_classes, activation='softmax', kernel_initializer='he_uniform')
])

model.summary()

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train,
          epochs=epochs,
          batch_size=batch_size,
          verbose=2,
          validation_data=(x_val, y_val))

方法 2:使用 tensorflow.keras.utils.Sequence,构造一个 data generator

import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.python.keras import backend as K
from tensorflow.keras.utils import Sequence

from sklearn.model_selection import StratifiedShuffleSplit

import cv2
import os
import numpy as np
import h5py
import time

class CIFAR10Sequence(Sequence):
    def __init__(self, x_set, y_set, batch_size):
        """
        :param x_set: hdf5
        :param y_set: hdf5
        :param batch_size: int
        """
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size

    def __len__(self):
        return int(np.ceil(len(self.x) / float(self.batch_size)))

    def __getitem__(self, idx):
        batch_x = self.x[idx * self.batch_size:(idx + 1) * self.batch_size]
        batch_y = self.y[idx * self.batch_size:(idx + 1) * self.batch_size]

        batch_x = batch_x.astype(np.float32)
        batch_x = batch_x / 255

        return batch_x, batch_y

def _resized_data():
    """
    将 resize 后的 cifar-10 保存到 'data/cifar-10.h5'
    图片大小: [224, 224, 3]
    :return: None
    """
    cifar10 = tf.keras.datasets.cifar10

    (x_train, y_train), (x_test, y_test) = cifar10.load_data()

    start_time = time.clock()

    x_train = np.array([cv2.resize(img, (224, 224), interpolation=cv2.INTER_CUBIC) for img in x_train])
    x_test = np.array([cv2.resize(img, (224, 224), interpolation=cv2.INTER_CUBIC) for img in x_test])

    # initialize
    x_val = np.array([])
    y_val = np.array([])

    sss = StratifiedShuffleSplit(n_splits=1, test_size=0.1, random_state=32)
    for train_index, val_index in sss.split(x_train, y_train):
        print("TRAIN:", train_index, "VAL:", val_index)
        x_train, x_val = x_train[train_index], x_train[val_index]
        y_train, y_val = y_train[train_index], y_train[val_index]

    end_time = time.clock()
    print('Time consuming of resizing: ', (end_time - start_time))

    # 写文件
    filename = 'data/cifar-10.h5'
    h5f = h5py.File(filename, 'w')
    h5f.create_dataset('x_train', data=x_train)
    h5f.create_dataset('y_train', data=y_train)
    h5f.create_dataset('x_val', data=x_val)
    h5f.create_dataset('y_val', data=y_val)
    h5f.create_dataset('x_test', data=x_test)
    h5f.create_dataset('y_test', data=y_test)
    h5f.close()

def load_resized_data(filename='data/cifar-10.h5'):
    if not os.path.exists(filename):
        _resized_data()

    # 不要关闭 h5 文件,否则将无法读取数据,这一步并不会直接将数据加载到内存中
    # h5 文件支持切片读取,而且也很快
    h5f = h5py.File(filename, 'r')
    x_train = h5f['x_train']
    y_train = h5f['y_train']
    x_val = h5f['x_val']
    y_val = h5f['y_val']
    x_test = h5f['x_test']
    y_test = h5f['y_test']

    return (x_train, y_train), (x_val, y_val), (x_test, y_test)

K.clear_session()
config = tf.ConfigProto()
config.gpu_options.allow_growth = True  # 不全部占满显存, 按需分配
K.set_session(tf.Session(config=config))

# 超参数
learning_rate = 0.001
epochs = 120
batch_size = 32

(x_train, y_train), (x_val, y_val), (x_test, y_test) = load_resized_data()

x_val = x_val.astype(np.float32)
x_test = x_test.astype(np.float32)

x_val = x_val / 255
x_test = x_test / 255

model = tf.keras.models.Sequential([
    layers.ZeroPadding2D(padding=(2, 2), input_shape=(224, 224, 3)),
    layers.Conv2D(64, (11, 11), strides=(4, 4), padding='valid', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)),

    layers.Conv2D(192, (5, 5), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)),

    layers.Conv2D(384, (3, 3), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu',
                  kernel_initializer='he_uniform'),
    layers.MaxPooling2D(pool_size=(3, 3), strides=(2, 2)),

    layers.Flatten(),

    layers.Dense(4096, activation='relu', kernel_initializer='he_uniform'),
    layers.Dropout(drop_rate),
    layers.Dense(4096, activation='relu', kernel_initializer='he_uniform'),
    layers.Dropout(drop_rate),
    layers.Dense(num_classes, activation='softmax', kernel_initializer='he_uniform')
])

model.summary()

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# shuffle 默认为 True, 意味着在训练一个 epoch 之后,CIFAR10Sequence 的 idx 会随机选择,而不是顺序选择,这样在 batch-level 进行了随机,一个 batch 内的样本顺序是固定的
model.fit_generator(CIFAR10Sequence(x_train, y_train, batch_size=batch_size),
                    # steps_per_epoch=int(np.ceil(len(x_train)/batch_size)),
                    epochs=epochs,
                    verbose=2,
                    callbacks=None,
                    validation_data=(x_val[:], y_val[:]))

References

class CIFAR10Sequence(Sequence) -- github
keras.utils.Sequence()
AlexNet in pytorch/vision

原文地址:https://www.cnblogs.com/wuliytTaotao/p/11191702.html

时间: 2024-10-07 14:24:53

【tf.keras】在 cifar 上训练 AlexNet,数据集过大导致 OOM的相关文章

用DPM(Deformable Part Model,voc-release3.1)算法在INRIA数据集上训练自己的人体检测模型

我的环境 DPM源码版本:voc-release3.1 VOC开发包版本:VOC2007_devkit_08-Jun Matlab版本:MatlabR2012b c++编译器:VS2010 系统:Win7 32位 learn.exe迭代次数:5万次 数据集:INRIA 人体数据集,等 步骤一,首先要使voc-release3.1目标检测部分的代码在windows系统下跑起来: 在Windows下运行Felzenszwalb的Deformable Part Models(voc-release4.

用DPM(Deformable Part Model,voc-release4.01)算法在INRIA数据集上训练自己的人体检测模型

步骤一,首先要使voc-release4.01目标检测部分的代码在windows系统下跑起来: 参考在window下运行DPM(deformable part models) -(检测demo部分) 步骤二,把训练部分代码跑通,在VOC数据集上进行测试,如下文: 在windows下运行Felzenszwalb的Deformable Part Model(DPM)源码voc-release3.1来训练自己的模型 但是其中的learn.cpp代码有误,其中319行check(argc == 8)通不

tf.keras入门1——使用sequential model建立一个VGGlike模型

建立一个简单的模型 sequential model sequential model是一个线性堆叠layers的模型.你既可以通过使用List加入layers的方法初始化,也可以通过.add方法添加layers. 为了建立一个简单的模型,这里以一个全连接层的多层感知机为例: import tensorflow as tf from tensorflow import keras from keras import layers model = Sequential([ layers.Dense

【tf.keras】AdamW: Adam with Weight decay

论文 Decoupled Weight Decay Regularization 中提到,Adam 在使用时,L2 regularization 与 weight decay 并不等价,并提出了 AdamW,在神经网络需要正则项时,用 AdamW 替换 Adam+L2 会得到更好的性能. TensorFlow 2.0 在 tensorflow_addons 库里面实现了 AdamW,目前在 Mac 和 Linux 上可以直接pip install tensorflow_addons进行安装,在

tf.keras 用生成器读取图片数据+预处理

0. 需求 当训练的数据非常多时,是不希望分配过多的内存将数据存入,否则其他占用内存的数据处理步骤就没法进行了.我们最好是以小批量地方式读入数据,然后预处理,然后送到网络,之后释放内存,以此循环. 1. 方法的简要说明 tf.keras中有一个高度封装的图片预处理类:ImageDataGenerator ImageDataGenerator类还实现了一个非常方便的自动读取训练集文件夹的方法:flow_from_directory() 我们实例化一个ImageDataGenerator类后,设置预

【tensorflow2.0】高阶api--主要为tf.keras.models提供的模型的类接口

下面的范例使用TensorFlow的高阶API实现线性回归模型. TensorFlow的高阶API主要为tf.keras.models提供的模型的类接口. 使用Keras接口有以下3种方式构建模型:使用Sequential按层顺序构建模型,使用函数式API构建任意结构模型,继承Model基类构建自定义模型. 此处分别演示使用Sequential按层顺序构建模型以及继承Model基类构建自定义模型. 一,使用Sequential按层顺序构建模型[面向新手] import tensorflow as

【tf.keras】tf.keras模型复现

keras 构建模型很简单,上手很方便,同时又是 tensorflow 的高级 API,所以学学也挺好. 模型复现在我们的实验中也挺重要的,跑出了一个模型,虽然我们可以将模型的 checkpoint 保存,但再跑一遍,怎么都得不到相同的结果,对我而言这是不能接受的. 用 keras 实现模型,想要能够复现,需要将设置各个可能的随机过程的 seed:而且,代码不要在 GPU 上跑,而是在 CPU 上跑.(也就是说,GPU 上得到的 keras 模型没办法再复现.) 我的 tensorflow+ke

【tf.keras】tf.keras使用tensorflow中定义的optimizer

我的 tensorflow+keras 版本: print(tf.VERSION) # '1.10.0' print(tf.keras.__version__) # '2.1.6-tf' tf.keras 没有实现 AdamW,即 Adam with Weight decay.论文<DECOUPLED WEIGHT DECAY REGULARIZATION>提出,在使用 Adam 时,weight decay 不等于 L2 regularization.具体可以参见 当前训练神经网络最快的方式

使用faster-rcnn.pytorch训练自己数据集

引言 最近在实验室复现faster-rcnn代码,基于此项目jwyang/faster-rcnn.pytorch(目前GitHub上star最多的faster-rcnn实现),成功测试源码数据集后,想使用自己的数据集爽一下. 本文主要介绍如何跑通源代码并“傻瓜式”训练自己的数据集~之前的此类博客都是介绍如何在原作者的caffe源码下进行数据集训练,那么本文针对目前形势一片大好的pytorh版faster-rcnn源码进行训练新的数据集,废话不多说,Lets go! faster-rcnn pyt