Convolutional Neural Network (CNN)

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHub הורד מחברת

מדריך זה מדגים אימון של רשת עצבית קונבולוציונית פשוטה (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
170508288/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 מקבל טנסורים של צורה (גובה_תמונה, רוחב_תמונה, ערוצי_צבע), תוך התעלמות מגודל האצווה. אם אתה חדש בממדים האלה, 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 (MaxPooling  (None, 6, 6, 64)         0         
 2D)                                                             
                                                                 
 conv2d_2 (Conv2D)           (None, 4, 4, 64)          36928     
                                                                 
=================================================================
Total params: 56,320
Trainable params: 56,320
Non-trainable params: 0
_________________________________________________________________

למעלה, אתה יכול לראות שהפלט של כל שכבת Conv2D ו-MaxPooling2D הוא טנזור תלת מימדי של צורה (גובה, רוחב, ערוצים). מידות הרוחב והגובה נוטות להתכווץ ככל שמתעמקים ברשת. מספר ערוצי הפלט עבור כל שכבת Conv2D נשלט על ידי הארגומנט הראשון (למשל, 32 או 64). בדרך כלל, ככל שהרוחב והגובה מתכווצים, אתה יכול להרשות לעצמך (מבחינה חישובית) להוסיף עוד ערוצי פלט בכל שכבת Conv2D.

הוסף שכבות צפופות מעל

כדי להשלים את המודל, תזין את טנזור הפלט האחרון מבסיס הפיתול (של הצורה (4, 4, 64)) לשכבה אחת או יותר צפופה כדי לבצע סיווג. שכבות צפופות לוקחות וקטורים כקלט (שהם 1D), בעוד שהפלט הנוכחי הוא טנזור תלת מימדי. ראשית, תשטח (או תפתח) את פלט התלת-ממד ל-1D, ולאחר מכן תוסיף שכבה אחת או יותר צפופה למעלה. ל-CIFAR יש 10 מחלקות פלט, אז אתה משתמש בשכבת צפופה סופית עם 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 (MaxPooling  (None, 6, 6, 64)         0         
 2D)                                                             
                                                                 
 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 [==============================] - 8s 4ms/step - loss: 1.4971 - accuracy: 0.4553 - val_loss: 1.2659 - val_accuracy: 0.5492
Epoch 2/10
1563/1563 [==============================] - 6s 4ms/step - loss: 1.1424 - accuracy: 0.5966 - val_loss: 1.1025 - val_accuracy: 0.6098
Epoch 3/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.9885 - accuracy: 0.6539 - val_loss: 0.9557 - val_accuracy: 0.6629
Epoch 4/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.8932 - accuracy: 0.6878 - val_loss: 0.8924 - val_accuracy: 0.6935
Epoch 5/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.8222 - accuracy: 0.7130 - val_loss: 0.8679 - val_accuracy: 0.7025
Epoch 6/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.7663 - accuracy: 0.7323 - val_loss: 0.9336 - val_accuracy: 0.6819
Epoch 7/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.7224 - accuracy: 0.7466 - val_loss: 0.8546 - val_accuracy: 0.7086
Epoch 8/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.6726 - accuracy: 0.7611 - val_loss: 0.8777 - val_accuracy: 0.7068
Epoch 9/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.6372 - accuracy: 0.7760 - val_loss: 0.8410 - val_accuracy: 0.7179
Epoch 10/10
1563/1563 [==============================] - 6s 4ms/step - loss: 0.6024 - accuracy: 0.7875 - val_loss: 0.8475 - val_accuracy: 0.7192

העריכו את המודל

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 - 1s - loss: 0.8475 - accuracy: 0.7192 - 634ms/epoch - 2ms/step

png

print(test_acc)
0.7192000150680542

CNN הפשוט שלך השיג דיוק בדיקה של למעלה מ-70%. לא רע עבור כמה שורות קוד! לסגנון אחר של CNN, בדוק את הדוגמה המהירה של TensorFlow 2 למומחים המשתמשת ב-Keras subclass API ו- tf.GradientTape .