Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

train your own dataset #54

Closed
xiaozhuka opened this issue May 7, 2019 · 7 comments
Closed

train your own dataset #54

xiaozhuka opened this issue May 7, 2019 · 7 comments

Comments

@xiaozhuka
Copy link

xiaozhuka commented May 7, 2019

使用CornerNet训练自己的数据

训练过程

环境配置

  • python3.5
  • cuda8+cudnn7
  • pytorch1.0.1.post2
  • torchvision0.2.2.post3
  • python3-tk
  • tqdm

训练步骤

Compiling Corner Pooling Layers

Compile the C++ implementation of the corner pooling layers. (GCC4.9.2 or above is required.)

cd <CornerNet-Lite dir>/core/models/py_utils/_cpools/
python setup.py install --user

Compiling NMS

Compile the NMS code which are originally from Faster R-CNN and Soft-NMS.

cd <CornerNet-Lite dir>/core/external
make

拷贝文件

以使用WiderFace数据集人脸检测为例  

  1. 拷贝core/models/CornerNet_Squeeze.py -> core/models/CornerNet_Squeeze_face.py
  2. 拷贝configs/CornerNet_Squeeze.json -> configs/CornerNet_Squeeze_face.json
  3. 拷贝core/dbs/coco.py -> core/dbs/widerface.py

修改文件

配置文件修改CornerNet_Squeeze.json

  1. dataset: WiderFace
  2. batch_size = sum(chunk_sizes), chunk_sizes的长度等于GPU个数
  3. train_split: 训练集Annotation的名字
  4. val_split:验证集Annotation的名字
  5. categories: 80改为1

没有添加pretrain字段,这里不使用预训练模型
如果使用预训练模型需要在加载预训练模型后删除tl_heats和br_heats layers,否则输出匹配不上
如果使用预训练模型而不删除tl_heats和br_heats layers,可以不用将80修改为1[3个地方],直接预测80类即可

模型定义修改core/models/CornerNet_Squeeze.py

  1. 94行:tl_heats从80改为1
  2. 95行:br_heats从80改为1

数据加载修改core/dbs/widerface.py

首先在core/dbs/init.py文件中添加数据集:

datasets = {
    "COCO": COCO,
    "WiderFace": WiderFace,
}

其次需要修改数据路径以及加载方式,主要修改如下:

class WiderFace(DETECTION):
    def __init__(self, db_config, split=None, sys_config=None):
        super(WiderFace, self).__init__(db_config)
    self._coco_cls_ids = [
            1
        ]

    self._coco_cls_names = [
            'face'
        ]
    self._split     = {
                "train": "train",
                "val":  "val"
            }[split]
    self._data_dir  = os.path.join(coco_dir, "JPEGImages")
    self._anno_file = os.path.join(coco_dir, "{}.json".format(self._split))

注意数据集需要自己转换成coco格式

最后建立WiderFace数据集到data目录下的软链接,尤其注意数据路径

错误解决办法

  1. File "/home/huanyun/code/CornerNet-Lite/core/sample/init.py", line 5, in data_sampling_func
    return globals()[sys_configs.sampling_function](sys_configs, db, k_ind, data_aug, debug)
    File "/home/huanyun/code/CornerNet-Lite/core/sample/cornernet.py", line 139, in cornernet
    tl_regrs[b_ind, tag_ind, :] = [fxtl - xtl, fytl - ytl]
    IndexError: index 128 is out of bounds for axis 1 with size 128
    问题分析:当前图片中的boundingbox太多,默认是max_tag_len = 128
    解决办法:增加max_tag_len
  2. python2下tqdm不能正确识别,因此使用python3
  3. 需要安装python3-tk,sudo apt-get install方式安装失败(有人直接安装成功),换成阿里的源再apt-get也不行(有人安装成功),最后源码编译tk和pcl[http://www.tcl.tk/software/tcltk/download.html]后重新安装python3.5
    尽管之前是3.5.3+,最新安装的是python3.5.3,python3的第三方库需要重新安装,因此最好不要这么安装,非常麻烦【https://www.jianshu.com/p/0baa9657377f】
  4. 训练时ImageShape获取不到,检查出来是annotations中有的图像不存在,重新检查确保图像存在即可
  5. 测试时频繁在一张图像出现cuda out of memory,检查一下是否当前图像太大,输入网络的图像分辨率是original_size * test_scale,可以适当缩小test_scale
@jianyin2016
Copy link

你好,我也用WIDER训练了,我设置的max_tag_len=1280还是会有IndexError,有没有推荐的值呢?

@xiaozhuka
Copy link
Author

@jianyin2016 我使用的是500。
但我的WiderFace数据集是处理过的,我没有训练分辨率低于20的人脸

@li10141110
Copy link

Thank u for yr good job

@RolandoGough
Copy link

@xiaozhuka 你好 请问下你用WiderFace数据集训练的结果怎么样 和mtcnn比相差多少?

@mylife126
Copy link

感谢分享知识! 超级有帮助。 能再请问一个问题关于label的format的问题么? 教程中提到的 “注意数据集需要自己转换成coco格式”, 请问能给一个例子么。 例如在YOLO中,COCO的label全部是和每一张图片一一对应的,都存在一个.txt file中,label的格式为 [class, normalized center x, normalized center y, normalized width, normalized height]. 请问train Cornet的时候也是这么操作的么? 十分感谢!!
@xiaozhuka

@Liuxi-G
Copy link

Liuxi-G commented Nov 27, 2019

请问输入图片尺寸不一样是否需要调整参数?

@pioneer158
Copy link

I use labelme to label figure, then transforms coco datasets:

import argparse
import json
import matplotlib.pyplot as plt
import skimage.io as io
import cv2
from labelme import utils
import numpy as np
import glob
import PIL.Image

class labelme2coco(object):
def init(self,labelme_json=[],save_json_path='./new.json'):
'''
:param labelme_json: 所有labelme的json文件路径组成的列表
:param save_json_path: json保存位置
'''
self.labelme_json=labelme_json
self.save_json_path=save_json_path
self.images=[]
self.categories=[]
self.annotations=[]
# self.data_coco = {}
self.label=[]
self.annID=1
self.height=0
self.width=0

    self.save_json()

def data_transfer(self):
    for num,json_file in enumerate(self.labelme_json):
        with open(json_file,'r') as fp:
            data = json.load(fp)  # 加载json文件
            self.images.append(self.image(data,num))
            for shapes in data['shapes']:
                label=shapes['label'].split('_')
                print('label:',label)
                if label[0] not in self.label:
                    self.categories.append(self.categorie(label))
                    self.label.append(label[0])
                points=shapes['points']
                self.annotations.append(self.annotation(points,label,num))
                self.annID+=1

def image(self,data,num):
    image={}
    # img = utils.img_b64_to_array(data['imageData'])  # 解析原图片数据
    img=io.imread(data['imagePath']) # 通过图片路径打开图片
    # img = cv2.imread(data['imagePath'], 0)
    height, width = img.shape[:2]
    img = None
    image['height']=height
    image['width'] = width
    image['id']=num+1
    image['file_name'] = data['imagePath'].split('/')[-1]

    self.height=height
    self.width=width

    return image

def categorie(self,label):
    categorie={}
    categorie['supercategory'] = label[0]
    categorie['id']=len(self.label)+1 # 0 默认为背景
    categorie['name'] = label[0]
    return categorie

def annotation(self,points,label,num):
    annotation={}
    # annotation['segmentation']=[list(np.asarray(points).flatten())]  默认版本
    annotation['segmentation']=[np.asarray(points).flatten().tolist()]
    annotation['iscrowd'] = 0
    annotation['image_id'] = num+1
    # annotation['bbox'] = str(self.getbbox(points)) # 使用list保存json文件时报错
    # list(map(int,a[1:-1].split(','))) a=annotation['bbox'] 使用该方式转成list
    annotation['bbox'] = list(map(float,self.getbbox(points)))

    annotation['category_id'] = self.getcatid(label)
    annotation['id'] = self.annID
    return annotation

def getcatid(self,label):
    for categorie in self.categories:
        if label[0]==categorie['name']:
            return categorie['id']
    return -1

def getbbox(self,points):
    # img = np.zeros([self.height,self.width],np.uint8)
    # cv2.polylines(img, [np.asarray(points)], True, 1, lineType=cv2.LINE_AA)  # 画边界线
    # cv2.fillPoly(img, [np.asarray(points)], 1)  # 画多边形 内部像素值为1
    polygons = points
    mask = self.polygons_to_mask([self.height,self.width], polygons)
    return self.mask2box(mask)

def mask2box(self, mask):
    '''从mask反算出其边框
    mask:[h,w]  0、1组成的图片
    1对应对象,只需计算1对应的行列号(左上角行列号,右下角行列号,就可以算出其边框)
    '''
    # np.where(mask==1)
    index = np.argwhere(mask == 1)
    rows = index[:, 0]
    clos = index[:, 1]
    # 解析左上角行列号
    left_top_r = np.min(rows)  # y
    left_top_c = np.min(clos)  # x

    # 解析右下角行列号
    right_bottom_r = np.max(rows)
    right_bottom_c = np.max(clos)

    # return [(left_top_r,left_top_c),(right_bottom_r,right_bottom_c)]
    # return [(left_top_c, left_top_r), (right_bottom_c, right_bottom_r)]
    # return [left_top_c, left_top_r, right_bottom_c, right_bottom_r]  # [x1,y1,x2,y2]
    return [left_top_c, left_top_r, right_bottom_c-left_top_c, right_bottom_r-left_top_r]  # [x1,y1,w,h] 对应COCO的bbox格式

def polygons_to_mask(self,img_shape, polygons):
    mask = np.zeros(img_shape, dtype=np.uint8)
    mask = PIL.Image.fromarray(mask)
    xy = list(map(tuple, polygons))
    PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
    mask = np.array(mask, dtype=bool)
    return mask

def data2coco(self):
    data_coco={}
    data_coco['images']=self.images
    data_coco['categories']=self.categories
    data_coco['annotations']=self.annotations
    return data_coco

def save_json(self):
    self.data_transfer()
    self.data_coco = self.data2coco()
    # print('输出data_coco:',self.data_coco)
    # 保存json文件
    json.dump(self.data_coco, open(self.save_json_path, 'w'), indent=4)  # indent=4 更加美观显示

if name == 'main':

labelme_train_json=glob.glob('./train_json/*.json')
labelme_val_json = glob.glob('./val_json/*.json')
train = False
val = True

if train:
    labelme2coco(labelme_train_json,'./instances_train2017.json')
if val:
    labelme2coco(labelme_val_json,'./instances_val2017.json')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants