https://github.com/facebookresearch/maskrcnn-benchmark/issues/521
稍後實驗改正
記錄方法一:
Steps1) COCO format將自己的數據集按照coco官方形式進行標註。這樣會好一點,測試時候直接用coco官方api就可以了。可用labelme等等,再進行轉換,還有對應的json文件。official coco format 2) Creating a
|
18 2 3
!python trim_detectron_model.py \
--pretrained_path /root/.torch/models/_detectron_35857345_12_2017_baselines_e2e_faster_rcnn_R-50-FPN_1x.yaml.01_36_30.cUF7QR7I_output_train_coco_2014_train%3Acoco_2014_valminusminival_generalized_rcnn_model_final.pkl \
--save_path ../weights/trimmed_weights/trimmed_e2e_faster_rcnn_R_50_FPN_1x_OURconfig.pth \
--cfg ../configs/caffe2/e2e_faster_rcnn_R_50_FPN_1x_caffe2.yaml
記錄方法二:
original = torch.load(' path / to / your / checkpoint.pth ')
new = { “ model ”:original [ “ model ” ]}
torch.save(new,' path / to / new / checkpoint.pth ')
1 -爲特定模型創建cfg
2 -使用load_c2_format函數,將爲您提供包含模型字段的dict。在那裏,可以通過刪除字段等來執行您想要的模型手術
3 - 使用 torch.save保存目標,結構應該還是按dict(model=state_dict).保存,並且請注意擴展名是.pth,而不是pkl
4 - 更改 MODEL.WEIGHT指向更改後的.pth文件地址。
from maskrcnn_benchmark.config import cfg
from maskrcnn_benchmark.utils.c2_model_loading import load_c2_format
cfg.merge_from_file("configs/caffe2/e2e_mask_rcnn_X_101_32x8d_FPN_1x_caffe2.yaml")
path = '/home/antonio/.torch/models/X-101-32x8d.pkl'
_d = load_c2_format(cfg, path)
keys = [k for k in _d['model'].keys()]
print(sorted(keys))
def _transfer_pretrained_weights(model, pretrained_model_pth):
pretrained_weights = torch.load(pretrained_model_pth)['model']
new_dict = {k.replace('module.',''):v for k, v in pretrained_weights.items()
if 'cls_score' not in k and 'bbox_pred' not in k}
this_state = model.state_dict()
this_state.update(new_dict)
model.load_state_dict(this_state)
return model
def train(cfg, local_rank, distributed):
old_model = build_detection_model(cfg)
pretrained_model_pth = "/home/belhal/.torch/models/_detectron_35858933_12_2017_baselines_e2e_mask_rcnn_R-50-FPN_1x.yaml.01_48_14.DzEQe4wC_output_train_coco_2014_train%3Acoco_2014_valminusminival_generalized_rcnn_model_final.pkl"
model = _transfer_pretrained_weights(old_model,pretrained_model_pth)
device = torch.device(cfg.MODEL.DEVICE)
model.to(device)
....
path='/Users/belhal/.torch/models/_detectron_35858933_12_2017_baselines_e2e_mask_rcnn_R-50-FPN_1x.yaml.01_48_14.DzEQe4wC_output_train_coco_2014_train%3Acoco_2014_valminusminival_generalized_rcnn_model_final.pkl'
from maskrcnn_benchmark.utils.c2_model_loading import load_c2_format
cfg.merge_from_file("../configs/e2e_mask_rcnn_X_101_32x8d_FPN_1x.yaml")
_d = load_c2_format(cfg, path)
newdict = _d
def removekey(d, listofkeys):
r = dict(d)
for key in listofkeys:
del r[key]
return r
newdict['model'] = removekey(_d['model'], ['cls_score.bias','cls_score.weight','bbox_pred.bias','bbox_pred.weight'])
w = torch.load("X-101-32x8d.pth")
然而,發生錯誤:UnicodeDecodeError:'ascii'編解碼器無法解碼位置2中的字節0xad:序數不在範圍內(128)
我可以通過使用pickle來解決這個錯誤:
with open("X-101-32x8d.pkl", "rb") as f: w = pickle.load(f, encoding='latin1')
記錄方法三:該方法終結於:
[loaded_state_dict]函數可以檢查函數中的哪些鍵 ,可以在這裏進行操作(maskrcnn-benchmark/maskrcnn_benchmark/utils/model_serialization.py )
不會影響repo中的其他部分。大概是
model_dict = model.state_dict()
loaded_state_dict = {k: v for k, v in loaded_state_dict.items() if k in model_dict and "roi_heads" not in k}
model_dict.update(loaded_state_dict)
如果是這樣,則無需經過4個步驟。只用編輯 [load_state_dict method]
align_and_update_state_dicts(model_state_dict, loaded_state_dict)
**步驟1**。運行demo.py以測試您的軟件包是否已成功安裝。同時,您可以保存預先訓練的模型,該模型已從pkl格式轉換爲pth格式,可以通過pytorch模型加載。該模型是演示中COCODEmo對象的數據,因此您可以保存預訓練模型的權重,如下所示
pretrained_model_path = "./pretrained_model/maskRCNN.pth"
check_point = {'state': coco_demo.model.state_dict()}
torch.save(check_point, pretrained_model_path)
這樣,無需查看[_load_file fun](https://github.com/facebookresearch/maskrcnn-benchmark/blob/f25c6cff92d32d92abe8965d68401004e90c8bee/maskrcnn_benchmark/utils/checkpoint.py#L117).另外還有個保存權重到OrderedDict的方法:(https://github.com/pytorch/pytorch/blob/828cb18fa35c7c132ab920de1c0dc6d859f152d6/torch/nn/modules/module.py#L602)
retrained_model = torch.load(checkpoint_path)['model']
model_dict = self.model.state_dict()
pretrained_dict = {k: v for k, v in pretrained_model.items() if k in model_dict and "roi_heads" not in k}
model_dict.update(pretrained_dict)
**step 2**. 使用configs文件夾中的yaml文件創建fastercnn或maskRCNN模型。執行此操作時,您需要調用cfg.merge_from_list方法來更改[_C.MODEL.ROI_BOX_HEAD.NUM_CLASSES = 81]到數據集中的類數(後臺在此實現中不計算)。(https://github.com/facebookresearch/maskrcnn-benchmark/blob/f25c6cff92d32d92abe8965d68401004e90c8bee/maskrcnn_benchmark/config/defaults.py#L182)
**step 3**.需要創建兩個類。
第一個類:[torchvision.datasets.coco.CocoDetection] (
maskrcnn-benchmark/maskrcnn_benchmark/data/datasets/coco.py
class COCODataset(torchvision.datasets.coco.CocoDetection):
獲取一個圖像及其對應的bbox和標籤,而不將Bbox和標籤捆綁在BoxList對象中。也就是 return img, target, idx
此類與[COCODataset](https://github.com/facebookresearch/maskrcnn-benchmark/blob/f25c6cff92d32d92abe8965d68401004e90c8bee/maskrcnn_benchmark/data/datasets/coco.py#L9). 在每次迭代中,該類生成一個元組(img,bbox,label),其中img由Image.open(...).convert('RGB')生成;
bbox 是 2d numpy 數組, label是1d 數組(mask的話就是掩碼信息).
第二類繼承自第一類,這個類的主要職責是將一個圖像的真實包裝在一個BoxList對象中,類似於[line]
img, anno = super(COCODataset, self).__getitem__(idx) |
(https://github.com/facebookresearch/maskrcnn-benchmark/blob/f25c6cff92d32d92abe8965d68401004e90c8bee/maskrcnn_benchmark/data/datasets/coco.py#L43).
**step 4**. 對於pytorch預訓練模型,權重在字典中被分類,其中鍵是layer的名稱。因此,您可以排除不存在的layer或者您想要從頭開始訓練,如下所示:pretrained_model = torch.load(checkpoint_path)['state']
import os
import torch
import argparse
from maskrcnn_benchmark.config import cfg
from maskrcnn_benchmark.utils.c2_model_loading import load_c2_format
def removekey(d, listofkeys):
r = dict(d)
for key in listofkeys:
print('key: {} is removed'.format(key))
r.pop(key)
return r
parser = argparse.ArgumentParser(description="Trim Detection weights and save in PyTorch format.")
parser.add_argument(
"--pretrained_path",
default="~/.torch/models/_detectron_35858933_12_2017_baselines_e2e_mask_rcnn_R-50-FPN_1x.yaml.01_48_14.DzEQe4wC_output_train_coco_2014_train%3Acoco_2014_valminusminival_generalized_rcnn_model_final.pkl",
help="path to detectron pretrained weight(.pkl)",
type=str,
)
parser.add_argument(
"--save_path",
default="./pretrained_model/mask_rcnn_R-50-FPN_1x_detectron_no_last_layers.pth",
help="path to save the converted model",
type=str,
)
parser.add_argument(
"--cfg",
default="configs/e2e_mask_rcnn_R_50_FPN_1x.yaml",
help="path to config file",
type=str,
)
args = parser.parse_args()
#
DETECTRON_PATH = os.path.expanduser(args.pretrained_path)
print('detectron path: {}'.format(DETECTRON_PATH))
cfg.merge_from_file(args.cfg)
_d = load_c2_format(cfg, DETECTRON_PATH)
newdict = _d
newdict['model'] = removekey(_d['model'],
['cls_score.bias', 'cls_score.weight', 'bbox_pred.bias', 'bbox_pred.weight'])
torch.save(newdict, args.save_path)
print('saved to {}.'.format(args.save_path))
城市景觀數據集與coco
def clip_weights_from_pretrain_of_coco_to_cityscapes(f, out_file):
""""""
from maskrcnn_benchmark.config.paths_catalog import COCO_CATEGORIES
from maskrcnn_benchmark.config.paths_catalog import CITYSCAPES_FINE_CATEGORIES
coco_cats = COCO_CATEGORIES
cityscapes_cats = CITYSCAPES_FINE_CATEGORIES
coco_cats_to_inds = dict(zip(coco_cats, range(len(coco_cats))))
cityscapes_cats_to_inds = dict(
zip(cityscapes_cats, range(len(cityscapes_cats)))
)
checkpoint = torch.load(f)
m = checkpoint['model']
weight_names = {
"cls_score": "module.roi_heads.box.predictor.cls_score.weight",
"bbox_pred": "module.roi_heads.box.predictor.bbox_pred.weight",
"mask_fcn_logits": "module.roi_heads.mask.predictor.mask_fcn_logits.weight",
}
bias_names = {
"cls_score": "module.roi_heads.box.predictor.cls_score.bias",
"bbox_pred": "module.roi_heads.box.predictor.bbox_pred.bias",
"mask_fcn_logits": "module.roi_heads.mask.predictor.mask_fcn_logits.bias",
}
representation_size = m[weight_names["cls_score"]].size(1)
cls_score = nn.Linear(representation_size, len(cityscapes_cats))
nn.init.normal_(cls_score.weight, std=0.01)
nn.init.constant_(cls_score.bias, 0)
representation_size = m[weight_names["bbox_pred"]].size(1)
class_agnostic = m[weight_names["bbox_pred"]].size(0) != len(coco_cats) * 4
num_bbox_reg_classes = 2 if class_agnostic else len(cityscapes_cats)
bbox_pred = nn.Linear(representation_size, num_bbox_reg_classes * 4)
nn.init.normal_(bbox_pred.weight, std=0.001)
nn.init.constant_(bbox_pred.bias, 0)
dim_reduced = m[weight_names["mask_fcn_logits"]].size(1)
mask_fcn_logits = Conv2d(dim_reduced, len(cityscapes_cats), 1, 1, 0)
nn.init.constant_(mask_fcn_logits.bias, 0)
nn.init.kaiming_normal_(
mask_fcn_logits.weight, mode="fan_out", nonlinearity="relu"
)
def _copy_weight(src_weight, dst_weight):
for ix, cat in enumerate(cityscapes_cats):
if cat not in coco_cats:
continue
jx = coco_cats_to_inds[cat]
dst_weight[ix] = src_weight[jx]
return dst_weight
def _copy_bias(src_bias, dst_bias, class_agnostic=False):
if class_agnostic:
return dst_bias
return _copy_weight(src_bias, dst_bias)
m[weight_names["cls_score"]] = _copy_weight(
m[weight_names["cls_score"]], cls_score.weight
)
m[weight_names["bbox_pred"]] = _copy_weight(
m[weight_names["bbox_pred"]], bbox_pred.weight
)
m[weight_names["mask_fcn_logits"]] = _copy_weight(
m[weight_names["mask_fcn_logits"]], mask_fcn_logits.weight
)
m[bias_names["cls_score"]] = _copy_bias(
m[bias_names["cls_score"]], cls_score.bias
)
m[bias_names["bbox_pred"]] = _copy_bias(
m[bias_names["bbox_pred"]], bbox_pred.bias, class_agnostic
)
m[bias_names["mask_fcn_logits"]] = _copy_bias(
m[bias_names["mask_fcn_logits"]], mask_fcn_logits.bias
)
print("f: {}\nout_file: {}".format(f, out_file))
torch.save(m, out_file)
對最後一層進行手術的兩種示例:
Download the model from MODEL_ZOO
wget https://download.pytorch.org/models/maskrcnn/e2e_mask_rcnn_X_101_32x8d_FPN_1x.pth
// Load the model in python
python
import torch
model = torch.load("e2e_mask_rcnn_X_101_32x8d_FPN_1x.pth ")
// Remove the previous training parameters.
del model['iteration']
del model['scheduler']
del model['optimizer']
// Remove the output layers in COCO, these are the mismatched layers you saw.
//Second stage prediction
del model["model"]["module.roi_heads.box.predictor.cls_score.weight"]
del model["model"]["module.roi_heads.box.predictor.cls_score.bias"]
del model["model"]["module.roi_heads.box.predictor.bbox_pred.weight"]
del model["model"]["module.roi_heads.box.predictor.bbox_pred.bias"]
//mask prediction
del model["model"]["module.roi_heads.mask.predictor.mask_fcn_logits.weight"]
del model["model"]["module.roi_heads.mask.predictor.mask_fcn_logits.bias"]
// RPN
del model["model"]["module.rpn.head.cls_logits.weight"]
del model["model"]["module.rpn.head.cls_logits.bias"]
del model["model"]["module.rpn.head.bbox_pred.weight"]
del model["model"]["module.rpn.head.bbox_pred.bias"]
//save the model
torch.save(model, "modified_model.pth")
Then use modified_model.pth in your MODEL.WEIGHT
def delete_net_weights_for_finetune(
model_file,
out_file,
rpn_final_convs=False,
bbox_final_fcs=True,
mask_final_conv=True
):
del_keys = []
checkpoint = torch.load(model_file)
print("keys: {}".format(checkpoint.keys()))
m = checkpoint['model']
if rpn_final_convs:
# 'module.rpn.anchor_generator.cell_anchors.0',
# 'module.rpn.anchor_generator.cell_anchors.1',
# 'module.rpn.anchor_generator.cell_anchors.2',
# 'module.rpn.anchor_generator.cell_anchors.3',
# 'module.rpn.anchor_generator.cell_anchors.4'
# 'module.rpn.head.cls_logits.weight',
# 'module.rpn.head.cls_logits.bias',
# 'module.rpn.head.bbox_pred.weight',
# 'module.rpn.head.bbox_pred.bias',
del_keys.extend([
k for k in m.keys() if k.find("rpn.anchor_generator") is not -1
])
del_keys.extend([
k for k in m.keys() if k.find("rpn.head.cls_logits") is not -1
])
del_keys.extend([
k for k in m.keys() if k.find("rpn.head.bbox_pred") is not -1
])
if bbox_final_fcs:
# 'module.roi_heads.box.predictor.cls_score.weight',
# 'module.roi_heads.box.predictor.cls_score.bias',
# 'module.roi_heads.box.predictor.bbox_pred.weight',
# 'module.roi_heads.box.predictor.bbox_pred.bias',
del_keys.extend([
k for k in m.keys() if k.find(
"roi_heads.box.predictor.cls_score"
) is not -1
])
del_keys.extend([
k for k in m.keys() if k.find(
"roi_heads.box.predictor.bbox_pred"
) is not -1
])
if mask_final_conv:
# 'module.roi_heads.mask.predictor.mask_fcn_logits.weight',
# 'module.roi_heads.mask.predictor.mask_fcn_logits.bias',
del_keys.extend([
k for k in m.keys() if k.find(
"roi_heads.mask.predictor.mask_fcn_logits"
) is not -1
])
for k in del_keys:
print("del k: {}".format(k))
del m[k]
# checkpoint['model'] = m
print("f: {}\nout_file: {}".format(f, out_file))
recursively_mkdirs(os.path.dirname(out_file))
torch.save({"model": m}, out_file)