前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文上手最新TensorFlow2.0系列(二)

一文上手最新TensorFlow2.0系列(二)

作者头像
磐创AI
发布2019-08-20 13:06:33
2.1K0
发布2019-08-20 13:06:33
举报

编辑 | 安可

出品 | 磐创AI技术团队

【磐创AI导读】:本系列文章介绍了与tensorflow的相关知识,包括其介绍、安装及使用等。本篇文章将接着上篇文章继续介绍它的安装及部分使用。查看上篇:文末福利|一文上手TensorFlow2.0(一)。想要获取更多的机器学习、深度学习资源,欢迎大家点击上方蓝字关注我们的公众号:磐创AI。

系列文章目录:

  • Tensorflow2.0 介绍
    • Tensorflow 常见基本概念
    • 从1.x 到2.0 的变化
    • Tensorflow2.0 的架构

  • Tensorflow2.0 的安装(CPU和GPU)
  • Tensorflow2.0 使用
    • “tf.data” API
    • “tf.keras”API

  • 使用GPU加速
    • 安装配置GPU环境
    • 使用Tensorflow-GPU

2. TensorFlow2.0安装

Tensorflow兼容性最好的是Unix内核的系统,如Linux,MacOS等。另外TensorFlow的GPU版本仅支持Linux环境,不支持Windows和Mac环境,因此本节的安装部分仅针对Linux系统环境。我们会统一使用Anaconda,在Mac和Windows下安装的过程也较为简单,读者可以自行参考其官方文档。Anaconda官网有各个平台详细的安装使用教程:https://docs.anaconda.com/anaconda/install/。

作者使用的开发环境如下:

1. 安装Anaconda

我们打算使用python3.6,因此我们下载Anaconda5.2.0版本,该版本对应的python版本是3.6.5,为了下载的更快一点,我们从清华大学的镜像站下载:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/?C=N&O=D,下载“Anaconda3-5.2.0-Linux-x86_64.sh”文件。

(1)安装Anaconda

1. 执行“bashAnaconda3-5.2.0-Linux-x86_64.sh”,提示需要阅读licenses,按下回车继续,如图1所示。

图1 安装Anaconda

2. 出现提示是否接受licenses,输入“yes”回车。提示Anaconda将要安装的位置,回车确认。

图2

3.提示是否要写入配置文件,输入“yes”回车。

图3

4.提示是否安装“VSCode”,输入“no”回车。安装完成。

图4

如图5所示,安装好后我们键入“python3”,此时运行的还是系统自带的python版本,我们执行“source ~/.bashrc”让配置生效,此时在执行“python3”,运行的就是Anaconda。

图5

(2)创建虚拟环境

接下来我们在Anaconda中创建一个虚拟Python环境,终端中执行如下命令:

conda create --name apython python=3.6

接着出现提示是否继续,输入“y”回车,稍等片刻一个Python3.6的虚拟环境就创建好了。此时系统中有多个版本的Python,为了方便使用,我们配置一下环境变量,为每个版本的Python设置一个别名。另外为了后面方便使用“pip”来管理虚拟环境的包,我们为虚拟环境的“pip”命令也创建一个别名。 编辑“~/.bashrc”文件,在文件末尾增加如下内容:

alias python="/usr/bin/python2"
alias python3="/usr/bin/python3"
alias apython="/home/lqhou/anaconda3/envs/apython/bin/python3"
alias apip="/home/lqhou/anaconda3/envs/apython/bin/pip"

注意Anaconda的路径要根据实际情况来填写,“/home/lqhou/anaconda3”为作者系统上Anaconda的安装路径。配置完成后键入“source ~/.bashrc”让配置生效,之后我们分别执行“python”、“python3”和“apython”命令,如图6所示:

图6 测试别名

这里python和python3命名指向的都是系统自带的python版本,apython命令指向的是我们刚刚创建的python虚拟环境。这里需要注意,当我们要使用“pip”命令为我们创建的python虚拟环境安装包时,需要使用这里我们配置的“apip”命令,直接使用pip或pip3命令,会把包安装到系统自带的python环境中。

2. 安装TensorFlow

GPU版的TensorFlow包含了CPU版本,如果读者手上有GPU资源的话,可以直接参考后文会提到的安装GPU版的TensorFlow。

我们可以直接使用“pip installtensorflow==2.0.0-alpha0”命令来进行安装。由于作者使用的pip源还没有加入“TensorFlow2.0.0-alpha0”版本,所以这里我们直接到“PyPi”网站下载TensorFlow2.0 Alpha版的安装包。进入网址:https://pypi.org/project/tensorflow/2.0.0a0/#files,部分安装包如图7所示:

图7 TensorFlow2.0 Alpha版安装包列表

这里我们需要根据实际的Python版本和操作系统环境来下载相应的安装包,这里作者的python版本是python3.6.8,操作系统是64位的Ubuntu16.04。因此作者下载的是“tensorflow-2.0.0a0-cp36-cp36m-manylinux1_x86_64.whl”。

下载完成后,我们执行如下命令进行安装。

apip install tensorflow-2.0.0a0-cp36-cp36m-manylinux1_x86_64.whl

安装完成后,我们进入python的交互式解释器环境验证安装是否成功,如图8所示:

图8 测试TensorFlow2.0 Alpha是否安装成功

3. 使用Jupyter Notebook

JupyterNotebook是一个开源的Web应用程序,常被用于交互式的开发和展示一些数据科学项目(例如数据清洗和转换、数据可视化以及机器学习等等)。在本章中为了方便大家学习,我们会使用Jupyter NoteBook作为我们的编程环境(读者也可以使用Google的Colab:https://colab.research.google.com

),后面章节的项目和代码,读者可以任意选择自己喜欢的编程工具。

在我们安装好Anaconda后,Anaconda集成了Jupyter NoteBook,因此我们可以直接使用,如图9所示。

图9 Anaconda界面

我们直接点击Jupyter下方的“运行”即可启动Jupyter(也可以在终端中输入“jupyter-notebook”来启动),启动之后会自动打开一个WEB页面,如图10所示。这里列出了默认路径下的所有目录和文件,我们可以打开自己存放代码的目录。

图10 Jupyter Notebook启动之后打开的WEB界面

如图11所示,点击页面右上角的“new”菜单,再点击“python[conda env:apython3]”菜单之后就会创建一个新的后缀名为“ipynb”的notebook文件。读者的“new”菜单中可能只有一个“Python”kernel,而没有另外两个Anaconda的python环境的kenel。这里读者可以在命令行下执行命令“source activate apython3”进入我们之前创建的“apython3”虚拟环境,然后再执行命令“jupyter-notebook”命令启动Jupyter,这时我们在“new”菜单下就可以看到我们需要使用的kernel了。

图11 创建一个新的notebook文件

新创建的notebook文件会自动的在新的标签页打开,如图12所示,新创建的是一个空的notebook文件。

图12 打开后的notebook文件

如图13所示,我们在notebook的单元格内输入代码,点击“Run”之后会在单元格的下方显示代码运行的结果。

图13 在notebook文件中编写代码

3 TensorFlow2.0使用

3.1 “tf.data”API

除了GPU和TPU等硬件加速设备以外,一个高效的数据输入管道也可以很大程度的提升模型性能,减少模型训练所需要的时间。数据输入管道本质是一个ELT(Extract、Transform和Load)过程:

  • Extract:从硬盘中读取数据(可以是本地的也可以是云端的)。
  • Transform:数据的预处理(例如数据清洗、格式转换等)。
  • Load:将处理好的数据加载到计算设备(例如CPU、GPU以及TPU等)。

数据输入管道一般使用CPU来执行ELT过程,GPU等其他硬件加速设备则负责模型的训练,ELT过程和模型的训练并行执行,从而提高模型训练的效率。另外ELT过程的各个步骤也都可以进行相应的优化,例如并行的读取数据以及并行的处理数据等。在TensorFlow中我们可以使用“tf.data”API来构建这样的数据输入管道。

我们首先下载接下来的实验中需要用的图像数据集(数据集的下载地址为“https://storage.googleapis.com/download.tensorflow.org/example_images/”,由于该地址需要访问外国网站后才能访问,本书作者已经将下载好的数据集上传到百度云网盘,下载地址为“https://pan.baidu.com/s/16fvNOBvKyGVa8yCB5mDUOQ”。)

该数据集是一个花朵图片的数据集,将下载下来的数据解压后如图2-15所示,除了一个License文件以外主要是五个分别存放着对应类别花朵图片的文件夹。其中“daisy(雏菊)”文件夹中有633张图片,“dandelion(蒲公英)”文件夹中有898张图片,“roses(玫瑰)”文件夹中有641张图片,“sunflowers(向日葵)”文件夹中有699张图片,“tulips(郁金香)”文件夹中有799张图片。

图14 解压后的数据集

接下来我们开始实现代码,首先我们导入需要使用的包:

import tensorflow as tf
import pathlib

pathlib提供了一组用于处理文件系统路径的类。导入需要的包后,可以先检查一下TensorFlow的版本:

print(tf.__version__)

首先获取所有图片样本文件的路径:

# 获取当前路径
data_root = pathlib.Path.cwd()
# 获取指定目录下的文件路径(返回是一个列表,每一个元素是一个PosixPath对象)
all_image_paths = list(data_root.glob('*/*/*'))
print(type(all_image_paths[0]))
# 将PosixPath对象转为字符串
all_image_paths = [str(path) for path in all_image_paths]
print(all_image_paths[0])
print(data_root)

输出结果如图15所示:

图15 文件路径输出结果

接下来我们需要统计图片的类别,并给每一个类别分配一个类标:

# 获取图片类别的名称,即存放样本图片的五个文件夹的名称
label_names = sorted(item.name for item in data_root.glob('*/*/') if item.is_dir())
# 将类别名称转为数值型的类标
label_to_index = dict((name, index) for index, name in enumerate(label_names))
# 获取所有图片的类标
all_image_labels = [label_to_index[pathlib.Path(path).parent.name]

print(label_to_index)
print("First 10 labels indices: ", all_image_labels[:2])
print("First 10 labels indices: ", all_image_paths[:2])

输出结果如图16所示,daisy(雏菊)、dandelion(蒲公英)、roses(玫瑰)、sunflowers(向日葵)、tulips(郁金香)的类标分别为0、1、2、3、4、5。

图16 图片类标的输出结果

处理完类标之后,我们接下来需要对图片本身做一些处理,这里我们定义一个函数用来加载和预处理图片数据:

def load_and_preprocess_image(path):
 # 读取图片
 image = tf.io.read_file(path)
 # 将jpeg格式的图片解码,得到一个张量(三维的矩阵)
 image = tf.image.decode_jpeg(image, channels=3)
 # 由于数据集中每张图片的大小不一样,统一调整为192*192
 image = tf.image.resize(image, [192, 192])
 # 对每个像素点的RGB值做归一化处理
 image /= 255.0
 
 return image

完成对类标和图像数据的预处理之后,我们使用“tf.data.Dataset”来构建和管理数据集:

# 构建图片路径的“dataset”
path_ds = tf.data.Dataset.from_tensor_slices(all_image_paths)
# 使用AUTOTUNE自动调节管道参数
AUTOTUNE = tf.data.experimental.AUTOTUNE
# 构建图片数据的“dataset”
image_ds = path_ds.map(load_and_preprocess_image,
num_parallel_calls=AUTOTUNE)
# 构建类标数据的“dataset”
label_ds = tf.data.Dataset.from_tensor_slices(tf.cast(all_image_labels, tf.int64))
# 将图片和类标压缩为(图片,类标)对
image_label_ds = tf.data.Dataset.zip((image_ds, label_ds))

print(image_ds)
print(label_ds)
print(image_label_ds)

输出结果如图17所示:

图17 构建的“dataset”

在代码中,我们使用了“from_tensor_slices”方法使用张量的切片元素构建“dataset”,“tf.data.Dataset”类还提供了“from_tensor”直接使用单个张量来构建“dataset”,以及可以使用生成器生成的元素来构建“dataset”的“from_generator”方法。

我们使用了“tf.data.Dataset”的“map”方法,该方法允许我们自己定义一个函数,将原数据集中的元素依次经过该函数处理,并将处理后的数据作为新的数据集,处理前和处理后的数据顺序不变。例如这里我们自己定义了一个“load_and_preprocess_image”函数,将“path_ds”中的图片路径转换成了经过预处理的图像数据,并保存在了“image_ds”中。

最后我们使用“tf.data.Dataset”的“zip”方法将图片数据和类标数据压缩成“(图片,类标)”对,其结构如图17所示。我们可视化一下数据集中的部分数据:

import matplotlib.pyplot as plt

plt.figure(figsize=(8,8))
for n,image_label in enumerate(image_label_ds.take(4)):
 plt.subplot(2,2,n+1)
 plt.imshow(image_label[0])
 plt.grid(False)
 plt.xticks([])
 plt.yticks([])
 plt.xlabel(image_label[1])

结果如图18所示:

图18 数据集中部分数据的可视化

接下来我们用创建的dataset训练一个分类模型,这个例子的目的是让读者了解如何使用我们创建的dataset,为了简单,我们直接使用“tf.keras.applications”包中训练好的模型,并将其迁移到我们的花朵分类任务上来。这里我们使用“MobileNetV2”模型。

# 下载的模型在用户根目录下,具体位置:“~/.keras/models/
mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_192_no_top.h5”
mobile_net = tf.keras.applications.MobileNetV2(input_shape=(192, 192, 3),
include_top=False)
# 禁止训练更新“MobileNetV2”模型的参数
mobile_net.trainable = False

当我们执行代码后,训练好的“MobileNetV2”模型会被下载到本地,该模型是在ImageNet数据集上训练的。因为我们是想把该训练好的模型迁移到我们的花朵分类问题中来,所以代码我们设置该模型的参数不可训练和更新。

接下来我们打乱一下数据集,以及定义好训练过程中每个“batch”的大小。

# 使用Dataset类的shuffle方法打乱数据集
image_count = len(all_image_paths)
ds = image_label_ds.shuffle(buffer_size=image_count)
# 让数据集重复多次
ds = ds.repeat()
# 设置每个batch的大小
BATCH_SIZE = 32
ds = ds.batch(BATCH_SIZE)
# 通过“prefetch”方法让模型的训练和每个batch数据集的加载并行
ds = ds.prefetch(buffer_size=AUTOTUNE)

在代码中,我们使用“tf.data.Dataset”类的“shuffle”方法将数据集进行打乱。代码使用“repeat”方法让数据集可以重复获取,通常情况下如果我们一个“epoch”只对完整的数据集训练一遍的话,可以不需要设置“repeat”。“repeat”方法可以设置参数,例如“ds.repeat(2)”是让数据集可以重复获取两遍,即一个训练回合(epoch)中我们可以使用两遍数据集,不加参数的话,则默认可以无限次重复获取数据集。

代码里我们设置了训练过程中一个“batch”的大小。我们使用“tf.data.Dataset.prefetch”方法让ELT过程的 “数据准备(EL)”和“数据消耗(T)”过程并行。

由于“MobileNetV2”模型接收的输入数据是归一化后范围在[-1,1]之间的数据,我们在第31行代码中对数据进行了一次归一化处理后,其范围在[0,1]之间,因此我们需要将我们的数据映射到[-1,1]之间。

# 定义一个函数用来将范围在[0,1]之间的数据映射到[-1,1]之间
def change_range(image,label):
 return 2*image-1, label
# 使用“map”方法对dataset进行处理
keras_ds = ds.map(change_range)

接下来我们定义模型,由于预训练好的“MobileNetV2”返回的数据维度为“(32,6,6,1280)”,其中32是一个“batch”的大小,“6,6”代表输出的特征图的大小为“6X6”,1280代表该层使用了1280个卷积核。为了适应我们的分类任务,我们需要在“MobileNetV2”返回数据的基础上再增加两层网络层。

model = tf.keras.Sequential([
 mobile_net,
 tf.keras.layers.GlobalAveragePooling2D(),
 tf.keras.layers.Dense(len(label_names))])

全局平均池化(GAP,Global Average Pooling)将每一个特征图求平均,将该平均值作为该特征图池化后的结果,因此经过该操作后数据的维度变为了(32,1280)。由于我们的花朵分类任务是一个5分类的任务,因此我们再使用一个全连接(Dense),将维度变为(32,5)。

接着我们编译一下模型,同时指定使用的优化器和损失函数:

model.compile(optimizer=tf.keras.optimizers.Adam(),
 loss='sparse_categorical_crossentropy',
 metrics=["accuracy"])
model.summary()

“model.summary()”可以输出模型各层的参数概况,如图19所示:

图19 模型各层的参数概况

最后我们使用“model.fit”训练模型:

model.fit(ds, epochs=1, steps_per_epoch=10)

这里参数“epochs”指定需要训练的回合数,“steps_per_epoch”代表每个回合要取多少个“batch”数据,通常“steps_per_epoch”的大小等于我们数据集的大小除以“batch”的大小后上取整。关于模型的训练部分,我们在后面中会详细介绍。

在本节中我们简单了解了“tf.data”API的使用,在后面章节的项目实战部分我们还会用到该API来构建数据输入管道,包括图像以及文本数据。

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

本文分享自 磐创AI 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 2. TensorFlow2.0安装
  • 3 TensorFlow2.0使用
  • 3.1 “tf.data”API
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档