ホーム » TensorFlow 2.0 » TensorFlow 2.0 : Tutorials : データのロードと前処理 :- TFRecord と tf.Example

TensorFlow 2.0 : Tutorials : データのロードと前処理 :- TFRecord と tf.Example

TensorFlow 2.0 : Beginner Tutorials : データのロードと前処理 :- TFRecord と tf.Example (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/09/2019

* 本ページは、TensorFlow org サイトの TF 2.0 – Beginner Tutorials – Load and preprocess data の以下のページを
翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/
Facebook: https://www.facebook.com/ClassCatJP/

 

データのロードと前処理 :- TFRecord と tf.Example

データを効率的に読むにはデータをシリアライズしてそれをそれぞれ線形に読めるファイルのセット (それぞれ 100-200MB) にストアすることが役立つかもしれません。これはデータがネットワークを通してストリームされている場合に特に真です。これはまた任意のデータ前処理をキャッシュするためにも有用かもしれません。

TFRecord 形式はバイナリ・レコードのシークエンスをストアするための単純な形式です。

protocol buffer は構造化データの効率的なシリアライゼーションのためのクロスプラットフォーム、クロス言語なライブラリです。

protocol message は .proto ファイルで定義されます、これらはしばしばメッセージ型を理解するための最も容易な方法です。

tf.Example メッセージ (or protobuf) は {“string”: value} マッピングを表わす柔軟なメッセージ型です。それは TensorFlow での利用のために設計されてそして TFX のような高位レベル API を通して使用されます。

このノートブックは tf.Example メッセージをどのように作成し、パースし、そして使用するか、そしてそれから .tfrecord ファイル to/from tf.Example メッセージをシリアライズし、書き、そして読むかを実演します。

Note: 有用である一方で、これらの構造はオプションです。既存のコードを TFRecords を使用するように変換する必要はありません、貴方が tf.data を使用していてそしてデータが依然として訓練のボトルネックでない限りは。データセットのパフォーマンス tips のためには Data Input Pipeline Performance を見てください。

 

セットアップ

from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf

import numpy as np
import IPython.display as display

 

tf.Example

tf.Example のためのデータ型

根本的には、tf.Example は {“string”: tf.train.Feature} マッピングです。

tf.train.Feature メッセージ型は次の 3 つの型の一つを受け取れます (リファレンスとして .proto ファイル 参照)。
殆どの他の generic 型はこれらの一つに強制できます :

  1. tf.train.BytesList (次の型が強制可能です)
    • string
    • byte
  2. tf.train.FloatList (次の型が強制可能です)
    • float (float32)
    • double (float64)
  3. tf.train.Int64List (次の型が強制可能です)
    • bool
    • enum
    • int32
    • uint32
    • int64
    • uint64

標準的な TensorFlow 型を tf.Example-互換 tf.train.Feature に変換するためには、下のショートカット関数を使用できます。各関数はスカラー入力値を取りそして上の 3 つのリスト型の一つを含む tf.train.Feature を返すことに注意してください :

# The following functions can be used to convert a value to a type compatible
# with tf.Example.

def _bytes_feature(value):
  """Returns a bytes_list from a string / byte."""
  if isinstance(value, type(tf.constant(0))):
    value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _float_feature(value):
  """Returns a float_list from a float / double."""
  return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))

def _int64_feature(value):
  """Returns an int64_list from a bool / enum / int / uint."""
  return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

Note: 単純であるために、このサンプルはスカラー入力を使用しているだけです。非スカラー特徴を処理する最も単純な方法は tensor をバイナリ文字列に変換するために tf.serialize_tensor を使用することです。文字列は tensorflow ではスカラーです。バイナリ文字列を tensor に変換し戻すためには tf.parse_tensor を使用します。

下はこれらの関数がどのように動作するかの幾つかのサンプルです。変化する入力型と標準化された出力型に注意してください。関数のための入力型が上で述べた強制可能な型の一つに適合しない場合には、関数は例外をあげます (e.g. _int64_feature(1.0) はエラーを出します、何故ならば 1.0 は float であるからです、従って代わりに _float_feature 関数により使用されるべきです) :

print(_bytes_feature(b'test_string'))
print(_bytes_feature(u'test_bytes'.encode('utf-8')))

print(_float_feature(np.exp(1)))

print(_int64_feature(True))
print(_int64_feature(1))
bytes_list {
  value: "test_string"
}

bytes_list {
  value: "test_bytes"
}

float_list {
  value: 2.7182817459106445
}

int64_list {
  value: 1
}

int64_list {
  value: 1
}

総ての proto メッセージは .SerializeToString メソッドを使用してバイナリ文字列にシリアライズできます :

feature = _float_feature(np.exp(1))

feature.SerializeToString()
b'\x12\x06\n\x04T\xf8-@'

 

tf.Example メッセージを作成する

既存のデータから tf.Example メッセージを作成することを望むとします。実際に、データセットはどこから由来することもできますが、単一の観測 (= observation) から tf.Example メッセージを作成する手続きは同じです :

  1. 各観測内で、各値は上の関数の一つを使用して、3 つの互換な型の一つを含む tf.train.Feature に変換される必要があります。
  2. 特徴名文字列から #1 で生成されたエンコードされた特徴値へのマップ (辞書) を作成します。
  3. ステップ 2 で生成されたマップは Features メッセージ に変換されます。

このノートブックでは、NumPy を使用してデータセットを作成します。

データセットは 4 つの特徴を持ちます : * boolean 特徴、同じ確率で False か True * 整数特徴、[0, 5] から一様にランダムに選択されます * 文字列特徴、整数特徴をインデックスとして使用して文字列テーブルから生成されます * float 特徴、標準正規分布から

各々の上の分布からの 10,000 の i.i.d. (独立同一分布) 観測から成るサンプルを考えます :

# The number of observations in the dataset.
n_observations = int(1e4)

# Boolean feature, encoded as False or True.
feature0 = np.random.choice([False, True], n_observations)

# Integer feature, random from 0 to 4.
feature1 = np.random.randint(0, 5, n_observations)

# String feature
strings = np.array([b'cat', b'dog', b'chicken', b'horse', b'goat'])
feature2 = strings[feature1]

# Float feature, from a standard normal distribution
feature3 = np.random.randn(n_observations)

これらの特徴の各々は _bytes_feature, _float_feature, _int64_feature の一つを使用して tf.Example-互換型に強制できます。それからこれらのエンコードされた特徴から tf.Example メッセージを作成できます :

def serialize_example(feature0, feature1, feature2, feature3):
  """
  Creates a tf.Example message ready to be written to a file.
  """
  # Create a dictionary mapping the feature name to the tf.Example-compatible
  # data type.
  feature = {
      'feature0': _int64_feature(feature0),
      'feature1': _int64_feature(feature1),
      'feature2': _bytes_feature(feature2),
      'feature3': _float_feature(feature3),
  }

  # Create a Features message using tf.train.Example.

  example_proto = tf.train.Example(features=tf.train.Features(feature=feature))
  return example_proto.SerializeToString()

例えば、データセットから単一の観測を持つと仮定します, [False, 4, bytes(‘goat’), 0.9876]。create_message() を使用して観測のための tf.Example メッセージを作成してプリントすることができます。各単一の観測は上のように Features メッセージとして書かれます。tf.Example メッセージ は Features メッセージ回りの単なるラッパーであることに注意してください :

# This is an example observation from the dataset.

example_observation = []

serialized_example = serialize_example(False, 4, b'goat', 0.9876)
serialized_example
b'\nR\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04[\xd3|?'

メッセージをデコードするために tf.train.Example.FromString メソッドを使用します。

example_proto = tf.train.Example.FromString(serialized_example)
example_proto
features {
  feature {
    key: "feature0"
    value {
      int64_list {
        value: 0
      }
    }
  }
  feature {
    key: "feature1"
    value {
      int64_list {
        value: 4
      }
    }
  }
  feature {
    key: "feature2"
    value {
      bytes_list {
        value: "goat"
      }
    }
  }
  feature {
    key: "feature3"
    value {
      float_list {
        value: 0.9876000285148621
      }
    }
  }
}

 

TFRecords 形式詳細

TFRecord ファイルはレコードのシークエンスを含みます。ファイルはシーケンシャルにのみ読むことができます。

各レコードはデータ・ペイロードのためのバイト文字列、 更にデータ長、そして整合性チェックのための CRC32 (Castagnoli polynomial を使用する 32-bit CRC) ハッシュを含みます。

各レコードは次の形式でストアされます :

uint64 length
uint32 masked_crc32_of_length
byte   data[length]
uint32 masked_crc32_of_data

レコードはファイルを生成するために一緒に結合されます。CRC は ここで説明されます、そして CRC のマスクは :

masked_crc = ((crc >> 15) | (crc << 17)) + 0xa282ead8ul

Note: TFRecord ファイルで tf.Example を使用する必要性はありません。tf.Example は辞書をバイト文字列にシリアライズするための単なる方法です。テキスト行、エンコードされた画像データ、あるいはシリアライズされた tensor (ロードするとき tf.io.serialize_tensortf.io.parse_tensor を使用して)。より多くのオプションについては tf.io モジュールを見てください。

 

tf.data を使用する TFRecord ファイル

tf.data モジュールはまた TensorFlow でデータを読み書きするためのツールも提供します。

 

TFRecord ファイルを書く

データをデータセットに得る最も容易な方法は from_tensor_slices メソッドを使用することです。

配列に適用されれば、それはスカラーのデータセットを返します :

tf.data.Dataset.from_tensor_slices(feature1)
<TensorSliceDataset shapes: (), types: tf.int64>

配列のタプルに適用されると、それはタプルのデータセットを返します :

features_dataset = tf.data.Dataset.from_tensor_slices((feature0, feature1, feature2, feature3))
features_dataset
<TensorSliceDataset shapes: ((), (), (), ()), types: (tf.bool, tf.int64, tf.string, tf.float64)>
# Use `take(1)` to only pull one example from the dataset.
for f0,f1,f2,f3 in features_dataset.take(1):
  print(f0)
  print(f1)
  print(f2)
  print(f3)
tf.Tensor(True, shape=(), dtype=bool)
tf.Tensor(4, shape=(), dtype=int64)
tf.Tensor(b'goat', shape=(), dtype=string)
tf.Tensor(1.6098582698561394, shape=(), dtype=float64)

Dataset の各要素に関数を適用するために tf.data.Dataset.map メソッドを使用します。

mapped 関数は TensorFlow グラフモードで作用しなければなりません — それは作用して tf.Tensor を返さなければなりません。create_example のような非 tensor 関数はそれを互換にするために tf.py_function でラップできます。

tf.py_function は (そうしないと利用可能でない) shape と型情報を指定することを必要とします :

def tf_serialize_example(f0,f1,f2,f3):
  tf_string = tf.py_function(
    serialize_example,
    (f0,f1,f2,f3),  # pass these args to the above function.
    tf.string)      # the return type is `tf.string`.
  return tf.reshape(tf_string, ()) # The result is a scalar
tf_serialize_example(f0,f1,f2,f3)
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xd6\x0f\xce?'>

この関数を dataset の各要素に適用します :

serialized_features_dataset = features_dataset.map(tf_serialize_example)
serialized_features_dataset
<MapDataset shapes: (), types: tf.string>
def generator():
  for features in features_dataset:
    yield serialize_example(*features)
serialized_features_dataset = tf.data.Dataset.from_generator(
    generator, output_types=tf.string, output_shapes=())
serialized_features_dataset
<FlatMapDataset shapes: (), types: tf.string>

そしてそれらを TFRecord ファイルに書きます :

filename = 'test.tfrecord'
writer = tf.data.experimental.TFRecordWriter(filename)
writer.write(serialized_features_dataset)

 

TFRecord ファイルを読む

tf.data.TFRecordDataset クラスを使用して TFRecord ファイルを読むこともできます。

tf.data を使用して TFRecord ファイルを消費するためのより多くの情報は ここ で見つかります。

TFRecordDatasets の使用は入力データを標準化してパフォーマンスを最適化するために有用かもしれません。

filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 shapes: (), types: tf.string>

この時点で dataset はシリアライズされた tf.train.Example メッセージを含みます。反復されたときそれはこれらをスカラー文字列 tensor として返します。

最初の 10 レコードを示すだけのために .take メソッドを使用します。

Note: tf.data.Dataset に渡る反復は eager execution が有効なときにだけ動作します。

for raw_record in raw_dataset.take(10):
  print(repr(raw_record))
<tf.Tensor: shape=(), dtype=string, numpy=b'\nR\n\x14\n\x08feature2\x12\x08\n\x06\n\x04goat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xd6\x0f\xce?\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x04'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nU\n\x17\n\x08feature2\x12\x0b\n\t\n\x07chicken\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\x04d\xa1?\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\tf.Tensor: shape=(), dtype=string, numpy=b'\nS\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x03\n\x15\n\x08feature2\x12\t\n\x07\n\x05horse\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xf7\xcb\xd3?'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xc9\x07\xaf?'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04a\xd4\xdb\xbd'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nS\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x03\n\x15\n\x08feature2\x12\t\n\x07\n\x05horse\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xfd\xb7\xb1\xbf'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nU\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x02\n\x17\n\x08feature2\x12\x0b\n\t\n\x07chicken\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xf8\x0e\x07@'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x00\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xee\x0f\xa4\xbf'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nU\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x02\n\x17\n\x08feature2\x12\x0b\n\t\n\x07chicken\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04\xf0\xa0\xb3>'>
<tf.Tensor: shape=(), dtype=string, numpy=b'\nQ\n\x13\n\x08feature2\x12\x07\n\x05\n\x03cat\n\x14\n\x08feature3\x12\x08\x12\x06\n\x04CX\xd6>\n\x11\n\x08feature0\x12\x05\x1a\x03\n\x01\x01\n\x11\n\x08feature1\x12\x05\x1a\x03\n\x01\x00'>

これらの tensor は下の関数を使用してパースされます。ここで feature_description が必要であることに注意してください、何故ならば dataset がグラフ実行を使用し、そしてそれらの shape と型シグネチャーを構築するためにこの記述を必要とするためです :

# Create a description of the features.
feature_description = {
    'feature0': tf.io.FixedLenFeature([], tf.int64, default_value=0),
    'feature1': tf.io.FixedLenFeature([], tf.int64, default_value=0),
    'feature2': tf.io.FixedLenFeature([], tf.string, default_value=''),
    'feature3': tf.io.FixedLenFeature([], tf.float32, default_value=0.0),
}

def _parse_function(example_proto):
  # Parse the input `tf.Example` proto using the dictionary above.
  return tf.io.parse_single_example(example_proto, feature_description)

代わりに、バッチ全体を一度にパースするために "tf.parse example" を使用します。tf.data.Dataset.map メソッドを使用してこの関数を dataset で各項目に適用します :

parsed_dataset = raw_dataset.map(_parse_function)
parsed_dataset
<MapDataset shapes: {feature0: (), feature1: (), feature2: (), feature3: ()}, types: {feature0: tf.int64, feature1: tf.int64, feature2: tf.string, feature3: tf.float32}>

dataset で観測を表示するために eager execution を使用します。この dataset には 10,000 観測がありますが、最初の 10 を表示するだけです。データは特徴の辞書として表示されます。各項目は tf.Tensor で、そしてこの tensor の numpy 要素は特徴の値を表示します :

for parsed_record in parsed_dataset.take(10):
  print(repr(parsed_record))
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=4>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'goat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=1.6098583>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'chicken'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=1.2608647>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=3>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'horse'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=1.654662>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=1.3674251>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-0.107338674>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=3>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'horse'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-1.3884274>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'chicken'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=2.1102886>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=-1.2817361>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=2>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'chicken'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.35083723>}
{'feature0': <tf.Tensor: shape=(), dtype=int64, numpy=1>, 'feature1': <tf.Tensor: shape=(), dtype=int64, numpy=0>, 'feature2': <tf.Tensor: shape=(), dtype=string, numpy=b'cat'>, 'feature3': <tf.Tensor: shape=(), dtype=float32, numpy=0.41864213>}

ここで、tf.parse_example 関数は tf.Example フィールドを標準 tensor にアンパックします。

 

Python の TFRecord ファイル

tf.io モジュールはまた TFRecord ファイルを読み書きするために pure-Python 関数もまた含みます。

 

TFRecord ファイルを書く

次に、10,000 観測をファイル test.tfrecord に書きます。各観測は tf.Example メッセージに変換されて、それからファイルに書かれます。それからファイル test.tfrecord が作成されたことを確認できます :

# Write the `tf.Example` observations to the file.
with tf.io.TFRecordWriter(filename) as writer:
  for i in range(n_observations):
    example = serialize_example(feature0[i], feature1[i], feature2[i], feature3[i])
    writer.write(example)
!du -sh {filename}
984K    test.tfrecord

 

TFRecord ファイルを読む

これらのシリアライズされた tensor は tf.train.Example.ParseFromString を使用して容易にパースできます :

filenames = [filename]
raw_dataset = tf.data.TFRecordDataset(filenames)
raw_dataset
<TFRecordDatasetV2 shapes: (), types: tf.string>
for raw_record in raw_dataset.take(1):
  example = tf.train.Example()
  example.ParseFromString(raw_record.numpy())
  print(example)
features {
  feature {
    key: "feature0"
    value {
      int64_list {
        value: 1
      }
    }
  }
  feature {
    key: "feature1"
    value {
      int64_list {
        value: 4
      }
    }
  }
  feature {
    key: "feature2"
    value {
      bytes_list {
        value: "goat"
      }
    }
  }
  feature {
    key: "feature3"
    value {
      float_list {
        value: 1.6098582744598389
      }
    }
  }
}

 

ウォークスルー : 画像データを読み書きする

これは TFRecord を使用してどのように画像データを読み書きするかのサンプルです。これの目的はどのように入力データ (この場合は画像) を TFRecord ファイルとして書いて、それからファイルを読み戻して画像を表示するかを end-to-end で示すことです。

これは有用です、例えば、同じ入力データセット上で幾つかのモデルを使用することを望むのであれば。画像データを生でストアする代わりに、それは TFRecord 形式に前処理できて、そしれそれは総てのそれ以上の処理とモデリングで使用できます。

最初に雪の中の猫の この画像 と建設中の Williamsburg Bridge, NYC の この写真 をダウンロードしましょう。

 

画像を取得する

cat_in_snow  = tf.keras.utils.get_file('320px-Felis_catus-cat_on_snow.jpg', 'https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg')
williamsburg_bridge = tf.keras.utils.get_file('194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg')
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/320px-Felis_catus-cat_on_snow.jpg
24576/17858 [=========================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/194px-New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg
16384/15477 [===============================] - 0s 0us/step
display.display(display.Image(filename=cat_in_snow))
display.display(display.HTML('Image cc-by: <a "href=https://commons.wikimedia.org/wiki/File:Felis_catus-cat_on_snow.jpg">Von.grzanka'))

Image cc-by: Von.grzanka
display.display(display.Image(filename=williamsburg_bridge))
display.display(display.HTML('<a "href=https://commons.wikimedia.org/wiki/File:New_East_River_Bridge_from_Brooklyn_det.4a09796u.jpg">From Wikimedia'))

From Wikimedia

 

TFRecord ファイルを書く

前のように、特徴を tf.Example と互換な型としてエンコードします。これは生画像文字列特徴に加えて高さ、幅、depth、そして任意のラベル特徴をストアします。後者は猫画像と橋画像の間を識別するためにファイルを書くときに使用されます。猫画像のために 0、そして橋画像のために 1 を使用します :

image_labels = {
    cat_in_snow : 0,
    williamsburg_bridge : 1,
}
# This is an example, just using the cat image.
image_string = open(cat_in_snow, 'rb').read()

label = image_labels[cat_in_snow]

# Create a dictionary with features that may be relevant.
def image_example(image_string, label):
  image_shape = tf.image.decode_jpeg(image_string).shape

  feature = {
      'height': _int64_feature(image_shape[0]),
      'width': _int64_feature(image_shape[1]),
      'depth': _int64_feature(image_shape[2]),
      'label': _int64_feature(label),
      'image_raw': _bytes_feature(image_string),
  }

  return tf.train.Example(features=tf.train.Features(feature=feature))

for line in str(image_example(image_string, label)).split('\n')[:15]:
  print(line)
print('...')
features {
  feature {
    key: "depth"
    value {
      int64_list {
        value: 3
      }
    }
  }
  feature {
    key: "height"
    value {
      int64_list {
        value: 213
      }
...

特徴の総てが今は tf.Example メッセージにストアされていることに気付いてください。次に、上のコードを機能的にして example メッセージを images.tfrecords という名前のファイルに書きます :

# Write the raw image files to `images.tfrecords`.
# First, process the two images into `tf.Example` messages.
# Then, write to a `.tfrecords` file.
record_file = 'images.tfrecords'
with tf.io.TFRecordWriter(record_file) as writer:
  for filename, label in image_labels.items():
    image_string = open(filename, 'rb').read()
    tf_example = image_example(image_string, label)
    writer.write(tf_example.SerializeToString())
!du -sh {record_file}
36K images.tfrecords

 

TFRecord ファイルを読む

貴方は今はファル —images.tfrecords— を持ちます、そして貴方が書いたものを読む戻すためにその中のレコードに渡り反復できます。このサンプルで画像を再生成するだけとすれば、必要な唯一の特徴は生画像文字列です。上で説明された getter を使用してそれを抽出します、つまり example.features.feature['image_raw'].bytes_list.value[0] です。どこレコードが猫でそしてどれが橋であるかを決定するためにラベルも使用できます :

raw_image_dataset = tf.data.TFRecordDataset('images.tfrecords')

# Create a dictionary describing the features.
image_feature_description = {
    'height': tf.io.FixedLenFeature([], tf.int64),
    'width': tf.io.FixedLenFeature([], tf.int64),
    'depth': tf.io.FixedLenFeature([], tf.int64),
    'label': tf.io.FixedLenFeature([], tf.int64),
    'image_raw': tf.io.FixedLenFeature([], tf.string),
}

def _parse_image_function(example_proto):
  # Parse the input tf.Example proto using the dictionary above.
  return tf.io.parse_single_example(example_proto, image_feature_description)

parsed_image_dataset = raw_image_dataset.map(_parse_image_function)
parsed_image_dataset
<MapDataset shapes: {depth: (), height: (), image_raw: (), label: (), width: ()}, types: {depth: tf.int64, height: tf.int64, image_raw: tf.string, label: tf.int64, width: tf.int64}>

TFRecord ファイルから画像をリカバーします :

for image_features in parsed_image_dataset:
  image_raw = image_features['image_raw'].numpy()
  display.display(display.Image(data=image_raw))
 

以上



AI導入支援 #2 ウェビナー

スモールスタートを可能としたAI導入支援   Vol.2
[無料 WEB セミナー] [詳細]
「画像認識 AI PoC スターターパック」の紹介
既に AI 技術を実ビジネスで活用し、成果を上げている日本企業も多く存在しており、競争優位なビジネスを展開しております。
しかしながら AI を導入したくとも PoC (概念実証) だけでも高額な費用がかかり取組めていない企業も少なくないようです。A I導入時には欠かせない PoC を手軽にしかも短期間で認知度を確認可能とするサービの紹介と共に、AI 技術の特性と具体的な導入プロセスに加え運用時のポイントについても解説いたします。
日時:2021年10月13日(水)
会場:WEBセミナー
共催:クラスキャット、日本FLOW(株)
後援:働き方改革推進コンソーシアム
参加費: 無料 (事前登録制)
人工知能開発支援
◆ クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com