tensorflow2.3.0迁移学习案例分析(以猫狗识别为例)

我对迁移学习的简单理解就是,将别人训练好的模型用到自己的程序中,同时根据实际情况,重新训练模型中的部分参数。我认为这样有2个好处,一是由于使用了已知的模型,那么节省训练的时间,二是在充分利用已知的成果,节省精力。下面我使用Jupyter Notebook编辑环境,以猫狗识别为例,对迁移学习进行分析。

1、首先导入需要的包

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import glob
import os

2、为了使代码更加见解,我进行了如下的赋值。

keras = tf.keras
layers = tf.keras.layers

3、读取数据集,获取数据集中每条数据的路径,路径存放到列表中。其中,train_image_path用于存放训练数据集,test_image_path用于存放验证数据集。

train_image_path = glob.glob('/home/haha/资料/人工智能/数据集/dog-cat-2000/train/*/*.jpg')
test_image_path = glob.glob('/home/haha/资料/人工智能/数据集/dog-cat-2000/test/*/*.jpg')
np.random.shuffle(train_image_path)

执行test_image_path[:5],可以看到验证数据集中前5项,如下。

['/home/haha/资料/人工智能/数据集/dog-cat-2000/test/dog/dog.1433.jpg',
 '/home/haha/资料/人工智能/数据集/dog-cat-2000/test/dog/dog.1091.jpg',
 '/home/haha/资料/人工智能/数据集/dog-cat-2000/test/dog/dog.1269.jpg',
 '/home/haha/资料/人工智能/数据集/dog-cat-2000/test/dog/dog.1267.jpg',
 '/home/haha/资料/人工智能/数据集/dog-cat-2000/test/dog/dog.1043.jpg']

4、获取数据集中的每条数据对应的标签。dog的标签值为0,cat的标签值为1。

train_image_label = [int(p.split('/')[-2] == 'cat') for p in train_image_path]
test_image_label = [int(p.split('/')[-2] == 'cat') for p in test_image_path]

5、定义图片的预处理函数。

def load_preprosess_image(path, label):
    image = tf.io.read_file(path)
    image = tf.image.decode_jpeg(image, channels=3) #由于图像是彩色的,所以channels=3
    image = tf.image.resize(image, [256,256]) #将图片大小值为256*256
    image = tf.cast(image, tf.float32) #图片像素值的默认类型为uint8,现在需要将数据类型转换为tf.float32
    image = image/255 #图片每一像素的值范围是0-255,现在需做归一化处理,所以除以255
    #label的形式为[1,2,3],下面代码将label的形式转化为[[1], [2], [3]]
    label = tf.reshape(label, [1])
    return image, label

6、将图片的路径和标签组合列表中的一项。

train_image_ds = tf.data.Dataset.from_tensor_slices((train_image_path, train_image_label))
test_image_ds = tf.data.Dataset.from_tensor_slices((test_image_path, test_image_label))

7、调用load_preprosess_image进行图片预处理。

AUTOTUNE = tf.data.experimental.AUTOTUNE  #TensorFlow根据系统的实际情况,自动选择合适的值
#调用load_preprosess_image函数,进行图片处理。num_parallel_calls为TensorFlow选择的cpu的核心数。
train_image_ds = train_image_ds.map(load_preprosess_image, num_parallel_calls=AUTOTUNE)
#调用load_preprosess_image函数,进行图片处理。num_parallel_calls为TensorFlow选择的cpu的核心数。
test_image_ds = test_image_ds.map(load_preprosess_image, num_parallel_calls=AUTOTUNE)

8、我想看一下数据集。执行test_image_ds就可以看一下测试数据集的信息,结果为<ParallelMapDataset shapes: ((256, 256, 3), (1,)), types: (tf.float32, tf.int32)>,表示每张图片的大小为256*256,厚度为3(即彩色图片),对应图片标签的长度为1。

如下代码可以查看一下第一张图片:

for image, label in test_image_ds.take(2):
    plt.imshow(image)

显示为:

9、设置数据集的相关属性等操作。训练时,每次从数据集中读取一批(即32条数据)。必须对训练数据集做shuffle(乱序)操作。

BATCH_SIZE = 32
train_count = len(train_image_path)
test_count = len(test_image_path)
train_image_ds = train_image_ds.shuffle(train_count).repeat().batch(BATCH_SIZE)
test_image_ds = test_image_ds.repeat().batch(BATCH_SIZE)

10、迁移学习需要使用已有的模型的参数,那么模型参数从何而来,当然是从网上下载。从网上下载vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5文件,放到本机/home/haha/.keras/datasets目录中。该文件就是vgg16卷集神经网络的权重文件。然后以下代码就是读取该文件。

tf.keras.datasets.mnist.load_data() #该语句的作用是使得程序从本地(/home/wchw/.keras/datasets)读取数据,而不需要从网上下载。

11、获取卷积基。如果省略第9步,那该步骤就需要在线下载权重,现在速度很慢。使用的权重为在别人在imagenet数据集上训练好的权重。include_top = False表示只使用卷积基,而不使用全连接部分。因此,我需要自己训练全连接层的权重。我为什么选择自己训练全连接层,我的理解是卷基层是对特征进行提取,而该特征是cat还是dog,这就需要自己构建全连接层,用我自己的数据集进行训练得出的模型进行判断。

#weights='imagenet'表示使用在imagenet上训练好的权重
#include_top = False表示只使用卷积基,而不使用全连接部分
covn_base = keras.applications.VGG16(weights='imagenet', include_top = False)

12、执行covn_base.summary()可以查看该模型的信息。下面是最后的几部分:

13、下面构建模型。model.add(covn_base)表示使用已有的卷积部分(即迁移学习的核心),后面的就是我自己构建的全连接层部分。

model = keras.Sequential()
model.add(covn_base)
model.add(layers.GlobalAveragePooling2D())
model.add(layers.Dense(512, activation = 'relu'))
model.add(layers.Dense(1, activation = 'sigmoid'))

执行model.summary(),可查看该模型,如下:

问题来了,为什么Total params: 14,977,857。Trainable params: 14,977,857。因为我还需要进行其他的设置,看下一步。

14、设置卷积部分不可训练,也就是使用卷积部分现有的权重。

covn_base.trainable = False

执行model.summary()

可发现:Total params: 14,977,857。Trainable params: 263,169。Non-trainable params: 14,714,688。这是希望看到的。

15、编译模型。

model.compile(optimizer=keras.optimizers.Adam(lr=0.0005),
             loss = 'binary_crossentropy',
              metrics = ['acc']
             )

16、训练模型。

history = model.fit(
    train_image_ds,
    steps_per_epoch=train_count//BATCH_SIZE,
    epochs=15,
    validation_data=test_image_ds,
    validation_steps=test_count//BATCH_SIZE
)

部分结果如下:

 

 

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值