python深度学习笔记(二) 深度学习用于计算机视觉

一、卷积神经网络简介

首先展示一个简单的卷积神经网络,它是Conv2D层和MaxPooling2D层的堆叠。

实例化一个小型卷积神经网络:

from keras import layers
from keras import models

model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(28,28,1)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation='relu'))

 卷积神经网络接收形状为(image_heigut,image_width,image_channels)的输入张量(不包括批量维度)。

每个Conv2D层和MaxPooling2D层的输出都是一个形状为(height,width,channels)的3D张量。宽度和高度两个维度的尺寸会随着网络加深而变小。通道数量由传入Conv2D层的第一个参数所控制。

下一步是将最后的输出张量输入到一个密集链接分类器网络中,即Dense层的堆叠。这些分类器可以处理1D向量,而当前的输出是3D张量。因此需将3D输出展平为1D,然后在上面添加几个Dense层。

#在卷积网络上添加分类器

model.add(layers.Flatten())
model.add(layers.Dense(64,activation='relu'))
#将进行10类别分类,最后一层使用带10个输出的softmax激活
model.add(layers.Dense(10,activation='softmax'))

#在MNIST图像上训练卷积神经网络

from keras.dataset import mnist
from keras.utils import to_categorical

(train_images,train_labels),(test_images,test_labels)=mnist.load_data()

train_images = train_images.reshape((60000,28,28,1))
train_images = train_images.astype('float32')/255

trest_images = test_images.reshape((10000,28,28,1))
test_images = test_images.astype('float32')/255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['accuracy'])

model.fit(train_images,train_labels,epochs=5,batch_size=64)

1、卷积运算

密集连接层和卷积层的根本区别在于,Dense层从输入特征空间中学到的是全局模式,而卷积层学到的是局部模式。

        卷积神经网络学到的模式具有平移不变性 ( translation invariant)。卷积神经网络在图像右下角学到某个模式之后,它可以在任何地方识别这个模式,比如左上角。对于密集连接网络来说,如果模式出现在新的位置,它只能重新学习这个模式。这使得卷积神经网络在处理图像时可以高效利用数据( 因为视觉世界从根本上具有平移不变性 ),它只需要更少的训练样本就可以学到具有泛化能力的数据表示。

        卷积神经网络可以学到模式的空间层次结构 (spatial hierarchies of patters )。第一个卷积层将学习较小的局部模式( 比如边缘 ),第二个卷积层将学习由第一层特征组成的更大的模式,以此类推。这使得卷积神经网络可以有效地学习越来越复杂、越来越抽象的视觉概念 (因为视觉世界从根本上具有空间层次结构 )。

        对于包含两个空间轴(高度和宽度)和一个深度轴(也叫通道轴)的 3D 张量,其卷积也叫特征图 (feature map )。对于 RGB 图像,深度轴的维度大小等于 3,因为图像有 3 个颜色通道红色、绿色和蓝色。对于黑白图像(比如 MNIST 数字图像 ),深度等于1(表示灰度等级 )。卷积运算从输人特征图中提取图块,并对所有这些图块应用相同的变换,生成输出特征图 (outputfeature map )。该输出特征图仍是一个 3D 张量,具有宽度和高度,其深度可以任意取值,因为输出深度是层的参数,深度轴的不同通道不再像 RGB 输人那样代表特定颜色,而是代表过滤器(filter )。过滤器对输人数据的某一方面进行编码,比如,单个过滤器可以从更高层次编码这样个概念:“输入中包含一张脸。

卷积由以下两个关键参数所定义:

1、从输入中提取的图块尺寸: 这些图块的大小通常是 3x3或5x5。
2、 输出特征图的深度:卷积所计算的过滤器的数量。一般第一层的深度为 32,最后一层的
深度是 64。

注意,输出的宽度和高度可能与输入的宽度和高度不同。不同的原因可能有两点:

1、 边界效应,可以通过对输入特征图进行填充来抵消。

2、使用了步幅(stride )。

2、最大池化运算

        在卷积神经网络示例中,在每个 MaxPooling2D 层之后,特征图的尺寸都会减半。例如,在第一个MaxPooling2D 层之前,特征图的尺寸是 26x26,但最大池化运算将其减半为 13x 13。这就是最大池化的作用:对特征图进行下采样,与步进卷积类似
        最大池化是从输人特征图中提取窗口,并输出每个通道的最大值。它的概念与卷积类似但是最大池化使用硬编码的 max 张量运算对局部图块进行变换,而不是使用学到的线性变换(卷积核 )。最大池化与卷积的最大不同之处在于,最大池化通常使用 2x2 的窗口和步幅 2,其目的是将特征图下采样 2 倍。与此相对的是,卷积通常使用 3x3 窗口和步幅 1

        使用下采样的原因,一是减少需要处理的特征图的元素个数,二是通过让连续卷积层的观察窗口越来越大( 即窗口覆盖原始输人的比例越来越大 ),从而引入空间过滤器的层级结构

        最大池化不是实现这种下采样的唯一方法。还可以在前一个卷积层中使用步幅来实现。此外,还可以使用平均池化来代替最大池化,其方法是将每个局部输入图块变换为取该图块各通道的平均值,而不是最大值。但最大池化的效果往往比这些替代方法更好简而言之,原因在于特征中往往编码了某种模式或概念在特征图的不同位置是否存在 ( 因此得名特征图 )。而观察不同特征的最大值而不是平均值能够给出更多的信息。因此,最合理的子采样策略是首先生成密集的特征图(通过无步进的卷积 ),然后观察特征每个小图块上的最大激活而不是查看输入的稀疏窗口(通过步进卷积)或对输入图块取平均,因为后两种方法可能导致错过或淡化特征是否存在的信息。

二、在小型数据集上从头开始训练一个卷积神经网络

一个实例,讨论猫狗图像分类,数据集中包含 4000 张猫和狗的图像(2000张猫的图像,2000 张狗的图像 )。我们将 2000 张图像用于训练,1000 张用于验证,1000张用于测试。

解决这一问题的基本策略,即使用已有的少量数据从头开始训练一个新模型首先,在 2000 个训练样本上训练一个简单的小型卷积神经网络,不做任何正则化,为模型目标设定一个基准。这会得到 71% 的分类精度。此时主要的问题在于过拟合。然后,我们会介绍数据增强 (data augmentation ),它在计算机视觉领域是一种非常强大的降低过拟合的技术。使用数据增强之后,网络精度将提高到 82%。
将深度学习应用于小型数据集的另外两个重要技巧: 用预训练的网络做特征提取(得到的精度范围在 90%~96%),对预训练的网络进行微调(最终精度为 97%)。总而言之这三种策略一从头开始训练一个小型模型、使用预训练的网络做特征提取、对预训练的网络进行微调--构成了你的工具箱,未来可用于解决小型数据集的图像分类问题。

1、下载数据

用到的猫狗分类数据集可以从 https://www.kaggle.comc/dogs-vs-cats/data 下载原始数据集 。

3、构建网络

#将猫狗分类的小型卷积神经网络实例化

from keras import layers
from keras import models

model = models.Sequential()

model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))

model.add(layers.Flatten())
model.add(layers.Dense(512,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))

#配置模型用于训练
from keras import optimizers

model.compile(loss='binary_crossentropy',
                    optimizer=optimizers.RMSprop(lr=1e-4),
                    metrics=['acc'])

 构建一个小型卷积神经网络,卷积神经网络由Conv2D(使用relu激活)和MaxPooling2D层交替堆叠构成。

要处理更大的图像或更复杂的问题时,需要相应的增大网络,可以再加一个Conv2D+MaxPooling2D的组合。这样既可以增大网络容量,也可以进一步减小特征图的尺寸,使其在连接Flatten层时尺寸不会太大。

注意:网络中特征图的深度在逐渐增大(从32到128),而特征图的尺寸在逐渐减小。这几乎是所有卷积神经网络的模式。

因为面对的是一个二分类问题,所以网络最后一层是使用sigmoid激活的单一单元(大小为1的Dense层)。这个单元会对某个类别的概率进行编码。

编译时使用RMSprop优化器。因为网络最后一层是单一sigmoid单元,所以使用二元交叉熵作为损失函数。

4、数据预处理

将数据输入神经网络之前,应该将数据格式化为经过预处理的浮点数张量。所以步骤如下:

1、读取图像文件

2、将jpeg文件解码为RGB像素网格

3、将这些像素网格转换为浮点数张量

4、将像素值(0~255范围内)缩放到[0,1]区间

keras拥有自动完成这些步骤的工具。有一个图像处理辅助工具的模块,位于keras.preprocessing.image。它包含ImageDataGenerator类,可以快速创建python生成器,能够将硬盘上的图像文件自动转换为预处理好的张量批量。

#使用ImageDataGenerator从目录中读取图像
from keras.preprocessing.image import ImageDataGenerator

#将所有图像乘以1/255缩放
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)

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

validation_generator = test_datagen.flow_from_directory(
        validation_dir,
        target_size=(150,150),
        batch_size=20,  #每个批量中包含20个样本(批量大小)
        class_mode='binary')

Python生成器:

 python生成器是一个类似于迭代器的对象,一个可以和for..in运算符一起使用的对象。生成器是用yield运算符来构造的。

#生成器的例子,可以生成整数
def generator():
    i=0
    while True:
        i+=1
        yield i

for item in generator():
    print(item)
    if item > 4:
        break

 利用生成器,可以让模型对数据进行拟合。

可使用 fit_generator 方法来拟合,它在数据生成器上的效果和 fit 相同。它的第一个参数应该是一个 Python 生成器,可以不停地生成输入和目标组成的批量,比如 train_generator。因为数据是不断生成的,所以 Keras模型要知道每一轮需要从生成器中抽取多少个样本。这是 steps_per_epoch 参数的作用: 从生成器中抽取 steps_per_epoch 个批量后 (即运行了 steps_per_epoch 次梯度下降),拟合过程将进入下一个轮次。本例中,每个批量包含 20 个样本,所以读取完所有 2000 个样本需要 100个批量。

使用 fit_generator 时,可以传人一个 validation_data 参数,其作用和在 fit 方
法中类似。值得注意的是,这个参数可以是一个数据生成器,但也可以是 Numpy 数组组成的元组。如果向 validation_data 传人一个生成器,那么这个生成器应该能够不停地生成验证数据批量,因此还需要指定 validation_steps 参数,说明需要从验证生成器中抽取多少个批次用于评估。

#利用批量生成器拟合模型
history = model.fit_generator(
    train_generator,
    steps_per_epoch=100,
    epochs=30,
    validation_data=validation_generator,
    validation_steps=50)

#保存模型
model.save('cats_and_dogs_small_1.h5')

 绘制训练过程中模型在训练数据和验证数据上的损失和精度:

#绘制训练过程中的损失曲线和精度曲线
import matplotlib.pyplot as plt

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,'bo',label='Training acc')
plt.plot(epochs,val_acc,'b',label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

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

plt.show()

 从这些图像中都能看出过拟合的特征。训练精度随着时间线性增加,直到接近 100%,而验证精度则停留在 70%~72%。验证损失仅在 5 轮后就达到最小值,然后保持不变,而训练损失则直线性下降,直到接近于 0。
因为训练样本相对较少(2000 个 ),所以过拟合是必须要考虑的问题。前面已经介绍过几种降低过拟合的技巧,比如 dropout 和权重衰减(L2 正则化)。现在将使用一种针对于计算机视觉领域的新方法,在用深度学习模型处理图像时几乎都会用到这种方法,它就是数据增强

5、使用数据增强

过拟合的原因是学习样本太少,导致无法训练出能够泛化到新数据的模型。如果拥有无限的数据,那么模型能够观察到数据分布的所有内容,这样就永远不会过拟合。

数据增强是从现有的训练样本中生成更多的训练数据,其方法是利用多种能够生成可信图像的随机变换来增加(augment)样本。其目标是,模型在训练时不会两次查看完全相同的图像。这让模型能够观察到数据的更多内容,从而具有更好的泛化能力。
在Keras 中,这可以通过对 ImageDataGenerator 实例读取的图像执行多次随机变换来实现。

#利用ImageDataGenerator来设置数据增强
datagen = ImageDataGenerator(
    rotation_range=10,
    width_shift_range-0.2,
    height_shift_range-0.2,
    shear_range-0.2,
    zoom_range-0.2,
    horizontal_flip=True,
    fill_mode='nearest')

rotation_range是角度值(0~180),表示图像随机旋转的范围

width_shift和height_shift是图像在水平或垂直方向上平移的范围(相对于总宽度和总高度的比例) 

shear_range是随机错切变换的角度

zoom_range是图像随机缩放的范围

horizontal_flip是随机将一半图像水平翻转。如果没有水平不对称的假设(比如真实世界的图像),这种做法是有意义的

fill_mode是用于填充新创建像素的方法,这些新像素可能来自于旋转或宽度/高度平移。

#显示几个随机增强后的训练图像
from keras.preprocessing import image  
#图像预处理工具的模块

fnames = [os.path.join(train_cats_dir,fname) for
     fname in os.listdir(train_cats_dir)]

#选择一张图像进行增强
img_path = fnames[3]

#读取图像并调整大小
img = image.load_img(img_path,target_size=(150,150))

#将其转换为形状(150,150,3)的Numpy数组
x = image.img_to_array(img)

#将其形状改变为(1,150,150,3)
x = x.reshape((1,) + x.shape)

#生成随机变换后的图像批量。循环是无限的,需要在某个时刻终止循环
i=0
for batch in datagen.flow(x,batch_size=1)
    plt.figure(i)
    imgplot = plt.imshow(image.array_to_img(batch[0]))
    i+=1
    if i % 4 == 0:
        break

plt.show()

为了进一步降低过拟合,需要向模型中添加一个Dropout层,添加到密集连接器之前:

#定义一个包含dropout的新卷积神经网络
model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activaton='relu',input_shape=(150,150,3)))
model.add(layers.MaxPooling2D((2,2)))

model.add(layers.Conv2D(64,(3,3),activaton='relu'))
model.add(layers.MaxPooling2D((2,2)))

model.add(layers.Conv2D(128,(3,3),activaton='relu'))
model.add(layers.MaxPooling2D((2,2)))

model.add(layers.Conv2D(128,(3,3),activaton='relu'))
model.add(layers.MaxPooling2D((2,2)))

model.add(layers.Flatten())
model.add(layers.Dropout(0.5))

model.add(layers.Dense(512,activaton='relu'))
model.add(layers.Dense(1,activation='sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])

训练网络:

#利用数据增强生成器训练卷积神经网络
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)

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

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

validation_generator = train_datagen.flow_from_directory(
    validation_dir,
    target_size=(150,150),
    batch_size=32,
    class_mode='binary')

history = model.fit_generator(
    train_generator,
    steps_per_epoch=100,
    epochs=100,
    validation_data=validation_generator,
    validation_steps=50)

#保存模型
model.save('cats_and_dogs_small_2.h5')

三、使用预训练的卷积神经网络

使用预训练网络有两种办法:特征提取和微调模型。

1、特征提取

特征提取是使用之前网络学到的表示来从新样本中提取出有趣的特征。然后将这些特征输入一个新的分类器,从头开始训练。

用于图像分类的卷积神经网络包含两部分:首先是一系列池化层和卷积层,最后是一个密集连接分类器。第一部分叫作模型的卷积基(convolutional base)。对于卷积神经网络而言,特征提取就是取出之前训练好的网络的卷积基,在上面运行新数据,然后在输出上面训练一个新的分类器。

某个卷积层提取的表示的通用性(以及可复用性)取决于该层在模型中的深度。模型中更靠近底部的层提取的是局部的、高度通用的特征图(比如视觉边缘、颜色和纹理),而更靠近顶部的层提取的是更加抽象的概念 (如“猫耳朵”或“狗眼睛”)。 因此,如果新数据集与原始模型训练的数据集有很大差异那么最好只使用模型的前几层来做特征提取,而不是使用整个卷积基。

#将VGG16卷积基实例化
from keras.applications import VGG16

conv_base = VGG16(weights='imagenet',
                  include_top=False,
                  input_shape=(150,150,3))

这里向构造函数中传递了3个参数:

weights 指定模型初始化的权重检查点

include_top  指定模型最后是否包含密集连接分类器。

input_shape 是输入到网络中的图像张量的形状。

在特征上添加一个密集连接分类器,有两种方法:

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

保存数据在conv_base中的输出,然后将这些输出作为输入用于新模型。

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

#使用预训练的卷积基提取特征
import os
import numpy as np
from keras.preprocessing.image import ImageDataGenerator

base_dir = '/User/.../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')

datagen = ImageDataGenerator(rescale=1./255)
batch_size = 20

def extract_features(directory,sample_count):
    features = np.zeros(shape=(shape_count,4,4,512))
    labels = np.zeros(shape=(shape_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:
        features_batch = conv_base.predict(inputs_batch)
        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,2000)
test_features,test_labels = extract_features(test_dir,2000)

#提取的形状特征为(samoles,4,4,512),要将其输入到密集连接分类器中,首先必须将其形状展平为(samples,8192)
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))

定义并训练密集连接分类器

from keras import models
from keras import layers
from keras import optimizers

model = model.Sequential()
model.add(layers.Dense(256,activation='relu',input_dim=4*4*512))
#使用dropout正则化
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))

绘制结果:

import matplotlib.pyplot as plt

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,'bo',label='Training acc')
plt.plot(epochs,val_acc,'b',label='Validation acc')
plt.title('Training and Validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs,loss,'bo',label='Training loss')
plt.plot(epochs,val_loss,'bo',label='Validation loss')
plt.title('Training and Validation loss')
plt.legend()

plt.show()

2、使用数据增强的特征提取

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

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

#在卷积基上添加一个密集连接分类器
from keras import models
from keras import layers

model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
mpdel.add(layers.Dense(256,acyivation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))

 在编译和训练模型之前,一定要“冻结”卷积基。冻结( reeze)一个或多个层是指在训练过程中保持其权重不变。如果不这么做,那么卷积基之前学到的表示将会在训练过程中被修改。因为其上添加的 Dense 层是随机初始化的,所以非常大的权重更新将会在网络中传播,对之前学到的表示造成很大破坏。
在Keras 中,冻结网络的方法是将其 trainable 属性设为 False。

>>>conv_base.trainable = False

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

#利用冻结的卷积基端到端地训练模型
from keras.preprocessing.image import ImageDataGenerator
from 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,
        #将所有图像大小调整为(150,150)
        target_size=(150,150),
        batch_size=20,
        #因为使用了binary_crossentropy损失,所以需要用二进制标签
        class_mode='binary')


validatopn_generator = train_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'])

history = model.fit_generator(
      train_generator,
      steps_per_epoch=100,
      epochs=30,
      validation_data=validation_generator,
      validation_steps=50)

2、微调模型

另一种广泛使用的模型复用方法是模型微调 (fine-tuning),与特征提取互为补充。对于用于特征提取的冻结的模型基,微调是指将其顶部的几层“解冻”,并将这解冻的几层和新增加的部分(本例中是全连接分类器)联合训练(见图 5-19 )。之所以叫作微调,是因为它只是略微调整了所复用模型中更加抽象的表示,以便让这些表示与手头的问题更加相关。

训练期间通过网络传播的误差信号会特别大,微调的几层之前学到的表示都会被破坏。因此微调网络的步骤如下。
(1)在已经训练好的基网络(base network)上添加自定义网络
(2) 冻结基网络。
(3)训练所添加的部分。
(4)解冻基网络的一些层
(5)联合训练解冻的这些层和添加的部分
在做特征提取时已经完成了前三个步骤。继续进行第四步: 先解冻 conv_base,然后冻结其中的部分层。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值