我正在尝试使用Caffe2中的squeezenet对ETH Food-101数据集进行分类。我的模型是从模型动物园导入的,我对模型进行了两种类型的修改:
1)将最后一层的尺寸更改为101输出
2)来自数据库的图像采用NHWC形式,我只是翻转了权重的尺寸以匹配。 (我打算改变这个)
Food101数据集有75,000个用于训练的图像,我目前使用的批量大小为128,起始学习率为-0.01,伽马值为0.999,步长为1.我注意到的是前2000次迭代网络精度在1/128左右徘徊,这需要一个小时左右才能完成。
我将所有权重添加到model.params中,以便它们可以在梯度下降期间更新(数据除外),并将所有权重重新初始化为Xavier并将偏差重新初始化为常量。我希望准确度在前一百到几千次迭代中相当快地增长,然后随着迭代次数的增加而减少。就我而言,学习在0附近保持不变。
当我查看渐变文件时,我发现平均值大约为10 ^ -6,标准偏差为10 ^ -7。这解释了学习速度慢,但我还没有能够让渐变开始更高。
这些是几次迭代后第一次卷积的梯度统计
Min Max Avg Sdev
-1.69821e-05 2.10922e-05 1.52149e-06 5.7707e-06
-1.60263e-05 2.01478e-05 1.49323e-06 5.41754e-06
-1.62501e-05 1.97764e-05 1.49046e-06 5.2904e-06
-1.64293e-05 1.90508e-05 1.45681e-06 5.22742e-06
以下是我的代码的核心部分:
#init_path is path to init_net protobuf
#pred_path is path to pred_net protobuf
def main(init_path, pred_path):
ws.ResetWorkspace()
data_folder = '/home/myhome/food101/'
#some debug code here
arg_scope = {"order":"NCHW"}
train_model = model_helper.ModelHelper(name="food101_train", arg_scope=arg_scope)
if not debug:
data, label = AddInput(
train_model, batch_size=128,
db=os.path.join(data_folder, 'food101-train-nchw-leveldb'),
db_type='leveldb')
init_net_def, pred_net_def = update_squeeze_net(init_path, pred_path)
#print str(init_net_def)
train_model.param_init_net.AppendNet(core.Net(init_net_def))
train_model.net.AppendNet(core.Net(pred_net_def))
ws.RunNetOnce(train_model.param_init_net)
add_params(train_model, init_net_def)
AddTrainingOperators(train_model, 'softmaxout', 'label')
AddBookkeepingOperators(train_model)
ws.RunNetOnce(train_model.param_init_net)
if debug:
ws.FeedBlob('data', data)
ws.FeedBlob('label', label)
ws.CreateNet(train_model.net)
total_iters = 10000
accuracy = np.zeros(total_iters)
loss = np.zeros(total_iters)
# Now, we will manually run the network for 200 iterations.
for i in range(total_iters):
#try:
conv1_w = ws.FetchBlob('conv1_w')
print conv1_w[0][0]
ws.RunNet("food101_train")
#except RuntimeError:
# print ws.FetchBlob('conv1').shape
# print ws.FetchBlob('pool1').shape
# print ws.FetchBlob('fire2/squeeze1x1_w').shape
# print ws.FetchBlob('fire2/squeeze1x1_b').shape
#softmax = ws.FetchBlob('softmaxout')
#print softmax[i]
#print softmax[i][0][0]
#print softmax[i][0][:5]
#print softmax[64*i]
accuracy[i] = ws.FetchBlob('accuracy')
loss[i] = ws.FetchBlob('loss')
print accuracy[i], loss[i]
我的add_params函数初始化权重如下
#ops allows me to only initialize the weights of specific ops because i initially was going to do last layer training
def add_params(model, init_net_def, ops=[]):
def add_param(op):
for output in op.output:
if "_w" in output:
weight_shape = []
for arg in op.arg:
if arg.name == 'shape':
weight_shape = arg.ints
weight_initializer = initializers.update_initializer(
None,
None,
("XavierFill", {}))
model.create_param(
param_name=output,
shape=weight_shape,
initializer=weight_initializer,
tags=ParameterTags.WEIGHT)
elif "_b" in output:
weight_shape = []
for arg in op.arg:
if arg.name == 'shape':
weight_shape = arg.ints
weight_initializer = initializers.update_initializer(
None,
None,
("ConstantFill", {}))
model.create_param(
param_name=output,
shape=weight_shape,
initializer=weight_initializer,
我发现当我使用完整的训练集时,我的损失函数会波动,但是如果我只使用一个批次并且多次迭代它,我会发现损失函数下降但非常缓慢。
答案 0 :(得分:1)
虽然SqueezeNet的参数比AlexNet少50倍,但它仍然是一个非常大的网络。 The original paper没有提及训练时间,但基于SqueezeNet的SQ需要22个小时才能使用两张Titan X显卡进行训练 - 这是一些经过预训练的重量!我没有详细介绍您的代码,但您所描述的是预期的行为 - 您的网络能够在单个批次上学习,而不是像您预期的那样快。
我建议尽可能多地重用权重而不是重新初始化它们,就像SQ的创建者一样。这被称为转移学习,它可以工作,因为无论图像的内容如何,图像中的许多低级特征(线条,曲线,基本形状)都是相同的,并且重复使用这些图层的权重可以节省网络不得不从头开始重新学习它们。