1、使用 tf.data 加载 pandas dataframes
1 2 3 4 | from __future__ import absolute_import, division, print_function, unicode_literals import pandas as pd import tensorflow as tf |
使用 pandas 读取 csv 文件。
1 2 3 4 5 6 | csv_file = tf.keras.utils.get_file('heart.csv', 'https://storage.googleapis.com/applied-dl/heart.csv') df = pd.read_csv(csv_file) df.head() df.dtypes |

将 thal 列(数据帧(dataframe)中的 object )转换为离散数值。
1 2 3 4 | df['thal'] = pd.Categorical(df['thal']) df['thal'] = df.thal.cat.codes df.head() |

1 2 3 4 5 6 | target = df.pop('target') dataset = tf.data.Dataset.from_tensor_slices((df.values, target.values)) for feat, targ in dataset.take(5): print ('Features: {}, Target: {}'.format(feat, targ)) |

1 | train_dataset = dataset.shuffle(len(df)).batch(1) |
创建并训练模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def get_compiled_model(): model = tf.keras.Sequential([ tf.keras.layers.Dense(10, activation='relu'), tf.keras.layers.Dense(10, activation='relu'), tf.keras.layers.Dense(1, activation='sigmoid') ]) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) return model model = get_compiled_model() model.fit(train_dataset, epochs=15) |

2、用 tf.data 加载图片
配置
1 2 3 4 | from __future__ import absolute_import, division, print_function, unicode_literals import tensorflow as tf AUTOTUNE = tf.data.experimental.AUTOTUNE |
下载数据集
1 2 3 4 5 | import pathlib data_root_orig = tf.keras.utils.get_file(origin='https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz', fname='flower_photos', untar=True) data_root = pathlib.Path(data_root_orig) print(data_root) |

1 2 | for item in data_root.iterdir(): print(item) |

1 2 3 4 5 6 7 | import random all_image_paths = list(data_root.glob('*/*')) all_image_paths = [str(path) for path in all_image_paths] random.shuffle(all_image_paths) image_count = len(all_image_paths) image_count |

1 | all_image_paths[:10] |

列出可用的标签:
1 2 | label_names = sorted(item.name for item in data_root.glob('*/') if item.is_dir()) label_names |

为每个标签分配索引:
1 2 3 | # 为每个标签分配索引: label_to_index = dict((name, index) for index, name in enumerate(label_names)) label_to_index |

创建一个列表,包含每个文件的标签索引:
1 2 3 4 | all_image_labels = [label_to_index[pathlib.Path(path).parent.name] for path in all_image_paths] print("First 10 labels indices: ", all_image_labels[:10]) |

加载和格式化图片
1 2 3 4 5 6 7 8 9 10 11 12 | def preprocess_image(image): # 将它解码为图像 tensor(张量): image = tf.image.decode_jpeg(image, channels=3) image = tf.image.resize(image, [192, 192]) image /= 255.0 # normalize to [0,1] range return image def load_and_preprocess_image(path): image = tf.io.read_file(path) return preprocess_image(image) |
1 2 3 4 5 6 7 8 9 10 | import matplotlib.pyplot as plt img_path = all_image_paths[0] label = all_image_labels[0] plt.imshow(load_and_preprocess_image(img_path)) plt.grid(False) plt.xlabel(img_path) plt.title(label_names[label].title()) print() |

将字符串数组切片,得到一个字符串数据集:
1 2 3 | # 构建一个 tf.data.Dataset path_ds = tf.data.Dataset.from_tensor_slices(all_image_paths) print(path_ds) |
1 | <TensorSliceDataset shapes: (), types: tf.string> |
现在创建一个新的数据集,通过在路径数据集上映射 preprocess_image 来动态加载和格式化图片。
1 2 | image_ds = path_ds.map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE) image_ds |
1 | <ParallelMapDataset shapes: (192, 192, 3), types: tf.float32> |
使用同样的 from_tensor_slices 方法你可以创建一个标签数据集:
1 2 3 4 | label_ds = tf.data.Dataset.from_tensor_slices(tf.cast(all_image_labels, tf.int64)) for label in label_ds.take(10): print(label_names[label.numpy()]) |
1 2 3 4 5 6 7 8 9 10 | sunflowers sunflowers roses tulips sunflowers sunflowers dandelion sunflowers dandelion roses |
由于这些数据集顺序相同,你可以将他们打包在一起得到一个(图片, 标签)对数据集:
1 2 | image_label_ds = tf.data.Dataset.zip((image_ds, label_ds)) image_label_ds |
1 | <ZipDataset shapes: ((192, 192, 3), ()), types: (tf.float32, tf.int64)> |
1 2 3 4 5 6 7 8 | ds = tf.data.Dataset.from_tensor_slices((all_image_paths, all_image_labels)) # 元组被解压缩到映射函数的位置参数中 def load_and_preprocess_from_path_label(path, label): return load_and_preprocess_image(path), label image_label_ds = ds.map(load_and_preprocess_from_path_label) image_label_ds |
1 | <MapDataset shapes: ((192, 192, 3), ()), types: (tf.float32, tf.int32)> |
训练的基本方法,使用 tf.data.Dataset.apply 方法和融合过的 tf.data.experimental.shuffle_and_repeat 函数来打乱和重启
1 2 3 4 5 6 7 8 | # 训练的基本方法 BATCH_SIZE = 32 ds = image_label_ds.apply( tf.data.experimental.shuffle_and_repeat(buffer_size=image_count)) ds = ds.batch(BATCH_SIZE) ds = ds.prefetch(buffer_size=AUTOTUNE) ds |
1 | <PrefetchDataset shapes: ((None, 192, 192, 3), (None,)), types: (tf.float32, tf.int32)> |
从 tf.keras.applications 取得 MobileNet v2 副本。该模型副本会被用于一个简单的迁移学习例子。设置 MobileNet 的权重为不可训练:
1 2 | mobile_net = tf.keras.applications.MobileNetV2(input_shape=(192, 192, 3), include_top=False) mobile_net.trainable=False |
1 2 | Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet_v2/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_192_no_top.h5 9412608/9406464 [==============================] - 0s 0us/step |
在你将输出传递给 MobilNet 模型之前,你需要将其范围从 [0,1] 转化为 [-1,1]:
1 2 3 4 | def change_range(image,label): return 2*image-1, label keras_ds = ds.map(change_range) |
1 2 3 4 5 | # 数据集可能需要几秒来启动,因为要填满其随机缓冲区。 image_batch, label_batch = next(iter(keras_ds)) feature_map_batch = mobile_net(image_batch) print(feature_map_batch.shape) |
1 | (32, 6, 6, 1280) |
构建模型
1 2 3 4 5 6 7 8 9 10 | model = tf.keras.Sequential([ mobile_net, tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Dense(len(label_names), activation = 'softmax')]) model.compile(optimizer=tf.keras.optimizers.Adam(), loss='sparse_categorical_crossentropy', metrics=["accuracy"]) model.summary() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= mobilenetv2_1.00_192 (Model) (None, 6, 6, 1280) 2257984 _________________________________________________________________ global_average_pooling2d (Gl (None, 1280) 0 _________________________________________________________________ dense_6 (Dense) (None, 5) 6405 ================================================================= Total params: 2,264,389 Trainable params: 6,405 Non-trainable params: 2,257,984 _________________________________________________________________ |
传递给 model.fit() 之前你会指定 step 的真实数量
1 2 | steps_per_epoch=tf.math.ceil(len(all_image_paths)/BATCH_SIZE).numpy() steps_per_epoch |
1 | 115.0 |
1 | model.fit(ds, epochs=1, steps_per_epoch=115) |
1 2 | 115/115 [==============================] - 10s 86ms/step - loss: 0.6913 - accuracy: 0.7405 <tensorflow.python.keras.callbacks.History at 0x7f9ee776d0f0> |
3、使用 tf.data 加载文本数据
将使用相同作品(荷马的伊利亚特)三个不同版本的英文翻译,然后训练一个模型来通过单行文本确定译者。
环境搭建
1 2 3 4 5 6 | from __future__ import absolute_import, division, print_function, unicode_literals import tensorflow as tf import tensorflow_datasets as tfds import os |
1 2 3 4 5 6 7 8 9 | DIRECTORY_URL = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/' FILE_NAMES = ['cowper.txt', 'derby.txt', 'butler.txt'] for name in FILE_NAMES: text_dir = tf.keras.utils.get_file(name, origin=DIRECTORY_URL+name) parent_dir = os.path.dirname(text_dir) parent_dir |
1 2 3 4 5 6 7 | Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt 819200/815980 [==============================] - 0s 0us/step Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt 811008/809730 [==============================] - 0s 0us/step Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt 811008/807992 [==============================] - 0s 0us/step '/root/.keras/datasets' |
将文本加载到数据集中,将迭代数据集中的每一个样本并且返回( example, label )对。
1 2 3 4 5 6 7 8 9 | def labeler(example, index): return example, tf.cast(index, tf.int64) labeled_data_sets = [] for i, file_name in enumerate(FILE_NAMES): lines_dataset = tf.data.TextLineDataset(os.path.join(parent_dir, file_name)) labeled_dataset = lines_dataset.map(lambda ex: labeler(ex, i)) labeled_data_sets.append(labeled_dataset) |
将这些标记的数据集合并到一个数据集中,然后对其进行随机化操作。
1 2 3 4 5 6 7 8 9 10 | BUFFER_SIZE = 50000 BATCH_SIZE = 64 TAKE_SIZE = 5000 all_labeled_data = labeled_data_sets[0] for labeled_dataset in labeled_data_sets[1:]: all_labeled_data = all_labeled_data.concatenate(labeled_dataset) all_labeled_data = all_labeled_data.shuffle( BUFFER_SIZE, reshuffle_each_iteration=False) |
你可以使用 tf.data.Dataset.take 与 print 来查看 (example, label) 对的外观。numpy 属性显示每个 Tensor 的值。
1 2 | for ex in all_labeled_data.take(5): print(ex) |
1 2 3 4 5 | (<tf.Tensor: shape=(), dtype=string, numpy=b"In boxing, Clytomedes, OEnops' son,">, <tf.Tensor: shape=(), dtype=int64, numpy=1>) (<tf.Tensor: shape=(), dtype=string, numpy=b'in your heart, and this, all about one single girl, whereas we now'>, <tf.Tensor: shape=(), dtype=int64, numpy=2>) (<tf.Tensor: shape=(), dtype=string, numpy=b"With angry taunts he drove the gather'd crowds.">, <tf.Tensor: shape=(), dtype=int64, numpy=0>) (<tf.Tensor: shape=(), dtype=string, numpy=b'bravest of the Achaeans."'>, <tf.Tensor: shape=(), dtype=int64, numpy=2>) (<tf.Tensor: shape=(), dtype=string, numpy=b"Olympian over-arch'd with clouds of gold">, <tf.Tensor: shape=(), dtype=int64, numpy=0>) |
建立词汇表
首先,通过将文本标记为单独的单词集合来构建词汇表。
- 迭代每个样本的 numpy 值。
- 使用 tfds.features.text.Tokenizer 来将其分割成 token。
- 将这些 token 放入一个 Python 集合中,借此来清除重复项。
- 获取该词汇表的大小以便于以后使用。
1 2 3 4 5 6 7 8 9 | tokenizer = tfds.features.text.Tokenizer() vocabulary_set = set() for text_tensor, _ in all_labeled_data: some_tokens = tokenizer.tokenize(text_tensor.numpy()) vocabulary_set.update(some_tokens) vocab_size = len(vocabulary_set) vocab_size |
1 | 17178 |
样本编码
通过传递 vocabulary_set 到 tfds.features.text.TokenTextEncoder 来构建一个编码器。编码器的 encode 方法传入一行文本,返回一个整数列表。
尝试运行这一行代码并查看输出的样式。
1 2 3 4 | encoder = tfds.features.text.TokenTextEncoder(vocabulary_set) example_text = next(iter(all_labeled_data))[0].numpy() print(example_text) |
1 | b"In boxing, Clytomedes, OEnops' son," |
1 2 | encoded_example = encoder.encode(example_text) print(encoded_example) |
1 | [6870, 1006, 14062, 7080, 16501] |
通过将编码器打包到 tf.py_function 并且传参至数据集的 map 方法的方式来运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | def encode(text_tensor, label): encoded_text = encoder.encode(text_tensor.numpy()) return encoded_text, label def encode_map_fn(text, label): # py_func doesn't set the shape of the returned tensors. encoded_text, label = tf.py_function(encode, inp=[text, label], Tout=(tf.int64, tf.int64)) # `tf.data.Datasets` work best if all components have a shape set # so set the shapes manually: encoded_text.set_shape([None]) label.set_shape([]) return encoded_text, label all_encoded_data = all_labeled_data.map(encode_map_fn) all_encoded_data |
1 | <MapDataset shapes: ((None,), ()), types: (tf.int64, tf.int64)> |
将数据集分割为测试集和训练集且进行分支
使用 tf.data.Dataset.take 和 tf.data.Dataset.skip 来建立一个小一些的测试数据集和稍大一些的训练数据集。
在数据集被传入模型之前,数据集需要被分批。最典型的是,每个分支中的样本大小与格式需要一致。但是数据集中样本并不全是相同大小的(每行文本字数并不相同)。因此,使用 tf.data.Dataset.padded_batch(而不是 batch )将样本填充到相同的大小。
1 2 | train_data = all_encoded_data.skip(TAKE_SIZE).shuffle(BUFFER_SIZE) train_data |
1 | <ShuffleDataset shapes: ((None,), ()), types: (tf.int64, tf.int64)> |
1 2 3 4 | train_data = train_data.padded_batch(BATCH_SIZE, padded_shapes=(tf.TensorShape([None,]),tf.TensorShape([]))) test_data = all_encoded_data.take(TAKE_SIZE) test_data = test_data.padded_batch(BATCH_SIZE, padded_shapes=(tf.TensorShape([None,]),tf.TensorShape([]))) |
建立模型
由于我们填充了零即引入了一个新的 token 来编码,因此词汇表大小(vocab_size)增加了一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | model = tf.keras.Sequential() model.add(tf.keras.layers.Embedding(vocab_size+1, 64)) # LSTM 层,它允许模型利用上下文中理解单词含义。 model.add(tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64))) # 一个或多个紧密连接的层 # 编辑 `for` 行的列表去检测层的大小 for units in [64, 64]: model.add(tf.keras.layers.Dense(units, activation='relu')) # 输出层。第一个参数是标签个数。 model.add(tf.keras.layers.Dense(3, activation='softmax')) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.fit(train_data, epochs=3, validation_data=test_data) |
1 2 3 4 5 6 7 | Epoch 1/3 697/697 [==============================] - 18s 25ms/step - loss: 0.5225 - accuracy: 0.7457 - val_loss: 0.3818 - val_accuracy: 0.8258 Epoch 2/3 697/697 [==============================] - 17s 24ms/step - loss: 0.3010 - accuracy: 0.8678 - val_loss: 0.3646 - val_accuracy: 0.8340 Epoch 3/3 697/697 [==============================] - 17s 24ms/step - loss: 0.2316 - accuracy: 0.8990 - val_loss: 0.3820 - val_accuracy: 0.8384 <tensorflow.python.keras.callbacks.History at 0x7f9f45767b00> |
1 2 3 | eval_loss, eval_acc = model.evaluate(test_data) print('\nEval loss: {}, Eval accuracy: {}'.format(eval_loss, eval_acc)) |
1 2 3 | 79/79 [==============================] - 2s 27ms/step - loss: 0.3820 - accuracy: 0.8384 Eval loss: 0.3820337951183319, Eval accuracy: 0.8384000062942505 |