项目目录:
制作自己的数据集
运行&解析小训练脚本
1.运行&解析小训练脚本
代码基于keras
先上个github(和上集一样):
https://github.com/2206487433/deep-learning-explorer-master
label分别是正方形、三角形、圆形
初步了解语义分割的同学,从了解这个项目开始是非常合适的。
先介绍一下小项目文件:
data:看上一集
logs:运行代码后保存的权重
mask-rcnn:主代码
pycococreatortools:将数据集转换为COCO类型(这里是类型,不是格式)
这一节不会详细解析mask-rcnn,因为mask-rcnn工程量挺大的。
我们进入deep-learning-explorer-master\mask-rcnn\notebooks\mask_rcnn.ipynb
进行直接训练:
import os
import sys
import random
import math
import re
import time
import numpy as np
import cv2
import matplotlib
import matplotlib.pyplot as plt
# 插入要调用文件夹的路径
sys.path.insert(0, '../libraries')
from mrcnn.config import Config
import mrcnn.utils as utils
import mrcnn.model as modellib
import mrcnn.visualize as visualize
from mrcnn.model import log
import mcoco.coco as coco
import mextra.utils as extra_utils
%matplotlib inline
%config IPCompleter.greedy=True
# 数据集和权重的路径 ../表示回到上一级目录
DATA_DIR = r"../../data/shapes"
WEIGHTS_DIR = r"../../data/shapes/weights"
MODEL_DIR = r"../../logs"
# 初始化权重的路径
COCO_MODEL_PATH = os.path.join(WEIGHTS_DIR, "mask_rcnn_coco.h5")
# 如果初始化权重不存在就下载
if not os.path.exists(COCO_MODEL_PATH):
utils.download_trained_weights(COCO_MODEL_PATH)
这里没有提供,权重建议网上下载后放到目录下,不然太慢。
coco权重链接:https://pan.baidu.com/s/1drKvfg 密码:yer9
图片展示时调用到:
def get_ax(rows=1, cols=1, size=8):
"""返回要在其中使用的Matplotlib轴数组
在笔记本上的所有可视化。提供一个
控制图形大小的中心点。
更改默认大小属性以控制大小
渲染图像
"""
_, ax = plt.subplots(rows, cols, figsize=(size*cols, size*rows))
return ax
调用数据集,训练、验证、测试:
调用专门加载coco数据集的模块
dataset_train = coco.CocoDataset()
dataset_train.load_coco(DATA_DIR, subset="shapes_train", year="2018")
dataset_train.prepare()
dataset_validate = coco.CocoDataset()
dataset_validate.load_coco(DATA_DIR, subset="shapes_validate", year="2018")
dataset_validate.prepare()
dataset_test = coco.CocoDataset()
dataset_test.load_coco(DATA_DIR, subset="shapes_test", year="2018")
dataset_test.prepare()
加载图片展示:
我们加载的是训练集,随机选取id进行图片加载.
获取id后加载出相应的图片数组image.
用load_mask获取相应图片的标记掩码(mask)[bool类型] 和 label类别对应的id号(class_ids).
mask意思是背景为False前景为True,从而显示出label
image_ids = np.random.choice(dataset_train.image_ids, 4)
for image_id in image_ids:
image = dataset_train.load_image(image_id)
mask, class_ids = dataset_train.load_mask(image_id)
visualize.display_top_masks(image, mask, class_ids, dataset_train.class_names)
Configuration基本上聚集了所有参数
有些参数还不知道什么意思,正在学习中。
GPU_COUNT:cup使用数量
IMAGES_PER_GPU:在处理锚框时替代batch,作每次输入图片数量
NUM_CLASSES:背景+类别
IMAGE_MAX_DIM:输入图片的大小
RPN_ANCHOR_SCALES:
TRAIN_ROIS_PER_IMAGE:
STEPS_PER_EPOCH:训练集训练批次次数
VALIDATION_STEPS:验证集训练批次次数
image_size = 64
rpn_anchor_template = (1, 2, 4, 8, 16) # anchor sizes in pixels
rpn_anchor_scales = tuple(i * (image_size // 16) for i in rpn_anchor_template)
class ShapesConfig(Config):
"""Configuration for training on the shapes dataset.
"""
NAME = "shapes"
# Train on 1 GPU and 2 images per GPU. Put multiple images on each
# GPU if the images are small. Batch size is 2 (GPUs * images/GPU).
GPU_COUNT = 1
IMAGES_PER_GPU = 1
# Number of classes (including background)
NUM_CLASSES = 1 + 3 # background + 3 shapes (triangles, circles, and squares)
# Use smaller images for faster training.
IMAGE_MAX_DIM = image_size
IMAGE_MIN_DIM = image_size
# Use smaller anchors because our image and objects are small
RPN_ANCHOR_SCALES = rpn_anchor_scales
# Aim to allow ROI sampling to pick 33% positive ROIs.
TRAIN_ROIS_PER_IMAGE = 32
STEPS_PER_EPOCH = 400
VALIDATION_STEPS = STEPS_PER_EPOCH / 20
config = ShapesConfig()
config.display()
加载训练过之后的model
没有就跳过
model = modellib.MaskRCNN(mode="training", config=config, model_dir=MODEL_DIR)
判断加载初始化权重
我们这里用的是coco权重
inititalize_weights_with = "coco" # imagenet, coco, or last
if inititalize_weights_with == "imagenet":
model.load_weights(model.get_imagenet_weights(), by_name=True)
elif inititalize_weights_with == "coco":
model.load_weights(COCO_MODEL_PATH, by_name=True,
exclude=["mrcnn_class_logits", "mrcnn_bbox_fc",
"mrcnn_bbox", "mrcnn_mask"])
elif inititalize_weights_with == "last":
# Load the last model you trained and continue training
model.load_weights(model.find_last()[1], by_name=True)
train-1
阉割训练
获取训练集和验证集
学习率
迭代次数
layers='heads':只用头部网络进行训练(这样我这烂电脑就可以使用)
model.train(dataset_train, dataset_validate,
learning_rate=config.LEARNING_RATE,
epochs=2,
layers='heads')
train-2
这一次用全部网络进行训练
model.train(dataset_train, dataset_validate,
learning_rate=config.LEARNING_RATE / 10,
epochs=3, # starts from the previous epoch, so only 1 additional is trained
layers="all")
Detection
InferenceConfig继承权重修改权重
这里用的是验证(inferencec)模型与训练(train)模型有一定区别,获取权重路径
加载训练好的权重(我没有提供训练好的权重,没有必要,自己训练就行)
class InferenceConfig(ShapesConfig):
GPU_COUNT = 1
IMAGES_PER_GPU = 1
inference_config = InferenceConfig()
model = modellib.MaskRCNN(mode="inference",
config=inference_config,
model_dir=MODEL_DIR)
print(model.find_last()[1])
model_path = model.find_last()[1]
assert model_path != "", "Provide path to trained weights"
print("Loading weights from ", model_path)
model.load_weights(model_path, by_name=True)
获取本地图片验证图片
随机id获取图片
用modellib.load_image_gt获取图片信息:
original_image:图片数组
image_meta:(不知何用)
gt_class_id:类别对应的id
gt_bbox:锚框坐标(记住是框)(坐标是[x, y, h, w]就可以定义一个框)
gt_mask:填充label的值(bool类型)
然后用获取得到的信息来展示标记后的图片。
下面model.detect用来获取验证后图片的标记信息(这信息带有scores分数),然后展示图片
image_id = random.choice(dataset_test.image_ids)
original_image, image_meta, gt_class_id, gt_bbox, gt_mask =\
modellib.load_image_gt(dataset_test, inference_config,
image_id, use_mini_mask=False)
log("original_image", original_image)
log("image_meta", image_meta)
log("gt_class_id", gt_class_id)
log("gt_bbox", gt_bbox)
log("gt_mask", gt_mask)
visualize.display_instances(original_image, gt_bbox, gt_mask, gt_class_id,
dataset_train.class_names, figsize=(8, 8))
results = model.detect([original_image], verbose=1)
r = results[0]
visualize.display_instances(original_image, r['rois'], r['masks'], r['class_ids'],
dataset_test.class_names, r['scores'], ax=get_ax())
输出图片中,有锚框,有填充颜色
评分
调用模块评分
predictions =\
extra_utils.compute_multiple_per_class_precision(model, inference_config,
dataset_test, number_of_images=25, iou_threshold=0.5)
complete_predictions = []
for shape in predictions:
complete_predictions += predictions[shape]
print("{} ({}): {}".format(shape, len(predictions[shape]), np.mean(predictions[shape])))
print("--------")
print("average: {}".format(np.mean(complete_predictions)))
也是展示图片
与上面的图片一样,但展示的方法不同
extra_utils.result_to_coco获取图片的各种信息后转化成coco的json格式,然后用这个格式进行展示,也就说明了这里内置了一个转化成coco的json的函数,需要转化时可以进行调用。
把转化的json写成临时文件,所以这里很容易出错,理解代码后可以适当进行修改
json.dump()是将str转化成dict格式,但要和文件操作结合起来了。
然后把json写进COCO中可能是要后面的调用用到(我也不是很明白,就这样理解先)
import json
import pylab
import matplotlib.pyplot as plt
from tempfile import NamedTemporaryFile
from pycocotools.coco import COCO
coco_dict = extra_utils.result_to_coco(results[0], dataset_test.class_names,
np.shape(original_image)[0:2], tolerance=0)
# coco_dict = coco_dict.split(" ")
NamedTemporaryFile(delete=False)
print(coco_dict)
import os
with NamedTemporaryFile('w', delete=False) as jsonfile:
json.dump(coco_dict, jsonfile)
jsonfile.flush()
coco_data = COCO(jsonfile.name)
前面几行用于展示图片,展示的是没有标记的图片
之后是在图片的基础上加标记颜色
这里的图片展示方法与前面不同的是:前面用rois锚框和mask值来显示图片,这里用的是coco格式的json(上一级有介绍)所以颜色填充时填充并不完整。
category_ids = coco_data.getCatIds(catNms=['square', 'circle', 'triangle'])
image_data = coco_data.loadImgs(1)[0]
image = original_image
plt.imshow(image);
plt.axis('off') # 是否显示横线
pylab.rcParams['figure.figsize'] = (8.0, 10.0)
annotation_ids = coco_data.getAnnIds(imgIds=image_data['id'], catIds=category_ids, iscrowd=None)
annotations = coco_data.loadAnns(annotation_ids)
coco_data.showAnns(annotations)