优化:
1.使用数据增强技术。
2.使用数据生成器提高训练速度。
3.调节超参数,提高模型精度。
4.使用VGG技术迁移学习,提高训练速度。
目标
-
算法应用
- 熟练掌握TensorFlow框架使用
- 掌握神经网络图像相关案例
1.训练的时候读取本地图片以及类别
train_generator = ImageDataGenerator()
- 生产图片的批次张量值并且提供数据增强功能
- rescale=1.0 / 255,:标准化
- zca_whitening=False: # zca白化的作用是针对图片进行PCA降维操作,减少图片的冗余信息
- rotation_range=20:默认0, 旋转角度,在这个角度范围随机生成一个值
- width_shift_range=0.2,:默认0,水平平移
- height_shift_range=0.2:默认0, 垂直平移
- shear_range=0.2:# 平移变换
- zoom_range=0.2:
- horizontal_flip=True:水平翻转
使用train_generator.flow_from_directory()
-
directory=path,# 读取目录
-
target_size=(h,w),# 目标形状
-
batch_size=size,# 批数量大小
-
class_mode='binary', # 目标值格式,One of "categorical", "binary", "sparse",
- "categorical" :2D one-hot encoded labels
- "binary" will be 1D binary labels
-
shuffle=True
2.思路和步骤
- 读取本地的图片数据以及类别
- keras.preprocessing.image import ImageDataGenerator提供了读取转换功能
- 模型的结构修改(添加我们自定的分类层)
- freeze掉原始VGG模型
- 编译以及训练和保存模型方式
- 输入数据进行预测
3.模型设计
VGG模型的修改添加全连接层
一个GlobalAveragePooling2D + 两个全连接层
-
在图像分类任务中,模型经过最后CNN层后的尺寸为[bath_size, img_width, img_height, channels],通常的做法是:接一个flatten layer,将尺寸变为[batch_size, w h channels]再至少接一个FC layer,这样做的最大问题是:模型参数多,且容易过拟合。
-
利用pooling layer来替代最后的FC layer
4.编译和训练
def compile(self, model):
model.compile(optimizer=keras.optimizers.Adam(),
loss=keras.losses.sparse_categorical_crossentropy,
metrics=['accuracy'])
5.训练和回调函数callbacks
keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1)
参数
- filepath: 字符串,保存模型的路径, 如果
filepath
是weights.{epoch:02d}-{val_loss:.2f}.hdf5
, 那么模型被保存的的文件名就会有训练轮数和验证损失。 - monitor: 被监测的数据,损失函数或者准确率
- verbose: 详细信息模式,0 或者 1 ,输出结果打印
- save_best_only: 如果
save_best_only=True
, 被监测数据的最佳模型就不会被覆盖,只保留最好的 - mode: {auto, min, max} 的其中之一。 如果
save_best_only=True
,那么是否覆盖保存文件的决定就取决于被监测数据的最大或者最小值。 对于val_acc
,模式就会是max
,而对于val_loss
,模式就需要是min
,等等。 在auto
模式中,方向会自动从被监测的数据的名字中判断出来。 - save_weights_only: 如果 True,那么只有模型的权重会被保存 (
model.save_weights(filepath)
), 否则的话,整个模型会被保存 (model.save(filepath)
)。 - period: 每个检查点之间的间隔(训练轮数)。
6.进行预测
预测的步骤就是读取图片以及处理到模型中预测,加载我们训练的模型
7.训练记录如下
_________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, None, None, 3)] 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, None, None, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, None, None, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, None, None, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, None, None, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, None, None, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, None, None, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, None, None, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, None, None, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, None, None, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_pool (MaxPooling2D) (None, None, None, 512) 0
_________________________________________________________________
global_average_pooling2d (Gl (None, 512) 0
_________________________________________________________________
dense (Dense) (None, 1024) 525312
_________________________________________________________________
dense_1 (Dense) (None, 5) 5125
=================================================================
Total params: 15,245,125
Trainable params: 15,245,125
Non-trainable params: 0
_________________________________________________________________
None
WARNING:tensorflow:`period` argument is deprecated. Please use `save_freq` to specify the frequency in number of samples seen.
Epoch 1/5
2022-01-11 19:45:50.379409: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 205520896 exceeds 10% of system memory.
2022-01-11 19:45:50.889438: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 205520896 exceeds 10% of system memory.
1/25 [>.............................] - ETA: 7:36 - loss: 1.8611 - acc: 0.37502022-01-11 19:46:07.844408: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 205520896 exceeds 10% of system memory.
2022-01-11 19:46:08.092422: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 205520896 exceeds 10% of system memory.
2/25 [=>............................] - ETA: 6:24 - loss: 1.6121 - acc: 0.50002022-01-11 19:46:22.274233: W tensorflow/core/framework/cpu_allocator_impl.cc:81] Allocation of 205520896 exceeds 10% of system memory.
3/25 [==>...........................] - ETA: 5:50 - loss: 1.6170 - acc: 0.4583
4/25 [===>..........................] - ETA: 5:26 - loss: 1.5825 - acc: 0.5000
5/25 [=====>........................] - ETA: 5:06 - loss: 1.5714 - acc: 0.5125
6/25 [======>.......................] - ETA: 4:48 - loss: 1.5080 - acc: 0.5104
7/25 [=======>......................] - ETA: 4:31 - loss: 1.4150 - acc: 0.5536
8/25 [========>.....................] - ETA: 4:14 - loss: 1.3916 - acc: 0.5312
9/25 [=========>....................] - ETA: 3:58 - loss: 1.3366 - acc: 0.5417
10/25 [===========>..................] - ETA: 3:43 - loss: 1.2681 - acc: 0.5750
11/25 [============>.................] - ETA: 3:27 - loss: 1.2320 - acc: 0.5795
12/25 [=============>................] - ETA: 3:12 - loss: 1.1886 - acc: 0.5833
13/25 [==============>...............] - ETA: 2:57 - loss: 1.1473 - acc: 0.6010
14/25 [===============>..............] - ETA: 2:42 - loss: 1.1124 - acc: 0.6205
15/25 [=================>............] - ETA: 2:27 - loss: 1.0875 - acc: 0.6250
16/25 [==================>...........] - ETA: 2:12 - loss: 1.0576 - acc: 0.6367
17/25 [===================>..........] - ETA: 1:57 - loss: 1.0182 - acc: 0.6507
18/25 [====================>.........] - ETA: 1:42 - loss: 0.9929 - acc: 0.6667
19/25 [=====================>........] - ETA: 1:27 - loss: 0.9637 - acc: 0.6809
20/25 [=======================>......] - ETA: 1:13 - loss: 0.9327 - acc: 0.6969
21/25 [========================>.....] - ETA: 58s - loss: 0.9055 - acc: 0.7083
22/25 [=========================>....] - ETA: 43s - loss: 0.8836 - acc: 0.7159
23/25 [==========================>...] - ETA: 29s - loss: 0.8649 - acc: 0.7201
24/25 [===========================>..] - ETA: 14s - loss: 0.8540 - acc: 0.7214Epoch 1/5
1/25 [>.............................] - ETA: 6:08 - loss: 0.3627 - acc: 0.9375
2/25 [=>............................] - ETA: 5:40 - loss: 0.3628 - acc: 0.9062
3/25 [==>...........................] - ETA: 5:21 - loss: 0.3862 - acc: 0.8750
4/25 [===>..........................] - ETA: 5:15 - loss: 0.3624 - acc: 0.8750
5/25 [=====>........................] - ETA: 4:57 - loss: 0.3307 - acc: 0.9000
6/25 [======>.......................] - ETA: 4:41 - loss: 0.3185 - acc: 0.9062
7/25 [=======>......................] - ETA: 3:59 - loss: 0.4027 - acc: 0.8800
25/25 [==============================] - 459s 18s/step - loss: 0.8366 - acc: 0.7225 - val_loss: 0.4027 - val_acc: 0.8800
Epoch 2/5
1/25 [>.............................] - ETA: 5:49 - loss: 0.2977 - acc: 0.8750
2/25 [=>............................] - ETA: 5:33 - loss: 0.2384 - acc: 0.9375
3/25 [==>...........................] - ETA: 5:18 - loss: 0.2150 - acc: 0.9583
4/25 [===>..........................] - ETA: 5:03 - loss: 0.2440 - acc: 0.9375
5/25 [=====>........................] - ETA: 4:48 - loss: 0.2576 - acc: 0.9250
6/25 [======>.......................] - ETA: 4:34 - loss: 0.2808 - acc: 0.8958
7/25 [=======>......................] - ETA: 4:20 - loss: 0.2706 - acc: 0.9107
8/25 [========>.....................] - ETA: 4:05 - loss: 0.2600 - acc: 0.9141
9/25 [=========>....................] - ETA: 3:51 - loss: 0.2458 - acc: 0.9236
10/25 [===========>..................] - ETA: 3:36 - loss: 0.2523 - acc: 0.9312
11/25 [============>.................] - ETA: 3:22 - loss: 0.2505 - acc: 0.9318
12/25 [=============>................] - ETA: 3:09 - loss: 0.2468 - acc: 0.9375
13/25 [==============>...............] - ETA: 2:56 - loss: 0.2361 - acc: 0.9423
14/25 [===============>..............] - ETA: 2:41 - loss: 0.2375 - acc: 0.9420
15/25 [=================>............] - ETA: 2:28 - loss: 0.2371 - acc: 0.9458
16/25 [==================>...........] - ETA: 2:14 - loss: 0.2274 - acc: 0.9492
17/25 [===================>..........] - ETA: 2:00 - loss: 0.2229 - acc: 0.9522
18/25 [====================>.........] - ETA: 1:45 - loss: 0.2139 - acc: 0.9549
19/25 [=====================>........] - ETA: 1:30 - loss: 0.2122 - acc: 0.9539
20/25 [=======================>......] - ETA: 1:15 - loss: 0.2084 - acc: 0.9563
21/25 [========================>.....] - ETA: 1:00 - loss: 0.2046 - acc: 0.9583
22/25 [=========================>....] - ETA: 45s - loss: 0.2091 - acc: 0.9489
23/25 [==========================>...] - ETA: 30s - loss: 0.2055 - acc: 0.9511
24/25 [===========================>..] - ETA: 15s - loss: 0.2005 - acc: 0.9531Epoch 1/5
1/25 [>.............................] - ETA: 6:42 - loss: 0.1403 - acc: 1.0000
2/25 [=>............................] - ETA: 6:10 - loss: 0.1468 - acc: 0.9688
3/25 [==>...........................] - ETA: 5:48 - loss: 0.2241 - acc: 0.9167
4/25 [===>..........................] - ETA: 5:29 - loss: 0.2017 - acc: 0.9375
5/25 [=====>........................] - ETA: 5:09 - loss: 0.1962 - acc: 0.9250
6/25 [======>.......................] - ETA: 4:50 - loss: 0.1872 - acc: 0.9375
7/25 [=======>......................] - ETA: 4:06 - loss: 0.1914 - acc: 0.9400
25/25 [==============================] - 475s 19s/step - loss: 0.1960 - acc: 0.9550 - val_loss: 0.1914 - val_acc: 0.9400
Epoch 3/5
1/25 [>.............................] - ETA: 5:50 - loss: 0.2164 - acc: 0.9375
2/25 [=>............................] - ETA: 5:34 - loss: 0.1589 - acc: 0.9688
3/25 [==>...........................] - ETA: 5:20 - loss: 0.1342 - acc: 0.9792
4/25 [===>..........................] - ETA: 5:05 - loss: 0.1308 - acc: 0.9844
5/25 [=====>........................] - ETA: 4:51 - loss: 0.1385 - acc: 0.9750
6/25 [======>.......................] - ETA: 4:37 - loss: 0.1266 - acc: 0.9792
7/25 [=======>......................] - ETA: 4:23 - loss: 0.1370 - acc: 0.9732
8/25 [========>.....................] - ETA: 4:09 - loss: 0.1324 - acc: 0.9766
9/25 [=========>....................] - ETA: 3:54 - loss: 0.1235 - acc: 0.9792
10/25 [===========>..................] - ETA: 3:40 - loss: 0.1169 - acc: 0.9812
11/25 [============>.................] - ETA: 3:26 - loss: 0.1161 - acc: 0.9830
12/25 [=============>................] - ETA: 3:11 - loss: 0.1118 - acc: 0.9844
13/25 [==============>...............] - ETA: 2:56 - loss: 0.1084 - acc: 0.9856
14/25 [===============>..............] - ETA: 2:42 - loss: 0.1051 - acc: 0.9866
15/25 [=================>............] - ETA: 2:27 - loss: 0.1039 - acc: 0.9875
16/25 [==================>...........] - ETA: 2:12 - loss: 0.1010 - acc: 0.9883
17/25 [===================>..........] - ETA: 1:57 - loss: 0.1011 - acc: 0.9890
18/25 [====================>.........] - ETA: 1:43 - loss: 0.1008 - acc: 0.9896
19/25 [=====================>........] - ETA: 1:28 - loss: 0.0988 - acc: 0.9901
20/25 [=======================>......] - ETA: 1:13 - loss: 0.0960 - acc: 0.9906
21/25 [========================>.....] - ETA: 59s - loss: 0.0936 - acc: 0.9911
22/25 [=========================>....] - ETA: 44s - loss: 0.0913 - acc: 0.9915
23/25 [==========================>...] - ETA: 29s - loss: 0.0938 - acc: 0.9891
24/25 [===========================>..] - ETA: 14s - loss: 0.0919 - acc: 0.9896Epoch 1/5
1/25 [>.............................] - ETA: 6:25 - loss: 0.1734 - acc: 0.9375
2/25 [=>............................] - ETA: 5:55 - loss: 0.1461 - acc: 0.9375
3/25 [==>...........................] - ETA: 5:35 - loss: 0.2080 - acc: 0.8958
4/25 [===>..........................] - ETA: 5:18 - loss: 0.1843 - acc: 0.9219
5/25 [=====>........................] - ETA: 5:04 - loss: 0.1667 - acc: 0.9250
6/25 [======>.......................] - ETA: 4:48 - loss: 0.1599 - acc: 0.9271
7/25 [=======>......................] - ETA: 4:05 - loss: 0.1575 - acc: 0.9300
25/25 [==============================] - 467s 19s/step - loss: 0.0898 - acc: 0.9900 - val_loss: 0.1575 - val_acc: 0.9300
Epoch 4/5
1/25 [>.............................] - ETA: 6:11 - loss: 0.1034 - acc: 1.0000
2/25 [=>............................] - ETA: 5:50 - loss: 0.0808 - acc: 1.0000
3/25 [==>...........................] - ETA: 5:36 - loss: 0.0719 - acc: 1.0000
4/25 [===>..........................] - ETA: 5:31 - loss: 0.0739 - acc: 0.9844
5/25 [=====>........................] - ETA: 5:19 - loss: 0.0667 - acc: 0.9875
6/25 [======>.......................] - ETA: 5:02 - loss: 0.0652 - acc: 0.9896
7/25 [=======>......................] - ETA: 4:45 - loss: 0.0609 - acc: 0.9911
8/25 [========>.....................] - ETA: 4:29 - loss: 0.0631 - acc: 0.9922
9/25 [=========>....................] - ETA: 4:13 - loss: 0.0636 - acc: 0.9931
10/25 [===========>..................] - ETA: 3:58 - loss: 0.0607 - acc: 0.9937
11/25 [============>.................] - ETA: 3:44 - loss: 0.0611 - acc: 0.9943
12/25 [=============>................] - ETA: 3:29 - loss: 0.0587 - acc: 0.9948
13/25 [==============>...............] - ETA: 3:13 - loss: 0.0558 - acc: 0.9952
14/25 [===============>..............] - ETA: 2:57 - loss: 0.0545 - acc: 0.9955
15/25 [=================>............] - ETA: 2:41 - loss: 0.0551 - acc: 0.9958
16/25 [==================>...........] - ETA: 2:24 - loss: 0.0529 - acc: 0.9961
17/25 [===================>..........] - ETA: 2:08 - loss: 0.0541 - acc: 0.9963
18/25 [====================>.........] - ETA: 1:52 - loss: 0.0521 - acc: 0.9965
19/25 [=====================>........] - ETA: 1:36 - loss: 0.0502 - acc: 0.9967
20/25 [=======================>......] - ETA: 1:20 - loss: 0.0513 - acc: 0.9969
21/25 [========================>.....] - ETA: 1:04 - loss: 0.0513 - acc: 0.9970
22/25 [=========================>....] - ETA: 1:10 - loss: 0.0500 - acc: 0.9972
23/25 [==========================>...] - ETA: 46s - loss: 0.0504 - acc: 0.9973
24/25 [===========================>..] - ETA: 23s - loss: 0.0495 - acc: 0.9974
代码如下:
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications.vgg16 import VGG16, preprocess_input
import numpy as np
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
class TransferModel(object):
"""VGG迁移学习做5个类别图片识别
"""
def __init__(self):
# 初始化训练集和测试集的迭代器
self.train_generator = ImageDataGenerator(rescale=1.0 / 255.0,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
self.test_generator = ImageDataGenerator(rescale=1.0 / 255.0)
# 数据目录
self.train_dir = "./data/train"
self.test_dir = "./data/test"
# 定义输入数据的大小和批次大小
self.image_size = (224, 224)
self.batch_size = 16
# 初始化VGG基础模型,
self.base_model = VGG16(weights='imagenet', include_top=False)
self.label_dict = {
'0': 'elephants',
'1': 'flowers',
'2': 'horse'
}
def get_local_data(self):
"""读取本地的图片数据以及类别标签
:return:
"""
# 1、datagen.flow_from_directory
train_gen = self.train_generator.flow_from_directory(self.train_dir,
target_size=self.image_size,
batch_size=self.batch_size,
class_mode='binary',
shuffle=True)
test_gen = self.train_generator.flow_from_directory(self.test_dir,
target_size=self.image_size,
batch_size=self.batch_size,
class_mode='binary',
shuffle=True)
return train_gen, test_gen
def refine_base_model(self):
"""
修改VGG的模型
:return: 新的迁移学习模型
"""
# 1、获取VGG模型的输出,不包含原有模型的top结构
x = self.base_model.outputs[0]
x = tf.keras.layers.GlobalAveragePooling2D()(x)
# 两个全连接层
x = tf.keras.layers.Dense(1024, activation=tf.nn.relu)(x)
y_predict = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x)
transfer_model = tf.keras.models.Model(inputs=self.base_model.inputs, outputs=y_predict)
return transfer_model
def freeze_vgg_model(self):
"""
冻结VGG的前面卷积结构,不参与训练
:return:
"""
# 循环获取base_model当中的层
for layer in self.base_model.layers:
layer.trainable = False
return None
def compile(self, model):
"""
编译模型,指定优化器损失计算方式,准确率衡量
:return:
"""
model.compile(optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.sparse_categorical_crossentropy,
metrics=['accuracy'])
return None
def fit_generator(self, model, train_gen, test_gen):
"""进行模型训练
:param model:
:param train_gen:
:param test_gen:
:return:
"""
modelckpt = tf.keras.callbacks.ModelCheckpoint('./ckpt/transfer_{epoch:02d}-{acc:.2f}.h5',
monitor='accuracy',
save_best_only=False,
save_weights_only=False,
mode='auto',
period=1)
h = model.fit_generator(train_gen, epochs=5, validation_data=test_gen, callbacks=[modelckpt])
k = h.history()
print('ooo')
return None
def predict(self, model):
"""预测输入图片的类别
:return:
"""
model.load_weights("./ckpt/transfer_01-0.82.h5")
# 读取图片处理图片数据,形状,数据归一化
image = tf.io.read_file("./data/test/dinosaurs/402.jpg")
image_decoded = tf.image.decode_jpeg(image)
image_resized = tf.image.resize(image_decoded, [224, 224]) / 255.0
img = tf.reshape(image_resized, (1, image_resized.shape[0], image_resized.shape[1], image_resized.shape[2]))
print("修改之后的形状:", img.shape)
# 3、输入数据做预测
y_predict = model.predict(img)
index = np.argmax(y_predict, axis=1)
print('=====', index)
print('-=-=-=', index[0])
print('-=-=-=', type(index[0]))
print('-=-=-=', type(str(index[0])))
print(self.label_dict[str(index[0])])
return None
if __name__ == '__main__':
tm = TransferModel()
train_gen, test_gen = tm.get_local_data()
print(train_gen, test_gen)
# 模型的compile和训练
model = tm.refine_base_model()
print(model.summary())
tm.freeze_vgg_model()
tm.compile(model)
tm.fit_generator(model, train_gen, test_gen)