ML Community Day คือวันที่ 9 พฤศจิกายน! ร่วมกับเราสำหรับการปรับปรุงจาก TensorFlow, JAX และอื่น ๆ เรียนรู้เพิ่มเติม

tf.data: สร้างไปป์ไลน์อินพุต TensorFlow

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHubดาวน์โหลดโน๊ตบุ๊ค

tf.data API ช่วยให้คุณสามารถสร้างท่อป้อนข้อมูลที่ซับซ้อนจากง่ายชิ้นนำมาใช้ใหม่ ตัวอย่างเช่น ไปป์ไลน์สำหรับโมเดลรูปภาพอาจรวมข้อมูลจากไฟล์ในระบบไฟล์แบบกระจาย ใช้การรบกวนแบบสุ่มกับแต่ละรูปภาพ และรวมรูปภาพที่เลือกแบบสุ่มเข้าเป็นกลุ่มสำหรับการฝึก ไปป์ไลน์สำหรับโมเดลข้อความอาจเกี่ยวข้องกับการดึงสัญลักษณ์จากข้อมูลข้อความดิบ แปลงเป็นสัญลักษณ์ที่ฝังด้วยตารางค้นหา และการรวมลำดับที่มีความยาวต่างกัน tf.data API ทำให้มันเป็นไปได้ที่จะจัดการกับข้อมูลจำนวนมากอ่านจากรูปแบบข้อมูลที่แตกต่างและดำเนินการเปลี่ยนแปลงที่ซับซ้อน

tf.data API แนะนำ tf.data.Dataset นามธรรมที่แสดงถึงลำดับขององค์ประกอบซึ่งในแต่ละองค์ประกอบประกอบด้วยหนึ่งหรือมากกว่าส่วนประกอบ ตัวอย่างเช่น ในไปป์ไลน์รูปภาพ องค์ประกอบอาจเป็นตัวอย่างการฝึกเดี่ยว โดยมีองค์ประกอบเทนเซอร์คู่หนึ่งแทนรูปภาพและป้ายกำกับ

มีสองวิธีในการสร้างชุดข้อมูล:

  • แหล่งที่มาของข้อมูลที่จะสร้าง Dataset จากข้อมูลที่เก็บไว้ในหน่วยความจำหรือในหนึ่งหรือมากกว่าไฟล์

  • การเปลี่ยนแปลงข้อมูลที่สร้างชุดข้อมูลจากหนึ่งหรือมากกว่า tf.data.Dataset วัตถุ

import tensorflow as tf
import pathlib
import os
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

np.set_printoptions(precision=4)

กลศาสตร์พื้นฐาน

ในการสร้างท่อป้อนข้อมูลคุณต้องเริ่มต้นด้วยแหล่งข้อมูล ตัวอย่างเช่นในการสร้าง Dataset จากข้อมูลในหน่วยความจำคุณสามารถใช้ tf.data.Dataset.from_tensors() หรือ tf.data.Dataset.from_tensor_slices() หรือถ้าการป้อนข้อมูลของคุณจะถูกเก็บไว้ในแฟ้มในรูปแบบ TFRecord แนะนำคุณสามารถใช้ tf.data.TFRecordDataset()

เมื่อคุณมี Dataset วัตถุคุณสามารถเปลี่ยนมันเป็นใหม่ Dataset โดยการผูกมัดโทรวิธีการใน tf.data.Dataset วัตถุ ตัวอย่างเช่นคุณสามารถใช้การแปลงต่อองค์ประกอบเช่น Dataset.map() , และการเปลี่ยนแปลงหลายองค์ประกอบเช่น Dataset.batch() โปรดดูเอกสารสำหรับ tf.data.Dataset สำหรับรายการที่สมบูรณ์ของการเปลี่ยนแปลง

Dataset วัตถุเป็น iterable หลาม ทำให้สามารถใช้องค์ประกอบโดยใช้ for loop:

dataset = tf.data.Dataset.from_tensor_slices([8, 3, 0, 8, 2, 1])
dataset
<TensorSliceDataset shapes: (), types: tf.int32>
for elem in dataset:
  print(elem.numpy())
8
3
0
8
2
1

หรือโดยการสร้างอย่างชัดเจนหลาม iterator ใช้ iter และใช้องค์ประกอบของการใช้ next :

it = iter(dataset)

print(next(it).numpy())
8

อีกวิธีหนึ่งคือองค์ประกอบของชุดข้อมูลที่สามารถบริโภคได้ใช้ reduce การเปลี่ยนแปลงซึ่งจะช่วยลดองค์ประกอบทั้งหมดในการผลิตเป็นผลเดียว ตัวอย่างต่อไปนี้แสดงให้เห็นถึงวิธีการใช้ reduce การเปลี่ยนแปลงในการคำนวณผลรวมของชุดข้อมูลของจำนวนเต็มที่

print(dataset.reduce(0, lambda state, value: state + value).numpy())
22

โครงสร้างชุดข้อมูล

ชุดข้อมูลที่ก่อให้ลำดับขององค์ประกอบที่แต่ละองค์ประกอบเดียวกัน (ซ้อน) โครงสร้างของส่วนประกอบ แต่ละองค์ประกอบของโครงสร้างสามารถของแทนได้ประเภทใด ๆ โดย tf.TypeSpec รวมทั้ง tf.Tensor , tf.sparse.SparseTensor , tf.RaggedTensor , tf.TensorArray หรือ tf.data.Dataset

โครงสร้างงูหลามที่สามารถใช้ในการแสดง (ซ้อน) โครงสร้างขององค์ประกอบ ได้แก่ tuple , dict , NamedTuple และ OrderedDict โดยเฉพาะอย่างยิ่ง list ไม่ได้เป็นโครงสร้างที่ถูกต้องสำหรับการแสดงโครงสร้างขององค์ประกอบชุดข้อมูล นี้เป็นเพราะผู้ใช้ tf.data ต้นรู้สึกอย่างมากเกี่ยวกับ list ปัจจัยการผลิต (เช่นการส่งผ่านไปยัง tf.data.Dataset.from_tensors ) การบรรจุโดยอัตโนมัติขณะที่เทนเซอร์และ list เอาท์พุท (เช่นค่าการกลับมาของฟังก์ชั่นที่ผู้ใช้กำหนด) ถูกข่มขู่เป็น tuple เป็นผลให้ถ้าคุณต้องการ list ป้อนข้อมูลที่จะถือว่าเป็นโครงสร้างที่คุณจำเป็นต้องแปลงเป็น tuple และหากคุณต้องการ list ออกไปเป็นองค์ประกอบเดียวแล้วคุณจะต้องชัดเจนแพ็คโดยใช้ tf.stack .

Dataset.element_spec คุณสมบัติช่วยให้คุณสามารถตรวจสอบประเภทขององค์ประกอบแต่ละองค์ประกอบ สถานที่ให้ผลตอบแทนที่เป็นโครงสร้างที่ซ้อนกันของ tf.TypeSpec วัตถุที่ตรงกับโครงสร้างขององค์ประกอบซึ่งอาจจะเป็นองค์ประกอบเดียว tuple ของส่วนประกอบหรือ tuple ซ้อนกันของส่วนประกอบ ตัวอย่างเช่น:

dataset1 = tf.data.Dataset.from_tensor_slices(tf.random.uniform([4, 10]))

dataset1.element_spec
TensorSpec(shape=(10,), dtype=tf.float32, name=None)
dataset2 = tf.data.Dataset.from_tensor_slices(
   (tf.random.uniform([4]),
    tf.random.uniform([4, 100], maxval=100, dtype=tf.int32)))

dataset2.element_spec
(TensorSpec(shape=(), dtype=tf.float32, name=None),
 TensorSpec(shape=(100,), dtype=tf.int32, name=None))
dataset3 = tf.data.Dataset.zip((dataset1, dataset2))

dataset3.element_spec
(TensorSpec(shape=(10,), dtype=tf.float32, name=None),
 (TensorSpec(shape=(), dtype=tf.float32, name=None),
  TensorSpec(shape=(100,), dtype=tf.int32, name=None)))
# Dataset containing a sparse tensor.
dataset4 = tf.data.Dataset.from_tensors(tf.SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4]))

dataset4.element_spec
SparseTensorSpec(TensorShape([3, 4]), tf.int32)
# Use value_type to see the type of value represented by the element spec
dataset4.element_spec.value_type
tensorflow.python.framework.sparse_tensor.SparseTensor

Dataset ชุดข้อมูลสนับสนุนการเปลี่ยนแปลงของโครงสร้างใด ๆ เมื่อใช้ Dataset.map() และ Dataset.filter() แปลงซึ่งใช้ฟังก์ชั่นให้กับแต่ละองค์ประกอบโครงสร้างองค์ประกอบกำหนดข้อโต้แย้งของการทำงาน:

dataset1 = tf.data.Dataset.from_tensor_slices(
    tf.random.uniform([4, 10], minval=1, maxval=10, dtype=tf.int32))

dataset1
<TensorSliceDataset shapes: (10,), types: tf.int32>
for z in dataset1:
  print(z.numpy())
[1 9 8 8 1 8 6 9 6 2]
[6 6 2 5 7 2 8 6 6 2]
[7 6 5 1 5 8 6 1 6 9]
[1 5 1 4 3 6 4 1 1 3]
dataset2 = tf.data.Dataset.from_tensor_slices(
   (tf.random.uniform([4]),
    tf.random.uniform([4, 100], maxval=100, dtype=tf.int32)))

dataset2
<TensorSliceDataset shapes: ((), (100,)), types: (tf.float32, tf.int32)>
dataset3 = tf.data.Dataset.zip((dataset1, dataset2))

dataset3
<ZipDataset shapes: ((10,), ((), (100,))), types: (tf.int32, (tf.float32, tf.int32))>
for a, (b,c) in dataset3:
  print('shapes: {a.shape}, {b.shape}, {c.shape}'.format(a=a, b=b, c=c))
shapes: (10,), (), (100,)
shapes: (10,), (), (100,)
shapes: (10,), (), (100,)
shapes: (10,), (), (100,)

การอ่านข้อมูลเข้า

การใช้อาร์เรย์ NumPy

ดู โหลดอาร์เรย์ NumPy สำหรับตัวอย่างเพิ่มเติม

ถ้าทุกเหมาะกับการป้อนข้อมูลของคุณในหน่วยความจำวิธีที่ง่ายที่สุดในการสร้าง Dataset จากพวกเขาคือการแปลงให้ tf.Tensor วัตถุและการใช้ Dataset.from_tensor_slices()

train, test = tf.keras.datasets.fashion_mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
40960/29515 [=========================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
26435584/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
16384/5148 [===============================================================================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
4431872/4422102 [==============================] - 0s 0us/step
images, labels = train
images = images/255

dataset = tf.data.Dataset.from_tensor_slices((images, labels))
dataset
<TensorSliceDataset shapes: ((28, 28), ()), types: (tf.float64, tf.uint8)>

การใช้เครื่องกำเนิด Python

แหล่งข้อมูลอีกเรื่องธรรมดาที่สามารถจะกินเป็น tf.data.Dataset เป็นเครื่องกำเนิดไฟฟ้าหลาม

def count(stop):
  i = 0
  while i<stop:
    yield i
    i += 1
for n in count(5):
  print(n)
0
1
2
3
4

Dataset.from_generator คอนสตรัคแปลงกำเนิดหลามเพื่อการทำงานอย่างเต็มที่ tf.data.Dataset

ตัวสร้างรับ callable เป็นอินพุต ไม่ใช่ตัววนซ้ำ ซึ่งช่วยให้สามารถรีสตาร์ทเครื่องกำเนิดไฟฟ้าเมื่อถึงจุดสิ้นสุด มันต้องใช้เวลาเป็นตัวเลือก args อาร์กิวเมนต์ซึ่งจะถูกส่งเป็นอาร์กิวเมนต์ callable ของ

output_types อาร์กิวเมนต์ถูกต้องเนื่องจาก tf.data สร้าง tf.Graph ภายในและขอบกราฟต้องมี tf.dtype

ds_counter = tf.data.Dataset.from_generator(count, args=[25], output_types=tf.int32, output_shapes = (), )
for count_batch in ds_counter.repeat().batch(10).take(10):
  print(count_batch.numpy())
[0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24  0  1  2  3  4]
[ 5  6  7  8  9 10 11 12 13 14]
[15 16 17 18 19 20 21 22 23 24]
[0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24  0  1  2  3  4]
[ 5  6  7  8  9 10 11 12 13 14]
[15 16 17 18 19 20 21 22 23 24]

output_shapes อาร์กิวเมนต์ไม่จำเป็นต้องใช้ แต่แนะนำอย่างสูงในฐานะการดำเนินงาน tensorflow จำนวนมากไม่สนับสนุนเทนเซอร์ที่มีอันดับที่ไม่รู้จัก ถ้าความยาวของแกนโดยเฉพาะอย่างยิ่งเป็นที่รู้จักหรือตัวแปรตั้งเป็น None ใน output_shapes

นอกจากนี้ยังเป็นสิ่งสำคัญที่จะทราบว่า output_shapes และ output_types ปฏิบัติตามกฎการทำรังเช่นเดียวกับวิธีการอื่น ๆ ชุด

นี่คือตัวอย่างเครื่องกำเนิดไฟฟ้าที่แสดงให้เห็นทั้งสองลักษณะ โดยจะส่งกลับค่าทูเพิลของอาร์เรย์ โดยที่อาร์เรย์ที่สองเป็นเวกเตอร์ที่ไม่ทราบความยาว

def gen_series():
  i = 0
  while True:
    size = np.random.randint(0, 10)
    yield i, np.random.normal(size=(size,))
    i += 1
for i, series in gen_series():
  print(i, ":", str(series))
  if i > 5:
    break
0 : [ 0.814   0.7245 -0.8296  0.106   2.6089  0.799 ]
1 : [0.6854]
2 : [-0.1255 -0.5735]
3 : [ 0.1669 -1.1696  0.0912 -0.4514  2.5346 -0.7017 -1.1124]
4 : [-0.9659]
5 : [-0.5551 -0.8024  0.264  -0.5541 -0.6733  1.6715  0.4508 -0.7317 -2.3218]
6 : [ 0.4648 -0.0541 -0.8733 -1.4034  0.29    0.669   1.2556]

เป็นผลผลิตที่ได้เป็น int32 สองคือ float32

รายการแรกเป็นสเกลารูปร่าง () และที่สองเป็นเวกเตอร์ของความยาวที่ไม่รู้จักรูปร่าง (None,)

ds_series = tf.data.Dataset.from_generator(
    gen_series, 
    output_types=(tf.int32, tf.float32), 
    output_shapes=((), (None,)))

ds_series
<FlatMapDataset shapes: ((), (None,)), types: (tf.int32, tf.float32)>

ตอนนี้ก็สามารถใช้งานได้เหมือนปกติ tf.data.Dataset ทราบว่าเมื่อ batching ชุดข้อมูลที่มีรูปร่างตัวแปรคุณจำเป็นต้องใช้ Dataset.padded_batch

ds_series_batch = ds_series.shuffle(20).padded_batch(10)

ids, sequence_batch = next(iter(ds_series_batch))
print(ids.numpy())
print()
print(sequence_batch.numpy())
[16  4  6  8 23  1 10  2 15 13]

[[ 0.3357 -0.3727  0.7409 -0.8574 -0.2802  0.2744 -0.2841 -1.3277]
 [ 0.7422  0.251   1.1745 -0.2416  0.7332  0.8136 -1.7633  0.    ]
 [ 0.3777 -2.2714  0.      0.      0.      0.      0.      0.    ]
 [ 0.7962 -0.3259 -0.9036  0.7381  0.      0.      0.      0.    ]
 [ 0.3902 -1.2637 -0.6834  0.5808 -0.3917  0.      0.      0.    ]
 [-1.32    0.      0.      0.      0.      0.      0.      0.    ]
 [ 1.9602  0.4305 -0.1827  0.0427 -0.7381 -0.0948 -0.0964  0.1041]
 [ 1.2071  0.0665 -0.4292  0.      0.      0.      0.      0.    ]
 [-0.7277  1.3547 -1.0543  1.9235  0.1442 -1.0691  0.2263  0.    ]
 [ 1.2949  1.5027  0.5522  0.083   0.665  -0.9897  0.0659  0.    ]]

สำหรับตัวอย่างที่มีเหตุผลมากขึ้นลองห่อ preprocessing.image.ImageDataGenerator เป็น tf.data.Dataset

ขั้นแรกให้ดาวน์โหลดข้อมูล:

flowers = tf.keras.utils.get_file(
    'flower_photos',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    untar=True)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
228818944/228813984 [==============================] - 10s 0us/step
228827136/228813984 [==============================] - 10s 0us/step

สร้าง image.ImageDataGenerator

img_gen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255, rotation_range=20)
images, labels = next(img_gen.flow_from_directory(flowers))
Found 3670 images belonging to 5 classes.
print(images.dtype, images.shape)
print(labels.dtype, labels.shape)
float32 (32, 256, 256, 3)
float32 (32, 5)
ds = tf.data.Dataset.from_generator(
    lambda: img_gen.flow_from_directory(flowers), 
    output_types=(tf.float32, tf.float32), 
    output_shapes=([32,256,256,3], [32,5])
)

ds.element_spec
(TensorSpec(shape=(32, 256, 256, 3), dtype=tf.float32, name=None),
 TensorSpec(shape=(32, 5), dtype=tf.float32, name=None))
for images, label in ds.take(1):
  print('images.shape: ', images.shape)
  print('labels.shape: ', labels.shape)
Found 3670 images belonging to 5 classes.
images.shape:  (32, 256, 256, 3)
labels.shape:  (32, 5)

กำลังใช้ข้อมูล TFRecord

ดู TFRecords โหลด สำหรับตัวอย่างแบบ end-to-end

tf.data API สนับสนุนความหลากหลายของรูปแบบไฟล์เพื่อให้คุณสามารถประมวลผลชุดข้อมูลขนาดใหญ่ที่ไม่เหมาะสมในหน่วยความจำ ตัวอย่างเช่น รูปแบบไฟล์ TFRecord เป็นรูปแบบไบนารีเชิงบันทึกอย่างง่ายที่แอปพลิเคชัน TensorFlow จำนวนมากใช้สำหรับข้อมูลการฝึกอบรม tf.data.TFRecordDataset ชั้นช่วยให้คุณสามารถสตรีมผ่านเนื้อหาของหนึ่งหรือมากกว่าหนึ่งไฟล์ TFRecord เป็นส่วนหนึ่งของท่อป้อนข้อมูล

นี่คือตัวอย่างการใช้ไฟล์ทดสอบจาก French Street Name Signs (FSNS)

# Creates a dataset that reads all of the examples from two files.
fsns_test_file = tf.keras.utils.get_file("fsns.tfrec", "https://storage.googleapis.com/download.tensorflow.org/data/fsns-20160927/testdata/fsns-00000-of-00001")
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/fsns-20160927/testdata/fsns-00000-of-00001
7905280/7904079 [==============================] - 1s 0us/step
7913472/7904079 [==============================] - 1s 0us/step

filenames อาร์กิวเมนต์ TFRecordDataset initializer สามารถเป็นได้ทั้งสตริงรายการสตริงหรือ tf.Tensor ของสตริง ดังนั้น หากคุณมีไฟล์สองชุดสำหรับการฝึกอบรมและการตรวจสอบ คุณสามารถสร้างวิธีการจากโรงงานที่สร้างชุดข้อมูล โดยใช้ชื่อไฟล์เป็นอาร์กิวเมนต์อินพุต:

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

โครงการ TensorFlow จำนวนมากที่ใช้ต่อเนื่อง tf.train.Example ระเบียนในแฟ้ม TFRecord ของพวกเขา ต้องถอดรหัสเหล่านี้ก่อนจึงจะสามารถตรวจสอบได้:

raw_example = next(iter(dataset))
parsed = tf.train.Example.FromString(raw_example.numpy())

parsed.features.feature['image/text']
bytes_list {
  value: "Rue Perreyon"
}

การใช้ข้อมูลข้อความ

ดู โหลดข้อความ สำหรับการสิ้นสุดตัวอย่างสิ้น

ชุดข้อมูลจำนวนมากถูกแจกจ่ายเป็นไฟล์ข้อความตั้งแต่หนึ่งไฟล์ขึ้นไป tf.data.TextLineDataset มีวิธีที่ง่ายที่จะดึงสายจากหนึ่งหรือไฟล์ข้อความเพิ่มเติม รับหนึ่งหรือชื่อไฟล์มากขึ้น TextLineDataset จะผลิตองค์ประกอบสตริงมูลค่าต่อหนึ่งบรรทัดของไฟล์เหล่านั้น

directory_url = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'
file_names = ['cowper.txt', 'derby.txt', 'butler.txt']

file_paths = [
    tf.keras.utils.get_file(file_name, directory_url + file_name)
    for file_name in file_names
]
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/cowper.txt
819200/815980 [==============================] - 0s 0us/step
827392/815980 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/derby.txt
811008/809730 [==============================] - 0s 0us/step
819200/809730 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/illiad/butler.txt
811008/807992 [==============================] - 0s 0us/step
819200/807992 [==============================] - 0s 0us/step
dataset = tf.data.TextLineDataset(file_paths)

ต่อไปนี้คือสองสามบรรทัดแรกของไฟล์แรก:

for line in dataset.take(5):
  print(line.numpy())
b"\xef\xbb\xbfAchilles sing, O Goddess! Peleus' son;"
b'His wrath pernicious, who ten thousand woes'
b"Caused to Achaia's host, sent many a soul"
b'Illustrious into Ades premature,'
b'And Heroes gave (so stood the will of Jove)'

สายสลับระหว่างไฟล์ใช้ Dataset.interleave ทำให้ง่ายต่อการสับเปลี่ยนไฟล์ด้วยกัน ต่อไปนี้คือบรรทัดแรก สอง และสามจากการแปลแต่ละรายการ:

files_ds = tf.data.Dataset.from_tensor_slices(file_paths)
lines_ds = files_ds.interleave(tf.data.TextLineDataset, cycle_length=3)

for i, line in enumerate(lines_ds.take(9)):
  if i % 3 == 0:
    print()
  print(line.numpy())
b"\xef\xbb\xbfAchilles sing, O Goddess! Peleus' son;"
b"\xef\xbb\xbfOf Peleus' son, Achilles, sing, O Muse,"
b'\xef\xbb\xbfSing, O goddess, the anger of Achilles son of Peleus, that brought'

b'His wrath pernicious, who ten thousand woes'
b'The vengeance, deep and deadly; whence to Greece'
b'countless ills upon the Achaeans. Many a brave soul did it send'

b"Caused to Achaia's host, sent many a soul"
b'Unnumbered ills arose; which many a soul'
b'hurrying down to Hades, and many a hero did it yield a prey to dogs and'

โดยค่าเริ่มต้น TextLineDataset ผลตอบแทนถัวเฉลี่ยทุกบรรทัดของแต่ละไฟล์ซึ่งอาจจะไม่เป็นที่น่าพอใจเช่นถ้าไฟล์เริ่มต้นด้วยสายหัวหรือมีการแสดงความคิดเห็น เส้นเหล่านี้สามารถถอดออกได้โดยใช้ Dataset.skip() หรือ Dataset.filter() แปลง ที่นี่ คุณข้ามบรรทัดแรก แล้วกรองเพื่อค้นหาผู้รอดชีวิตเท่านั้น

titanic_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
titanic_lines = tf.data.TextLineDataset(titanic_file)
for line in titanic_lines.take(10):
  print(line.numpy())
b'survived,sex,age,n_siblings_spouses,parch,fare,class,deck,embark_town,alone'
b'0,male,22.0,1,0,7.25,Third,unknown,Southampton,n'
b'1,female,38.0,1,0,71.2833,First,C,Cherbourg,n'
b'1,female,26.0,0,0,7.925,Third,unknown,Southampton,y'
b'1,female,35.0,1,0,53.1,First,C,Southampton,n'
b'0,male,28.0,0,0,8.4583,Third,unknown,Queenstown,y'
b'0,male,2.0,3,1,21.075,Third,unknown,Southampton,n'
b'1,female,27.0,0,2,11.1333,Third,unknown,Southampton,n'
b'1,female,14.0,1,0,30.0708,Second,unknown,Cherbourg,n'
b'1,female,4.0,1,1,16.7,Third,G,Southampton,n'
def survived(line):
  return tf.not_equal(tf.strings.substr(line, 0, 1), "0")

survivors = titanic_lines.skip(1).filter(survived)
for line in survivors.take(10):
  print(line.numpy())
b'1,female,38.0,1,0,71.2833,First,C,Cherbourg,n'
b'1,female,26.0,0,0,7.925,Third,unknown,Southampton,y'
b'1,female,35.0,1,0,53.1,First,C,Southampton,n'
b'1,female,27.0,0,2,11.1333,Third,unknown,Southampton,n'
b'1,female,14.0,1,0,30.0708,Second,unknown,Cherbourg,n'
b'1,female,4.0,1,1,16.7,Third,G,Southampton,n'
b'1,male,28.0,0,0,13.0,Second,unknown,Southampton,y'
b'1,female,28.0,0,0,7.225,Third,unknown,Cherbourg,y'
b'1,male,28.0,0,0,35.5,First,A,Southampton,y'
b'1,female,38.0,1,5,31.3875,Third,unknown,Southampton,n'

การใช้ข้อมูล CSV

ดู โหลดไฟล์ CSV และ โหลดนุ่น DataFrames สำหรับตัวอย่างเพิ่มเติม

รูปแบบไฟล์ CSV เป็นรูปแบบที่นิยมสำหรับการจัดเก็บข้อมูลแบบตารางในข้อความธรรมดา

ตัวอย่างเช่น:

titanic_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
df = pd.read_csv(titanic_file)
df.head()

ถ้าเหมาะกับข้อมูลของคุณในหน่วยความจำเดียวกัน Dataset.from_tensor_slices วิธีการทำงานในพจนานุกรมที่ช่วยให้ข้อมูลที่จะนำเข้าได้อย่างง่ายดาย:

titanic_slices = tf.data.Dataset.from_tensor_slices(dict(df))

for feature_batch in titanic_slices.take(1):
  for key, value in feature_batch.items():
    print("  {!r:20s}: {}".format(key, value))
'survived'          : 0
  'sex'               : b'male'
  'age'               : 22.0
  'n_siblings_spouses': 1
  'parch'             : 0
  'fare'              : 7.25
  'class'             : b'Third'
  'deck'              : b'unknown'
  'embark_town'       : b'Southampton'
  'alone'             : b'n'

แนวทางที่ปรับขนาดได้มากขึ้นคือการโหลดจากดิสก์เท่าที่จำเป็น

tf.data โมดูลมีวิธีการบันทึกของสารสกัดจากหนึ่งหรือมากกว่าไฟล์ CSV ที่สอดคล้องกับ RFC 4180

experimental.make_csv_dataset ฟังก์ชั่นคือการติดต่อระดับสูงสำหรับการอ่านชุดไฟล์ CSV รองรับการอนุมานประเภทคอลัมน์และคุณสมบัติอื่นๆ เช่น การแบ่งกลุ่มและการสับเปลี่ยน เพื่อให้การใช้งานง่ายขึ้น

titanic_batches = tf.data.experimental.make_csv_dataset(
    titanic_file, batch_size=4,
    label_name="survived")
for feature_batch, label_batch in titanic_batches.take(1):
  print("'survived': {}".format(label_batch))
  print("features:")
  for key, value in feature_batch.items():
    print("  {!r:20s}: {}".format(key, value))
'survived': [1 0 0 1]
features:
  'sex'               : [b'male' b'male' b'male' b'female']
  'age'               : [17. 18. 28.  5.]
  'n_siblings_spouses': [0 1 0 0]
  'parch'             : [2 1 0 0]
  'fare'              : [110.8833   7.8542   7.725   12.475 ]
  'class'             : [b'First' b'Third' b'Third' b'Third']
  'deck'              : [b'C' b'unknown' b'unknown' b'unknown']
  'embark_town'       : [b'Cherbourg' b'Southampton' b'Queenstown' b'Southampton']
  'alone'             : [b'n' b'n' b'y' b'y']

คุณสามารถใช้ select_columns อาร์กิวเมนต์ถ้าคุณต้องการเพียงส่วนย่อยของคอลัมน์

titanic_batches = tf.data.experimental.make_csv_dataset(
    titanic_file, batch_size=4,
    label_name="survived", select_columns=['class', 'fare', 'survived'])
for feature_batch, label_batch in titanic_batches.take(1):
  print("'survived': {}".format(label_batch))
  for key, value in feature_batch.items():
    print("  {!r:20s}: {}".format(key, value))
'survived': [0 1 0 0]
  'fare'              : [ 7.25   19.2583  7.8542  7.8958]
  'class'             : [b'Third' b'Third' b'Third' b'Third']

นอกจากนี้ยังมีระดับต่ำกว่า experimental.CsvDataset ระดับที่ให้การควบคุมที่ละเอียดปลีกย่อย ไม่สนับสนุนการอนุมานประเภทคอลัมน์ คุณต้องระบุประเภทของแต่ละคอลัมน์แทน

titanic_types  = [tf.int32, tf.string, tf.float32, tf.int32, tf.int32, tf.float32, tf.string, tf.string, tf.string, tf.string] 
dataset = tf.data.experimental.CsvDataset(titanic_file, titanic_types , header=True)

for line in dataset.take(10):
  print([item.numpy() for item in line])
[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']
[1, b'female', 38.0, 1, 0, 71.2833, b'First', b'C', b'Cherbourg', b'n']
[1, b'female', 26.0, 0, 0, 7.925, b'Third', b'unknown', b'Southampton', b'y']
[1, b'female', 35.0, 1, 0, 53.1, b'First', b'C', b'Southampton', b'n']
[0, b'male', 28.0, 0, 0, 8.4583, b'Third', b'unknown', b'Queenstown', b'y']
[0, b'male', 2.0, 3, 1, 21.075, b'Third', b'unknown', b'Southampton', b'n']
[1, b'female', 27.0, 0, 2, 11.1333, b'Third', b'unknown', b'Southampton', b'n']
[1, b'female', 14.0, 1, 0, 30.0708, b'Second', b'unknown', b'Cherbourg', b'n']
[1, b'female', 4.0, 1, 1, 16.7, b'Third', b'G', b'Southampton', b'n']
[0, b'male', 20.0, 0, 0, 8.05, b'Third', b'unknown', b'Southampton', b'y']

หากบางคอลัมน์ว่างเปล่า อินเทอร์เฟซระดับต่ำนี้จะให้คุณระบุค่าเริ่มต้นแทนประเภทคอลัมน์ได้

%%writefile missing.csv
1,2,3,4
,2,3,4
1,,3,4
1,2,,4
1,2,3,
,,,
Writing missing.csv
# Creates a dataset that reads all of the records from two CSV files, each with
# four float columns which may have missing values.

record_defaults = [999,999,999,999]
dataset = tf.data.experimental.CsvDataset("missing.csv", record_defaults)
dataset = dataset.map(lambda *items: tf.stack(items))
dataset
<MapDataset shapes: (4,), types: tf.int32>
for line in dataset:
  print(line.numpy())
[1 2 3 4]
[999   2   3   4]
[  1 999   3   4]
[  1   2 999   4]
[  1   2   3 999]
[999 999 999 999]

โดยค่าเริ่มต้น CsvDataset ผลตอบแทนถัวเฉลี่ยคอลัมน์ทุกบรรทัดของไฟล์ซึ่งอาจจะไม่เป็นที่พึงปรารถนาทุกตัวอย่างเช่นถ้าไฟล์เริ่มต้นด้วยบรรทัดส่วนหัวที่ควรละเลยหรือถ้าบางคอลัมน์ที่ไม่จำเป็นในการป้อนข้อมูล เส้นเหล่านี้และสาขาสามารถลบออกได้ด้วย header และ select_cols ข้อโต้แย้งตามลำดับ

# Creates a dataset that reads all of the records from two CSV files with
# headers, extracting float data from columns 2 and 4.
record_defaults = [999, 999] # Only provide defaults for the selected columns
dataset = tf.data.experimental.CsvDataset("missing.csv", record_defaults, select_cols=[1, 3])
dataset = dataset.map(lambda *items: tf.stack(items))
dataset
<MapDataset shapes: (2,), types: tf.int32>
for line in dataset:
  print(line.numpy())
[2 4]
[2 4]
[999   4]
[2 4]
[  2 999]
[999 999]

การใช้ชุดไฟล์

มีชุดข้อมูลจำนวนมากที่แจกจ่ายเป็นชุดของไฟล์ โดยที่แต่ละไฟล์เป็นตัวอย่าง

flowers_root = tf.keras.utils.get_file(
    'flower_photos',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    untar=True)
flowers_root = pathlib.Path(flowers_root)

ไดเร็กทอรี root มีไดเร็กทอรีสำหรับแต่ละคลาส:

for item in flowers_root.glob("*"):
  print(item.name)
sunflowers
daisy
LICENSE.txt
roses
tulips
dandelion

ไฟล์ในไดเร็กทอรีแต่ละคลาสเป็นตัวอย่าง:

list_ds = tf.data.Dataset.list_files(str(flowers_root/'*/*'))

for f in list_ds.take(5):
  print(f.numpy())
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/18687587599_3dd4fdf255.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/16863587471_cc3a6ffb29_m.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/sunflowers/9431890901_cd11bda584_n.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/3562861685_8b8d747b4d.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/14087326141_1906d5a373_n.jpg'

อ่านข้อมูลโดยใช้ tf.io.read_file ฟังก์ชั่นและสารสกัดจากฉลากจากเส้นทางกลับ (image, label) คู่:

def process_path(file_path):
  label = tf.strings.split(file_path, os.sep)[-2]
  return tf.io.read_file(file_path), label

labeled_ds = list_ds.map(process_path)
for image_raw, label_text in labeled_ds.take(1):
  print(repr(image_raw.numpy()[:100]))
  print()
  print(label_text.numpy())
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00H\x00H\x00\x00\xff\xed\x00\x9aPhotoshop 3.0\x008BIM\x04\x04\x00\x00\x00\x00\x00b\x1c\x01Z\x00\x03\x1b%G\x1c\x02\x00\x00\x02\x00\x02\x1c\x027\x00\x0820100808\x1c\x02t\x006                 '

b'sunflowers'

แบทช์องค์ประกอบชุดข้อมูล

แบทช์ง่าย

รูปแบบที่ง่ายของกอง batching n องค์ประกอบติดต่อกันของชุดข้อมูลเป็นองค์ประกอบหนึ่ง Dataset.batch() การเปลี่ยนแปลงไม่ตรงนี้มีข้อ จำกัด เช่นเดียวกับ tf.stack() ผู้ประกอบการที่ใช้กับส่วนประกอบแต่ละองค์ประกอบ: คือผมสำหรับแต่ละองค์ประกอบองค์ประกอบทั้งหมดต้องมีเมตริกซ์ของรูปร่างเหมือนกันแน่นอน

inc_dataset = tf.data.Dataset.range(100)
dec_dataset = tf.data.Dataset.range(0, -100, -1)
dataset = tf.data.Dataset.zip((inc_dataset, dec_dataset))
batched_dataset = dataset.batch(4)

for batch in batched_dataset.take(4):
  print([arr.numpy() for arr in batch])
[array([0, 1, 2, 3]), array([ 0, -1, -2, -3])]
[array([4, 5, 6, 7]), array([-4, -5, -6, -7])]
[array([ 8,  9, 10, 11]), array([ -8,  -9, -10, -11])]
[array([12, 13, 14, 15]), array([-12, -13, -14, -15])]

ในขณะที่ tf.data พยายามในการเผยแพร่ข้อมูลรูปร่างการตั้งค่าเริ่มต้นของ Dataset.batch ผลในชุดขนาดที่ไม่รู้จักเพราะชุดที่ผ่านมาอาจจะไม่เต็มรูปแบบ หมายเหตุ None ในรูปร่าง:

batched_dataset
<BatchDataset shapes: ((None,), (None,)), types: (tf.int64, tf.int64)>

ใช้ drop_remainder โต้แย้งที่จะไม่สนใจว่าชุดที่ผ่านมาและได้รับการขยายพันธุ์รูปร่างเต็มรูปแบบ:

batched_dataset = dataset.batch(7, drop_remainder=True)
batched_dataset
<BatchDataset shapes: ((7,), (7,)), types: (tf.int64, tf.int64)>

แบทช์เทนเซอร์พร้อมช่องว่างภายใน

สูตรข้างต้นใช้ได้กับเทนเซอร์ที่มีขนาดเท่ากันทั้งหมด อย่างไรก็ตาม โมเดลจำนวนมาก (เช่น โมเดลตามลำดับ) ทำงานกับข้อมูลอินพุตที่สามารถมีขนาดต่างกันได้ (เช่น ลำดับที่มีความยาวต่างกัน) เพื่อจัดการกับกรณีนี้ Dataset.padded_batch เปลี่ยนแปลงช่วยให้คุณสามารถเทนเซอร์ชุดของรูปร่างที่แตกต่างกันโดยการระบุหนึ่งหรือมากกว่าหนึ่งมิติในการที่พวกเขาอาจจะมีเบาะ

dataset = tf.data.Dataset.range(100)
dataset = dataset.map(lambda x: tf.fill([tf.cast(x, tf.int32)], x))
dataset = dataset.padded_batch(4, padded_shapes=(None,))

for batch in dataset.take(2):
  print(batch.numpy())
  print()
[[0 0 0]
 [1 0 0]
 [2 2 0]
 [3 3 3]]

[[4 4 4 4 0 0 0]
 [5 5 5 5 5 0 0]
 [6 6 6 6 6 6 0]
 [7 7 7 7 7 7 7]]

Dataset.padded_batch เปลี่ยนแปลงให้คุณตั้งค่า padding แตกต่างกันสำหรับมิติของแต่ละองค์ประกอบในแต่ละครั้งและมันอาจจะเป็นตัวแปรที่มีความยาว (ความหมายโดย None ในตัวอย่างข้างต้น) หรือคงยาว นอกจากนี้ยังสามารถแทนที่ค่าช่องว่างภายในซึ่งมีค่าเริ่มต้นเป็น 0

เวิร์กโฟลว์การฝึกอบรม

กำลังประมวลผลหลายยุค

tf.data API มีสองวิธีหลักในการดำเนินการหลาย epochs ของข้อมูลเดียวกัน

วิธีที่ง่ายที่สุดในการย้ำกว่าชุดในยุคสมัยหลายคือการใช้ Dataset.repeat() การเปลี่ยนแปลง ขั้นแรก สร้างชุดข้อมูลของข้อมูลไททานิค:

titanic_file = tf.keras.utils.get_file("train.csv", "https://storage.googleapis.com/tf-datasets/titanic/train.csv")
titanic_lines = tf.data.TextLineDataset(titanic_file)
def plot_batch_sizes(ds):
  batch_sizes = [batch.shape[0] for batch in ds]
  plt.bar(range(len(batch_sizes)), batch_sizes)
  plt.xlabel('Batch number')
  plt.ylabel('Batch size')

ใช้ Dataset.repeat() การเปลี่ยนแปลงที่มีการขัดแย้งใดจะทำซ้ำการป้อนข้อมูลไปเรื่อย ๆ

Dataset.repeat เปลี่ยนแปลงเชื่อมข้อโต้แย้งได้โดยไม่ต้องส่งสัญญาณการสิ้นสุดของยุคหนึ่งและจุดเริ่มต้นของยุคถัดไป ด้วยเหตุนี้ Dataset.batch นำมาใช้หลังจาก Dataset.repeat จะให้ผลผลิตสำหรับกระบวนการที่ขอบเขตยุค straddle:

titanic_batches = titanic_lines.repeat(3).batch(128)
plot_batch_sizes(titanic_batches)

png

หากคุณจำเป็นต้องแยกยุคชัดเจนใส่ Dataset.batch ก่อนที่จะทำซ้ำ:

titanic_batches = titanic_lines.batch(128).repeat(3)

plot_batch_sizes(titanic_batches)

png

หากคุณต้องการดำเนินการคำนวณแบบกำหนดเอง (เช่น เพื่อรวบรวมสถิติ) เมื่อสิ้นสุดแต่ละยุค จะเป็นการง่ายที่สุดที่จะรีสตาร์ทชุดข้อมูลซ้ำในแต่ละยุค:

epochs = 3
dataset = titanic_lines.batch(128)

for epoch in range(epochs):
  for batch in dataset:
    print(batch.shape)
  print("End of epoch: ", epoch)
(128,)
(128,)
(128,)
(128,)
(116,)
End of epoch:  0
(128,)
(128,)
(128,)
(128,)
(116,)
End of epoch:  1
(128,)
(128,)
(128,)
(128,)
(116,)
End of epoch:  2

สุ่มสับเปลี่ยนข้อมูลเข้า

Dataset.shuffle() การเปลี่ยนแปลงยังคงเป็นบัฟเฟอร์ขนาดคงที่และเลือกองค์ประกอบถัดไปอย่างสม่ำเสมอโดยการสุ่มจากบัฟเฟอร์ที่

เพิ่มดัชนีไปยังชุดข้อมูลเพื่อให้คุณเห็นผล:

lines = tf.data.TextLineDataset(titanic_file)
counter = tf.data.experimental.Counter()

dataset = tf.data.Dataset.zip((counter, lines))
dataset = dataset.shuffle(buffer_size=100)
dataset = dataset.batch(20)
dataset
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/data/experimental/ops/counter.py:66: scan (from tensorflow.python.data.experimental.ops.scan_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Dataset.scan(...) instead
<BatchDataset shapes: ((None,), (None,)), types: (tf.int64, tf.string)>

ตั้งแต่ buffer_size 100 และขนาดของชุดเป็น 20 ชุดแรกมีองค์ประกอบใด ๆ กับดัชนีกว่า 120

n,line_batch = next(iter(dataset))
print(n.numpy())
[ 79   8  60  24  11  56  65  58  67 108  59  81  92  70  94  57  27  73
  17  75]

เช่นเดียวกับ Dataset.batch เพื่อเทียบกับ Dataset.repeat เรื่อง

Dataset.shuffle ไม่ได้ส่งสัญญาณการสิ้นสุดของยุคจนกว่าบัฟเฟอร์สับเปลี่ยนเป็นที่ว่างเปล่า ดังนั้นการสับเปลี่ยนที่วางไว้ก่อนการทำซ้ำจะแสดงทุกองค์ประกอบของยุคหนึ่งก่อนที่จะย้ายไปที่ถัดไป:

dataset = tf.data.Dataset.zip((counter, lines))
shuffled = dataset.shuffle(buffer_size=100).batch(10).repeat(2)

print("Here are the item ID's near the epoch boundary:\n")
for n, line_batch in shuffled.skip(60).take(5):
  print(n.numpy())
Here are the item ID's near the epoch boundary:

[518 434 421 561 588 600 523 616 404 557]
[524 595 532 411 500 621 558 544 625 620]
[546 297 599 597 465 591 581 374]
[15  4  3  8 49 37 48 42 23 68]
[55 11 36 34 75 26 32 77 94 91]
shuffle_repeat = [n.numpy().mean() for n, line_batch in shuffled]
plt.plot(shuffle_repeat, label="shuffle().repeat()")
plt.ylabel("Mean item ID")
plt.legend()
<matplotlib.legend.Legend at 0x7fbce04a2d10>

png

แต่ให้ทำซ้ำก่อนที่การสับเปลี่ยนจะผสมขอบเขตของยุคเข้าด้วยกัน:

dataset = tf.data.Dataset.zip((counter, lines))
shuffled = dataset.repeat(2).shuffle(buffer_size=100).batch(10)

print("Here are the item ID's near the epoch boundary:\n")
for n, line_batch in shuffled.skip(55).take(15):
  print(n.numpy())
Here are the item ID's near the epoch boundary:

[614  15 484 606 517 618  17  16 593 218]
[620 575 604 535 496 449  23 605   2  38]
[  3 543 409 480 624  36 430 607 465 531]
[373 422 608 497   4 387 623 440 591 600]
[586 609 506  35  56  13  60 603 625  55]
[ 29  58 572 279 468  37  62  46  77 545]
[  7  68  45 622 563 528  18 499  66  84]
[ 31 568  26 358 613 393 557 511 583  89]
[81 59 96 47 92 57 93 49 67 72]
[ 90 111  27  74 565  65  98  75  80 110]
[610 339  63  69  48 104 112 114 471  61]
[102  19 113  88 611  95 117  10 118  73]
[510 379 592  40  54 571  64 503 144 509]
[101  20  41 479  30 137  34  50 374 433]
[538  51  43  24 617  86 153 140 143 124]
repeat_shuffle = [n.numpy().mean() for n, line_batch in shuffled]

plt.plot(shuffle_repeat, label="shuffle().repeat()")
plt.plot(repeat_shuffle, label="repeat().shuffle()")
plt.ylabel("Mean item ID")
plt.legend()
<matplotlib.legend.Legend at 0x7fbce04eb4d0>

png

กำลังประมวลผลข้อมูลล่วงหน้า

Dataset.map(f) การเปลี่ยนแปลงผลิตชุดใหม่โดยการใช้ฟังก์ชั่นได้รับ f องค์ประกอบของชุดข้อมูลที่ป้อนข้อมูลที่แต่ละ มันจะขึ้นอยู่กับ map() ฟังก์ชั่นที่ใช้กันทั่วไปในรายการ (และโครงสร้างอื่น ๆ ) ในภาษาเขียนโปรแกรมการทำงาน ฟังก์ชั่น f เตะ tf.Tensor วัตถุที่เป็นตัวแทนขององค์ประกอบหนึ่งในการป้อนข้อมูลและส่งกลับ tf.Tensor วัตถุที่จะเป็นตัวแทนขององค์ประกอบเดียวในชุดข้อมูลใหม่ การใช้งานนั้นใช้การดำเนินการ TensorFlow มาตรฐานเพื่อแปลงองค์ประกอบหนึ่งเป็นอีกองค์ประกอบหนึ่ง

ส่วนนี้จะครอบคลุมตัวอย่างทั่วไปของวิธีการใช้ Dataset.map()

ถอดรหัสข้อมูลภาพและปรับขนาด

เมื่อฝึกโครงข่ายประสาทเทียมกับข้อมูลภาพในโลกแห่งความเป็นจริง มักจะจำเป็นต้องแปลงภาพที่มีขนาดต่างกันให้เป็นขนาดทั่วไป เพื่อที่ภาพเหล่านั้นจะถูกจัดกลุ่มเป็นขนาดคงที่

สร้างชุดข้อมูลชื่อไฟล์ดอกไม้ใหม่:

list_ds = tf.data.Dataset.list_files(str(flowers_root/'*/*'))

เขียนฟังก์ชันที่จัดการองค์ประกอบของชุดข้อมูล

# Reads an image from a file, decodes it into a dense tensor, and resizes it
# to a fixed shape.
def parse_image(filename):
  parts = tf.strings.split(filename, os.sep)
  label = parts[-2]

  image = tf.io.read_file(filename)
  image = tf.image.decode_jpeg(image)
  image = tf.image.convert_image_dtype(image, tf.float32)
  image = tf.image.resize(image, [128, 128])
  return image, label

ทดสอบว่ามันใช้งานได้

file_path = next(iter(list_ds))
image, label = parse_image(file_path)

def show(image, label):
  plt.figure()
  plt.imshow(image)
  plt.title(label.numpy().decode('utf-8'))
  plt.axis('off')

show(image, label)

png

แมปไว้เหนือชุดข้อมูล

images_ds = list_ds.map(parse_image)

for image, label in images_ds.take(2):
  show(image, label)

png

png

การใช้ตรรกะ Python โดยพลการ

ด้วยเหตุผลด้านประสิทธิภาพ ให้ใช้การดำเนินการ TensorFlow เพื่อประมวลผลข้อมูลของคุณล่วงหน้าทุกครั้งที่ทำได้ อย่างไรก็ตาม บางครั้งการเรียกไลบรารี Python ภายนอกเมื่อแยกวิเคราะห์ข้อมูลอินพุตของคุณก็มีประโยชน์ คุณสามารถใช้ tf.py_function() การดำเนินงานใน Dataset.map() การเปลี่ยนแปลง

ตัวอย่างเช่นถ้าคุณต้องการใช้การหมุนสุ่ม tf.image โมดูลมีเพียง tf.image.rot90 ซึ่งไม่ได้เป็นประโยชน์มากสำหรับการเสริมภาพ

เพื่อแสดงให้เห็น tf.py_function ลองใช้ scipy.ndimage.rotate ฟังก์ชั่นแทน:

import scipy.ndimage as ndimage

def random_rotate_image(image):
  image = ndimage.rotate(image, np.random.uniform(-30, 30), reshape=False)
  return image
image, label = next(iter(images_ds))
image = random_rotate_image(image)
show(image, label)
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

png

ที่จะใช้ฟังก์ชั่นนี้กับ Dataset.map caveats เดียวกันใช้เช่นเดียวกับ Dataset.from_generator คุณจะต้องอธิบายรูปร่างกลับมาและประเภทเมื่อคุณใช้ฟังก์ชั่น:

def tf_random_rotate_image(image, label):
  im_shape = image.shape
  [image,] = tf.py_function(random_rotate_image, [image], [tf.float32])
  image.set_shape(im_shape)
  return image, label
rot_ds = images_ds.map(tf_random_rotate_image)

for image, label in rot_ds.take(2):
  show(image, label)
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).

png

png

แยก tf.Example ข้อความบัฟเฟอร์โปรโตคอล

ท่อป้อนข้อมูลหลายแยก tf.train.Example ข้อความบัฟเฟอร์โปรโตคอลจากรูปแบบ TFRecord แต่ละ tf.train.Example บันทึกมีมากกว่าหนึ่ง "คุณสมบัติ" และท่อป้อนข้อมูลมักจะแปลงคุณลักษณะเหล่านี้เป็นเทนเซอร์

fsns_test_file = tf.keras.utils.get_file("fsns.tfrec", "https://storage.googleapis.com/download.tensorflow.org/data/fsns-20160927/testdata/fsns-00000-of-00001")
dataset = tf.data.TFRecordDataset(filenames = [fsns_test_file])
dataset
<TFRecordDatasetV2 shapes: (), types: tf.string>

คุณสามารถทำงานกับ tf.train.Example Protos นอก tf.data.Dataset จะเข้าใจข้อมูล:

raw_example = next(iter(dataset))
parsed = tf.train.Example.FromString(raw_example.numpy())

feature = parsed.features.feature
raw_img = feature['image/encoded'].bytes_list.value[0]
img = tf.image.decode_png(raw_img)
plt.imshow(img)
plt.axis('off')
_ = plt.title(feature["image/text"].bytes_list.value[0])

png

raw_example = next(iter(dataset))
def tf_parse(eg):
  example = tf.io.parse_example(
      eg[tf.newaxis], {
          'image/encoded': tf.io.FixedLenFeature(shape=(), dtype=tf.string),
          'image/text': tf.io.FixedLenFeature(shape=(), dtype=tf.string)
      })
  return example['image/encoded'][0], example['image/text'][0]
img, txt = tf_parse(raw_example)
print(txt.numpy())
print(repr(img.numpy()[:20]), "...")
b'Rue Perreyon'
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x02X' ...
decoded = dataset.map(tf_parse)
decoded
<MapDataset shapes: ((), ()), types: (tf.string, tf.string)>
image_batch, text_batch = next(iter(decoded.batch(10)))
image_batch.shape
TensorShape([10])

กรอบเวลาของอนุกรมเวลา

สำหรับสิ้นเพื่อวางอนุกรมเวลาดูตัวอย่าง: การพยากรณ์อนุกรมเวลา

ข้อมูลอนุกรมเวลามักถูกจัดระเบียบโดยให้แกนเวลาไม่เสียหาย

ใช้ง่าย Dataset.range แสดงให้เห็นถึง:

range_ds = tf.data.Dataset.range(100000)

โดยปกติ โมเดลที่อิงตามข้อมูลประเภทนี้จะต้องการการแบ่งเวลาแบบต่อเนื่องกัน

วิธีที่ง่ายที่สุดคือแบทช์ข้อมูล:

การใช้ batch

batches = range_ds.batch(10, drop_remainder=True)

for batch in batches.take(5):
  print(batch.numpy())
[0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[20 21 22 23 24 25 26 27 28 29]
[30 31 32 33 34 35 36 37 38 39]
[40 41 42 43 44 45 46 47 48 49]

หรือหากต้องการคาดการณ์อย่างหนาแน่นหนึ่งก้าวสู่อนาคต คุณอาจเปลี่ยนคุณลักษณะและป้ายกำกับทีละขั้นโดยสัมพันธ์กัน:

def dense_1_step(batch):
  # Shift features and labels one step relative to each other.
  return batch[:-1], batch[1:]

predict_dense_1_step = batches.map(dense_1_step)

for features, label in predict_dense_1_step.take(3):
  print(features.numpy(), " => ", label.numpy())
[0 1 2 3 4 5 6 7 8]  =>  [1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18]  =>  [11 12 13 14 15 16 17 18 19]
[20 21 22 23 24 25 26 27 28]  =>  [21 22 23 24 25 26 27 28 29]

ในการทำนายทั้งหน้าต่างแทนออฟเซ็ตคงที่ คุณสามารถแบ่งแบทช์ออกเป็นสองส่วน:

batches = range_ds.batch(15, drop_remainder=True)

def label_next_5_steps(batch):
  return (batch[:-5],   # Inputs: All except the last 5 steps
          batch[-5:])   # Labels: The last 5 steps

predict_5_steps = batches.map(label_next_5_steps)

for features, label in predict_5_steps.take(3):
  print(features.numpy(), " => ", label.numpy())
[0 1 2 3 4 5 6 7 8 9]  =>  [10 11 12 13 14]
[15 16 17 18 19 20 21 22 23 24]  =>  [25 26 27 28 29]
[30 31 32 33 34 35 36 37 38 39]  =>  [40 41 42 43 44]

ในการอนุญาตให้บางส่วนทับซ้อนระหว่างคุณสมบัติของชุดหนึ่งและป้ายชื่อของผู้อื่นให้ใช้ Dataset.zip :

feature_length = 10
label_length = 3

features = range_ds.batch(feature_length, drop_remainder=True)
labels = range_ds.batch(feature_length).skip(1).map(lambda labels: labels[:label_length])

predicted_steps = tf.data.Dataset.zip((features, labels))

for features, label in predicted_steps.take(5):
  print(features.numpy(), " => ", label.numpy())
[0 1 2 3 4 5 6 7 8 9]  =>  [10 11 12]
[10 11 12 13 14 15 16 17 18 19]  =>  [20 21 22]
[20 21 22 23 24 25 26 27 28 29]  =>  [30 31 32]
[30 31 32 33 34 35 36 37 38 39]  =>  [40 41 42]
[40 41 42 43 44 45 46 47 48 49]  =>  [50 51 52]

การใช้ window

ในขณะที่ใช้ Dataset.batch งานมีสถานการณ์ที่คุณอาจต้องควบคุมปลีกย่อย Dataset.window วิธีช่วยให้คุณควบคุม แต่ต้องดูแลบางอย่างจะส่งกลับ Dataset ของ Datasets ดู โครงสร้างชุดข้อมูล รายละเอียด

window_size = 5

windows = range_ds.window(window_size, shift=1)
for sub_ds in windows.take(5):
  print(sub_ds)
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>
<_VariantDataset shapes: (), types: tf.int64>

Dataset.flat_map วิธีสามารถใช้ชุดข้อมูลชุดข้อมูลและแผ่ให้มันกลายเป็นชุดเดียว:

for x in windows.flat_map(lambda x: x).take(30):
   print(x.numpy(), end=' ')
0 1 2 3 4 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9

ในเกือบทุกกรณีคุณจะต้องการที่จะ .batch ชุดแรก:

def sub_to_batch(sub):
  return sub.batch(window_size, drop_remainder=True)

for example in windows.flat_map(sub_to_batch).take(5):
  print(example.numpy())
[0 1 2 3 4]
[1 2 3 4 5]
[2 3 4 5 6]
[3 4 5 6 7]
[4 5 6 7 8]

ตอนนี้คุณสามารถเห็นได้ว่า shift การควบคุมอาร์กิวเมนต์เท่าใดแต่ละหน้าต่างย้ายมากกว่า

เมื่อรวมสิ่งนี้เข้าด้วยกัน คุณอาจเขียนฟังก์ชันนี้:

def make_window_dataset(ds, window_size=5, shift=1, stride=1):
  windows = ds.window(window_size, shift=shift, stride=stride)

  def sub_to_batch(sub):
    return sub.batch(window_size, drop_remainder=True)

  windows = windows.flat_map(sub_to_batch)
  return windows
ds = make_window_dataset(range_ds, window_size=10, shift = 5, stride=3)

for example in ds.take(10):
  print(example.numpy())
[ 0  3  6  9 12 15 18 21 24 27]
[ 5  8 11 14 17 20 23 26 29 32]
[10 13 16 19 22 25 28 31 34 37]
[15 18 21 24 27 30 33 36 39 42]
[20 23 26 29 32 35 38 41 44 47]
[25 28 31 34 37 40 43 46 49 52]
[30 33 36 39 42 45 48 51 54 57]
[35 38 41 44 47 50 53 56 59 62]
[40 43 46 49 52 55 58 61 64 67]
[45 48 51 54 57 60 63 66 69 72]

จากนั้น แยกป้ายกำกับได้ง่ายเหมือนเมื่อก่อน:

dense_labels_ds = ds.map(dense_1_step)

for inputs,labels in dense_labels_ds.take(3):
  print(inputs.numpy(), "=>", labels.numpy())
[ 0  3  6  9 12 15 18 21 24] => [ 3  6  9 12 15 18 21 24 27]
[ 5  8 11 14 17 20 23 26 29] => [ 8 11 14 17 20 23 26 29 32]
[10 13 16 19 22 25 28 31 34] => [13 16 19 22 25 28 31 34 37]

สุ่มตัวอย่างใหม่

เมื่อทำงานกับชุดข้อมูลที่มีคลาสไม่สมดุลมาก คุณอาจต้องการสุ่มตัวอย่างชุดข้อมูล tf.data มีสองวิธีการที่จะทำเช่นนี้ ชุดข้อมูลการฉ้อโกงบัตรเครดิตเป็นตัวอย่างที่ดีของปัญหาประเภทนี้

zip_path = tf.keras.utils.get_file(
    origin='https://storage.googleapis.com/download.tensorflow.org/data/creditcard.zip',
    fname='creditcard.zip',
    extract=True)

csv_path = zip_path.replace('.zip', '.csv')
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/creditcard.zip
69156864/69155632 [==============================] - 3s 0us/step
69165056/69155632 [==============================] - 3s 0us/step
creditcard_ds = tf.data.experimental.make_csv_dataset(
    csv_path, batch_size=1024, label_name="Class",
    # Set the column types: 30 floats and an int.
    column_defaults=[float()]*30+[int()])

ตอนนี้ตรวจสอบการกระจายของคลาส มันเบ้มาก:

def count(counts, batch):
  features, labels = batch
  class_1 = labels == 1
  class_1 = tf.cast(class_1, tf.int32)

  class_0 = labels == 0
  class_0 = tf.cast(class_0, tf.int32)

  counts['class_0'] += tf.reduce_sum(class_0)
  counts['class_1'] += tf.reduce_sum(class_1)

  return counts
counts = creditcard_ds.take(10).reduce(
    initial_state={'class_0': 0, 'class_1': 0},
    reduce_func = count)

counts = np.array([counts['class_0'].numpy(),
                   counts['class_1'].numpy()]).astype(np.float32)

fractions = counts/counts.sum()
print(fractions)
[0.9964 0.0036]

วิธีการทั่วไปในการฝึกอบรมด้วยชุดข้อมูลที่ไม่สมดุลคือการทำให้สมดุล tf.data มีไม่กี่วิธีที่ช่วยให้ขั้นตอนการทำงานนี้:

การสุ่มตัวอย่างชุดข้อมูล

วิธีการหนึ่งที่จะ resampling ชุดคือการใช้ sample_from_datasets นี้มีผลบังคับใช้มากขึ้นเมื่อคุณมีแยก data.Dataset สำหรับแต่ละชั้นเรียน

ที่นี่ เพียงใช้ตัวกรองเพื่อสร้างจากข้อมูลการฉ้อโกงบัตรเครดิต:

negative_ds = (
  creditcard_ds
    .unbatch()
    .filter(lambda features, label: label==0)
    .repeat())
positive_ds = (
  creditcard_ds
    .unbatch()
    .filter(lambda features, label: label==1)
    .repeat())
for features, label in positive_ds.batch(10).take(1):
  print(label.numpy())
[1 1 1 1 1 1 1 1 1 1]

กับการใช้ tf.data.experimental.sample_from_datasets ผ่านชุดข้อมูลและน้ำหนักของแต่ละ:

balanced_ds = tf.data.experimental.sample_from_datasets(
    [negative_ds, positive_ds], [0.5, 0.5]).batch(10)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/data/experimental/ops/interleave_ops.py:260: RandomDataset.__init__ (from tensorflow.python.data.ops.dataset_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Dataset.random(...)`.

ตอนนี้ชุดข้อมูลสร้างตัวอย่างของแต่ละคลาสด้วยความน่าจะเป็น 50/50:

for features, labels in balanced_ds.take(10):
  print(labels.numpy())
[1 0 1 0 0 1 1 1 0 0]
[1 1 1 1 0 0 0 0 1 0]
[1 1 1 1 0 0 1 1 1 1]
[0 1 0 0 0 1 1 1 0 1]
[0 1 0 0 0 1 0 0 1 1]
[0 1 0 0 1 1 1 0 1 0]
[1 0 1 0 0 0 0 1 1 1]
[0 1 0 1 0 0 1 1 0 0]
[0 0 1 0 0 1 0 0 0 1]
[1 0 1 0 0 0 0 1 0 1]

การสุ่มตัวอย่างการปฏิเสธ

หนึ่งปัญหากับข้างต้น experimental.sample_from_datasets วิธีการก็คือว่ามันต้องแยก tf.data.Dataset ต่อชั้น ใช้ Dataset.filter งาน แต่ผลในข้อมูลทั้งหมดที่ถูกโหลดครั้งที่สอง

data.experimental.rejection_resample ฟังก์ชั่นสามารถนำไปใช้ชุดข้อมูลเพื่อปรับสมดุลของมันในขณะที่เพียงโหลดเพียงครั้งเดียว องค์ประกอบจะถูกลบออกจากชุดข้อมูลเพื่อให้เกิดความสมดุล

data.experimental.rejection_resample ยิง class_func โต้แย้ง นี้ class_func ถูกนำไปใช้แต่ละองค์ประกอบชุดและจะใช้ในการตรวจสอบที่ชั้นตัวอย่างเป็นสำหรับวัตถุประสงค์ของการสมดุล

องค์ประกอบของ creditcard_ds มีอยู่แล้ว (features, label) คู่ ดังนั้น class_func เพียงแค่ต้องการที่จะกลับป้ายเหล่านั้น

def class_func(features, label):
  return label

ตัวสุ่มตัวอย่างยังต้องการการกระจายเป้าหมาย และตัวเลือกการประมาณการการกระจายเริ่มต้น:

resampler = tf.data.experimental.rejection_resample(
    class_func, target_dist=[0.5, 0.5], initial_dist=fractions)

ข้อเสนอที่ resampler กับตัวอย่างของแต่ละบุคคลดังนั้นคุณต้อง unbatch ชุดก่อนที่จะใช้ resampler นี้:

resample_ds = creditcard_ds.unbatch().apply(resampler).batch(10)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/data/experimental/ops/resampling.py:159: Print (from tensorflow.python.ops.logging_ops) is deprecated and will be removed after 2018-08-20.
Instructions for updating:
Use tf.print instead of tf.Print. Note that tf.print returns a no-output operator that directly prints the output. Outside of defuns or eager mode, this operator will not be executed unless it is directly specified in session.run or used as a control dependency for other operators. This is only a concern in graph mode. Below is an example of how to ensure tf.print executes in graph mode:

ผลตอบแทนที่ได้ resampler สร้าง (class, example) คู่จากการแสดงผลของ class_func ในกรณีนี้ example ได้แล้ว (feature, label) คู่เพื่อให้การใช้งาน map จะลดการสำเนาพิเศษของฉลาก:

balanced_ds = resample_ds.map(lambda extra_label, features_and_label: features_and_label)

ตอนนี้ชุดข้อมูลสร้างตัวอย่างของแต่ละคลาสด้วยความน่าจะเป็น 50/50:

for features, labels in balanced_ds.take(10):
  print(labels.numpy())
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
Proportion of examples rejected by sampler is high: [0.996386707][0.996386707 0.0036132813][0 1]
[1 1 0 1 1 1 1 1 0 1]
[0 0 0 1 1 0 0 1 0 1]
[0 0 0 1 0 0 1 1 0 1]
[0 0 0 1 0 0 1 1 0 0]
[0 1 1 0 1 0 1 0 0 0]
[0 0 1 0 1 1 0 0 0 0]
[0 0 0 1 1 1 0 1 1 1]
[0 0 0 1 1 0 0 0 1 1]
[0 0 1 1 0 1 0 0 0 0]
[1 0 0 0 1 1 1 0 0 0]

จุดตรวจ Iterator

สนับสนุน Tensorflow การจุดตรวจ เพื่อที่ว่าเมื่อขั้นตอนการฝึกอบรมของคุณเตะมันสามารถเรียกคืนด่านใหม่ล่าสุดที่จะกู้คืนมากที่สุดของความคืบหน้า นอกจากจุดตรวจสอบตัวแปรโมเดลแล้ว คุณยังสามารถตรวจสอบความคืบหน้าของตัววนซ้ำชุดข้อมูลได้อีกด้วย ซึ่งอาจเป็นประโยชน์หากคุณมีชุดข้อมูลขนาดใหญ่และไม่ต้องการเริ่มชุดข้อมูลตั้งแต่ต้นในการรีสตาร์ทแต่ละครั้ง แต่ทราบว่าด่าน iterator อาจมีขนาดใหญ่ตั้งแต่การเปลี่ยนแปลงเช่น shuffle และ prefetch จำเป็นต้องมีองค์ประกอบบัฟเฟอร์ภายในการทำซ้ำโดย

ที่จะรวม iterator ของคุณได้ในด่านผ่าน iterator ไป tf.train.Checkpoint คอนสตรัค

range_ds = tf.data.Dataset.range(20)

iterator = iter(range_ds)
ckpt = tf.train.Checkpoint(step=tf.Variable(0), iterator=iterator)
manager = tf.train.CheckpointManager(ckpt, '/tmp/my_ckpt', max_to_keep=3)

print([next(iterator).numpy() for _ in range(5)])

save_path = manager.save()

print([next(iterator).numpy() for _ in range(5)])

ckpt.restore(manager.latest_checkpoint)

print([next(iterator).numpy() for _ in range(5)])
[0, 1, 2, 3, 4]
[5, 6, 7, 8, 9]
[5, 6, 7, 8, 9]

การใช้ tf.data กับ tf.keras

tf.keras API ช่วยลดความยุ่งยากหลายแง่มุมของการสร้างและการดำเนินโมเดลการเรียนรู้ มัน .fit() และ .evaluate() และ .predict() API ที่สนับสนุนชุดข้อมูลเป็นปัจจัยการผลิต นี่คือชุดข้อมูลและการตั้งค่าแบบจำลองอย่างรวดเร็ว:

train, test = tf.keras.datasets.fashion_mnist.load_data()

images, labels = train
images = images/255.0
labels = labels.astype(np.int32)
fmnist_train_ds = tf.data.Dataset.from_tensor_slices((images, labels))
fmnist_train_ds = fmnist_train_ds.shuffle(5000).batch(32)

model = tf.keras.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(10)
])

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), 
              metrics=['accuracy'])

ผ่านชุดของ (feature, label) คู่เป็นสิ่งที่จำเป็นสำหรับการ Model.fit และ Model.evaluate :

model.fit(fmnist_train_ds, epochs=2)
Epoch 1/2
1875/1875 [==============================] - 4s 2ms/step - loss: 0.5993 - accuracy: 0.7991
Epoch 2/2
1875/1875 [==============================] - 3s 2ms/step - loss: 0.4618 - accuracy: 0.8410
<keras.callbacks.History at 0x7fbce01a3810>

หากคุณผ่านชุดข้อมูลที่ไม่มีที่สิ้นสุดเช่นโดยการเรียก Dataset.repeat() คุณก็ยังจำเป็นต้องผ่านการ steps_per_epoch อาร์กิวเมนต์:

model.fit(fmnist_train_ds.repeat(), epochs=2, steps_per_epoch=20)
Epoch 1/2
20/20 [==============================] - 0s 2ms/step - loss: 0.4410 - accuracy: 0.8484
Epoch 2/2
20/20 [==============================] - 0s 2ms/step - loss: 0.4588 - accuracy: 0.8547
<keras.callbacks.History at 0x7fb900392250>

สำหรับการประเมิน คุณสามารถผ่านจำนวนขั้นตอนการประเมินได้:

loss, accuracy = model.evaluate(fmnist_train_ds)
print("Loss :", loss)
print("Accuracy :", accuracy)
1875/1875 [==============================] - 4s 2ms/step - loss: 0.4328 - accuracy: 0.8520
Loss : 0.4328066110610962
Accuracy : 0.8520166873931885

สำหรับชุดข้อมูลแบบยาว ให้กำหนดจำนวนขั้นตอนในการประเมิน:

loss, accuracy = model.evaluate(fmnist_train_ds.repeat(), steps=10)
print("Loss :", loss)
print("Accuracy :", accuracy)
10/10 [==============================] - 0s 2ms/step - loss: 0.5152 - accuracy: 0.8313
Loss : 0.5151785612106323
Accuracy : 0.831250011920929

ป้ายไม่จำเป็นในเมื่อโทร Model.predict

predict_ds = tf.data.Dataset.from_tensor_slices(images).batch(32)
result = model.predict(predict_ds, steps = 10)
print(result.shape)
(320, 10)

แต่ป้ายกำกับจะถูกละเว้นหากคุณส่งชุดข้อมูลที่มี:

result = model.predict(fmnist_train_ds, steps = 10)
print(result.shape)
(320, 10)