- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我目前正在尝试了解如何重用 VGG19(或其他架构)以改进我的小型图像分类模型。我将图像(在本例中为绘画)分为 3 类(比方说,15、16 和 17 世纪的绘画)。我有一个相当小的数据集,每类 1800 个训练示例,验证集中每类 250 个。
我有以下实现:
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras import backend as K
from keras.callbacks import ModelCheckpoint
from keras.regularizers import l2, l1
from keras.models import load_model
# set proper image ordering for TensorFlow
K.set_image_dim_ordering('th')
batch_size = 32
# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1./255)
# this is a generator that will read pictures found in
# subfolers of 'data/train', and indefinitely generate
# batches of augmented image data
train_generator = train_datagen.flow_from_directory(
'C://keras//train_set_paintings//', # this is the target directory
target_size=(150, 150), # all images will be resized to 150x150
batch_size=batch_size,
class_mode='categorical')
# this is a similar generator, for validation data
validation_generator = test_datagen.flow_from_directory(
'C://keras//validation_set_paintings//',
target_size=(150, 150),
batch_size=batch_size,
class_mode='categorical')
model = Sequential()
model.add(Conv2D(16, (3, 3), input_shape=(3, 150, 150)))
model.add(Activation('relu')) # also tried LeakyRelu, no improvments
model.add(MaxPooling2D(pool_size=(2, 3), data_format="channels_first"))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 3), data_format="channels_first"))
model.add(Flatten())
model.add(Dense(64, kernel_regularizer=l2(.01)))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(3))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam', # also tried SGD, it doesn't perform as well as adam
metrics=['accuracy'])
fBestModel = 'best_model_final_paintings.h5'
best_model = ModelCheckpoint(fBestModel, verbose=0, save_best_only=True)
hist = model.fit_generator(
train_generator,
steps_per_epoch=2000 // batch_size,
epochs=100,
validation_data=validation_generator,
validation_steps=200 // batch_size,
callbacks=[best_model],
workers=8 # cpu generation is run in parallel to the gpu training
)
print("Maximum train accuracy:", max(hist.history["acc"]))
print("Maximum train accuracy on epoch:", hist.history["acc"].index(max(hist.history["acc"]))+1)
print("Maximum validation accuracy:", max(hist.history["val_acc"]))
print("Maximum validation accuracy on epoch:", hist.history["val_acc"].index(max(hist.history["val_acc"]))+1)
如果我使架构更深,如果我更严格地对其进行正则化,它要么会过度拟合,要么像疯了一样跳来跳去,甚至在某一时刻达到 100%:
我也尝试过使用 BatchNormalization,但是模型几乎没有学习,它在训练集上的准确率不超过 50%。尝试使用和不使用丢弃。
除了过度改变架构之外,我正在寻找其他改进模型的方法。我看到的选项之一是重用现有架构及其权重并将其插入到我的模型中。但我找不到任何真实的例子来说明如何去做。我主要关注这篇博文: https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html
它谈到了重用 VGG19 来提高准确性,但并没有真正解释它是如何完成的。还有其他我可以效仿的例子吗?我将如何使其适应我当前的实现?我找到了一个完整的模型架构,但无法在我的硬件上运行它,因此我正在寻找一种方法来重用已经训练好的带有权重的模型,然后根据我的问题对其进行调整。
此外,我不理解博客在 VGG 部分中谈到的“瓶颈功能”背后的概念。如果有人能解释一下,我们会很高兴。
最佳答案
你绝对应该试试 Transfer Learning (链接是“迁移学习 Keras”的第一个 Google 结果,有很多关于该主题的教程)。本质上,TL 是对具有新分类层的大型数据集(即最常见的 Imagenet)进行预训练的网络的微调。背后的想法是,您希望保留在网络较低层学习到的所有好的特征(因为您的图像很可能也具有这些特征),并且只在这些特征之上学习一个新的分类器。这往往很有效,特别是如果您的数据集较小,不允许从头开始对网络进行全面训练(这也比全面训练快得多)
请注意,有多种方法可以进行 TL(我鼓励您研究该主题以找到最适合您的方法)。在我的应用程序中,我只是使用从 Imagenet 公共(public)检查点获取的权重初始化网络,删除最后一层并从那里训练所有内容(使用足够低的学习率,否则你会弄乱你的低级功能实际上想保留)。这种方法允许数据扩充。
另一种方法是使用瓶颈。在这种情况下,瓶颈(在其他情况下也称为嵌入)是您的输入样本之一在网络中某个深度级别的内部表示。换句话说,当网络的输出在 N 层后停止时,您可以看到 N 级的瓶颈。为什么这有用?因为您可以使用预训练网络预先计算所有样本的瓶颈,然后仅模拟网络最后一层的训练,而无需实际重新计算网络的所有(昂贵的)部分直到瓶颈点。
假设您有一个具有以下结构的网络:
in -> A -> B -> C -> D -> E -> out
其中 in
和 out
是输入和输出层,另一个是您可能在网络中拥有的任何类型的层。假设您发现在某处发布了在 Imagenet 上预训练的网络检查点。 Imagenet 有 1000 个类,您不需要任何一个。因此,您将丢弃网络的最后一层(分类器)。然而,其他图层包含您要保留的功能。让 E
成为我们示例中的分类器层。
从您的数据集中获取样本,将它们提供给 in
并收集匹配的瓶颈值 作为层 D
的输出。您对数据集中的所有样本执行一次此操作。瓶颈集合是您将用于训练新分类器的新数据集。
您构建了一个具有以下结构的虚拟网络:
bottleneck_in -> E' -> out
您现在像往常一样训练这个网络,但不是从您的数据集中提供样本,而是从瓶颈数据集中提供匹配的瓶颈。请注意,这样做会保存从 A
到 D
的所有层的计算,但这样您就不能在训练期间应用任何数据扩充 (当然,您仍然可以构建瓶颈,但您将有大量数据要存储)。
最后,要构建您的最终分类器,您的网络架构将是
in -> A -> B -> C -> D -> E' -> out
权重 A
到 D
来自公共(public)检查点,权重 E'
来自您的训练。
关于python - 如何在 Keras 中重用 VGG19 进行图像分类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46150757/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!