国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

目標檢測——YOLO系列學習(一)YOLOv1

這篇具有很好參考價值的文章主要介紹了目標檢測——YOLO系列學習(一)YOLOv1。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

YOLO可以說是單階段的目標檢測方法的集大成之作,必學的經典論文,從準備面試的角度來學習一下yolo系列。


YOLOv1

1.RCNN系列回顧

RCNN系列,無論哪種算法,核心思路都是Region Proposal(定位)+ classifier(修正定位+分類)。所以也被稱為兩階段算法。但是難以達到實時檢測的效果,因此yolov1將其修改為單階段的算法,yolov1雖然犧牲了一定的精度,但是檢測速度大幅提升,而后續(xù)的yolo版本在其之上改進,現(xiàn)在已經有yolov9和yolo-world了,成為主流的目標檢測模型。

2.YOLOv1

(部分內容和圖參考保姆級教程:圖解目標檢測算法YOLOv1 - 知乎 (zhihu.com))

論文原文:

1506.02640.pdf (arxiv.org)https://arxiv.org/pdf/1506.02640.pdf在講解過程中會出現(xiàn)很多專業(yè)詞匯,會挨著進行說明。

YOLOv1的核心思路就是舍棄Region Proposal這個極其耗時的過程,轉而進行回歸。怎么實現(xiàn)舍棄RP的,就是學習的關鍵。

(1)核心思想

采用利用整張圖作為網絡的輸入,將圖像劃分為S*S個grid,某一個grid只關注于預測物體中心在這個grid中的目標,整個網絡最后直接在輸出層回歸 bounding box 的位置和 bounding box 所屬的類別。

目標檢測——YOLO系列學習(一)YOLOv1,目標檢測,目標跟蹤,人工智能

Grid和Bouding Box

這里可能會產生一點誤解,故區(qū)分一下。

Grid:將圖片直接劃分為S*S個grid,位置是固定死的,比如上圖中,劃分為了7*7個grid。

Bouding Box:就是最后檢測出物體的框,如上圖中框住狗狗的紅色框,在算法流程中,可以用兩種數(shù)據(jù)形式表示,一種是使用中心坐標+長寬的形式(Cx,Cy,H,W),一種是使用左上和右下角點坐標的形式(x1,y1,x2,y2)。而每個框除了要包含位置信息,還包含了該框是否包含物體的置信度,這個置信度怎么計算的我們后面講解,這里只需要記住每個Bounding Box其實對應了5個數(shù)據(jù)。

置信度(Confidence)的計算

置信度就是算法的自信心得分,這個值越高,代表這個BoundigBox里越有可能包含物體。計算方式如下:

Pr(Object)為邊界框內存在對象的概率,若存在對象,Pr?(Object)=1,否則Pr?(Object)=0。

但是這里要注意一下,其實我們整個網絡的計算中是不需要用這個公式計算的,網絡輸出一個0~1的值就好。

IOU(Intersection over Union ratio)

IOU又叫做交并比,其實很好理解,就是兩個框計算出來的一個值,意義上來看,IOU值越大,表示兩個框的重合度越高,從公式上來看:

一個實現(xiàn)代碼如下:

def calculate_iou(bbox1,bbox2):
    """計算bbox1=(x1,y1,x2,y2)和bbox2=(x3,y3,x4,y4)兩個bbox的iou"""
    intersect_bbox = [0., 0., 0., 0.]  # bbox1和bbox2的交集
    if bbox1[2]<bbox2[0] or bbox1[0]>bbox2[2] or bbox1[3]<bbox2[1] or bbox1[1]>bbox2[3]:
        pass
    else:
        intersect_bbox[0] = max(bbox1[0],bbox2[0])
        intersect_bbox[1] = max(bbox1[1],bbox2[1])
        intersect_bbox[2] = min(bbox1[2],bbox2[2])
        intersect_bbox[3] = min(bbox1[3],bbox2[3])

    area1 = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])  # bbox1面積
    area2 = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])  # bbox2面積
    area_intersect = (intersect_bbox[2] - intersect_bbox[0]) * (intersect_bbox[3] - intersect_bbox[1])  # 交集面積
    # print(bbox1,bbox2)
    # print(intersect_bbox)
    # input()

    if area_intersect>0:
        return area_intersect / (area1 + area2 - area_intersect)  # 計算iou
    else:
        return 0

按照這個思路,我們可以簡要理一下網絡的輸入輸出:

輸入一張固定大小的圖像,規(guī)定劃分的格子數(shù)S*S,規(guī)定每個格子要預測幾個框B。

輸出為一個S*S*(B*5+Class),S和B對應輸入,5就是boundingbox中包含的五個信息,class就是類別的預測,這里類別使用的是one-hot編碼。

目標檢測——YOLO系列學習(一)YOLOv1,目標檢測,目標跟蹤,人工智能

以作者在論文里提到的PASCAL VOC上的實驗為例:

S=7,B=5,有20個類別,故輸出tensor的維度為7*7*(5*2)

這里有個很容易錯誤理解的點,就是這個class的分類結果其實是對應了這一個grid的,一個grid輸出一個20維的分類結果,而不是整個grid所得到的兩個BoundingBox的分類結果,

(2)網絡結構

YOLOv1的數(shù)據(jù)流如下:

  • resize圖片尺寸(沒有ROI)
  • 輸入網絡,輸出tensor
  • 非極大值抑制(NMS)

網絡的結構如下:

目標檢測——YOLO系列學習(一)YOLOv1,目標檢測,目標跟蹤,人工智能

這里光看圖可能很多初學的同學不是很看的懂,我們來看看一個簡單的pytorch版本:

參考:動手學習深度學習pytorch版——從零開始實現(xiàn)YOLOv1_自己實現(xiàn)的yolov-CSDN博客

這一部分需要說明一下,由于原論文是采用自己設計的20層卷積層先在ImageNet上訓練了一周,完成特征提取部分的訓練。我們作為學習者而非發(fā)明者來說,花一周時間訓練實在是太長了。因此,在這里我打算對原論文的結構做一點改變。YOLOv1的前20層是用于特征提取的,也就是隨便替換為一個分類網絡(除去最后的全連接層)其實都行。因此,我打算使用ResNet34的網絡作為特征提取部分。這樣做的好處是,pytorch的torchvision中提供了ResNet34的預訓練模型,訓練集也是ImageNet,等于說有先成訓練好的模型可以直接使用,從而免去了特征提取部分的訓練時間。然后,除去ResNet34的最后兩層,再連接上YOLOv1的最后4個卷積層和兩個全連接層,作為我們訓練的網絡結構。
??此外,還進行了一些小調整,比如最后增加了一個Sigmoid層,以及在卷積層后增加了BN層等等。具體代碼如下:

import torchvision.models as tvmodel
import torch.nn as nn
import torch

class YOLOv1_resnet(nn.Module):
    def __init__(self):
        super(YOLOv1_resnet,self).__init__()
        resnet = tvmodel.resnet34(pretrained=True)  # 調用torchvision里的resnet34預訓練模型
        resnet_out_channel = resnet.fc.in_features  # 記錄resnet全連接層之前的網絡輸出通道數(shù),方便連入后續(xù)卷積網絡中
        self.resnet = nn.Sequential(*list(resnet.children())[:-2])  # 去除resnet的最后兩層
        # 以下是YOLOv1的最后四個卷積層
        self.Conv_layers = nn.Sequential(
            nn.Conv2d(resnet_out_channel,1024,3,padding=1),
            nn.BatchNorm2d(1024),  # 為了加快訓練,這里增加了BN層,原論文里YOLOv1是沒有的
            nn.LeakyReLU(),
            nn.Conv2d(1024,1024,3,stride=2,padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
            nn.Conv2d(1024, 1024, 3, padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
            nn.Conv2d(1024, 1024, 3, padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
        )
        # 以下是YOLOv1的最后2個全連接層
        self.Conn_layers = nn.Sequential(
            nn.Linear(7*7*1024,4096),
            nn.LeakyReLU(),
            nn.Linear(4096,7*7*30),
            nn.Sigmoid()  # 增加sigmoid函數(shù)是為了將輸出全部映射到(0,1)之間,因為如果出現(xiàn)負數(shù)或太大的數(shù),后續(xù)計算loss會很麻煩
        )

    def forward(self, input):
        input = self.resnet(input)
        input = self.Conv_layers(input)
        input = input.view(input.size()[0],-1)
        input = self.Conn_layers(input)
        return input.reshape(-1, (5*NUM_BBOX+len(CLASSES)), 7, 7)  # 記住最后要reshape一下輸出數(shù)據(jù)

這里我們主要關注最后兩個fc層,是沒有使用池化操作的,直接使用view和resize就實現(xiàn)了三維張量和二維張量的轉換。

(3)非極大值抑制

非極大值抑制的目的就是去掉一些冗余框。

這一部分可以參考一下:目標檢測入門之非最大值抑制(NMS)算法 - 知乎 (zhihu.com)

(4)損失函數(shù)

損失函數(shù)是理解YOLOv1訓練的關鍵,具體形式如下:

目標檢測——YOLO系列學習(一)YOLOv1,目標檢測,目標跟蹤,人工智能

這里的損失函數(shù)包括五項:

前兩項對應BoundingBox的損失函數(shù)(針對x, y, H, W進行學習)

接下來兩項對應Confidence的損失函數(shù)(針對置信度進行學習)

最后一項對應分類的損失(針對類別label進行學習)

細節(jié)上來說:

1.公式中每一個均方誤差的系數(shù):?表示的是第i個grid的第j個BoundingBox是否負責Object,每個grid對應的B個BoudingBox中,與GT的IOU最大的BoundingBox才負責這個Object,其余的為,這一部分可以簡單看一下代碼:

if iou1 >= iou2:
    coor_loss = coor_loss + 5 * (torch.sum((pred[i,0:2,m,n] - labels[i,0:2,m,n])**2) \
              + torch.sum((pred[i,2:4,m,n].sqrt()-labels[i,2:4,m,n].sqrt())**2))
    obj_confi_loss = obj_confi_loss + (pred[i,4,m,n] - iou1)**2
    # iou比較小的bbox不負責預測物體,因此confidence loss算在noobj中,注意,對于標簽的置信度應該是iou2
    noobj_confi_loss = noobj_confi_loss + 0.5 * ((pred[i,9,m,n]-iou2)**2)

這里計算obj_confi_loss和noobj_confi_loss使用的pred和IOU都是不一樣的,pred[i,4,m,n]中的4對應的是IOU更大的框,9對應的是IOU更小的框。

2.這里對?(w,?)?在損失函數(shù)中的處理分別取了根號,原因在于,如果不取根號,損失函數(shù)往往更傾向于調整尺寸比較大的預測框。例如,20 個像素點的偏差,對于 800x600 的預測框幾乎沒有影響,此時的IOU數(shù)值還是很大,但是對于 30x40 的預測框影響就很大。取根號是為了盡可能的消除大尺寸框與小尺寸框之間的差異。

3.此時再來看?與??,YOLO 面臨的物體檢測問題,是一個典型的類別數(shù)目不均衡的問題(Focal Loss就是解決這個問題的,一個面試中常問的點)。其中 49 個格點,含有物體的格點往往只有 3、4 個,其余全是不含有物體的格點。此時如果不采取點措施,那么物體檢測的mAP不會太高,因為模型更傾向于不含有物體的格點。?與?的作用,就是讓含有物體的格點,在損失函數(shù)中的權重更大,讓模型更加“重視”含有物體的格點所造成的損失。在論文中,?與?的取值分別為 5 與 0.5 。

最后整個Loss部分的代碼如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-857092.html

class Loss_yolov1(nn.Module):
    def __init__(self):
        super(Loss_yolov1,self).__init__()

    def forward(self, pred, labels):
        """
        :param pred: (batchsize,30,7,7)的網絡輸出數(shù)據(jù)
        :param labels: (batchsize,30,7,7)的樣本標簽數(shù)據(jù)
        :return: 當前批次樣本的平均損失
        """
        num_gridx, num_gridy = labels.size()[-2:]  # 劃分網格數(shù)量
        num_b = 2  # 每個網格的bbox數(shù)量
        num_cls = 20  # 類別數(shù)量
        noobj_confi_loss = 0.  # 不含目標的網格損失(只有置信度損失)
        coor_loss = 0.  # 含有目標的bbox的坐標損失
        obj_confi_loss = 0.  # 含有目標的bbox的置信度損失
        class_loss = 0.  # 含有目標的網格的類別損失
        n_batch = labels.size()[0]  # batchsize的大小

        # 可以考慮用矩陣運算進行優(yōu)化,提高速度,為了準確起見,這里還是用循環(huán)
        for i in range(n_batch):  # batchsize循環(huán)
            for n in range(7):  # x方向網格循環(huán)
                for m in range(7):  # y方向網格循環(huán)
                    if labels[i,4,m,n]==1:# 如果包含物體
                        # 將數(shù)據(jù)(px,py,w,h)轉換為(x1,y1,x2,y2)
                        # 先將px,py轉換為cx,cy,即相對網格的位置轉換為標準化后實際的bbox中心位置cx,xy
                        # 然后再利用(cx-w/2,cy-h/2,cx+w/2,cy+h/2)轉換為xyxy形式,用于計算iou
                        bbox1_pred_xyxy = ((pred[i,0,m,n]+n)/num_gridx - pred[i,2,m,n]/2,(pred[i,1,m,n]+m)/num_gridy - pred[i,3,m,n]/2,
                                           (pred[i,0,m,n]+n)/num_gridx + pred[i,2,m,n]/2,(pred[i,1,m,n]+m)/num_gridy + pred[i,3,m,n]/2)
                        bbox2_pred_xyxy = ((pred[i,5,m,n]+n)/num_gridx - pred[i,7,m,n]/2,(pred[i,6,m,n]+m)/num_gridy - pred[i,8,m,n]/2,
                                           (pred[i,5,m,n]+n)/num_gridx + pred[i,7,m,n]/2,(pred[i,6,m,n]+m)/num_gridy + pred[i,8,m,n]/2)
                        bbox_gt_xyxy = ((labels[i,0,m,n]+n)/num_gridx - labels[i,2,m,n]/2,(labels[i,1,m,n]+m)/num_gridy - labels[i,3,m,n]/2,
                                        (labels[i,0,m,n]+n)/num_gridx + labels[i,2,m,n]/2,(labels[i,1,m,n]+m)/num_gridy + labels[i,3,m,n]/2)
                        iou1 = calculate_iou(bbox1_pred_xyxy,bbox_gt_xyxy)
                        iou2 = calculate_iou(bbox2_pred_xyxy,bbox_gt_xyxy)
                        # 選擇iou大的bbox作為負責物體
                        if iou1 >= iou2:
                            coor_loss = coor_loss + 5 * (torch.sum((pred[i,0:2,m,n] - labels[i,0:2,m,n])**2) \
                                        + torch.sum((pred[i,2:4,m,n].sqrt()-labels[i,2:4,m,n].sqrt())**2))
                            obj_confi_loss = obj_confi_loss + (pred[i,4,m,n] - iou1)**2
                            # iou比較小的bbox不負責預測物體,因此confidence loss算在noobj中,注意,對于標簽的置信度應該是iou2
                            noobj_confi_loss = noobj_confi_loss + 0.5 * ((pred[i,9,m,n]-iou2)**2)
                        else:
                            coor_loss = coor_loss + 5 * (torch.sum((pred[i,5:7,m,n] - labels[i,5:7,m,n])**2) \
                                        + torch.sum((pred[i,7:9,m,n].sqrt()-labels[i,7:9,m,n].sqrt())**2))
                            obj_confi_loss = obj_confi_loss + (pred[i,9,m,n] - iou2)**2
                            # iou比較小的bbox不負責預測物體,因此confidence loss算在noobj中,注意,對于標簽的置信度應該是iou1
                            noobj_confi_loss = noobj_confi_loss + 0.5 * ((pred[i, 4, m, n]-iou1) ** 2)
                        class_loss = class_loss + torch.sum((pred[i,10:,m,n] - labels[i,10:,m,n])**2)
                    else:  # 如果不包含物體
                        noobj_confi_loss = noobj_confi_loss + 0.5 * torch.sum(pred[i,[4,9],m,n]**2)

        loss = coor_loss + obj_confi_loss + noobj_confi_loss + class_loss
        # 此處可以寫代碼驗證一下loss的大致計算是否正確,這個要驗證起來比較麻煩,比較簡潔的辦法是,將輸入的pred置為全1矩陣,再進行誤差檢查,會直觀很多。
        return loss/n_batch

3.YOLOv1的缺點

  • 由于輸出層為全連接層,因此在檢測時,YOLO訓練模型只支持與訓練圖像相同的輸入分辨率。
  • 雖然每個格子可以預測B個bounding box,但是最終只選擇只選擇IOU最高的bounding box作為物體檢測輸出,即每個格子最多只預測出一個物體。當物體占畫面比例較小,如圖像中包含畜群或鳥群時,每個格子包含多個物體,但卻只能檢測出其中一個。這是YOLO方法的一個缺陷。
  • YOLO loss函數(shù)中,大物體IOU誤差和小物體IOU誤差對網絡訓練中l(wèi)oss貢獻值接近(雖然采用求平方根方式,但沒有根本解決問題)。因此,對于小物體,小的IOU誤差也會對網絡優(yōu)化過程造成很大的影響,從而降低了物體檢測的定位準確性。

到了這里,關于目標檢測——YOLO系列學習(一)YOLOv1的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 深度學習||YOLO(You Only Look Once)深度學習的實時目標檢測算法(YOLOv1~YOLOv5)

    目錄 YOLOv1: YOLOv2: YOLOv3: YOLOv4: YOLOv5: 總結: YOLO(You Only Look Once)是一系列基于深度學習的實時目標檢測算法。 自從2015年首次被提出以來,YOLO系列不斷發(fā)展,推出了多個版本,包括YOLOv1, YOLOv2, YOLOv3, YOLOv4, 和YOLOv5等。下面是對YOLO系列的詳解: 提出時間 : 2015年。 主要貢獻 :

    2024年02月20日
    瀏覽(14)
  • 【目標檢測——YOLO系列】YOLOv1 —《You Only Look Once: Unified, Real-Time Object Detection》

    【目標檢測——YOLO系列】YOLOv1 —《You Only Look Once: Unified, Real-Time Object Detection》

    論文地址:1506.02640] You Only Look Once: Unified, Real-Time Object Detection (arxiv.org) 代碼地址:pjreddie/darknet: Convolutional Neural Networks (github.com) YOLOv1是一種end to end目標檢測算法,由Joseph Redmon等人于2015年提出。它是一種基于單個神經網絡的實時目標檢測算法。 YOLOv1的中文名稱是\\\"你只看一

    2024年02月08日
    瀏覽(18)
  • 目標檢測YOLO算法,先從yolov1開始

    目標檢測YOLO算法,先從yolov1開始

    有一套配套的學習資料,才能讓我們的學習事半功倍。 yolov1論文原址:You Only Look Once: Unified, Real-Time Object Detection 代碼地址:darknet: Convolutional Neural Networks (github.com) one-stage(單階段):YOLO系列 最核心的優(yōu)勢:速度非???,適合做實時檢測任務! 但是缺點也是有的,效果通常

    2024年02月09日
    瀏覽(49)
  • 【目標檢測系列】YOLOV1解讀

    【目標檢測系列】YOLOV1解讀

    從R-CNN到Fast-RCNN,之前的目標檢測工作都是分成兩階段,先提供位置信息在進行目標分類,精度很高但無法滿足實時檢測的要求。 而YoLo將目標檢測看作回歸問題,輸入為一張圖片,輸出為S*S*(5*B+C)的三維向量。該向量結果既包含位置信息,又包含類別信息??赏ㄟ^損失函數(shù),

    2024年02月13日
    瀏覽(20)
  • YOLOv5目標檢測學習(1):yolo系列算法的基礎概念

    YOLOv5目標檢測學習(1):yolo系列算法的基礎概念

    提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 關于深度學習目標檢測,有許多概念性的東西需要先了解一下。這里主要以基于深度學習的目標檢測算法的部署實現(xiàn)來學習。 以yolov5為例: 使用YOLOv5進行車輛和行人的目標檢測通常涉及以下步驟: 數(shù)據(jù)

    2024年04月09日
    瀏覽(24)
  • 【YOLO系列】YOLOv1論文超詳細解讀(翻譯 +學習筆記)

    【YOLO系列】YOLOv1論文超詳細解讀(翻譯 +學習筆記)

    從這篇開始,我們將進入YOLO的學習。YOLO是目前比較流行的目標檢測算法,速度快且結構簡單,其他的目標檢測算法如RCNN系列,以后有時間的話再介紹。 本文主要介紹的是YOLOV1,這是由以Joseph Redmon為首的大佬們于2015年提出的一種新的目標檢測算法。它與之前的目標檢測算法

    2024年02月04日
    瀏覽(47)
  • YOLO系列目標檢測算法-YOLOv6

    YOLO系列目標檢測算法-YOLOv6

    YOLO系列目標檢測算法目錄 - 文章鏈接 YOLO系列目標檢測算法總結對比- 文章鏈接 YOLOv1- 文章鏈接 YOLOv2- 文章鏈接 YOLOv3- 文章鏈接 YOLOv4- 文章鏈接 Scaled-YOLOv4- 文章鏈接 YOLOv5- 文章鏈接 YOLOv6 - 文章鏈接 YOLOv7- 文章鏈接 PP-YOLO- 文章鏈接 PP-YOLOv2- 文章鏈接 YOLOR- 文章鏈接 YOLOS- 文章鏈

    2023年04月08日
    瀏覽(45)
  • YOLO物體檢測-系列教程1:YOLOV1整體解讀(預選框/置信度/分類任/回歸任務/損失函數(shù)/公式解析/置信度/非極大值抑制)

    YOLO物體檢測-系列教程1:YOLOV1整體解讀(預選框/置信度/分類任/回歸任務/損失函數(shù)/公式解析/置信度/非極大值抑制)

    YOLOV1整體解讀 YOLOV2整體解讀 YOLOV1提出論文:You Only Look Once: Unified, Real-Time Object Detection two-stage(兩階段):Faster-rcnn Mask-Rcnn系列 one-stage(單階段):YOLO系列 最核心的優(yōu)勢:速度非???,適合做實時檢測任務! 但是缺點也是有的,效果通常情況下不會太好! 機器學習 分類任

    2024年02月09日
    瀏覽(22)
  • YOLO系列概述(yolov1至yolov7)

    YOLO系列概述(yolov1至yolov7)

    參考: 睿智的目標檢測53——Pytorch搭建YoloX目標檢測平臺 YoloV7 首先我們來看一下yolo系列的發(fā)展歷史,yolo v1和yolox是anchor free的方法,yolov2,yolov3,一直到y(tǒng)olov7是anchor base的方法。首選我們來回顧下每個版本的yolo都做了些什么 yolo v1是將 416 ? 416 416*416 4 1 6 ? 4 1 6 的圖片,分

    2024年02月05日
    瀏覽(29)
  • 人工智能詳細筆記:計算機視覺、目標檢測與R-CNN系列 YOLO系列模型

    計算機視覺概述 :計算機視覺是一種利用計算機算法和數(shù)學模型來模擬和自動化人類視覺的學科領域。 計算機視覺的地位 :計算機視覺(CV)與自然語言處理(NLP)、語音識別(SR)并列為機器學習方向的三大熱點方向。 計算機視覺的常見任務 :下面將從粗粒度到細粒度介

    2024年02月08日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包