文章目录
核心内容
- TensorFlow中的基本概念介绍
- TensorFlow中的核心API
- TensorFlow中的高层接口slim
- TensorFlow的调试技巧
- TensorFlow实现数据增强
- TensorFlow挑战Cifar-10图像分类任务
TensorFlow
Google开源的基于数据流图的科学计算库,适用于机器学习、深度学习等人工智能领域
开源库:https://github.com/tensorflow
相关模型:https://github.com/tensorflow/models
Tensor+Flow=TensorFlow
张量+数据流=TensorFlow
数据是按一定方向流动的,需要一定的计算
Graph
-
图描述了计算的过程,可以通过tensorflow图形化流程结构
- graph是在前端进行的,可用tensorflow来进行可视化
- 声明(单个/多个图)
- 保存为pb文件
- 从pb中恢复Graph
- Tensorboard可视化
input_a,input_b为数据的输入,add_e,maltiply_c为数据的加,乘运算,箭头表示数据的流向
计算图则为网络,网络的参数通过后续的学习得到
import tensorflow as tf
a=tf.constant(1,name='input_a') #张量(常量)
b=tf.constant(2,name='input_b')#张量
c=tf.multiply(a,b,name='multiply_c')#乘运算
d=tf.add(a,b,name='add_d')#加运算
e=tf.add(d,c,name='add_e')
sess=tf.Session()#会话
sess.run(e)
writer=tf.summary.FileWriter('graph',sess.graph)
Session
- 图必须在称之为“会话”的上下文中进行
- 会话将图的op分发到诸如CPU或者GPU之类的设备上执行
session完成了前端和后端的沟通,起到了桥梁的作用
常见操作:
- session的创建和关闭
- session 的注入机制
- 利用session指定不同的设备
- 通过session完成资源分配
创建和关闭会话
import tensorflow as tf
sess=tf.Session()#使用最多,和使用with创建等价
sess=tf.InteractiveSession()#交互式Session,主要用在交互性要求较高的脚本中
with tf.Session() as Sess:
...
sess.close()#session关闭
注入机制
是Session具体完成计算图运算的过程,前端和后端的桥梁,注入数据
sess.run(...)#run 中指定需要计算的节点
sess.run(tf.global_variables_initializer())#tf.global_variables_initializer():获取当前计算图全部变量
a=tf.placeholder(dtype=tf.float32)#定义a和b,是占位符,实际取值是计算时再赋值即feed操作
b=tf.placeholder(dtype=tf.float32)
add=a+b
add_val=sess.run(add,feed_dict={a:1,b:2})#a赋值为1,b赋值为2,最终得到value为3=a+b
指定资源设备
a=tf.placeholder(dtype=tf.float32)
b=tf.placeholder(dtype=tf.float32)
add=a+b
with tf.Session() as sess:
with tf.device("/cpu:0")#指定要运行的计算图所占用的资源设备
print(sess.run(add,feed_dict={a:1,b:2}))
资源分配-控制GPU资源使用率
config=tf.ConfigProto()
config.gpu_options.allow_growth=True#定义gpu参数
session=tf.Session(config=config,...)#利用config进行session的初始化
Tensor
在TensorFlow中,所有在节点之间传递的数据都为Tensor对象
将tensor表示为N维数组,图像:(batch * height * width * channel ):NHWC
Tensor 的定义:
tf.constant()#常量
tf.Variable()#变量
tf.placeholder()#占位符
tf.SparseTensor()#稀疏张量
具体定义:
#常量定义要给定具体的取值,value[1,2]以及当前常量的形状shape(1,2)
#数据类型dtype,可缺省,也可定义
#指定常量的name
#指定常量是否可以改变:verify_shape
cons=tf.constant(value=[1,2],dtype=tf.float32,shape=(1,2),name='testconst',verify_shape=False)
#占位
X=tf.placeholder(dtype=tf.float32,shape=[144,10],name='X')
X=tf.placeholder(dtype=float32,shape=[None,None],name='X')
#变量定义时不需要指定value,但需要shape,以及数据类型dtype和name
#变量即其值可以根据训练过程进行改变
W=tf.Variable(tf.zeros([3,10]),dtype=tf.float64,name='W')
Operation
Tensorflow Graph中的计算节点,输入输出均为Tensor
调用Session.run(tensor)或者tensor.eval()方可获取该Tensor的值
Feed
通过feed为计算图注入值:
注入值通常就是占位符
a=tf.placeholder(tf.float32)
b=tf.placeholder(tf.float32)
c=tf.add(a,b)
with tf.Session() as sess:
result=sess.run(c,feed_dict={a:3,b:4})#这里的c值就是Fecth
print(result)
Fetch
使用Fetch获取计算结果
tf.Session.run(fetches,feed_dict=None)
#fetches可以是单独的参数,也可以是list
范例:
import tensorflow as tf
x=tf.placeholder(tf.float32,shape=(1,2))
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))
a=tf.matmul(x,w1)#矩阵相乘
y=tf.matmul(a,w2)
with tf.Session() as sess:
#变量运行前必须进行初始化操作
init_op=tf.global_variables_initializer()
sess.run(init_op)
print(sess.run(y,feed_dict={x:[[0.7,0.5]]}))#对x赋值,计算y
结果:[[3.0904665]]
Tensorflow中核心API
基本运算
tf.expand_dims(input,dim,name=None)
tf.split(split_dim,num_split,value,name='split')
tf.concat(concat_dim,values,name='concat')
tf.cast()
tf.reshape()
tf.equal()
tf.matmul(a,b)
tf.argmax()#求最大索引值
tf.squeeze()#去掉纬度为1的张量值
搭建网络时常用tf.nn库
tf.nn.conv2d:卷积层
tf.nn.max_pool:池化层
tf.nn.abg_pool:池化层
tf.nn.relu:激活层
tf.nn.dropout:
tf.nn.l2_normalize:归一化层
tf.nn.batch_nomalization:BN层
tf.nn.l2_loss:损失层
tf.nn.softmax_cross_entropy_with_logits:交叉熵损失层
tf.train库:定义了和优化相关的函数
Tensorflow提供了TFRecord的格式来统一存储数据(数据的打包)
- TFRecord将图像数据和标签放在一起的二进制文件(protocol buffer),能更好的利用内存,实现快速的复制,移动,读取,存储
相应的接口函数:
- 数据读取:
tf.train.string_input_producer
- 数据解析:
tf.TFRecordReader,tf.parse_single_example
- 数据写入:
tf.python_io.TFRecordWriter
数据写入相关API方法:
writer=tf.python_io.TFRecordWriter()
example=tf.train.Example()//在tf.train.Example()中存取具体的数据,可以定义一个feature,如图像的宽和高
example=tf.train.Example()//在tf.train.Example()中存取具体的数据,可以定义一个feature,如图像的宽和高
writer.close()
example=tf.train.Example(features=tf.train.Features(feature={
#定义标签和图片,相应的数据类型
'label':tf.train.Feature(int64_list=tf.train.Feature(value=[index])),
'img_raw':tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw]))
}))
范例:读取cifar10数据
在cifar-10-batches-py中,已经是二进制文件,可以用python语言解析,也可以自行下载cifar数据进行解析后变成二进制文件。
官网数据下载:http://www.cs.toronto.edu/~kriz/cifar.html
其中data_batch为训练集,test_batch为测试集。
import urllib
import os
import sys
import tarfile
import glob
import pickle
import numpy as np
import cv2
classification=['airplane',
'automobile',
'bird',
'cat',
'deer',
'dog',
'frog',
'horse',
'ship',
'truck']
#解析函数
def unpickle(file):
import pickle
with open(file, 'rb') as fo:
dict = pickle.load(fo, encoding='bytes')
return dict
folders = '/Users/apple/Downloads/11人脸识别/projects/One/data/cifar-10-batches-py'
trfiles = glob.glob(folders + "/data_batch*")#获取所有文件,训练文件
data = []
labels = []
for file in trfiles:
dict = unpickle(file) #解码之后的数据,以字典的格式
data += list(dict[b"data"])
labels += list(dict[b"labels"])
print(labels)
#图片解析,图片存储
imgs = np.reshape(data,[-1,3,32,32]) #将数据reshape为3 x 32 x 32 ,-1表示为当前有多少图片
for i in range(imgs.shape[0]):
im_data = imgs[i,...]
im_data = np.transpose(im_data,[1,2,0])
im_data = cv2.cvtColor(im_data,cv2.COLOR_RGB2BGR)#数据,转换模式rgb,获取到适用opencv的数据
f="{}/{}".format("data/image/train",classification[labels[i]])#拼接地址,并根据标签找到图片
if not os.path.exists(f):#如果路径不存在
os.mkdir(f)
cv2.imwrite("{}/{}.jpg".format(f,str(i)),im_data)
结果:在项目train文件夹下多了十个文件夹,是cifar10数据集里的图片
TFRecord数据打包
使用tensorflow实现TFRecord图像数据打包,打包成二进制格式讲这些数据用于后续模型的训练
获得所有图片路径及其种类:
import glob
classification=['airplane',
'automobile',
'bird',
'cat',
'deer',
'dog',
'frog',
'horse',
'ship',
'truck']
#按照图片类别进行打包
index = 0 #种类索引
im_data = [] #存储图片路径
im_lables = [] #存储图片种类标签
for path in classification: #遍历种类
path = "/Users/apple/Downloads/11人脸识别/projects/face/data/image/train/" + path
im_list = glob.glob(path + "/*") #获取图片list
im_label = [index for i in range(im_list.__len__())] #获取图片的label,label就是classification对应的值,需要遍历索引号
index +=1
im_data += im_list #将每个种类下对应的图片路径存放在一起
im_lables +=im_label
print(im_lables)
print(im_data)
封装图片数据:
#存储获取到的图片数据
tfrecord_file = "/Users/apple/Downloads/11人脸识别/projects/face/data/image/train.tfrecord"
writer = tf.python_io.TFRecordWriter(tfrecord_file)#传入文件路径
#要将获取到的文件资源写入tfrecord
#获取数据列表
for i in range(im_data.__len__()):
im_d = im_data[i]#获取数据
im_l = im_lables[i]#获取label
#利用opencv函数对图像进行读取
data = cv2.imread(im_d)#传入文件路径
#将数据封装到example中
ex = tf.train.Example(
features = tf.train.Features(
feature = {
#图像数据采用byte格式存储
"image":tf.train.Feature(
bytes_list=tf.train.BytesList(
value=[data.tobytes()])), #value:图片数据转成bytes
"label":tf.train.Feature(
int64_list=tf.train.Int64List(
value=[im_l]))
}
)
)
writer.write(ex.SerializeToString())
writer.close()
在对图片数据进行打包时,要注意图片大小是否一致,cifar10中大小都为32x32x3,
图片大小不一致需对宽高进行定义:
#定义图片大小
"height": tf.train.Feature(
int64_list=tf.train.Int64List(
value=[data.shape[0]])),
"width": tf.train.Feature(
int64_list=tf.train.Int64List(
value=[data.shape[1]]))
打包时可将数据打乱:
index = [i for i in range(im_data.__len__())]
np.random.shuffle(index)
#打包时可以将图片数据打乱
index = [i for i in range(im_data.__len__())]
np.random.shuffle(index)
#获取数据列表
for i in range(im_data.__len__()):
im_d = im_data[index[i]]#获取数据
im_l = im_lables[index[i]]#获取label
#利用opencv函数对图像进行读取
data = cv2.imread(im_d)#传入文件路径
#将数据封装到example中
ex = tf.train.Example(
features = tf.train.Features(
feature = {
#图像数据采用byte格式存储
"image":tf.train.Feature(
bytes_list=tf.train.BytesList(
value=[data.tobytes()])), #value:图片数据转成bytes
"label":tf.train.Feature(
int64_list=tf.train.Int64List(
value=[im_l]))
}
)
)
writer.write(ex.SerializeToString())
writer.close()
读取文件有两种方式:
opencv和tensorflow
data = cv2.imread(im_d)#传入文件路径
data = tf.gfile.FastGFile(im_d,"rb").read()#得到的文件更小,会进行编码,使用时要进行解码
利用tensorflow对图片数据进行读取
利用tf.train.slice_input_producer进行读取
#利用tensorflow对图片数据进行读取
import tensorflow as tf
images = ['image1.jpg','image2.jpg','image3.jpg','image4.jpg']
labels = [1,2,3,4]
#利用tf.train.slice_input_producer进行读取,传入参数为路径和标签
[images,labels] = tf.train.slice_input_producer([images,labels],num_epochs=None,shuffle=True)
#一个epoch表示将所有样本进行一轮循环,None 表示不规定多少个epoch,只要想从文件序列读取数据就有数据
#shuffle:对文件数据打乱
with tf.Session() as sess:
sess.run(tf.local_variables_initializer())#初始化文件
#文件队列填充的线程,启动后则填充
tf.train.start_queue_runners(sess=sess)
#从文件对列中获取数据
#文件队列中只要八个数据,如果大于八则报错,epoch=2轮*4,如果想要更多数据则epoch=None
for i in range(10):
print(sess.run([images,labels]))
#结果:
"""[b'image1.jpg', 1]
[b'image3.jpg', 3]
[b'image2.jpg', 2]
[b'image4.jpg', 4]
[b'image1.jpg', 1]
[b'image4.jpg', 4]
[b'image3.jpg', 3]
[b'image2.jpg', 2]
[b'image3.jpg', 3]
[b'image1.jpg', 1]"""
利用tf.train.string_input_producer进行读取
import tensorflow as tf
#利用tf读取文件
filename = ['/Users/apple/Downloads/11人脸识别/projects/face/data/A.csv',
'/Users/apple/Downloads/11人脸识别/projects/face/data/B.csv',
'/Users/apple/Downloads/11人脸识别/projects/face/data/C.csv']
file_queue = tf.train.string_input_producer(filename,shuffle=True,num_epochs=2)#传入路径
reader = tf.WholeFileReader()#文件读取器
key, value = reader.read(file_queue) #获取键值对,key:图片名称,value图片内容
with tf.Session() as sess:
sess.run(tf.local_variables_initializer())
tf.train.start_queue_runners(sess=sess)#填充进程
for i in range(6):#epoce=2,文件数为3
print(sess.run([key,value]))
#结果:
"""[b'/Users/apple/Downloads/11\xe4\xba\xba\xe8\x84\xb8\xe8\xaf\x86\xe5\x88\xab/projects/face/data/A.csv', b'1.jpg,1\n2.jpg,2\n3.jpg,3\n']
[b'/Users/apple/Downloads/11\xe4\xba\xba\xe8\x84\xb8\xe8\xaf\x86\xe5\x88\xab/projects/face/data/C.csv', b'7.jpg,7\n8.jpg,8\n9.jpg,9\n']
[b'/Users/apple/Downloads/11\xe4\xba\xba\xe8\x84\xb8\xe8\xaf\x86\xe5\x88\xab/projects/face/data/B.csv', b'4.jpg,4\n5.jpg,5\n6.jpg,6\n']
[b'/Users/apple/Downloads/11\xe4\xba\xba\xe8\x84\xb8\xe8\xaf\x86\xe5\x88\xab/projects/face/data/B.csv', b'4.jpg,4\n5.jpg,5\n6.jpg,6\n']
[b'/Users/apple/Downloads/11\xe4\xba\xba\xe8\x84\xb8\xe8\xaf\x86\xe5\x88\xab/projects/face/data/C.csv', b'7.jpg,7\n8.jpg,8\n9.jpg,9\n']
[b'/Users/apple/Downloads/11\xe4\xba\xba\xe8\x84\xb8\xe8\xaf\x86\xe5\x88\xab/projects/face/data/A.csv', b'1.jpg,1\n2.jpg,2\n3.jpg,3\n']"""
利用TF对已经打包的数据进行解析
#对打包后的文件进行解析
import tensorflow as tf
filelist = ['/Users/apple/Downloads/11人脸识别/projects/face/data/image/train.tfrecord2']
file_queue = tf.train.string_input_producer(filelist, num_epochs=None,shuffle=True)
reader = tf.TFRecordReader()
_, ex = reader.read(file_queue)
#读取的数据是序列化后的数据
feature = {
'image':tf.FixedLenFeature([],tf.string),
'label':tf.FixedLenFeature([],tf.int64)
}
batchsize = 1
batch = tf.train.shuffle_batch([ex],batchsize,capacity=batchsize*10,min_after_dequeue=batchsize*5)
#解码
example = tf.parse_example(batch, features=feature)
image = example['image']
label = example['label']
image = tf.decode_raw(image,tf.uint8)
image = tf.reshape(image,[-1,32,32,3])
with tf.Session() as sess:
sess.run(tf.local_variables_initializer())
tf.train.start_queue_runners(sess=sess)
for i in range(1):
image_bth, _ = sess.run([image, label])
import cv2
#可视化
cv2.imshow("image", image_bth[0, ...])
cv2.waitKey(0)
Tensorflow中的高层接口(待学)
搭建网络结构:TF-Slim, TFLearn, Keras, TensorLayer
Tensorflow实现数据增强(介绍)
使用tf.image库进行数据增强
- 使用tf.image库进行数据增强
- 颜色扰动(亮度、对比度、HSV、RGB等)
- 裁剪/Pad
- 噪声/模糊
- 翻转/旋转(空间几何变换/放射变换)
- Draw Boxes
- 标准化
- 其他数据增强方法
- Mixup
- Oversampling
- 锐化/浮雕/灰度
- 边界检测
- 超像素
- 255-V
模型训练必须使用数据增强,充分利用大数据
TensorBoard使用
TensorBoard可以进行网络可视化/训练中间结果可视化
查看数据增强之后结果,数据分布,参数分布,各种图