YOLO是“You Only Look Once”的简称,它虽然不是最精确的算法,但在精确度和速度之间选择的折中,效果也是相当不错。YOLOv3借鉴了YOLOv1和YOLOv2,虽然没有太多的创新点,但在保持YOLO家族速度的优势的同时,提升了检测精度,尤其对于小物体的检测能力。YOLOv3算法使用一个单独神经网络作用在图像上,将图像划分多个区域并且预测边界框和每个区域的概率。
成都创新互联主营天桥网站建设的网络公司,主营网站建设方案,app软件开发公司,天桥h5小程序设计搭建,天桥网站营销推广欢迎天桥等地区企业咨询
YOLOv3仅使用卷积层,使其成为一个全卷积网络(FCN)。文章中,作者提出一个新的特征提取网络,Darknet-53。正如其名,它包含53个卷积层,每个后面跟随着batch normalization层和leaky ReLU层。没有池化层,使用步幅为2的卷积层替代池化层进行特征图的降采样过程,这样可以有效阻止由于池化层导致的低层级特征的损失。Darknet-53网络如下图左边所示。
输入是 。输出是带有识别类的边界框列表,每个边界框由 六个参数表示。如果 表示80个类别,那么每个边界框由85个数字表示。
在YOLO中,预测过程使用一个 卷积,所以输入是一个特征图。由于使用 卷积,因此预测图正好是特征图大小( 卷积只是用于改变通道数)。在YOLOv3中,此预测图是每个cell预测固定数量的边界框。
如上图所示,预测图的深度为75,假设预测图深度为 , 表示每个cell可以预测的边界框数量。这些 个边界框可以指定检测到一个物体。每个边界框有 个特征,分别描述中心点坐标和宽高(四个)和物体分数(一个)以及 个类置信度(上图中 )。YOLOv3每个cell预测三个边界框。
如果对象的中心(GT框中心)落在该cell感受野范围内,我们希望预测图的每个单元格都能通过其中一个边界框预测对象。其中只有一个边界框负责检测物体,首先我们需要确定此边界框属于哪个cell。
为了实现上面的想法,我们将原始图像分割为最后预测图维度大小的网格。如下图所示,输入图像维度为 ,步幅为32(最后的预测图降采样32倍),最后预测图维度为 ,所以我们将原始图像划分为 的网格。
直接预测框的宽高会导致训练时不稳定的梯度问题,因此,现在的很多目标检测方法使用log空间转换或者简单的偏移(offset)到称为锚框的预定义默认边界框。然后将这些变换应用到锚框以获得预测,YOLOv3具有三个锚框,可以预测每个单元格三个边界框。
锚框是边界框的先验,是使用k均值聚类在COCO数据集上计算的。我们将预测框的宽度和高度,以表示距聚类质心的偏移量。
以下公式描述了如何转换网络输出以获得边界框预测:
这里 分别是我们预测的中心坐标、宽度和高度。 是网络的输出。 是网格从顶左部的坐标。 是锚框的维度(见下图)。
通过sigmoid函数进行中心坐标预测,强制将值限制在0和1之间。YOLO不是预测边界框中心的绝对坐标,它预测的是偏移量:相对于预测对象的网格单元的左上角;通过特征图cell归一化维度。
例如,考虑上面狗的图像。如果预测中心坐标是 ,意味着中心在 (因为红色框左上角坐标是 )。但是如果预测的坐标大于1,例如 ,意味着中心在 ,现在中心在红色框右边,但是我们只能使用红色框对对象预测负责,所以我们添加一个sidmoid函数强制限制在0和1之间。
通过对输出应用对数空间转换,然后与锚框相乘,可以预测边界框的尺寸(如上面的计算公式)。
物体分数表示一个边界框包含一个物体的概率,对于红色框和其周围的框几乎都为1,但边角的框可能几乎都为0。物体分数也通过一个sigmoid函数,表示概率值。
类置信度表示检测到的物体属于一个具体类的概率值,以前的YOLO版本使用softmax将类分数转化为类概率。在YOLOv3中作者决定使用sigmoid函数取代,原因是softmax假设类之间都是互斥的,例如属于“Person”就不能表示属于“Woman”,然而很多情况是这个物体既是“Person”也是“Woman”。
为了识别更多的物体,尤其小物体,YOLOv3使用三个不同尺度进行预测(不仅仅只使用 )。三个不同尺度步幅分别是32、16和8。这意味着,输入 图像,检测尺度分别为 、 和 (如下图或者更详细如图2所示)。
YOLOv3为每种下采样尺度设定3个先验框,总共聚类9个不同尺寸先验框。在COCO数据集上9个先验框分别是: 。下表是9个先验框分配情况:
我们的网络生成10647个锚框,而图像中只有一个狗,怎么将10647个框减少为1个呢?首先,我们通过物体分数过滤一些锚框,例如低于阈值(假设0.5)的锚框直接舍去;然后,使用NMS(非极大值抑制)解决多个锚框检测一个物体的问题(例如红色框的3个锚框检测一个框或者连续的cell检测相同的物体,产生冗余),NMS用于去除多个检测框。
具体使用以下步骤:抛弃分数低的框(意味着框对于检测一个类信心不大);当多个框重合度高且都检测同一个物体时只选择一个框(NMS)。
为了更方便理解,我们选用上面的汽车图像。首先,我们使用阈值进行过滤一部分锚框。模型有 个数,每个盒子由85个数字描述。将 分割为下面的形状:box_confidence: 表示 个cell,每个cell5个框,每个框有物体的置信度概率;boxes: 表示每个cell5个框,每个框的表示;box_class_probs: 表示每个cell5个框,每个框80个类检测概率。
即使通过类分数阈值过滤一部分锚框,还剩下很多重合的框。第二个过程叫NMS,里面有个IoU,如下图所示。
下图给出更加详细的输入输出情况:
文章原文:
论文原文:
YOLOv3深入理解:
keras实现YOLOv3博客:
What new in YOLOv3?:
Method类中的方法的使用(含代码和注释):
getMethods()获得本类及父类中的public权限修饰**符方法
getDeclaredMethods()专门获得调用该方法的对象的本类中的所有方法包括private权限修饰符**的方法
getDeclaredMethod(String name,class?...parameterTypes)
第一个参数:方法的名称
第二个参数:可变长度,写你要查找的那个方法的参数类型列表.class
getParameterCount()得到方法的参数个数123456
package LessonForReflection03;import java.lang.reflect.Method;import java.lang.reflect.Modifier;abstract class Card{
private void creatRandomNumbers(int count)//private关键字
{
}
public void getFullCardsNumbers(String[] random, String pre_numbers)
{
}
public static void getUserInfor()
{
}
public abstract void getUserInfor(String tel);
public abstract void getUserInfor(int sal1, int sal2) throws ArrayIndexOutOfBoundsException,ArithmeticException;}public class MethodInforGetter {
public static void main(String[] args)
{
Class? c1 = Card.class;
System.out.println("-------------------------");
Method[] m1 = c1.getMethods();//getMethods()获得本类及父类中的public方法!
for (Method m:m1)
{
System.out.println(m);
}
System.out.println("-------------------------");
Method[] m2 = c1.getDeclaredMethods();//getDeclaredMethods()专门获得本类中的所有方法包括private!
for (Method m:m2)
{
System.out.println(m);
}
System.out.println("-------------------------");
/*
*getDeclaredMethod(String name,class?...parameterTypes)
*第一个参数:方法的名称
*第二个参数:可变长度,写你要查找的那个方法的参数类型列表
*
* getParameterCount()得到方法的参数个数
*/
try
{
Method m3 = c1.getDeclaredMethod("getUserInfor");
System.out.println(m3);
//getParameterCount()方法,获得方法参数个数
System.out.println(m3.getParameterCount());
System.out.println(Modifier.toString(m3.getModifiers()));//获得方法修饰符
System.out.println(m3.getReturnType());
System.out.println("-------------------------");
Method m4 = c1.getDeclaredMethod("getUserInfor", int.class,int.class);
//getExceptionTypes()可以获得初始化当前Method对象的给Class对象初始化的那个类的那个指定方法抛出的异常类型
Class?[] exception = m4.getExceptionTypes();
for (Class? e:exception)
{
System.out.println(e);
}
} catch (NoSuchMethodException | SecurityException e)
{
e.printStackTrace();
}
}}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
Constructor类中的方法的使用(含代码和注释):
java.lang.reflect.Constructor:
Constructor[] getConstructor()获得本类里的public权限修饰符构造函数,不能获取父类的!
Constructor[] getDeclaredConstructor()获得本类中的所以构造函数!
ConstructorT getConstructor(Class...parameterType)用参数决定获得本类中的某个的构造方法,只能获得public的
ConstructorT getDeclaredConstructor(Class...parameterType)用参数决定获得本类中的某个构造方法
附:
JDK8.0之后新增的类:
Executable:
它是Method和Constructor的父类
常用方法:
getParameter()获得类中方法参数
getExceptionTypes()获得类中某个方法抛出异常类型
getMoidfiers()获得方法权限修饰符
Parameter:
封装并代表了参数实例123456789101112131415
package LessonForReflection03;import java.lang.reflect.Constructor;import java.lang.reflect.Modifier;import java.lang.reflect.Parameter;/*
* java.lang.reflect.Constructor
*
* Constructor[] getConstructor();获得本类里的public权限修饰符构造函数,不能获取父类的
* Constructor[] getDeclaredConstructor();得本类里的全部构造
*
* ConstructorT getConstructor(Class...parameterType);用参数决定获得哪个构造方法
* ConstructorT getDeclaredConstructor(Class...parameterType);
*
*/public class ConstructorInforGetter {
public static void main(String[] args)
{
System.out.println("获得Cricle本类里的public权限修饰符构造函数,不能获取父类的Constructor[] getConstructor()");
System.out.println("子类继承不了父类中的构造方法和private");
//Constructor[] getConstructor()获得Cricle本类里的public权限修饰符构造函数,不能获取父类的
//子类继承不了父类中的构造方法和private
ClassCircle c1 = Circle.class;
Constructor?[] cons1 = c1.getConstructors();
for (Constructor? cons:cons1)
{
System.out.println(cons);
//System.out.println(cons.getName());
}
System.out.println("-----------------------");
System.out.println("方法获得本类中的所有构造函数getDeclaredConstructor()");
Constructor?[] cons2 = c1.getDeclaredConstructors();
for (Constructor? cons:cons2)
{
System.out.println(cons);
}
System.out.println("-----------------------");
try
{
System.out.println("方法用参数指定获得本类!构造方法,只能获取public的ConstructorT getConstructor(Class...parameterType)");
Constructor? cons3 = c1.getConstructor(int.class);
System.out.println(Modifier.toString(cons3.getModifiers()));
System.out.println(cons3);
System.out.println("-----------------------");
System.out.println("方法用参数指定获得本类!构造方法任何权限修饰符的都可以获得ConstructorT getDeclaredConstructor(Class...parameterType)");
Constructor? cons4 = c1.getDeclaredConstructor(String.class);
System.out.println(cons4);
System.out.println("-----------------------");
/*
* JDK8.0之后新增的类
* Executable:
* 是Method和Constructor的父类
* 方法:
* getParameter();
* getExceptionTypes();
* getModifiers();
* getTypeParameters();
*
* Parameter:
* 封装并代表了参数实例
*/
System.out.println("获取类中方法的参数getParameters()");
Constructor? cons5 = c1.getDeclaredConstructor(int.class,String.class);
Parameter[] p1 = cons5.getParameters();
for (Parameter p:p1)
{
System.out.println(p);
}
} catch (NoSuchMethodException | SecurityException e)
{
e.printStackTrace();
}
}}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
代码中提到的Circle类和Shape类二者为继承关系:
package LessonForReflection03;public class Circle extends Shape{
private int r;
private String color;
public Circle(int r, String color)
{
super();
this.r = r;
this.color = color;
}
public Circle(int r)
{
super();
this.r = r;
}
protected Circle(String color)
{
super();
this.color = color;
}
Circle()
{
super();
}}12345678910111213141516171819202122232425262728293031
package LessonForReflection03;public class Shape {
private int per;
public Shape(int per)
{
super();
this.per = per;
}
public Shape()
{
super();
}}1234567891011121314151617
部分文字来源于:
咕嘟咖啡杨海滨老师 — 《java编程语言高级特性》
轻量化研习Java相关技术倡导者
“爱码学院”联合创始人自适应教学理念提出者践行者;多年开发及项目管理经历;出版《JavaEE企业级应用与开发》一书;10余年高校项目实践毕设指导经验;企业软培经验丰富
因为sigmoid就是预测0到1之间的连续值。通常当二分类预测使用,你的问题是否复合二分类如果可以就把类别换成0和1就可以了,如果是做回归那就不行了,要换其他损失函数