如何使用RetinaNet模型构建面罩检测器!
在自动驾驶,视频监视,医疗应用和许多其他领域所需的计算机视觉中,对象检测是极为重要的领域。
我们正在努力应对前所未有的大规模流行病。全球各地的研究人员都在疯狂地尝试开发疫苗或COVID-19的疗法,而医生只是在防止这种流行病席卷整个世界。另一方面,许多国家发现社会疏远,使用口罩和手套可以稍微缓解这种情况。
我最近有一个想法,将我的
深度学习知识应用于当前情况。在本文中,我将向您介绍RetinaNet的实现,而它的背景知识并不多,并且正在研究中。
顶上的樱桃?我们将使用RetinaNet构建“面罩检测器”,以帮助我们应对这一持续的大流行。您可以推断相同的想法,为您的智能家居构建支持AI的解决方案。这种支持AI的解决方案仅对戴着口罩和手套的人敞开大门。
随着无人机的成本随着时间的推移而降低,我们看到了航空数据生成中的巨大峰值。因此,您可以使用此RetinaNet模型来检测空中图像甚至卫星图像中的不同对象(例如汽车(自行车,汽车等)或行人),以解决您的不同业务问题。
因此,您看到对象检测模型的应用层出不穷。
目录
什么是RetinaNet
需要RetinaNet
RetinaNet的架构
骨干网
用于对象分类的子网
子网用于对象回归
焦点损失
使用RetinaNet模型构建面罩检测器
收集资料
创建数据集
模型训练
模型测试
最后说明
什么是RetinaNet:–
RetinaNet是最好的一阶段对象检测模型之一,已被证明可以很好地处理密集和小规模的对象。因此,它已成为我们在航空和卫星图像中使用的流行对象检测模型。
 需要RetinaNet:–
RetinaNet由Facebook AI Research引入,旨在解决密集检测问题。在处理极端前景背景类时,需要填补诸如YOLO和SSD等单次目标检测器的不平衡和不一致性。
RetinaNet的体系结构:–
本质上,RetinaNet是一个由以下组成的复合网络:
骨干网(即自下而上的路径+自上而下的具有横向连接的路径,例如ResNet + FPN)
用于对象分类的子网
子网用于对象回归
使用RetinaNet的面罩检测器:RetinaNet体系结构图片来源
为了更好地理解,让我们分别了解架构的每个组成部分-
骨干网
自下而上的路径:–自下而上的路径(例如ResNet)用于特征提取。因此,无论输入图像的大小如何,它都会以不同的比例来计算特征图。
具有横向连接的自上而下的路径:–自上而下的路径从较高的金字塔等级对空间上较粗糙的特征图进行上采样,并且横向连接将具有相同空间大小的自上而下的层和自下而上的层合并。尽管在语义上更强大,但往往具有较小的分辨率。因此,更适合于检测较大的物体;相反,来自较低级特征图的网格单元具有高分辨率,因此更擅长检测较小的对象(参见图6 4)。)。因此,通过自上而下的路径及其与路径的自下而上的横向连接的组合,这些操作不需要太多额外的计算,因此生成的特征图的每个级别在语义和空间上都可以很强。因此,该体系结构是规模不变的,可以在速度和准确性方面提供更好的性能。
用于对象分类的子网
完全卷积网络(FCN)附加到每个FPN级别以进行对象分类。如上图所示,该子网包含3 * 3卷积层和256个滤镜,再加上另一个3 * 3卷积层和K * A滤镜。因此,输出要素图的大小为W * H * KA,其中W&H与输入要素图的宽度和高度成比例,而K&A分别是对象类别和锚点框的数量。
最后,将Sigmoid层(不是softmax)用于对象分类。
最后一个卷积层具有KA过滤器的原因是,如果从最后一个卷积层获得的特征图中每个位置的锚框提议数量为“ A”,则每个锚框都有可能被分类为K类数。因此,输出特征图的大小为KA通道或过滤器。
子网用于对象回归
回归子网与分类子网并行连接到FPN的每个特征图。回归子网的设计与分类子网的设计相同,不同之处在于最后一个卷积层的大小为3 * 3,带有4个过滤器,导致输出特征图的大小为W * H * 4A。
最后一个卷积层具有4个过滤器的原因是,为了定位类对象,回归子网为每个锚定框生成4个数字,以预测锚定框之间的相对偏移(以中心坐标,宽度和高度为单位)还有地面真相箱 因此,回归子网的输出特征图具有4A滤波器或通道。
焦点损失
Focal Loss(FL)是Cross-Entropy Loss(CE)的改进版本,它通过为硬的或容易错误分类的示例(例如,具有嘈杂纹理或部分对象或我们感兴趣的对象的背景)分配更多权重,尝试处理类不平衡问题),并简化简单的示例(即背景对象)。
因此,“焦点损失”减少了简单示例带来的损失贡献,并增加了纠正错误分类的示例的重要性。焦距损失只是交叉熵损失函数的扩展,它将降低简单示例的权重,并将训练重点放在硬底片上。
因此,为了实现这些研究人员的建议,
交叉熵损失为1- pt,可调聚焦参数≥0。RetinaNet物体检测方法使用焦距损失的α平衡变量,其中α= 0.25,γ= 2效果最佳。
使用RetinaNet的面罩检测器:焦点损失图片来源 
因此,焦点损失可以定义为–
使用RetinaNet的面罩检测器:公式
对于γ∈[0
当示例分类错误并且p t小时,调制因子接近1,并且不会影响损耗。
当p t →1时,该因子变为0,并且对分类良好的示例的损失进行了权衡。
聚焦参数γ平滑地调整了简单示例的权重。随着γ的增加,调制因子的作用也同样增加。(经过大量实验和试验,研究人员发现γ= 2最有效)
注意:-当γ= 0时,FL等效于CE。图中蓝色曲线
直观上,调制因子减少了简单示例的损耗贡献,并扩展了示例接收低损耗的范围。
您可以在本文中详细了解焦点损失(链接至我的焦点损失文章。),在这里,我谈到了交叉熵到焦点损失的演变,焦点损失的必要性,焦点损失与交叉熵的比较。
最重要的是,我用几个例子来说明为什么焦点损失比交叉熵更好。
现在,让我们看看RetinaNet的实现,以Python来构建Face Mask Detector –
使用RetinaNet模型构建面罩检测器
收集资料
任何深度学习模型都需要大量的训练数据才能在测试数据上获得良好的结果。在本文(链接到我的Web剪贴文章)中,我讨论了Web剪贴方法来为您的深度学习项目收集大量图像。
创建数据集:–
我们首先使用工具LabelImg为训练和验证数据集创建注释 。这个出色的注释工具可让您快速注释对象的边界框,以训练
机器学习模型。
您可以在anaconda命令提示符下使用以下命令安装它
点安装标签
您可以使用如下所示的labelmg工具为每个JPEG文件添加注释,它将生成带有每个边界框坐标的XML文件。我们将使用这些xml文件来训练我们的模型。
使用RetinaNet的面罩检测器:xml文件
模型培训:–
第1步。克隆并安装keras-retinanet存储库?
导入 os
打印(os.getcwd())
git clone 
https://github.com/fizyr/keras-retinanet.git
%cd keras-retinanet /
!pip安装。
!python setup.py build_ext --inplace
第2步。导入所有必需的库
将numpy导入为np
进口壁垒
将熊猫作为pd导入
导入os,sys,随机
将xml.etree.ElementTree导入为ET
将熊猫作为pd导入
从os import listdir
从os.path导入isfile,加入
导入matplotlib.pyplot作为plt
从PIL导入图片
汇入要求
导入urllib
从keras_retinanet.utils.visualization中导入draw_box,draw_caption,label_color
从keras_retinanet.utils.image导入preprocess_image,resize_image
第三步 导入JPEG和xml数据
pngPath ='C:/用户/ PraveenKumar / RetinaNet // maskDetectorJPEGImages /'
annotPath ='C:/ Users / PraveenKumar / RetinaNet // maskDetectorXMLfiles /'
data = pd.DataFrame(columns = ['fileName','xmin','ymin','xmax','ymax','class'])
os.getcwd()
#阅读的所有文件
allfiles = [F为?F在listdir同时(annotPath)如果ISFILE(合并(annotPath,F))]
#先读取图像中的所有pdf文件,然后读取文本中的文件,并将其存储在temp文件夹中 
#先读取图像中的所有pdf文件,然后读取文本中的文件,并将其存储在temp文件夹中
对于所有文件中的文件:
#print(文件)
如果(file.split(“。”)[1] =='xml'):
fileName ='C:/ Users / PraveenKumar / RetinaNet / maskDetectorJPEGImages /'+ file.replace(“。xml”,'。jpg')
        树= ET.parse(annotPath + file)
        根= tree.getroot()
        对于root.iter('object')中的obj:
            cls_name = obj.find('名称').text
            xml_box = obj.find('bndbox')
            xmin = xml_box.find('xmin')。text
            ymin = xml_box.find('ymin')。text
            xmax = xml_box.find('xmax')。text
            ymax = xml_box.find('ymax')。text
            #通过添加字典在空数据框中添加行
            数据= data.append({'fileName':fileName,'xmin':xmin,'ymin':ymin,'xmax':xmax,'ymax':ymax,'class':cls_name},ignore_index = True)
数据形状
第三步 编写函数以显示训练数据集上的边界框
 #选择一个随机图像
  filepath = df.sample()['fileName']。values [0]
  #获取该图像的所有行
  df2 = df [df ['fileName'] ==文件路径]
  我= np.array(Image.open(文件路径))
  #如果有PNG,它将具有Alpha通道
  im = im [:,:,:3]
  对于idx,在df2.iterrows()中行:
    框= [
      行['xmin'],
      行['ymin'],
      行['xmax'],
      行['ymax'],
    ]
    打印(盒)
    draw_box(im,box,color = {255,0,0))
  plt.axis('off')
  plt.imshow(im)
  plt.show()                        
show_image_with_boxes(数据)
使用RetinaNet的面罩检测器:面罩
#检查几条数据
data.head()的记录
使用RetinaNet的面罩检测器:头部
#定义标签并将其写入文件
classes = ['mask','noMask']
与开放( '../ maskDetectorClasses.csv', 'W')作为F:
  对于I,CLASS_NAME在枚举(类):
    f.write(f' {class_name},{i} \ n ')         
如果 不是os.path.exists('snapshots'):
  os.mkdir('快照')
注意:–最好从预先训练的模型开始,而不是从头开始训练模型。我们将使用已经在Coco数据集上进行过预训练的ResNet50模型。
URL_MODEL ='https://github.com/fizyr/keras-retinanet/releases/download/0.5.1/resnet50_coco_best_v2.1.0.h5'
urllib.request.urlretrieve(URL_MODEL,PRETRAINED_MODEL)
步骤4。训练RetinaNet模型
注意:–如果您使用的是Google Colab,则可以使用下面的代码片段来训练模型。
#放入带有训练数据标签的训练数据路径和文件
!keras_retinanet / bin / train.py --freeze-backbone \ --random-transform \ --weights {PRETRAINED_MODEL} \ --batch-size 8 \-步骤500 \-时期15 \ csv ma??skDetectorData.csv ma??skDetectorClasses.csv
但是,如果您正在使用本地Jupyter笔记本电脑或其他IDE进行培训,则可以在命令提示符下输入以下命令
python keras_retinanet / bin / train.py --freeze-backbone 
            --random-transform \
            --weights {PRETRAINED_MODEL} 
            -批量大小8 
            -步骤500 
            -纪元15  
            csv ma??skDetectorData.csv ma??skDetectorClasses.csv
让我们分析传递给脚本train.py的每个参数。
冻结主干:冻结主干层,当我们使用较小的数据集时特别有用,以避免过度拟合
random-transform:随机变换数据集以获得数据扩充
权重:使用预先训练的模型(您自己的模型或Fizyr发布的模型)初始化模型
批处理大小:训练批处理大小,值越高给出的学习曲线越平滑
步数:纪元的步数
纪元:要训练的纪元数
csv:以上脚本生成的注释文件
第五步 负荷训练模型
从 glob 导入glob
model_paths = glob('快照/resnet50_csv_0*.h5')
Latest_Path = Sorted(model_paths)[-1]
打印(“路径:”,latest_path)
从 keras_retinanet 导入模型
模型= models.load_model(latest_path,beabel_name ='resnet50')
型号= models.convert_model(型号)
label_map = {}
对于线在开( '../ maskDetectorClasses.csv'):
  行= line.rstrip()。split(',')
  label_map [int(row [1])] =第[0]行
模型测试:–
第六步 使用训练有素的模型进行预测
#编写函数以从数据集中随机选择一张图像,并使用训练模型进行预测。
def show_image_with_predictions(df,threshold = 0.6):
   #选择一个随机图像
  行= df.sample()
  filepath = row ['fileName']。values [0]
  print(“ filepath:”,文件路径)
  #获取该图像的所有行
  df2 = df [df ['fileName'] ==文件路径]
  我= np.array(Image.open(文件路径))
  print(“ im.shape:”,im.shape)
  #如果有PNG,它将具有Alpha通道
  im = im [:,:,:3]
  #
  在df2.iterrows()中为idx绘制真实的框:
    框= [
      行['xmin'],
      行['ymin'],
      行['xmax'],
      行['ymax'],
    ]
    打印(盒)
    draw_box(im,box,color = {255,0,0))
  ###剧情预测###
  #获取预测
  小鬼= preprocess_image(im)
  小鬼,比例= resize_image(im)
  盒子,分数,标签= model.predict_on_batch(
    np.expand_dims(imp,axis = 0)
  )
  #标准化框坐标
  框/ =比例
  #通过每个预测针对输入图像循环
  为框,得分,标签在拉链(盒[0],分数[0],标签[0]):
    #分数进行排序,以便我们能够尽快退出
    ,因为我们看到一个得分#
    如果得分<阈值以下,则低于阈值:
      断裂
    box = box.astype(np.int32)
    颜色= label_color(标签)
    draw_box(im,box,color = color)
    class_name = label_map
    caption = f“ {class_name}  {score:.3f} ”
    draw_caption(IM,方框,标题)
    分数,标签=分数,标签
  plt.axis('off')
  plt.imshow(im)
  plt.show()
  返回分数,标签
plt.rcParams ['figure.figsize'] = [20,10]
#根据您的业务需求分数随意更改阈值,
label = show_image_with_predictions(data,threshold = 0.6)
使用RetinaNet的面罩检测器:图像
#根据您的业务需求分数随意更改阈值,
label = show_image_with_predictions(data,threshold = 0.6)
#根据您的业务需求得分随意更改,
label = show_image_with_predictions(data,threshold = 0.6)
#根据您的业务需求得分随意更改,
label = show_image_with_predictions(data,threshold = 0.6)
#根据您的业务需求得分随意更改,
label = show_image_with_predictions(data,threshold = 0.6)
#根据您的业务需求
得分随意更改,label = show_image_with_predictions(数据,阈值= 0.6)
#根据您的业务需求
得分随意更改,label = show_image_with_predictions(数据,阈值= 0.6)
#根据您的业务需求
得分随意更改,label = show_image_with_predictions(数据,阈值= 0.6)
题库