日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【TensorFlow】笔记5:图像数据处理

發(fā)布時間:2025/3/19 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【TensorFlow】笔记5:图像数据处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 一、TFRecords輸入數(shù)據(jù)格式
    • 1、TFRecord格式介紹
    • 2、TFRecord樣例程序
      • (1)生成TFRecords文件
      • (2)讀取TFRecord文件
  • 二、圖像數(shù)據(jù)處理
    • 1、TF圖像處理函數(shù)
      • (1)圖像編碼處理
      • (2)圖像大小處理
        • a、通過算法使得新的圖像盡量保存原始圖像上所有的信息。
        • b、對圖像裁剪或填充——`tf.image.resize_image_with_crop_or_pad`函數(shù)
        • c、比例調(diào)整圖像大小——`tf.image.entral_crop`函數(shù)
        • d、剪裁或填充給定區(qū)域的圖像——`tf.image.crop_to_bounding_box`函數(shù)和`tf.image.pad_to_bounding_box`函數(shù)
      • (3)圖像翻轉(zhuǎn)
      • (4)圖像色彩調(diào)整
        • a、調(diào)整亮度
        • b、調(diào)整對比度
        • c、調(diào)整色相
        • d、調(diào)整飽和度
        • e、圖像標(biāo)準(zhǔn)化
        • f、處理標(biāo)注框(bounding box)
        • g、隨機(jī)截取圖像
    • 2、圖像預(yù)處理實例
  • 三、多線程輸入數(shù)據(jù)處理框架
    • 1、隊列與多線程
      • (1)兩種隊列
      • (2)多線程協(xié)同方法1:`tf.Coordinator` 類
      • (3)多線程協(xié)同方法2:`tf.QueueRunner` 類
    • 2、輸入文件隊列
      • 3、組合訓(xùn)練數(shù)據(jù)(batching)
        • (1)`tf.train.batch`
        • (2)`tf.train.shuffle_batch`
    • 4、輸入數(shù)據(jù)處理框架
    • 5、總結(jié)
  • 四、數(shù)據(jù)集(DataSet)
    • 1、數(shù)據(jù)集的基本使用方法
      • (1)tensor -> 數(shù)據(jù)集
      • (2)文本文件 -> 數(shù)據(jù)集
      • (3)TFRecord -> 數(shù)據(jù)集
    • 2、數(shù)據(jù)集的高層操作
      • (1)map操作
      • (2)shuffle 和 batch 操作
      • (3)repeat 操作
      • (4)其他操作
      • (5)示例

目標(biāo):如何對圖像數(shù)據(jù)進(jìn)行預(yù)處理使得訓(xùn)練得到的神經(jīng)網(wǎng)絡(luò)模型盡可能小地被無關(guān)因素所影響。同時,為減小預(yù)處理對訓(xùn)練速度的影響,使用多線程處理。

一、TFRecords輸入數(shù)據(jù)格式

TF統(tǒng)一存儲數(shù)據(jù)的格式:TFRecords,二進(jìn)制文件,可更好利用內(nèi)存、便于復(fù)制和移動,且不需要單獨(dú)的標(biāo)簽文件。

1、TFRecord格式介紹

TFRecord 文件中的數(shù)據(jù)都是通過 tf.train.Example協(xié)議內(nèi)存塊(Protocol Buffer)(協(xié)議內(nèi)存塊包含了字段Features)的格式存儲的。

tf.train.Example定義:

message Example {Features features = 1; };message Features {map<string, Feature> feature = 1; };message Feature {oneof kind{BytesList bytes_list = 1;FloatList float_list = 2;Int64List int64_list = 3;} };

tf.train.Example 中包含了一個從屬性名稱到取值的字典。
其中屬性名稱為一個字符串,屬性的取值可以為字符串(BytesList)、實數(shù)列表 (FloatList)或者整數(shù)列表( Int64List)。
比如將一張解碼前的圖像存為一個字符串,圖像所對應(yīng)的類別編號存為整數(shù)列表。在2中將給出 一個使用 TFRecord 的具體樣例 。

數(shù)據(jù)存儲:將數(shù)據(jù)填入到 Example 協(xié)議內(nèi)存塊(protocol buffer),將協(xié)議內(nèi)存塊序列化為一個字符串, 并且通過tf.python_io.TFRecordWriter 寫入到 TFRecords 文件。

從TFRecords文件中讀取數(shù)據(jù), 可以使用tf.TFRecordReader的tf.parse_single_example解析器。這個操作可以將Example協(xié)議內(nèi)存塊(protocol buffer)解析為張量。

2、TFRecord樣例程序

(1)生成TFRecords文件

將MNIST輸入數(shù)據(jù)轉(zhuǎn)換為TFRecord的格式

import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data import numpy as np# 生成整數(shù)型的屬性。 def _int64_feature(value):return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))# 生成字符串型的屬性。 def _bytes_feature(value):return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))DATASET_PATH = '/home/jie/Jie/codes/tf/datasets/MNIST_DATA' mnist = input_data.read_data_sets(DATASET_PATH, dtype=tf.uint8, one_hot=True) images = mnist.train.images # 訓(xùn)練數(shù)據(jù)所對應(yīng)的正確答案,可以作為一個屬性保存在 TFRecord 中 labels = mnist.train.labels # 訓(xùn)練數(shù)據(jù)的圖像分辨率,這可以作為 Example 中的一個屬性。 pixels = images.shape[1] num_example = mnist.train.num_example# 輸出 TFRecord 文件的地址。 filename = '/home/jie/Jie/codes/tf/datasets/MNIST_DATA/output.tfrecords' # 創(chuàng)建一個 writer 來寫 TFRecord 文件。 writer = tf.python_io.TFRecordWriter(filename) for index in range(num_example):# 將圖像矩陣轉(zhuǎn)化成一個字符串。image_raw = images[index].tostring()# 將一個樣例轉(zhuǎn)化為 Example Protocol Buffer ,并將所有的信息寫入這個數(shù)據(jù)結(jié)構(gòu)。example = tf.train.Example(features=tf.train.Features(features={'pixels':_int64_feature(pixels),'label':_int64_feature(np.argmax(labels[index])),'image_raw':_bytes_features(images_raw)}))# 將一個 Example 寫入 TFRecord 文件。writer.write(example.SerializeToString()) writer.close()

當(dāng)數(shù)據(jù)量較大時,也可以將數(shù)據(jù)寫入多個 TFRecord 文件。

(2)讀取TFRecord文件

import tensorflow as tf# 輸出 TFRecord 文件的地址。 filename = '/home/jie/Jie/codes/tf/datasets/MNIST_DATA/output.tfrecords' # 創(chuàng)建一個 reader 來讀取 TFRecord 文件中的樣例。 reader = tf.TFRecordReader() # tf.train.string_input_producer 創(chuàng)建一個隊列來維護(hù)輸入文件列表 filename_queue = tf.train.string_input_producer([filename])# 從文件中讀取一個樣例。也可以使用 read_up_to 函數(shù)-次性讀取多個樣例。 _, serialized_example = reader.read(filename_queue) # 解析讀入的一個樣例。若需要解析多個樣例,可用parse_example函數(shù) features = tf.parse_single_example(serialized_example,features={# TensorFlow 提供兩種不同的屬性解析方法。 # 1. tf.FixedLenFeature,所解析的結(jié)果為一個 Tensor。# 2. tf.VarLenFeature,所得到的解析結(jié)果為SparseTensor,用于處理稀疏數(shù)據(jù)。# 這里解析數(shù)據(jù)的格式需要和上面程序可入數(shù)據(jù)的格式一致。'image_raw':tf.FixedLenFeature([], tf.string),'pixels':tf.FixedLenFeature([], tf.int64),'label':tf.FixedLenFeature([], tf.int64),})# tf.decode_raw 可以將字符串解析成圖像對應(yīng)的像索數(shù)組。 image = tf.decode_raw(features['image_raw'], tf.uint8) label = tf.cast(features['label'], tf.int32) pixels = tf.cast(features['pixels'], tf.int32)sess = tf.Session() # 啟動多線程處理輸入數(shù)據(jù) coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(sess=sess, coord=coord)# 每次運(yùn)行可以讀取 TFRecord 文件中的一個樣例。 # 當(dāng)所有樣例都讀取完之后,在此樣例中程序會再重頭讀取 for i in range(10):print(sess.run([image, label, pixels]))

二、圖像數(shù)據(jù)處理

目標(biāo):可以盡量避免模型受到無關(guān)因素的影響。在大部分圖像識別中,通過預(yù)處理過程可以提高模型的準(zhǔn)確率。

1、TF圖像處理函數(shù)

(1)圖像編碼處理

RGB三維矩陣( jpeg 和 png 格式) 《==》 編碼/解碼

# -*-coding:utf-8-*- import tensorflow as tf import matplotlib.pyplot as pltIMAGES_PATH = '/home/jie/Desktop/6987985.jpeg' SAVE_PATH = '/home/jie/Desktop/output.jpeg' # 讀取圖像的原始數(shù)據(jù)。 image_raw_data = tf.gfile.FastGFile(IMAGES_PATH, 'rb').read()with tf.Session() as sess:# 對圖像進(jìn)行 jpeg 的格式解碼從而得到圖像對應(yīng)的三維矩陣。 # tf.image.decode_png 函數(shù)對 png 格式的圖像進(jìn)行解碼。# 解碼之后的結(jié)果為一個張量,在使用它的取值之前需要明確調(diào)用運(yùn)行的過程。img_data = tf.image.decode_jpeg(image_raw_data)print(img_data.eval())# 輸出解碼之后的三維矩陣,上面這一行代碼將輸出以下內(nèi)容。# 使用 pyplot 工具可視化得到的圖像。plt.imshow(img_data.eval())plt.show()# 將表示一張圖像的三維矩陣重新按照jpeg格式編碼并存入文件中。# 打開該圖像,與原始圖像一樣encoded_image = tf.image.encode_jpeg(img_data)with tf.gfile.GFile(SAVE_PATH, "wb") as f:f.write(encoded_image.eval())

輸出結(jié)果

[[[ 11 7 0][ 29 25 22][ 32 33 38]...[ 29 31 28][ 19 21 20][ 5 7 2]][[ 38 31 15][191 184 174][213 213 213]...[209 214 217][183 187 188][ 32 37 33]][[ 19 44 51][200 228 242][153 189 215]...[188 201 209][210 218 221][ 24 33 32]]...[[ 56 34 23][245 217 196][125 87 42]...[ 77 74 65][214 215 209][ 36 37 32]][[ 20 30 40][177 184 190][211 216 212]...[217 216 214][185 185 183][ 27 27 25]][[ 6 6 4][ 29 29 27][ 29 33 32]...[ 29 30 32][ 32 32 32][ 1 1 1]]]

(2)圖像大小處理

由于很多網(wǎng)絡(luò)輸入節(jié)點的個數(shù)是固定的,所以需要先將圖像的大小統(tǒng)一。
圖像大小調(diào)整有兩種方法:

a、通過算法使得新的圖像盡量保存原始圖像上所有的信息。

TF的 tf.image.resize_images 函數(shù)提供四種不同的方法

# 略去加載原始圖像,定義會話等過程,假設(shè):img_data是已經(jīng)解碼的圖像。# 1. 首先將圖片數(shù)據(jù)轉(zhuǎn)換為實數(shù)類型,即將0-255轉(zhuǎn)化為0.0-1.0范圍內(nèi)的實數(shù)。# 大多數(shù)圖像處理 API 支持整數(shù)和實數(shù)類型的輸入。# 如果輸入是整數(shù)類型,這些 API 會在內(nèi)部將輸入轉(zhuǎn)化為實數(shù)后處理,再將輸出轉(zhuǎn)化為整數(shù)。# 如果有多個處理步驟,在格數(shù)和實數(shù)之間的反復(fù)轉(zhuǎn)化將導(dǎo)致精度損失,# 因此推薦在圖像處理前將其轉(zhuǎn)化為實數(shù)類型。img_data = tf.image.convert_image_dtype(img_data, dtype=tf.float32)# 通過 tf.image.resize_images 函數(shù)調(diào)整圖像的大小。# 第一個參數(shù): 原始圖像# 第二個和第三個參數(shù)為調(diào)整后圖像的大小 # method 參數(shù)給出了調(diào)整圖像大小的算法resized = tf.image.resize_images(img_data, [300, 300], method=0)plt.imshow(resized.eval())plt.show()

method取值圖像大小調(diào)整算法
0雙線性插值法(Bilinear interpolation)
1最近鄰插值(Nearest neighbor interpolation)
2雙三次插值法(Bicubic interpolation)
3面積插值法(Area interpolation)

==》不同算法效果差別不大

b、對圖像裁剪或填充——tf.image.resize_image_with_crop_or_pad函數(shù)

# 通過 tf.image.resize_image_with_crop_or_pad 函數(shù)調(diào)整圖像的大小。# 第一個參數(shù): 原始圖像# 第二個和第三個參數(shù)為調(diào)整后的目標(biāo)圖像大小。# 如果原始圖像的尺寸大于大于目標(biāo)圖像,則該函數(shù)會自動截取y你是圖像中居中的部分。# 若目標(biāo)圖像大于原始圖像,則會自動在原始圖像的四周填充全0背景。croped = tf.image.resize_image_with_crop_or_pad(img_data, 400, 300)padded = tf.image.resize_image_with_crop_or_pad(img_data, 1500, 1500)plt.imshow(croped.eval())plt.show()plt.imshow(padded.eval())plt.show()


c、比例調(diào)整圖像大小——tf.image.entral_crop函數(shù)

# 第一個參數(shù)為原始圖像, 第二個參數(shù)為調(diào)整比例,這個比例需要是-個(0, 1]的實數(shù)central_cropped = tf.image.central_crop(img_data, 0.25)plt.imshow(central_cropped.eval())plt.show()

d、剪裁或填充給定區(qū)域的圖像——tf.image.crop_to_bounding_box函數(shù)和tf.image.pad_to_bounding_box函數(shù)

這兩個函數(shù)都要求給出的尺寸滿足一定的要求,否則程序會報錯。比如在使用 tf.image.crop_to_bounding_box 函數(shù)時, TensorFlow 要求提供的圖像尺寸要大于目標(biāo)尺寸,也就是要求原始圖像能夠裁剪出目標(biāo)圖像的大小。

(3)圖像翻轉(zhuǎn)

功能:上下翻轉(zhuǎn)、左右翻轉(zhuǎn)以及沿對角線翻轉(zhuǎn)

# 將圖像上下翻轉(zhuǎn)flipped1 = tf.image.flip_up_down(img_data)# 將圖像左右翻轉(zhuǎn)flipped2 = tf.image.flip_left_right(img_data)# 將圖像沿對角線翻轉(zhuǎn)flipped3 = tf.image.transpose_image(img_data)plt.subplot(221)plt.imshow(img_data.eval())plt.subplot(222)plt.imshow(flipped1.eval())plt.subplot(223)plt.imshow(flipped2.eval())plt.subplot(224)plt.imshow(flipped3.eval())plt.show()

輸出結(jié)果

在很多圖像識別問題中,圖像的翻轉(zhuǎn)不會影響識別的結(jié)果。
==》訓(xùn)練得到的模型可以識別不同角度的實體
==》隨機(jī)翻轉(zhuǎn)訓(xùn)練圖像是一種很常用的圖像預(yù)處理方式。

# 以 50% 概率上下翻轉(zhuǎn)圖像flipped1 = tf.image.random_flip_up_down(img_data)# 以 50% 概率左右翻轉(zhuǎn)圖像flipped2 = tf.image.random_flip_left_right(img_data)

(4)圖像色彩調(diào)整

調(diào)整圖像的亮度、對比度、飽和度和色相,在很多圖像識別應(yīng)用中不會影響識別結(jié)果。
==》隨機(jī)調(diào)整這些屬性,使得訓(xùn)練的模型盡可能小地受無關(guān)因素的影響。

a、調(diào)整亮度

tf.image.adjust_brightness()函數(shù)和tf.image.random_brightness()函數(shù)

注意:

  • 色彩調(diào)整的 API 可能導(dǎo)致像素的實數(shù)值超出 0.0-1.0 的范圍。在輸出最終圖像前需要將其值截斷在 0.0-1.0 范圍區(qū)間,否則不僅圖像無法正常可視化,以此為輸入的神經(jīng)網(wǎng)絡(luò)的訓(xùn)練質(zhì)量可能受到影響。
  • 若對圖像進(jìn)行多項處理操作,則截斷應(yīng)在最后一步
# 將圖像的亮度 -0.5adjusted1 = tf.image.adjust_brightness(img_data, -0.5) # 截斷在 0.0-1.0 范圍區(qū)間adjusted1 = tf.clip_by_value(adjusted1, 0.0, 1.0)# 將圖像的亮度 +0.5adjusted2 = tf.image.adjust_brightness(img_data, 0.5)# 在[-max_delta, max_delta)的范圍隨機(jī)調(diào)整圖像的亮度。max_delta = 0.9adjusted3 = tf.image.random_brightness(img_data, max_delta)

b、調(diào)整對比度

tf.image.adjust_contrast()函數(shù)和tf.image.random_contrast()函數(shù)

# 將圖像的對比度減少到 0.5 倍adjusted1 = tf.image.adjust_contrast(img_data, 0.5) # 將圖像的對比度增加 5 倍adjusted2 = tf.image.adjust_contrast(img_data, 5)# 在[lower, upper] 的范圍隨機(jī)調(diào)整圖像的對比度。lower = 10upper = 100adjusted3 = tf.image.random_contrast(img_data, lower, upper)

c、調(diào)整色相

tf.image.adjust_hue函數(shù)和tf.image.random_hue函數(shù)

# 分別將色相加 0.1、0.3、0.6 和 0.9 adjusted1 = tf.image.adjust_hue(img_data, 0.1)adjusted2 = tf.image.adjust_hue(img_data, 0.3) adjusted3 = tf.image.adjust_hue(img_data, 0.6) adjusted4 = tf.image.adjust_hue(img_data, 0.9) # 在 [-max_delta, max_delta] 的范圍隨機(jī)調(diào)整圖像的色相。max_delta = 0.5adjusted5 = tf.image.random_hue(img_data, max_delta)

注意:max_delta最大為 0.5

d、調(diào)整飽和度

tf.image.adjust_saturation函數(shù)和tf.image.random_saturation函數(shù)

# 將圖像的飽和度-5adjusted1 = tf.image.adjust_saturation(img_data, -5) # 將圖像的飽和度+5adjusted2 = tf.image.adjust_saturation(img_data, 5)# 在[lower, upper] 的范圍隨機(jī)調(diào)整圖像的飽和度lower = 10upper = 100adjusted3 = tf.image.random_saturation(img_data, lower, upper)

e、圖像標(biāo)準(zhǔn)化

tf.image.per_image_standardization() :函數(shù)將圖像上的亮度均值變?yōu)?,方差變?yōu)?。

adjusted = tf.image.per_image_standardization(img_data)

f、處理標(biāo)注框(bounding box)

tf.image.draw_bounding_boxes()函數(shù)在圖像中添加標(biāo)注框。輸入圖像矩陣的數(shù)字為實數(shù),且是一個 batch 的數(shù)據(jù)(四維張量)。所以,繪制圖時,需要tf.reduce_sum()函數(shù)進(jìn)行降維。

# 將圖像縮小一些,這樣可視化能讓標(biāo)注框更加清楚。img_data = tf.image.resize_images(img_data, [180, 267], method=1)# tf.image.draw_bounding_boxes 函數(shù)要求圖像矩陣中的數(shù)字為實數(shù).# -> 先將圖像矩陣轉(zhuǎn)化為實數(shù)類型。# 輸入是一個 bacth 的數(shù)據(jù)(多張圖像組成的四維矩陣),要將解碼之后的圖像矩陣添加一維bacthed = tf.expand_dims(tf.image.convert_image_dtype(img_data, tf.float32), 0)# 給出每一張圖像的所有標(biāo)注框。一個標(biāo)注框有 4 個數(shù)字,分別代表[Y_min, X_min, Y_max, X_max]# 注意這里給出的數(shù)字都是圖像的相對位置。# 比如在 180 × 267 的圖像中,[0.35, 0.47, 0.5, 0.56]代表了從(63,125)到(90, 150)的圖像。boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]])result = tf.image.draw_bounding_boxes(bacthed, boxes)result = tf.reduce_sum(result, 0) # 這里顯示的時候需要進(jìn)行降維處理plt.imshow(result.eval())plt.show()


注:bounding box位置不準(zhǔn),僅用于學(xué)習(xí)。

g、隨機(jī)截取圖像

隨機(jī)截取圖像上有信息含量的部分也是一個提
高模型健壯性( robustness )的一種方式。
==》使得訓(xùn)練模型不受被識別物體大小的影響。
==》tf.image.sample_distorted_bounding_box()函數(shù)

boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]])# min_object_covered=0.4 表示截取部分至少包含某個標(biāo)注框 40% 的內(nèi)容。begin, size, bbox_for_draw = tf.image.sample_distorted_bounding_box(tf.shape(img_data), bounding_boxes = boxes,min_object_covered=0.4)# 通過標(biāo)注框可視化隨機(jī)截取得到的圖像。bacthed = tf.expand_dims(tf.image.convert_image_dtype(img_data, tf.float32), 0)image_with_box = tf.image.draw_bounding_boxes(bacthed, bbox_for_draw)# 截取隨機(jī)出來的圖像。每次結(jié)果可能不盡相同.distored_image = tf.slice(img_data, begin, size)

2、圖像預(yù)處理實例

在解決真實的圖像識別問題時, 一般會同時使用多種處理方法。

本實例展示:將不同的圖像處理函數(shù)結(jié)合成一個完成的圖像預(yù)處理流程。從圖像片段截取,到圖像大小調(diào)整再到圖像翻轉(zhuǎn)及色彩調(diào)整的整個圖像預(yù)處理過程。

  • 調(diào)整亮度、對比度、飽和度和色相的順序會影響最后的結(jié)果,所以定義多種不同的順序。
  • 注意:數(shù)據(jù)預(yù)處理只針對訓(xùn)練數(shù)據(jù),而非測試數(shù)據(jù)

輸入:原始訓(xùn)練圖像
輸出:神經(jīng)網(wǎng)絡(luò)的輸入層

# -*-coding:utf-8 -*-import tensorflow as tf import numpy as np import matplotlib.pyplot as plt# 給定一張圖像,隨機(jī)調(diào)整圖像的色彩。 # 因為調(diào)整亮度、對比度、飽和度和色相的順序會影響最后的結(jié)果,所以定義多種不同的順序。 # 具體順序可在預(yù)處理時隨機(jī)選取一種。從而降低無關(guān)因素對模型的影響。 # 亮度(brightness) 對比度(contrast)、飽和度(saturation)和色相(hue) def distort_color(image, color_ordering=0):if color_ordering == 0:image = tf.image.random_brightness(image, max_delta=32./255.) # image = tf.image.random_saturation(image, lower=0.5, upper=1.5)image = tf.image.random_hue(image, max_delta=0.2)image = tf.image.random_contrast(image, lower=0.5, upper=1.5)elif color_ordering == 1:image = tf.image.random_saturation(image, lower=0.5, upper=1.5)image = tf.image.random_brightness(image, max_delta=32./255.)image = tf.image.random_contrast(image, lower=0.5, upper=1.5)image = tf.image.random_hue(image, max_delta=0.2)elif color_ordering == 2:image = tf.image.random_hue(image, max_delta=0.2)image = tf.image.random_contrast(image, lower=0.5, upper=1.5)image = tf.image.random_brightness(image, max_delta=32./255.)image = tf.image.random_saturation(image, lower=0.5, upper=1.5)# 截斷在 0.0-1.0 范圍區(qū)間return tf.clip_by_value(image, 0.0, 1.0)# 給定一張解碼后的圖像、目標(biāo)圖像的尺寸以及圖像上的標(biāo)注框, # 此函數(shù)可對給出的圖像進(jìn)行預(yù)處理 # 輸入:原始訓(xùn)練圖像 # 輸出:神經(jīng)網(wǎng)絡(luò)的輸入層 def preprocess_for_train(image, height, width, bbox):# 如果沒有提供標(biāo)注框,則認(rèn)為整個圖像就是需要關(guān)注的部分。if bbox is None:bbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4])# 轉(zhuǎn)換圖像張量的類型 。if image.dtype != tf.float32:image = tf.image.convert_image_dtype(image, dtype=tf.float32)# 隨機(jī)截取圖像,減小需要關(guān)注的物體大小對圖像識別算法的影響。bbox_begin, bbox_size, _ = tf.image.sample_distorted_bounding_box(tf.shape(image), bounding_boxes=bbox)distorted_image = tf.slice(image, bbox_begin, bbox_size)# 將隨機(jī)截取的圖像調(diào)整為神經(jīng)網(wǎng)絡(luò)輸入層的大小。大小調(diào)整的算法是隨機(jī)選摔的 。distorted_image = tf.image.resize_images(distorted_image, [height, width], method=np.random.randint(4))# 隨機(jī)左右翻轉(zhuǎn)圖像。distorted_image = tf.image.random_flip_left_right(distorted_image)# 使用一種隨機(jī)的順序調(diào)整圖像色彩。distorted_image = distort_color(distorted_image, np.random.randint(3))return distorted_imageIMAGE_PATH = '/home/jie/Desktop/6987985.jpeg' image_raw_data = tf.gfile.FastGFile(IMAGE_PATH, "rb").read() with tf.Session() as sess:img_data = tf.image.decode_jpeg(image_raw_data)boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]])for i in range(6):result = preprocess_for_train(img_data, 299, 299, boxes)plt.imshow(result.eval())plt.show()

三、多線程輸入數(shù)據(jù)處理框架

復(fù)雜的預(yù)處理過程會減慢整個訓(xùn)練的過程,所以為了避免預(yù)處理成為神經(jīng)網(wǎng)絡(luò)模型訓(xùn)練效率的瓶頸,TF提供多線程處理輸入數(shù)據(jù)的框架。

經(jīng)典輸入流程:

1、隊列與多線程

在TF中,隊列也是計算圖上有狀態(tài)的節(jié)點,修改隊列狀態(tài)的操作主要有 Enqueue、EnqueueMany和Dequeue。

(1)兩種隊列

  • FIFOQueue:先進(jìn)先出隊列。
  • RandomShuffleQueue:將隊列中的元素打亂,每次出隊列操作得到的是從當(dāng)前隊列所有元素中隨機(jī)選擇的一個。(訓(xùn)練網(wǎng)絡(luò)時希望每次使用的訓(xùn)練數(shù)據(jù)盡可能隨機(jī),推薦使用)
import tensorflow as tf# 創(chuàng)建一個先進(jìn)先出隊列,指定隊列中最多可以保存兩個元素,并指定類型為整數(shù)。 q = tf.FIFOQueue(2, "int32") # enqueue_many 函數(shù):初始化隊列中的元素,需要明確的調(diào)用這個初始化過程。 init = q.enqueue_many(([0, 10],)) # Dequeue 函數(shù):隊列中的第一個元素出隊列,并存入x中 x = q.dequeue()y = x + 1 # 將y重新加入隊列。 q_inc = q.enqueue([y])with tf.Session() as sess:# 運(yùn)行初始化隊列的操作。init.run()for _ in range(5):# 運(yùn)行q_inc將執(zhí)行數(shù)據(jù)出隊列、出隊的元素+1、重新歸入隊列的整個過程。v, _ = sess.run([x, q_inc])print(v)

輸出結(jié)果

0 10 1 11 2

TF中,隊列還是異步計算張量取值的一個重要機(jī)制。例:多個線程可同時向一個隊列中寫入或讀取元素。

(2)多線程協(xié)同方法1:tf.Coordinator 類

tf.Coordinator類:用于協(xié)同多個線程一起停止, 并提供了 should_stop、request_stop 和 join 三個函數(shù)。

工作過程:

  • 在啟動線程之前,需要先聲明一個 tf.Coordinator 類,并將這個類傳入每一個創(chuàng)建的線程中。
  • 啟動的線程需要一直查詢 tf.Coordinator 類中提供的 should_stop 函數(shù), 為 True 時,則 當(dāng)前線程也需要退出 。
  • 每一個啟動的線程都可以通過調(diào)用request_stop 函數(shù)來通知其他線程退出。當(dāng) 某一個線程調(diào)用 request_stop 函數(shù)之后 ,should_stop 函數(shù)的返回值將被設(shè)置為 True,這樣其他的線程就可以同時終止了。
  • # 線程中運(yùn)行的程序,這個程序每隔1秒判斷是否需要停止并打印向己的ID 。 def MyLoop(coord, worker_id):# 使用 tf.Coordinator 類提供的協(xié)同工具判斷當(dāng)前線程是否要停止。while not coord.should_stop():# 隨機(jī)停止所有的線程。if np.random.rand() < 0.1:print("Stoping from id: %d\n" % worker_id)# 調(diào)用 coord.request_stop() 函數(shù)來通知其他線程停止。coord.request_stop()else:# 打印當(dāng)前線程的Id。print("Working on id: %d\n" % worker_id)time.sleep(1)# 聲明一個 tf.train.Coordinator 類來協(xié)同多個線程。 coord = tf.train.Coordinator() # 聲明創(chuàng)建 5 個線程 threads = [threading.Thread(target=MyLoop, args=(coord, i)) for i in range(5)] # 啟動所有線程 for t in threads:t.start() # 等待所有線程退出 coord.join(threads)

    輸出

    Working on id: 0 Working on id: 1 Working on id: 2 Working on id: 3 Working on id: 4 Stoping from id: 0 Working on id: 2 Working on id: 3

    分析:主與所有線程啟動之后,每個線程會打印各自的 ID,于是前面 4 行打印出了它們的 ID 。然后在暫停 1 秒之后,所有線程又開始第二遍打印 ID。 在這個時候有一個線程退出的條件達(dá)到,于是調(diào)用了 coord.request_stop 函數(shù)來停止所有其他的線程。 然而在打印 Stoping from id: 0 之后,可以看到有線程仍然在輸出。這是因為這些線程已經(jīng)執(zhí)行完coord.should_stop的判斷,于是仍然會繼續(xù)輸出自己的 ID 。 但在下一輪判斷是否需要停止時將退出線程。 于是在打印一次 ID 之后就不會再有輸出了。

    (3)多線程協(xié)同方法2:tf.QueueRunner 類

    tf.QueueRunner類:用于啟動多個線程來操作同一個隊列,啟動的這些線程可以通過上面介紹的 tf.Coordinator 類來統(tǒng)一管理

    # 聲明一個先進(jìn)先出的隊列,隊列中最多100個元素,類型是實數(shù) queue = tf.FIFOQueue(100, "float") # 定義隊列的入隊操作 enqueue_op = queue.enqueue([tf.random_normal([1])])# 使用 tf.train.QueueRunner 創(chuàng)建多個線程運(yùn)行隊列的入隊操作。 # 第1個參數(shù):被操作的隊列, # [enqueue_op]*5 需要啟動5個線程,每個線程中運(yùn)行的是 enqueue_op 操作。 qr = tf.train.QueueRunner(queue, [enqueue_op] * 5)# 將定義過的QueueRunner加入TensorFlow 計算圖上指定的集合。 # tf.train.add_queue_runner 函數(shù)沒有指定集合,則加入默認(rèn)集合 tf.GraphKeys.QUEUE_RUNNERS。 # 下面的函數(shù)就是將剛剛定義的 qr 加入默認(rèn)的 tf.GraphKeys.QUEUE_RUNNERS 集合。 tf.train.add_queue_runner(qr) # 定義出隊操作。 out_tensor = queue.dequeue()with tf.Session() as sess:# 使用 tf.train.Coordinator 來協(xié)同啟動的線程。coord = tf.train.Coordinator()# 使用tf.train.QueueRunner時,需要明確調(diào)用tf.train.start_queue_runners來啟動所有線程。# 否則因為沒有線程運(yùn)行入隊操作,當(dāng)調(diào)用出隊操作時,程序會一直等待入隊操作被運(yùn)行。# tf.train.start_queue_runners 函數(shù)會默認(rèn)啟動tf.GraphKeys.QUEUE_RUNNERS集合中所有的QueueRunner。# 這個函數(shù)只支持啟動指定集合中的 QueueRnner,# 所以一般來說 tf.train.add_queue_runner 函數(shù)和tf.train.start_queue_runners函數(shù)會指定同一個集合。threads = tf.train.start_queue_runners(sess = sess, coord=coord)# 獲取隊列中的取值。for _ in range(3):print(sess.run(out_tensor)[0])# 使用 tf.train.Coordinator 來停止所有的線程。coord.request_stop()coord.join(threads)

    輸出結(jié)果

    -1.475753 -0.27835137 2.2407255

    2、輸入文件隊列

    雖然一個TFRecord文件可以存儲多個訓(xùn)練樣本,但當(dāng)訓(xùn)練數(shù)據(jù)量較大時,可以將數(shù)據(jù)分成多個TFRecord文件來提高處理效率。

  • 獲取一個正則表達(dá)式的所有文件: tf.train.match_filenames_once
  • 進(jìn)行有效的管理:tf.train.string_input_producer
  • 該函數(shù)會使用初始化時提供的文件列表創(chuàng)建一個輸入隊列,輸入隊列中的原始元素為文件列表中的所有文件,創(chuàng)建好的輸入隊列可以作為文件讀取函數(shù)的參數(shù),每層調(diào)用文件讀取函數(shù)時,該函數(shù)會先判斷當(dāng)前是否已經(jīng)有打開的文件可讀,如果沒有或者打開的文件已經(jīng)讀完,則該函數(shù)會從輸入隊列中出隊一個文件并從該文件中讀取數(shù)據(jù)。

    • 當(dāng) shuffle=True 時,文件在加入隊列之前會被打亂順序,所以出隊順序也是隨機(jī)的;
    • 隨機(jī)打亂文件順序以及加入輸入隊列的過程是一個單獨(dú)的線程,不會影響獲取文件的速度。
    • 當(dāng)輸入隊列中的所有文件都被處理完之后,會將初始化時提供的文件列表中的文件全部重新加入隊列。
    • num_epochs:限制加載初始文件列表的最大輪數(shù)
    • 當(dāng)設(shè)置為1時,計算完一輪之后,程序?qū)⒆詣油V埂?/li>
    • 神經(jīng)網(wǎng)絡(luò)模型測試時,所有測試數(shù)據(jù)僅僅需要使用一次即可,所以將其設(shè)置為1。
    # 創(chuàng)建 TFRecord 文件的幫助函數(shù)。 def _int64_feature(value):return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))# 模擬海量數(shù)據(jù)情況下將數(shù)據(jù)寫入不同文件 # num_shards : 總共寫入多少個文件, # instances_per_shard : 每個文件中有多少個數(shù)據(jù)。 num_shards = 2 instances_per_shard = 2 for i in range(num_shards):# 將數(shù)據(jù)分為多個文件時,可以將不同文件以類似 OOOOn-of-OOOOm 的后綴區(qū)分。# m:表示數(shù)據(jù)總共被存在了多少個文件中# n:表示當(dāng)前文件的編號# 式樣的方式既方便了通過正則表達(dá)式獲取文件列表,又在文件名中加入了更多的信息filename = ('./datasets/data.tfrecords-%.5d-of-%.5d' % (i, num_shards))writer = tf.python_io.TFRecordWriter(filename)# 將數(shù)據(jù)封裝成 Example 結(jié)構(gòu)并寫入 TFRecord 文件 。for j in range(instances_per_shard):# Example 結(jié)構(gòu)僅包含當(dāng)前樣例屬于第幾個文件以及是當(dāng)前文件的第幾個樣本。example = tf.train.Example(features=tf.train.Features(feature={'i':_int64_feature(i),'j':_int64_feature(j)}))writer.write(example.SerializeToString())writer.close()

    每一個文件中存儲了兩個樣例 。

    生成樣例之后,以下代碼展示了兩個函數(shù)的使用方法

    # 使用 tf.train.match_filenames_once 函數(shù)獲取文件列表。 files = tf.train.match_filenames_once('./datasets/data.tfrecords-*')# 通過 tf.train.string_input_producer 函數(shù)創(chuàng)建輸入隊列. # 輸入隊列巾的中的文件列表為tf.train.string_input_producer函數(shù)獲取的文件列表。 # 參數(shù)設(shè)置:shuffle為False,在一般解決真實問題時,shuffle設(shè)置為True filename_queue = tf.train.string_input_producer(files, shuffle=False)reader = tf.TFRecordReader() _, seraialized_example = reader.read(filename_queue) features = tf.parse_single_example(seraialized_example,features={'i':tf.FixedLenFeature([], tf.int64),'j':tf.FixedLenFeature([], tf.int64),})with tf.Session() as sess:# 雖然在本段程序中沒有聲明任何變量,# 但使用 tf.train.match_filenames_once 函數(shù)時前要初始化一些變量 。tf.local_variables_initializer().run()print(sess.run(files))# 聲明 tf.train.Coordinator 類來協(xié)同不同線程,并啟動線程。coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)# 多次執(zhí)行技取數(shù)據(jù)的操作。for i in range(6):print(sess.run([features['i'], features['j']]))coord.request_stop()coord.join(threads)

    輸出結(jié)果

    [b'./datasets/data.tfrecords-00000-of-00002'b'./datasets/data.tfrecords-00001-of-00002'] [0, 0] [0, 1] [1, 0] [1, 1] [0, 0] [0, 1]

    3、組合訓(xùn)練數(shù)據(jù)(batching)

    將多個輸入樣例組織成一個batch可以提高模型訓(xùn)練的效率,所以在得到單個樣例的預(yù)處理結(jié)果之后,還需要將其組織成batch,再提供給神經(jīng)網(wǎng)絡(luò)的輸入層。

  • tf.train.batch 和 tf.train.shuffle_batch 函數(shù)來將單個的樣例組織成 batch 的形式輸出。這兩個函數(shù)都會生成一個隊列,隊列的入隊操作是生成單個樣例的方法,而每次出隊得到的是一個 batch 的樣例 。
  • 唯一區(qū)別:是否會將數(shù)據(jù)順序打亂 。tf.train.shuffle_batch 為亂序。
  • (1)tf.train.batch

    import tensorflow as tf# 使用 tf.train.match_filenames_once 函數(shù)獲取文件列表。 files = tf.train.match_filenames_once('./datasets/data.tfrecords-*')# 通過 tf.train.string_input_producer 函數(shù)創(chuàng)建輸入隊列. # 輸入隊列巾的中的文件列表為tf.train.string_input_producer函數(shù)獲取的文件列表。 # 參數(shù)設(shè)置:shuffle為False,在一般解決真實問題時,shuffle設(shè)置為True filename_queue = tf.train.string_input_producer(files, shuffle=False)reader = tf.TFRecordReader() _, seraialized_example = reader.read(filename_queue) features = tf.parse_single_example(seraialized_example,features={'i':tf.FixedLenFeature([], tf.int64),'j':tf.FixedLenFeature([], tf.int64),})# 使用上面樣例。這里假設(shè) Example 結(jié)構(gòu)中 i 表示一個樣例的特征向量, # 比如一張圖像的像索矩陣。而 j 表示該樣例對應(yīng)的標(biāo)簽 。 example, label = features['i'], features['j']# 一個 batch 中樣例的個數(shù)。 batch_size = 3 # 文件隊列中最多可以存儲的樣例個數(shù) capacity = 1000 + 3 * batch_size# 使用 tf.train.batch 函數(shù)來組合樣例。[example, label]參數(shù)給出需組合的元素. # 當(dāng)隊列長度等于容量時,TF將暫停入隊操作,而只是等待元索出隊。 # 當(dāng)元素個數(shù)小于容量時, TF將自動重新啟動入隊操作。 example_batch, label_batch = tf.train.batch([example, label], batch_size=batch_size, capacity=capacity)with tf.Session() as sess:# tf.initialize_all_variables().run()tf.local_variables_initializer().run()coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)# 獲取并打印組合之后的樣例。在真實問題中,這個輸出一般會作為神經(jīng)網(wǎng)絡(luò)的輸入。for i in range(2):cur_example_batch, cur_label_batch = sess.run([example_batch, label_batch])print(cur_example_batch, cur_label_batch)coord.request_stop()coord.join(threads)

    報錯:因為使用match_filenames_once需要用local_variables_initializer初始化局部變量(local variables)沒有初始化

    • 局部變量初始化:tf.local_variables_initializer().run()
    OutOfRangeError (see above for traceback): FIFOQueue '_1_batch/fifo_queue' is closed and has insufficient elements (requested 3, current size 0)[[Node: batch = QueueDequeueManyV2[component_types=[DT_INT64, DT_INT64], timeout_ms=-1, _device="/job:localhost/replica:0/task:0/device:CPU:0"](batch/fifo_queue, batch/n)]]

    輸出結(jié)果

    [0 0 1] [0 1 0] [1 0 0] [1 0 1] # tf.train.batch 函數(shù)可以將單個的數(shù)據(jù)組織成3個一組的batch # 在example,lable中讀到的數(shù)據(jù)依次為: example:0, lable:0 example:0, lable:1 example:1, lable:0 example:1, lable:1 # 這是因為函數(shù)不會隨機(jī)打亂順序,所以組合之后得到的數(shù)據(jù)組合成了上面給出的輸出

    (2)tf.train.shuffle_batch

    tf.train.shuffle_batch 代碼示例如下:

    import tensorflow as tf# 獲取文件列表。 files = tf.train.match_filenames_once('./datasets/data.tfrecords-*')# 創(chuàng)建文件輸入隊列 filename_queue = tf.train.string_input_producer(files, shuffle=False)# 讀取并解析Example reader = tf.TFRecordReader() _, seraialized_example = reader.read(filename_queue) features = tf.parse_single_example(seraialized_example,features={'i':tf.FixedLenFeature([], tf.int64),'j':tf.FixedLenFeature([], tf.int64),})# i代表特征向量,j代表標(biāo)簽 example, label = features['i'], features['j']# 一個 batch 中樣例的個數(shù)。 batch_size = 3 # 文件隊列中最多可以存儲的樣例個數(shù) capacity = 1000 + 3 * batch_size# 組合樣例。 # `min_after_dequeue` 是該函數(shù)特有的參數(shù),參數(shù)限制了出隊時隊列中元素的最少個數(shù), # 但當(dāng)隊列元素個數(shù)太少時,隨機(jī)的意義就不大了 example_batch, label_batch = tf.train.shuffle_batch([example, label], batch_size=batch_size, capacity=capacity, min_after_dequeue=30)with tf.Session() as sess:# 使用match_filenames_once需要用local_variables_initializer初始化一些變量tf.local_variables_initializer().run()# 用Coordinator協(xié)同線程,并啟動線程coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)# 獲取并打印組合之后的樣例。在真實問題中,這個輸出一般會作為神經(jīng)網(wǎng)絡(luò)的輸入。for i in range(2):cur_example_batch, cur_label_batch = sess.run([example_batch, label_batch])print(cur_example_batch, cur_label_batch)coord.request_stop()coord.join(threads)

    輸出結(jié)果

    [0 0 0] [1 1 0] [0 0 1] [1 1 0]

    4、輸入數(shù)據(jù)處理框架

    框架主要是三方面的內(nèi)容:

    • TFRecord 輸入數(shù)據(jù)格式
    • 圖像數(shù)據(jù)處理
    • 多線程輸入數(shù)據(jù)處理
    import tensorflow as tf# 獲取文件列表。 files = tf.train.match_filenames_once('./datasets/data.tfrecords-*')# 創(chuàng)建文件輸入隊列 filename_queue = tf.train.string_input_producer(files, shuffle=False)# 讀取并解析Example reader = tf.TFRecordReader() _, seraialized_example = reader.read(filename_queue) features = tf.parse_single_example(seraialized_example,features={'image':tf.FixedLenFeature([], tf.string),'label':tf.FixedLenFeature([], tf.int64),'height':tf.FixedLenFeature([], tf.int64),'width':tf.FixedLenFeature([], tf.int64),'channels':tf.FixedLenFeature([], tf.int64),}) image, label = features['image'], features['label'] height, width = features['height'], features['width'] channels = features['channels']# 從原始圖像數(shù)據(jù)解析出像素矩陣,并根據(jù)圖像尺寸還原圖像。 decoded_image = tf.decoded_raw(image, tf.int8) decoded_image.set_shape([height, width, channels])# 定義神經(jīng)網(wǎng)絡(luò)輸入層圖片的大小。 image_size = 299# 圖像預(yù)處理 distorted_image = preprocess_for_train(decoded_image, image_size, image_size, None)# 將處理后的圖像和標(biāo)續(xù)數(shù)據(jù)通過 tf.train.shuffle_batch 整理成神經(jīng)網(wǎng)絡(luò)訓(xùn)練時需要的 batch, min_after_dequeue = 10000 batch_size = 100 capacity = min_after_dequeue + 3 * batch_size# 組合樣例。 # `min_after_dequeue` 是該函數(shù)特有的參數(shù),參數(shù)限制了出隊時隊列中元素的最少個數(shù), # 但當(dāng)隊列元素個數(shù)太少時,隨機(jī)的意義就不大了 image_batch, label_batch = tf.train.shuffle_batch([distorted_image, label], batch_size=batch_size, capacity=capacity, min_after_dequeue=min_after_dequeue)# 定義神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)以及優(yōu)化過程 learing_rate = 0.01 logit = inferenece(image_batch) loss = calc_loss(logit, label_batch) train_step = tf.train.GradientDescentOptimizer(learing_rate).minimize(loss)with tf.Session() as sess:# 使用match_filenames_once需要用local_variables_initializer初始化一些變量sess.run((tf.global_variables_initializer(), tf.local_variables_initializer()))# 用Coordinator協(xié)同線程,并啟動線程coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)# 神經(jīng)網(wǎng)絡(luò)訓(xùn)練過程TRAINING_ROUNDS = 5000for i in range(TRAINING_ROUNDS):sess.run(train_step)coord.request_stop()coord.join(threads)

    5、總結(jié)

    對于輸入數(shù)據(jù)的處理,大體上流程都差不多,可以歸結(jié)如下:

  • 將數(shù)據(jù)轉(zhuǎn)為 TFRecord 格式的多個文件
  • 用 tf.train.match_filenames_once() 創(chuàng)建文件列表(圖中為{A,B,C})
  • 用 tf.train.string_input_producer() 創(chuàng)建輸入文件隊列,可以將輸入文件順序隨機(jī)打亂,并加入輸入隊列(是否打亂為可選項,該函數(shù)也會生成并維護(hù)一個輸入文件隊列,不同進(jìn)程中的文件讀取函數(shù)可以共享這個輸入文件隊列)
  • 用 tf.TFRecordReader() 讀取文件中的數(shù)據(jù)
  • 用 tf.parse_single_example() 解析數(shù)據(jù)
  • 對數(shù)據(jù)進(jìn)行解碼及預(yù)處理
  • 用 tf.train.shuffle_batch() 將數(shù)據(jù)組合成 batch
  • 將 batch 用于訓(xùn)練
  • 四、數(shù)據(jù)集(DataSet)

    TF核心組件:tf.data。數(shù)據(jù)集框架中,每一個數(shù)據(jù)來源被抽象為一個數(shù)據(jù)集,以數(shù)據(jù)集為基本對象,方便地進(jìn)行 batching、隨機(jī)打亂( shuffle)等操作。

    1、數(shù)據(jù)集的基本使用方法

    由于訓(xùn)練數(shù)據(jù)通常無法全部寫入內(nèi)存中,從數(shù)據(jù)集中讀取數(shù)據(jù)時需要使用一個迭代器( iterator)按順序進(jìn)行讀取,數(shù)據(jù)集也是計算圖上的一個節(jié)點。

    (1)tensor -> 數(shù)據(jù)集

    示例:從一個張量創(chuàng)建一個數(shù)據(jù)集,遍歷這個數(shù)據(jù)集,并對每個輸入輸出 y=x2y=x^2y=x2 的值。

    import tensorflow as tf# 1.定義數(shù)據(jù)集構(gòu)造方法:從-個數(shù)組創(chuàng)建數(shù)據(jù)集 input_data = [1, 2, 3, 5, 8] dataset = tf.data.Dataset.from_tensor_slices(input_data)# 2.定義一個迭代器用于遍歷數(shù)據(jù)集 # 因為數(shù)據(jù)集定義時未用placeholder作為參數(shù),則此處用one_shot_iterator() iterator = dataset.make_one_shot_iterator() # 3.返回一個輸入數(shù)據(jù)的張量 x = iterator.get_next() y = x * xwith tf.Session() as sess:for i in range(len(input_data)):print(sess.run(y))

    輸出結(jié)果

    1 4 9 25 64

    數(shù)據(jù)集讀取數(shù)據(jù)有三個基本步驟:

  • 定義數(shù)據(jù)集的構(gòu)造方法:eg:tf.data.Dataset.from_tensor_slices
  • 定義遍歷器;
  • 使用 get_next() 方法從遍歷器中讀取數(shù)據(jù)張量,作為計算圖其他部分的輸入。
  • (2)文本文件 -> 數(shù)據(jù)集

    tf.data.TextLineDataset()函數(shù)

    TXT_FILE1 = './datasets/Text/1.txt' TXT_FILE2 = './datasets/Text/2.txt'input_files = [TXT_FILE1, TXT_FILE2] dataset = tf.data.TextLineDataset(input_files)# 定義一個迭代器用于遍歷數(shù)據(jù)集 iterator = dataset.make_one_shot_iterator() # 返回一個字符串類型的張量,代表文件中的一行。 x = iterator.get_next() with tf.Session() as sess:# 循環(huán)的次數(shù)為文檔中總共的行數(shù),否則會報錯for i in range(3):print(sess.run(x))

    結(jié)果輸出

    b'HELLO' b'MY FRIENDS!' b'AHHAHA'

    (3)TFRecord -> 數(shù)據(jù)集

    TFRecordDataset()函數(shù)讀取 TFRecord 形式的數(shù)據(jù)(常為圖像數(shù)據(jù)),因為每個 TFRecord 都有自己不同的 feature 格式,因此在讀取時,需提供一個 parse 函數(shù)進(jìn)行解析。

    # 解析一個 TFRecord 的方法。record是從文件中讀取的一個樣例。 def parser(record):# 解析讀入的一個樣例。features = tf.parse_single_example(record,features={'feat1': tf.FixedLenFeature([], tf.int64),'feat2': tf.FixedLenFeature([], tf.inp64)})return features['feat1'], features['feat2']# 從 TFRecord 文件創(chuàng)建數(shù)據(jù)集 FILE1_PATH = '' FILE2_PATH = '' input_files = [FILE1_PATH, FILE2_PATH] dataset = tf.dataset.TFRecordDataset(input_files) # 二進(jìn)制的數(shù)據(jù)# map()函數(shù)表示對數(shù)據(jù)集中的每一條數(shù)據(jù)進(jìn)行調(diào)用相應(yīng)方法。 # 通過 map() 來調(diào)用 parser() 對二進(jìn)制數(shù)據(jù)進(jìn)行解析。 dataset = dataset.map(parser)# 定義一個迭代器用于遍歷數(shù)據(jù)集 iterator = Dataset.make_one_shot_iterator()# feat1, feat2 是 parser() 返回的一維int64型張量,可以作為輸入用于進(jìn)一步的計算。feat1, feat2 = iterator.get_next()with tf.Session() as sess:for i in range(10):f1, f2 = sess.run([feat1, feat2])

    注意

    • 使用 one shot_iterator 時,數(shù)據(jù)集的所有參數(shù)必須已經(jīng)確定,因此不需要特別的初始化過程。
    • 使用 placeholder 初始化數(shù)據(jù)集,則需用 initializable_iterator 動態(tài)初始化數(shù)據(jù)集。如下所示
    # 解析一個 TFRecord 的方法。record是從文件中讀取的一個樣例。 def parser(record):# 解析讀入的一個樣例。features = tf.parse_single_example(record,features={'feat1': tf.FixedLenFeature([], tf.int64),'feat2': tf.FixedLenFeature([], tf.inp64)})return features['feat1'], features['feat2']FILE1_PATH = '' FILE2_PATH = ''# 從 TFRecord 文件創(chuàng)建數(shù)據(jù)集,具體文件路徑是一個 placeholder,稍后再提供路徑。 input_files = tf.placeholder(tf.string) dataset = tf.data.TFRecordDataset(input_files) dataset = dataset.map(parser)# 定義遍歷 dataset 的 initializable_iterator. iterator = dataset.make_initializable_iterator() feat1, feat2 = iterator.get_next()with tf.Session() as sess:# 首先初始化 interator,并給出 input_files 的值。sess.run(iterator.initializer,feed_dict={input_files: [FILE1_PATH, FILE2_PATH]})# 遍歷所有數(shù)據(jù)一個epoch。當(dāng)遍歷結(jié)束時,程序會拋出 OutOfRangeError。while True:try:sess.run([feat1, feat2])except tf.errors.OutOfRangeError as e:break

    上述示例通過使用placeholder和feed_dict的方式傳給數(shù)據(jù)集。

    注意:上面的循環(huán)體不是指定循環(huán)10次sess.run,而是使用while(True)try-except的形式來將所有數(shù)據(jù)遍歷一遍(即一個epoch),因為在動態(tài)指定輸入數(shù)據(jù)時,不同數(shù)據(jù)來源的數(shù)據(jù)量大小難以預(yù)知,而這個方法我們不必提前知道數(shù)據(jù)量的精確大小。

    2、數(shù)據(jù)集的高層操作

    (1)map操作

    dataset = dataset.map(parser)

    map(parser) 表示對數(shù)據(jù)集中每一條數(shù)據(jù)調(diào)用參數(shù)中指定的 parser 方法。對每一條數(shù)據(jù)進(jìn)行處理后,map將處理后的數(shù)據(jù)包裝成一個新的數(shù)據(jù)集返回。

    map可用于對數(shù)據(jù)的任何預(yù)處理操作。

    dataset = dataset.map(lambda x: preprocess_for_train(x, image_size, image_size, None))

    lambda表達(dá)式的作用:將原來有4個參數(shù)的函數(shù)轉(zhuǎn)化為只有1個參數(shù)的函數(shù)。第一個參數(shù)decoded_image 變成了 lambda 表達(dá)式中的 x ,后3個參數(shù)都被換成了具體的數(shù)值。注意這里的 image_size 是一個變量,有具體取值,該值需要在程序的上文中給出。

    在返回的新的數(shù)據(jù)集上,可以直接繼續(xù)調(diào)用其他高層操作,比如預(yù)處理、shuffle、batch等操作。==》更加干凈簡潔

    (2)shuffle 和 batch 操作

    dataset = dataset.shuffle(buffer_size) # 隨機(jī)打亂順序 dataset = dataset.batch(batch_size) # 將數(shù)據(jù)組合成batch

    其中buffer_size相當(dāng)于tf.train.shuffle_batch 的 min_after_dequeue 參數(shù)。shuffle 算法在內(nèi)部使用一個緩沖區(qū)中保存 buffer_size 條數(shù)據(jù),每讀入一條新數(shù)據(jù)時,從這個緩沖區(qū)中隨機(jī)選擇一條數(shù)據(jù)進(jìn)行輸出。緩沖區(qū)的大小越大,隨機(jī)的性能越好,但占用的內(nèi)存也越多 。

    batch方法中的 batch_size 參數(shù)表示要輸出的每個 batch 由多少條數(shù)據(jù)組成

    (3)repeat 操作

    作用:將數(shù)據(jù)集中的數(shù)據(jù)復(fù)制多份,其中每一份數(shù)據(jù)被稱為一個 epoch。

    dataset = dataset.repeat(N) # 將數(shù)據(jù)集重復(fù) N 份

    注意:如果數(shù)據(jù)集在 repeat 前己經(jīng)進(jìn)行了 shuffle 操作,輸出的每個 epoch 中隨機(jī) shuffle 的結(jié)果并不會相同 。repeat 和 map 、shuffle 、batch 等操作一樣,都只是計算圖中的一個計算節(jié)點 。repeat 只代表重復(fù)相同的處理過程,并不會記錄前一個epoch的處理結(jié)果。

    (4)其他操作

    • concatenate():將兩個數(shù)據(jù)集順序連接起來;
    • take(N):從數(shù)據(jù)集中讀取前 N 項數(shù)據(jù);
    • skip(N):在數(shù)據(jù)集中跳過前 N 項數(shù)據(jù);
    • flap_map():從多個數(shù)據(jù)集中輪流讀取數(shù)據(jù)。

    (5)示例

    從文件中讀取原始數(shù)據(jù),進(jìn)行預(yù)處理、shuffle、batching 等操作,并通過 repeat 方法訓(xùn)練多個 epoch。此外,測試集和訓(xùn)練集做了不同的預(yù)處理。在訓(xùn)練時,調(diào)用上小節(jié)中的 preprocess_for_train 方法對圖像進(jìn)行隨機(jī)反轉(zhuǎn)等預(yù)處理操作;而在測試時,測試數(shù)據(jù)以原本的樣子直接輸入測試。

    對數(shù)據(jù)依次進(jìn)行預(yù)處理、shuffle、batching操作

    import tensorflow as tf import tempfile# 1. 列舉輸入文件 TRAIN_PATH = 'output.tfrecords' TEST_PATH = 'output_test.tfrecords' train_files = tf.train.match_filenames_once(TRAIN_PATH) test_files = tf.train.match_filenames_once(TEST_PATH)# 2. 定義parser方法TFRecord中解析數(shù)據(jù) # 解析一個TFRecord的方法。 def parser(record):features = tf.parse_single_example(record,features={'image_raw':tf.FixedLenFeature([],tf.string),'pixels':tf.FixedLenFeature([],tf.int64),'label':tf.FixedLenFeature([],tf.int64)})decoded_images = tf.decode_raw(features['image_raw'],tf.uint8)retyped_images = tf.cast(decoded_images, tf.float32)images = tf.reshape(retyped_images, [784])labels = tf.cast(features['label'],tf.int32)#pixels = tf.cast(features['pixels'],tf.int32)return images, labelsimage = 299 # 定義神經(jīng)網(wǎng)絡(luò)輸入層圖片的大小 batch_size = 100 # 定義組合數(shù)據(jù) batch 的大小 shuffle_buffer = 10000 # 定義隨機(jī)打亂數(shù)據(jù)時buffer大小# 定義讀取訓(xùn)練集和測試集 dataset = tf.data.TFRecordDataset(train_files) dataset = dataset.map(parser)# 對數(shù)據(jù)依次進(jìn)行預(yù)處理、shuffle、batching操作 # dataset = dataset.map( # lambda image, label: ( # preprocess_for_train(image, image_size, image_size, None), label)) dataset = dataset.shuffle(shuffle_buffer).batch(batch_size)# 重復(fù)NUM_EPOCHS 個epoch NUM_EPOCHS = 10 dataset = dataset.repeat(NUM_EPOCHS)# 定義數(shù)據(jù)集迭代器。 iterator = dataset.make_initializable_iterator() image_batch, label_batch = iterator.get_next()# 4. 定義神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)和優(yōu)化過程 def inference(input_tensor, weights1, biases1, weights2, biases2):layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1)return tf.matmul(layer1, weights2) + biases2INPUT_NODE = 784 OUTPUT_NODE = 10 LAYER1_NODE = 500 REGULARAZTION_RATE = 0.0001 TRAINING_STEP = 5000weights1 = tf.Variable(tf.truncated_normal([INPUT_NODE, LAYER1_NODE], stddev=0.1)) biases1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE])) weights2 = tf.Variable(tf.truncated_normal([LAYER1_NODE, OUTPUT_NODE], stddev=0.1)) biases2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE]))y = inference(image_batch, weights1, biases1, weights2, biases2)# 計算交叉熵及其平均值 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=label_batch) cross_entropy_mean = tf.reduce_mean(cross_entropy)# 損失函數(shù)的計算 regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE) regularaztion = regularizer(weights1) + regularizer(weights2) loss = cross_entropy_mean + regularaztion# 優(yōu)化損失函數(shù) train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)# 5. 定義測試用數(shù)據(jù)集 # 定義測試用的Dataset。 test_dataset = tf.data.TFRecordDataset(test_files) test_dataset = test_dataset.map(parser) test_dataset = test_dataset.batch(batch_size)# 定義測試數(shù)據(jù)上的迭代器 test_iterator = test_dataset.make_initializable_iterator() test_image_batch, test_label_batch = test_iterator.get_next()# 定義測試數(shù)據(jù)上的預(yù)測結(jié)果 test_logit = inference(test_image_batch, weights1, biases1, weights2, biases2) predictions = tf.argmax(test_logit, axis=-1, output_type=tf.int32)# 聲明會話并運(yùn)行神經(jīng)網(wǎng)絡(luò)的優(yōu)化過程。 with tf.Session() as sess:# 初始化變量。sess.run((tf.global_variables_initializer(),tf.local_variables_initializer()))# 初始化訓(xùn)練數(shù)據(jù)的迭代器。sess.run(iterator.initializer)# 循環(huán)進(jìn)行訓(xùn)練,直到數(shù)據(jù)集完成輸入、拋出OutOfRangeError錯誤。while True:try:sess.run(train_step)except tf.errors.OutOfRangeError as e:break# 初始化測試數(shù)據(jù)的迭代器。test_results = []test_labels = []sess.run(test_iterator.initializer)while True:try:pred, label = sess.run([predictions, test_label_batch])test_results.extend(pred)test_labels.extend(label)except tf.errors.OutOfRangeError as e:break# 計算準(zhǔn)確率 correct = [float(y==y_) for (y, y_) in zip(test_results, test_labels)] accuarcy = sum(correct)/len(correct) print("Test accuarcy is: ", accuarcy)

    輸出結(jié)果

    Test accuarcy is: 0.9005

    總結(jié)

    以上是生活随笔為你收集整理的【TensorFlow】笔记5:图像数据处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。