1.数据集获取
获取猫狗数据集kaggle提取码:kfhw
数据集中有train.zip和test.zip两个压缩包,但是对test.zip中图片文件的名称中没有cat和dog进行区分,没法分类,所以只用到了train.zip一个文件,对train.zip进行解压,一共有25000张图片,图片名中指明了cat or dog
2.对图片进行预处理
#data_preprocess.py
import cv2
import os
import numpy as np
import random
import time
import pickle
data_dir = './data' # 解压后数据
start_time = time.time()
print("正在制作数据....")
# 图片统一大小100*100
# 训练集 20000张
# 测试集 剩下的所有,在训练集中进行切分,因为测试集没有标签
all_data_files = os.listdir(os.path.join(data_dir, "train/"))
random.shuffle(all_data_files) # 打乱文件顺序
all_train_files = all_data_files[:20000] # 前20000个图片用来训练
all_test_files = all_data_files[20000:] # 后5000个图片用来测试
train_images = [] # 存储图片对应的narry数组的
train_labels = [] # 存储图片对应标签
train_files = [] # 存储对应图片名
test_images = []
test_labels = []
test_files = []
for each in all_train_files:
img = cv2.imread(os.path.join(data_dir, "train", each), 1)
# print(img.shape) # 每张图片的大小不一致,需要转换成统一大小
resized_img = cv2.resize(img, (100, 100))
img_data = np.array(resized_img) # 统一转换成narray数组类型,因为tensorflow支持narray
train_images.append(img_data)
if 'cat' in each:
train_labels.append(0) # 0表示猫
elif 'dog' in each:
train_labels.append(1) # 1表示狗
else:
raise Exception("\n%s is a wrong train file" % (each))
train_files.append(each)
for each in all_test_files:
img = cv2.imread(os.path.join(data_dir, "train", each), 1)
# print(img.shape) # 每张图片的大小不一致,需要转换成统一大小
resized_img = cv2.resize(img, (100, 100))
img_data = np.array(resized_img) # 统一转换成narray数组类型,因为tensorflow支持narray
test_images.append(img_data)
if 'cat' in each:
test_labels.append(0) # 0表示猫
elif 'dog' in each:
test_labels.append(1) # 1表示狗
else:
raise Exception("\n%s is a wrong test file" % (each))
test_files.append(each)
# print(len(train_images), len(test_images))
train_data = {
'images': train_images,
'labels': train_labels,
'files': train_files
}
test_data = {
'images': test_images,
'labels': test_labels,
'files': test_files
}
with open(os.path.join(data_dir,"train-data"),'wb') as f:
pickle.dump(train_data,f)
with open(os.path.join(data_dir,'test-data'),'wb') as f:
pickle.dump(test_data,f)
end_time = time.time()
print('制作结束,用时{}秒.'.format(end_time-start_time))
预处理完成以后在data文件夹下面会多出两个文件train-data和test-data
预处理的代码参考自
3.训练
#train.py
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Dropout, Convolution2D, MaxPool2D, Flatten
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import to_categorical
import pickle
import numpy as np
def load_data(filename):
with open(filename, 'rb') as f:
data = pickle.load(f, encoding='utf-8')
return np.array(data['images']), to_categorical(np.array(data['labels']), num_classes=2), np.array(data['files'])
TRAIN_DIR = "data/train-data"
train_images, train_labels, train_files = load_data(TRAIN_DIR)
model = Sequential([
Convolution2D(16, kernel_size=(3, 3), strides=(1, 1), padding="same", input_shape=(100, 100, 3), activation='relu'),
# 100*100*96
MaxPool2D((2, 2), strides=(2, 2), padding='same'), # 50*50*96
Convolution2D(32, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu'), # 50*50*192
MaxPool2D((2, 2), strides=(2, 2), padding='same'), # 25*25*192
Convolution2D(64, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu'), # 25*25*384
MaxPool2D((2, 2), strides=(2, 2), padding='same'), #
Convolution2D(128, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu'),
MaxPool2D((2, 2), strides=(2, 2), padding='same'),
Flatten(),
Dense(512, activation='relu'),
Dropout(0.3),
Dense(256, activation='relu'),
Dropout(0.3),
Dense(2)
])
# 模型编译
model.compile(optimizer=Adam(), loss='categorical_crossentropy', metrics=['accuracy'])
# 模型训练
model.fit(train_images, train_labels, batch_size=200, epochs=10)
model.save("cat_and_dog.h5") # hdf5文件 pip intall h5py
训练完成以后将训练的模型进行保存
4.对训练好的模型可以进行更多的训练
#more_train.py
from tensorflow.keras.models import load_model
from tensorflow.keras.utils import to_categorical
import pickle
import numpy as np
def load_data(filename):
with open(filename, 'rb') as f:
data = pickle.load(f, encoding='utf-8')
return np.array(data['images']), to_categorical(np.array(data['labels']), num_classes=2), np.array(data['files'])
TRAIN_DIR = "data/train-data"
train_images, train_labels, train_files = load_data(TRAIN_DIR)
model = load_model("cat_and_dog.h5") # 同时加载结构和参数
# 模型训练
model.fit(train_images, train_labels, batch_size=200, epochs=10)
model.save("cat_and_dog.h5") # hdf5文件 pip intall h5py
更多的训练是基于之前已经训练过的模型
5.模型训练好以后可以进行测试
#test.py
from tensorflow.keras.models import load_model
from tensorflow.keras.utils import to_categorical
import pickle
import numpy as np
def load_data(filename):
with open(filename, 'rb') as f:
data = pickle.load(f, encoding='utf-8')
return np.array(data['images']), to_categorical(np.array(data['labels']), num_classes=2), np.array(data['files'])
TEST_DIR = "data/test-data"
test_image, test_labels, test_files = load_data(TEST_DIR)
model = load_model("cat_and_dog.h5") # 同时加载结构和参数
# 模型评估
loss, accuracy = model.evaluate(test_image, test_labels)
print("test loss", loss)
print("test accuracy", accuracy)
6.工程的目录结构
其中被框住的文件是有用的文件,绿色的被框住的是预处理后生成的文件
7结果
经过train.py训练以后这是我在训练一遍之后的准确度,其实经过多次训练还有一定的上升空间