人臉識別智慧小程式 | Tensorflow基礎 | 03
- TensorFlow概念介紹-Graph
- Session-Tensor-Operation-Feed-Fetch介紹
- TensorFlow中核心API介面
- TensorFlow資料讀取機制與API方法
- Cifar10資料解析程式設計案例
- Tensorflow中TFRecord資料打包程式設計案例
- 如何使用tf.train.slice_input_producer讀取檔案列表中的樣本
- 如何使用tf.train.string_input_producer讀取檔案列表中的樣本
- 如何通過TF對已經打包過的資料進行解析
- TF中的高階API介面
- TF中的資料增強
- Tensorboard 除錯技巧
- 小結
TensorFlow概念介紹-Graph
TensorFlow:Google開源的基於資料流圖的科學計算庫,適用於機器學習、深度學習等人工智慧領域。
TensorFlow的原始碼是開源的,可以在github上進行下載。
安裝可以直接通過pip直接安裝,也可以把原始碼下載到本地自己進行編譯。
然後TF中提供了很多模型,包括計算機視覺和自然語言處理的,在搭建模型的時候可以直接呼叫這裡面的model。
- 前端:程式設計模型、構造計算圖、Python、Cpp、Java
網路也被稱為計算圖。
通過構造這樣的一個圖結構,並定好資料流向,來完成整個推理運算。
- 後端:執行計算圖,C++
前端使用Python搭建網路模型,構造出來的計算圖是不會運算的。前端搭建好計算圖,並給定資料,後端再經過運算,得到輸出。
Graph:描述了整個計算過程。
- 宣告(單個/多個)
一個圖表示一個網路,如果需要用到多個網路來解決一個任務,那就需要宣告多個圖,也就是多個Graph。
- 儲存為pb檔案
pb檔案包括了網路的結構和網路的引數。
-
從pb中恢復Graph
-
Tensorboard視覺化
Graph是在前端來完成的,並且可以通過tf進行視覺化展示。
上圖是一個圖形化的結果。
Session-Tensor-Operation-Feed-Fetch介紹
Session
- Graph必須在Session的上下文中執行
- Session將Graph的op分發到諸如CPU或GPU之類的裝置上執行
Graph <=> Session <=> 後端
Session相當於是Graph和後端的一個溝通的橋樑。
注入機制: 實際上就是Session具體完成計算圖的過程,也是在注入機制中完成了前端和後端這個橋樑的作用。
Tensor
- 在tf中,所有在節點之間傳遞的資料都為Tensor物件
- N維陣列,影象:\((batch*height*width*channel)\)
上圖是tensor常用的定義方式,重點掌握前三種。
tf.constant() # 常量
tf.Variable() # 變數
tr.placeholder() # 佔位符
Operation(op)
- tf Graph中的計算節點,輸入輸出均為Tensor
- 呼叫Session.run(tensor)或者tensor.eval()方可獲取該Tensor的值
上圖中的兩個add,一個maltiply都是op。
具體計算圖的op(操作)在哪裡完成,可以通過Session來指定完成這些op的裝置資源。
Feed:通過feed為計算圖注入值
Feed為Tensor完成具體值的注入,這裡注入的值通常是那些佔位符。
佔位符是在構造計算圖時,那些沒有辦法確定的Tensor。
Fetch: 使用Fetch獲取計算結果
TensorFlow中核心API介面
上面是常用的op操作。
tf.nn 是常用的網路搭建API。
tf.train 定義了很多和優化相關的一些函式。
TFRecord: tf提供了TFRcord的格式來統一儲存資料
TFRecord將影象資料和標籤放在一起的二進位制檔案(protocol buffer),能更好的利用記憶體,實現快速的複製、移動、讀取、儲存。
TensorFlow資料讀取機制與API方法
如果直接從磁碟讀取資料,那麼IO的等待時間會造成計算資源的浪費。
檔名佇列有什麼用呢?這裡就涉及到我們模型訓練的一個概念——Epoch。
訓練樣本是分為一個一個batch的,意思就是每次從訓練樣本中取出一部分樣本,用這個一部分樣本來對網路引數進行調整,進行模型的訓練。
假如訓練樣本有10000個,batch的數量為100,那麼一個Epoch就有100個batch。每取完100個batch(不重複),就叫做跑完了一個Epoch。一個Epoch就意味著全部的樣本都在網路中進行了一遍計算。
通過檔名佇列,可以完成對Epoch更好的管理。比如在檔名佇列中構造出3個Epoch,用A,B,C表示,那麼它們都是包含了所有的檔案列表的,那麼就可以方便進行shuffle。
Cifar10資料解析程式設計案例
接下來以Cifar-10為例,介紹如何使用tf進行資料讀取&資料打包。
Cifar-10也是影象分類任務,在卷積神經網中,我們評價一個模型效果的好壞,可以使用ImageNet資料集對模型進行效能評估,也可以使用Cifar-10或Cifar-100。
按照如下設定,本地連線遠端程式設計環境!
cifar10資料集下載地址
http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
下載好cifar10資料,解壓後,發現其是二進位制格式存放的,為了更方便的展示讀寫的效果,會對這些二進位制檔案進行解析,將其解析成具體的圖片,並將其存放在data/image/的train/和test/下。
下面的程式碼是對cifar-10圖片進行解碼。
import urllib
import urllib.request
import os
import sys
import tarfile
import glob
import pickle
import numpy as np
import cv2 # pip install opencv-python
def download_and_uncompress_tarball(tarball_url, dataset_dir):
"""
完成對cifar10資料的下載和解壓
Downloads the `tarball_url` and uncompresses it locally.
Args:
tarball_url: The URL of a tarball file.
dataset_dir: The directory where the temporary files are stored.
"""
filename = tarball_url.split('/')[-1]
filepath = os.path.join(dataset_dir, filename)
def _progress(count, block_size, total_size):
sys.stdout.write('\r>> Downloading %s %.1f%%' % (
filename, float(count * block_size) / float(total_size) * 100.0))
sys.stdout.flush()
filepath, _ = urllib.request.urlretrieve(tarball_url, filepath, _progress)
print()
statinfo = os.stat(filepath)
print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
tarfile.open(filepath, 'r:gz').extractall(dataset_dir)
DATA_URL = 'http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz' # cifar10資料集
DATA_DIR = 'data'
# cifar10的10個分類
classification = ['airplane',
'automobile',
'bird',
'cat',
'deer',
'dog',
'frog',
'horse',
'ship',
'truck']
def unpickle(file):
"""
這是cifar10網站給的關於檔案解析的指令碼
:param file: 二進位制檔案
:return: 解析好的鍵值對
"""
import pickle
with open(file, 'rb') as fo:
dict = pickle.load(fo, encoding='bytes')
return dict
def to_image(from_file, to_file):
"""
將cifar10還原成圖片
儲存至 to_file/train/ to_file/test/
:param from_file: 圖片二進位制檔案
:param to_file: 圖片儲存路徑
:return:
"""
# 下面將二進位制檔案解析成圖片
folders = from_file
# glob模組的主要方法就是glob,該方法返回所有匹配的檔案路徑列表(list)
# train_test_file = ["/data_batch*", "/test_batch*"]
for x in ["train", "test"]:
if x == "train":
t_files = glob.glob(folders + "/data_batch*")
else:
t_files = glob.glob(folders + "/test_batch*")
# 定義資料和標籤為一個空格list
data = []
labels = []
# 將每個檔案都進行解碼,得到解碼後的資料
for file in t_files:
dt = unpickle(file)
data += list(dt[b"data"])
labels += list(dt[b"labels"])
print(labels) # 列印標籤 進行檢視
# 在cifar10是通道優先的
imgs = np.reshape(data, [-1, 3, 32, 32])
for i in range(imgs.shape[0]): # imgs.shape[0] 圖片資料總量
im_data = imgs[i, ...] # 獲取第i張圖片
im_data = np.transpose(im_data, [1, 2, 0]) # 將channel交換到最後一維
im_data = cv2.cvtColor(im_data, cv2.COLOR_RGB2BGR) # 將RGB轉換為BGR模式
f = "{}/{}/{}".format("data/image", x, classification[labels[i]])
print(f)
if not os.path.exists(f):
os.makedirs(f)
# 命名 編號.jpg
cv2.imwrite("{}/{}.jpg".format(f, str(i)), im_data)
print("Finish!")
if __name__ == '__main__':
# 下載和解壓cifar10資料
# download_and_uncompress_tarball(DATA_URL, DATA_DIR)
to_image("data/cifar-10-batches-py", "data/image/")
Tensorflow中TFRecord資料打包程式設計案例
然後需要對解碼好的圖片進行打包,生成TFRecord Writer。
import tensorflow as tf
import cv2
import numpy as np
import glob
import os
import warnings
from tqdm import tqdm
warnings.filterwarnings("ignore")
classification = ['airplane',
'automobile',
'bird',
'cat',
'deer',
'dog',
'frog',
'horse',
'ship',
'truck']
if __name__ == "__main__":
for x in ["test", "train"]:
idx = 0
im_data = []
im_labels = []
for path in classification:
path = "data/image/%s/" % x + path
im_list = glob.glob(path + "/*")
im_label = [idx for i in range(im_list.__len__())]
idx += 1
im_data += im_list
im_labels += im_label
print(im_labels[:10])
print(im_data[:10])
tfrecord_file = "data/%s.tfrecord" % x
with tf.python_io.TFRecordWriter(tfrecord_file) as writer:
# 使用shuffle進行打亂
index = [i for i in range(im_data.__len__())]
np.random.shuffle(index)
for i in tqdm(range(im_data.__len__())):
im_d = im_data[index[i]]
im_l = im_labels[index[i]]
data = cv2.imread(im_d) # 使用opencv讀取圖片
# 下面是另一種圖片讀取方式
#data = tf.gfile.FastGFile(im_d, "rb").read()
# 使用tf.train.Example將features編碼資料封裝成特定的PB協議格式
ex = tf.train.Example(
features=tf.train.Features(
feature={
"image": tf.train.Feature(
bytes_list=tf.train.BytesList(
value=[data.tobytes()])),
"label": tf.train.Feature(
int64_list=tf.train.Int64List(
value=[im_l])),
}
)
)
# 將example資料系列化為字串,並將系列化為字串的example資料寫入協議緩衝區
writer.write(ex.SerializeToString())
如何使用tf.train.slice_input_producer讀取檔案列表中的樣本
從檔案列表中讀取樣本。
import tensorflow as tf
images = ['image1.jpg', 'image2.jpg', 'image3.jpg', 'image4.jpg']
labels = [1, 2, 3, 4]
"""
tf.train.slice_input_producer是一個tensor生成器,作用是按照設定,每次從一個tensor列表中按順序或者隨機抽取出一個tensor放入檔名佇列。
"""
[images, labels] = tf.train.slice_input_producer([images, labels],num_epochs=None,shuffle=True)
with tf.Session() as sess:
sess.run(tf.local_variables_initializer())
tf.train.start_queue_runners(sess=sess)
for i in range(10):
print(sess.run([images, labels]))
如何使用tf.train.string_input_producer讀取檔案列表中的樣本
從檔案資料中讀取樣本。
import tensorflow as tf
filename = ['data/A.csv', 'data/B.csv', 'data/C.csv']
file_queue = tf.train.string_input_producer(filename,
shuffle=True,
num_epochs=None)
reader = tf.WholeFileReader()
key, value = reader.read(file_queue)
with tf.Session() as sess:
sess.run(tf.local_variables_initializer())
tf.train.start_queue_runners(sess=sess)
for i in range(10):
print(sess.run([key, value]))
train.slice_input_producer 和 train.string_input_producer 的差別
主要的區別就是string_input_producer輸出的結果是一個佇列,而slice_input_producer輸出的結果是一個tensor。後者可以直接用sess.run()的方式獲得tensor的值,但是對於string_input_producer 沒有辦法這樣直接獲取。
如何通過TF對已經打包過的資料進行解析
import tensorflow as tf
import cv2
filelist = ['data/train.tfrecord']
file_queue = tf.train.string_input_producer(filelist,
num_epochs=None,
shuffle=True)
reader = tf.TFRecordReader()
_, ex = reader.read(file_queue) # 解碼得到打包的資料
# 定義好feature
feature = {
'image': tf.FixedLenFeature([], tf.string),
'label': tf.FixedLenFeature([], tf.int64)
}
batchsize = 2
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])
cv2.imshow("image", image_bth[0, ...])
cv2.waitKey(0)
上面的示例程式碼完成了對TFRecord資料的讀取,並且每次讀取的時候都是讀取了一個batch_size的資料,也進行了視覺化。
在進行模型訓練的時候,就是這樣,每次讀取一個batch_size的資料,並且將這個batch_size的資料餵給網路訓練。
TF中的高階API介面
之前介紹的是一些tf的基本api介面,如果我們在設計網路的時候,使用這些基本的api介面,這時候就需要寫大量的程式碼。
在tf中,有更加高層的封裝,其中用的最多的就是slim和keras。
TF中的資料增強
資料增強是防止過擬合非常常見的一個手段,在tf中可以通過 tf.image來對影象進行資料增強。
對影象資料進行擾動,進而提高模型對噪聲的魯棒性。
第一幅圖是原圖,後面的都是經過資料增強之後獲取到的影象,這時候就相當於是產生了一些新的樣本,而深度學習是要依賴於大資料的,資料越充分,那麼學到的模型就更加的魯棒。因此在進行模型訓練的時候,資料增強是必須要使用的一種手段。
Tensorboard 除錯技巧
Tensorboard:可以進行網路視覺化/訓練中間結果視覺化。
訓練中間結果採用sess.run()打印出來,或可以新增到tensorboard中,進行視覺化展示。
小結
Tensorflow是什麼?
TensorFlow:Google開源的基於資料流圖的科學計算庫,適用於機器學習、深度學習等人工智慧領域。
TensorFlow的原始碼是開源的,可以在github上進行下載。
安裝可以直接通過pip直接安裝,也可以把原始碼下載到本地自己進行編譯。
**然後TF中提供了很多模型,包括計算機視覺和自然語言處理的,在搭建模型的時候可以直接呼叫這裡面的model。**
TensorFlow的架構
* 前端:程式設計模型、構造計算圖、Python、Cpp、Java
網路也被稱為計算圖。
通過構造這樣的一個圖結構,並定好資料流向,來完成整個推理運算。
* 後端:執行計算圖,C++
前端使用Python搭建網路模型,構造出來的計算圖是不會運算的。前端搭建好計算圖,並給定資料,後端再經過運算,得到輸出。
Graph
Graph:描述了整個計算過程。
* 宣告(單個/多個)
一個圖表示一個網路,如果需要用到多個網路來解決一個任務,那就需要宣告多個圖,也就是多個Graph。
* 儲存為pb檔案
pb檔案包括了網路的結構和網路的引數。
* 從pb中恢復Graph
* Tensorboard視覺化
Graph是在前端來完成的,並且可以通過tf進行視覺化展示。
上圖是一個圖形化的結果。
Session
Session
* Graph必須在Session的上下文中執行
* Session將Graph的op分發到諸如CPU或GPU之類的裝置上執行
Graph <=> Session <=> 後端
Session相當於是Graph和後端的一個溝通的橋樑。
注入機制: 實際上就是Session具體完成計算圖的過程,也是在注入機制中完成了前端和後端這個橋樑的作用。
Tensor
Tensor
* 在tf中,所有在節點之間傳遞的資料都為Tensor物件
* N維陣列,影象:$(batch*height*width*channel)$
上圖是tensor常用的定義方式,重點掌握前三種。
tf.constant() # 常量
tf.Variable() # 變數
tr.placeholder() # 佔位符
Operation
Operation(op)
* tf Graph中的**計算節點**,輸入輸出均為Tensor
* 呼叫Session.run(tensor)或者tensor.eval()方可獲取該Tensor的值
上圖中的兩個add,一個maltiply都是op。
具體計算圖的op(操作)在哪裡完成,可以通過Session來指定完成這些op的裝置資源。
Feed & Fetch
Feed:通過feed為計算圖注入值
Feed為Tensor完成具體值的注入,這裡注入的值通常是那些佔位符。
佔位符是在構造計算圖時,那些沒有辦法確定的Tensor。
Fetch: 使用Fetch獲取計算結果
TFRecord
TFRecord: tf提供了TFRcord的格式來統一儲存資料
TFRecord將影象資料和標籤放在一起的二進位制檔案(protocol buffer),能更好的利用記憶體,實現快速的複製、移動、讀取、儲存。
tf的資料讀取機制
輸入資料 -> 檔名佇列 -> 記憶體佇列 -> 計算
檔名佇列有什麼用呢?這裡就涉及到我們模型訓練的一個概念——Epoch。
訓練樣本是分為一個一個batch的,意思就是每次從訓練樣本中取出一部分樣本,用這個一部分樣本來對網路引數進行調整,進行模型的訓練。
假如訓練樣本有10000個,batch的數量為100,那麼一個Epoch就有100個batch。每取完100個batch(不重複),就叫做跑完了一個Epoch。一個Epoch就意味著全部的樣本都在網路中進行了一遍計算。
通過檔名佇列,可以完成對Epoch更好的管理。比如在檔名佇列中構造出3個Epoch,用A,B,C表示,那麼它們都是包含了所有的檔案列表的,那麼就可以方便進行shuffle。
關於TFRecord的Writer和Reader
這是一個模板程式碼的..
知道這個東西,然後用的時候在對照著進行修改!
train.slice_input_producer 和 train.string_input_producer 的差別
主要的區別就是string_input_producer輸出的結果是一個佇列,而slice_input_producer輸出的結果是一個tensor。後者可以直接用sess.run()的方式獲得tensor的值,但是對於string_input_producer 沒有辦法這樣直接獲取。
tf的高層介面
之前介紹的是一些tf的基本api介面,如果我們在設計網路的時候,使用這些基本的api介面,這時候就需要寫大量的程式碼。
在tf中,有更加高層的封裝,其中用的最多的就是slim和keras。
資料增強
資料增強是防止過擬合非常常見的一個手段,在tf中可以通過 tf.image來對影象進行資料增強。
對影象資料進行擾動,進而提高模型對噪聲的魯棒性。
第一幅圖是原圖,後面的都是經過資料增強之後獲取到的影象,這時候就相當於是產生了一些新的樣本,而深度學習是要依賴於大資料的,資料越充分,那麼學到的模型就更加的魯棒。**因此在進行模型訓練的時候,資料增強是必須要使用的一種手段。**