tf.data学習ガイド(超実用、超詳細)
42087 ワード
tf.dataはtensorflow 2でさえ極めて使いやすいデータ読み出しパイプで構築されたAPIである.0では、キューなどの他の方法に完全に代わっています.このAPIを使用してデータパイプを構築し、主に2つのAPIに依存します. tf.data.Dataset tf.data.Iterator
tf.data.Datasetは、データの読み込み、前処理、batchやepochなどの通常の操作の調整に使用されますが、読み取りデータはIteratorインタフェースに依存します.両者の関係はPytorchのDatasetとDataLoaderに似ている.なお、Tensorflow 2とtensorflow 1世代の特性が異なるため、本稿では2つの部分に分けてtfについて説明する.dataの2つのバージョンでの使い方.
共通の基礎知識
ファイル名とラベルは既知で、dataで各ファイルのアドレスを保存し、labelで各ファイルに対応するラベルを保存します.dataとlabelはいずれもリストであり、data=[‘xxxx.jpg’,‘qqq.jpg’,...]の形式である.label = [0,2,3,4,1,…]
上記のコードにより,訓練データの画像アドレスが得られたが,labelについては,私が例示しただけなので,全0のlabelが生成され,長さは読み取った画像アドレスと一致した.
まず、最も簡単で最もよく使われる方法を見て、tfを使用します.data.Dataset.from_tensor_slices
これはdatasetを構築したとしても.tf.data.Datasetクラスにはいくつかの関数がよく使用されます. batch() repeat() shuffle() map() zip()/後で紹介しますが、あまり使われていませんが、機能は強いです.
batch():パラメータとして整数値を用いてbatchのbatch sizeを記述した.repeat():パラメータは同じ整数値であり、dataset全体が何回(epoch)繰り返される必要があるかを記述し、パラメータがなければ無限に繰り返される.shuffle():名前の通りmap():プリプロセッシング、画像復号などの操作としてよく用いられ、パラメータは関数ハンドルであり、datasetの各要素はこの関数を通って新しいtensorに元の要素の代わりになる.
次に,Iteratorと組み合わせて以上の4つの手法の使用を理解する.
Tensorflow 1.xでのパイプの構築
tf.data.Dataset.make_one_shot_iterator() tf.data.Dataset.make_initializable_iterator() make_one_shot_iteratorはユーザ表示で初期化する必要はありませんが、データセットを1回だけ反復(遍歴)できます. make_initializable_iteratorは、ユーザが表示して初期化する必要があり、初期化時に間で定義されたplaceholderに送ることができ、より柔軟な使用を達成することができる.
反復器にget_がありますnextメソッドは、データのtensorsを取得します.このtensorsの意味は、データセットの構築に使用されるfrom_tensors_sliceのパラメータ形式.
2つの例を見てみましょう.
私たちがdatasetに送った内容が画像の経路情報であるため、出力されたのは画像名であることがわかりましたが、今は画像データを読み取りたいと思っています.これはmapメソッドを使用する必要があります.まず、画像を読み込む関数をカスタマイズします.
次にdatasetのbatchメソッドを用いて,batchを1回ずつ読み出す.
次にrepeatを使用してデータセットを2回繰り返します.次に、合計をグローバル変数countで記録し、82*2=164に等しいかどうかを確認します.
OK、確かに私たちが考えているように.
またtf.data.Dataset.make_initializable_iterator()この方法は初期化可能な反復器を返します.ユーザーはsessを使用する必要があります.run(iterator.initializer)は初期化を表示します.
反復器を初期化したとき、batchsizeが20であったことがわかり、最初に反復したbatchは20サンプルで、全部で82個が故障していないことがわかります.2回目に反復器を初期化するとき、batchsizeは40に設定されているので、2回目の反復batchは40サンプルで、全部で82サンプルで、問題はありません.
Note:tf.Dataには、反復器とfeeding反復器を再初期化することもできます.基本的には以上の2つの反復器に機能的に代わることができるので、紹介しません.詳細についてはhereを参照してください
また、反復器の状態は保存できます.例えば、訓練が半分になり、サンプルがどこに読み込まれたのか、この状態を保存し、次はインポートモデルを実行し、その後、前回の状態に続いて実行します.
Tensorflow 2.0でパイプを作成
tf.data.Datasetは、データの読み込み、前処理、batchやepochなどの通常の操作の調整に使用されますが、読み取りデータはIteratorインタフェースに依存します.両者の関係はPytorchのDatasetとDataLoaderに似ている.なお、Tensorflow 2とtensorflow 1世代の特性が異なるため、本稿では2つの部分に分けてtfについて説明する.dataの2つのバージョンでの使い方.
共通の基礎知識
どのバージョンにおいても、1世代と2世代はデータセットを構築する上で同じであり、異なる点はtfにある.data.Iteratorがどのように使うか、つまりデータを読み取る方法が違います.このセクションでは、tfを構築する方法について説明します.data.Datasetモジュール.
import tensorflow as tf
import tensorflow.contrib.eager as tfe
import os
# tf.enable_eager_execution()
file_path = r'E:\dataset\DAVIS\JPEGImages\480p\bear'
data= [os.path.join(file_path,i) for i in os.listdir(file_path)]
label = [0]*len(data)
print(data)
print(len(label))
#['E:\\dataset\\DAVIS\\JPEGImages\\480p\\bear\\00000.jpg', 'E:\\dataset\\DAVIS\\JPEGImages\\480p\\bear\\00001.jpg',
......]
#82
上記のコードにより,訓練データの画像アドレスが得られたが,labelについては,私が例示しただけなので,全0のlabelが生成され,長さは読み取った画像アドレスと一致した.
まず、最も簡単で最もよく使われる方法を見て、tfを使用します.data.Dataset.from_tensor_slices
dataset = tf.data.Dataset.from_tensor_slices((data,label))
print(datset)
#
これはdatasetを構築したとしても.tf.data.Datasetクラスにはいくつかの関数がよく使用されます.
batch():パラメータとして整数値を用いてbatchのbatch sizeを記述した.repeat():パラメータは同じ整数値であり、dataset全体が何回(epoch)繰り返される必要があるかを記述し、パラメータがなければ無限に繰り返される.shuffle():名前の通りmap():プリプロセッシング、画像復号などの操作としてよく用いられ、パラメータは関数ハンドルであり、datasetの各要素はこの関数を通って新しいtensorに元の要素の代わりになる.
次に,Iteratorと組み合わせて以上の4つの手法の使用を理解する.
Tensorflow 1.xでのパイプの構築
データセットdatasetタイプのデータインタフェースを取得するには、Iteratorを使用します.Datasetタイプは、反復器を直接生成する関数を提供します.
反復器にget_がありますnextメソッドは、データのtensorsを取得します.このtensorsの意味は、データセットの構築に使用されるfrom_tensors_sliceのパラメータ形式.
2つの例を見てみましょう.
import tensorflow as tf
import tensorflow.contrib.eager as tfe
import os
# tf.enable_eager_execution() #
file_path = r'E:\dataset\DAVIS\JPEGImages\480p\bear'
data = [os.path.join(file_path,i) for i in os.listdir(file_path)]
label = [0]*len(data)
# print(data)
# print(len(label))
dataset = tf.data.Dataset.from_tensor_slices((data,label))
# print(dataset)
iterator = dataset.make_one_shot_iterator()
img_name, label = iterator.get_next()
with tf.Session() as sess:
while 1:
try:
name, num = sess.run([img_name,label])
print(name)
assert num == 0, "fail to read label"
except tf.errors.OutOfRangeError:
print("iterator done")
break
# b'E:\\dataset\\DAVIS\\JPEGImages\\480p\\bear\\00000.jpg'
# b'E:\\dataset\\DAVIS\\JPEGImages\\480p\\bear\\00001.jpg'
# b'E:\\dataset\\DAVIS\\JPEGImages\\480p\\bear\\00002.jpg'
# .....
# iterator done
私たちがdatasetに送った内容が画像の経路情報であるため、出力されたのは画像名であることがわかりましたが、今は画像データを読み取りたいと思っています.これはmapメソッドを使用する必要があります.まず、画像を読み込む関数をカスタマイズします.
def _parse_function(filename, label):
image_string = tf.read_file(filename)
image_decoded = tf.image.decode_jpeg(image_string,channels=3)
image_resized = tf.image.resize_images(image_decoded, [224, 224])
return image_resized, label
file_path = r'E:\dataset\DAVIS\JPEGImages\480p\bear'
data = [os.path.join(file_path,i) for i in os.listdir(file_path)]
label = [0]*len(data)
# print(data)
# print(len(label))
dataset = tf.data.Dataset.from_tensor_slices((data,label))
dataset = dataset.map(_parse_function) #
# print(dataset)
iterator = dataset.make_one_shot_iterator()
img, label = iterator.get_next()
with tf.Session() as sess:
while 1:
try:
image, num = sess.run([img,label])
print(image.shape)
assert num == 0, "fail to read label"
except tf.errors.OutOfRangeError:
print("iterator done")
break
# ....
# (224, 224, 3)
# (224, 224, 3)
# (224, 224, 3)
# iterator done
次にdatasetのbatchメソッドを用いて,batchを1回ずつ読み出す.
dataset = tf.data.Dataset.from_tensor_slices((data,label))
dataset = dataset.map(_parse_function)
dataset = dataset.batch(5)
# ,
(5, 224, 224, 3)
(5, 224, 224, 3)
(2, 224, 224, 3)
iterator done
82 , 2 batch。
次にrepeatを使用してデータセットを2回繰り返します.次に、合計をグローバル変数countで記録し、82*2=164に等しいかどうかを確認します.
file_path = r'E:\dataset\DAVIS\JPEGImages\480p\bear'
data = [os.path.join(file_path,i) for i in os.listdir(file_path)]
label = [0]*len(data)
# print(data)
# print(len(label))
dataset = tf.data.Dataset.from_tensor_slices((data,label))
dataset = dataset.map(_parse_function)
dataset = dataset.batch(1) # 1,
dataset = dataset.repeat(2) #
# print(dataset)
iterator = dataset.make_one_shot_iterator()
img, label = iterator.get_next()
count = 0
with tf.Session() as sess:
while 1:
try:
image, num = sess.run([img,label])
print(image.shape)
count += 1
except tf.errors.OutOfRangeError:
print("iterator done")
print("count is ",count) # conut
break
# ....
(1, 224, 224, 3)
(1, 224, 224, 3)
iterator done
count is 164
OK、確かに私たちが考えているように.
またtf.data.Dataset.make_initializable_iterator()この方法は初期化可能な反復器を返します.ユーザーはsessを使用する必要があります.run(iterator.initializer)は初期化を表示します.
import tensorflow as tf
import tensorflow.contrib.eager as tfe
import os
# tf.enable_eager_execution()
from read import _parse_function as _parse_function
file_path = r'E:\dataset\DAVIS\JPEGImages\480p\bear'
data = [os.path.join(file_path,i) for i in os.listdir(file_path)]
label = [0]*len(data)
dataset = tf.data.Dataset.from_tensor_slices((data,label))
dataset = dataset.map(_parse_function)
batch_size = tf.placeholder(tf.int64,shape=[])
dataset = dataset.batch(batch_size)
dataset = dataset.repeat(1)
iterator = dataset.make_initializable_iterator()
img, label = iterator.get_next()
with tf.Session() as sess:
sess.run(iterator.initializer, feed_dict={
batch_size: 20})
while 1:
try:
image, num = sess.run([img,label])
print(image.shape)
except tf.errors.OutOfRangeError:
print("second iterator done")
break
sess.run(iterator.initializer, feed_dict={
batch_size: 40}) # batchsize
while 1:
try:
image, num = sess.run([img,label])
print(image.shape)
except tf.errors.OutOfRangeError:
print("first iterator done")
break
#
# (20, 224, 224, 3)
(20, 224, 224, 3)
(20, 224, 224, 3)
(20, 224, 224, 3)
(2, 224, 224, 3)
first iterator done
(40, 224, 224, 3)
(40, 224, 224, 3)
(2, 224, 224, 3)
second iterator done
反復器を初期化したとき、batchsizeが20であったことがわかり、最初に反復したbatchは20サンプルで、全部で82個が故障していないことがわかります.2回目に反復器を初期化するとき、batchsizeは40に設定されているので、2回目の反復batchは40サンプルで、全部で82サンプルで、問題はありません.
Note:tf.Dataには、反復器とfeeding反復器を再初期化することもできます.基本的には以上の2つの反復器に機能的に代わることができるので、紹介しません.詳細についてはhereを参照してください
また、反復器の状態は保存できます.例えば、訓練が半分になり、サンプルがどこに読み込まれたのか、この状態を保存し、次はインポートモデルを実行し、その後、前回の状態に続いて実行します.
saveable_iter = tf.data.experimental.make_saveable_from_iterator(iterator)
tf.compat.v1.add_to_collections(tf.GraphKeys.SAVEABLE_OBJECTS,saveable_iter)
saver = tf.train.Saver()
with tf.Session() as sess:
.....
saver.save(path_to_checkpoint)
# restore the state of iterator
with tf.Session() as sess:
saver.restore(sess,path_to_checkpoint)
Tensorflow 2.0でパイプを作成
TF2.0はPyTrochと同様のeagerモードをサポートするので,このモードではsessionとplacehoderは破棄される.この場合、取得データの読み出しインタフェースは、tf 1のみとなる.xは少し違いますが、もっと簡単で使いやすいです.
私たちはdatasetを構築した後、python内蔵関数iterだけでいいです.例:import tensorflow as tf
import tensorflow.contrib.eager as tfe
import os
tf.enable_eager_execution() # eager , 1.13.1, 2.0,
from read import _parse_function as _parse_function
file_path = r'E:\dataset\DAVIS\JPEGImages\480p\bear'
data = [os.path.join(file_path,i) for i in os.listdir(file_path)]
label = [0]*len(data)
dataset = tf.data.Dataset.from_tensor_slices((data,label))
dataset = dataset.map(_parse_function)
dataset = dataset.batch(40)
dataset = dataset.repeat(1)
iterator = iter(dataset)
while 1:
try:
image, _ = next(iterator)
print(image.shape)
except StopIteration: # python
print("iterator done")
break;
#
(40, 224, 224, 3)
(40, 224, 224, 3)
(2, 224, 224, 3)
iterator done
import tensorflowも使えます.contrib.eager as tfeがサポートするIteratorクラス生成反復器.... #
iterator = tfe.Iterator(dataset)
for img, _ in iterator:
print(img.shape)
# (40, 224, 224, 3)
(40, 224, 224, 3)
(2, 224, 224, 3)
リファレンスリンク
[0.2]Tensorflow踏坑記の頭痛のtf.Data TensorFlowの新しいデータ読み出し方式:Dataset API入門チュートリアルGitHubの前の例cs 230カリキュラムTensorFlow tf.dataインポートデータ(tf.data公式チュートリアル)
import tensorflow as tf
import tensorflow.contrib.eager as tfe
import os
tf.enable_eager_execution() # eager , 1.13.1, 2.0,
from read import _parse_function as _parse_function
file_path = r'E:\dataset\DAVIS\JPEGImages\480p\bear'
data = [os.path.join(file_path,i) for i in os.listdir(file_path)]
label = [0]*len(data)
dataset = tf.data.Dataset.from_tensor_slices((data,label))
dataset = dataset.map(_parse_function)
dataset = dataset.batch(40)
dataset = dataset.repeat(1)
iterator = iter(dataset)
while 1:
try:
image, _ = next(iterator)
print(image.shape)
except StopIteration: # python
print("iterator done")
break;
#
(40, 224, 224, 3)
(40, 224, 224, 3)
(2, 224, 224, 3)
iterator done
.... #
iterator = tfe.Iterator(dataset)
for img, _ in iterator:
print(img.shape)
# (40, 224, 224, 3)
(40, 224, 224, 3)
(2, 224, 224, 3)
[0.2]Tensorflow踏坑記の頭痛のtf.Data TensorFlowの新しいデータ読み出し方式:Dataset API入門チュートリアルGitHubの前の例cs 230カリキュラムTensorFlow tf.dataインポートデータ(tf.data公式チュートリアル)