การจำแนกเรือ (Ship) โดยใช้ Transfer Learning บน Tensorflow + Keras



สรุปขั้นตอน

  1. Prepare train data
    1. Read train csv
    2. [x] Load image 
    3. [x] Convert image to array
    4. [x] Put image array in list
    5. [x] Convert list to numpy array
    6. [y] Transform label in form of 0 to n-1
    7. [y] Convert list to one-hot array
  2. Pre-process image
    1. Split train and validation data
    2. Data augmentation
  3. Build a model
    1. Create model and summary
    2. Complile model
  4. Train data with model
  5. Show train result
    1. Save model
    2. Save history
    3. Show time used
    4. Plot train accuracy and loss
  6. Prepare test data
    1. Read test csv
    2. [x] Load image
    3. [x] Convert image to array. 
    4. [x] Put image array in list
    5. [x] Convert list to numpy array
    6. [x] Normalized array
    7. [y] Transform label to list 0 to n-1
    8. [y] Convert list to numpy array
    9. [y] Convert list to one-hot array
  7. Predict test data
  8. Show test result
    1. Evaluate model 
    2. Convert one-hot to list
    3. Save prediction
    4. Plot confusion matrix
    5. Print and save classification report 

1. Prepare train data

1.1 Read train csv

import pandas as pd
rcsv = pd.read_csv('train.csv', dtype={'image': 'object', 'category': 'int8'})
rcsv.head()

การเรียก column เป็น list

a = trainCsv.iloc[:, :-1].values
b = trainCsv.iloc[:, 1].values
c = trainCsv.image
d = trainCsv.category
e = trainCsv['image'].values
f = trainCsv['category'].values





1.2 [x] Load image 

from keras.preprocessing.image import load_img
imgPath = 'train/2556711.jpg'
imgDim = (150, 150)
img1 = load_img(imgPath, target_size=imgDim)


1.3 [x] Convert image to array

from keras.preprocessing.image import img_to_array, array_to_img
imgToArr1 = img_to_array(img1)
arrToImg1 = array_to_img(imgToArr1)



1.4 [x] Put image array in list

imgDim = (224,224)
trainArrListX = []
for imgName in trainCsv.image:
    trainArrListX.append(img_to_array(load_img('train/'+imgName, target_size=imgDim)))

หรือเขียนแบบสั้นๆ ดังนี้

trainArrListX = [img_to_array(load_img('train/'+img_name, target_size=imgDim)) for imgName in trainCsv.image]


1.5 [x] Convert list to numpy array

import numpy as np
x_train = np.array(trainArrListX)


1.6 [y] Transform label in form of 0 to n-1

1.7 [y] Convert list to one-hot array

ตัวเลขใน label ต้องเริ่มจาก 0 จึงจะมาแปลงเป็น to_categorical ได้ จึงต้องลบ 1 เพราะ label เดิมคือ 1, 2, 3, 4, 5

trainY = trainCsv['category'].values
trainY = trainY - 1

from keras.utils import to_categorical
y_train_onehot = to_categorical(trainY)



2. Pre-process image

2.1 Split train and validation data

from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train_onehot, test_size=0.2, random_state=42)



2.2 Data augmentation

การกำหนดค่า augmentation และ rescale ด้วย ImageDataGenerator

from keras.preprocessing.image import ImageDataGenerator

batch_size = 32

#Create the augmentation configuration
train_datagen = ImageDataGenerator(rescale=1./255,  
                                    rotation_range=30,
                                    width_shift_range=0.2,
                                    height_shift_range=0.2,
                                    shear_range=0.2,
                                    zoom_range=0.2,
                                    brightness_range=[0.5,1],
                                    horizontal_flip=True,)
val_datagen = ImageDataGenerator(rescale=1./255)

#Create the image generators
train_generator = train_datagen.flow(x_train, y_train, batch_size=batch_size)
val_generator = val_datagen.flow(x_val, y_val, batch_size=batch_size)


หรือใส่ชนิดค่าและการ rescale เอง (manually)

x_train = x_train.astype('float32')
x_train /= 255

ดูตัวอย่างรูปที่ทำ augmentation

import matplotlib.pyplot as plt
%matplotlib inline 
plt.figure(figsize=(24,10))
x,y = train_generator.next()
for i in range(1,11):
    image = x[i]
    plt.subplot(2,5,i)
    plt.imshow(image)


3. Build a Model

3.1 Create model and summary

from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras.applications import MobileNet

IMG_SHAPE = (200, 200, 3)

base_model = MobileNet(weights='imagenet', include_top=False, input_shape=IMG_SHAPE)
base_model.trainable = False

model = Sequential([
  base_model,
  GlobalAveragePooling2D(),
  Dense(1024,activation='relu'),
  Dense(512,activation='relu'),
  Dense(5, activation='softmax')
])
model.summary()


3.2 Complile model

model.compile(loss='categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])

4. Train data with model

batch_size = 32

import time
startTime = time.time()

history = model.fit_generator(train_generator,
                              steps_per_epoch=len(x_train) // batch_size,
                              epochs=10)
endTime = time.time()



5. Show train result

5.1 Save model

model.save_weights('my-model_save-wieghts.h5')
model.save('my-model_save.h5')

5.2 Save history

histDf = pd.DataFrame(history.history) 
histCsv = 'my-model_history.csv'
with open(histCsv, mode='w') as f:
    histDf.to_csv(f)

5.3 Show time used

print("Strat time = "+str(startTime))
print("End time = "+str(endTime))
print("Use time = "+str(endTime-startTime))


5.4 Plot train accuracy and loss

import matplotlib.pyplot as plt
%matplotlib inline 

acc = history.history['acc']
loss = history.history['loss']
epochs = range(1, len(acc) + 1)

#Train and validation accuracy
plt.style.use('default')
plt.grid(True)
plt.xticks(np.arange(0, len(acc)+1, 1.0))
#plt.yticks(np.arange(0, 1))
plt.plot(epochs, acc, 'b', label='Training Accurarcy')
plt.title('Training Accuracy (My Model)')
plt.legend()
plt.grid(True)
plt.figure()
plt.plot(epochs, loss, 'r', label='Training Loss')
plt.grid(True)
plt.xticks(np.arange(0, len(acc)+1, 1.0))
plt.title('Training Loss (My Model)')
plt.legend()
plt.show()


6. Prepare test data

6.1 Read test csv

6.2 [x] Load image 

6.3 [x] Convert image to array. 

6.4 [x] Put image array in list 

6.5 [x] Convert list to numpy array

6.6 [x] Normalized array

testCsv = pd.read_csv('test.csv', dtype={'image': 'object', 'category': 'int8'})
testArrListX = [img_to_array(load_img('test/'+imgName, target_size=imgDim)) for imgName in testCsv.image]
x_test = np.array(testArrListX)/255.0

6.7 [y] Convert list to numpy array

6.8 [y] Convert list to one-hot array

testY = testCsv['category'].values
testY = testY - 1
y_test = np.array(testY)
y_test_onehot = to_categorical(testY)

7. Predict test data

y_pred_onehot = model.predict(x_test)


8. Show test result

8.1 Evaluate model

y_pred_onehot = model.predict(x_test)

- 16s 33ms/sample - loss: 0.2866 - accuracy: 0.9020 0.3295358799695969 0.902

8.2 Convert one-hot to list

y_pred = []
for i in range(len(y_pred_onehot)):
    y_pred.append(np.argmax(y_pred_onehot[i]))

หรือ
y_pred = [np.argmax(y_pred_onehot[i]) for i in range(len(y_pred_onehot))]

8.3 Save prediction

testDict = {'image': testCsv.image, 'y_true': testCsv.category-1, 'y_pred': y_pred}
dfPred = pd.DataFrame(testDict)
exportPred = dfPred.to_csv(r'prediction.csv', index = None, header=True)

8.4 Plot confusion matrix

from sklearn.metrics import confusion_matrix
cfArr = confusion_matrix(y_test, y_pred)

import seaborn as sn
dfCm = pd.DataFrame(cfArr, index = ['Cargo', 'Military', 'Carrier', 'Cruise', 'Tankers'], columns = ['Cargo', 'Military', 'Carrier', 'Cruise', 'Tankers'])
plt.figure()
sn.heatmap(dfCm, annot=True, cmap="Blues")
plt.title('Confusion Matrix (My Model)',fontsize = 15)
plt.show()



8.5 Print and save classification report

from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))

report = classification_report(y_test, y_pred, output_dict=True)
dfRp = pd.DataFrame(report).transpose()
exportRp = dfRp.to_csv(r'classification-report.csv', index = None, header=True)



โค้ดเต็ม

# ---------- 1. Prepare train data ---------- 
import numpy as np
rcsv = pd.read_csv('train.csv', dtype={'image': 'object', 'category': 'int8'})
trainArrListX = [img_to_array(load_img('train/'+img_name, target_size=(200,200))) for imgName in trainCsv.image]
x_train = np.array(trainArrListX)

from keras.utils import to_categorical
trainY = trainCsv['category'].values
trainY = trainY - 1
y_train_onehot = to_categorical(trainY)

# ---------- 2. Pre-process image ---------- 
from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train_onehot, test_size=0.2, random_state=42)

from keras.preprocessing.image import ImageDataGenerator
batch_size = 32
train_datagen = ImageDataGenerator(rescale=1./255,  
                                    rotation_range=30,
                                    width_shift_range=0.2,
                                    height_shift_range=0.2,
                                    shear_range=0.2,
                                    zoom_range=0.2,
                                    brightness_range=[0.5,1],
                                    horizontal_flip=True,)
val_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow(x_train, y_train, batch_size=batch_size)
val_generator = val_datagen.flow(x_val, y_val, batch_size=batch_size)

# ---------- 3. Build a model ---------- 
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras.applications import MobileNet

IMG_SHAPE = (200, 200, 3)
base_model = MobileNet(weights='imagenet', include_top=False, input_shape=IMG_SHAPE)
base_model.trainable = False
model = Sequential([
  base_model,
  GlobalAveragePooling2D(),
  Dense(1024,activation='relu'),
  Dense(512,activation='relu'),
  Dense(5, activation='softmax')
])
model.summary()
model.compile(loss='categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])

# ---------- 4. Train data with model ---------- 
import time
batch_size = 32
startTime = time.time()
history = model.fit_generator(train_generator,
                              steps_per_epoch=len(x_train) // batch_size,
                              epochs=10)
endTime = time.time()


# ---------- 5. Show train result ---------- 
# ---- Save model & history, Show time used ----
model.save_weights('my-model_save-wieghts.h5')
model.save('my-model_save.h5')

import pandas as pd
histDf = pd.DataFrame(history.history) 
histCsv = 'my-model_history.csv'
with open(histCsv, mode='w') as f:
    histDf.to_csv(f)

print("Strat time = "+str(startTime))
print("End time = "+str(endTime))
print("Use time = "+str(endTime-startTime))

# ---- Plot train accuracy and loss ----
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline 

acc = history.history['accuracy']
loss = history.history['loss']
epochs = range(1, len(acc) + 1)

#Train and validation accuracy
plt.style.use('default')
plt.grid(True)
plt.xticks(np.arange(0, len(acc)+1, 1.0))
plt.plot(epochs, acc, 'b', label='Training Accurarcy')
plt.title('Training Accuracy (My Model)')
plt.xlabel("Epoch #")
plt.ylabel("Accuracy")
plt.legend()
plt.grid(True)
plt.figure()
plt.plot(epochs, loss, 'r', label='Training Loss')
plt.grid(True)
plt.xticks(np.arange(0, len(acc)+1, 1.0))
plt.title('Training Loss (My Model)')
plt.xlabel("Epoch #")
plt.ylabel("Loss")
plt.legend()
plt.show()

# ---------- 6. Prepare test data ----------
import pandas as pd
testCsv = pd.read_csv('test.csv', dtype={'image': 'object', 'category': 'int8'})
testArrListX = [img_to_array(load_img('test/'+imgName, target_size=imgDim)) for imgName in testCsv.image]
x_test = np.array(testArrListX)/255.0

testY = testCsv['category'].values
testY = testY - 1
y_test = np.array(testY)
y_test_onehot = to_categorical(testY)

# ---------- 7. Predict test data ----------
y_pred_onehot = model.predict(x_test)

# ---------- 8. Show test result ----------
# ---- Evaluate model ----
model.evaluate(x_test, y_test_onehot)

# ---- Convert one-hot to list ----
y_pred = [np.argmax(y_pred_onehot[i]) for i in range(len(y_pred_onehot))]

# ---- Save prediction ----
testDict = {'image': testCsv.image, 'y_label': testY, 'y_true': testY_le, 'y_pred': y_pred}
dfPred = pd.DataFrame(testDict)
exportPred = dfPred.to_csv(r'prediction.csv', index = None, header=True)

# ---- Plot confusion matrix ----
from sklearn.metrics import confusion_matrix
cfArr = confusion_matrix(y_test, y_pred)

import seaborn as sn
dfCm = pd.DataFrame(cfArr, index = ['Cargo', 'Military', 'Carrier', 'Cruise', 'Tankers'], columns = ['Cargo', 'Military', 'Carrier', 'Cruise', 'Tankers'])
plt.figure()
sn.heatmap(dfCm, annot=True, cmap="Blues")
plt.title('Confusion Matrix (My Model)',fontsize = 15)
plt.show()

# ---- Print and save classification report ----
from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))

report = classification_report(y_test, y_pred, output_dict=True)
dfRp = pd.DataFrame(report).transpose()
exportRp = dfRp.to_csv(r'classification-report.csv', index = None, header=True)


โค้ดย่อ

import numpy as np
import pandas as pd
import time
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split
from keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras.applications import MobileNet
from sklearn.metrics import classification_report


rcsv = pd.read_csv('train.csv', dtype={'image': 'object', 'category': 'int8'})
trainArrListX = [img_to_array(load_img('train/'+img_name, target_size=(200,200))) for imgName in trainCsv.image]
x_train = np.array(trainArrListX)
trainY = trainCsv['category'].values
trainY = trainY - 1
y_train_onehot = to_categorical(trainY)

x_train, x_val, y_train, y_val = train_test_split(x_train, y_train_onehot, test_size=0.2, random_state=42)


batch_size = 32
train_datagen = ImageDataGenerator(rescale=1./255,  
                                    rotation_range=30,
                                    width_shift_range=0.2,
                                    height_shift_range=0.2,
                                    shear_range=0.2,
                                    zoom_range=0.2,
                                    brightness_range=[0.5,1],
                                    horizontal_flip=True,)
val_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow(x_train, y_train, batch_size=batch_size)
val_generator = val_datagen.flow(x_val, y_val, batch_size=batch_size)


base_model = MobileNet(weights='imagenet', include_top=False, input_shape=(200,200,3))
base_model.trainable = False
model = Sequential([
  base_model,
  GlobalAveragePooling2D(),
  Dense(1024,activation='relu'),
  Dense(512,activation='relu'),
  Dense(5, activation='softmax')
])
model.summary()
model.compile(loss='categorical_crossentropy',optimizer='Adam',metrics=['accuracy'])


history = model.fit_generator(train_generator,
                              steps_per_epoch=len(x_train) // batch_size,
                              epochs=10)

testCsv = pd.read_csv('test.csv', dtype={'image': 'object', 'category': 'int8'})
testArrListX = [img_to_array(load_img('test/'+imgName, target_size=(200,200))) for imgName in testCsv.image]
x_test = np.array(testArrListX)/255.0
testY = testCsv['category'].values
testY = testY - 1
y_test = np.array(testY)
y_test_onehot = to_categorical(testY)

model.evaluate(x_test, y_test_onehot)
y_pred_onehot = model.predict(x_test)

y_pred = [np.argmax(y_pred_onehot[i]) for i in range(len(y_pred_onehot))]
confusion_matrix(y_test, y_pred)
print(classification_report(y_test, y_pred))


Previous
Next Post »