一、总结

一句话总结:

其实就是把vgg16对应的conv_base像层一样放到Sequential中,然后对图片进行数据增强即可
model.add(conv_base)
from tensorflow.keras import models 
from tensorflow.keras import layers 
 
model = models.Sequential() 
model.add(conv_base) 
model.add(layers.Flatten()) 
model.add(layers.Dense(256, activation='relu')) 
model.add(layers.Dense(1, activation='sigmoid'))
model.summary() 

 

 

1、模型的行为和层类似?

向Sequential模型中添加一个模型(比如vgg16):所以你可以向 Sequential 模型中添加一个模型(比如 conv_base), 就像添加一个层一样。
from tensorflow.keras import models 
from tensorflow.keras import layers 
 
model = models.Sequential() 
model.add(conv_base) 
model.add(layers.Flatten()) 
model.add(layers.Dense(256, activation='relu')) 
model.add(layers.Dense(1, activation='sigmoid'))
model.summary() 

 

 

2、模型的行为和层类似?

向Sequential模型中添加一个模型(比如vgg16):所以你可以向 Sequential 模型中添加一个模型(比如 conv_base), 就像添加一个层一样。

 

 

3、在编译和训练模型之前,一定要“冻结”卷积基?

【冻结表示权重不变】:冻结(freeze)一个或多个层是指在训练 过程中保持其权重不变。
【不冻结会破坏预训练的网络】:如果不这么做,那么卷积基之前学到的表示将会在训练过程中被修改。 因为其上添加的 Dense 层是随机初始化的,所以非常大的权重更新将会在网络中传播,对之前 学到的表示造成很大破坏。

 

 

4、在 Keras 中,如何冻结网络?

【将其trainable属性设为False】:在 Keras 中,冻结网络的方法是将其 trainable 属性设为 False。
conv_base.trainable = False
>>> print('This is the number of trainable weights '          
    'before freezing the conv base:', len(model.trainable_weights)) 
This is the number of trainable weights before freezing the conv base: 30 
>>> conv_base.trainable = False 
>>> print('This is the number of trainable weights '           
    'after freezing the conv base:', len(model.trainable_weights)) 
This is the number of trainable weights after freezing the conv base: 4 

 

 

 

二、5.3-3、猫狗分类(使用预训练网络-数据增强的特征提取)

博客对应课程的视频位置:

 

import pandas as pd
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
In [2]:
from tensorflow.keras.applications import VGG16 

# 把vgg模型弄过来
conv_base = VGG16(weights='imagenet',    
                  # include_top=False表示不包含dense层
                  include_top=False,                   
                  input_shape=(150, 150, 3))
# C:\Users\Fan Renyi\.keras\models\vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5

扩展 conv_base 模型,然后在输入数据上端到端地运行模型。

模型的行为和层类似,所以你可以向 Sequential 模型中添加一个模型(比如 conv_base), 就像添加一个层一样。

In [11]:
import os 
base_dir = 'E:\\78_recorded_lesson\\001_course_github\\AI_dataSet\\dogs-vs-cats\\cats_and_dogs_small'
train_dir = os.path.join(base_dir, 'train')  
validation_dir = os.path.join(base_dir, 'validation')  
test_dir = os.path.join(base_dir, 'test') 
In [4]:
from tensorflow.keras import models 
from tensorflow.keras import layers 
 
model = models.Sequential() 
model.add(conv_base) 
model.add(layers.Flatten()) 
model.add(layers.Dense(256, activation='relu')) 
model.add(layers.Dense(1, activation='sigmoid'))
model.summary() 
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
vgg16 (Functional)           (None, 4, 4, 512)         14714688  
_________________________________________________________________
flatten (Flatten)            (None, 8192)              0         
_________________________________________________________________
dense (Dense)                (None, 256)               2097408   
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 257       
=================================================================
Total params: 16,812,353
Trainable params: 16,812,353
Non-trainable params: 0
_________________________________________________________________

如你所见,VGG16 的卷积基有 14 714 688 个参数,非常多。在其上添加的分类器有 200 万 个参数。

冻结卷积层

In [5]:
print('This is the number of trainable weights before freezing the conv base:', len(model.trainable_weights)) 
This is the number of trainable weights before freezing the conv base: 30
In [6]:
conv_base.trainable = False 
In [7]:
print('This is the number of trainable weights after freezing the conv base:', len(model.trainable_weights)) 
This is the number of trainable weights after freezing the conv base: 4

如此设置之后,只有添加的两个 Dense 层的权重才会被训练。总共有4 个权重张量,每层 2 个(主权重矩阵和偏置向量)。注意,为了让这些修改生效,你必须先编译模型。如果在编译 之后修改了权重的 trainable 属性,那么应该重新编译模型,否则这些修改将被忽略。

3、利用冻结的卷积基端到端地训练模型

In [14]:
from tensorflow.keras.preprocessing.image import ImageDataGenerator 
from tensorflow.keras import optimizers 

train_datagen = ImageDataGenerator(       
    rescale=1./255,       
    rotation_range=40,       
    width_shift_range=0.2,       
    height_shift_range=0.2,       
    shear_range=0.2,       
    zoom_range=0.2,       
    horizontal_flip=True,       
    fill_mode='nearest')

# 注意,不能增强验证数据
test_datagen = ImageDataGenerator(rescale=1./255) 

train_generator = train_datagen.flow_from_directory(         
    train_dir, # 目标目录
    target_size=(150, 150), # 将所有图像的大小调整为 150×150
    batch_size=20,         
    class_mode='binary') # 因为使用了binary_crossentropy 损失,所以需要用二进制标签

validation_generator = test_datagen.flow_from_directory(         
    validation_dir,         
    target_size=(150, 150),         
    batch_size=20,         
    class_mode='binary') 

model.compile(loss='binary_crossentropy',               
              optimizer=optimizers.RMSprop(lr=2e-5),               
              metrics=['acc'])
Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
In [15]:
history = model.fit(       
    train_generator,       
    steps_per_epoch=100,       
    epochs=130,       
    validation_data=validation_generator,       
    validation_steps=50) 
Epoch 1/130
100/100 [==============================] - 19s 192ms/step - loss: 0.2739 - acc: 0.8880 - val_loss: 0.2376 - val_acc: 0.9030
Epoch 2/130
100/100 [==============================] - 19s 191ms/step - loss: 0.2712 - acc: 0.8870 - val_loss: 0.2447 - val_acc: 0.8960
Epoch 3/130
100/100 [==============================] - 20s 201ms/step - loss: 0.2732 - acc: 0.8870 - val_loss: 0.2383 - val_acc: 0.8980
Epoch 4/130
100/100 [==============================] - 20s 201ms/step - loss: 0.2765 - acc: 0.8775 - val_loss: 0.2384 - val_acc: 0.9000
Epoch 5/130
100/100 [==============================] - 21s 206ms/step - loss: 0.2956 - acc: 0.8740 - val_loss: 0.2488 - val_acc: 0.8950
Epoch 6/130
100/100 [==============================] - 21s 213ms/step - loss: 0.2715 - acc: 0.8845 - val_loss: 0.2375 - val_acc: 0.9050
Epoch 7/130
100/100 [==============================] - 20s 201ms/step - loss: 0.2795 - acc: 0.8735 - val_loss: 0.2405 - val_acc: 0.9000
Epoch 8/130
100/100 [==============================] - 20s 204ms/step - loss: 0.2739 - acc: 0.8875 - val_loss: 0.2377 - val_acc: 0.9010
Epoch 9/130
100/100 [==============================] - 21s 211ms/step - loss: 0.2802 - acc: 0.8750 - val_loss: 0.2431 - val_acc: 0.8990
......
Epoch 114/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2238 - acc: 0.9070 - val_loss: 0.2567 - val_acc: 0.8960
Epoch 115/130
100/100 [==============================] - 17s 173ms/step - loss: 0.2203 - acc: 0.9060 - val_loss: 0.2550 - val_acc: 0.9010
Epoch 116/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2187 - acc: 0.9085 - val_loss: 0.2510 - val_acc: 0.9010
Epoch 117/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2288 - acc: 0.9015 - val_loss: 0.2504 - val_acc: 0.9040
Epoch 118/130
100/100 [==============================] - 17s 173ms/step - loss: 0.2015 - acc: 0.9225 - val_loss: 0.2518 - val_acc: 0.9020
Epoch 119/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2242 - acc: 0.9020 - val_loss: 0.2497 - val_acc: 0.9030
Epoch 120/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2066 - acc: 0.9125 - val_loss: 0.2600 - val_acc: 0.8990
Epoch 121/130
100/100 [==============================] - 17s 173ms/step - loss: 0.2248 - acc: 0.9075 - val_loss: 0.2518 - val_acc: 0.9030
Epoch 122/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2062 - acc: 0.9175 - val_loss: 0.2630 - val_acc: 0.9000
Epoch 123/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2259 - acc: 0.9055 - val_loss: 0.2500 - val_acc: 0.9030
Epoch 124/130
100/100 [==============================] - 17s 173ms/step - loss: 0.2108 - acc: 0.9150 - val_loss: 0.2533 - val_acc: 0.8970
Epoch 125/130
100/100 [==============================] - 17s 173ms/step - loss: 0.2185 - acc: 0.9075 - val_loss: 0.2602 - val_acc: 0.8980
Epoch 126/130
100/100 [==============================] - 17s 173ms/step - loss: 0.2157 - acc: 0.9110 - val_loss: 0.2636 - val_acc: 0.8980
Epoch 127/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2096 - acc: 0.9100 - val_loss: 0.2523 - val_acc: 0.9020
Epoch 128/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2149 - acc: 0.9085 - val_loss: 0.2585 - val_acc: 0.9010
Epoch 129/130
100/100 [==============================] - 17s 174ms/step - loss: 0.2131 - acc: 0.9100 - val_loss: 0.2516 - val_acc: 0.9020
Epoch 130/130
100/100 [==============================] - 17s 173ms/step - loss: 0.2318 - acc: 0.9040 - val_loss: 0.2485 - val_acc: 0.8980
In [16]:
acc = history.history['acc'] 
val_acc = history.history['val_acc'] 
loss = history.history['loss'] 
val_loss = history.history['val_loss'] 

epochs = range(1, len(acc) + 1) 

plt.plot(epochs, acc, 'b--', label='Training acc') 
plt.plot(epochs, val_acc, 'r-', label='Validation acc') 
plt.title('Training and validation accuracy') 
plt.legend() 

plt.figure() 

plt.plot(epochs, loss, 'b--', label='Training loss') 
plt.plot(epochs, val_loss, 'r-', label='Validation loss') 
plt.title('Training and validation loss') 
plt.legend() 

plt.show()
《python深度学习》笔记---5.3-3、猫狗分类(使用预训练网络-数据增强的特征提取)
《python深度学习》笔记---5.3-3、猫狗分类(使用预训练网络-数据增强的特征提取)
In [ ]: