我正在尝试构建一个CNN来将对象分类为三个主要类别。这三个对象包括兰博基尼、气缸头和飞机部件。我的数据集包含6580张图片,每个类别大约有2200张图片。你可以在Google Drive上查看我的数据集 数据集。我的CNN架构是AlexNet,但我已经将第8个全连接层的输出从1000改成了3。我在训练中使用了以下设置
test_iter:1000test_interval:1000base_lr:0.001lr_policy:"step"gamma:0.1stepsize:2500max_iter:40000momentum:0.9weight_decay:0.0005
但是,问题是在我训练后部署模型时,结果总是如下 {'prob': array([[ 0.33333334, 0.33333334, 0.33333334]], dtype=float32)}
。
下面的代码是我加载模型并输出概率向量的脚本。
import numpy as npimport matplotlib.pyplot as pltimport sysimport caffeimport cv2MODEL_FILE ='deploy_ex0.prototxt'PRETRAINED='snapshot_ex0_1_model_iter_40000.caffemodel'caffe.set_mode_cpu()net = caffe.Net(MODEL_FILE, PRETRAINED, caffe.TEST)#预处理 transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})#均值减去 mean_file = np.array([104,117,123]) transformer.set_mean('data', mean_file)transformer.set_transpose('data', (2,0,1))transformer.set_channel_swap('data', (2,1,0))transformer.set_raw_scale('data', 255.0)#批次大小 net.blobs['data'].reshape(1,3,227,227)#在数据层加载图像 im=cv2.imread('test.jpg', cv2.IMREAD_COLOR)img =cv2.resize(im, (227,227))net.blobs['data'].data[...] = transformer.preprocess('data', img)#计算 out=net.forward()print out
我想知道为什么我会得到这样的结果?你能帮助我调试我的CNN吗?
此外,训练后我得到了这些结果
I0421 06:56:12.285953 2224 solver.cpp:317] Iteration 40000, loss = 5.06557e-05I0421 06:56:12.286027 2224 solver.cpp:337] Iteration 40000, Testing net (#0)I0421 06:58:32.159469 2224 solver.cpp:404] Test net output #0: accuracy = 0.99898I0421 06:58:32.159626 2224 solver.cpp:404] Test net output #1: loss = 0.00183688 (* 1 = 0.00183688 loss)I0421 06:58:32.159643 2224 solver.cpp:322] Optimization Done.I0421 06:58:32.159654 2224 caffe.cpp:222] Optimization Done.
谢谢
11月11日回答后的编辑:
我使用了一个简单的模型,包括1个卷积层、1个ReLU层、1个池化层和2个全连接层。下面的代码是架构规范:
name:"CNN"layer { name: "convnet" type: "Data" top: "data" top: "label" include { phase: TRAIN } transform_param { mirror:true crop_size:227 mean_value:87.6231 mean_value:87.6757 mean_value:87.1677 #mean_file:"/home/jaba/caffe/data/diota_model/mean.binaryproto" } data_param { source: "/home/jaba/caffe/data/diota_model/train_lmdb" batch_size: 32 backend: LMDB }}layer { name: "convnet" type: "Data" top: "data" top: "label" include { phase: TEST } transform_param { mirror:true crop_size:227 mean_value:87.6231 mean_value:87.6757 mean_value:87.1677 #mean_file:"/home/jaba/caffe/data/diota_model/mean.binaryproto" } data_param { source: "/home/jaba/caffe/data/diota_model/val_lmdb" batch_size: 20 backend: LMDB }}layer { name: "conv1" type: "Convolution" bottom: "data" top: "conv1" param { lr_mult: 1 } param { lr_mult: 2 } convolution_param { num_output: 20 kernel_size: 5 stride: 1 weight_filler { type: "xavier" } bias_filler { type: "constant" } }}layer { name: "relu1" type: "ReLU" bottom: "conv1" top: "conv1"}layer { name: "pool1" type: "Pooling" bottom: "conv1" top: "pool1" pooling_param { pool: MAX kernel_size: 3 stride: 2 }}layer { name: "ip1" type: "InnerProduct" bottom: "pool1" top: "ip1" param { lr_mult: 1 } param { lr_mult: 2 } inner_product_param { num_output: 300 weight_filler { type: "xavier" } bias_filler { type: "constant" } }}layer { name:"ip2" type:"InnerProduct" bottom:"ip1" top:"ip2" param { lr_mult:1 } param { lr_mult:2 } inner_product_param { num_output: 3 weight_filler { type: "xavier" } bias_filler { type: "constant" } }}layer { name: "accuracy" type: "Accuracy" bottom: "ip1" bottom: "label" top: "accuracy" include { phase: TEST }}layer { name: "loss" type: "SoftmaxWithLoss" bottom: "ip1" bottom: "label" top: "loss"}
我训练了这个CNN共22个周期,并获得了86%的准确率。对于求解器参数,我使用了以下设置:
net: "/home/jaba/caffe/data/diota_model/simple_model/train_val.prototxt"test_iter: 50test_interval: 100base_lr: 0.00001momentum: 0.9weight_decay: 0.0005lr_policy: "inv"gamma: 0.0001power: 0.75display: 100max_iter: 3500snapshot: 100snapshot_prefix: "/home/jaba/caffe/data/diota_model/simple_model/snap_shot_model"solver_mode: GPU
现在,当我部署模型时,它不会返回相同的概率向量。但是,有一个问题是,当我加载模型并在validation_lmdb文件夹上测试时,我没有得到相同的准确率值,我得到了大约56%的准确率。
我使用下面的脚本来计算准确率:
我将数据集的大小更改为1002用于测试,4998用于学习。你能给我一些解决这个问题的建议吗?
谢谢!
回答:
我认为我看到了两个不同的问题,都是过拟合的不同形式。用你6580张图片的85%进行训练,你有5593张用于训练,987张用于测试。
一
40000次迭代 * (每次迭代256张图片) * (每5593张图片一个周期) ~= 1831个周期。在ILSVRC数据集(1.28M张图片)上,AlexNet只训练了40-50个周期(取决于规模)。你的模型最终损失几乎为0,并且在整个测试集中只有一张照片出错。
二
AlexNet的宽度(每层的滤波器数量)是为ILSVRC数据集的1000个类别和无数特征调整的。你没有为你的数据缩小它。第5层扩展到4096个滤波器:这几乎是每张图片一个。ILSVRC训练AlexNet识别特征如猫脸、车辆的一侧等——你的模型将训练识别从正前方偏离30度、水平上方8度、背景中有草和驾驶员侧背景中有白杨树的深蓝色兰博基尼。
换句话说,你训练的AlexNet像浇筑的塑料壳一样适合训练数据集。它不会适合任何东西,除了初始数据集。
我有点惊讶它在其他汽车、其他气缸头和飞机部件上表现得稍微好一点。然而,我见过足够多的过拟合模型,它们的输出几乎是随机的。
首先,减少训练的长度。其次,尝试减少每层的num_output大小。
11月11日原帖评论后的编辑
是的,你必须减少每层中的内核/滤波器/输出的数量。特别是第5层有4K个滤波器,这意味着网络可以为你的数据集中的每张照片分配几乎一个滤波器。这不利于有效学习:与其有一小部分滤波器学习垫圈的特征,你有超过1000个滤波器,每个都学习特定垫圈照片的一个非常具体的特征。
AlexNet、GoogleNet、ResNet、VGG等都是为解决对广泛对象的静态图像进行一般区分的问题而构建和调整的。你当然可以使用这些一般概念,但它们不适合用于一个如此小且定义更明确的问题的拓扑结构。