最近学习了TensorFlow,发现一个模型叫vgg16,然后搭建环境跑了一下,觉得十分神奇,而且准确率十分的高。又上了一节选修课,关于人工智能,老师让做一个关于人工智能的试验,于是觉得vgg16很不错,可以直接用。

但发现vgg16是训练好的模型,拿来直接用太没水平,于是网上发现说可以用vgg16进行迁移学习。

我理解的迁移学习:

迁移学习符合人们学习的过程,如果要学习一样新东西,我们肯定会运用或是借鉴之前的学习经验,这样能够快速的把握要点,能够快速的学习。迁移学习也是如此。

vgg16模型是前人训练出的能够识别1000种物品的模型,而且识别率很高,它的模型如图:

可以数出绿色的模块一共有16层,通过多层的卷积和池化,会提取图片特征值,然后把图片压缩成一个一维数组输入到全连接层中,图中有三层全连接层fc1,fc2,fc3,再经过softmax输出概率分布的预测结果。

进过试验,这个模型能够很好的识别花,但是如果要在此基础上识别多种花,还需要在此基础上进行训练,但是训练的过程将简化很多。接下来通过代码来讲解

项目:

Transfer_learning:

--checkpoint    #用来保存模型

--   #自动生成的四个文件

--flower_photos   #图片

--daisy

  --dandeline

  --roses

  --sunflowers

  --tulips

#vgg16模型

--utils.py

--vgg16.npy

--vgg16.py

--app.py

--ftrain.py

--get_features.py

--transfer_test.py

--transfer_train.py

--codes.npy #存储图片特征值

--labels #存储图片的标签

--1.jpg  #检测图片

--.......

第一步获取图片的特征,对于vgg16模型,fc1层之前所做的就是提取图片特征,我们无需再费事去训练模型去提取图片的特征,而是直接使用它提供的完善的模型去提取特征,并且它能够很好的把握图片的特征,然后它这些特征存储起来,用于下面的训练。

get_features.py

#coding=utf-8
import os
import numpy as np
import tensorflow as tf
import vgg16
import utils #接下来我们将 flower_photos 文件夹中的花朵图片都载入到进来,并且用图片所在的子文件夹作为标签值。
data_dir = 'flower_photos/'
contents = os.listdir(data_dir)
classes = [each for each in contents if os.path.isdir(data_dir + each)] #利用vgg16计算得到特征值
# 首先设置计算batch的值,如果运算平台的内存越大,这个值可以设置得越高
batch_size = 10
# 用codes_list来存储特征值
codes_list = []
# 用labels来存储花的类别
labels = []
# batch数组用来临时存储图片数据
batch = [] codes = None with tf.Session() as sess:
# 构建VGG16模型对象
vgg = vgg16.Vgg16()
input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])
with tf.name_scope("content_vgg"):
# 载入VGG16模型
vgg.build(input_) # 对每个不同种类的花分别用VGG16计算特征值
for each in classes:
print ("Starting {} images".format(each))
class_path = data_dir + each
files = os.listdir(class_path)
for ii, file in enumerate(files, 1):
# 载入图片并放入batch数组中
img = utils.load_image(os.path.join(class_path, file))
batch.append(img.reshape((1, 224, 224, 3)))
labels.append(each) # 如果图片数量到了batch_size则开始具体的运算
if ii % batch_size == 0 or ii == len(files):
images = np.concatenate(batch) feed_dict = {input_: images}
# 计算特征值
codes_batch = sess.run(vgg.relu6, feed_dict=feed_dict) # 将结果放入到codes数组中
if codes is None:
codes = codes_batch
else:
codes = np.concatenate((codes, codes_batch)) # 清空数组准备下一个batch的计算
batch = []
print ('{} images processed'.format(ii))
#code is a two-dimensional array including features of all pictures
#这样我们就可以得到一个 codes 数组,和一个 labels 数组,分别存储了所有花朵的特征值和类别。
#可以用如下的代码将这两个数组保存到硬盘上:
#with open('codes', 'w') as f:
np.save("codes.npy",codes)
#codes.tofile(f)
#not good size of file is too big
#pickle.dump(codes,f) import csv
with open('labels', 'w') as f:
writer = csv.writer(f, delimiter='\n')
writer.writerow(labels)
#pickle.dump(labels,f)

进过上面代码我们已经得到了图片的特征值和标签,接下来,我们需要设置一个全连接层来训练,下面代码中增加了一层256个节点和5个节点的全连接层。

ftrain.py

#coding=utf-8
import os
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelBinarizer
import vgg16
import utils
from sklearn.model_selection import StratifiedShuffleSplit #模型保存的路径和名称
MODEL_SAVE_PATH="./checkpoints/"
MODEL_NAME="flowers.ckpt"
LABELS = "labels"
CODES = "codes.npy"
codes = None
label = []
labels = [] if CODES:
codes = np.load(CODES)
else:
print ("No such file,please run get_feature.py first") if LABELS:
with open(LABELS,"r") as f:
label = f.readlines()
for line in label:
line = line.strip()
labels.append(line)
else:
print ("No such file,please run get_feature.py first")
#准备训练集,验证集和测试集
#首先我把 labels 数组中的分类标签用 One Hot Encode 的方式替换
lb = LabelBinarizer()
lb.fit(labels)
labels_vecs = lb.transform(labels)
#return codes,labels,labels_vecs '''
接下来就是抽取数据,因为不同类型的花的数据数量并不是完全一样的,
而且 labels 数组中的数据也还没有被打乱,
所以最合适的方法是使用 StratifiedShuffleSplit 方法来进行分层随机划分。
假设我们使用训练集:验证集:测试集 = 8:1:1,那么代码如下:
'''
ss = StratifiedShuffleSplit(n_splits=1, test_size=0.2) train_idx, val_idx = next(ss.split(codes, labels)) half_val_len = int(len(val_idx)/2)
val_idx, test_idx = val_idx[:half_val_len], val_idx[half_val_len:] train_x, train_y = codes[train_idx], labels_vecs[train_idx]
val_x, val_y = codes[val_idx], labels_vecs[val_idx]
test_x, test_y = codes[test_idx], labels_vecs[test_idx] print ("Train shapes (x, y):", train_x.shape, train_y.shape)
print ("Validation shapes (x, y):", val_x.shape, val_y.shape)
print ("Test shapes (x, y):", test_x.shape, test_y.shape) #训练网络
'''
分好了数据集之后,就可以开始对数据集进行训练了,
假设我们使用一个 256 维的全连接层,
一个 5 维的全连接层(因为我们要分类五种不同类的花朵),
和一个 softmax 层。当然,这里的网络结构可以任意修改,
你可以不断尝试其他的结构以找到合适的结构。
'''
# 输入数据的维度 # 标签数据的维度
labels_ = tf.placeholder(tf.int64, shape=[None, labels_vecs.shape[1]])
inputs_ = tf.placeholder(tf.float32, shape=[None, codes.shape[1]])
# 加入一个256维的全连接的层 fc = tf.contrib.layers.fully_connected(inputs_, 256) # 加入一个5维的全连接层
logits = tf.contrib.layers.fully_connected(fc, labels_vecs.shape[1], activation_fn=None) # 得到最后的预测分布
predicted = tf.nn.softmax(logits) # 计算cross entropy值
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=labels_, logits=logits) # 计算损失函数
cost = tf.reduce_mean(cross_entropy) # 采用用得最广泛的AdamOptimizer优化器
optimizer = tf.train.AdamOptimizer().minimize(cost)
correct_pred = tf.equal(tf.argmax(predicted, 1), tf.argmax(labels_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) #为了方便把数据分成一个个 batch 以降低内存的使用,还可以再用一个函数专门用来生成 batch。
def get_batches(x, y, n_batches=10):
""" 这是一个生成器函数,按照n_batches的大小将数据划分了小块 """
batch_size = len(x)//n_batches for ii in range(0, n_batches*batch_size, batch_size):
# 如果不是最后一个batch,那么这个batch中应该有batch_size个数据
if ii != (n_batches-1)*batch_size:
X, Y = x[ii: ii+batch_size], y[ii: ii+batch_size]
# 否则的话,那剩余的不够batch_size的数据都凑入到一个batch中
else:
X, Y = x[ii:], y[ii:]
# 生成器语法,返回X和Y
yield X, Y

经过上面的代码,已经把图片集分成三部分,而且也设置好全连接成,接下来需要把图片特征喂入,开始训练模型。

transfer_train.py

import os
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import vgg16
import utils
import ftrain #运行
# 运行多少轮次
epochs = 20
# 统计训练效果的频率
iteration = 0
# 保存模型的保存器
saver = tf.train.Saver() with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
coord = tf.train.Coordinator()#
threads = tf.train.start_queue_runners(sess=sess, coord=coord)# for e in range(epochs):
for x, y in ftrain.get_batches(ftrain.train_x, ftrain.train_y):
feed = {ftrain.inputs_: x,
ftrain.labels_: y}
# 训练模型 loss, _ = sess.run([ftrain.cost, ftrain.optimizer], feed_dict=feed)
print ("Epoch: {}/{}".format(e+1, epochs),
"Iteration: {}".format(iteration),
"Training loss: {:.5f}".format(loss))
iteration += 1 if iteration % 5 == 0:
feed = {ftrain.inputs_: ftrain.val_x,
ftrain.labels_: ftrain.val_y} val_acc = sess.run(ftrain.accuracy, feed_dict=feed)
# 输出用验证机验证训练进度
print ("Epoch: {}/{}".format(e, epochs),
"Iteration: {}".format(iteration),
"Validation Acc: {:.4f}".format(val_acc))
# 保存模型
saver.save(sess, os.path.join(ftrain.MODEL_SAVE_PATH, ftrain.MODEL_NAME))

在控制台的输出结果中,我们可以看到随着迭代次数的增加,损失值在不断的降低,精确性也在提高。把训练好的模型保存起来,接下来用测试集来测试模型。

transfer_test.py

#coding=utf-8
import os
import numpy as np
import tensorflow as tf
import ftrain
import vgg16
import utils #用测试集来测试模型效果
saver = tf.train.Saver()
with tf.Session() as sess:
saver.restore(sess,tf.train.latest_checkpoint(ftrain.MODEL_SAVE_PATH))
feed = {ftrain.inputs_: ftrain.test_x,
ftrain.labels_: ftrain.test_y}
test_acc = sess.run(ftrain.accuracy,feed_dict=feed)
print ("Test accuracy: {:.4f}".format(test_acc))

测试代码,加载训练好的模型,然后把测试集代码喂入,计算精确度,控制台可以看到结果,我的结果达到90%以上

然后可以应用这个模型,来识别图片了,这个模型可以识别5中话,可以自己增加。

app.py

#coding=utf-8
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import vgg16
import utils
import ftrain def per_picture():
#deal with picture
testPicArr = []
img_path = input('Input the path and image name:')
img_ready = utils.load_image(img_path)
testPicArr.append(img_ready.reshape((1,224,224,3)))
images = np.concatenate(testPicArr)
return images labels_vecs = ['daisy','dandelion','roses','sunflower','tulips']
labels_vecs = np.array(labels_vecs)
fig=plt.figure(u"Top-5 预测结果") saver = tf.train.Saver()
with tf.Session() as sess:
#图片预处理
images = per_picture()
#输入vgg16中计算特征值
vgg = vgg16.Vgg16()
input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])
with tf.name_scope("content_vgg"):
# 载入VGG16模型
vgg.build(input_)
feed_dict = {input_: images}
# 计算特征值
codes_batch = sess.run(vgg.relu6, feed_dict=feed_dict)
#返回y矩阵中最大值的下标,如果是二维的加1
preValue = tf.argmax(ftrain.predicted, 1)
#加载训练好的新模型
saver.restore(sess, tf.train.latest_checkpoint(ftrain.MODEL_SAVE_PATH))
#计算预测值
preValue = sess.run(preValue, feed_dict={ftrain.inputs_:codes_batch})
print ("The prediction flower is:", labels_vecs[preValue])
probability = sess.run(ftrain.predicted, feed_dict={ftrain.inputs_:codes_batch})
top5 = np.argsort(probability[0])
print ("top5:",top5)
values = []
bar_label = []
for n, i in enumerate(top5):
print ("n:",n)
print ("i:",i)
values.append(probability[0][i])
bar_label.append(labels_vecs[i])
print (i, ":", labels_vecs[i], "----", utils.percent(probability[0][i]))
ax = fig.add_subplot(111)
ax.bar(range(len(values)), values, tick_label=bar_label, width=0.5, fc='g')
ax.set_ylabel(u'probabilityit')
ax.set_title(u'Top-5')
for a,b in zip(range(len(values)), values):
ax.text(a, b+0.0005, utils.percent(b), ha='center', va = 'bottom', fontsize=7)
plt.show()

上面代码过程是,首先要通过vgg16提取该图片的特征值,然后进行图片预处理,加载训练好的模型,输入进去,获得结果。

结果展示如下:

       

可以看到准确率很高,我每种图片只训练了144张,数据集有800多张。

以上代码可以在windows 下python3的环境运行。

代码和数据集参考自:https://cosx.org/2017/10/transfer-learning/

对于实现以上过程遇到的问题:

(1)首先对迁移学习的理解

  对于这个简单的试验,迁移学习主要体现在使用训练好的vgg16模型(存储在vgg16.npy中)提取图片的特征值,然后再对这些特征值训练。

(2)模型的保存和加载

  为了避免反复的去提取图片特征值(这个很耗时间),把特征值保存在codes.npy,把图片的标签存储在labels中。还有就是存储训练模型,这里因为对TensorFlow模型不太了解,所以出一个问题

存储模型后,在另一个文件中加载模型发现训练的模型和没训练的模型一样

  原因是因为在另一个文件中使用的不是同一个saver,我又对saver进行了初始化,导致使用了一个崭新的模型。

(3)模型保存优化部分:

  如果你不给tf.train.Saver()传入任何参数,那么saver将处理graph中的所有变量。其中每一个变量都以变量创建时传入的名称被保存。

有时候在检查点文件中明确定义变量的名称很有用。举个例子,你也许已经训练得到了一个模型,其中有个变量命名为"weights",你想把它的值恢复到一个新的变量"params"中。

有时候仅保存和恢复模型的一部分变量很有用。再举个例子,你也许训练得到了一个5层神经网络,现在想训练一个6层的新模型,可以将之前5层模型的参数导入到新模型的前5层中。

你可以通过给tf.train.Saver()构造函数传入Python字典,很容易地定义需要保持的变量及对应名称:键对应使用的名称,值对应被管理的变量。

增加:

对于代码中数据集增加,代码会报错,这里有同学发现了解决办法

TensorFlow迁移学习的识别花试验的更多相关文章

  1. 基于深度学习和迁移学习的识花实践——利用 VGG16 的深度网络结构中的五轮卷积网络层和池化层,对每张图片得到一个 4096 维的特征向量,然后我们直接用这个特征向量替代原来的图片,再加若干层全连接的神经网络,对花朵数据集进行训练(属于模型迁移)

    基于深度学习和迁移学习的识花实践(转)   深度学习是人工智能领域近年来最火热的话题之一,但是对于个人来说,以往想要玩转深度学习除了要具备高超的编程技巧,还需要有海量的数据和强劲的硬件.不过 Tens ...

  2. Google Tensorflow 迁移学习 Inception-v3

    附上代码加数据地址 https://github.com/Liuyubao/transfer-learning ,欢迎参考. 一.Inception-V3模型 1.1 详细了解模型可参考以下论文: [ ...

  3. 用tensorflow迁移学习猫狗分类

    笔者这几天在跟着莫烦学习TensorFlow,正好到迁移学习(至于什么是迁移学习,看这篇),莫烦老师做的是预测猫和老虎尺寸大小的学习.作为一个有为的学生,笔者当然不能再预测猫啊狗啊的大小啦,正好之前正 ...

  4. ML.NET 示例:图像分类模型训练-首选API(基于原生TensorFlow迁移学习)

    ML.NET 版本 API 类型 状态 应用程序类型 数据类型 场景 机器学习任务 算法 Microsoft.ML 1.5.0 动态API 最新 控制台应用程序和Web应用程序 图片文件 图像分类 基 ...

  5. 用tensorlayer导入Slim模型迁移学习

    上一篇博客[用tensorflow迁移学习猫狗分类]笔者讲到用tensorlayer的[VGG16模型]迁移学习图像分类,那麽问题来了,tensorlayer没提供的模型怎么办呢?别担心,tensor ...

  6. TensorFlow从1到2(九)迁移学习

    迁移学习基本概念 迁移学习是这两年比较火的一个话题,主要原因是在当前的机器学习中,样本数据的获取是成本最高的一块.而迁移学习可以有效的把原有的学习经验(对于模型就是模型本身及其训练好的权重值)带入到新 ...

  7. 『TensorFlow』迁移学习

    完全版见github:TransforLearning 零.迁移学习 将一个领域的已经成熟的知识应用到其他的场景中称为迁移学习.用神经网络的角度来表述,就是一层层网络中每个节点的权重从一个训练好的网络 ...

  8. 深度学习应用系列(二) | 如何使用keras进行迁移学习,以训练和识别自己的图片集

    本文的keras后台为tensorflow,介绍如何利用预编译的模型进行迁移学习,以训练和识别自己的图片集. 官网 https://keras.io/applications/ 已经介绍了各个基于Im ...

  9. tensorflow实现迁移学习

    此例程出自<TensorFlow实战Google深度学习框架>6.5.2小节 卷积神经网络迁移学习. 数据集来自http://download.tensorflow.org/example ...

随机推荐

  1. JHipster技术栈定制 - JHipster Registry配置信息加密

    本文说明了如何开启和使用JHipster-Registry的加解密功能. 1 整体规划 1.1 名词说明 名词 说明 备注 对称加密 最快速.最简单的一种加密方式,加密(encryption)与解密( ...

  2. Sql Server 获取本周周一

    SELECT DATEADD(Day,(@i+1)-(DATEPART(Weekday,getdate())+@@DATEFIRST-1)%7,getdate())

  3. c/c++ llinux epoll系列4 利用epoll_wait实现非阻塞的connect

    llinux epoll系列4 利用epoll_wait实现非阻塞的connect connect函数是阻塞的,而且不能设置connect函数的timeout时间,所以一旦阻塞太长时间,影响用户的体验 ...

  4. Windows 下安装drozer(Windows 10),连接手机(红米note4X)

    Windows 下安装drozer(Windows 10),连接手机(红米note4X) 首先下载drozer(http://mwr.to/drozer). 红米手机开发者模式 遇到第一个问题,红米手 ...

  5. Ubuntu系统分配存储空间的建议以及给Ubuntu系统根目录扩容方法(从20GB追加100GB)

    当初准备装双系统时,也思考了很久分配多少空间给Ubuntu16.04系统,查了许多资料,大多意思是‘/’目录总共给20GB,其他的给/home.网上资料推荐的大多跟这篇文章一样:https://blo ...

  6. 播放器的书签--推荐使用Potplayer

    VLC Player https://www.vlchelp.com/skipping-and-playing-audio-and-video-portions-in-vlc/ PotPlayer  ...

  7. Think_in_java_4th(并发学习一)

    Java的并发是在顺序语言的基础上提供对线程的支持的. 并发能够更加有效的执行我们的代码,也就是更加合理的应用CPU资源. 并发程序往往CPU和内存使用率,要高于同等的非并发程序. 下面就用Think ...

  8. ansible学习基础知识和模块(一)

    基础知识补充: 常用自动化运维工具 Ansible:使用python来开发的,无需设置Agentless(代理),一般管理几百台.与ssh的方式也不一样,ssh是基于c/s模式(客户端+服务器)来使用 ...

  9. adb.exe 安卓测试桥的使用

    一.android SDK提供了几个工具 (在SDK下build-tools目录下的工具) dx.bat ----------->把java编译器编译生成的.class 文件 ,变成一个文件,让 ...

  10. SpringBoot四大核心

    auto-configuration.starters.cli.actuator