Giúp bảo vệ Great Barrier Reef với TensorFlow trên Kaggle Tham Challenge

Tải và xử lý trước hình ảnh

Xem trên TensorFlow.org Xem nguồn trên GitHub Tải xuống sổ ghi chép

Hướng dẫn này chỉ ra cách tải và xử lý trước một tập dữ liệu hình ảnh theo ba cách:

Cài đặt

import numpy as np
import os
import PIL
import PIL.Image
import tensorflow as tf
import tensorflow_datasets as tfds
print(tf.__version__)
2.6.0

Tải xuống bộ dữ liệu về hoa

Hướng dẫn này sử dụng một tập dữ liệu gồm hàng nghìn bức ảnh về hoa. Tập dữ liệu về hoa chứa năm thư mục con, mỗi thư mục con:

flowers_photos/
  daisy/
  dandelion/
  roses/
  sunflowers/
  tulips/
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file(origin=dataset_url,
                                   fname='flower_photos',
                                   untar=True)
data_dir = pathlib.Path(data_dir)

Sau khi tải xuống (218MB), bây giờ bạn sẽ có sẵn một bản sao của các bức ảnh hoa. Có tổng cộng 3.670 hình ảnh:

image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)
3670

Mỗi thư mục chứa hình ảnh của loại hoa đó. Đây là một số loại hoa hồng:

roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))

png

roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[1]))

png

Tải dữ liệu bằng tiện ích Keras

Hãy tải những hình ảnh này ra đĩa bằng cách sử dụng hữu ích tf.keras.utils.image_dataset_from_directory tiện ích.

Tạo tập dữ liệu

Xác định một số tham số cho trình nạp:

batch_size = 32
img_height = 180
img_width = 180

Bạn nên sử dụng phân tách xác thực khi phát triển mô hình của mình. Bạn sẽ sử dụng 80% hình ảnh để đào tạo và 20% để xác nhận.

train_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
val_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)
Found 3670 files belonging to 5 classes.
Using 734 files for validation.

Bạn có thể tìm ra tên lớp trong class_names thuộc tính trên các bộ dữ liệu.

class_names = train_ds.class_names
print(class_names)
['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips']

Trực quan hóa dữ liệu

Đây là chín hình ảnh đầu tiên từ tập dữ liệu đào tạo.

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")

png

Bạn có thể đào tạo một mô hình sử dụng các bộ dữ liệu bằng cách thông qua họ để model.fit (hiển thị sau này trong hướng dẫn này). Nếu muốn, bạn cũng có thể lặp lại theo cách thủ công qua tập dữ liệu và truy xuất hàng loạt hình ảnh:

for image_batch, labels_batch in train_ds:
  print(image_batch.shape)
  print(labels_batch.shape)
  break
(32, 180, 180, 3)
(32,)

Các image_batch là một tensor của hình (32, 180, 180, 3) . Đây là một loạt các hình ảnh 32 hình dạng 180x180x3 (kích thước cuối cùng đề cập đến các kênh màu RGB). Các label_batch là một tensor của hình (32,) , đây là những tương ứng với nhãn đến 32 hình ảnh.

Bạn có thể gọi .numpy() trên một trong những tensors để chuyển đổi chúng sang một numpy.ndarray .

Chuẩn hóa dữ liệu

Các giá trị kênh RGB đang trong [0, 255] phạm vi. Điều này không lý tưởng cho một mạng nơ-ron; nói chung, bạn nên tìm cách làm nhỏ các giá trị đầu vào của mình.

Ở đây, bạn sẽ chuẩn hóa các giá trị được trong [0, 1] phạm vi bằng cách sử dụng tf.keras.layers.Rescaling :

normalization_layer = tf.keras.layers.Rescaling(1./255)

Có hai cách để sử dụng lớp này. Bạn có thể áp dụng nó vào các tập dữ liệu bằng cách gọi Dataset.map :

normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
image_batch, labels_batch = next(iter(normalized_ds))
first_image = image_batch[0]
# Notice the pixel values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image))
0.0 0.96902645

Hoặc, bạn có thể bao gồm lớp bên trong định nghĩa mô hình của mình để đơn giản hóa việc triển khai. Bạn sẽ sử dụng cách tiếp cận thứ hai ở đây.

Định cấu hình tập dữ liệu cho hiệu suất

Hãy đảm bảo sử dụng tìm nạp trước có bộ đệm để bạn có thể mang lại dữ liệu từ đĩa mà không bị chặn I / O. Đây là hai phương pháp quan trọng bạn nên sử dụng khi tải dữ liệu:

  • Dataset.cache giữ những hình ảnh trong bộ nhớ sau khi họ đang nạp tắt đĩa trong kỷ nguyên đầu tiên. Điều này sẽ đảm bảo tập dữ liệu không trở thành nút cổ chai trong khi đào tạo mô hình của bạn. Nếu tập dữ liệu của bạn quá lớn để vừa với bộ nhớ, bạn cũng có thể sử dụng phương pháp này để tạo bộ đệm ẩn trên đĩa hoạt động hiệu quả.
  • Dataset.prefetch trùng lặp dữ liệu tiền xử lý và mô hình thực hiện trong khi đào tạo.

Bạn đọc quan tâm có thể tìm hiểu thêm về cả hai phương pháp, cũng như làm thế nào để dữ liệu bộ nhớ cache vào đĩa trong phần Prefetching của hiệu suất với tf.data API Better dẫn.

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

Đào tạo một người mẫu

Để hoàn chỉnh, bạn sẽ chỉ ra cách huấn luyện một mô hình đơn giản bằng cách sử dụng các bộ dữ liệu bạn vừa chuẩn bị.

Các tuần tự mô hình bao gồm ba khối chập ( tf.keras.layers.Conv2D ) với một lớp tổng hợp max ( tf.keras.layers.MaxPooling2D ) trong mỗi trong số họ. Có một lớp đầy đủ kết nối ( tf.keras.layers.Dense ) với 128 đơn vị trên đầu trang của nó được kích hoạt bằng một chức năng kích hoạt ReLU ( 'relu' ). Mô hình này chưa được điều chỉnh theo bất kỳ cách nào — mục đích là cho bạn thấy cơ chế sử dụng các tập dữ liệu bạn vừa tạo. Để tìm hiểu thêm về phân loại hình ảnh, truy cập vào phân loại hình ảnh hướng dẫn.

num_classes = 5

model = tf.keras.Sequential([
  tf.keras.layers.Rescaling(1./255),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(num_classes)
])

Chọn tf.keras.optimizers.Adam ưu và tf.keras.losses.SparseCategoricalCrossentropy chức năng thua lỗ. Để xem đào tạo và chính xác xác nhận cho mỗi thời đại đào tạo, vượt qua metrics lập luận để Model.compile .

model.compile(
  optimizer='adam',
  loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
  metrics=['accuracy'])
model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 4s 21ms/step - loss: 1.2935 - accuracy: 0.4588 - val_loss: 1.1072 - val_accuracy: 0.5463
Epoch 2/3
92/92 [==============================] - 1s 11ms/step - loss: 1.0370 - accuracy: 0.5834 - val_loss: 0.9830 - val_accuracy: 0.6226
Epoch 3/3
92/92 [==============================] - 1s 11ms/step - loss: 0.8740 - accuracy: 0.6689 - val_loss: 0.9003 - val_accuracy: 0.6676
<keras.callbacks.History at 0x7f44180b31d0>

Bạn có thể nhận thấy độ chính xác xác thực thấp so với độ chính xác đào tạo, cho thấy mô hình của bạn đang quá trang bị. Bạn có thể tìm hiểu thêm về overfitting và làm thế nào để giảm nó trong này hướng dẫn .

Sử dụng tf.data để kiểm soát tốt hơn

Trên đây Keras tiền xử lý utility- tf.keras.utils.image_dataset_from_directory -is một cách thuận tiện để tạo ra một tf.data.Dataset từ một thư mục của hình ảnh.

Để kiểm soát hạt mịn, bạn có thể ghi đường dẫn đầu vào của riêng bạn sử dụng tf.data . Phần này chỉ ra cách thực hiện điều đó, bắt đầu với các đường dẫn tệp từ tệp TGZ mà bạn đã tải xuống trước đó.

list_ds = tf.data.Dataset.list_files(str(data_dir/'*/*'), shuffle=False)
list_ds = list_ds.shuffle(image_count, reshuffle_each_iteration=False)
for f in list_ds.take(5):
  print(f.numpy())
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/16055807744_000bc07afc_m.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/14399435971_ea5868c792.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/13509973805_bda5fa8982.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/6994925894_030e157fe0.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/sunflowers/4890268276_563f40a193.jpg'

Cấu trúc cây của các tập tin có thể được sử dụng để biên dịch một class_names danh sách.

class_names = np.array(sorted([item.name for item in data_dir.glob('*') if item.name != "LICENSE.txt"]))
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']

Chia bộ dữ liệu thành các bộ đào tạo và xác nhận:

val_size = int(image_count * 0.2)
train_ds = list_ds.skip(val_size)
val_ds = list_ds.take(val_size)

Bạn có thể in độ dài của mỗi tập dữ liệu như sau:

print(tf.data.experimental.cardinality(train_ds).numpy())
print(tf.data.experimental.cardinality(val_ds).numpy())
2936
734

Viết một hàm ngắn có thể chuyển đổi một đường dẫn tập tin đến một (img, label) cặp:

def get_label(file_path):
  # Convert the path to a list of path components
  parts = tf.strings.split(file_path, os.path.sep)
  # The second to last is the class-directory
  one_hot = parts[-2] == class_names
  # Integer encode the label
  return tf.argmax(one_hot)
def decode_img(img):
  # Convert the compressed string to a 3D uint8 tensor
  img = tf.io.decode_jpeg(img, channels=3)
  # Resize the image to the desired size
  return tf.image.resize(img, [img_height, img_width])
def process_path(file_path):
  label = get_label(file_path)
  # Load the raw data from the file as a string
  img = tf.io.read_file(file_path)
  img = decode_img(img)
  return img, label

Sử dụng Dataset.map để tạo ra một bộ dữ liệu của image, label cặp:

# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.
train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)
val_ds = val_ds.map(process_path, num_parallel_calls=AUTOTUNE)
for image, label in train_ds.take(1):
  print("Image shape: ", image.numpy().shape)
  print("Label: ", label.numpy())
Image shape:  (180, 180, 3)
Label:  2

Định cấu hình tập dữ liệu cho hiệu suất

Để đào tạo một mô hình với tập dữ liệu này, bạn sẽ muốn có dữ liệu:

  • Để được xáo trộn tốt.
  • Để được chia lô.
  • Hàng loạt để có sẵn càng sớm càng tốt.

Những tính năng này có thể được bổ sung bằng cách sử dụng tf.data API. Để biết thêm chi tiết, hãy truy cập đường ống Performance Input dẫn.

def configure_for_performance(ds):
  ds = ds.cache()
  ds = ds.shuffle(buffer_size=1000)
  ds = ds.batch(batch_size)
  ds = ds.prefetch(buffer_size=AUTOTUNE)
  return ds

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)

Trực quan hóa dữ liệu

Bạn có thể hình dung tập dữ liệu này tương tự như tập dữ liệu bạn đã tạo trước đó:

image_batch, label_batch = next(iter(train_ds))

plt.figure(figsize=(10, 10))
for i in range(9):
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(image_batch[i].numpy().astype("uint8"))
  label = label_batch[i]
  plt.title(class_names[label])
  plt.axis("off")
2021-10-26 01:32:12.160250: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

Tiếp tục đào tạo mô hình

Bây giờ bạn đã tự xây dựng một tương tự tf.data.Dataset đến một trong những tạo ra bởi tf.keras.utils.image_dataset_from_directory trên. Bạn có thể tiếp tục đào tạo mô hình với nó. Như trước đây, bạn sẽ tập luyện chỉ trong một vài kỷ nguyên để giữ cho thời gian chạy ngắn.

model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 2s 20ms/step - loss: 0.7521 - accuracy: 0.7183 - val_loss: 0.6710 - val_accuracy: 0.7452
Epoch 2/3
92/92 [==============================] - 1s 12ms/step - loss: 0.5771 - accuracy: 0.7861 - val_loss: 0.7169 - val_accuracy: 0.7221
Epoch 3/3
92/92 [==============================] - 1s 12ms/step - loss: 0.3940 - accuracy: 0.8542 - val_loss: 0.7691 - val_accuracy: 0.7180
<keras.callbacks.History at 0x7f437822c710>

Sử dụng tập dữ liệu TensorFlow

Cho đến nay, hướng dẫn này tập trung vào việc tải dữ liệu ra đĩa. Bạn cũng có thể tìm thấy một tập dữ liệu để sử dụng bằng cách khám phá lớn Danh mục của bộ dữ liệu dễ dàng để tải xuống tại TensorFlow Datasets .

Như trước đây bạn đã tải tập dữ liệu Flowers ra đĩa, bây giờ hãy nhập tập dữ liệu đó bằng TensorFlow Datasets.

Tải Flowers bộ dữ liệu sử dụng TensorFlow Datasets:

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

Tập dữ liệu về hoa có năm lớp:

num_classes = metadata.features['label'].num_classes
print(num_classes)
5

Lấy một hình ảnh từ tập dữ liệu:

get_label_name = metadata.features['label'].int2str

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2021-10-26 01:32:22.877036: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

Như trước đây, hãy nhớ hàng loạt, xáo trộn và định cấu hình các bộ đào tạo, xác thực và kiểm tra cho hiệu suất:

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)
test_ds = configure_for_performance(test_ds)

Bạn có thể tìm thấy một ví dụ hoàn chỉnh làm việc với các tập dữ liệu Flowers và TensorFlow Datasets bằng cách truy cập augmentation liệu hướng dẫn.

Bước tiếp theo

Hướng dẫn này chỉ ra hai cách tải hình ảnh ra đĩa. Đầu tiên, bạn đã học cách tải và xử lý trước một tập dữ liệu hình ảnh bằng cách sử dụng các lớp và tiện ích tiền xử lý của Keras. Tiếp theo, bạn đã học được làm thế nào để viết một đường ống đầu vào từ đầu sử dụng tf.data . Cuối cùng, bạn đã học cách tải xuống tập dữ liệu từ TensorFlow Datasets.

Đối với các bước tiếp theo của bạn: