โครงข่ายประสาทเทียม (CNN)

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

บทช่วยสอนนี้สาธิตการฝึกอบรม Convolutional Neural Network (CNN) อย่างง่ายเพื่อจำแนก รูปภาพ CIFAR เนื่องจากบทช่วยสอนนี้ใช้ Keras Sequential API การสร้างและฝึกโมเดลของคุณจึงใช้โค้ดเพียงไม่กี่บรรทัด

นำเข้า TensorFlow

import tensorflow as tf

from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt

ดาวน์โหลดและเตรียมชุดข้อมูล CIFAR10

ชุดข้อมูล CIFAR10 ประกอบด้วยภาพสี 60,000 ภาพใน 10 คลาส โดยแต่ละคลาสมี 6,000 ภาพ ชุดข้อมูลแบ่งออกเป็นภาพการฝึก 50,000 ภาพและภาพทดสอบ 10,000 ภาพ คลาสเป็นแบบแยกจากกันและไม่มีการทับซ้อนกันระหว่างพวกเขา

(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

# Normalize pixel values to be between 0 and 1
train_images, test_images = train_images / 255.0, test_images / 255.0
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 11s 0us/step

ตรวจสอบข้อมูล

เพื่อตรวจสอบว่าชุดข้อมูลดูถูกต้อง ให้พล็อต 25 ภาพแรกจากชุดการฝึกและแสดงชื่อคลาสด้านล่างแต่ละภาพ:

class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck']

plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i])
    # The CIFAR labels happen to be arrays, 
    # which is why you need the extra index
    plt.xlabel(class_names[train_labels[i][0]])
plt.show()

png

สร้างฐานบิด

โค้ด 6 บรรทัดด้านล่างกำหนดฐานที่ บิดเบี้ยว โดยใช้รูปแบบทั่วไป: สแต็กของ เลเยอร์ Conv2D และ MaxPooling2D

เมื่อป้อนข้อมูล CNN จะใช้เทนเซอร์ของรูปร่าง (image_height, image_width, color_channels) โดยไม่สนใจขนาดแบทช์ หากคุณยังใหม่กับมิติข้อมูลเหล่านี้ color_channels หมายถึง (R,G,B) ในตัวอย่างนี้ คุณจะกำหนดค่า CNN ของคุณเพื่อประมวลผลอินพุตของรูปร่าง (32, 32, 3) ซึ่งเป็นรูปแบบของภาพ CIFAR คุณสามารถทำได้โดยส่งอาร์กิวเมนต์ input_shape ไปยังเลเยอร์แรกของคุณ

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))

มาแสดงสถาปัตยกรรมของแบบจำลองของคุณกัน:

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 30, 30, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 13, 13, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 4, 4, 64)          36928     
=================================================================
Total params: 56,320
Trainable params: 56,320
Non-trainable params: 0
_________________________________________________________________

ด้านบน คุณจะเห็นว่าผลลัพธ์ของทุกเลเยอร์ Conv2D และ MaxPooling2D เป็นเทนเซอร์ของรูปร่าง 3 มิติ (ความสูง ความกว้าง ช่อง) ขนาดความกว้างและความสูงมักจะหดตัวเมื่อคุณเข้าไปลึกในเครือข่าย จำนวนช่องสัญญาณเอาต์พุตสำหรับแต่ละเลเยอร์ Conv2D ถูกควบคุมโดยอาร์กิวเมนต์แรก (เช่น 32 หรือ 64) โดยปกติ เมื่อความกว้างและความสูงลดลง คุณสามารถ (คำนวณ) เพื่อเพิ่มช่องสัญญาณออกในแต่ละเลเยอร์ Conv2D ได้

เพิ่มชั้นหนาแน่นด้านบน

ในการทำให้โมเดลสมบูรณ์ คุณจะต้องป้อนเทนเซอร์เอาต์พุตสุดท้ายจากฐานที่บิดเบี้ยว (ของรูปร่าง (4, 4, 64)) ลงในเลเยอร์หนาแน่นอย่างน้อยหนึ่งชั้นเพื่อทำการจำแนกประเภท เลเยอร์หนาแน่นใช้เวกเตอร์เป็นอินพุต (ซึ่งคือ 1D) ในขณะที่เอาต์พุตปัจจุบันเป็น 3D เทนเซอร์ ขั้นแรก คุณต้องทำให้แบน (หรือคลี่ออก) เอาต์พุต 3D เป็น 1D จากนั้นเพิ่มเลเยอร์หนาแน่นหนึ่งชั้นขึ้นไปที่ด้านบน CIFAR มี 10 คลาสเอาต์พุต ดังนั้นคุณใช้ Dense เลเยอร์สุดท้ายที่มี 10 เอาต์พุต

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))

นี่คือสถาปัตยกรรมที่สมบูรณ์ของแบบจำลองของคุณ:

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 30, 30, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 13, 13, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 4, 4, 64)          36928     
_________________________________________________________________
flatten (Flatten)            (None, 1024)              0         
_________________________________________________________________
dense (Dense)                (None, 64)                65600     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                650       
=================================================================
Total params: 122,570
Trainable params: 122,570
Non-trainable params: 0
_________________________________________________________________

สรุปเครือข่ายแสดงให้เห็นว่าเอาต์พุต (4, 4, 64) ถูกทำให้แบนเป็นเวกเตอร์ที่มีรูปร่าง (1024) ก่อนที่จะผ่านสองชั้นหนาแน่น

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

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

history = model.fit(train_images, train_labels, epochs=10, 
                    validation_data=(test_images, test_labels))
Epoch 1/10
1563/1563 [==============================] - 7s 3ms/step - loss: 1.5216 - accuracy: 0.4446 - val_loss: 1.2293 - val_accuracy: 0.5562
Epoch 2/10
1563/1563 [==============================] - 5s 3ms/step - loss: 1.1654 - accuracy: 0.5857 - val_loss: 1.0774 - val_accuracy: 0.6143
Epoch 3/10
1563/1563 [==============================] - 5s 3ms/step - loss: 1.0172 - accuracy: 0.6460 - val_loss: 1.0041 - val_accuracy: 0.6399
Epoch 4/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.9198 - accuracy: 0.6795 - val_loss: 0.9946 - val_accuracy: 0.6540
Epoch 5/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.8449 - accuracy: 0.7060 - val_loss: 0.9169 - val_accuracy: 0.6792
Epoch 6/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.7826 - accuracy: 0.7264 - val_loss: 0.8903 - val_accuracy: 0.6922
Epoch 7/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.7338 - accuracy: 0.7441 - val_loss: 0.9217 - val_accuracy: 0.6879
Epoch 8/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6917 - accuracy: 0.7566 - val_loss: 0.8799 - val_accuracy: 0.6990
Epoch 9/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6431 - accuracy: 0.7740 - val_loss: 0.9013 - val_accuracy: 0.6982
Epoch 10/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6074 - accuracy: 0.7882 - val_loss: 0.8949 - val_accuracy: 0.7075

ประเมินแบบจำลอง

plt.plot(history.history['accuracy'], label='accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.ylim([0.5, 1])
plt.legend(loc='lower right')

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)
313/313 - 0s - loss: 0.8949 - accuracy: 0.7075

png

print(test_acc)
0.7074999809265137

CNN แบบง่ายของคุณได้รับความแม่นยำในการทดสอบมากกว่า 70% ไม่เลวสำหรับโค้ดสองสามบรรทัด! สำหรับรูปแบบ CNN อื่น ให้ลองดู TensorFlow 2 quickstart สำหรับ ตัวอย่าง ผู้เชี่ยวชาญ ที่ใช้ Keras subclassing API และtf.GradientTape