YOLO是“You Only Look Once”的簡稱,它雖然不是最精確的算法,但在精確度和速度之間選擇的折中,效果也是相當不錯。YOLOv3借鑒了YOLOv1和YOLOv2,雖然沒有太多的創(chuàng)新點,但在保持YOLO家族速度的優(yōu)勢的同時,提升了檢測精度,尤其對于小物體的檢測能力。YOLOv3算法使用一個單獨神經(jīng)網(wǎng)絡作用在圖像上,將圖像劃分多個區(qū)域并且預測邊界框和每個區(qū)域的概率。
成都創(chuàng)新互聯(lián)主營天橋網(wǎng)站建設的網(wǎng)絡公司,主營網(wǎng)站建設方案,app軟件開發(fā)公司,天橋h5小程序設計搭建,天橋網(wǎng)站營銷推廣歡迎天橋等地區(qū)企業(yè)咨詢
YOLOv3僅使用卷積層,使其成為一個全卷積網(wǎng)絡(FCN)。文章中,作者提出一個新的特征提取網(wǎng)絡,Darknet-53。正如其名,它包含53個卷積層,每個后面跟隨著batch normalization層和leaky ReLU層。沒有池化層,使用步幅為2的卷積層替代池化層進行特征圖的降采樣過程,這樣可以有效阻止由于池化層導致的低層級特征的損失。Darknet-53網(wǎng)絡如下圖左邊所示。
輸入是 。輸出是帶有識別類的邊界框列表,每個邊界框由 六個參數(shù)表示。如果 表示80個類別,那么每個邊界框由85個數(shù)字表示。
在YOLO中,預測過程使用一個 卷積,所以輸入是一個特征圖。由于使用 卷積,因此預測圖正好是特征圖大小( 卷積只是用于改變通道數(shù))。在YOLOv3中,此預測圖是每個cell預測固定數(shù)量的邊界框。
如上圖所示,預測圖的深度為75,假設預測圖深度為 , 表示每個cell可以預測的邊界框數(shù)量。這些 個邊界框可以指定檢測到一個物體。每個邊界框有 個特征,分別描述中心點坐標和寬高(四個)和物體分數(shù)(一個)以及 個類置信度(上圖中 )。YOLOv3每個cell預測三個邊界框。
如果對象的中心(GT框中心)落在該cell感受野范圍內(nèi),我們希望預測圖的每個單元格都能通過其中一個邊界框預測對象。其中只有一個邊界框負責檢測物體,首先我們需要確定此邊界框?qū)儆谀膫€cell。
為了實現(xiàn)上面的想法,我們將原始圖像分割為最后預測圖維度大小的網(wǎng)格。如下圖所示,輸入圖像維度為 ,步幅為32(最后的預測圖降采樣32倍),最后預測圖維度為 ,所以我們將原始圖像劃分為 的網(wǎng)格。
直接預測框的寬高會導致訓練時不穩(wěn)定的梯度問題,因此,現(xiàn)在的很多目標檢測方法使用log空間轉(zhuǎn)換或者簡單的偏移(offset)到稱為錨框的預定義默認邊界框。然后將這些變換應用到錨框以獲得預測,YOLOv3具有三個錨框,可以預測每個單元格三個邊界框。
錨框是邊界框的先驗,是使用k均值聚類在COCO數(shù)據(jù)集上計算的。我們將預測框的寬度和高度,以表示距聚類質(zhì)心的偏移量。
以下公式描述了如何轉(zhuǎn)換網(wǎng)絡輸出以獲得邊界框預測:
這里 分別是我們預測的中心坐標、寬度和高度。 是網(wǎng)絡的輸出。 是網(wǎng)格從頂左部的坐標。 是錨框的維度(見下圖)。
通過sigmoid函數(shù)進行中心坐標預測,強制將值限制在0和1之間。YOLO不是預測邊界框中心的絕對坐標,它預測的是偏移量:相對于預測對象的網(wǎng)格單元的左上角;通過特征圖cell歸一化維度。
例如,考慮上面狗的圖像。如果預測中心坐標是 ,意味著中心在 (因為紅色框左上角坐標是 )。但是如果預測的坐標大于1,例如 ,意味著中心在 ,現(xiàn)在中心在紅色框右邊,但是我們只能使用紅色框?qū)ο箢A測負責,所以我們添加一個sidmoid函數(shù)強制限制在0和1之間。
通過對輸出應用對數(shù)空間轉(zhuǎn)換,然后與錨框相乘,可以預測邊界框的尺寸(如上面的計算公式)。
物體分數(shù)表示一個邊界框包含一個物體的概率,對于紅色框和其周圍的框幾乎都為1,但邊角的框可能幾乎都為0。物體分數(shù)也通過一個sigmoid函數(shù),表示概率值。
類置信度表示檢測到的物體屬于一個具體類的概率值,以前的YOLO版本使用softmax將類分數(shù)轉(zhuǎn)化為類概率。在YOLOv3中作者決定使用sigmoid函數(shù)取代,原因是softmax假設類之間都是互斥的,例如屬于“Person”就不能表示屬于“Woman”,然而很多情況是這個物體既是“Person”也是“Woman”。
為了識別更多的物體,尤其小物體,YOLOv3使用三個不同尺度進行預測(不僅僅只使用 )。三個不同尺度步幅分別是32、16和8。這意味著,輸入 圖像,檢測尺度分別為 、 和 (如下圖或者更詳細如圖2所示)。
YOLOv3為每種下采樣尺度設定3個先驗框,總共聚類9個不同尺寸先驗框。在COCO數(shù)據(jù)集上9個先驗框分別是: 。下表是9個先驗框分配情況:
我們的網(wǎng)絡生成10647個錨框,而圖像中只有一個狗,怎么將10647個框減少為1個呢?首先,我們通過物體分數(shù)過濾一些錨框,例如低于閾值(假設0.5)的錨框直接舍去;然后,使用NMS(非極大值抑制)解決多個錨框檢測一個物體的問題(例如紅色框的3個錨框檢測一個框或者連續(xù)的cell檢測相同的物體,產(chǎn)生冗余),NMS用于去除多個檢測框。
具體使用以下步驟:拋棄分數(shù)低的框(意味著框?qū)τ跈z測一個類信心不大);當多個框重合度高且都檢測同一個物體時只選擇一個框(NMS)。
為了更方便理解,我們選用上面的汽車圖像。首先,我們使用閾值進行過濾一部分錨框。模型有 個數(shù),每個盒子由85個數(shù)字描述。將 分割為下面的形狀:box_confidence: 表示 個cell,每個cell5個框,每個框有物體的置信度概率;boxes: 表示每個cell5個框,每個框的表示;box_class_probs: 表示每個cell5個框,每個框80個類檢測概率。
即使通過類分數(shù)閾值過濾一部分錨框,還剩下很多重合的框。第二個過程叫NMS,里面有個IoU,如下圖所示。
下圖給出更加詳細的輸入輸出情況:
文章原文:
論文原文:
YOLOv3深入理解:
keras實現(xiàn)YOLOv3博客:
What new in YOLOv3?:
Method類中的方法的使用(含代碼和注釋):
getMethods()獲得本類及父類中的public權(quán)限修飾**符方法
getDeclaredMethods()專門獲得調(diào)用該方法的對象的本類中的所有方法包括private權(quán)限修飾符**的方法
getDeclaredMethod(String?name,class?...parameterTypes)
第一個參數(shù):方法的名稱
第二個參數(shù):可變長度,寫你要查找的那個方法的參數(shù)類型列表.class
getParameterCount()得到方法的參數(shù)個數(shù)123456
package?LessonForReflection03;import?java.lang.reflect.Method;import?java.lang.reflect.Modifier;abstract?class?Card{
private?void?creatRandomNumbers(int?count)//private關(guān)鍵字
{
}
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)
*第一個參數(shù):方法的名稱
*第二個參數(shù):可變長度,寫你要查找的那個方法的參數(shù)類型列表
*
*?getParameterCount()得到方法的參數(shù)個數(shù)
*/
try?
{
Method?m3?=?c1.getDeclaredMethod("getUserInfor");
System.out.println(m3);
//getParameterCount()方法,獲得方法參數(shù)個數(shù)
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權(quán)限修飾符構(gòu)造函數(shù),不能獲取父類的!
Constructor[]?getDeclaredConstructor()獲得本類中的所以構(gòu)造函數(shù)!
ConstructorT?getConstructor(Class...parameterType)用參數(shù)決定獲得本類中的某個的構(gòu)造方法,只能獲得public的
ConstructorT?getDeclaredConstructor(Class...parameterType)用參數(shù)決定獲得本類中的某個構(gòu)造方法
附:
JDK8.0之后新增的類:
Executable:
它是Method和Constructor的父類
常用方法:
getParameter()獲得類中方法參數(shù)
getExceptionTypes()獲得類中某個方法拋出異常類型
getMoidfiers()獲得方法權(quán)限修飾符
Parameter:
封裝并代表了參數(shù)實例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權(quán)限修飾符構(gòu)造函數(shù),不能獲取父類的
*??Constructor[]?getDeclaredConstructor();得本類里的全部構(gòu)造
*
*??ConstructorT?getConstructor(Class...parameterType);用參數(shù)決定獲得哪個構(gòu)造方法
*??ConstructorT?getDeclaredConstructor(Class...parameterType);
*
*/public?class?ConstructorInforGetter?{
public?static?void?main(String[]?args)?
{
System.out.println("獲得Cricle本類里的public權(quán)限修飾符構(gòu)造函數(shù),不能獲取父類的Constructor[]?getConstructor()");
System.out.println("子類繼承不了父類中的構(gòu)造方法和private");
//Constructor[]?getConstructor()獲得Cricle本類里的public權(quán)限修飾符構(gòu)造函數(shù),不能獲取父類的
//子類繼承不了父類中的構(gòu)造方法和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("方法獲得本類中的所有構(gòu)造函數(shù)getDeclaredConstructor()");
Constructor?[]?cons2?=?c1.getDeclaredConstructors();
for?(Constructor??cons:cons2)
{
System.out.println(cons);
}
System.out.println("-----------------------");
try?
{
System.out.println("方法用參數(shù)指定獲得本類!構(gòu)造方法,只能獲取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("方法用參數(shù)指定獲得本類!構(gòu)造方法任何權(quán)限修飾符的都可以獲得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:
*??封裝并代表了參數(shù)實例
*/
System.out.println("獲取類中方法的參數(shù)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類二者為繼承關(guān)系:
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相關(guān)技術(shù)倡導者
“愛碼學院”聯(lián)合創(chuàng)始人自適應教學理念提出者踐行者;多年開發(fā)及項目管理經(jīng)歷;出版《JavaEE企業(yè)級應用與開發(fā)》一書;10余年高校項目實踐畢設指導經(jīng)驗;企業(yè)軟培經(jīng)驗豐富
因為sigmoid就是預測0到1之間的連續(xù)值。通常當二分類預測使用,你的問題是否復合二分類如果可以就把類別換成0和1就可以了,如果是做回歸那就不行了,要換其他損失函數(shù)