การจำแนกภาพ CIFAR-10 ใน TensorFlow
Tags: tensorflow, learning, python
Published: 2024-04-20 09:17:07

ในบทความนี้เราจะพูดถึงวิธีการจำแนกภาพโดยใช้ TensorFlow ในการจำแนก โดยเราจะทำการจำแนกภาพตามหมวดหมู่ของคลาสที่เกี่ยวข้องกับ CIFAR-10 Dataset โดยจะมีภาพที่แตกต่างกัน 10 กลุ่ม มีรวมกันทั้งหมด 60,000 ภาพ โดยใน 10 กลุ่มแบ่งออกเป็น Airplane, Automobile, Bird, Cat, Deer, Dog, Frog, Horse, Ship, Truck และทุกภาพมีขนาด 32×32 รวมทั้งมีทั้งหมด 50,000 ภาพสำหรับใช้ในการฝึกและอีก 10,000 ภาพที่ใช้สำหรับการทดสอบ
โดยเราจะใช้ tensorflow's keras API เพื่อสร้างโมเดล และแนะนำว่าให้ใช้ GPU หรือ Google colab notebooks ช่วยในการทำงาน

## ขั้นตอนทำ
เริ่มจากการนำไลบรารีและโมดูลที่จำเข้าไปใน Google Colab 

```
import tensorflow as tf 
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.layers import Input, Conv2D, Dense, Flatten, Dropout
from tensorflow.keras.layers import GlobalMaxPooling2D, MaxPooling2D
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.models import Model
```
หลังจากเรานำไลบรารีและโมดูลที่จำเข้าไปใน Google Colab แล้วเราจะมาทำการโหลดข้อมูล CIFAR-10 ที่มีอยู่ใน tensorflow keras API โดยใช้ tensorflow.keras.datasets.cifar10 แล้วจะแบ่งเป็นชุดฝึกและชุดทดสอบโดยใช้ฟังก์ชัน load_data()

```
cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print(x_train.shape, y_train.shape, x_test.shape, y_test.shape)
```
ได้ออกมาเป็นแบบนี้
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilx4so48iceetvxps93s.png)
โดยเราจะเห็นได้ว่ามีภาพที่ใช้ฝึก 50,000 และภาพทดสอบ 10,000 ภาพตามที่ระบุไว้ในตอนแรก โดยทุกภาพจะมีขนาด 32x32 และมีช่องสี 3 นั่นคือเป็นภาพสี นอกจากนี้ยังเห็นได้ว่ามีการกำหนดป้ายชื่อเพียงหนึ่งป้ายชื่อต่อภาพเท่านั้น

ในตอนนี้เรามีข้อมูลที่ใช้ในการจำแนกภาพแล้ว แต่ยังต้องทำการประมวลผลข้อมูลก่อนโดยเราจะทำการลดค่าพิกเซลจากช่วง 1-256 ให้อยู่ในค่าระหว่าง 0 และ 1 เพื่อให้การฝึกมีประสิทธิภาพ และเราจะทำการยุบ (flatten) ค่าป้ายของภาพโดยใช้ฟังก์ชัน flatten() ให้เป็นแถวด้วย

```
x_train, x_test = x_train / 255.0, x_test / 255.0

y_train, y_test = y_train.flatten(), y_test.flatten()
```
ตอนนี้เราจะมาดูผลลัพธ์กันว่าภาพเป็นอย่างไรบ้างโดยใช้ฟังก์ชัน subplot() จาก matplotlib และวนลูปผ่านภาพ 25 ภาพแรกจากชุดข้อมูลการฝึกของเรา

```
fig, ax = plt.subplots(5, 5)
k = 0

for i in range(5):
	for j in range(5):
		ax[i][j].imshow(x_train[k], aspect='auto')
		k += 1

plt.show()
```
ต่อจากนี้เราจะเริ่มทำการสร้างโมเดลกัน โดยเราจะใช้Convolution Neural Network หรือ CNN , convolution ที่เป็น Conv2d , pooling , normalization methods ในส่วนท้ายก็จะส่งผ่านไปยัง dense และ dense ซึ่งเป็นการเอาต์พุต เราใช้ activation function ชื่อ "relu" ในการเอาต์พุตและใช้ฟังก์ชัน "softmax"

นอกจากนี้เรายังควรระบุโครงสร้างของโมเดลที่เราจะสร้าง เช่น จำนวนชั้นของ convolution, ขนาดของ kernel, จำนวนชั้นที่ใช้ในการปรับปรุงความลึกของชั้น, และจำนวนหน่วยในชั้นที่เชื่อมต่อแบบ fully connected ตามลำดับ ดังนั้นเราสามารถเริ่มต้นการสร้างโมเดลด้วยโค้ดต่อไปนี้

```
K = len(set(y_train))

print("number of classes:", K)

i = Input(shape=x_train[0].shape)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(i)
x = BatchNormalization()(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = MaxPooling2D((2, 2))(x)

x = Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = Conv2D(64, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = MaxPooling2D((2, 2))(x)

x = Conv2D(128, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = Conv2D(128, (3, 3), activation='relu', padding='same')(x)
x = BatchNormalization()(x)
x = MaxPooling2D((2, 2))(x)

x = Flatten()(x)
x = Dropout(0.2)(x)

x = Dense(1024, activation='relu')(x)
x = Dropout(0.2)(x)

x = Dense(K, activation='softmax')(x)

model = Model(i, x)

model.summary()
```
ผลลัพธ์
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zaxmxvkx2qofq4zvpvd.png)
จากนั้นเราจะทำการคอมไพล์มัน โดยใช้ฟังก์ชัน model.compile() เพื่อคอมไพล์

```
model.compile(optimizer='adam',
			loss='sparse_categorical_crossentropy',
			metrics=['accuracy'])
```
เมื่อคอมไพล์เสร็จก็จะมาถึงการฝึกโมเดลของเรา โดยเราจะใช้ model.fit() ทั้งหมดเข้าไปในโมเดล โดยเราจะฝึกโมเดลจนกระทั่ง 10 epochs แต่จริงแล้วเราจะฝึกโมเดลกี่ epochs ก็ได้ตามที่ต้องการ

```
r = model.fit(
x_train, y_train, validation_data=(x_test, y_test), epochs=10)
```
เมื่อโมเดลเริ่มฝึกการฝึกจะมีลักษณะนี้
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7v9ick0o7r2nnexgnwrl.png)
หลังจากเราฝึกโมเดลของเราจนเสร็จแล้ว มันก็สามารถทำได้เลยแต่หากอยากได้ความแม่นยำมากขึ้นเราสามารถเพิ่มการเพิ่มข้อมูลในข้อมูลของเราแล้วฝึกโมเดลอีกครั้ง โดยการเรียกใช้ model.fit() อีกครั้งบนข้อมูลที่เพิ่มขึ้น การเพิ่มข้อมูลที่เพิ่มขึ้นจะทำให้การฝึกทำงานต่อไปจากที่จบลง โดยเราจะให้ข้อมูลของเราใน batch size ของ 32 และเราจะย้ายช่วงของความกว้างและความสูงไป 0.1 และพลิกภาพตามแนวนอน จากนั้นเรียก model.fit อีกครั้ง

```
batch_size = 32
data_generator = tf.keras.preprocessing.image.ImageDataGenerator(
width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True)

train_generator = data_generator.flow(x_train, y_train, batch_size)
steps_per_epoch = x_train.shape[0] // batch_size

r = model.fit(train_generator, validation_data=(x_test, y_test),
			steps_per_epoch=steps_per_epoch, epochs=10)
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wbcgql2k8qs3mb3r2xzd.png)
เราจะมาดูความแม่นยำกันด้วยโค้ดนี้

```
plt.plot(r.history['accuracy'], label='acc', color='red')
plt.plot(r.history['val_accuracy'], label='val_acc', color='green')
plt.legend()
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kq7soi3qw653quqjjzhc.png)
ต่อมาเราจะมาทำการจำแนกภาพโดยใช้ฟังก์ชัน model.predict() ก่อนที่จะส่งภาพไปยังโมเดลของเรา เราจำเป็นต้องลดค่าพิกเซลให้อยู่ในช่วงระหว่าง 0 และ 1 และเปลี่ยนรูปร่างให้เป็น (1,32,32,3) เพราะโมเดลของเราต้องการข้อมูลนำเข้าในรูปแบบนี้เท่านั้น แม้ว่าเราจะใช้ภาพจากชุดข้อมูลก็ตาม ภาพนั้นอยู่ในรูปแบบพิกเซลที่ลดลงแล้ว แต่เราต้อง reshape มันอีกครั้งเพื่อให้เป็น (1,32,32,3) โดยใช้ฟังก์ชัน reshape() เราสามารถเปรียบเทียบผลลัพธ์ที่ทำนายและผลลัพธ์ต้นฉบับได้ เนื่องจากเรากำลังใช้ข้อมูลจากชุดข้อมูลใหม่ ตามโค้ดด้านล่างนี้

```
labels = '''airplane automobile bird cat deerdog frog horseship truck'''.split()

image_number = 0

plt.imshow(x_test[image_number])

n = np.array(x_test[image_number])

p = n.reshape(1, 32, 32, 3)

predicted_label = labels[model.predict(p).argmax()]

original_label = labels[y_test[image_number]]

print("Original label is {} and predicted label is {}".format(
	original_label, predicted_label))
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxoe8qankxoula6xb1fm.png)
เราได้ผลลัพธ์การจำแนกภาพเป็นแมว และภาพจริงๆก็เป็นแมวถูกต้องตามที่เราจำแนกออกมา

แต่ก็จะมีภาพที่มีการจำแนกที่ผิดอยู่เช่นกันอย่างภาพที่ 5722 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgm635wbj86zvj8idmqd.png)
โดยในภาพนี้ภาพจริงจะเป็ยภาพของเครื่องบิน แต่ถูกจำแนกเป็นนกนั้นเอง

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

**References**
https://www.geeksforgeeks.org/cifar-10-image-classification-in-tensorflow/