deep learning keras: 关于动物识别的vgg_16模型与调优

       几个月前看到DataCastle的“猫狗大战”的竞赛的时候,想过要用CNN进行识别,毕竟这方面有很多参考的案例,然而当时正在研究其他算法,神经网络理解的也不是很精通,就没有去实现。一个月前,看到网站论坛里yinjh战队分享的源代码,并且取得了很高的成绩,就想着照着做做,当作学习。初步分析代码后,发现了一个很严重的问题,他们貌似没有用到训练集,这就有点吃惊了(这是神马黑科技???)。原来他们用了一种vgg_16的模型,而且已经有了训练好的权重(“vgg16_weights.h5”),对于日常物品可以直接进行识别。我当时的心情~~哈哈,很想知道竞赛组织者是怎么想的,辛辛苦苦准备的大赛竟然被一个已经训练好的模型完美吊打。不过以能跑的都是好鞍为原则,还是研究了下这个模型。

       打开keras官方文档,发现卷积模块完全一样,再看看学习规则,也就是sgd的参数需要自己调,这个团队简直机智到家(目瞪口呆~)。跑了一遍代码,发现还是有问题的,cv2.imread读到空图,resize直接挂掉,因此需要甄别一下空图。改之后继续跑,顺利输出结果,截取前五十个提交,有成绩了。继续截取前两百个提交,成绩提升到0.98,还不错。接下来改sgd参数,先改lr(学习率初始值),调了很多次,不升反降,哈哈(都0.98了还咋升)。decay没啥好调的,调动量,其实这个参数前辈已经调得很好了,梯度肯定是缓和的,0.9也合适。

       这次对vgg_16的学习有几个认识,第一,keras的调包操作虽然比较显得业余,但是如果懂得调参,并调得一手好参数,那么模型也能拟合到位的。第二,在图像以及其他的深度学习中保存权重参数将可以省很大力气,以后可以“调包”的时候就很方便了。第三,这次最大的问题,是对图像处理的理解上,有些地方还是需要好好学习cv的处理部分。

最后,引入这次代码(多处加注释)。

#coding:utf-8
import os   #处理字符串路径
import glob   #查找文件

from keras.models import Sequential   #导入Sequential模型

from keras.layers.core import Flatten, Dense, Dropout

from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D

from keras.optimizers import SGD

import cv2, numpy as np

from pandas import Series,DataFrame

def VGG_16(weights_path=None):    #根据keras官方文档建立VGG_16模型

    model = Sequential()

    model.add(ZeroPadding2D((1,1),input_shape=(3,224,224)))
    model.add(Convolution2D(64, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(64, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2,2), strides=(2,2)))


    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(128, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(128, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2,2), strides=(2,2)))


    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(256, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(256, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(256, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2,2), strides=(2,2)))

    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2,2), strides=(2,2)))


    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(ZeroPadding2D((1,1)))
    model.add(Convolution2D(512, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2,2), strides=(2,2)))


    model.add(Flatten())
    model.add(Dense(4096, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(4096, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1000, activation='softmax'))

    if weights_path:
        model.load_weights(weights_path)

    return model

model = VGG_16('vgg16_weights.h5')   #用训练好的vgg16_weights权重做预测
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)    #采用随机梯度下降法,学习率初始值0.1,动量参数为0.9,学习率衰减值为1e-6,确定使用Nesterov动量
model.compile(optimizer=sgd, loss='categorical_crossentropy')    #配置模型学习过程,目标函数为categorical_crossentropy:亦称作多类的对数损失,注意使用该目标函数时,需要将标签转化为形如(nb_samples, nb_classes)的二值序列

dogs=[251, 268, 256, 253, 255, 254, 257, 159, 211, 210, 212, 214, 213, 216, 215, 219, 220, 221, 217, 218, 207, 209, 206, 205, 208, 193, 202, 194, 191, 204, 187, 203, 185, 192, 183, 199, 195, 181, 184, 201, 186, 200, 182, 188, 189, 190, 197, 196, 198, 179, 180, 177, 178, 175, 163, 174, 176, 160, 162, 161, 164, 168, 173, 170, 169, 165, 166, 167, 172, 171, 264, 263, 266, 265, 267, 262, 246, 242, 243, 248, 247, 229, 233, 234, 228, 231, 232, 230, 227, 226, 235, 225, 224, 223, 222, 236, 252, 237, 250, 249, 241, 239, 238, 240, 244, 245, 259, 261, 260, 258, 154, 153, 158, 152, 155, 151, 157, 156]   #训练好的权重文件里,属于狗的位置

cats=[281,282,283,284,285,286,287]   #权重文件里,猫的位置

path = os.path.join('imgs', 'test', '*.jpg')   #拼接路径
files = glob.glob(path)    #打开这个路径

result=[]
flbase=0
p=0
a=0


for fl in files:
    a=cv2.imread(fl)   #读入图像
    if  a ==None:     #异常检测,检测空图
        pass
    else:
        im = cv2.resize(a,(224,224)).astype(np.float32)   #使图片变为224*224大小并转化为float32格式
        im[:,:,0] -= 103.939
        im[:,:,1] -= 116.779
        im[:,:,2] -= 123.68
        im = im.transpose((2,0,1))
        im = np.expand_dims(im,axis=0)    
        out = model.predict(im)   #输出的预测列表是二维列表,即[[x]]的形式,这个列表里储存了该图像与权重文件中每个物品的相似度
        flbase = os.path.basename(fl)
        p = np.sum(out[0,dogs]) / (np.sum(out[0,dogs]) + np.sum(out[0,cats]))   #计算该图像与狗的相似度/(该图像与狗的相似度+该图像与猫的相似度)
        result.append((flbase,p))   #将(文件名,相似概率)加到result列表里

result=sorted(result, key=lambda x:x[1], reverse=True)   #按概率逆序排序

for x in result:
    print x[0],x[1]

for x in result:
    print x[0]

dataframe=DataFrame(result)
dataframe.to_csv("~/dogs-recognition.csv")






你可能感兴趣的:(Deep,Learning,计算机视觉,数据挖掘,卷积神经网络,vgg_16,CNN)