keras dense 层是什么意思

keras dense 层是什么意思,第1张

Dense就是常用的全连接层,所实现的运算是output = activation(dot(input, kernel)+bias)。其中activation是逐元素计算的激活函数,kernel是本层的权值矩阵,bias为偏置向量,只有当use_bias=True才会添加。

一个稍微讲究一点的办法是,利用在大规模数据集上预训练好的网络。这样的网络在多数的计算机视觉问题上都能取得不错的特征,利用这样的特征可以让我们获得更高的准确率。

我们将使用vgg-16网络,该网络在ImageNet数据集上进行训练,这个模型我们之前提到过了。因为ImageNet数据集包含多种“猫”类和多种“狗”类,这个模型已经能够学习与我们这个数据集相关的特征了。事实上,简单的记录原来网络的输出而不用bottleneck特征就已经足够把我们的问题解决的不错了。不过我们这里讲的方法对其他的类似问题有更好的推广性,包括在ImageNet中没有出现的类别的分类问题。

VGG-16的网络结构如下:

我们的方法是这样的,我们将利用网络的卷积层部分,把全连接以上的部分抛掉。然后在我们的训练集和测试集上跑一遍,将得到的输出(即“bottleneck feature”,网络在全连接之前的最后一层激活的feature map)记录在两个numpy array里。然后我们基于记录下来的特征训练一个全连接网络。

我们将这些特征保存为离线形式,而不是将我们的全连接模型直接加到网络上并冻结之前的层参数进行训练的原因是处于计算效率的考虑。运行VGG网络的代价是非常高昂的,尤其是在CPU上运行,所以我们只想运行一次。这也是我们不进行数据提升的原因。

我们不再赘述如何搭建vgg-16网络了,这件事之前已经说过,在keras的example里也可以找到。但让我们看看如何记录bottleneck特征。

generator = datagen.flow_from_directory(

'data/train',

target_size=(150, 150),

batch_size=32,

class_mode=None, # this means our generator will only yield batches of data, no labels

shuffle=False) # our data will be in order, so all first 1000 images will be cats, then 1000 dogs

# the predict_generator method returns the output of a model, given

# a generator that yields batches of numpy data

bottleneck_features_train = model.predict_generator(generator, 2000)

# save the output as a Numpy array

np.save(open('bottleneck_features_train.npy', 'w'), bottleneck_features_train)

generator = datagen.flow_from_directory(

'data/validation',

target_size=(150, 150),

batch_size=32,

class_mode=None,

shuffle=False)

bottleneck_features_validation = model.predict_generator(generator, 800)

np.save(open('bottleneck_features_validation.npy', 'w'), bottleneck_features_validation)

记录完毕后我们可以将数据载入,用于训练我们的全连接网络:

train_data = np.load(open('bottleneck_features_train.npy'))

# the features were saved in order, so recreating the labels is easy

train_labels = np.array([0] * 1000 + [1] * 1000)

validation_data = np.load(open('bottleneck_features_validation.npy'))

validation_labels = np.array([0] * 400 + [1] * 400)

model = Sequential()

model.add(Flatten(input_shape=train_data.shape[1:]))

model.add(Dense(256, activation='relu'))

model.add(Dropout(0.5))

model.add(Dense(1, activation='sigmoid'))

model.compile(optimizer='rmsprop',

loss='binary_crossentropy',

metrics=['accuracy'])

model.fit(train_data, train_labels,

nb_epoch=50, batch_size=32,

validation_data=(validation_data, validation_labels))

model.save_weights('bottleneck_fc_model.h5')

因为特征的size很小,模型在CPU上跑的也会很快,大概1s一个epoch,最后我们的准确率是90%~91%,这么好的结果多半归功于预训练的vgg网络帮助我们提取特征。

下面是代码:

[python] view plain copy

import os

import h5py

import numpy as np

from keras.preprocessing.image import ImageDataGenerator

from keras.models import Sequential

from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D

from keras.layers import Activation, Dropout, Flatten, Dense

import sys

defaultencoding = 'utf-8'

if sys.getdefaultencoding() != defaultencoding:

reload(sys)

sys.setdefaultencoding(defaultencoding)

# path to the model weights file.

weights_path = '../weights/vgg16_weights.h5'

top_model_weights_path = 'bottleneck_fc_model.h5'

# dimensions of our images.

img_width, img_height = 150, 150

train_data_dir = '../data/train'

validation_data_dir = '../data/validation'

nb_train_samples = 2000

nb_validation_samples = 800

nb_epoch = 50

def save_bottlebeck_features():

datagen = ImageDataGenerator(rescale=1./255)

# build the VGG16 network

model = Sequential()

model.add(ZeroPadding2D((1, 1), input_shape=(3, img_width, img_height)))

model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))

model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))

model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))

model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))

model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))

model.add(ZeroPadding2D((1, 1)))

model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))

model.add(MaxPooling2D((2, 2), strides=(2, 2)))

# load the weights of the VGG16 networks

# (trained on ImageNet, won the ILSVRC competition in 2014)

# note: when there is a complete match between your model definition

# and your weight savefile, you can simply call model.load_weights(filename)

assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'

f = h5py.File(weights_path)

for k in range(f.attrs['nb_layers']):

if k >= len(model.layers):

# we don't look at the last (fully-connected) layers in the savefile

break

g = f['layer_{}'.format(k)]

weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]

model.layers[k].set_weights(weights)

f.close()

print('Model loaded.')

generator = datagen.flow_from_directory(

train_data_dir,

target_size=(img_width, img_height),

batch_size=32,

class_mode=None,

shuffle=False)

print('generator ok.')

bottleneck_features_train = model.predict_generator(generator, nb_train_samples)

print('predict ok.')

np.save(open('bottleneck_features_train.npy', 'wb'), bottleneck_features_train)

generator = datagen.flow_from_directory(

validation_data_dir,

target_size=(img_width, img_height),

batch_size=32,

class_mode=None,

shuffle=False)

bottleneck_features_validation = model.predict_generator(generator, nb_validation_samples)

np.save(open('bottleneck_features_validation.npy', 'wb'), bottleneck_features_validation)

print('save_bottlebeck_features ok')

def train_top_model():

train_data = np.load(open('bottleneck_features_train.npy'))

train_labels = np.array([0] * (nb_train_samples / 2) + [1] * (nb_train_samples / 2))

validation_data = np.load(open('bottleneck_features_validation.npy'))

validation_labels = np.array([0] * (nb_validation_samples / 2) + [1] * (nb_validation_samples / 2))

model = Sequential()

model.add(Flatten(input_shape=train_data.shape[1:]))

model.add(Dense(256, activation='relu'))

model.add(Dropout(0.5))

model.add(Dense(1, activation='sigmoid'))

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

model.fit(train_data, train_labels,

nb_epoch=nb_epoch, batch_size=32,

validation_data=(validation_data, validation_labels))

model.save_weights(top_model_weights_path)

print('train_top_model ok')

save_bottlebeck_features()

train_top_model()

  之前展示了tensorflow2.0的一个初级的实用例子作为开始,对比1.x版本 *** 作还是有好很多的。接下来也将继续从比较基础的层面去了解tf2.0的各种实现

  tensorflow2.0在上以keras去搭建网络,这种封装好的基础/高级api在使用上无疑更便捷,但在学习的过程中也不妨自己去实现一些功能,加深理解。

以实现最简单的全连接层和训练过程为例,

简单搭个网络:

我们可以用类去自定义Dense的功能,也是非常简单的

这一样来,就可以直接用自定义的类DenseLayer去替换keras的全连接层

对于实现分类的损失函数而言,也是简单粗暴的,对于标签的格式是one_hot的,用 tf.nn.softmax_cross_entropy_with_logits ,

反之 tf.nn.sparse_softmax_cross_entropy_with_logits ,本文自然用到了后者。

关于tf2.0,貌似 tf.GradientTape() 保留了下来,自定义梯度计算这一部分可以作为一个篇章去讲述,以后也会去探索

所以把单步训练和梯度更新过程写在一起

因为在loss_func的计算里包含了softmax,所以在最后一层不添加激活函数

参考上一篇文章,但也有不一样的地方,其中没用到测试集,只关注训练时loss的变化过程

最终可以看到loss是降得很快的

end.


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11940190.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存