当前位置:   article > 正文

基于深度学习的人脸识别系统:卷积神经网络实现(VIPLFaceNet、VGGNet、Xception、ResNet50、ResNet18)、AM-Softmax损失

viplfacenet

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


ResNet结构并分析其在计算机视觉方面取得成功的原因

Resnet通过引入残差单元来解决退化问题。
结构:
(1)通过增加 恒等快捷连接(identity shortcut connection)实现,直接跳过一个或多个层。优势是残差映射在实际中往往更容易优化。
(2)Resnet网络中短路连接shortcut的方式考虑到x的维度与F(X)维度可能不匹配情况,需进行维度匹配。通常采用两种方法解决这一问题:
zero_padding:对恒等层进行0填充的方式将维度补充完整。这种方法不会增加额外的参数
projection:在恒等层采用1x1的卷积核来增加维度。这种方法会增加额外的参数
(3)bottleneck 实现方式
使用1x1的卷积层来降维,最后一层使用1x1的卷积层来进行升维
(4)激活函数移动到残差部分可以提高模型的精度


  1. train.py
  2. #!/usr/bin env python
  3. from keras.callbacks import EarlyStopping, ReduceLROnPlateau, CSVLogger, ModelCheckpoint
  4. # DO NOT REMOVE THIS:
  5. from model.cnn_models import *
  6. from utils.data_generator import DataGenerator
  7. from model.amsoftmax import wrap_cnn, amsoftmax_loss
  8. input_shape = (64, 64, 1)
  9. batch_size = 64
  10. num_epochs = 1000
  11. #patience:生成被监视的验证数量,当training时无再改进时将停下来。验证数量不能为每个epoch
  12. patience = 100
  13. log_file_path = "./log.csv"
  14. cnn = "ResNet18"
  15. trained_models_path = "./trained_models/" + cnn
  16. generator = DataGenerator(dataset="olivettifaces",
  17. path="./data/olivetti_faces/olivettifaces.jpg",
  18. batch_size=batch_size,
  19. input_size=input_shape,
  20. is_shuffle=True,
  21. data_augmentation=10,
  22. validation_split=.2)
  23. num_classes, num_images, training_set_size, validation_set_size = generator.get_number()
  24. #类型数40、images数8400、训练集大小6720、验证集大小1680
  25. print("get_number:",num_classes, num_images, training_set_size, validation_set_size)
  26. #eval() 函数用来执行一个字符串表达式,并返回表达式的值。
  27. #此处eval("ResNet18") 实际执行的是 ./model/cnn_models文件中的def ResNet18()函数
  28. model = wrap_cnn(model=eval(cnn),
  29. feature_layer="feature",
  30. input_shape=input_shape,
  31. num_classes=num_classes)
  32. model.compile(optimizer='adam',
  33. loss=amsoftmax_loss, #自定义amsoftmax_loss
  34. metrics=['accuracy'])
  35. model.summary()
  36. #画出model网络模型的拓扑图
  37. from tensorflow.keras.utils import plot_model
  38. #如果是在默认的C:\Users\Administrator路径下打开的命令提示符窗口执行的代码的话,则保存图片到该当前默认路径下
  39. plot_model(model,to_file="model.png") #产生网络模型的拓扑图
  40. from IPython.display import Image #画生网络模型的拓扑图
  41. Image("model.png")
  42. # callbacks
  43. early_stop = EarlyStopping('loss', 0.1, patience=patience)
  44. reduce_lr = ReduceLROnPlateau('loss', factor=0.1, patience=int(patience / 2), verbose=1)
  45. csv_logger = CSVLogger(log_file_path, append=False)
  46. #epoch和accuracy这样的单词字眼必须对应fit训练时返回的字典中的key:accuracy、loss等,否则会报错Key Error找不到该key
  47. model_names = trained_models_path + '.{epoch:02d}-{accuracy:2f}.hdf5'
  48. model_checkpoint = ModelCheckpoint(model_names,
  49. monitor='loss',
  50. verbose=1,
  51. save_best_only=True,
  52. save_weights_only=False)
  53. callbacks = [model_checkpoint, csv_logger, early_stop, reduce_lr]
  54. # train model by generator
  55. model.fit_generator(generator=generator.flow('train'),
  56. steps_per_epoch=int(training_set_size / batch_size),
  57. epochs=num_epochs,
  58. verbose=1,
  59. callbacks=callbacks,
  60. validation_data=generator.flow('validate'),
  61. validation_steps=int(validation_set_size / batch_size)
  62. )
  63. """
  64. Model: "model_2"
  65. __________________________________________________________________________________________________
  66. Layer (type) Output Shape Param # Connected to
  67. ==================================================================================================
  68. input (InputLayer) (None, 64, 64, 1) 0
  69. __________________________________________________________________________________________________
  70. conv1_pad (ZeroPadding2D) (None, 70, 70, 1) 0 input[0][0]
  71. __________________________________________________________________________________________________
  72. conv1 (Conv2D) (None, 32, 32, 64) 3200 conv1_pad[0][0]
  73. __________________________________________________________________________________________________
  74. batch_normalization_1 (BatchNor (None, 32, 32, 64) 256 conv1[0][0]
  75. __________________________________________________________________________________________________
  76. activation_1 (Activation) (None, 32, 32, 64) 0 batch_normalization_1[0][0]
  77. __________________________________________________________________________________________________
  78. pool1_pad (ZeroPadding2D) (None, 34, 34, 64) 0 activation_1[0][0]
  79. __________________________________________________________________________________________________
  80. max_pooling2d_1 (MaxPooling2D) (None, 16, 16, 64) 0 pool1_pad[0][0]
  81. __________________________________________________________________________________________________
  82. zero_padding2d_1 (ZeroPadding2D (None, 18, 18, 64) 0 max_pooling2d_1[0][0]
  83. __________________________________________________________________________________________________
  84. conv2d_1 (Conv2D) (None, 8, 8, 64) 36928 zero_padding2d_1[0][0]
  85. __________________________________________________________________________________________________
  86. batch_normalization_2 (BatchNor (None, 8, 8, 64) 256 conv2d_1[0][0]
  87. __________________________________________________________________________________________________
  88. activation_2 (Activation) (None, 8, 8, 64) 0 batch_normalization_2[0][0]
  89. __________________________________________________________________________________________________
  90. zero_padding2d_2 (ZeroPadding2D (None, 10, 10, 64) 0 activation_2[0][0]
  91. __________________________________________________________________________________________________
  92. conv2d_2 (Conv2D) (None, 8, 8, 64) 36928 zero_padding2d_2[0][0]
  93. __________________________________________________________________________________________________
  94. conv2d_3 (Conv2D) (None, 8, 8, 64) 4160 max_pooling2d_1[0][0]
  95. __________________________________________________________________________________________________
  96. batch_normalization_3 (BatchNor (None, 8, 8, 64) 256 conv2d_2[0][0]
  97. __________________________________________________________________________________________________
  98. batch_normalization_4 (BatchNor (None, 8, 8, 64) 256 conv2d_3[0][0]
  99. __________________________________________________________________________________________________
  100. add_1 (Add) (None, 8, 8, 64) 0 batch_normalization_3[0][0]
  101. batch_normalization_4[0][0]
  102. __________________________________________________________________________________________________
  103. activation_3 (Activation) (None, 8, 8, 64) 0 add_1[0][0]
  104. __________________________________________________________________________________________________
  105. zero_padding2d_3 (ZeroPadding2D (None, 10, 10, 64) 0 activation_3[0][0]
  106. __________________________________________________________________________________________________
  107. conv2d_4 (Conv2D) (None, 8, 8, 64) 36928 zero_padding2d_3[0][0]
  108. __________________________________________________________________________________________________
  109. batch_normalization_5 (BatchNor (None, 8, 8, 64) 256 conv2d_4[0][0]
  110. __________________________________________________________________________________________________
  111. activation_4 (Activation) (None, 8, 8, 64) 0 batch_normalization_5[0][0]
  112. __________________________________________________________________________________________________
  113. zero_padding2d_4 (ZeroPadding2D (None, 10, 10, 64) 0 activation_4[0][0]
  114. __________________________________________________________________________________________________
  115. conv2d_5 (Conv2D) (None, 8, 8, 64) 36928 zero_padding2d_4[0][0]
  116. __________________________________________________________________________________________________
  117. batch_normalization_6 (BatchNor (None, 8, 8, 64) 256 conv2d_5[0][0]
  118. __________________________________________________________________________________________________
  119. add_2 (Add) (None, 8, 8, 64) 0 batch_normalization_6[0][0]
  120. activation_3[0][0]
  121. __________________________________________________________________________________________________
  122. activation_5 (Activation) (None, 8, 8, 64) 0 add_2[0][0]
  123. __________________________________________________________________________________________________
  124. zero_padding2d_5 (ZeroPadding2D (None, 10, 10, 64) 0 activation_5[0][0]
  125. __________________________________________________________________________________________________
  126. conv2d_6 (Conv2D) (None, 4, 4, 128) 73856 zero_padding2d_5[0][0]
  127. __________________________________________________________________________________________________
  128. batch_normalization_7 (BatchNor (None, 4, 4, 128) 512 conv2d_6[0][0]
  129. __________________________________________________________________________________________________
  130. activation_6 (Activation) (None, 4, 4, 128) 0 batch_normalization_7[0][0]
  131. __________________________________________________________________________________________________
  132. zero_padding2d_6 (ZeroPadding2D (None, 6, 6, 128) 0 activation_6[0][0]
  133. __________________________________________________________________________________________________
  134. conv2d_7 (Conv2D) (None, 4, 4, 128) 147584 zero_padding2d_6[0][0]
  135. __________________________________________________________________________________________________
  136. conv2d_8 (Conv2D) (None, 4, 4, 128) 8320 activation_5[0][0]
  137. __________________________________________________________________________________________________
  138. batch_normalization_8 (BatchNor (None, 4, 4, 128) 512 conv2d_7[0][0]
  139. __________________________________________________________________________________________________
  140. batch_normalization_9 (BatchNor (None, 4, 4, 128) 512 conv2d_8[0][0]
  141. __________________________________________________________________________________________________
  142. add_3 (Add) (None, 4, 4, 128) 0 batch_normalization_8[0][0]
  143. batch_normalization_9[0][0]
  144. __________________________________________________________________________________________________
  145. activation_7 (Activation) (None, 4, 4, 128) 0 add_3[0][0]
  146. __________________________________________________________________________________________________
  147. zero_padding2d_7 (ZeroPadding2D (None, 6, 6, 128) 0 activation_7[0][0]
  148. __________________________________________________________________________________________________
  149. conv2d_9 (Conv2D) (None, 4, 4, 128) 147584 zero_padding2d_7[0][0]
  150. __________________________________________________________________________________________________
  151. batch_normalization_10 (BatchNo (None, 4, 4, 128) 512 conv2d_9[0][0]
  152. __________________________________________________________________________________________________
  153. activation_8 (Activation) (None, 4, 4, 128) 0 batch_normalization_10[0][0]
  154. __________________________________________________________________________________________________
  155. zero_padding2d_8 (ZeroPadding2D (None, 6, 6, 128) 0 activation_8[0][0]
  156. __________________________________________________________________________________________________
  157. conv2d_10 (Conv2D) (None, 4, 4, 128) 147584 zero_padding2d_8[0][0]
  158. __________________________________________________________________________________________________
  159. batch_normalization_11 (BatchNo (None, 4, 4, 128) 512 conv2d_10[0][0]
  160. __________________________________________________________________________________________________
  161. add_4 (Add) (None, 4, 4, 128) 0 batch_normalization_11[0][0]
  162. activation_7[0][0]
  163. __________________________________________________________________________________________________
  164. activation_9 (Activation) (None, 4, 4, 128) 0 add_4[0][0]
  165. __________________________________________________________________________________________________
  166. zero_padding2d_9 (ZeroPadding2D (None, 6, 6, 128) 0 activation_9[0][0]
  167. __________________________________________________________________________________________________
  168. conv2d_11 (Conv2D) (None, 2, 2, 256) 295168 zero_padding2d_9[0][0]
  169. __________________________________________________________________________________________________
  170. batch_normalization_12 (BatchNo (None, 2, 2, 256) 1024 conv2d_11[0][0]
  171. __________________________________________________________________________________________________
  172. activation_10 (Activation) (None, 2, 2, 256) 0 batch_normalization_12[0][0]
  173. __________________________________________________________________________________________________
  174. zero_padding2d_10 (ZeroPadding2 (None, 4, 4, 256) 0 activation_10[0][0]
  175. __________________________________________________________________________________________________
  176. conv2d_12 (Conv2D) (None, 2, 2, 256) 590080 zero_padding2d_10[0][0]
  177. __________________________________________________________________________________________________
  178. conv2d_13 (Conv2D) (None, 2, 2, 256) 33024 activation_9[0][0]
  179. __________________________________________________________________________________________________
  180. batch_normalization_13 (BatchNo (None, 2, 2, 256) 1024 conv2d_12[0][0]
  181. __________________________________________________________________________________________________
  182. batch_normalization_14 (BatchNo (None, 2, 2, 256) 1024 conv2d_13[0][0]
  183. __________________________________________________________________________________________________
  184. add_5 (Add) (None, 2, 2, 256) 0 batch_normalization_13[0][0]
  185. batch_normalization_14[0][0]
  186. __________________________________________________________________________________________________
  187. activation_11 (Activation) (None, 2, 2, 256) 0 add_5[0][0]
  188. __________________________________________________________________________________________________
  189. zero_padding2d_11 (ZeroPadding2 (None, 4, 4, 256) 0 activation_11[0][0]
  190. __________________________________________________________________________________________________
  191. conv2d_14 (Conv2D) (None, 2, 2, 256) 590080 zero_padding2d_11[0][0]
  192. __________________________________________________________________________________________________
  193. batch_normalization_15 (BatchNo (None, 2, 2, 256) 1024 conv2d_14[0][0]
  194. __________________________________________________________________________________________________
  195. activation_12 (Activation) (None, 2, 2, 256) 0 batch_normalization_15[0][0]
  196. __________________________________________________________________________________________________
  197. zero_padding2d_12 (ZeroPadding2 (None, 4, 4, 256) 0 activation_12[0][0]
  198. __________________________________________________________________________________________________
  199. conv2d_15 (Conv2D) (None, 2, 2, 256) 590080 zero_padding2d_12[0][0]
  200. __________________________________________________________________________________________________
  201. batch_normalization_16 (BatchNo (None, 2, 2, 256) 1024 conv2d_15[0][0]
  202. __________________________________________________________________________________________________
  203. add_6 (Add) (None, 2, 2, 256) 0 batch_normalization_16[0][0]
  204. activation_11[0][0]
  205. __________________________________________________________________________________________________
  206. activation_13 (Activation) (None, 2, 2, 256) 0 add_6[0][0]
  207. __________________________________________________________________________________________________
  208. zero_padding2d_13 (ZeroPadding2 (None, 4, 4, 256) 0 activation_13[0][0]
  209. __________________________________________________________________________________________________
  210. conv2d_16 (Conv2D) (None, 1, 1, 512) 1180160 zero_padding2d_13[0][0]
  211. __________________________________________________________________________________________________
  212. batch_normalization_17 (BatchNo (None, 1, 1, 512) 2048 conv2d_16[0][0]
  213. __________________________________________________________________________________________________
  214. activation_14 (Activation) (None, 1, 1, 512) 0 batch_normalization_17[0][0]
  215. __________________________________________________________________________________________________
  216. zero_padding2d_14 (ZeroPadding2 (None, 3, 3, 512) 0 activation_14[0][0]
  217. __________________________________________________________________________________________________
  218. conv2d_17 (Conv2D) (None, 1, 1, 512) 2359808 zero_padding2d_14[0][0]
  219. __________________________________________________________________________________________________
  220. conv2d_18 (Conv2D) (None, 1, 1, 512) 131584 activation_13[0][0]
  221. __________________________________________________________________________________________________
  222. batch_normalization_18 (BatchNo (None, 1, 1, 512) 2048 conv2d_17[0][0]
  223. __________________________________________________________________________________________________
  224. batch_normalization_19 (BatchNo (None, 1, 1, 512) 2048 conv2d_18[0][0]
  225. __________________________________________________________________________________________________
  226. add_7 (Add) (None, 1, 1, 512) 0 batch_normalization_18[0][0]
  227. batch_normalization_19[0][0]
  228. __________________________________________________________________________________________________
  229. activation_15 (Activation) (None, 1, 1, 512) 0 add_7[0][0]
  230. __________________________________________________________________________________________________
  231. zero_padding2d_15 (ZeroPadding2 (None, 3, 3, 512) 0 activation_15[0][0]
  232. __________________________________________________________________________________________________
  233. conv2d_19 (Conv2D) (None, 1, 1, 512) 2359808 zero_padding2d_15[0][0]
  234. __________________________________________________________________________________________________
  235. batch_normalization_20 (BatchNo (None, 1, 1, 512) 2048 conv2d_19[0][0]
  236. __________________________________________________________________________________________________
  237. activation_16 (Activation) (None, 1, 1, 512) 0 batch_normalization_20[0][0]
  238. __________________________________________________________________________________________________
  239. zero_padding2d_16 (ZeroPadding2 (None, 3, 3, 512) 0 activation_16[0][0]
  240. __________________________________________________________________________________________________
  241. conv2d_20 (Conv2D) (None, 1, 1, 512) 2359808 zero_padding2d_16[0][0]
  242. __________________________________________________________________________________________________
  243. batch_normalization_21 (BatchNo (None, 1, 1, 512) 2048 conv2d_20[0][0]
  244. __________________________________________________________________________________________________
  245. add_8 (Add) (None, 1, 1, 512) 0 batch_normalization_21[0][0]
  246. activation_15[0][0]
  247. __________________________________________________________________________________________________
  248. activation_17 (Activation) (None, 1, 1, 512) 0 add_8[0][0]
  249. __________________________________________________________________________________________________
  250. feature (GlobalAveragePooling2D (None, 512) 0 activation_17[0][0]
  251. __________________________________________________________________________________________________
  252. dropout_1 (Dropout) (None, 512) 0 feature[0][0]
  253. __________________________________________________________________________________________________
  254. predictions (AMSoftmax) (None, 40) 20480 dropout_1[0][0]
  255. ==================================================================================================
  256. Total params: 11,209,536
  257. Trainable params: 11,199,808
  258. Non-trainable params: 9,728
  259. __________________________________________________________________________________________________
  260. """

  1. cnn_models.py
  2. from keras import layers
  3. from keras.layers import Activation, Dropout, Conv2D, Dense
  4. from keras.layers import BatchNormalization
  5. from keras.layers import Flatten
  6. from keras.layers import GlobalAveragePooling2D
  7. from keras.layers import InputLayer, Input
  8. from keras.layers import MaxPooling2D
  9. from keras.layers import SeparableConv2D
  10. from keras.layers import ZeroPadding2D, Add
  11. from keras.models import Model
  12. from keras.models import Sequential
  13. from keras.regularizers import l2
  14. # 来自 VIPLFaceNet
  15. # 你可以在以下网址看到文献: https://arxiv.org/abs/1609.03892
  16. def VIPL_FaceNet(input_shape, num_classes):
  17. model = Sequential()
  18. model.add(InputLayer(input_shape=input_shape,
  19. name="input"))
  20. # Conv layer 1 output shape (55, 55, 48)
  21. model.add(Conv2D(
  22. kernel_size=(9, 9),
  23. activation="relu",
  24. filters=48,
  25. strides=(4, 4)
  26. ))
  27. # pool1
  28. model.add(MaxPooling2D((3, 3), strides=(2, 2), padding='same'))
  29. # Conv layer 2 output shape (27, 27, 128)
  30. model.add(Conv2D(
  31. strides=(1, 1),
  32. kernel_size=(3, 3),
  33. activation="relu",
  34. filters=128
  35. ))
  36. # Conv layer 3 output shape (13, 13, 192)
  37. model.add(Conv2D(
  38. strides=(1, 1),
  39. kernel_size=(3, 3),
  40. activation="relu",
  41. filters=128
  42. ))
  43. # pool2
  44. model.add(MaxPooling2D((3, 3), strides=(2, 2), padding='same'))
  45. # conv4
  46. model.add(Conv2D(
  47. kernel_size=(3, 3),
  48. activation="relu",
  49. filters=256,
  50. padding="same",
  51. strides=(1, 1)
  52. ))
  53. # conv5
  54. model.add(Conv2D(
  55. kernel_size=(3, 3),
  56. activation="relu",
  57. filters=192,
  58. padding="same",
  59. strides=(1, 1)
  60. ))
  61. # conv6
  62. model.add(Conv2D(
  63. kernel_size=(3, 3),
  64. activation="relu",
  65. filters=192,
  66. padding="same",
  67. strides=(1, 1)
  68. ))
  69. # conv7
  70. model.add(Conv2D(
  71. kernel_size=(3, 3),
  72. activation="relu",
  73. filters=128,
  74. padding="same",
  75. strides=(1, 1)
  76. ))
  77. # pool3
  78. model.add(MaxPooling2D((3, 3), strides=(2, 2), padding='same'))
  79. # fully connected layer 1
  80. model.add(Flatten())
  81. model.add(Dense(4096))
  82. model.add(BatchNormalization())
  83. model.add(Activation('relu'))
  84. model.add(Dropout(0.5))
  85. # fully connected layer 2
  86. model.add(Dense(2048))
  87. model.add(BatchNormalization())
  88. model.add(Activation('relu', name="feature"))
  89. model.add(Dropout(0.5))
  90. # output
  91. model.add(Dense(num_classes))
  92. model.add(Activation('softmax', name='predictions'))
  93. # return
  94. return model
  95. # 实现 VGGNet
  96. def VGGNet(input_shape, num_classes):
  97. # 因为 VGGNet 更深,而且网络中有许多max pooling,
  98. # 不建议input_shape太小,原input_shape是 (224, 224, 3)。
  99. assert input_shape[0] >= 224 and input_shape[1] >= 224
  100. model = Sequential()
  101. model.add(InputLayer(input_shape=input_shape,
  102. name="input"))
  103. # Conv1,2
  104. model.add(Conv2D(
  105. kernel_size=(3, 3),
  106. activation="relu",
  107. filters=64,
  108. strides=(1, 1)))
  109. model.add(Conv2D(
  110. kernel_size=(3, 3),
  111. activation="relu",
  112. filters=64,
  113. strides=(1, 1)))
  114. # pool1
  115. model.add(MaxPooling2D((2, 2), strides=(2, 2),
  116. padding='same'))
  117. # Conv 3,4
  118. model.add(Conv2D(
  119. kernel_size=(3, 3),
  120. activation="relu",
  121. filters=128,
  122. strides=(1, 1)))
  123. model.add(Conv2D(
  124. kernel_size=(3, 3),
  125. activation="relu",
  126. filters=128,
  127. strides=(1, 1)))
  128. # pool2
  129. model.add(MaxPooling2D((2, 2), strides=(2, 2),
  130. padding='same'))
  131. # Conv 5-7
  132. model.add(Conv2D(
  133. kernel_size=(3, 3),
  134. activation="relu",
  135. filters=256,
  136. strides=(1, 1)))
  137. model.add(Conv2D(
  138. kernel_size=(3, 3),
  139. activation="relu",
  140. filters=256,
  141. strides=(1, 1)))
  142. model.add(Conv2D(
  143. kernel_size=(3, 3),
  144. activation="relu",
  145. filters=256,
  146. strides=(1, 1)))
  147. # pool3
  148. model.add(MaxPooling2D((2, 2), strides=(2, 2),
  149. padding='same'))
  150. # Conv 8-10
  151. model.add(Conv2D(
  152. kernel_size=(3, 3),
  153. activation="relu",
  154. filters=512,
  155. strides=(1, 1)))
  156. model.add(Conv2D(
  157. kernel_size=(3, 3),
  158. activation="relu",
  159. filters=512,
  160. strides=(1, 1)))
  161. model.add(Conv2D(
  162. kernel_size=(3, 3),
  163. activation="relu",
  164. filters=512,
  165. strides=(1, 1)))
  166. # pool4
  167. model.add(MaxPooling2D((2, 2), strides=(2, 2),
  168. padding='same'))
  169. # Conv 11-13
  170. model.add(Conv2D(
  171. kernel_size=(3, 3),
  172. activation="relu",
  173. filters=512,
  174. strides=(1, 1)))
  175. model.add(Conv2D(
  176. kernel_size=(3, 3),
  177. activation="relu",
  178. filters=512,
  179. strides=(1, 1)))
  180. model.add(Conv2D(
  181. kernel_size=(3, 3),
  182. activation="relu",
  183. filters=512,
  184. strides=(1, 1)))
  185. # pool5
  186. model.add(MaxPooling2D((2, 2), strides=(2, 2), padding='same'))
  187. # fully connected layer 1
  188. model.add(Flatten())
  189. model.add(Dense(2048))
  190. model.add(BatchNormalization())
  191. model.add(Activation('relu'))
  192. model.add(Dropout(0.5))
  193. # fully connected layer 2
  194. model.add(Dense(2048))
  195. model.add(BatchNormalization())
  196. model.add(Activation('relu', name="feature"))
  197. model.add(Dropout(0.5))
  198. model.add(Dense(num_classes))
  199. model.add(Activation('softmax', name='predictions'))
  200. return model
  201. # 面部分类
  202. # 源代码: https://github.com/oarriaga/face_classification/blob/master/src/models/cnn.py
  203. def tiny_XCEPTION(input_shape, num_classes, l2_regularization=0.01):
  204. regularization = l2(l2_regularization)
  205. # base
  206. img_input = Input(input_shape, name="input")
  207. x = Conv2D(5, (3, 3), strides=(1, 1), kernel_regularizer=regularization,
  208. use_bias=False)(img_input)
  209. x = BatchNormalization()(x)
  210. x = Activation('relu')(x)
  211. x = Conv2D(5, (3, 3), strides=(1, 1), kernel_regularizer=regularization,
  212. use_bias=False)(x)
  213. x = BatchNormalization()(x)
  214. x = Activation('relu')(x)
  215. # module 1
  216. residual = Conv2D(8, (1, 1), strides=(2, 2),
  217. padding='same', use_bias=False)(x)
  218. residual = BatchNormalization()(residual)
  219. x = SeparableConv2D(8, (3, 3), padding='same',
  220. kernel_regularizer=regularization,
  221. use_bias=False)(x)
  222. x = BatchNormalization()(x)
  223. x = Activation('relu')(x)
  224. x = SeparableConv2D(8, (3, 3), padding='same',
  225. kernel_regularizer=regularization,
  226. use_bias=False)(x)
  227. x = BatchNormalization()(x)
  228. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
  229. x = layers.add([x, residual])
  230. # module 2
  231. residual = Conv2D(16, (1, 1), strides=(2, 2),
  232. padding='same', use_bias=False)(x)
  233. residual = BatchNormalization()(residual)
  234. x = SeparableConv2D(16, (3, 3), padding='same',
  235. kernel_regularizer=regularization,
  236. use_bias=False)(x)
  237. x = BatchNormalization()(x)
  238. x = Activation('relu')(x)
  239. x = SeparableConv2D(16, (3, 3), padding='same',
  240. kernel_regularizer=regularization,
  241. use_bias=False)(x)
  242. x = BatchNormalization()(x)
  243. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
  244. x = layers.add([x, residual])
  245. # module 3
  246. residual = Conv2D(32, (1, 1), strides=(2, 2),
  247. padding='same', use_bias=False)(x)
  248. residual = BatchNormalization()(residual)
  249. x = SeparableConv2D(32, (3, 3), padding='same',
  250. kernel_regularizer=regularization,
  251. use_bias=False)(x)
  252. x = BatchNormalization()(x)
  253. x = Activation('relu')(x)
  254. x = SeparableConv2D(32, (3, 3), padding='same',
  255. kernel_regularizer=regularization,
  256. use_bias=False)(x)
  257. x = BatchNormalization()(x)
  258. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
  259. x = layers.add([x, residual])
  260. # module 4
  261. residual = Conv2D(64, (1, 1), strides=(2, 2),
  262. padding='same', use_bias=False)(x)
  263. residual = BatchNormalization()(residual)
  264. x = SeparableConv2D(64, (3, 3), padding='same',
  265. kernel_regularizer=regularization,
  266. use_bias=False)(x)
  267. x = BatchNormalization()(x)
  268. x = Activation('relu')(x)
  269. x = SeparableConv2D(64, (3, 3), padding='same',
  270. kernel_regularizer=regularization,
  271. use_bias=False)(x)
  272. x = BatchNormalization()(x)
  273. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
  274. x = layers.add([x, residual])
  275. x = Conv2D(1024, (3, 3),
  276. # kernel_regularizer=regularization,
  277. padding='same')(x)
  278. x = GlobalAveragePooling2D()(x)
  279. x = Dense(1024, name="feature")(x)
  280. x = Dropout(.5)(x)
  281. x = Dense(num_classes)(x)
  282. output = Activation('softmax', name='predictions')(x)
  283. model = Model(img_input, output)
  284. return model
  285. def ResNet50(input_shape, num_classes):
  286. # wrap ResNet50 from keras, because ResNet50 is so deep.
  287. from keras.applications.resnet50 import ResNet50
  288. input_tensor = Input(shape=input_shape, name="input")
  289. x = ResNet50(include_top=False,
  290. weights=None,
  291. input_tensor=input_tensor,
  292. input_shape=None,
  293. pooling="avg",
  294. classes=num_classes)
  295. x = Dense(units=2048, name="feature")(x.output)
  296. return Model(inputs=input_tensor, outputs=x)
  297. # 实现于 ResNet's block.
  298. # 实现了两个 classes block: 一个是基本块basic block,另一个是瓶颈块bottleneck block
  299. def basic_block(filters, kernel_size=3, is_first_block=True):
  300. stride = 1
  301. if is_first_block:
  302. stride = 2
  303. def f(x):
  304. # f(x) named y
  305. # 1st Conv
  306. y = ZeroPadding2D(padding=1)(x)
  307. y = Conv2D(filters, kernel_size, strides=stride, kernel_initializer='he_normal')(y)
  308. y = BatchNormalization()(y)
  309. y = Activation("relu")(y)
  310. # 2nd Conv
  311. y = ZeroPadding2D(padding=1)(y)
  312. y = Conv2D(filters, kernel_size, kernel_initializer='he_normal')(y)
  313. y = BatchNormalization()(y)
  314. # f(x) + x
  315. if is_first_block:
  316. shortcut = Conv2D(filters, kernel_size=1, strides=stride, kernel_initializer='he_normal')(x)
  317. shortcut = BatchNormalization()(shortcut)
  318. else:
  319. shortcut = x
  320. y = Add()([y, shortcut])
  321. y = Activation("relu")(y)
  322. return y
  323. return f
  324. # ResNet v1, we can see the paper at:
  325. # https://arxiv.org/abs/1512.03385
  326. def ResNet18(input_shape, num_classes):
  327. input_layer = Input(shape=input_shape, name="input")
  328. # Conv1
  329. x = layers.ZeroPadding2D(padding=(3, 3), name='conv1_pad')(input_layer)
  330. x = layers.Conv2D(64, (7, 7),
  331. strides=(2, 2),
  332. padding='valid',
  333. kernel_initializer='he_normal',
  334. name='conv1')(x)
  335. x = layers.BatchNormalization()(x)
  336. x = layers.Activation('relu')(x)
  337. x = layers.ZeroPadding2D(padding=(1, 1), name='pool1_pad')(x)
  338. x = layers.MaxPooling2D((3, 3), strides=(2, 2))(x)
  339. # Conv2
  340. x = basic_block(filters=64)(x)
  341. x = basic_block(filters=64, is_first_block=False)(x)
  342. # Conv3
  343. x = basic_block(filters=128)(x)
  344. x = basic_block(filters=128, is_first_block=False)(x)
  345. # Conv4
  346. x = basic_block(filters=256)(x)
  347. x = basic_block(filters=256, is_first_block=False)(x)
  348. # Conv5
  349. x = basic_block(filters=512)(x)
  350. x = basic_block(filters=512, is_first_block=False)(x)
  351. x = GlobalAveragePooling2D(name="feature")(x)
  352. output_layer = Dense(num_classes, activation='softmax')(x)
  353. model = Model(input_layer, output_layer)
  354. return model
  1. amsoftmax.py
  2. import tensorflow as tf
  3. from keras import backend as K
  4. from keras.layers import Dropout
  5. from keras.engine.topology import Layer
  6. from keras.models import Model
  7. class AMSoftmax(Layer):
  8. def __init__(self, units, **kwargs):
  9. self.units = units
  10. self.kernel = None
  11. super(AMSoftmax, self).__init__(**kwargs)
  12. # 类(初始化值)(call函数传入值):即创建完实例对象后就执行call函数,
  13. # 那么类中的执行顺序为先执行 _init__函数,然后执行 build函数,最后执行 call函数
  14. def build(self, input_shape):
  15. assert len(input_shape) >= 2
  16. self.kernel = self.add_weight(name='kernel',
  17. shape=(input_shape[1], self.units),
  18. initializer='uniform',
  19. trainable=True)
  20. super(AMSoftmax, self).build(input_shape)
  21. #作为模型输出层的输出
  22. def call(self, inputs, **kwargs):
  23. # 得到余弦相似性
  24. # cosine余弦 = x * w / (||x|| * ||w||)
  25. inputs = K.l2_normalize(inputs, axis=1)
  26. kernel = K.l2_normalize(self.kernel, axis=0)
  27. cosine = K.dot(inputs, kernel)
  28. return cosine
  29. def compute_output_shape(self, input_shape):
  30. return input_shape[0], self.units
  31. def get_config(self):
  32. config = {
  33. 'units': self.units}
  34. base_config = super(AMSoftmax, self).get_config()
  35. return dict(list(base_config.items())
  36. + list(config.items()))
  37. # 参考自: https://github.com/hao-qiang/AM-Softmax/blob/master/AM-Softmax.ipynb
  38. def amsoftmax_loss(y_true, y_pred, scale=30.0, margin=0.35):
  39. # 定义两个常量张量
  40. m = K.constant(margin, name='m')
  41. s = K.constant(scale, name='s')
  42. # 重塑标签label
  43. label = K.reshape(K.argmax(y_true, axis=-1), shape=(-1, 1))
  44. label = K.cast(label, dtype=tf.int32)
  45. #pred_batch批预处理
  46. pred_batch = K.reshape(tf.range(K.shape(y_pred)[0]), shape=(-1, 1))
  47. #concat两个列向量,一个是pred_batch批预处理,另一个是标签label。
  48. ground_truth_indices = tf.concat([pred_batch,
  49. K.reshape(label, shape=(-1, 1))], axis=1)
  50. """
  51. 参考自:https://tensorflow.google.cn/api_docs/python/tf/gather_nd?hl=en
  52. tf.gather_nd(params, indices, batch_dims=0, name=None)
  53. 根据indices索引对params矩阵/向量进行元素操作
  54. indices = [[0, 0], [1, 1]]
  55. params = [['a', 'b'], ['c', 'd']]
  56. output = ['a', 'd']
  57. indices = [[1], [0]]
  58. params = [['a', 'b'], ['c', 'd']]
  59. output = [['c', 'd'], ['a', 'b']]
  60. """
  61. # get ground truth scores by indices
  62. ground_truth_scores = tf.gather_nd(y_pred, ground_truth_indices)
  63. # 如果 ground_truth_scores > m, 则 ground_truth_scores = group_truth_score - m
  64. #K.greater(x, y)用法:如果x>y,则返回 布尔张量
  65. added_margin = K.cast(K.greater(ground_truth_scores, m), dtype=tf.float32) * m
  66. added_margin = K.reshape(added_margin, shape=(-1, 1))
  67. #tf.subtract 减法
  68. added_embedding_feature = tf.subtract(y_pred, y_true * added_margin) * s
  69. #计算logits和labels之间的softmax cross entropy交叉熵
  70. cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_true, logits=added_embedding_feature)
  71. loss = tf.reduce_mean(cross_entropy)
  72. return loss
  73. def wrap_cnn(model, feature_layer, input_shape, num_classes):
  74. cnn = model(input_shape, num_classes)
  75. assert isinstance(cnn, Model)
  76. #获取feature (GlobalAveragePooling2D)的输出
  77. x = cnn.get_layer(name=feature_layer).output
  78. x = Dropout(.5)(x)
  79. #1.类(初始化值)(call函数传入值):即创建完实例对象后就执行call函数,
  80. # 那么类中的执行顺序为先执行 _init__函数,然后执行 build函数,最后执行 call函数
  81. #2.predictions (AMSoftmax) 作为模型输出,自定义AM-Softmax损失函数和AM-Softmax网络层
  82. output_layer = AMSoftmax(num_classes, name="predictions")(x)
  83. return Model(inputs=cnn.input, outputs=output_layer)
  84. def load_model(filepath):
  85. import keras.models
  86. model = keras.models.load_model(filepath,
  87. {"AMSoftmax": AMSoftmax,
  88. "amsoftmax_loss": amsoftmax_loss})
  89. return model
  1. evaluate.py
  2. # /usr/bin env python
  3. import os
  4. import cv2
  5. import matplotlib.pyplot as plt
  6. import numpy as np
  7. from sklearn.metrics import roc_curve, auc
  8. from data.olivetti_faces.split_img import split_to_dataset
  9. from model.amsoftmax import load_model
  10. from utils.feature import get_feature_function
  11. from utils.measure import kappa, cosine_similarity
  12. model_path = "./trained_models/tiny_XCEPTION.hdf5"
  13. img_path = "./data/olivetti_faces/olivettifaces.jpg"
  14. test_data_path = "./olive"
  15. input_shape = (64, 64, 1)
  16. def classifier():
  17. model = load_model(filepath=model_path)
  18. files = list(os.walk(test_data_path))[0][2]
  19. x_list = []
  20. total = 0
  21. correct = 0
  22. matrix = np.zeros(shape=(20, 20))
  23. for file in files:
  24. label = file.split("_")[0].replace("olive", "")
  25. img = cv2.imread(test_data_path + file)
  26. img = cv2.resize(img, (64, 64))
  27. img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  28. img = img / 256
  29. img = np.expand_dims(img, -1)
  30. img = np.expand_dims(img, 0)
  31. x_list.append(img)
  32. y = model.predict(x=img)
  33. y = int(np.argmax(y) / 2)
  34. y_correct = int(label)
  35. total += 1
  36. if y == y_correct:
  37. correct += 1
  38. matrix[y_correct][y] += 1
  39. k = kappa(matrix=matrix)
  40. print("total is {0}, precise is {1}, kappa is {2}."
  41. .format(total, correct / total, k))
  42. def recognition():
  43. # This threshold is used to determine if two face images belong to the same person.
  44. threshold = 0.80
  45. model = load_model(filepath=model_path)
  46. f = get_feature_function(model)
  47. base_feature = f(cv2.imread("./olive/0_0.jpg"))
  48. y_true = []
  49. for i in range(200):
  50. if i < 10:
  51. y_true.append(1) # True
  52. else:
  53. y_true.append(0) # False
  54. y_score = []
  55. for label in range(20):
  56. for photo in range(10):
  57. file = "./olive/" + str(label) + "_" + str(photo) + ".jpg"
  58. img_feature = f(cv2.imread(file))
  59. sim = cosine_similarity(base_feature, img_feature)
  60. print("label:{0} - {1} ,sim : {2}".format(label, photo, sim))
  61. if sim > threshold:
  62. y_score.append(1) # True
  63. else:
  64. y_score.append(0) # False
  65. correct = 0
  66. for i in range(200):
  67. if y_true[i] == y_score[i]:
  68. correct += 1
  69. print("acc is " + str(correct / 200))
  70. fpr, tpr, t = roc_curve(y_true, y_score)
  71. roc_auc = auc(fpr, tpr)
  72. plt.figure()
  73. lw = 2
  74. plt.figure(figsize=(10, 10))
  75. plt.plot(fpr, tpr, color='darkorange',
  76. lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
  77. plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='-.')
  78. plt.xlim([0.0, 1.0])
  79. plt.ylim([0.0, 1.05])
  80. plt.xlabel('False Positive Rate')
  81. plt.ylabel('True Positive Rate')
  82. plt.title('ROC curve')
  83. plt.legend(loc="lower right")
  84. plt.show()
  85. if __name__ == '__main__':
  86. if not os.path.exists(test_data_path):
  87. os.mkdir(test_data_path)
  88. # generate_more_faces(, test_data_path)
  89. split_to_dataset(img_path, test_data_path)
  90. recognition()

  1. predict.py
  2. import os
  3. import cv2
  4. from utils.feature import get_feature_function
  5. from utils.measure import *
  6. model_path = "./trained_models/tiny_XCEPTION.hdf5"
  7. def main():
  8. get_feature = get_feature_function(model=model_path)
  9. features = []
  10. base_feature = None
  11. dir_list = list(list(os.walk("./data/manual_testing"))[0])[2]
  12. dir_list.sort()
  13. for file in dir_list:
  14. path = "./data/manual_testing/" + file
  15. img = cv2.imread(path)
  16. feature = get_feature(img)
  17. features.append((file, feature))
  18. if file == "base.jpg":
  19. base_feature = feature
  20. for file, feature in features:
  21. print(file, '\t',
  22. cosine_similarity(feature, base_feature), '\t',
  23. euclidean_metric(feature, base_feature), '\t',
  24. pearson_correlation(feature, base_feature))
  25. if __name__ == '__main__':
  26. main()
  27. """
  28. base.jpg 1.0000000596046448 1.0 0.99999994
  29. base_full.jpg 0.8650757670402527 0.0014323909546049918 0.73107094
  30. lena.jpg 0.7991840243339539 0.0010432298559344395 0.59929365
  31. man1.jpg 0.6370709836483002 0.0031209503507164146 0.2738905
  32. man1_2.jpg 0.5672858357429504 0.002656866875466825 0.13452913
  33. man2.jpg 0.48662818130105734 0.0027977924693378836 -0.026793957
  34. woman1_crop.jpg 0.8841563165187836 0.00508468014331387 0.76889646
  35. woman1_full.jpg 0.8546876013278961 0.0016342116788881774 0.70945275
  36. woman2_crop.jpg 0.7393457293510437 0.002660944596353025 0.47877395
  37. woman2_full.jpg 0.8256216049194336 0.0009339273743781038 0.65218705
  38. woman3_crop.jpg 0.8040041327476501 0.003071616047994001 0.6079379
  39. woman3_full.jpg 0.8212800323963165 0.0013429052489530274 0.6433183
  40. woman4_crop.jpg 0.696440264582634 0.0032429208812613745 0.3926806
  41. woman4_full.jpg 0.8566377758979797 0.0015620006726975552 0.71384853
  42. woman5.jpg 0.9146099090576172 0.001529003613932187 0.8297442
  43. woman5_crop.jpg 0.9101028144359589 0.005750450657876265 0.8201517
  44. """
  1. web.py
  2. import cv2
  3. from tempfile import SpooledTemporaryFile
  4. import numpy as np
  5. from flask import Flask
  6. from flask import request
  7. from utils.feature import get_feature_function
  8. from utils.measure import cosine_similarity
  9. model_path = "./trained_models/tiny_XCEPTION.hdf5"
  10. get_feature = get_feature_function(model=model_path)
  11. app = Flask(__name__, static_folder="web_static")
  12. # if we save file to disk, we must use the following configuration.
  13. # upload_folder = './web_static/uploads/'
  14. # app.config['UPLOAD_FOLDER'] = upload_folder
  15. app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif', 'bmp'}
  16. @app.route("/")
  17. def hello():
  18. return "Hello, SmooFaceEngine!"
  19. @app.route("/test")
  20. def test():
  21. html = '''
  22. <!DOCTYPE html>
  23. <html lang="en">
  24. <head>
  25. <meta charset="UTF-8">
  26. <title>Uploading</title>
  27. </head>
  28. <body>
  29. <form action="/data" method="post" enctype="multipart/form-data">
  30. <input type="file" name="pic1" value="Pic1" /><br>
  31. <input type="file" name="pic2" value="Pic2" /><br>
  32. <input type="submit" value="upload">
  33. </form>
  34. </body>
  35. </html>
  36. '''
  37. return html
  38. def get_feature_from_client(request_filename):
  39. # If we want to save this file to disk, we can use the
  40. # following code. But if we should save the binary file from client to disk,
  41. # the program would run slowly.
  42. """
  43. import random
  44. def get_random_string(length):
  45. string = ""
  46. for i in range(0, length):
  47. code = random.randint(97, 122)
  48. string += chr(code)
  49. return string
  50. pic = request.files[request_filename]
  51. img_type = pic.filename.split('.')[1]
  52. filename = get_random_string(10) + "." + img_type
  53. filepath = os.path.join(app.root_path,
  54. app.config['UPLOAD_FOLDER'],
  55. filename)
  56. pic.save(filepath)
  57. vector = get_feature(filepath)
  58. os.unlink(filepath)
  59. return vector
  60. """
  61. # the following codes:
  62. # We will save the file from client to memory, then
  63. # the program run much faster than saving it to disk.
  64. file = request.files[request_filename]
  65. stream = file.stream
  66. # for old version flask:
  67. """
  68. if isinstance(stream, SpooledTemporaryFile):
  69. stream = stream.file
  70. """
  71. value = bytearray(stream.read())
  72. value = np.asarray(value, dtype='uint8')
  73. img = cv2.imdecode(value, 1)
  74. vector = get_feature(img)
  75. return vector
  76. @app.route("/data", methods=["POST"])
  77. def predict():
  78. vector1 = get_feature_from_client('pic1')
  79. vector2 = get_feature_from_client('pic2')
  80. similarity = cosine_similarity(vector1, vector2)
  81. return str(similarity)
  82. if __name__ == "__main__":
  83. app.run(host='0.0.0.0', port=8080, debug=True)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/307597
推荐阅读
  

闽ICP备14008679号