天天看点

Pytorch-ENet-Nice训练Citysacapes和CamVidNice 发现训练ENet训练技巧完整的训练工程

Nice 发现

目前在图像分割中普遍会对训练图像和标签图像进行resize,一般采用最近邻插值法对训练图像和标签图像进行缩放,这样可以把图像resize成网络结构所需要的输入尺寸。但这会存在一个严重的问题,就算是最近邻插值法对标签图像进行resize也会在色彩边缘处插入错误的值,这意味着label image会插入错误的标签,这个问题通常会导致网络不能很好的训练。

所以只能采用下采样的方式对图片进行一个缩小操作,这样可以提高分割网络的训练精度。图像下采样的C++实现代码如下:

void scaleDownSampling(const Mat &src, Mat &dst, double xRatio, double yRatio)
{
    //判断是否为uchar型的像素
    CV_Assert(src.depth() == CV_8U);

    // 计算缩小后图像的大小,取整防止越界
    int rows = static_cast<int>(src.rows * xRatio);
    int cols = static_cast<int>(src.cols * yRatio);

    dst.create(rows, cols, src.type());

    const int channels = src.channels();

    switch (channels)
    {
        case 1: //单通道图像
        {
            uchar *p;
            const uchar *origal;

            for (int i = 0; i < rows; i++){
                p = dst.ptr<uchar>(i);
                //间隔采样取基数行
                int row = static_cast<int>((i + 1) / xRatio + 0.5) - 1;
                origal = src.ptr<uchar>(row);
                for (int j = 0; j < cols; j++){
                    //间隔采样取基数列
                    int col = static_cast<int>((j + 1) / yRatio + 0.5) - 1;
                    p[j] = origal[col];  //把像素值赋给dst
                }
            }
            break;
        }

        case 3://三通道图像
        {
            Vec3b *p;
            const Vec3b *origal;

            for (int i = 0; i < rows; i++) {
                p = dst.ptr<Vec3b>(i);
                int row = static_cast<int>((i + 1) / xRatio + 0.5) - 1;
                origal = src.ptr<Vec3b>(row);
                for (int j = 0; j < cols; j++){
                    int col = static_cast<int>((j + 1) / yRatio + 0.5) - 1;
                    p[j] = origal[col]; //把RGB三个值赋给dst
                }
            }
            break;
        }
    }
}
           

对于CItyscapes数据集要resize成1024*512的尺寸,可以采用这个工具进行实现,可以运行命令

./scaleDownSampling help

来查看参数列表。

训练ENet

训练ENet网络可以分为两部分,第一部分仅训练ENet网络的编码结构,第二部分是训练ENet的编码-解码结构。先来看个采用cityscapes数据集的训练效果图吧,刺激一下感官:

Pytorch-ENet-Nice训练Citysacapes和CamVidNice 发现训练ENet训练技巧完整的训练工程

效果还不错!!!

训练ENet_encoder结构

如果仅训练ENet的编码结构,需要把标签图像缩小8倍的尺寸,因为在编码结构最终会把图片卷成8倍小的尺寸。

训练encoder-decoder结构

训练ENet完整的结构保持图片和标签图片一致即可。对于cityscapes数据集建议采用1024512的输入尺寸,对于CamVid数据集建议采用480360的输入尺寸。

训练技巧

1、由于cityscapes数据集计算一次分类权重值的耗时很长,所以建议记录第一次训练的分类权重值,在之后重新训练时直接采用已有分类权重值来初始化优化器。同时保持分类权重值一致也是对恢复断点训练可以保持一致性。

2、训练ENet在误差值不再降低的时候,可以采用误差最小的模型并适当提高学习率重新训练,或许可以得到更低误差的模型。

完整的训练工程

github: https://github.com/Dawson-huang/Pytorch-ENet-Nice

欢迎star和fork,你的star可以给予我莫大的信心!!

继续阅读