【发布时间】: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