之前也写过关于使用tensorflow在猫狗数据集上的训练,想要学习的可以看一下
猫狗数据集:https://pan.baidu.com/s/13hw4LK8ihR6-6-8mpjLKDA 密码:dmp4
对于猫狗数据上的训练,存在一点问题在与不能够将所有的训练集读入到内存,这时候需要用到keras中的
model.fit_generator()
接下来还是看代码吧
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from keras.optimizers import RMSprop
from keras.preprocessing.image import ImageDataGenerator
#下面的一部分是进行数据预处理
import os
import shutil
dataset_dir = 'kaggle/train/'
train_cats_dir = 'kaggle/train/cats/'
train_dogs_dir = 'kaggle/train/dogs/'
validation_cats_dir = 'kaggle/validation/cats/'
validation_dogs_dir = 'kaggle/validation/dogs/'
if not os.path.exists(train_cats_dir):
os.mkdir(train_cats_dir)
if not os.path.exists(train_dogs_dir):
os.mkdir(train_dogs_dir)
if not os.path.exists(validation_cats_dir):
os.mkdir('kaggle/validation/')
os.mkdir(validation_cats_dir)
if not os.path.exists(validation_dogs_dir):
os.mkdir(validation_dogs_dir)
cat_count = 0
dog_count = 0
image_list = os.listdir(dataset_dir)
for image in image_list:
print(image)
animal = image.split('.')[0]
image_path = os.path.join(dataset_dir, image)
if animal == 'cat':
cat_count += 1
if cat_count % 5 == 0:
shutil.move(image_path, validation_cats_dir)
else:
shutil.move(image_path, train_cats_dir)
if animal == 'dog':
dog_count += 1
if dog_count % 5 == 0:
shutil.move(image_path, validation_dogs_dir)
else:
shutil.move(image_path, train_dogs_dir)
train_dir = 'kaggle/train/'
validation_dir = 'kaggle/validation/'
train_datagen = ImageDataGenerator(rescale=1. / 255)
validation_datagen = ImageDataGenerator(rescale=1. / 255)
train_generator = train_datagen.flow_from_directory(
train_dir, # target directory
target_size=(150, 150), # resize图片
batch_size=20,
class_mode='binary'
)
validation_generator = validation_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary'
)
for data_batch, labels_batch in train_generator:
print('data batch shape:', data_batch.shape)
print('labels batch shape:', labels_batch.shape)
break
model = Sequential()
model.add(Conv2D(32, (3, 3), activation='relu',
input_shape=(150, 150, 3)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
print(model.summary())
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(lr=1e-4),
metrics=['acc'])
hist = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
validation_steps=50)
model.save('cat_and_dog.h5')
上面的代码首先将kaggle/train/中的数据集分成两个部分,一部分是train的,一部分是validation的。因为model.fit_generator()函数的需求,还需要将train集中的猫狗数据分别放在kaggle/train/cats/和kaggle/train/dogs/;同理也需要将validation中的数据这样处理。然后就可以直接训练了。
注释:如果不成功的话,最好删除生成的kaggle文件,然后放上原始的kaggle文件。
需要解释的估计就是model.fit_generator()
还有关于ImageDataGenerator的使用方法
fit_generator(self, generator, steps_per_epoch=None, epochs=1, verbose=1, callbacks=None, validation_data=None, validation_steps=None, class_weight=None, max_queue_size=10, workers=1, use_multiprocessing=False, shuffle=True, initial_epoch=0)
使用 Python 生成器或 Sequence
实例逐批生成的数据,按批次训练模型。
生成器与模型并行运行,以提高效率。 例如,这可以让你在 CPU 上对图像进行实时数据增强,以在 GPU 上训练模型。
keras.utils.Sequence
的使用可以保证数据的顺序, 以及当 use_multiprocessing=True
时 ,保证每个输入在每个 epoch 只使用一次。
参数
Sequence
(keras.utils.Sequence
)。 生成器的输出应该为以下之一:(inputs, targets)
元组(inputs, targets, sample_weights)
元组。 所有的数组都必须包含同样数量的样本。生成器将无限地在数据集上循环。当运行到第 steps_per_epoch
时,记一个 epoch 结束。generator
产生的总步数(批次样本)。它通常应该等于你的数据集的样本数量除以批量大小。可选参数 Sequence
:如果未指定,将使用len(generator)
作为步数。epochs
应被理解为 「最终轮数」。模型并不是训练了 epochs
轮,而是到第 epochs
轮停止训练。Sequence
实例(inputs, targets)
元组(inputs, targets, sample_weights)
元组。validation_data
是一个生成器时才可用。 每个 epoch 结束时验证集生成器产生的步数。它通常应该等于你的数据集的样本数量除以批量大小。可选参数 Sequence
:如果未指定,将使用len(generator)
作为步数。Sequence
(keras.utils.Sequence) 实例同用。返回
一个 History
对象。
使用这种方法进行训练,感觉标签就是文件夹的个数,对于大规模的数据训练还是不怎么好用,可以使用接下来的博客,可以将所有图片的地址保存到内存中,然后进行训练。这样就不会出现内存不足的情况了
直接代码吧
import os
from keras.models import load_model
from keras.preprocessing import image
import matplotlib.pyplot as plt
import numpy as np
#单张图片的识别
model = load_model('cats_and_dogs_small_1.h5')
img = image.load_img('kaggle/test1/2.jpg', target_size=(150, 150))
# plt.imshow(img)
# plt.show()
#【3】将图片转化为4d tensor形式
x = image.img_to_array(img)
print(x.shape) #(224, 224, 3)
x = np.expand_dims(x, axis=0)
print(x.shape) #(1, 224, 224, 3)
pres = model.predict(x)
print(int(pres[0][0]))
if int(pres[0][0]) > 0.5:
print('识别的结果是狗')
#多张图片的识别,这里买可以从kaggle/test1/中复制几张图片放到一个新建的文件夹test中,然后进行测试
#如果加载kaggle/test1/中的全部分会超出内存,当然也可以使用训练时候的策略进行测试
file_list = os.listdir('test_image/')
images = []
for file in file_list:
# print(file)
img = image.load_img(os.path.join('test_image/', file), target_size=(150, 150))
img = image.img_to_array(img)
img = np.expand_dims(img, axis=0)
images.append(img)
x_train = np.array(images, dtype="float") / 255.0
x = np.concatenate([x for x in x_train])
#预测
y = model.predict(x)
#根据结果可以看出来,0代表的是猫,1代表的是狗。
# 同时也可以从训练cats_and_dogs_small/train/里面文件的顺序知道类别代表的信息
for i in range(len(file_list)):
print(y[i][0])
# print('image class:', int(y[i]))
# print('image class:', round(y[i]))
if y[i][0] > 0.5:
print('image {} class:'.format(file_list[i]), 1)
else:
print('image {} class:'.format(file_list[i]), 0)