Caffe时间(2) Caffe实践LeNet

接着上一篇blog继续写,今天是使用数据来训练LeNet,此处是用来进行图像的二分类问题,但是因为LeNet本身结构上的一些问题(主要是用来识别手写数字,在Mnist上训练效果可以达到99%),在进行了几轮实验后,发现最终的实验结果并不是非常理想,accuracy最高也才到85%,loss大概是在0.33左右,训练model重在调参,这是今天感受最深的一句话,我能说这大半天都在进行调参吗?

(/ω\)

虽然用的GPU比用CPU但是训练一遍也大概要20min(两块1080ti),但是实际训练中应该只有一块在跑(可能还是数据量小?相比于Mnist的数据集,GPU的色噪音小多了),现在正在一旁训练LeNet。

回到调参的问题,昨天晚上因为是第一次训练没经验,有些参数也没太看懂,导致出了一些问题。先来看一下比较重要的几个文件
再来附上这张图(比昨天的增加和修改了一些)

  • 定义网络结构的lenet_train_text.prototxt文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    name: "LeNet"
    layer {
    name: "mnist"
    type: "Data"
    top: "data"
    top: "label"
    include {
    phase: TRAIN
    }
    transform_param {
    scale: 0.00390625
    }
    data_param {
    source: "/home/deep/caffe/examples/My_Files/Build_lmdb/train_lmdb"
    batch_size: 34 //注意调节好此处和下面的batch_size的大小
    backend: LMDB
    }
    }
    layer {
    name: "mnist"
    type: "Data"
    top: "data"
    top: "label"
    include {
    phase: TEST
    }
    transform_param {
    scale: 0.00390625
    }
    data_param {
    source: "/home/deep/caffe/examples/My_Files/Build_lmdb/val_lmdb"
    batch_size: 38
    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: "pool1"
    type: "Pooling"
    bottom: "conv1"
    top: "pool1"
    pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
    }
    }
    layer {
    name: "conv2"
    type: "Convolution"
    bottom: "pool1"
    top: "conv2"
    param {
    lr_mult: 1
    }
    param {
    lr_mult: 2
    }
    convolution_param {
    num_output: 50
    kernel_size: 5
    stride: 1
    weight_filler {
    type: "xavier"
    }
    bias_filler {
    type: "constant"
    }
    }
    }
    layer {
    name: "pool2"
    type: "Pooling"
    bottom: "conv2"
    top: "pool2"
    pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
    }
    }
    layer {
    name: "ip1"
    type: "InnerProduct"
    bottom: "pool2"
    top: "ip1"
    param {
    lr_mult: 1
    }
    param {
    lr_mult: 2
    }
    inner_product_param {
    num_output: 500
    weight_filler {
    type: "xavier"
    }
    bias_filler {
    type: "constant"
    }
    }
    }
    layer {
    name: "relu1"
    type: "ReLU"
    bottom: "ip1"
    top: "ip1"
    }
    layer {
    name: "ip2"
    type: "InnerProduct"
    bottom: "ip1"
    top: "ip2"
    param {
    lr_mult: 1
    }
    param {
    lr_mult: 2
    }
    inner_product_param {
    num_output: 2 //注意根据自己的需要进行改变,这里是二分类问题
    weight_filler {
    type: "xavier"
    }
    bias_filler {
    type: "constant"
    }
    }
    }
    layer {
    name: "accuracy"
    type: "Accuracy"
    bottom: "ip2"
    bottom: "label"
    top: "accuracy"
    include {
    phase: TEST
    }
    }
    layer {
    name: "loss"
    type: "SoftmaxWithLoss"
    bottom: "ip2"
    bottom: "label"
    top: "loss"
    }

    注意调节batch_size大小,第一次直接使用训练Mnist的那套参数导致,一直不收敛,且loss一直是87.3365,改变之后loss终于降低

  • 定义训练参数的lenet_solver.prototxt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #网络原型文件的位置
    net: "/home/deep/caffe/examples/My_Files/lenet_train_test.prototxt"
    #测试迭代的次数,这里需要test_iter和上面TEST下面的batch_size的乘积要>=测试集的数据量
    test_iter: 50
    #由于是边进行训练边进行测试,这里就是指每训练500次要进行一下测试
    test_interval: 500
    #基础的学习率,学习率请看下方引用1部分;下面两个一般不用改
    base_lr: 0.0001
    momentum: 0.9
    weight_decay: 0.0005
    #这里也没改过
    lr_policy: "inv"
    gamma: 0.0001
    power: 0.75
    # Display every 100 iterations
    display: 100
    #这个就是指最大的迭代次数
    max_iter: 10000
    #每5000次保存一次快照,方便之后对模型进行后续的训练
    snapshot: 5000
    snapshot_prefix: "/home/deep/caffe/examples/My_Files/lenet"
    #训练模式,这里选择的是GPU模式
    solver_mode: GPU

    引用1:

    运用梯度下降算法进行优化时,权重的更新规则中,在梯度项前会乘以一个系数,这个系数就叫学习速率η。下面讨论在训练时选取η的策略。

    • 固定的学习速率。如果学习速率太小,则会使收敛过慢,如果学习速率太大,则会导致代价函数振荡,如下图所示
  • 执行训练的脚本文件train.sh

    1
    2
    3
    4
    5
    #!/usr/bin/env sh
    set -e

    /home/deep/caffe/build/tools/caffe train \
    --solver=/home/deep/caffe/examples/My_Files/lenet_solver.prototxt $@

    这个直接执行sudo bash train.sh就开始训练了,打印过程就不写了

    | Type | test_iter | test_interval | base_lr | train_size | test_size | accuracy | loss |
    | :—: | :——-: | :———–: | :—–: | :——–: | :——-: | :——: | :——: |
    | LeNet | 100 | 500 | 0.0001 | 136 | 24 | 0.85875 | 0.338477 |
    | LeNet | 50 | 500 | 0.0001 | 136 | 40 | 0.860526 | 0.337723 |
    | LeNet | 50 | 500 | 0.0001 | 34 | 38 | 0.861053 | 0.321303 |

    几次训练的参数和最终的结果见上表↑

    这里可以看一篇文章↓

    caffe 训练自己的数据集—调试技巧篇

    训练完成之后可以看到生成的多个成对出现的 .caffemodel 和 .solverstate文件,一个是模型文件,一个是中间状态文件(生成多少个取决于你自己设定的snapshot)。当训练过程中断,你想继续运行数据学习,此时只需要调用.solverstate文件即可。

    使用方式代码,我使用的是.sh直接运行,配置和官方给的文件train_caffenet.sh差不多,稍微添加点内容就可以了,按自己的情况进行对应修改。

    1
    2
    3
    ./build/tools/caffe train \  
    --solver=examples/test/solver.prototxt \
    --snapshot=examples/test/test_100000.solverstate

    参考下面的文章↓

    caffe的solverstate的使用

之后改用AlecNet进行了5W次迭代准确率可以达到95%左右,通过输出结果可以看出1.5W次到5W次迭代之间accuracy大概就是在94%~96%这个范围之间

这个马一些以后用↓

机器学习 - Solverstate 使用和CaffeMode 可视化

坚持原创分享,您的支持将鼓励我继续创作!