使用两种方法构建模型,一种是如下所示方法,构建一个VGG16网络:
model = Sequential()
model.add(Conv2D(32, (3, 3), strides=(1, 1), input_shape=(299, 299, 3), padding='same', activation='relu',
kernel_initializer='uniform'))
model.add(Conv2D(32, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, (3, 2), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(64, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(128, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(128, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(128, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(256, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(Conv2D(512, (3, 3), strides=(1, 1), padding='same', activation='relu', kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(2048, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(2048, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(100, activation='softmax'))
sgd = SGD(lr=0.001, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])
model.load_weights('c:/wei.h5')
classes = model.predict_classes(x_test)[0]
classlist = model.predict_proba(x_test).tolist() # 获取每个类的概率
或者使用如下方法,构建一个inception_v4网络:
CONV_BLOCK_COUNT = 0 # 用来命名计数卷积编号
INCEPTION_A_COUNT = 0
INCEPTION_B_COUNT = 0
INCEPTION_C_COUNT = 0
def conv_block(x, nb_filters, nb_row, nb_col, strides=(1, 1), padding='same', use_bias=False):
global CONV_BLOCK_COUNT
CONV_BLOCK_COUNT += 1
with K.name_scope('conv_block_' + str(CONV_BLOCK_COUNT)):
x = Conv2D(filters=nb_filters,
kernel_size=(nb_row, nb_col),
strides=strides,
padding=padding,
use_bias=use_bias)(x)
x = BatchNormalization(axis=-1, momentum=0.9997, scale=False)(x)
x = Activation("relu")(x)
return x
def stem(x_input):
with K.name_scope('stem'):
x = conv_block(x_input, 32, 3, 3, strides=(2, 2), padding='valid')
x = conv_block(x, 32, 3, 3, padding='valid')
x = conv_block(x, 64, 3, 3)
x1 = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='valid')(x)
x2 = conv_block(x, 96, 3, 3, strides=(2, 2), padding='valid')
x = concatenate([x1, x2], axis=-1)
x1 = conv_block(x, 64, 1, 1)
x1 = conv_block(x1, 96, 3, 3, padding='valid')
x2 = conv_block(x, 64, 1, 1)
x2 = conv_block(x2, 64, 7, 1)
x2 = conv_block(x2, 64, 1, 7)
x2 = conv_block(x2, 96, 3, 3, padding='valid')
x = concatenate([x1, x2], axis=-1)
x1 = conv_block(x, 192, 3, 3, strides=(2, 2), padding='valid')
x2 = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='valid')(x)
merged_vector = concatenate([x1, x2], axis=-1)
return merged_vector
def inception_A(x_input):
"""35*35 卷积块"""
global INCEPTION_A_COUNT
INCEPTION_A_COUNT += 1
with K.name_scope('inception_A' + str(INCEPTION_A_COUNT)):
averagepooling_conv1x1 = AveragePooling2D(pool_size=(3, 3), strides=(1, 1), padding='same')(
x_input) # 35 * 35 * 192
averagepooling_conv1x1 = conv_block(averagepooling_conv1x1, 96, 1, 1) # 35 * 35 * 96
conv1x1 = conv_block(x_input, 96, 1, 1) # 35 * 35 * 96
conv1x1_3x3 = conv_block(x_input, 64, 1, 1) # 35 * 35 * 64
conv1x1_3x3 = conv_block(conv1x1_3x3, 96, 3, 3) # 35 * 35 * 96
conv3x3_3x3 = conv_block(x_input, 64, 1, 1) # 35 * 35 * 64
conv3x3_3x3 = conv_block(conv3x3_3x3, 96, 3, 3) # 35 * 35 * 96
conv3x3_3x3 = conv_block(conv3x3_3x3, 96, 3, 3) # 35 * 35 * 96
merged_vector = concatenate([averagepooling_conv1x1, conv1x1, conv1x1_3x3, conv3x3_3x3],
axis=-1) # 35 * 35 * 384
return merged_vector
def inception_B(x_input):
"""17*17 卷积块"""
global INCEPTION_B_COUNT
INCEPTION_B_COUNT += 1
with K.name_scope('inception_B' + str(INCEPTION_B_COUNT)):
averagepooling_conv1x1 = AveragePooling2D(pool_size=(3, 3), strides=(1, 1), padding='same')(x_input)
averagepooling_conv1x1 = conv_block(averagepooling_conv1x1, 128, 1, 1)
conv1x1 = conv_block(x_input, 384, 1, 1)
conv1x7_1x7 = conv_block(x_input, 192, 1, 1)
conv1x7_1x7 = conv_block(conv1x7_1x7, 224, 1, 7)
conv1x7_1x7 = conv_block(conv1x7_1x7, 256, 1, 7)
conv2_1x7_7x1 = conv_block(x_input, 192, 1, 1)
conv2_1x7_7x1 = conv_block(conv2_1x7_7x1, 192, 1, 7)
conv2_1x7_7x1 = conv_block(conv2_1x7_7x1, 224, 7, 1)
conv2_1x7_7x1 = conv_block(conv2_1x7_7x1, 224, 1, 7)
conv2_1x7_7x1 = conv_block(conv2_1x7_7x1, 256, 7, 1)
merged_vector = concatenate([averagepooling_conv1x1, conv1x1, conv1x7_1x7, conv2_1x7_7x1], axis=-1)
return merged_vector
def inception_C(x_input):
"""8*8 卷积块"""
global INCEPTION_C_COUNT
INCEPTION_C_COUNT += 1
with K.name_scope('Inception_C' + str(INCEPTION_C_COUNT)):
averagepooling_conv1x1 = AveragePooling2D(pool_size=(3, 3), strides=(1, 1), padding='same')(x_input)
averagepooling_conv1x1 = conv_block(averagepooling_conv1x1, 256, 1, 1)
conv1x1 = conv_block(x_input, 256, 1, 1)
# 用 1x3 和 3x1 替代 3x3
conv3x3_1x1 = conv_block(x_input, 384, 1, 1)
conv3x3_1 = conv_block(conv3x3_1x1, 256, 1, 3)
conv3x3_2 = conv_block(conv3x3_1x1, 256, 3, 1)
conv2_3x3_1x1 = conv_block(x_input, 384, 1, 1)
conv2_3x3_1x1 = conv_block(conv2_3x3_1x1, 448, 1, 3)
conv2_3x3_1x1 = conv_block(conv2_3x3_1x1, 512, 3, 1)
conv2_3x3_1x1_1 = conv_block(conv2_3x3_1x1, 256, 3, 1)
conv2_3x3_1x1_2 = conv_block(conv2_3x3_1x1, 256, 1, 3)
merged_vector = concatenate(
[averagepooling_conv1x1, conv1x1, conv3x3_1, conv3x3_2, conv2_3x3_1x1_1, conv2_3x3_1x1_2], axis=-1)
return merged_vector
def reduction_A(x_input, k=192, l=224, m=256, n=384):
with K.name_scope('Reduction_A'):
"""Architecture of a 35 * 35 to 17 * 17 Reduction_A block."""
maxpool = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='valid')(x_input)
conv3x3 = conv_block(x_input, n, 3, 3, strides=(2, 2), padding='valid')
conv2_3x3 = conv_block(x_input, k, 1, 1)
conv2_3x3 = conv_block(conv2_3x3, l, 3, 3)
conv2_3x3 = conv_block(conv2_3x3, m, 3, 3, strides=(2, 2), padding='valid')
merged_vector = concatenate([maxpool, conv3x3, conv2_3x3], axis=-1)
return merged_vector
def reduction_B(x_input):
"""Architecture of a 17 * 17 to 8 * 8 Reduction_B block."""
with K.name_scope('Reduction_B'):
maxpool = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), padding='valid')(x_input)
conv3x3 = conv_block(x_input, 192, 1, 1)
conv3x3 = conv_block(conv3x3, 192, 3, 3, strides=(2, 2), padding='valid')
conv1x7_7x1_3x3 = conv_block(x_input, 256, 1, 1)
conv1x7_7x1_3x3 = conv_block(conv1x7_7x1_3x3, 256, 1, 7)
conv1x7_7x1_3x3 = conv_block(conv1x7_7x1_3x3, 320, 7, 1)
conv1x7_7x1_3x3 = conv_block(conv1x7_7x1_3x3, 320, 3, 3, strides=(2, 2), padding='valid')
merged_vector = concatenate([maxpool, conv3x3, conv1x7_7x1_3x3], axis=-1)
return merged_vector
def inception_v4_backbone(nb_classes=1000, load_weights=True):
x_input = Input(shape=(299, 299, 3))
# Stem
x = stem(x_input) # 35 x 35 x 384
# 4 x Inception_A
for i in range(2):
x = inception_A(x) # 35 x 35 x 384
# Reduction_A
x = reduction_A(x, k=192, l=224, m=256, n=384) # 17 x 17 x 1024
# 7 x Inception_B
for i in range(3):
x = inception_B(x) # 17 x 17 x1024
# Reduction_B
x = reduction_B(x) # 8 x 8 x 1536
# Average Pooling
x = AveragePooling2D(pool_size=(8, 8))(x) # 1536
# dropout
x = Dropout(0.2)(x)
x = Flatten()(x) # 1536
# 全连接层
x = Dense(units=nb_classes, activation='softmax')(x)
model = Model(inputs=x_input, outputs=x, name='Inception-V4')
return model
这两种不同的模型构建方式,所用的预测函数是不一样的。
在第一种方式中,使用如下的预测方法:
model.load_weights('c:/myvgg16.h5')
classes = model.predict_classes(x_test)[0]
classlist = model.predict_proba(x_test).tolist() # 获取每个类的概率
predict_classes返回的是输入所属于的类别,predict_proba返回的是每个类别的概率,一般由于不能100%的预测分类,所以第二个函数用的比较多。
第二种方式的预测函数如下:
classes = inception_v4_backbone.predict(x_test)[0]
这个函数和predict_proba类似,返回每个类的概率。
第三种方式如下:
或者使用如这篇文章中所说的方式进行预测,即使用数据生成器进行预测:
https://blog.csdn.net/qq_27261889/article/details/85239164
但这样有个很大的问题,就是不能对具体的那个文件进行预测,而只能对文件夹进行预测,用起来不是很方便。
优点在于如果需要一次性分类很多图片,没有内存的限制。
------------------------------------------------分割线---------------------------------------------------------------
其中尤其要注意的一点是,在模型的训练过程中,为了提高模型的准确度,会把整形的图片数据变成浮点型。
对应上面的方式分为
x_test.append(np.array(Image.open("c:/1.jpg").convert('RGB')))
x_test = np.array(x_test)
x_test = x_test.astype('float32')
x_test /= 255
和
train_datagen = ImageDataGenerator(
rescale=1. / 255
)
val_datagen = ImageDataGenerator(
rescale=1. / 255
)
inception_v4_model = inception_v4(nb_classes=534)
train_generator = train_datagen.flow_from_directory(directory='C:/train',
target_size=(299, 299),
batch_size=32,
shuffle=True
)
val_generator = val_datagen.flow_from_directory(directory='C:/test',
target_size=(299, 299),
batch_size=32,
shuffle=True
)
所以在预测的时候,同样需要把输入的图片进行浮点化的处理,否则可能出现,不论输入什么图片,都输出同一个类别的错误。