前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Mobilenet 和 Keras 来做迁移学习

使用 Mobilenet 和 Keras 来做迁移学习

作者头像
AI研习社
发布2018-12-14 10:05:28
1.5K0
发布2018-12-14 10:05:28
举报
文章被收录于专栏:AI研习社AI研习社

本文为 AI 研习社编译的技术博客,原标题 : Transfer Learning using Mobilenet and Keras 作者 | Ferhat Culfaz 翻译 | 胡瑛皓 校对 | 酱番梨 整理 | 菠萝妹 原文链接: https://towardsdatascience.com/transfer-learning-using-mobilenet-and-keras-c75daf7ff299 注:本文的相关链接请点击文末【阅读原文】进行访问

使用Mobilenet和Keras来做迁移学习

本文以notebook的实例的形式讲解。首先用Mobilenet分类狗的图片,然后演示一张不能正确分类的蓝雀图片,然后用迁移学习和Mobilenet重新训练,使这张图片得到正确分类。例子中举的是二分类,当然也可以按需要进行增加更多类型,看具体硬件和计算时间的限制。

Mobilenet论文地址:https://arxiv.org/pdf/1704.04861.pdf

MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications, Howard et al, 2017.

Mobilenet采用轻量级架构,会用它进行训练。它使用深度可分离卷积操作,意思是说其采用的是单通道卷积操作,而不是混合三种颜色然后进行扁平化操作。其具有过滤输入通道的效果。或就像论文作者解释的: “ MobileNets运用深度卷积操作,对每个输入通道应用单个过滤操作。然后逐点用1×1卷积合并深度卷积的结果。用标准卷积将输入进行过滤合并到一组新的输出。深度可分离卷积再将其分开成2层,一层用于过滤,另一层用于合并。上述分解显著减少了计算量和模型大小。”

逐点卷积和深度卷积的区别

Mobilenet的整体架构是这样的,其中包含30层:

  1. 步长2的卷积层
  2. 深度卷积
  3. 逐点卷积层使通道数翻倍
  4. 步长为2的深度卷积层
  5. 逐点卷积层使通道数翻倍等

等等

Mobilenet 完整架构

其维护成本很低,因而性能速度都很好。目前也有一些受青睐的预训练模型,模型的大小可在适应内存或磁盘上,与所用到的参数成正比。模型的速度和能耗与MACs(Multiply-Accumulates)数量成正比,该指标用以衡量乘法操作与累加操作的数量。

好,现在我们开始编码!

本文代码地址如下: https://github.com/ferhat00/Deep-Learning/tree/master/Transfer%20Learning%20CNN

首先,加载一些必要的包和库。

代码语言:javascript
复制
import keras
from keras import backend as K
from keras.layers.core import Dense, Activation
from keras.optimizers import Adam
from keras.metrics import categorical_crossentropy
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing import image
from keras.models import Model
from keras.applications import imagenet_utils
from keras.layers import Dense,GlobalAveragePooling2D
from keras.applications import MobileNet
from keras.applications.mobilenet import preprocess_input
import numpy as np
from IPython.display import Image
from keras.optimizers import Adam

我们从Keras导入预训练模型。

代码语言:javascript
复制
mobile = keras.applications.mobilenet.MobileNet()
def prepare_image(file):
    img_path = ''
    img = image.load_img(img_path + file, target_size=(224, 224))
    img_array = image.img_to_array(img)
    img_array_expanded_dims = np.expand_dims(img_array, axis=0)
    return keras.applications.mobilenet.preprocess_input(img_array_expanded_dims)

我们试试看分类不同品种的狗狗。

代码语言:javascript
复制
Image(filename='German_Shepherd.jpg')
代码语言:javascript
复制
preprocessed_image = prepare_image('German_Shepherd.jpg')
predictions = mobile.predict(preprocessed_image)
results = imagenet_utils.decode_predictions(predictions)
results

输出:

代码语言:javascript
复制
[[('n02106662', 'German_shepherd', 0.9796372),
  ('n02105162', 'malinois', 0.020184083),
  ('n02091467', 'Norwegian_elkhound', 0.00015799515),
  ('n02116738', 'African_hunting_dog', 5.2901587e-06),
  ('n02105251', 'briard', 3.9127376e-06)]]
Image(filename='labrador1.jpg')
代码语言:javascript
复制
preprocessed_image = prepare_image('labrador1.jpg')
predictions = mobile.predict(preprocessed_image)
results = imagenet_utils.decode_predictions(predictions)
results

输出:

代码语言:javascript
复制
[[(‘n02099712’, ‘Labrador_retriever’, 0.73073703),
 (‘n02087394’, ‘Rhodesian_ridgeback’, 0.03984367),
 (‘n02092339’, ‘Weimaraner’, 0.03359009),
 (‘n02109047’, ‘Great_Dane’, 0.028944707),
 (‘n02110341’, ‘dalmatian’, 0.022403581)]]
Image(filename='poodle1.jpg')
代码语言:javascript
复制
preprocessed_image = prepare_image('poodle1.jpg')
predictions = mobile.predict(preprocessed_image)
results = imagenet_utils.decode_predictions(predictions)
results

输出:

代码语言:javascript
复制
[[('n02113799', 'standard_poodle', 0.5650911),
  ('n02113712', 'miniature_poodle', 0.37279922),
  ('n02102973', 'Irish_water_spaniel', 0.053150617),
  ('n02113624', 'toy_poodle', 0.0072146286),
  ('n02093859', 'Kerry_blue_terrier', 0.0013652634)]]

目前为止一切都很好。分类器区分出不同品种的狗。那么让我们拿一种鸟类图片来试试,这里用蓝雀图片。

代码语言:javascript
复制
Image(filename='blue_tit.jpg')

蓝雀

代码语言:javascript
复制
preprocessed_image = prepare_image('blue_tit.jpg')
predictions = mobile.predict(preprocessed_image)
results = imagenet_utils.decode_predictions(predictions)
results

输出:

代码语言:javascript
复制
[[('n01592084', 'chickadee', 0.95554715),
  ('n01530575', 'brambling', 0.012973112),
  ('n01828970', 'bee_eater', 0.012916375),
  ('n01532829', 'house_finch', 0.010978725),
  ('n01580077', 'jay', 0.0020677084)]]

可以看到,分类器不能识别蓝雀。图片被错分为山雀(chickadee)。这是一种北美本土的鸟类,有一些微妙的不同:

山雀

我们调一下 Mobilenet 的架构,然后重新训练顶部几层,进行迁移学习。 要达成这个,拿一些图片来训练这个模型。这里会让模型学习蓝雀和乌鸦。这里就不用手工下载训练用到的图片了,用谷歌图像搜索,然后下载这些图片,google_images_download包很好用,加一下引用就行了。

地址: https://github.com/hardikvasa/google-images-download

代码语言:javascript
复制
!pip install google_images_download
from google_images_download import google_images_download
response = google_images_download.googleimagesdownload()
arguments = {"keywords":"blue tit","limit":100,"print_urls":False,"format":"jpg", "size":">400*300"}
paths = response.download(arguments)
arguments = {"keywords":"crow","limit":100,"print_urls":False, "format":"jpg", "size":">400*300"}
paths = response.download(arguments)

现在我们重用MobileNet,会下载一个轻量级存档文件(17Mb), 冻结其基础层,在模型顶部增加几层,然后进行训练。注意本文只训练一个二分类器,区分蓝雀和乌鸦。

代码语言:javascript
复制
base_model=MobileNet(weights='imagenet',include_top=False) #imports the mobilenet model and discards the last 1000 neuron layer.

x=base_model.output
x=GlobalAveragePooling2D()(x)
x=Dense(1024,activation='relu')(x) #we add dense layers so that the model can learn more complex functions and classify for better results.
x=Dense(1024,activation='relu')(x) #dense layer 2
x=Dense(512,activation='relu')(x) #dense layer 3
preds=Dense(2,activation='softmax')(x) #final layer with softmax activation

我们来看一下模型的架构

代码语言:javascript
复制
for i,layer in enumerate(model.layers):
  print(i,layer.name)

这里采用Imagenet数据集预训练的权重。保证所有权重是不可被训练(冻结)的。只训练最后几个dense层。

代码语言:javascript
复制
for layer in model.layers:
    layer.trainable=False
# or if we want to set the first 20 layers of the network to be non-trainable
for layer in model.layers[:20]:
    layer.trainable=False
for layer in model.layers[20:]:
    layer.trainable=True

把训练数据载入ImageDataGenerator。指定一下路径,它会自动将数据以批次形式供给训练,简化了编码过程。

代码语言:javascript
复制
train_datagen=ImageDataGenerator(preprocessing_function=preprocess_input) #included in our dependencies

train_generator=train_datagen.flow_from_directory('C:/Users/Ferhat/Python Code/Workshop/Tensoorflow transfer learning/downloads',
                                                 target_size=(224,224),
                                                 color_mode='rgb',
                                                 batch_size=32,
                                                 class_mode='categorical',
                                                 shuffle=True)

编译模型。现在开始训练。在GTX1070 GPU环境下,训练不到2分钟。

代码语言:javascript
复制
model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])
# Adam optimizer
# loss function will be categorical cross entropy
# evaluation metric will be accuracy

step_size_train=train_generator.n//train_generator.batch_size
model.fit_generator(generator=train_generator,
                   steps_per_epoch=step_size_train,
                   epochs=10)
代码语言:javascript
复制
Epoch 1/10
5/5 [==============================] - 5s 952ms/step - loss: 0.9098 - acc: 0.6562
Epoch 2/10
5/5 [==============================] - 3s 563ms/step - loss: 0.0503 - acc: 0.9686
Epoch 3/10
5/5 [==============================] - 3s 687ms/step - loss: 0.0236 - acc: 0.9930
Epoch 4/10
5/5 [==============================] - 4s 716ms/step - loss: 7.5358e-04 - acc: 1.0000
Epoch 5/10
5/5 [==============================] - 3s 522ms/step - loss: 0.0021 - acc: 1.0000
Epoch 6/10
5/5 [==============================] - 4s 780ms/step - loss: 0.0353 - acc: 0.9937
Epoch 7/10
5/5 [==============================] - 3s 654ms/step - loss: 0.0905 - acc: 0.9938
Epoch 8/10
5/5 [==============================] - 4s 890ms/step - loss: 0.0047 - acc: 1.0000
Epoch 9/10
5/5 [==============================] - 3s 649ms/step - loss: 0.0377 - acc: 0.9867
Epoch 10/10
5/5 [==============================] - 5s 929ms/step - loss: 0.0125 - acc: 1.0000

模型训练好了。我们来测试一些独立输入的图片,检查一下预测情况。

代码语言:javascript
复制
def load_image(img_path, show=False):

    img = image.load_img(img_path, target_size=(150, 150))
    img_tensor = image.img_to_array(img)                    # (height, width, channels)
    img_tensor = np.expand_dims(img_tensor, axis=0)         # (1, height, width, channels), add a dimension because the model expects this shape: (batch_size, height, width, channels)
    img_tensor /= 255.                                      # imshow expects values in the range [0, 1]

    if show:
        plt.imshow(img_tensor[0])                           
        plt.axis('off')
        plt.show()

    return img_tensor
  
#img_path = 'C:/Users/Ferhat/Python Code/Workshop/Tensoorflow transfer learning/blue_tit.jpg'
img_path = 'C:/Users/Ferhat/Python Code/Workshop/Tensoorflow transfer learning/crow.jpg'
new_image = load_image(img_path)

pred = model.predict(new_image)

pred

输出:

代码语言:javascript
复制
array([[4.5191143e-15, 1.0000000e+00]], dtype=float32)

结果显示,分类器准确的预测了乌鸦,此处蓝雀图像被注释掉了。

乌鸦

本文中的方法可被进一步扩展到更多图像类型的分类上,分类数增加抽象效果会更好。这种方法是轻量级、可快速实现的CNN迁移学习方法。当然这也取决于速度、准确度、采用的硬件以及你投入的时间。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AI研习社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图像搜索
图像搜索(Image Search)基于腾讯云的图像解决方案,集成了图像检索、超细粒度元素挖掘和图像匹配等技术,通过以图搜图的方式在用户自建图片库中快速检索出与输入图片相同或相似的图片集合,可应用于图片版权保护、电商侵权审核、相似素材查询、同款商品搜索与推荐等场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档