【问题标题】:keras stuck during optimizationkeras 在优化期间卡住了
【发布时间】:2016-12-11 00:55:57
【问题描述】:

在 CIFAR10 上尝试了 Keras 示例后,我决定尝试更大的东西:Tiny Imagenet 数据集上的类似 VGG 的网络。这是 ImageNet 数据集的子集,包含 200 个类(而不是 1000 个)和 100K 图像缩小到 64x64。

我从文件 vgg_like_convnet.py here 中得到了类 VGG 模型。不幸的是,事情的进展非常像here,只是这次改变学习率或将 TH 换成 TF 并没有帮助。既不改变优化器(见下面的代码)。

准确度基本上停留在 0.005,正如它所指出的,这是您对 200 个类的完全随机答案的期望。更糟糕的是,如果由于权重 init 的侥幸而从 0.007 开始,它将迅速收敛到 0.005 并在任何后续 epoch 中牢牢保持在那里。

Keras 代码(TH 版)如下:

from __future__ import print_function
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras.regularizers import l2, activity_l2, l1, activity_l1
from keras.optimizers import SGD, Adam, Adagrad, Adadelta
from keras.utils import np_utils
import numpy as np
import cPickle as pickle

# seed = 7
# np.random.seed(seed)

batch_size = 64
nb_classes = 200
nb_epoch = 30

# input image dimensions
img_rows, img_cols = 64, 64
# the tiny image net images are RGB
img_channels = 3

# Load the train dataset for TH
print('Load training data')
X_train=pickle.load(open('xtrain_shu_th.p','rb')) # np.zeros((100000,3,64,64)).astype('uint8')
y_train=pickle.load(open('ytrain_shu_th.p','rb')) # np.zeros((100000,1)).astype('uint8')

# Load the test dataset for TH
print('Load validation data')
X_test=pickle.load(open('xtest_th.p','rb')) # np.zeros((10000,3,64,64)).astype('uint8')
y_test=pickle.load(open('ytest_th.p','rb')) # np.zeros((10000,1)).astype('uint8')

# the data, shuffled and split between train and test sets
# (X_train, y_train), (X_test, y_test) = cifar10.load_data()
print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')

# convert class vectors to binary class matrices
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)

model = Sequential()

model.add(ZeroPadding2D((1,1),input_shape=(3,64,64)))
model.add(Convolution2D(64, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(64, 3, 3, activation='relu',))
model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(128, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_6'].values()))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(128, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_8'].values()))
model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_11'].values()))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_13'].values()))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_15'].values()))
model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_18'].values()))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_20'].values()))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))#,weights=pretrained_weights['layer_22'].values()))
model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))

model.add(Flatten())
model.add(Dense(4096))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(4096))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(200, activation='softmax'))

# let's train the model using SGD + momentum (how original).

opt = SGD(lr=0.0001, decay=1e-6, momentum=0.7, nesterov=True)
# opt= Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-08, decay=0.0)
# opt = Adadelta(lr=1.0, rho=0.95, epsilon=1e-08, decay=0.0)
# opt = Adagrad(lr=0.01, epsilon=1e-08, decay=0.0)
model.compile(loss='categorical_crossentropy',
              optimizer=opt,
              metrics=['accuracy'])

X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255

print('Optimization....')
model.fit(X_train, Y_train,
          batch_size=batch_size,
          nb_epoch=nb_epoch,
          validation_data=(X_test, Y_test),
          shuffle=True)

# Save the resulting model
model.save('model.h5')

Tiny Imagenet 数据集包含我使用 djpeg 转换为 PPM 的 JPEG 图像。然后,我创建了一个大型二进制文件,其中包含每个图像的类标签(1 字节),后跟(64x64x3 字节)。

从 Keras 读取这个文件非常慢。所以(我对 Python 很陌生,对你来说可能听起来很愚蠢),我决定初始化一个 4D Numpy 数组 (100000,3,64,64) (对于 TH,对于 TF,(100000,64,64,3) ) 与数据集并腌制它。现在,当我运行上面的代码时,将数据集加载到数组中需要大约 40 秒。

我什至使用下面的代码检查了腌制数组是否包含正确顺序的数据:

import numpy as np
import cPickle as pickle

print("Reading data")
pix=pickle.load(open('xtrain_th.p','rb'))
print("Done")

img=67857

f=open('img'+str(img)+'.ppm','wb')
f.write('P6\n64 64\n255\n')

for y in range(0,64):
    for x in range(0,64):
        f.write(chr(pix[img][0][y][x]))
        f.write(chr(pix[img][1][y][x]))
        f.write(chr(pix[img][2][y][x]))
f.close()

这将从数据集中提取 PPM 图像。

最后,我注意到训练数据集过于有序(即前 500 张图像都属于 0 类,后 500 张图像都属于 1 类,等等)

所以我用下面的代码对它们进行了洗牌:

# Dataset preparation for Theano backend
import cPickle as pickle
import numpy as np
import random as rnd

n=100000

print('Load training data')
X_train=pickle.load(open('xtrain_th.p','rb')) # np.zeros((100000,3,64,64)).astype('uint8')
y_train=pickle.load(open('ytrain_th.p','rb')) # np.zeros((100000,1)).astype('uint8')

tmpa=np.zeros((3,64,64)).astype('uint8')

# Shuffle the data
print('Shuffling training data')
for _ in range(0,n):
    i=rnd.randrange(n)
    j=rnd.randrange(n)
    tmpa=X_train[i]
    X_train[i]=X_train[j];
    X_train[j]=tmpa
    tmp=y_train[i][0]
    y_train[i][0]=y_train[j][0]
    y_train[j][0]=tmp

print 'Pickle dump'
pickle.dump(X_train,open('xtrain_shu_th.p','wb'))
pickle.dump(y_train,open('ytrain_shu_th.p','wb'))

没有任何帮助。我没想到第一次尝试时的准确率是 99%,但至少有一些移动,然后是平稳的。

我想试试 TFLearn,但几天前我查看时发现它有一个待处理的错误。

有什么想法吗?提前致谢

【问题讨论】:

  • 我实际上可以在 Keras 代码中看到一个问题:从一个 64x64 的小图像开始,在到达密集层之前,maxpools 将其降到几乎没有...... ..
  • 我从文件 vgg16_keras.py 中获取了网络,而不是 vgg_like_convnet.py。后者有 5 个最大池阶段,每个阶段将分辨率每侧降低 2。由于图像分辨率从 64x64 开始,因此在密集层之前它仅达到 2x2。这似乎太小了。所以我削减了几个 maxpool 层并细化了网络。现在密集层之前的层是 8x8(类似于 VGG 中的 7x7),但没有区别:保持在 0.005 精度。更改优化器会使起点有所不同,但最终结果完全相同:5.298 和 acc=1/200
  • 您确定您的训练数据匹配吗?即正确的img的正确标签。图像格式是否正确。 IE你能画出来吗?通常,这些或优化器是精度非常差的问题。
  • 是的,我考虑过贴错标签。我修改了上面的程序,它读取预洗牌的数据集以读取和打印标签以及生成 PPM 图像。然后,我目视检查它是否与原始数据集中的几个数据点的相同图像和标签匹配。不是结论性的,但有些东西。至于绘图,我不知道该怎么做,我需要研究一下。我现在将从一个极简的网络开始,然后尝试发展它。
  • 制作了一个极简网络(即与 CIFAR10 Keras 示例相同,但有 200 个输出)和完全相同的问题。可能在 0.005 附近有点振荡。我完全不知道,我最好的猜测是数据集已经磨损但不知道是什么

标签: machine-learning deep-learning keras conv-neural-network


【解决方案1】:

您可以使用 keras 模型 API (https://keras.io/models/model/#fit) 的内置 shuffle。只需将 shuffle 参数设置为 true。您可以进行批量洗牌和全局洗牌。默认为全局随机播放。

需要注意的一点是,适合的验证拆分是在洗牌发生之前完成的。因此,如果您也想改组您的验证数据,我建议您使用:sklearn.utils.shuffle。 (http://scikit-learn.org/stable/modules/generated/sklearn.utils.shuffle.html)

来自github:

if shuffle == 'batch':
    index_array = batch_shuffle(index_array, batch_size)              
elif shuffle:
    random.shuffle(index_array)

【讨论】:

  • 谢谢。我在 Keras 文档中看到了这一点,但它会打乱整个数据集还是只在一个批次中? Keras 文档对此非常少,也不是很清楚。未打乱的数据集非常有序:属于同一类的 200 组 500 张图像。由于批次只有 32/64,因此批次内的洗牌将毫无用处。 Shuffle 需要是全局的。
  • 已编辑答案以解决后续问题。
  • 谢谢,使用未洗牌的数据集并让 Keras 洗牌它在极简主义网络上工作。它移动缓慢但稳定,经过 200 个 epoch 后它仍在取得进展,尽管仍然只有 20% 的准确度,比 0.5% 好很多!
  • 您可以通过接受答案和/或投票来感谢我。
  • 我点击了您的答案附近的向上箭头,它说,由于我没有声誉(或类似的东西),我的背书被注意到但不被计算在内。还有什么我可以做的吗?我如何接受答案?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-21
  • 1970-01-01
  • 2023-01-11
  • 2018-05-05
相关资源
最近更新 更多