การจำแนกรูปภาพ Image

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

บทช่วยสอนนี้แสดงวิธีจำแนกรูปภาพดอกไม้ มันสร้างตัวแยกประเภทรูปภาพโดยใช้โมเดล keras.Sequential และโหลดข้อมูลโดยใช้ preprocessing.image_dataset_from_directory คุณจะได้รับประสบการณ์เชิงปฏิบัติด้วยแนวคิดต่อไปนี้:

  • โหลดชุดข้อมูลออกจากดิสก์อย่างมีประสิทธิภาพ
  • ระบุเทคนิคที่เกินพอดีและปรับใช้เพื่อลดปัญหา รวมถึงการเสริมข้อมูลและการออกกลางคัน

บทช่วยสอนนี้เป็นไปตามเวิร์กโฟลว์การเรียนรู้ของเครื่องขั้นพื้นฐาน:

  1. ตรวจสอบและทำความเข้าใจข้อมูล
  2. สร้างไปป์ไลน์อินพุต
  3. สร้างโมเดล
  4. ฝึกโมเดล
  5. ทดสอบโมเดล
  6. ปรับปรุงแบบจำลองและทำซ้ำกระบวนการ

นำเข้า TensorFlow และไลบรารีอื่นๆ

import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential

ดาวน์โหลดและสำรวจชุดข้อมูล

บทช่วยสอนนี้ใช้ชุดข้อมูลภาพถ่ายดอกไม้ประมาณ 3,700 ภาพ ชุดข้อมูลประกอบด้วยไดเร็กทอรีย่อย 5 ไดเร็กทอรี หนึ่งไดเร็กทอรีต่อคลาส:

flower_photo/
  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('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)

หลังจากดาวน์โหลด คุณควรมีสำเนาของชุดข้อมูลที่พร้อมใช้งาน มีทั้งหมด 3,670 ภาพ:

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

นี่คือดอกกุหลาบบางส่วน:

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

png

PIL.Image.open(str(roses[1]))

png

และดอกทิวลิปบางส่วน:

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

png

PIL.Image.open(str(tulips[1]))

png

โหลดโดยใช้ keras.preprocessing

มาโหลดอิมเมจเหล่านี้ออกจากดิสก์โดยใช้ยูทิลิตี้ image_dataset_from_directory ที่ เป็นประโยชน์ สิ่งนี้จะนำคุณจากไดเร็กทอรีของรูปภาพบนดิสก์ไปยังtf.data.Dataset ในtf.data.Dataset เพียงไม่กี่บรรทัด หากต้องการ คุณยังสามารถเขียนโค้ดการโหลดข้อมูลของคุณเองตั้งแต่ต้นโดยไปที่บทแนะนำการ โหลดรูปภาพ

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

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

batch_size = 32
img_height = 180
img_width = 180

แนวทางปฏิบัติที่ดีในการใช้การแยกการตรวจสอบความถูกต้องเมื่อพัฒนาแบบจำลองของคุณ ลองใช้รูปภาพ 80% สำหรับการฝึกอบรมและ 20% สำหรับการตรวจสอบ

train_ds = tf.keras.preprocessing.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.preprocessing.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.

คุณสามารถค้นหาชื่อคลาสได้ในแอตทริบิวต์ class_names บนชุดข้อมูลเหล่านี้ ซึ่งสอดคล้องกับชื่อไดเร็กทอรีตามลำดับตัวอักษร

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

เห็นภาพข้อมูล

นี่คือภาพ 9 ภาพแรกจากชุดข้อมูลการฝึก

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

คุณจะฝึกโมเดลโดยใช้ชุดข้อมูลเหล่านี้โดยส่งต่อไปยัง model.fit ในอีกสักครู่ หากต้องการ คุณยังสามารถวนซ้ำชุดข้อมูลด้วยตนเองและเรียกค้นชุดรูปภาพ:

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

image_batch คือเทนเซอร์ของรูปร่าง (32, 180, 180, 3) นี่คือชุดรูปภาพขนาด 180x180x3 จำนวน 32 รูป (มิติสุดท้ายหมายถึงช่องสี RGB) label_batch คือเทนเซอร์ของรูปร่าง (32,) ซึ่งเป็นป้ายกำกับที่สอดคล้องกับรูปภาพ 32 รูป

คุณสามารถเรียก . .numpy() บน image_batch และ labels_batch เพื่อแปลงเป็น numpy.ndarray

กำหนดค่าชุดข้อมูลสำหรับประสิทธิภาพ

ตรวจสอบให้แน่ใจว่าได้ใช้การดึงข้อมูลล่วงหน้าแบบบัฟเฟอร์ เพื่อให้คุณสามารถส่งข้อมูลจากดิสก์โดยไม่ต้องให้ I/O ถูกบล็อก นี่เป็นสองวิธีสำคัญที่คุณควรใช้เมื่อโหลดข้อมูล

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

Dataset.prefetch() ทับซ้อนการประมวลผลข้อมูลล่วงหน้าและการดำเนินการโมเดลขณะฝึก

ผู้อ่านที่สนใจสามารถเรียนรู้เพิ่มเติมเกี่ยวกับทั้งสองวิธี รวมถึงวิธีแคชข้อมูลลงดิสก์ใน คู่มือประสิทธิภาพข้อมูล

AUTOTUNE = tf.data.AUTOTUNE

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

ทำให้ข้อมูลเป็นมาตรฐาน

ค่าช่อง RGB อยู่ในช่วง [0, 255] ไม่เหมาะสำหรับโครงข่ายประสาทเทียม โดยทั่วไป คุณควรพยายามทำให้ค่าอินพุตของคุณมีขนาดเล็ก ที่นี่ คุณจะกำหนดมาตรฐานให้อยู่ในช่วง [0, 1] โดยใช้เลเยอร์การปรับขนาด

normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)

มีสองวิธีในการใช้เลเยอร์นี้ คุณสามารถใช้กับชุดข้อมูลได้โดยเรียกแผนที่:

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 pixels values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image))
0.0 0.9997713

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

สร้างแบบจำลอง

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

num_classes = 5

model = Sequential([
  layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])

รวบรวมโมเดล

สำหรับบทช่วยสอนนี้ ให้เลือกตัว optimizers.Adam ตัว optimizers.Adam ประสิทธิภาพและการสูญเสียของ losses.SparseCategoricalCrossentropy loss หากต้องการดูการฝึกอบรมและความถูกต้องของการตรวจสอบสำหรับช่วงการฝึกแต่ละครั้ง ให้ส่งอาร์กิวเมนต์ metrics

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

สรุปโมเดล

ดูเลเยอร์ทั้งหมดของเครือข่ายโดยใช้วิธีการ summary ของโมเดล:

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
rescaling_1 (Rescaling)      (None, 180, 180, 3)       0         
_________________________________________________________________
conv2d (Conv2D)              (None, 180, 180, 16)      448       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 90, 90, 16)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 90, 90, 32)        4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 45, 45, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 45, 45, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 22, 22, 64)        0         
_________________________________________________________________
flatten (Flatten)            (None, 30976)             0         
_________________________________________________________________
dense (Dense)                (None, 128)               3965056   
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 645       
=================================================================
Total params: 3,989,285
Trainable params: 3,989,285
Non-trainable params: 0
_________________________________________________________________

ฝึกโมเดล

epochs=10
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
Epoch 1/10
92/92 [==============================] - 3s 16ms/step - loss: 1.4412 - accuracy: 0.3784 - val_loss: 1.1290 - val_accuracy: 0.5409
Epoch 2/10
92/92 [==============================] - 1s 10ms/step - loss: 1.0614 - accuracy: 0.5841 - val_loss: 1.0058 - val_accuracy: 0.6131
Epoch 3/10
92/92 [==============================] - 1s 10ms/step - loss: 0.8999 - accuracy: 0.6560 - val_loss: 0.9920 - val_accuracy: 0.6104
Epoch 4/10
92/92 [==============================] - 1s 10ms/step - loss: 0.7416 - accuracy: 0.7153 - val_loss: 0.9279 - val_accuracy: 0.6458
Epoch 5/10
92/92 [==============================] - 1s 10ms/step - loss: 0.5618 - accuracy: 0.7844 - val_loss: 1.0019 - val_accuracy: 0.6322
Epoch 6/10
92/92 [==============================] - 1s 10ms/step - loss: 0.3950 - accuracy: 0.8634 - val_loss: 1.0232 - val_accuracy: 0.6553
Epoch 7/10
92/92 [==============================] - 1s 10ms/step - loss: 0.2228 - accuracy: 0.9268 - val_loss: 1.2722 - val_accuracy: 0.6444
Epoch 8/10
92/92 [==============================] - 1s 10ms/step - loss: 0.1188 - accuracy: 0.9687 - val_loss: 1.4410 - val_accuracy: 0.6567
Epoch 9/10
92/92 [==============================] - 1s 10ms/step - loss: 0.0737 - accuracy: 0.9802 - val_loss: 1.6363 - val_accuracy: 0.6444
Epoch 10/10
92/92 [==============================] - 1s 10ms/step - loss: 0.0566 - accuracy: 0.9847 - val_loss: 1.9752 - val_accuracy: 0.6390

เห็นภาพผลการฝึก

สร้างแผนการสูญเสียและความแม่นยำในชุดการฝึกอบรมและการตรวจสอบ

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

png

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

เรามาดูกันว่ามีอะไรผิดพลาดและพยายามเพิ่มประสิทธิภาพโดยรวมของโมเดล

ฟิตเกินไป

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

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

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

การเสริมข้อมูล

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

คุณจะใช้การเพิ่มข้อมูลโดยใช้เลเยอร์จาก tf.keras.layers.experimental.preprocessing สิ่งเหล่านี้สามารถรวมอยู่ในโมเดลของคุณเหมือนกับเลเยอร์อื่นๆ และรันบน GPU

data_augmentation = keras.Sequential(
  [
    layers.experimental.preprocessing.RandomFlip("horizontal", 
                                                 input_shape=(img_height, 
                                                              img_width,
                                                              3)),
    layers.experimental.preprocessing.RandomRotation(0.1),
    layers.experimental.preprocessing.RandomZoom(0.1),
  ]
)

ลองนึกภาพว่าตัวอย่างบางส่วนเป็นอย่างไรโดยการใช้การเสริมข้อมูลกับภาพเดียวกันหลายๆ ครั้ง:

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

png

คุณจะใช้การเสริมข้อมูลเพื่อฝึกโมเดลในอีกสักครู่

ออกกลางคัน

อีกเทคนิคหนึ่งในการลดการ overfitting คือการแนะนำ Dropout ให้กับเครือข่าย ซึ่งเป็นรูปแบบของการ ทำให้เป็น มาตรฐาน

เมื่อคุณใช้ Dropout กับเลเยอร์ มันจะสุ่มเอาออก (โดยการตั้งค่าการเปิดใช้งานเป็นศูนย์) จำนวนหน่วยเอาท์พุตจากเลเยอร์ในระหว่างกระบวนการฝึกอบรม Dropout ใช้ตัวเลขที่เป็นเศษส่วนเป็นค่าอินพุต ในรูปแบบเช่น 0.1, 0.2, 0.4 เป็นต้น ซึ่งหมายถึงการปล่อยหน่วยเอาต์พุต 10%, 20% หรือ 40% แบบสุ่มจากเลเยอร์ที่ใช้

มาสร้างโครงข่ายประสาทเทียมใหม่โดยใช้ layers.Dropout แล้วฝึกมันโดยใช้รูปภาพเสริม

model = Sequential([
  data_augmentation,
  layers.experimental.preprocessing.Rescaling(1./255),
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Dropout(0.2),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])

รวบรวมและฝึกโมเดล

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
sequential_1 (Sequential)    (None, 180, 180, 3)       0         
_________________________________________________________________
rescaling_2 (Rescaling)      (None, 180, 180, 3)       0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 180, 180, 16)      448       
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 90, 90, 16)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 90, 90, 32)        4640      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 45, 45, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 45, 45, 64)        18496     
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 22, 22, 64)        0         
_________________________________________________________________
dropout (Dropout)            (None, 22, 22, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 30976)             0         
_________________________________________________________________
dense_2 (Dense)              (None, 128)               3965056   
_________________________________________________________________
dense_3 (Dense)              (None, 5)                 645       
=================================================================
Total params: 3,989,285
Trainable params: 3,989,285
Non-trainable params: 0
_________________________________________________________________
epochs = 15
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
Epoch 1/15
92/92 [==============================] - 2s 13ms/step - loss: 1.2685 - accuracy: 0.4465 - val_loss: 1.0464 - val_accuracy: 0.5899
Epoch 2/15
92/92 [==============================] - 1s 11ms/step - loss: 1.0195 - accuracy: 0.5964 - val_loss: 0.9466 - val_accuracy: 0.6008
Epoch 3/15
92/92 [==============================] - 1s 11ms/step - loss: 0.9184 - accuracy: 0.6356 - val_loss: 0.8412 - val_accuracy: 0.6689
Epoch 4/15
92/92 [==============================] - 1s 11ms/step - loss: 0.8497 - accuracy: 0.6768 - val_loss: 0.9339 - val_accuracy: 0.6444
Epoch 5/15
92/92 [==============================] - 1s 11ms/step - loss: 0.8180 - accuracy: 0.6781 - val_loss: 0.8309 - val_accuracy: 0.6689
Epoch 6/15
92/92 [==============================] - 1s 11ms/step - loss: 0.7424 - accuracy: 0.7105 - val_loss: 0.7765 - val_accuracy: 0.6962
Epoch 7/15
92/92 [==============================] - 1s 11ms/step - loss: 0.7157 - accuracy: 0.7251 - val_loss: 0.7451 - val_accuracy: 0.7016
Epoch 8/15
92/92 [==============================] - 1s 11ms/step - loss: 0.6764 - accuracy: 0.7476 - val_loss: 0.9703 - val_accuracy: 0.6485
Epoch 9/15
92/92 [==============================] - 1s 11ms/step - loss: 0.6667 - accuracy: 0.7439 - val_loss: 0.7249 - val_accuracy: 0.6962
Epoch 10/15
92/92 [==============================] - 1s 11ms/step - loss: 0.6282 - accuracy: 0.7619 - val_loss: 0.7187 - val_accuracy: 0.7071
Epoch 11/15
92/92 [==============================] - 1s 11ms/step - loss: 0.5816 - accuracy: 0.7793 - val_loss: 0.7107 - val_accuracy: 0.7275
Epoch 12/15
92/92 [==============================] - 1s 11ms/step - loss: 0.5570 - accuracy: 0.7813 - val_loss: 0.6945 - val_accuracy: 0.7493
Epoch 13/15
92/92 [==============================] - 1s 11ms/step - loss: 0.5396 - accuracy: 0.7939 - val_loss: 0.6713 - val_accuracy: 0.7302
Epoch 14/15
92/92 [==============================] - 1s 11ms/step - loss: 0.5194 - accuracy: 0.7936 - val_loss: 0.6771 - val_accuracy: 0.7371
Epoch 15/15
92/92 [==============================] - 1s 11ms/step - loss: 0.4930 - accuracy: 0.8096 - val_loss: 0.6705 - val_accuracy: 0.7384

เห็นภาพผลการฝึก

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

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()

png

คาดการณ์ข้อมูลใหม่

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

sunflower_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg"
sunflower_path = tf.keras.utils.get_file('Red_sunflower', origin=sunflower_url)

img = keras.preprocessing.image.load_img(
    sunflower_path, target_size=(img_height, img_width)
)
img_array = keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch

predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])

print(
    "This image most likely belongs to {} with a {:.2f} percent confidence."
    .format(class_names[np.argmax(score)], 100 * np.max(score))
)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg
122880/117948 [===============================] - 0s 0us/step
This image most likely belongs to sunflowers with a 99.36 percent confidence.