在lintcode刷AI题:猫狗分类器

lintcode上面有十几道类似于Kaggle的小项目,用于深度学习的入手练习再好不过了,现在就让我们上手这道猫狗分类器的问题吧!

(全程用Keras框架,简单上手!)

本题网址:LintCode

题目描述:

给出一张猫或狗的图片,识别出这是猫还是狗。

这种识别具有很重要的意义,比如:

Web服务为了进行保护,会防止一些计算机进行恶意访问或信息爬取,进而设立一些验证问题,这些验证问题对于人来说很容易做,但是对于计算机这很困难。这样的方法称为CAPTCHA(完全自动公开的图灵测试)或HIP(人类交互证明)。 HIP有很多用处,例如减少垃圾邮件,防止暴力破解密码等。

比较有名的Asirra(用于限制访问的动物图像识别)就是一个HIP,它会让用户识别图片信息,比如识别出图片中是猫还是狗。对于人来说这很容易,但是对于计算机很困难。以下是Asirra的一个例子:

寻找流浪宠物为其提供住所的网站——Petfinder.com,向微软研究院提供了超过三百万张猫和狗的图像,这些图片由美国各地成千上万的动物收容所手动分类。

对于要入侵的计算机,随机猜测一般是最简单的攻击方法。图片识别并不容易,因为图片之间不同的的背景,角度,姿势,亮度等都存在着巨大的差异,很难识别。

不过随着机器学习——尤其是神经网络的发展,这项工作精度可以达到60%以上。而60%分类器就已经能将12幅图像的猜测概率从1/4096提高到1/459。

这道题目会给大家上万张的图片作为训练集,你能在猫狗之间分辨出它们的差异吗?



一 下载,探索数据

这道题提供了25000张猫狗图片,分为训练集(10000猫,10000狗),测试集(5000张,猫狗未标注)

图片看起来就像这样子的:

这里请使用python将所有图片都缩放到224*224大小,保存到另一个文件夹中,做完这一步后可以把原始数据删掉,代码很简单,下面是例子:

  # 修改图片大小
for i in range(10000):
    img_path = '.\猫狗分类器data\train\cat.%d.jpg'%(i)
    im = Image.open(img_path)
    resizedIm = im.resize((224, 224))
    im.save(r'.\猫狗分类器data\\reshape_train\cat.%d.jpg'%(i))

二 数据预处理

如果想要用这2W张训练图片直接训练出一个分类器的话,那么最后的分数并不会很高,原因是图片实在太少,分类器的泛化能力很差,因此我们为了提升泛化能力(刷分),就需要动用一些训练好的模型,我们选用的是Keras官方已经训练好的VGG19网络,提取出VGG19网络最后一层卷积层的输出数据,每张照片经过模型,转换为了[7,7,512]大小的数据。

将2W张猫狗图片全部经过这样的处理后,保存到一个train_data_x.npy数组里面去,训练标签就设置为一个2w x 1大小的向量,猫用0表示,狗用1表示。同理对于5k张测试集数据,也这样保存到test_data_x.npy里面去。

代码如下:

# 数据预处理
# 导入训练好的VGG网络
model = VGG19(weights='imagenet', include_top=False)
train_data_x = np.zeros([20000,7,7,512]).astype("float16")
train_data_y = np.zeros([20000,])
train_data_y[10000:] = 1
# 猫的数据0
for i in range(10000):
    img_path = '.\猫狗分类器data\\reshape_train\cat.%d.jpg'%(i)
    img = image.load_img(img_path, target_size=(224, 224))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    features = model.predict(x)
    train_data_x[i, ::] = features
    print(i)

# 狗的数据1
for i in range(10000):
    img_path = '.\猫狗分类器data\\reshape_train\dog.%d.jpg'%(i)
    img = image.load_img(img_path, target_size=(224, 224))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    features = model.predict(x)
    train_data_x[i+10000, ::] = features
    print(i+10000)
np.save("./猫狗分类器data/train_data_x.npy",train_data_x)
np.save("./猫狗分类器data/train_data_y.npy",train_data_y)

# 测试数据
test_data_x = np.zeros([5000,7,7,512]).astype("float16")
for i in range(5000):
    img_path = '.\猫狗分类器data\\reshape_test\%d.jpg'%(i)
    img = image.load_img(img_path, target_size=(224, 224))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    features = model.predict(x)
    test_data_x[i, ::] = features
    print(i)
np.save("./猫狗分类器data/test_data_x.npy",test_data_x)

初次运行代码可能需要下载vgg模型,不过此后就再也不需要啦!



三 建立模型,并训练

在训练之前先读取数据,并且将7*7*512的数组平摊成25088长度的向量。

由于在原版的vgg网络中,卷积层后面也都是全连接层,这里的模型也都使用全连接层。首先将25088->2048->512->64,每一步都是全连接层+dropout+relu,在“64”层后面利用sigmoid转换成0-1之间的数据,越靠近0,表示预测猫的可能性更大,反之越靠近1,表示预测狗的可能性更大。

在Nvidia GeForce GTX 1050 Ti (4 GB)上,训练耗时1-2min

# 读取数据
train_data_x = np.load("./猫狗分类器data/train_data_x.npy")
train_data_y = np.load("./猫狗分类器data/train_data_y.npy")
test_data_x = np.load("./猫狗分类器data/test_data_x.npy")
print(train_data_x.shape,train_data_y.shape,test_data_x.shape)  
# (20000, 7, 7, 512) (20000,) (5000, 7, 7, 512)

train_data_x = np.reshape(train_data_x,[train_data_x.shape[0], -1])
test_data_x = np.reshape(test_data_x,[test_data_x.shape[0], -1])
print(train_data_x.shape,train_data_y.shape,test_data_x.shape)  
# (20000, 25088) (20000,) (5000, 25088)

# 构建模型
model = Sequential()
model.add(Dense(2048,activation="relu",input_shape=(25088,)))
model.add(Dropout(0.5))
model.add(Dense(512,activation="relu"))
model.add(Dropout(0.5))
model.add(Dense(64))
model.add(Dense(1,activation="sigmoid"))
model.summary()

model.compile(loss='binary_crossentropy',optimizer='adadelta',metrics=['accuracy'])
model.fit(x=train_data_x,y=train_data_y,batch_size=2048,nb_epoch=15,verbose=1)


四 预测,提交数据

这一步就很简单啦,用训练好的模型预测猫狗,并写到submission.csv里面就行了。

# 预测答案
test_y = model.predict_classes(test_data_x)
answer = pd.read_csv(open("./猫狗分类器data/sampleSubmission.csv"))
answer["label"] = test_y
answer.to_csv("./猫狗分类器data/submission.csv",index=False)  # 不要保存引索列

上交后,正确率0.98240,排名5/53


五 开源

所有代码都在我的github上,下载即运行

猜你喜欢

转载自blog.csdn.net/yuweiming70/article/details/80856012