NCHC國網機器學習工讀生 研究報告
壹. 訓練程序與結果 Training Results
(1) 使用自己筆電training
最基礎入門的是使用cifar-10提供的image classifier訓練並完成分10類的task,
使用cifar-10練習的code網路上很容易查詢,
但因為不是使用自己的資料集,本篇報告將著重在如何使用自己的資料集訓練出想要的影像分類模型
本次任務使用的資料集為:ImageNet提供的影像。
第一階段目標: 訓練一個分三類的影像模型
- 三類為: Husky, Hen, Penguin
- 電腦中資料的路徑為:
D:/NCHC/ImageNet/
下有三個資料夾
分別為:/Husky
,/Hen
,/Penguin
參照keras-聖經
書中教材:首先撰寫一個最簡單的CNN 影像分類模型
程式碼:
import numpy as np
import matplotlib.pyplot as plt
import os
import cv2
DataPATH = "D:/NCHC/ImageNet"
CATEGORIES = ["Husky","Hen", "Penguin"]
for category in CATEGORIES:
path = os.path.join(DataPATH, category)
for img in os.listdir(path):
img_array = cv2.imread(os.path.join(path,img), cv2.IMREAD_GRAYSCALE)
break
break
IMG_SIZE = 50
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
plt.imshow(new_array, cmap='gray')
plt.show()
training_data = []
def create_training_data():
for category in CATEGORIES:
path = os.path.join(DataPATH, category)
class_num = CATEGORIES.index(category)
for img in os.listdir(path):
try:
img_array = cv2.imread(os.path.join(path,img), cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (IMG_SIZE,IMG_SIZE))
training_data.append([new_array, class_num])
except Exception as e:
pass
create_training_data()
print(len(training_data))
import random
random.shuffle(training_data)
for sample in training_data[:10]:
print(sample[1])
X = []
y = []
for features,label in training_data:
X.append(features)
y.append(label)
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
import pickle
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import TensorBoard
from keras.utils import np_utils
import time
X = X/255.0
y = np_utils.to_categorical(y)
model = Sequential()
model.add(Conv2D(filters=32,kernel_size=(3,3),
input_shape= X.shape[1:],
activation='relu',
padding='same'))
model.add(Dropout(rate=0.25))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(filters=64, kernel_size=(3, 3),
activation='relu', padding='same'))
model.add(Dropout(0.25))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dropout(rate=0.25))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(rate=0.25))
model.add(Dense(3, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'],
)
model.fit(X, y,
batch_size=32,
epochs=10,
validation_split=0.3)
print(model.summary())
在沒有做影像擴增等調整前,可想而知會遇到過擬合的問題,如下:
Training Accuracy : 0.95
Validation Accuracy: 0.775

(2) 優化模型,提高驗證準確率
接著我們將原始資料的相片進行擴增等預處理,將訓練資料量變多,以降低過擬合的問題。
如此一來驗證正確率便提高到約有0.9 (90%)
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, MaxPool2D, Flatten, Activation
from tensorflow.keras import backend as K
from tensorflow.keras.preprocessing.image import ImageDataGenerator
img_width, img_height = 28,28
input_depth = 1
train_data_dir = 'D:/NCHC/ImageNet'
testing_data_dir = 'dataset/mnist/testing'
epochs = 2
batch_size = 5
train_datagen = ImageDataGenerator(rescale=1/255)
test_datagen = ImageDataGenerator(rescale=1/255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
color_mode='grayscale',
target_size=(img_width,img_height),
batch_size=batch_size,
class_mode='categorical')
testing_generator = test_datagen.flow_from_directory(
testing_data_dir,
color_mode='grayscale',
target_size=(img_width,img_height),
batch_size=batch_size,
class_mode='categorical')
DataPATH = "D:/NCHC/ImageNet"
CATEGORIES = ["Husky","Hen", "Penguin"]
for category in CATEGORIES:
path = os.path.join(DataPATH, category)
for img in os.listdir(path):
img_array = cv2.imread(os.path.join(path,img), cv2.IMREAD_GRAYSCALE)
break
break
IMG_SIZE = 50
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
plt.imshow(new_array, cmap='gray')
plt.show()
training_data = []
def create_training_data():
for category in CATEGORIES:
path = os.path.join(DataPATH, category)
class_num = CATEGORIES.index(category)
for img in os.listdir(path):
try:
img_array = cv2.imread(os.path.join(path,img), cv2.IMREAD_GRAYSCALE)
training_data.append([new_array, class_num])
except Exception as e:
pass
create_training_data()
print(len(training_data))
import random
random.shuffle(training_data)
for sample in training_data[:10]:
print(sample[1])
X = []
y = []
for features,label in training_data:
X.append(features)
y.append(label)
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
import pickle
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import TensorBoard
from keras.utils import np_utils
import time
NAME = "Cats-vs-dogs-64x2-CNN"
y = np_utils.to_categorical(y)
X = X/255.0
model = Sequential()
model.add(Conv2D(filters=32,kernel_size=(3,3),
input_shape= X.shape[1:],
activation='relu',
padding='same'))
model.add(Dropout(rate=0.25))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(filters=64, kernel_size=(3, 3),
activation='relu', padding='same'))
model.add(Dropout(0.25))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dropout(rate=0.25))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(rate=0.25))
model.add(Dense(3, activation='softmax'))
tensorboard = TensorBoard(log_dir="logs/{}".format(NAME))
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'],
)
model.fit(X, y,
batch_size=32,
epochs=10,
validation_split=0.3)
print(model.summary())
(3) 基於VGG16的影像分類模型

構想如上圖:拿人家練好的厲害的Model
將最後一個輸出層客製化成符合我們需求的模型
第一個方法個人電腦較負擔的起:特徵萃取法
想法:先把之前的features萃取出來
存入numpy 陣列,接著將input data經由這些feature後
最後輸入convolutional base
此方法速度快成本也低。
唯一缺點:不允許資料擴增法
我在電腦的D:/NCHC/ImageNet/test/test_imgs
放了七張沒有非訓練照片
一張一張餵給Model做分類
以下為分類結果:
- 輸出格式:
- 這張圖片實際檔名 (Your input images: )
- 模型分類後的結果 (Output prediction: )
可以看到:正確率是100% ! (7/7)
當然因為這個task(分七類)還是相對簡單
更複雜的task可能花更多心思來設計

在Jupyter Notebook 上測試的結果
Found 8711 images belonging to 7 classes.
Found 10 images belonging to 1 classes.
1/1 [==============================] - 1s 869ms/step
Classes order: {'Coffee': 0, 'Geysir': 1, 'Hen': 2, 'Husky': 3, 'Leopard': 4, 'Papaya': 5, 'Penguin': 6}
Your input images: test_imgs\coffee0.jpg
Output Prediction : Coffee
Your input images: test_imgs\coffee1.jpg
Output Prediction : Coffee
Your input images: test_imgs\geysir0.jpg
Output Prediction : Geysir
Your input images: test_imgs\hen0.jpg
Output Prediction : Hen
Your input images: test_imgs\husky0.jpg
Output Prediction : Husky
Your input images: test_imgs\husky1.jpg
Output Prediction : Husky
Your input images: test_imgs\leopard.jpg
Output Prediction : Leopard
Your input images: test_imgs\leopard1.jpg
Output Prediction : Leopard
Your input images: test_imgs\papaya0.jpg
Output Prediction : Papaya
Your input images: test_imgs\penguin0.jpg
Output Prediction : Penguin


import numpy as np
import matplotlib.pyplot as plt
import os # handle data path.
import cv2
import pickle
import tensorflow as tf
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
# more info on callbakcs: https:
from tensorflow.keras.callbacks import TensorBoard
from keras.utils import np_utils
import time
from keras.applications import VGG16
conv_base = VGG16( weights = 'imagenet',
include_top = False,
input_shape = (150,150, 3))
conv_base.summary()
# Method 1 : use conv_base & own Dense Layer (output layer)
base_dir = 'D:/NCHC/ImageNet'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')
datagen = ImageDataGenerator(rescale = 1./255)
batch_size = 1
def extract_features(directory, sample_count):
features = np.zeros(shape=(sample_count, 4, 4, 512))
labels = np.zeros(shape=(sample_count,7) )
print("labels shape",labels.shape)
generator = datagen.flow_from_directory( directory,
target_size=(150,150),
batch_size = batch_size,
class_mode = 'categorical')
i = 0
for inputs_batch, labels_batch in generator:
features_batch = conv_base.predict(inputs_batch)
# print("features batch shape",features_batch.shape)
# print("label batch ",labels_batch.shape)
features[i * batch_size :(i + 1) * batch_size] = features_batch
# print("features shape",features.shape)
labels[ i * batch_size : (i + 1) * batch_size] = labels_batch
i += 1
print(i, end = '')
if i * batch_size >= sample_count:
break
return features, labels
train_features, train_labels = extract_features(train_dir, 8711)
validation_features, validation_labels = extract_features(validation_dir, 128)
test_features, test_labels = extract_features(test_dir, 3)
train_features = np.reshape(train_features, (8711, 4 * 4 * 512))
validation_features = np.reshape(validation_features, (128, 4 * 4 * 512))
test_features = np.reshape(test_features, (3, 4 * 4 * 512))
##### Constructing our custom 'Dense Layer', and train! ####
from keras import models
from keras import layers
from keras import optimizers
model = models.Sequential()
model.add(layers.Dense(256, activation='relu', input_dim=4*4*512))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(7, activation='sigmoid'))
model.compile( optimizer = optimizers.RMSprop(lr = 2e-5),
loss = 'categorical_crossentropy',
metrics = ['acc'])
history = model.fit(train_features, train_labels,
epochs = 30,
batch_size = 20,
validation_data = (validation_features, validation_labels))
############# Plot accuracy & loss #############
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(acc) + 1)
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
model.save_weights("CNN04_params.h5")
from keras.models import load_model
model.save("CNN04_model.h5")
############# Load existed model and Predict (test) the accuracy of your model. #############
IMG_SIZE = 150
train_datagen = ImageDataGenerator(
rescale = 1./255,
rotation_range = 40,
width_shift_range = 0.2,
height_shift_range=0.2,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
test_datagen = ImageDataGenerator(rescale=1./255)
train_dir = "D:/NCHC/ImageNet/train"
validation_dir ="D:/NCHC/ImageNet/validation"
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size = (IMG_SIZE,IMG_SIZE),
batch_size = 32,
class_mode = 'categorical'
)
test_dir = 'D:/NCHC/ImageNet/test'
test_datagen = datagen
test_generator = test_datagen.flow_from_directory(
test_dir,
target_size=(IMG_SIZE, IMG_SIZE),
batch_size=10,
class_mode= 'categorical',
shuffle=False)
test_generator.reset()
custom_dense = load_model("CNN04_model.h5")
model_pred = Sequential()
model_pred.add(conv_base)
model_pred.add(layers.Flatten())
model_pred.add(custom_dense)
pred = model_pred.predict_generator(test_generator, verbose=1)
predicted_class_indices = np.argmax(pred, axis=1)
labels = (train_generator.class_indices)
label = dict((v,k) for k,v in labels.items())
# 建立代码标签与真实标签的关系
predictions = [label[i] for i in predicted_class_indices]
print("\n\nClasses order: ", train_generator.class_indices)
#建立预测结果和文件名之间的关系
filenames = test_generator.filenames
for idx in range(len(filenames )):
# print('\nOutput probability distributions: ', pred[idx])
print('\nYour input images: %s\n' % filenames[idx])
print('Output Prediction : %s' % (predictions[idx]))
# print('Actual : %s' % filenames[idx])
print('')
print('\n\n')
(4) 延續(3)但使用直接擴增模型方式訓練(需較多計算資源)
此為使用微調部分
引入整個VGG模型,加入最後一層Dense Layer
再整個拿去訓練。
此訓練結果請見下方:使用Azure訓練
貳. 使用Azure 幫助訓練你的神經網路
1. Steps
(1) Log in your Azure account:

登入後,點選左上角選擇欄位->訂用帳戶
發現它寫:您沒有任何訂用帳戶
因此要先取得訂用帳戶
本範例是採用 Azure 開放授權的方式,取得金鑰,進而取得計算點數

這邊依照各單位教學,如何取得授權,涉及機密,在此不說明
(2) 取得授權後
可看到右上角跳出通知:餘額點數尚有多少

接著可以回到首頁
(3) 新建機器學習服務
首頁:

點選 新建-> AI & 機器學習服務
會出現以下頁面:

點選標題下的 +新建

訂用帳戶:選擇你的帳戶
資源群組:若無,可新建一個(取名字)
工作區名稱:此機器學習workspace名字
其他欄位任意填寫即可
完成資料大概如下:

之後按下檢閱+建立:
檢驗成功後會出現以下畫面

按下建立:
成功後會將你導入你的工作區主頁面
以此範例,我的工作區取名為VM1

(4) 完成建立 Workspace,遵照導引教學
初次使用,azure會有完整的導覽,基本上按照他的導引,就能學會如何使用機器學習workspace~

2. How to import your machine learning code.
如果你已經有jupyter notebook,可以從
機器學習工作區/筆記本
這個分頁下,
點選第三個欄位 上傳
可以上傳檔案或資料夾,非常方便
你的Dataset也可以透過此方法上傳,缺點是資料很大的時候(上萬張照片)上傳時間就會比較久
上傳成功後,上方一樣會出線綠色通知條

3. How to execute your notebook
將機器學習程式碼與datasets都上傳到工作區後,我們要執行此程式碼,
你會發現它寫:
找不到任何計算
這表示:你要新增計算單元
點選最右邊的三個小點:點選新增計算

會出現新增計算執行個體

這個步驟攸關你之後run notebook時的執行速度快慢
若你需要處理較多圖形運算,選擇GPU當然比CPU快許多
不過要注意選擇GPU後,你的程式碼可能要稍做修改,否則會有資源不夠等問題(我就郁到了…,短時間內沒那麼容易修好)

新建完計算執行個體後,可以在計算
頁面發現你剛剛新增的計算單元:

回到筆記本
選擇在 Jupyter Lab中編輯:

進入 Jupyter Lab 後:可以點選上面的執行

開始執行後的畫面如下:

正在訓練的樣子:

本次訓練結果:
使用 VGG16-base 加上自己的output layer 疊成之神經網路:
validation accuracy : 97.5 %
(只訓練5 epochs)



重要!!如何停止工作區扣款
必須刪除計算執行個體才能停止計費
取得授權
Notebook說明