本文重点介绍通过拆分原始数据集来加载和训练神经网络模型。 当整个数据集对于本地 RAM 来说太大并且必须在使用“model.fit”训练模型之前拆分
我们通常这样加载 CIFAR10 图像数据集
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
(train_data, train_labels), (test_data, test_labels) = datasets.cifar10.load_data()
load_data()
函数会自动下载数据集并将其存储在 ~/.keras/datasets/cifar-10-batches-py/
中,这就是您可以在文件夹中找到的内容。 查看 load_data()
的源代码,它会加载所有批次并让我们将数据很好地返回到 train_data, train_labels), (test_data, test_labels)
,但是如果您想一一阅读它们怎么办? 你会怎么做,这就是我们今天要探讨的。
我们用python的pickle
模块来加载数据。首先定义这个函数
def load_pickle(filename):
""" load correct version of pickle """
version = platform.python_version_tuple()
if version[0] == '2':
return pickle.load(filename)
elif version[0] == '3':
return pickle.load(filename, encoding='latin1')
raise ValueError("invalid python version: {}".format(version))
def load_data_partition(filename) -> None:
""" load single batch of cifar """
with open(filename, 'rb') as f:
datadict = load_pickle(filename=f)
data = datadict['data']
labels = datadict['labels']
batch_labels = datadict['batch_label']
filenames = datadict['filenames']
data = data.reshape(data.shape[0], 3, IMG_SIZE, IMG_SIZE) # reshape into (n, 3, 32, 32)
data = data.transpose(0, 2, 3, 1) # reshape into (n, 32, 32, 3)
data = data.astype('float32')
data = data / 255 # normalize
labels = np.array(labels) # convert to numpy array
return data, labels, batch_labels, filenames
load_pickle
安python版本返回准确的pickle.load
。然后load_partion
能读取~/.keras/datasets/cifar-10-batches-py/
里的batch文件,返回正确形状的tensor。如果直接用data的话,图片会有错误。
然后我们定义我们的神经网络模型。先定义一个比较简单的卷积神经网络。
def model_1():
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(IMG_SIZE, IMG_SIZE, 3)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(10))
return model
现在我们来定义主逻辑流程。 确保将 root
更改为正确的文件路径。
root = "~/.keras/datasets/cifar-10-batches-py/"
ef main():
model = model_1()
model.compile(optimizer='adam', loss=SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
model.summary()
for i in range(5):
print('training data_batch_{}'.format(i+1))
train_images, train_labels, batch_labels, filenames = load_data_partition(os.path.join(root, 'data_batch_{}'.format(i+1)))
# split into train and validation
val_images, val_labels = train_images[:2500], train_labels[:2500]
train_images, train_labels = train_images[2500:], train_labels[2500:]
model.fit(train_images, train_labels, validation_data=(val_images, val_labels), epochs=10)
# test our model at the end
print("testing")
test_images, test_labels, batch_labels, file_names = load_data_partition(os.path.join(root, 'test_batch'))
print(model.evaluate(test_images, test_labels))
在这里我们看到如何使用pickle
批量读取像CIFAR10这样的数据集,并不断调用model.fit
来训练我们的神经网络模型。 在这种情况下,CIFAR10 图像集(每批)非常小,形状为 (10000, 32, 32 3)
。 所有 5 个批次组合的形状都是 (50000, 32, 32, 3)
,但是如果图像更大怎么办? 例如,AlexNet 图像分类 CNN 模型需要具有维度 (277, 277, 3)
的图像。 如果我们将所有 50,000 张图像加载到内存中并将其大小调整为 277x277,除非您有大量 RAM,否则您的程序很可能会崩溃。 因此,有时我们可能需要批量加载和训练(这与 model.fit
中的批处理参数不同!)否则我们将耗尽内存。
下一次,让我们学习如何预处理图像(调整图像大小和数据增强)、如何保存图像以及如何定义 AlexNet 模型。下次再见!