zoukankan      html  css  js  c++  java
  • 《python深度学习》笔记---5.3-2、猫狗分类(使用预训练网络-实战)

    《python深度学习》笔记---5.3-2、猫狗分类(使用预训练网络-实战)

    一、总结

    一句话总结:

    【卷积就是特征提取】:从预训练网络训练猫狗分类,可以更加方便的理解卷积层就是特征提取
    【使用预训练网络效果非常好】:我们的验证精度达到了约90%,比上一节从头开始训练的小型模型效果要好得多。但从图 中也可以看出,虽然 dropout 比率相当大,但模型几乎从一开始就过拟合。这是因为本方法没有 使用数据增强,而数据增强对防止小型图像数据集的过拟合非常重要。

    1、引入vgg16已经训练好的模型?

    from tensorflow.keras.applications import VGG16
    conv_base = VGG16(weights='imagenet',include_top=False,input_shape=(150, 150, 3))
    # 把vgg模型弄过来
    conv_base = VGG16(weights='imagenet',    
                      # include_top=False表示不包含dense层
                      include_top=False,                   
                      input_shape=(150, 150, 3))
    
    这里向构造函数中传入了三个参数。
    
    ‰ weights 指定模型初始化的权重检查点。
    ‰ include_top 指定模型最后是否包含密集连接分类器。默认情况下,这个密集连接分类器对应于ImageNet 的 1000 个类别。因为我们打算使用自己的密集连接分类器(只有 两个类别:cat 和 dog),所以不需要包含它。 
    ‰ input_shape 是输入到网络中的图像张量的形状。这个参数完全是可选的,如果不传 入这个参数,那么网络能够处理任意形状的输入。

    2、利用预训练好的VGG16抽取训练集、验证集和测试集的特征?

    【主要就是VGG16的predict方法】:features_batch = conv_base.predict(inputs_batch)
    '''
    directory:目录
    sample_count:样本数
    '''
    def extract_features(directory, sample_count):
        # 初始化 features
        features = np.zeros(shape=(sample_count, 4, 4, 512))      
        # 初始化 labels
        labels = np.zeros(shape=(sample_count))
        # 图像增强()
        generator = datagen.flow_from_directory(         
            directory,          
            target_size=(150, 150),          
            batch_size=batch_size,          
            class_mode='binary')     
        i = 0     
        for inputs_batch, labels_batch in generator: 
            # 调用 conv_base 模型的 predict 方法来从这些图像中提取特征。
            features_batch = conv_base.predict(inputs_batch)         
            # 切片依次找到features和labels
            features[i * batch_size : (i + 1) * batch_size] = features_batch          
            labels[i * batch_size : (i + 1) * batch_size] = labels_batch         
            i += 1
            # 如果所有的样本弄完了,就终止循环
            if i * batch_size >= sample_count: 
                # 注意,这些生成器在循环中不断 生成数据,所以你必须在读取完 所有图像后终止循环
                break       
        return features, labels 
    train_features, train_labels = extract_features(train_dir, 2000)  
    validation_features, validation_labels = extract_features(validation_dir, 1000)  
    test_features, test_labels = extract_features(test_dir, 1000)

    3、预训练好的VGG16后面接dense层实例?

    其实就是把vgg16提取好的特征放到作为输入数据放到dense网络里面就好
    model = models.Sequential() 
    model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512)) 
    model.add(layers.Dropout(0.5)) 
    model.add(layers.Dense(1, activation='sigmoid')) 
    model.compile(optimizer=optimizers.RMSprop(lr=2e-5),               
                  loss='binary_crossentropy',               
                  metrics=['acc']) 
    history = model.fit(train_features, train_labels,                     
                        epochs=30,                     
                        batch_size=20,                     
                        validation_data=(validation_features, validation_labels)) 

    二、5.3-2、猫狗分类(使用预训练网络-实战)

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

    import pandas as pd
    import numpy as np
    import tensorflow as tf
    import matplotlib.pyplot as plt
    
    In [3]:
    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:UsersFan Renyi.kerasmodelsvgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
    

    这里向构造函数中传入了三个参数。

    ‰ weights 指定模型初始化的权重检查点。
    
    ‰ include_top 指定模型最后是否包含密集连接分类器。默认情况下,这个密集连接分类器对应于ImageNet 的 1000 个类别。因为我们打算使用自己的密集连接分类器(只有 两个类别:cat 和 dog),所以不需要包含它。 
    
    ‰ input_shape 是输入到网络中的图像张量的形状。这个参数完全是可选的,如果不传 入这个参数,那么网络能够处理任意形状的输入。

    1、 不使用数据增强的快速特征提取

    首先,运行 ImageDataGenerator 实例,将图像及其标签提取为Numpy 数组。我们需要 调用 conv_base 模型的 predict 方法来从这些图像中提取特征。

    In [1]:
    import os 
    from tensorflow.keras.preprocessing.image import ImageDataGenerator 
    
    In [4]:
    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 [5]:
    datagen = ImageDataGenerator(rescale=1./255)  
    batch_size = 20 
    
    In [12]:
    '''
    directory:目录
    sample_count:样本数
    '''
    def extract_features(directory, sample_count):
        # 初始化 features
        features = np.zeros(shape=(sample_count, 4, 4, 512))      
        # 初始化 labels
        labels = np.zeros(shape=(sample_count))
        # 图像增强()
        generator = datagen.flow_from_directory(         
            directory,          
            target_size=(150, 150),          
            batch_size=batch_size,          
            class_mode='binary')     
        i = 0     
        for inputs_batch, labels_batch in generator: 
            # 调用 conv_base 模型的 predict 方法来从这些图像中提取特征。
            features_batch = conv_base.predict(inputs_batch)         
            # 切片依次找到features和labels
            features[i * batch_size : (i + 1) * batch_size] = features_batch          
            labels[i * batch_size : (i + 1) * batch_size] = labels_batch         
            i += 1
            # 如果所有的样本弄完了,就终止循环
            if i * batch_size >= sample_count: 
                # 注意,这些生成器在循环中不断 生成数据,所以你必须在读取完 所有图像后终止循环
                break       
        return features, labels 
    
    In [15]:
    train_features, train_labels = extract_features(train_dir, 2000)  
    validation_features, validation_labels = extract_features(validation_dir, 1000)  
    test_features, test_labels = extract_features(test_dir, 1000)
    
    Found 2000 images belonging to 2 classes.
    Found 1000 images belonging to 2 classes.
    Found 1000 images belonging to 2 classes.
    
    In [17]:
    print(train_features.shape)
    print(train_labels.shape)
    
    (2000, 4, 4, 512)
    (2000,)
    

    目前,提取的特征形状为 (samples, 4, 4, 512)。我们要将其输入到密集连接分类器中, 所以首先必须将其形状展平为 (samples, 8192)。

    In [18]:
    train_features = np.reshape(train_features, (2000, 4 * 4 * 512)) 
    validation_features = np.reshape(validation_features, (1000, 4 * 4 * 512)) 
    test_features = np.reshape(test_features, (1000, 4 * 4 * 512)) 
    
    In [19]:
    print(train_features.shape)
    
    (2000, 8192)
    

    现在你可以定义你的密集连接分类器(注意要使用dropout 正则化),并在刚刚保存的数据 和标签上训练这个分类器。

    In [20]:
    from tensorflow.keras import models 
    from tensorflow.keras import layers 
    from tensorflow.keras import optimizers 
    
    In [21]:
    model = models.Sequential() 
    model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512)) 
    model.add(layers.Dropout(0.5)) 
    model.add(layers.Dense(1, activation='sigmoid')) 
    
    In [22]:
    model.compile(optimizer=optimizers.RMSprop(lr=2e-5),               
                  loss='binary_crossentropy',               
                  metrics=['acc']) 
    
    In [23]:
    history = model.fit(train_features, train_labels,                     
                        epochs=30,                     
                        batch_size=20,                     
                        validation_data=(validation_features, validation_labels)) 
    
    Epoch 1/30
    100/100 [==============================] - 1s 5ms/step - loss: 0.5869 - acc: 0.6830 - val_loss: 0.4461 - val_acc: 0.8280
    Epoch 2/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.4259 - acc: 0.8145 - val_loss: 0.3650 - val_acc: 0.8550
    Epoch 3/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.3570 - acc: 0.8530 - val_loss: 0.3341 - val_acc: 0.8670
    Epoch 4/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.3124 - acc: 0.8780 - val_loss: 0.3015 - val_acc: 0.8750
    Epoch 5/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.2856 - acc: 0.8885 - val_loss: 0.2838 - val_acc: 0.8840
    Epoch 6/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.2666 - acc: 0.8960 - val_loss: 0.2731 - val_acc: 0.8880
    Epoch 7/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.2477 - acc: 0.9030 - val_loss: 0.2646 - val_acc: 0.8910
    Epoch 8/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.2388 - acc: 0.9080 - val_loss: 0.2625 - val_acc: 0.8920
    Epoch 9/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.2251 - acc: 0.9130 - val_loss: 0.2534 - val_acc: 0.8960
    Epoch 10/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.2059 - acc: 0.9255 - val_loss: 0.2513 - val_acc: 0.8970
    Epoch 11/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1988 - acc: 0.9265 - val_loss: 0.2598 - val_acc: 0.8920
    Epoch 12/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1903 - acc: 0.9320 - val_loss: 0.2458 - val_acc: 0.8990
    Epoch 13/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1818 - acc: 0.9335 - val_loss: 0.2417 - val_acc: 0.9050
    Epoch 14/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1786 - acc: 0.9340 - val_loss: 0.2402 - val_acc: 0.9030
    Epoch 15/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1706 - acc: 0.9390 - val_loss: 0.2375 - val_acc: 0.9020
    Epoch 16/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1574 - acc: 0.9480 - val_loss: 0.2349 - val_acc: 0.9020
    Epoch 17/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1587 - acc: 0.9455 - val_loss: 0.2346 - val_acc: 0.9060
    Epoch 18/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1448 - acc: 0.9500 - val_loss: 0.2474 - val_acc: 0.9000
    Epoch 19/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1411 - acc: 0.9485 - val_loss: 0.2345 - val_acc: 0.9010
    Epoch 20/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1383 - acc: 0.9510 - val_loss: 0.2326 - val_acc: 0.9030
    Epoch 21/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1313 - acc: 0.9570 - val_loss: 0.2412 - val_acc: 0.9010
    Epoch 22/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1262 - acc: 0.9600 - val_loss: 0.2337 - val_acc: 0.9040
    Epoch 23/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1213 - acc: 0.9600 - val_loss: 0.2347 - val_acc: 0.9040
    Epoch 24/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1164 - acc: 0.9615 - val_loss: 0.2337 - val_acc: 0.9020
    Epoch 25/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1124 - acc: 0.9630 - val_loss: 0.2342 - val_acc: 0.9040
    Epoch 26/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1033 - acc: 0.9650 - val_loss: 0.2321 - val_acc: 0.9070
    Epoch 27/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.1029 - acc: 0.9685 - val_loss: 0.2391 - val_acc: 0.9040
    Epoch 28/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.0988 - acc: 0.9670 - val_loss: 0.2335 - val_acc: 0.9090
    Epoch 29/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.0935 - acc: 0.9720 - val_loss: 0.2416 - val_acc: 0.9030
    Epoch 30/30
    100/100 [==============================] - 0s 4ms/step - loss: 0.0933 - acc: 0.9730 - val_loss: 0.2348 - val_acc: 0.9080
    

    训练速度非常快,因为你只需处理两个 Dense 层。即使在CPU 上运行,每轮的时间也不 到一秒钟。

    训练期间的损失曲线和精度曲线

    In [26]:
    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()
    

    我们的验证精度达到了约90%,比上一节从头开始训练的小型模型效果要好得多。但从图 中也可以看出,虽然 dropout 比率相当大,但模型几乎从一开始就过拟合。这是因为本方法没有 使用数据增强,而数据增强对防止小型图像数据集的过拟合非常重要。

    根本原因的话其实就是 因为预训练的vgg16中训练了很多数据,而这些数据使准确率提供很正常

    In [ ]:
     
     
    我的旨在学过的东西不再忘记(主要使用艾宾浩斯遗忘曲线算法及其它智能学习复习算法)的偏公益性质的完全免费的编程视频学习网站: fanrenyi.com;有各种前端、后端、算法、大数据、人工智能等课程。
    博主25岁,前端后端算法大数据人工智能都有兴趣。
    大家有啥都可以加博主联系方式(qq404006308,微信fan404006308)互相交流。工作、生活、心境,可以互相启迪。
    聊技术,交朋友,修心境,qq404006308,微信fan404006308
    26岁,真心找女朋友,非诚勿扰,微信fan404006308,qq404006308
    人工智能群:939687837

    作者相关推荐

  • 相关阅读:
    毕业设计每日博客——第八周4
    毕业设计每日博客——第八周3
    毕业设计每日博客——第八周2
    毕业设计每日博客——第八周1
    毕业设计每日博客——第七周5
    毕业设计每日博客——第七周4
    毕业设计每日博客——第七周3
    毕业设计每日博客——第七周2
    毕业设计每日博客——第七周1
    毕业设计每日博客——第六周5
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/13798376.html
Copyright © 2011-2022 走看看