CV】keras_resnet 在cifar10数据集上分类
?
碼農有道 2020-06-01 14:29:17 ?510 ?收藏
展開
文章目錄
1.導入庫
2.數據準備
2.1 加載訓練集
2.2 加載測試集
2.3 對類別做One-Hot編碼
2.4 對圖片像素的0-255值做歸一化,并減去均值
3.搭建神經網絡
3.1 定義函數resnet_layer,返回值是經過resnet_layer計算的結果
3.2 定義函數resnet_v1,返回值是模型對象
3.3 定義函數resnet_v2,返回值是模型對象
3.4 實例化模型對象
3.5 多GPU并行訓練
3.6 打印模型架構信息
4. 模型訓練
4.1 規劃學習率(訓練到后期時學習率需減小)
4.2 模型訓練時的參數設置
4.3 使用圖像增強的結果做模型訓練
5.模型評估
5.1 加載訓練好的模型
5.2 計算訓練集的準確率
5.3 計算測試集的準確率
6. 模型測試結果可視化
6.1 隨機選100張圖可視化
6.2 隨機選取100張圖片的同時,要求10個類別,每個類別取10張
7.Keras中權重文件的讀寫
7.1 使用load_model方法加載模型文件
7.2 使用save_weights方法保存權重文件
7.3 使用load_weights方法加載權重文件
1.導入庫
1.keras(resnet):https://github.com/keras-team/keras/blob/master/examples/cifar10_resnet.py
2.用到的cifar10數據集和模型權重鏈接:https://pan.baidu.com/s/1L4oZAPg_9B_YipPeihmBwQ 提取碼:8jcw
5個data_batch文件,每個1萬數據
# 加入下面2行,可以使py代碼文件中的修改即時生效
%load_ext autoreload
%autoreload 2
# 下行如果python2使用print,也得加上括號
from __future__ import print_function
import keras
# 導入keras庫的這4種層:全連接層Dense,2維卷積層Conv2D,批量歸一化層BatchNormalization,激活層Activation
from keras.layers import Dense, Conv2D, BatchNormalization, Activation
# 導入keras庫的這3種層:平均2維池化層AveratePooling2D, 輸入層Input,激活層Activation
from keras.layers import AveragePooling2D, Input, Flatten
# 導入keras庫的優化器:Adam優化器
from keras.optimizers import Adam
# 導入keras庫的回傳函數:模型檢查點ModelCheckpoint, LearningRateScheduler
from keras.callbacks import ModelCheckpoint, LearningRateScheduler
# 導入keras庫的回傳函數:學習率遞減ReduceLROnPlateau
from keras.callbacks import ReduceLROnPlateau
# 導入keras庫的圖片處理函數:圖片數據生成器
from keras.preprocessing.image import ImageDataGenerator
# 導入keras庫的正則化函數:L2正則化
from keras.regularizers import l2
# 導入keras庫的后端:backend中文叫做后端,取別名為K
from keras import backend as K
# 導入keras庫的模型函數:Model
from keras.models import Model
# 導入keras庫的數據集類:cifar10
from keras.datasets import cifar10
# 導入必需的常用庫
import numpy as np
import os
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2.數據準備
2.1 加載訓練集
官方代碼沒有指定路徑:
from keras.datasets.cifar import load_batch #load_batch用于加載指定路徑
## 加載數據集cifar10里面的訓練集
def load_train_dataset(dirPath='../resources/cifar-10-batches-py/'):
? ? train_sample_quantity = 50000
? ? image_width = 32
? ? image_height = 32
? ? channel_quantity = 3
? ? train_X = np.zeros((train_sample_quantity, channel_quantity, image_width, image_height),
? ? ? ? ? ? ? ? ? ? ? ?dtype='uint8')
? ? train_y = np.zeros((train_sample_quantity, ),
? ? ? ? ? ? ? ? ? ? ? ?dtype='uint8') ?#下面循環寫入相同大小零矩陣
? ? for i in range(1, 6):
? ? ? ? fileName = 'data_batch_%d' %i ?#看文件名格式
? ? ? ? filePath = os.path.join(dirPath, fileName)
? ? ? ? startIndex = (i - 1) * 10000
? ? ? ? endIndex = i * 10000 ? ? ? ? ? ? #用到了load_batch,訓練集定義5萬,循環5次,0-1萬行,1萬-2萬行....
? ? ? ? train_X[startIndex:endIndex, :, :, :], train_y[startIndex:endIndex] = load_batch(filePath)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? print('train_X矩陣轉置前:', train_X.shape)
? ? # 從官網上下載的數據集的4個維度為樣本個數n、通道數c、寬度w、高度h
? ? # Keras基于Tensorflow,數據的維度順序要求:樣本個數n、寬度w、高度h、通道數c,所以使用np.transpose完成矩陣轉置
? ? train_X = train_X.transpose(0, 2, 3, 1)
? ? print('train_X矩陣轉置后:', train_X.shape)
? ? return train_X, train_y
dirPath = '../resources/cifar-10-batches-py/'
train_imageData, train_y = load_train_dataset()?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2.2 加載測試集
# 加載數據集cifar10里面的測試集
def load_test_dataset(dirPath='../resources/cifar-10-batches-py/'):
? ? fileName = 'test_batch'
? ? filePath = os.path.join(dirPath, fileName)
? ? test_X, test_y = load_batch(filePath)
? ? print('test_X矩陣轉置前:', test_X.shape)
? ? test_X = test_X.transpose(0, 2, 3, 1)
? ? print('test_X矩陣轉置后:', test_X.shape)
? ? return test_X, test_y
dirPath = '../resources/cifar-10-batches-py/'
test_imageData, test_y = load_test_dataset()
1
2
3
4
5
6
7
8
9
10
11
12
2.3 對類別做One-Hot編碼
# 對類別ID做One-Hot編碼
from keras.utils import to_categorical
class_quantity = 10
train_Y = to_categorical(train_y, class_quantity)
test_Y = to_categorical(test_y, class_quantity)
1
2
3
4
5
6
2.4 對圖片像素的0-255值做歸一化,并減去均值
train_X = train_imageData.astype('float32') / 255
test_X = test_imageData.astype('float32') / 255
pixel_mean = np.mean(train_X, axis=0)
print('pixel_mean.shape:', pixel_mean.shape)
train_X = train_X - pixel_mean
test_X = test_X - pixel_mean
1
2
3
4
5
6
3.搭建神經網絡
3.1 定義函數resnet_layer,返回值是經過resnet_layer計算的結果
def resnet_layer(inputs, ? #定義了一層resnet_layer
? ? ? ? ? ? ? ? ?num_filters=16,
? ? ? ? ? ? ? ? ?kernel_size=3,
? ? ? ? ? ? ? ? ?strides=1,
? ? ? ? ? ? ? ? ?activation='relu',
? ? ? ? ? ? ? ? ?batch_normalization=True,
? ? ? ? ? ? ? ? ?conv_first=True):
? ??
? ? conv = Conv2D(num_filters,
? ? ? ? ? ? ? ? ? kernel_size=kernel_size,
? ? ? ? ? ? ? ? ? strides=strides,
? ? ? ? ? ? ? ? ? padding='same',
? ? ? ? ? ? ? ? ? kernel_initializer='he_normal',
? ? ? ? ? ? ? ? ? kernel_regularizer=l2(1e-4))
? ? x = inputs
? ? if conv_first: #為resnet V1
? ? ? ? x = conv(x) #conv為一函數,相當于下圖weight
? ? ? ? if batch_normalization:
? ? ? ? ? ? x = BatchNormalization()(x)
? ? ? ? if activation is not None:
? ? ? ? ? ? x = Activation(activation)(x)
? ? else: ?#為resnet V2
? ? ? ? if batch_normalization:
? ? ? ? ? ? x = BatchNormalization()(x) #BatchNormalization()實例化一個函數對象
? ? ? ? if activation is not None:
? ? ? ? ? ? x = Activation(activation)(x)
? ? ? ? x = conv(x)
? ? return x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3.2 定義函數resnet_v1,返回值是模型對象
def resnet_v1(input_shape, depth, num_classes=10):
? ? if (depth - 2) % 6 != 0:
? ? ? ? raise ValueError('depth should be 6n+2 (eg 20, 32, 44 in [a])')
? ? # Start model definition.
? ? num_filters = 16
? ? num_res_blocks = int((depth - 2) / 6)
? ? inputs = Input(shape=input_shape)
? ? x = resnet_layer(inputs=inputs)
? ? # Instantiate the stack of residual units
? ? for stack in range(3):
? ? ? ? for res_block in range(num_res_blocks):
? ? ? ? ? ? strides = 1
? ? ? ? ? ? if stack > 0 and res_block == 0: ?# first layer but not first stack
? ? ? ? ? ? ? ? strides = 2 ?# downsample
? ? ? ? ? ? y = resnet_layer(inputs=x,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?strides=strides)
? ? ? ? ? ? y = resnet_layer(inputs=y,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?activation=None)
? ? ? ? ? ? if stack > 0 and res_block == 0: ?# first layer but not first stack
? ? ? ? ? ? ? ? # linear projection residual shortcut connection to match
? ? ? ? ? ? ? ? # changed dims
? ? ? ? ? ? ? ? x = resnet_layer(inputs=x,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?kernel_size=1,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?strides=strides,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?activation=None,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?batch_normalization=False)
? ? ? ? ? ? x = keras.layers.add([x, y])
? ? ? ? ? ? x = Activation('relu')(x)
? ? ? ? num_filters *= 2
? ? # Add classifier on top.
? ? # v1 does not use BN after last shortcut connection-ReLU
? ? x = AveragePooling2D(pool_size=8)(x)
? ? y = Flatten()(x)
? ? outputs = Dense(num_classes,
? ? ? ? ? ? ? ? ? ? activation='softmax',
? ? ? ? ? ? ? ? ? ? kernel_initializer='he_normal')(y)
? ? # Instantiate model.
? ? model = Model(inputs=inputs, outputs=outputs)
? ? return model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
3.3 定義函數resnet_v2,返回值是模型對象
def resnet_v2(input_shape, depth, num_classes=10):
? ? if (depth - 2) % 9 != 0:#深度必須是9n+2,比如20層,56層,110層
? ? ? ? raise ValueError('depth should be 9n+2 (eg 56 or 110 in [b])')
? ? # Start model definition.
? ? num_filters_in = 16 # 卷積核數量
? ? num_res_blocks = int((depth - 2) / 9)
? ? inputs = Input(shape=input_shape)
? ??
? ? x = resnet_layer(inputs=inputs, ?# resnet lay 0如下表,第一次調用了一層resnet_layer
? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters_in,
? ? ? ? ? ? ? ? ? ? ?conv_first=True)
? ? ? ? ? ? ? ? ? ? ?
? ? # Instantiate the stack of residual units 實例化剩余單元的堆棧
? ? for stage in range(3):
? ? ? ? for res_block in range(num_res_blocks):
? ? ? ? ? ? activation = 'relu'
? ? ? ? ? ? batch_normalization = True
? ? ? ? ? ? strides = 1
? ? ? ? ? ? if stage == 0:?
? ? ? ? ? ? #如果stage和res_block == 0,不進行activation,batch_normalization,
? ? ? ? ? ? ? ? num_filters_out = num_filters_in * 4
? ? ? ? ? ? ? ? if res_block == 0: ?# first layer and first stage
? ? ? ? ? ? ? ? ? ? activation = None
? ? ? ? ? ? ? ? ? ? batch_normalization = False
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? num_filters_out = num_filters_in * 2
? ? ? ? ? ? ? ? if res_block == 0: ?# first layer but not first stage
? ? ? ? ? ? ? ? ? ? strides = 2 ? ?# downsample
? ? ? ? ? ? # bottleneck residual unit
? ? ? ? ? ? y = resnet_layer(inputs=x,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters_in,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?kernel_size=1,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?strides=strides,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?activation=activation,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?batch_normalization=batch_normalization,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?conv_first=False)
? ? ? ? ? ? y = resnet_layer(inputs=y,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters_in,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?conv_first=False)
? ? ? ? ? ? y = resnet_layer(inputs=y,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters_out,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?kernel_size=1,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?conv_first=False)
? ? ? ? ? ? if res_block == 0:
? ? ? ? ? ? ? ? # linear projection residual shortcut connection to match
? ? ? ? ? ? ? ? # changed dims
? ? ? ? ? ? ? ? x = resnet_layer(inputs=x,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?num_filters=num_filters_out,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?kernel_size=1,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?strides=strides,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?activation=None,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?batch_normalization=False)
? ? ? ? ? ? x = keras.layers.add([x, y]) #實現shotcut
? ? ? ? num_filters_in = num_filters_out
? ? #如上三個resnet_layer調用一個shotcut
? ??
? ? # Add classifier on top.
? ? # v2 has BN-ReLU before Pooling
? ? x = BatchNormalization()(x) ?#如下三行代碼對應下表對應后面幾行
? ? x = Activation('relu')(x)
? ? x = AveragePooling2D(pool_size=8)(x)
? ? y = Flatten()(x)
? ? outputs = Dense(num_classes,
? ? ? ? ? ? ? ? ? ? activation='softmax',
? ? ? ? ? ? ? ? ? ? kernel_initializer='he_normal')(y)
? ? # Instantiate model.
? ? model = Model(inputs=inputs, outputs=outputs)
? ? return model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
3.4 實例化模型對象
# Model version
# Orig paper: version = 1 (ResNet v1), Improved ResNet: version = 2 (ResNet v2)
version = 2
# Computed depth from supplied model parameter n
n = 2
if version == 1:
? ? depth = n * 6 + 2
elif version == 2:
? ? depth = n * 9 + 2
? ??
# 根據ResNet版本,獲取對應的模型對象
if version == 2:
? ? model = resnet_v2(input_shape=input_shape, depth=depth)
else:
? ? model = resnet_v1(input_shape=input_shape, depth=depth)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
3.5 多GPU并行訓練
https://github.com/matterport/Mask_RCNN/blob/master/mrcnn/parallel_model.py
打開parallel_model.py文件,在原來文件加入紅點一行:
from parallel_model import ParallelModel
gpu_count = 2
model = ParallelModel(model, gpu_count)
model.compile(loss='categorical_crossentropy',
? ? ? ? ? ? ? optimizer=Adam(lr=0.001),
? ? ? ? ? ? ? metrics=['accuracy'])
1
2
3
4
5
6
7
3.6 打印模型架構信息
# Model name, depth and version
model_type = 'ResNet%dv%d' % (depth, version)
print(model_type)
model.summary()
1
2
3
4
如下所示三個resnet_layer為一個shotcut,但如上圖是兩個layer再加,作者用的三個效果更好
用于數據集cifar10的圖像分類網絡ResNet20v2架構
? ? 處理層_0: 輸入層,調用keras.layers中的Input類,通過傳遞參數shape實例化對象
? ? 數據層_0:矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 3
resnet_layer_0 #對應2.3節第一個x = resnet_layer ?#第一個3表示上層通道數或卷積核fliter數 ? ? ? ? ? ? ? ??
? ? ? ? 處理層_1:conv2d_1 ? ? ?卷積核形狀: ? ? ? ?3 x 3 x 3 x 16 / 1?
?#輸入3大小3*3輸出16,步長1,因為輸出是16,所以加16個b?
?#所以3*3*3*16=432(卷積核占的參數量)再加16為第一層conv2d_1參數個數448 ? ? ? ? ? ? ? ? ? ? ? ?
? ? 數據層_1:矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 16 ?#None表示batch size ? ? ??
? ? ? ? 處理層_2:batch_normalization_1
? ? 數據層_2: 矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 16
? ? ? ? 處理層_3:activation_1
? ? 數據層_3:矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 16?
resnet_layer_1 ? ? ? ?
? ? ? ? 處理層_4:conv2d_2 ? ? ?卷積核形狀: ? ? ? ?16 x 1 x 1 x 16 / 1 ? ? ? ?
? ? 數據層_4:矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 16
resnet_layer_2 ? ?
? ? ? ? 處理層_5:batch_normalization_2
? ? 數據層_5:矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 16
? ? ? ? 處理層_6:activation_2
? ? 數據層_6: 矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 16
? ? ? ? 處理層_7:conv2d_3 ? ? ?卷積核形狀: ? ? ? ? 16 x 3 x 3 x 16 / 1
? ? 數據層_7:矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 16
? ??
? ??
resnet_layer_3 ? ?
? ? ? ? 處理層_8: batch_normalization_3
? ? 數據層_8:矩陣形狀: ? ? ? ? ? ? ? N x 32 x 32 x 16
? ? ? ? 處理層_9:activation_3 ? ?
? ? 數據層_9:矩陣形狀: ? ? ? ? ? ? ? N x 32 x 32 x 16
? ? ? ? 處理層_10:conv2d_4 ? ? 卷積核形狀: ? ? ? 16 x 1 x 1 x 64 / 1
? ? 數據層_10:矩陣形狀: ? ? ? ? ? ? ?N x 32 x 32 x 64
shortcut_1 #不默認對上層處理,取指定層處理,相加,route_1是自己定義的
? ? ? ? 處理層_11:route_1 ? 取數據層_3 #數據層_3和下行數據層_11是同一層
? ? 數據層_11:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 16 ??
? ? ? ? 處理層_12:conv2d_5 ? ? 卷積核形狀: ? ? ? 16 x 1 x 1 x 64 / 1
? ? ? ? #(32-1+0)/1 +1=32,公式里第一個32表示上層長32,第二個32是得出這層長
? ? ? ? #N x 32 x 32 x 16經過16 x 1 x 1 x 64 / 1處理得出N x 32 x 32 x 64即下行
? ? 數據層_12:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 64?
? ? ? ? 處理層_13:add_1 ? ? 把數據層_10、數據層_12相加
? ? 數據層_13:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 64 ? ?
? ??
/// ??
? ??
resnet_layer_4
? ? ? ? 處理層_14:batch_normalization_4
? ? 數據層_14:矩陣形狀: ? ? ? ? ? ? N x 32 x 32 x 64
? ? ? ? 處理層_15:activation_4
? ? 數據層_15:矩陣形狀: ? ? ? ? ? ? N x 32 x 32 x 64
? ? ? ? 處理層_16:conv2d_6 ? ?卷積核形狀: ? ? ? ?64 x 1 x 1 x 16 / 1 ?
? ? 數據層_16:矩陣形狀: ? ? ? ? ? ? N x 32 x 32 x 16
? ??
? ??
resnet_layer_5 ? ?
? ? ? ? 處理層_17:batch_normalization_5
? ? 數據層_17:矩陣形狀: ? ? ? ? ? ? N x 32 x 32 x 16
? ? ? ? 處理層_18:activation_5
? ? 數據層_18:矩陣形狀: ? ? ? ? ? ? N x 32 x 32 x 16
? ? ? ? 處理層_19:conv2d_7 ? ?卷積核形狀: ? ? ? ?16 x 3 x 3 x 16 / 1 ?
? ? 數據層_19:矩陣形狀: ? ? ? ? ? ? N x 32 x 32 x 16
? ??
? ??
resnet_layer_6
? ? ? ? 處理層_20:batch_normalization_6
? ? 數據層_20:矩陣形狀: ? ? ? ? ? N x 32 x 32 x 16
? ? ? ? 處理層_21:activation_6
? ? 數據層_21:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 16
? ? ? ? 處理層_22:conv2d_8 ? ?卷積核形狀: ? ? ? 16 x 1 x 1 x 64 / 1
? ? 數據層_22:矩陣形狀: ? ? ? ? ? N x 32 x 32 x 64
shortcut_2
? ? ? ? 處理層_23:add_2 ? ? 把數據層_22、數據層_13相加
? ? 數據層_23:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 64
? ??
//
??
resnet_layer_7 ? ?
? ? ? ? 處理層_24:batch_normalization_7?
? ? 數據層_24:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 64
? ? ? ? 處理層_25:activation_7
? ? 數據層_25:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 64
? ? ? ? 處理層_26:conv2d_9 ? ? 卷積核形狀: ? ? ?64 x 1 x 1 x 64 / 2
? ? 數據層_26:矩陣形狀: ? ? ? ? ? N x 16 x 16 x 64 #通道擴展指最后位64變大,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#下采樣指由32*32變為16*16
resnet_layer_8
? ? ? ? 處理層_25:batch_normalization_8
? ? 數據層_25:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ? ? ? 處理層_26:activation_8
? ? 數據層_26:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ? ? ? 處理層_27:conv2d_10 ? ?卷積核形狀: ? ? ?64 x 3 x 3 x 64 / 1
? ? 數據層_27:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ??
resnet_layer_9
? ? ? ? 處理層_28:batch_normalization_9
? ? 數據層_28:矩陣形狀: ? ? ? ? ? N x 16 x 16 x 64
? ? ? ? 處理層_29:activation_9
? ? 數據層_29:矩陣形狀 ? ? ? ? ? ? N x 16 x 16 x 64
? ? ? ? 處理層_30:conv2d_11 ? ?卷積核形狀: ? ? ?64 x 1 x 1 x 128 / 1
? ? 數據層_30:矩陣形狀 ? ? ? ? ? ? N x 16 x 16 x 128
shortcut_3
? ? ? ? 處理層_31:route_2 ? ? ? ?取數據層_23
? ? 數據層_31:矩陣形狀: ? ? ? ? ? ?N x 32 x 32 x 64
? ? ? ? 處理層_32:conv2d_12 ? ?卷積核形狀: ? ? ?64 x 1 x 1 x 128 / 2
? ? 數據層_32:矩陣形狀: ? ? ? ? ? N x 16 x 16 x 128
? ? ? ? 處理層_33:add_3 ? ? ? ?把數據層_32、數據層_30相加
? ? 數據層_33:矩陣形狀: ? ? ? ? ? N x 16 x 16 x 128 ? ?
resnet_layer_10 ? ?
? ? ? ? 處理層_34:batch_normalization_10
? ? 數據層_34:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 128
? ? ? ? 處理層_35:activation_10
? ? 數據層_35:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 128
? ? ? ? 處理層_36:conv2d_13 ? ?卷積核形狀: ? ? ?128 x 1 x 1 x 64 / 1
? ? 數據層_36:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
resnet_layer_11
? ? ? ? 處理層_37:batch_normalization_11
? ? 數據層_37:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ? ? ? 處理層_38:activation_11
? ? 數據層_38:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ? ? ? 處理層_39:conv2d_14 ? ?卷積核形狀: ? ? ? 64 x 3 x 3 x 64 / 1
? ? 數據層_39:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ??
resnet_layer_12 ? ?
? ? ? ? 處理層_40:batch_normalization_12
? ? 數據層_40:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ? ? ? 處理層_41:activation_12
? ? 數據層_41:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 64
? ? ? ? 處理層_42:conv2d_15 ? ?卷積核形狀: ? ? ? 64 x 1 x 1 x 128 / 1
? ? 數據層_42:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 128
? ??
shortcut_4
? ? ? ? 處理層_43:add_4 ? ? ? ?把數據層_42、數據層_33相加
? ? 數據層_43:矩陣形狀: ? ? ? ? ? N x 16 x 16 x 128
/
resnet_layer_13 ? ?
? ? ? ? 處理層_44:batch_normalization_13
? ? 數據層_44:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 128
? ? ? ? 處理層_45:activation_13
? ? 數據層_45:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 128
? ? ? ? 處理層_46:conv2d_16 ? ?卷積核形狀: ? ? ? 128 x 1 x 1 x 128 / 2
? ? 數據層_46:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128 ? ?
resnet_layer_14 ? ?
? ? ? ? 處理層_47:batch_normalization_14
? ? 數據層_47:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
? ? ? ? 處理層_48:activation_14
? ? 數據層_48:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
? ? ? ? 處理層_49:conv2d_17 ? ?卷積核形狀: ? ? 128 x 3 x 3 x 128 / 1
? ? 數據層_49:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
resnet_layer_15 ? ?
? ? ? ? 處理層_50:batch_normalization_15
? ? 數據層_50:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
? ? ? ? 處理層_51:activation_15
? ? 數據層_51:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
? ? ? ? 處理層_52:conv2d_18 ? ?卷積核形狀: ? ? 128 x 1 x 1 x 256 / 1
? ? 數據層_52:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 256
? ? ? ? ?
shortcut_5
? ? ? ? 處理層_53:route_3 ? ? ? ? ?取數據層_43
? ? 數據層_53:矩陣形狀: ? ? ? ? ? ?N x 16 x 16 x 128 ? ?
? ? ? ? 處理層_54:conv2d_19 ? ?卷積核形狀: ? ? ?128 x 1 x 1 x 256 / 2
? ? 數據層_54:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 256
? ? ? ? 處理層_55:add_5 ? ? ? ?把數據層_54、數據層_52相加
? ? 數據層_55:矩陣形狀: ? ? ? ? ? N x 8 x 8 x 256 ? ?
?
? ??
resnet_layer_16 ? ?
? ? ? ? 處理層_56:batch_normalization_16
? ? 數據層_56:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 256?
? ? ? ? 處理層_57:activation_16
? ? 數據層_57:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 256?
? ? ? ? 處理層_58:conv2d_20 ? ?卷積核形狀: ? ? 256 x 1 x 1 x 128 / 1
? ? 數據層_58:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128?
resnet_layer_17
? ? ? ? 處理層_59:batch_normalization_17
? ? 數據層_59:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
? ? ? ? 處理層_60:activation_17
? ? 數據層_60:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128?
? ? ? ? 處理層_61:conv2d_21 ? ?卷積核形狀: ? ? 128 x 3 x 3 x 128 / 1
? ? 數據層_61:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
resnet_layer_18
? ? ? ? 處理層_62:batch_normalization_18
? ? 數據層_62:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128
? ? ? ? 處理層_63:activation_18
? ? 數據層_63:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 128?
? ? ? ? 處理層_64:conv2d_22 ? ?卷積核形狀: ? ? 128 x 1 x 1 x 256 / 1
? ? 數據層_64:矩陣形狀: ? ? ? ? ? ?N x 8 x 8 x 256
shortcut_6 ?#18層每3次一共做了6次shortcut
? ? ? ? 處理層_62:add_6 ? ? ? ?把數據層_64、數據層_55相加
? ? 數據層_62:矩陣形狀: ? ? ? ? ? N x 8 x 8 x 256
/
? ??
classifier#如果是yoloV3就是yolo層了
? ? ? ? 處理層_63:batch_normalization_19
? ? 數據層_63:矩陣形狀: ? ? ? ? ? N x 8 x 8 x 256
? ? ? ? 處理層_64:activation_19
? ? 數據層_64:矩陣形狀: ? ? ? ? ? N x 8 x 8 x 256
? ? ? ? 處理層_65:average_pooling2d_1
? ? 數據層_65:矩陣形狀: ? ? ? ? ? N x 1 x 1 x 256
? ? ? ? 處理層_66:flatten_1
? ? 數據層_66:矩陣形狀: ? ? ? ? ? N x 256
? ? ? ? 處理層_67:dense_1
? ? 數據層_67:矩陣形狀: ? ? ? ? ? N x 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
所以ResNet20_V2:這個20是conv共19層(layer0)+dense1層
4. 模型訓練
4.1 規劃學習率(訓練到后期時學習率需減小)
def lr_schedule(epoch):
? ? lr = 1e-3
? ? if epoch > 180:
? ? ? ? lr *= 0.5e-3
? ? elif epoch > 160:
? ? ? ? lr *= 1e-3
? ? elif epoch > 120:
? ? ? ? lr *= 1e-2
? ? elif epoch > 80:
? ? ? ? lr *= 1e-1
? ? print('Learning rate: ', lr)
? ? return lr
1
2
3
4
5
6
7
8
9
10
11
12
4.2 模型訓練時的參數設置
# Training parameters
batch_size = 64 ?# orig paper trained all networks with batch_size=128
epochs = 200
# Prepare model model saving directory.
save_dir = os.path.abspath('../resources/saved_models')
model_name = 'cifar10_%s_model.{epoch:03d}.h5' % model_type
if not os.path.isdir(save_dir):
? ? os.makedirs(save_dir)
filepath = os.path.join(save_dir, model_name)
# Prepare callbacks for model saving and for learning rate adjustment.
checkpoint = ModelCheckpoint(filepath=filepath,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?monitor='val_acc',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?verbose=0,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?save_best_only=True)
lr_scheduler = LearningRateScheduler(lr_schedule)
lr_reducer = ReduceLROnPlateau(factor=np.sqrt(0.1),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?cooldown=0,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?patience=5,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?min_lr=0.5e-6)
callbacks = [checkpoint, lr_reducer, lr_scheduler]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
4.3 使用圖像增強的結果做模型訓練
data_augmentation = True
if data_augmentation:
? ? print('Using real-time data augmentation.')
? ? # This will do preprocessing and realtime data augmentation:
? ? datagen = ImageDataGenerator(
? ? ? ? # set input mean to 0 over the dataset
? ? ? ? featurewise_center=False,
? ? ? ? # set each sample mean to 0
? ? ? ? samplewise_center=False,
? ? ? ? # divide inputs by std of dataset
? ? ? ? featurewise_std_normalization=False,
? ? ? ? # divide each input by its std
? ? ? ? samplewise_std_normalization=False,
? ? ? ? # apply ZCA whitening
? ? ? ? zca_whitening=False,
? ? ? ? # epsilon for ZCA whitening
? ? ? ? zca_epsilon=1e-06,
? ? ? ? # randomly rotate images in the range (deg 0 to 180)
? ? ? ? rotation_range=0,
? ? ? ? # randomly shift images horizontally
? ? ? ? width_shift_range=0.1,
? ? ? ? # randomly shift images vertically
? ? ? ? height_shift_range=0.1,
? ? ? ? # set range for random shear
? ? ? ? shear_range=0.,
? ? ? ? # set range for random zoom
? ? ? ? zoom_range=0.,
? ? ? ? # set range for random channel shifts
? ? ? ? channel_shift_range=0.,
? ? ? ? # set mode for filling points outside the input boundaries
? ? ? ? fill_mode='nearest',
? ? ? ? # value used for fill_mode = "constant"
? ? ? ? cval=0.,
? ? ? ? # randomly flip images
? ? ? ? horizontal_flip=True,
? ? ? ? # randomly flip images
? ? ? ? vertical_flip=False,
? ? ? ? # set rescaling factor (applied before any other transformation)
? ? ? ? rescale=None,
? ? ? ? # set function that will be applied on each input
? ? ? ? preprocessing_function=None,
? ? ? ? # image data format, either "channels_first" or "channels_last"
? ? ? ? data_format=None,
? ? ? ? # fraction of images reserved for validation (strictly between 0 and 1)
? ? ? ? validation_split=0.0)
? ?
? ? datagen.fit(x_train)
? ? # Fit the model on the batches generated by datagen.flow().
? ? model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size),
? ? ? ? ? ? ? ? ? ? ? ? validation_data=(x_test, y_test),
? ? ? ? ? ? ? ? ? ? ? ? epochs=epochs,
? ? ? ? ? ? ? ? ? ? ? ? verbose=1,?
? ? ? ? ? ? ? ? ? ? ? ? workers=4,
? ? ? ? ? ? ? ? ? ? ? ? callbacks=callbacks)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
附:python的生成器與keras.preprocessing.image文件的ImageDataGenerator類的關系:
問號可以找在哪個路徑:
如下圖打開image.py發現是繼承image:
找image:
5.模型評估
5.1 加載訓練好的模型
from keras.models import load_model
from keras.optimizers import Adam
model_filePath = '../resources/saved_models/cifar10_ResNet56v2_model.162.h5'
model = load_model(model_filePath)
model.compile(loss='categorical_crossentropy',
? ? ? ? ? ? ? optimizer=Adam(lr=0.001),
? ? ? ? ? ? ? metrics=['accuracy'])
1
2
3
4
5
6
7
8
5.2 計算訓練集的準確率
scores = model.evaluate(train_X, train_Y, verbose=1, batch_size=1000)
print('Test loss:%.6f' %scores[0])
print('Test accuracy:%.6f' %scores[1])
1
2
3
5.3 計算測試集的準確率
scores = model.evaluate(test_X, test_Y, verbose=1, batch_size=1000)
print('Test loss:%.6f' %scores[0])
print('Test accuracy:%.6f' %scores[1])
1
2
3
6. 模型測試結果可視化
6.1 隨機選100張圖可視化
import math
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
import random
def draw_image(position, image, title, isTrue):
? ? plt.subplot(*position)
? ? plt.imshow(image)
? ? plt.axis('off')
? ? if not isTrue:
? ? ? ? plt.title(title, color='red')
? ? else:
? ? ? ? plt.title(title)
? ? ? ??
def batch_draw_images(model, batch_size, test_imageData, test_X, test_y, id2name_dict):
? ? index_list = list(range(len(test_imageData)))
? ? selected_index_list = random.sample(index_list, batch_size)
? ? true_imageData = test_imageData[selected_index_list]
? ? true_X = test_X[selected_index_list]
? ? true_y = np.array(test_y)[selected_index_list]
? ? predict_Y = model.predict(true_X)
? ? predict_y = np.argmax(predict_Y, axis=1)
? ? row_number = math.ceil(batch_size ** 0.5)
? ? column_number = row_number
? ? plt.figure(figsize=(row_number+8, column_number+8))
? ? for i in range(row_number):
? ? ? ? for j in range(column_number):
? ? ? ? ? ? index = i * column_number + j
? ? ? ? ? ? if index < batch_size:
? ? ? ? ? ? ? ? position = (row_number, column_number, index+1)
? ? ? ? ? ? ? ? image = true_imageData[index]
? ? ? ? ? ? ? ? actual_classId = true_y[index]
? ? ? ? ? ? ? ? predict_classId = predict_y[index]
? ? ? ? ? ? ? ? isTrue = actual_classId==predict_classId
? ? ? ? ? ? ? ? actual_className = id2name_dict[actual_classId]
? ? ? ? ? ? ? ? predict_className = id2name_dict[predict_classId]
? ? ? ? ? ? ? ? title = 'actual:%s\npredict:%s' %(actual_className, predict_className)
? ? ? ? ? ? ? ? draw_image(position, image, title, isTrue)
batch_size = 100 #展示100張圖
className_list = ['飛機', '汽車', '鳥', '貓', '鹿', '狗', '青蛙', '馬', '船', '卡車']
id2name_dict = {a:b for a, b in enumerate(className_list)}
batch_draw_images(model, batch_size, test_imageData, test_X, test_y, id2name_dict)
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
6.2 隨機選取100張圖片的同時,要求10個類別,每個類別取10張
def get_selectedIndexList(test_y, batch_size):
? ? assert batch_size % 10 == 0, 'batch_size must be times by 10, or you change function get_selectedIndexList'
? ? column_number = int(batch_size / 10)
? ? classId_ndarray = np.unique(test_y)
? ? selected_index_list = []
? ? for i, classId in enumerate(classId_ndarray):
? ? ? ? index_ndarray = np.where(test_y==classId)[0]
? ? ? ? selected_index_ndarray = np.random.choice(index_ndarray, column_number)
? ? ? ? selected_index_list.extend(selected_index_ndarray.tolist())
? ? return selected_index_list ? ?
? ? ? ??
def batch_draw_images_2(model, selected_index_list, test_imageData, test_X, test_y, id2name_dict):
? ? true_imageData = test_imageData[selected_index_list]
? ? true_X = test_X[selected_index_list]
? ? true_y = np.array(test_y)[selected_index_list]
? ? predict_Y = model.predict(true_X)
? ? predict_y = np.argmax(predict_Y, axis=1)
? ? row_number = math.ceil(batch_size ** 0.5)
? ? column_number = row_number
? ? plt.figure(figsize=(row_number+8, column_number+8))
? ? for i in range(row_number):
? ? ? ? for j in range(column_number):
? ? ? ? ? ? index = i * column_number + j
? ? ? ? ? ? if index < batch_size:
? ? ? ? ? ? ? ? position = (row_number, column_number, index+1)
? ? ? ? ? ? ? ? image = true_imageData[index]
? ? ? ? ? ? ? ? actual_classId = true_y[index]
? ? ? ? ? ? ? ? predict_classId = predict_y[index]
? ? ? ? ? ? ? ? isTrue = actual_classId==predict_classId
? ? ? ? ? ? ? ? actual_className = id2name_dict[actual_classId]
? ? ? ? ? ? ? ? predict_className = id2name_dict[predict_classId]
? ? ? ? ? ? ? ? title = 'actual:%s\npredict:%s' %(actual_className, predict_className)
? ? ? ? ? ? ? ? draw_image(position, image, title, isTrue)
batch_size = 100 ? ??
className_list = ['飛機', '汽車', '鳥', '貓', '鹿', '狗', '青蛙', '馬', '船', '卡車']
id2name_dict = {a:b for a, b in enumerate(className_list)}
selected_index_list = get_selectedIndexList(test_y, batch_size)
batch_draw_images_2(model, selected_index_list, test_imageData, test_X, test_y, id2name_dict)
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
7.Keras中權重文件的讀寫
7.1 使用load_model方法加載模型文件
from keras.models import load_model
from keras.optimizers import Adam
model_filePath = '../resources/saved_models/cifar10_ResNet56v2_model.162.h5'
model = load_model(model_filePath)
model.compile(loss='categorical_crossentropy',
? ? ? ? ? ? ? optimizer=Adam(lr=0.001),
? ? ? ? ? ? ? metrics=['accuracy'])
1
2
3
4
5
6
7
8
7.2 使用save_weights方法保存權重文件
weights_h5FilePath = '../resources/saved_models/resnet56v2_weights.h5'
model.save_weights(weights_h5FilePath)
1
2
7.3 使用load_weights方法加載權重文件
input_shape = (32, 32, 3)
depth = 56
model = resnet_v2(input_shape, depth)
weights_h5FilePath = '../resources/saved_models/resnet56v2_weights.h5'
model.load_weights(weights_h5FilePath)
model.compile(loss='categorical_crossentropy',
? ? ? ? ? ? ? optimizer=Adam(lr=0.001),
? ? ? ? ? ? ? metrics=['accuracy'])
?
總結
以上是生活随笔為你收集整理的CV】keras_resnet 在cifar10数据集上分类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Keras中Callback函数的使用
- 下一篇: 基于Keras搭建cifar10数据集训