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

番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8

這篇具有很好參考價值的文章主要介紹了番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1.研究背景與意義

項目參考AAAI Association for the Advancement of Artificial Intelligence

研究背景與意義

番茄是全球重要的蔬菜作物之一,具有廣泛的經(jīng)濟和營養(yǎng)價值。然而,番茄病蟲害的嚴重威脅導(dǎo)致了產(chǎn)量和質(zhì)量的損失。因此,開發(fā)一種高效準確的番茄病蟲害檢測系統(tǒng)對于農(nóng)業(yè)生產(chǎn)的可持續(xù)發(fā)展至關(guān)重要。

傳統(tǒng)的番茄病蟲害檢測方法主要依賴于人工目視觀察,這種方法存在著效率低、主觀性強、易出錯等問題。近年來,隨著計算機視覺和深度學習技術(shù)的快速發(fā)展,基于圖像處理和機器學習的自動化檢測方法逐漸成為研究熱點。

目前,基于深度學習的目標檢測算法已經(jīng)在圖像識別領(lǐng)域取得了顯著的成果。其中,YOLO(You Only Look Once)算法是一種快速、準確的目標檢測算法,被廣泛應(yīng)用于各種物體檢測任務(wù)中。然而,傳統(tǒng)的YOLO算法在處理小目標和密集目標時存在一定的困難,且對于番茄病蟲害這種細小的目標檢測任務(wù)來說,其性能仍然有待提高。

為了解決上述問題,本研究提出了一種改進的番茄病蟲害檢測系統(tǒng),即融合感受野注意力卷積(RFAConv)改進YOLOv8。該系統(tǒng)通過引入感受野注意力機制,能夠自適應(yīng)地調(diào)整網(wǎng)絡(luò)對不同尺度目標的關(guān)注程度,從而提高小目標和密集目標的檢測性能。此外,通過融合感受野注意力卷積,可以更好地捕捉番茄病蟲害的細節(jié)特征,提高檢測的準確性和魯棒性。

本研究的意義主要體現(xiàn)在以下幾個方面:

  1. 提高番茄病蟲害檢測的準確性:傳統(tǒng)的目標檢測算法在處理小目標和密集目標時存在一定的困難,而融合感受野注意力卷積改進的YOLOv8算法能夠有效地提高小目標和密集目標的檢測準確性,從而提高番茄病蟲害檢測的準確性。

  2. 提高番茄病蟲害檢測的效率:傳統(tǒng)的人工目視觀察方法效率低下,而基于深度學習的自動化檢測方法能夠?qū)崿F(xiàn)快速、準確的檢測。融合感受野注意力卷積改進的YOLOv8算法具有較高的計算效率,能夠在保證準確性的同時提高檢測的效率。

  3. 促進農(nóng)業(yè)生產(chǎn)的可持續(xù)發(fā)展:番茄病蟲害對番茄產(chǎn)量和質(zhì)量造成了嚴重的影響,通過開發(fā)高效準確的番茄病蟲害檢測系統(tǒng),可以及時發(fā)現(xiàn)和控制病蟲害,減少損失,提高農(nóng)業(yè)生產(chǎn)的可持續(xù)發(fā)展能力。

總之,融合感受野注意力卷積改進的YOLOv8算法在番茄病蟲害檢測領(lǐng)域具有重要的研究意義和應(yīng)用價值。通過提高檢測的準確性和效率,可以為農(nóng)業(yè)生產(chǎn)提供有效的技術(shù)支持,促進農(nóng)業(yè)的可持續(xù)發(fā)展。

2.圖片演示

番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

3.視頻演示

番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8_嗶哩嗶哩_bilibili

4.數(shù)據(jù)集的采集&標注和整理

圖片的收集

首先,我們需要收集所需的圖片。這可以通過不同的方式來實現(xiàn),例如使用現(xiàn)有的公開數(shù)據(jù)集TdDatasets。

labelImg是一個圖形化的圖像注釋工具,支持VOC和YOLO格式。以下是使用labelImg將圖片標注為VOC格式的步驟:

(1)下載并安裝labelImg。
(2)打開labelImg并選擇“Open Dir”來選擇你的圖片目錄。
(3)為你的目標對象設(shè)置標簽名稱。
(4)在圖片上繪制矩形框,選擇對應(yīng)的標簽。
(5)保存標注信息,這將在圖片目錄下生成一個與圖片同名的XML文件。
(6)重復(fù)此過程,直到所有的圖片都標注完畢。

由于YOLO使用的是txt格式的標注,我們需要將VOC格式轉(zhuǎn)換為YOLO格式??梢允褂酶鞣N轉(zhuǎn)換工具或腳本來實現(xiàn)。
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

下面是一個簡單的方法是使用Python腳本,該腳本讀取XML文件,然后將其轉(zhuǎn)換為YOLO所需的txt格式。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import xml.etree.ElementTree as ET
import os

classes = []  # 初始化為空列表

CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)

def convert_annotation(image_id):
    in_file = open('./label_xml\%s.xml' % (image_id), encoding='UTF-8')
    out_file = open('./label_txt\%s.txt' % (image_id), 'w')  # 生成txt格式文件
    tree = ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        cls = obj.find('name').text
        if cls not in classes:
            classes.append(cls)  # 如果類別不存在,添加到classes列表中
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
             float(xmlbox.find('ymax').text))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

xml_path = os.path.join(CURRENT_DIR, './label_xml/')

# xml list
img_xmls = os.listdir(xml_path)
for img_xml in img_xmls:
    label_name = img_xml.split('.')[0]
    print(label_name)
    convert_annotation(label_name)

print("Classes:")  # 打印最終的classes列表
print(classes)  # 打印最終的classes列表

番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

整理數(shù)據(jù)文件夾結(jié)構(gòu)

我們需要將數(shù)據(jù)集整理為以下結(jié)構(gòu):

-----data
   |-----train
   |   |-----images
   |   |-----labels
   |
   |-----valid
   |   |-----images
   |   |-----labels
   |
   |-----test
       |-----images
       |-----labels

確保以下幾點:

所有的訓(xùn)練圖片都位于data/train/images目錄下,相應(yīng)的標注文件位于data/train/labels目錄下。
所有的驗證圖片都位于data/valid/images目錄下,相應(yīng)的標注文件位于data/valid/labels目錄下。
所有的測試圖片都位于data/test/images目錄下,相應(yīng)的標注文件位于data/test/labels目錄下。
這樣的結(jié)構(gòu)使得數(shù)據(jù)的管理和模型的訓(xùn)練、驗證和測試變得非常方便。

模型訓(xùn)練
 Epoch   gpu_mem       box       obj       cls    labels  img_size
 1/200     20.8G   0.01576   0.01955  0.007536        22      1280: 100%|██████████| 849/849 [14:42<00:00,  1.04s/it]
           Class     Images     Labels          P          R     mAP@.5 mAP@.5:.95: 100%|██████████| 213/213 [01:14<00:00,  2.87it/s]
             all       3395      17314      0.994      0.957      0.0957      0.0843

 Epoch   gpu_mem       box       obj       cls    labels  img_size
 2/200     20.8G   0.01578   0.01923  0.007006        22      1280: 100%|██████████| 849/849 [14:44<00:00,  1.04s/it]
           Class     Images     Labels          P          R     mAP@.5 mAP@.5:.95: 100%|██████████| 213/213 [01:12<00:00,  2.95it/s]
             all       3395      17314      0.996      0.956      0.0957      0.0845

 Epoch   gpu_mem       box       obj       cls    labels  img_size
 3/200     20.8G   0.01561    0.0191  0.006895        27      1280: 100%|██████████| 849/849 [10:56<00:00,  1.29it/s]
           Class     Images     Labels          P          R     mAP@.5 mAP@.5:.95: 100%|███████   | 187/213 [00:52<00:00,  4.04it/s]
             all       3395      17314      0.996      0.957      0.0957      0.0845

5.核心代碼講解

5.1 predict.py
from ultralytics.engine.predictor import BasePredictor
from ultralytics.engine.results import Results
from ultralytics.utils import ops

class DetectionPredictor(BasePredictor):
    def postprocess(self, preds, img, orig_imgs):
        preds = ops.non_max_suppression(preds,
                                        self.args.conf,
                                        self.args.iou,
                                        agnostic=self.args.agnostic_nms,
                                        max_det=self.args.max_det,
                                        classes=self.args.classes)

        if not isinstance(orig_imgs, list):
            orig_imgs = ops.convert_torch2numpy_batch(orig_imgs)

        results = []
        for i, pred in enumerate(preds):
            orig_img = orig_imgs[i]
            pred[:, :4] = ops.scale_boxes(img.shape[2:], pred[:, :4], orig_img.shape)
            img_path = self.batch[0][i]
            results.append(Results(orig_img, path=img_path, names=self.model.names, boxes=pred))
        return results

這段代碼定義了一個名為DetectionPredictor的類,該類繼承自BasePredictor類。其中,postprocess方法用于對預(yù)測結(jié)果進行后處理,并返回一個Results對象的列表。在postprocess方法中,首先使用ops.non_max_suppression函數(shù)對預(yù)測結(jié)果進行非最大值抑制處理,然后根據(jù)輸入圖片的形狀和原始圖片的形狀對預(yù)測框進行縮放,最后將處理后的結(jié)果封裝為Results對象并添加到結(jié)果列表中。

該程序文件名為predict.py,是一個用于預(yù)測的程序文件。該文件使用了Ultralytics YOLO庫,采用AGPL-3.0許可證。

該文件定義了一個名為DetectionPredictor的類,該類繼承自BasePredictor類,用于基于檢測模型進行預(yù)測。

該類中包含了一個postprocess方法,用于對預(yù)測結(jié)果進行后處理,并返回一個Results對象的列表。在postprocess方法中,首先對預(yù)測結(jié)果進行非最大抑制處理,根據(jù)一些參數(shù)進行篩選,得到最終的預(yù)測結(jié)果。然后,將輸入的圖像轉(zhuǎn)換為numpy數(shù)組,并根據(jù)預(yù)測結(jié)果對邊界框進行縮放。最后,將原始圖像、圖像路徑、類別名稱和預(yù)測框作為參數(shù),創(chuàng)建一個Results對象,并將其添加到結(jié)果列表中。

該文件還包含了一個示例代碼,展示了如何使用DetectionPredictor類進行預(yù)測。首先導(dǎo)入所需的庫和模塊,然后創(chuàng)建一個DetectionPredictor對象,并使用predict_cli方法進行預(yù)測。

總結(jié)起來,該程序文件是一個用于基于檢測模型進行預(yù)測的工具類,其中包含了預(yù)測結(jié)果的后處理方法和示例代碼。

5.2 train.py
from copy import copy
import numpy as np
from ultralytics.data import build_dataloader, build_yolo_dataset
from ultralytics.engine.trainer import BaseTrainer
from ultralytics.models import yolo
from ultralytics.nn.tasks import DetectionModel
from ultralytics.utils import LOGGER, RANK
from ultralytics.utils.torch_utils import de_parallel, torch_distributed_zero_first

class DetectionTrainer(BaseTrainer):
    def build_dataset(self, img_path, mode='train', batch=None):
        gs = max(int(de_parallel(self.model).stride.max() if self.model else 0), 32)
        return build_yolo_dataset(self.args, img_path, batch, self.data, mode=mode, rect=mode == 'val', stride=gs)

    def get_dataloader(self, dataset_path, batch_size=16, rank=0, mode='train'):
        assert mode in ['train', 'val']
        with torch_distributed_zero_first(rank):
            dataset = self.build_dataset(dataset_path, mode, batch_size)
        shuffle = mode == 'train'
        if getattr(dataset, 'rect', False) and shuffle:
            LOGGER.warning("WARNING ?? 'rect=True' is incompatible with DataLoader shuffle, setting shuffle=False")
            shuffle = False
        workers = 0
        return build_dataloader(dataset, batch_size, workers, shuffle, rank)

    def preprocess_batch(self, batch):
        batch['img'] = batch['img'].to(self.device, non_blocking=True).float() / 255
        return batch

    def set_model_attributes(self):
        self.model.nc = self.data['nc']
        self.model.names = self.data['names']
        self.model.args = self.args

    def get_model(self, cfg=None, weights=None, verbose=True):
        model = DetectionModel(cfg, nc=self.data['nc'], verbose=verbose and RANK == -1)
        if weights:
            model.load(weights)
        return model

    def get_validator(self):
        self.loss_names = 'box_loss', 'cls_loss', 'dfl_loss'
        return yolo.detect.DetectionValidator(self.test_loader, save_dir=self.save_dir, args=copy(self.args))

    def label_loss_items(self, loss_items=None, prefix='train'):
        keys = [f'{prefix}/{x}' for x in self.loss_names]
        if loss_items is not None:
            loss_items = [round(float(x), 5) for x in loss_items]
            return dict(zip(keys, loss_items))
        else:
            return keys

    def progress_string(self):
        return ('\n' + '%11s' *
                (4 + len(self.loss_names))) % ('Epoch', 'GPU_mem', *self.loss_names, 'Instances', 'Size')

    def plot_training_samples(self, batch, ni):
        plot_images(images=batch['img'],
                    batch_idx=batch['batch_idx'],
                    cls=batch['cls'].squeeze(-1),
                    bboxes=batch['bboxes'],
                    paths=batch['im_file'],
                    fname=self.save_dir / f'train_batch{ni}.jpg',
                    on_plot=self.on_plot)

    def plot_metrics(self):
        plot_results(file=self.csv, on_plot=self.on_plot)

    def plot_training_labels(self):
        boxes = np.concatenate([lb['bboxes'] for lb in self.train_loader.dataset.labels], 0)
        cls = np.concatenate([lb['cls'] for lb in self.train_loader.dataset.labels], 0)
        plot_labels(boxes, cls.squeeze(), names=self.data['names'], save_dir=self.save_dir, on_plot=self.on_plot)

這個程序文件是一個用于訓(xùn)練目標檢測模型的程序。它使用了Ultralytics YOLO庫,該庫提供了訓(xùn)練和驗證目標檢測模型的功能。

該程序文件定義了一個名為DetectionTrainer的類,該類繼承自BaseTrainer類。DetectionTrainer類包含了構(gòu)建數(shù)據(jù)集、構(gòu)建數(shù)據(jù)加載器、預(yù)處理批次、設(shè)置模型屬性等方法,用于訓(xùn)練目標檢測模型。

在程序的主函數(shù)中,首先定義了一些參數(shù),包括模型文件路徑、數(shù)據(jù)文件路徑和訓(xùn)練輪數(shù)等。然后創(chuàng)建了一個DetectionTrainer對象,并調(diào)用其train方法開始訓(xùn)練。

總體來說,這個程序文件使用Ultralytics YOLO庫提供的功能來訓(xùn)練目標檢測模型。

5.3 backbone\revcol.py
import torch
import torch.nn as nn

class RevCol(nn.Module):
    def __init__(self, kernel='C2f', channels=[32, 64, 96, 128], layers=[2, 3, 6, 3], num_subnet=5, save_memory=True) -> None:
        super().__init__()
        self.num_subnet = num_subnet
        self.channels = channels
        self.layers = layers

        self.stem = Conv(3, channels[0], k=4, s=4, p=0)

        for i in range(num_subnet):
            first_col = True if i == 0 else False
            self.add_module(f'subnet{str(i)}', SubNet(channels, layers, kernel, first_col, save_memory=save_memory))
        
        self.channel = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]

    def forward(self, x):
        c0, c1, c2, c3 = 0, 0, 0, 0
        x = self.stem(x)        
        for i in range(self.num_subnet):
            c0, c1, c2, c3 = getattr(self, f'subnet{str(i)}')(x, c0, c1, c2, c3)       
        return [c0, c1, c2, c3]

該程序文件名為backbone\revcol.py,是一個用于深度學習的神經(jīng)網(wǎng)絡(luò)模型的實現(xiàn)。該文件包含了多個模塊和函數(shù),用于定義網(wǎng)絡(luò)的結(jié)構(gòu)和實現(xiàn)前向傳播和反向傳播的過程。

該文件中定義了以下模塊和函數(shù):

  1. RevCol類:該類是整個神經(jīng)網(wǎng)絡(luò)模型的主要部分。它包含了多個子網(wǎng)絡(luò)(SubNet),每個子網(wǎng)絡(luò)由多個層級(Level)組成。每個層級由多個卷積層(Conv)組成。RevCol類的前向傳播過程通過調(diào)用子網(wǎng)絡(luò)的前向傳播函數(shù)來實現(xiàn)。

  2. SubNet類:該類是一個子網(wǎng)絡(luò),由多個層級(Level)組成。每個層級由多個卷積層(Conv)組成。SubNet類的前向傳播過程通過調(diào)用層級的前向傳播函數(shù)來實現(xiàn)。

  3. Level類:該類是一個層級,由多個卷積層(Conv)組成。Level類的前向傳播過程通過調(diào)用卷積層的前向傳播函數(shù)來實現(xiàn)。

  4. Conv類:該類是一個卷積層,用于實現(xiàn)卷積操作。

  5. ReverseFunction類:該類是一個自定義的反向傳播函數(shù),用于實現(xiàn)反向傳播過程。

該文件還定義了一些輔助函數(shù)和變量,用于處理張量的狀態(tài)和梯度等操作。

總體來說,該程序文件實現(xiàn)了一個具有多個子網(wǎng)絡(luò)和層級的神經(jīng)網(wǎng)絡(luò)模型,用于進行深度學習任務(wù)。

5.4 backbone\SwinTransformer.py


class Mlp(nn.Module):
    """ Multilayer perceptron."""

    def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
        super().__init__()
        out_features = out_features or in_features
        hidden_features = hidden_features or in_features
        self.fc1 = nn.Linear(in_features, hidden_features)
        self.act = act_layer()
        self.fc2 = nn.Linear(hidden_features, out_features)
        self.drop = nn.Dropout(drop)

    def forward(self, x):
        x = self.fc1(x)
        x = self.act(x)
        x = self.drop(x)
        x = self.fc2(x)
        x = self.drop(x)
        return x


def window_partition(x, window_size):
    """
    Args:
        x: (B, H, W, C)
        window_size (int): window size

    Returns:
        windows: (num_windows*B, window_size, window_size, C)
    """
    B, H, W, C = x.shape
    x = x.view(B, H // window_size, window_size, W // window_size, window_size, C)
    windows = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, C)
    return windows


def window_reverse(windows, window_size, H, W):
    """
    Args:
        windows: (num_windows*B, window_size, window_size, C)
        window_size (int): Window size
        H (int): Height of image
        W (int): Width of image

    Returns:
        x: (B, H, W, C)
    """
    B = int(windows.shape[0] / (H * W / window_size / window_size))
    x = windows.view(B, H // window_size, W // window_size, window_size, window_size, -1)
    x = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1)
    return x


class WindowAttention(nn.Module):
    """ Window based multi-head self attention (W-MSA) module with relative position bias.
    It supports both of shifted and non-shifted window.

    Args:
        dim (int): Number of input channels.
        window_size (tuple[int]): The height and width of the window.
        num_heads (int): Number of attention heads.
        qkv_bias (bool, optional):  If True, add a learnable bias to query, key, value. Default: True
        qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set
        attn_drop (float, optional): Dropout ratio of attention weight. Default: 0.0
        proj_drop (float, optional): Dropout ratio of output. Default: 0.0
    """

    def __init__(self, dim, window_size, num_heads, qkv_bias=True, qk_scale=None, attn_drop=0., proj_drop=0.):

        super().__init__()
        self.dim = dim
        self.window_size = window_size  # Wh, Ww
        self.num_heads = num_heads
        head_dim = dim // num_heads
        self.scale = qk

該程序文件是Swin Transformer模型的一個實現(xiàn)。Swin Transformer是一種基于窗口的多頭自注意力模塊,用于圖像分類任務(wù)。該模型包含了多個Swin Transformer塊和Patch Merging層。

SwinTransformer_Tiny是一個小型的Swin Transformer模型,用于處理輸入特征。模型的主要組成部分包括:

  1. Mlp:多層感知機模塊,用于將輸入特征映射到隱藏特征空間。
  2. window_partition和window_reverse:用于將輸入特征劃分為窗口,并將窗口重新組合成特征。
  3. WindowAttention:基于窗口的多頭自注意力模塊,用于計算特征之間的相似度。
  4. SwinTransformerBlock:Swin Transformer塊,包含了窗口注意力模塊、多層感知機模塊和殘差連接。
  5. PatchMerging:用于將輸入特征的分辨率降低一半。

該程序文件實現(xiàn)了SwinTransformer_Tiny模型的前向傳播函數(shù),包括窗口劃分、窗口注意力計算、窗口合并等操作。

5.5 backbone\VanillaNet.py
import torch
import torch.nn as nn
from timm.layers import weight_init

class activation(nn.ReLU):
    def __init__(self, dim, act_num=3, deploy=False):
        super(activation, self).__init__()
        self.deploy = deploy
        self.weight = torch.nn.Parameter(torch.randn(dim, 1, act_num*2 + 1, act_num*2 + 1))
        self.bias = None
        self.bn = nn.BatchNorm2d(dim, eps=1e-6)
        self.dim = dim
        self.act_num = act_num
        weight_init.trunc_normal_(self.weight, std=.02)

    def forward(self, x):
        if self.deploy:
            return torch.nn.functional.conv2d(
                super(activation, self).forward(x), 
                self.weight, self.bias, padding=(self.act_num*2 + 1)//2, groups=self.dim)
        else:
            return self.bn(torch.nn.functional.conv2d(
                super(activation, self).forward(x),
                self.weight, padding=self.act_num

該程序文件名為backbone\VanillaNet.py,是一個用于構(gòu)建VanillaNet模型的Python代碼文件。

該文件定義了以下類和函數(shù):

  • activation類:繼承自nn.ReLU類,用于定義激活函數(shù)。
  • Block類:繼承自nn.Module類,用于定義模型的基本塊。
  • VanillaNet類:繼承自nn.Module類,用于定義VanillaNet模型。
  • update_weight函數(shù):用于更新模型的權(quán)重。
  • vanillanet_5到vanillanet_13_x1_5_ada_pool函數(shù):用于創(chuàng)建不同版本的VanillaNet模型。

其中,VanillaNet類是該文件的主要內(nèi)容,它定義了VanillaNet模型的結(jié)構(gòu)和前向傳播方法。根據(jù)輸入的參數(shù),可以創(chuàng)建不同版本的VanillaNet模型。

在文件的最后,通過調(diào)用vanillanet

5.6 extra_modules\rep_block.py


class DiverseBranchBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size,
                 stride=1, padding=None, dilation=1, groups=1,
                 internal_channels_1x1_3x3=None,
                 deploy=False, single_init=False):
        super(DiverseBranchBlock, self).__init__()
        self.deploy = deploy

        self.nonlinear = Conv.default_act

        self.kernel_size = kernel_size
        self.out_channels = out_channels
        self.groups = groups
        
        if padding is None:
            padding = autopad(kernel_size, padding, dilation)
        assert padding == kernel_size // 2

        if deploy:
            self.dbb_reparam = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride,
                                      padding=padding, dilation=dilation, groups=groups, bias=True)

        else:

            self.dbb_origin = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=groups)

            self.dbb_avg = nn.Sequential()
            if groups < out_channels:
                self.dbb_avg.add_module('conv',
                                        nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1,
                                                  stride=1, padding=0, groups=groups, bias=False))
                self.dbb_avg.add_module('bn', BNAndPadLayer(pad_pixels=padding, num_features=out_channels))
                self.dbb_avg.add_module('avg', nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=0))
                self.dbb_1x1 = conv_bn(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=stride,
                                       padding=0, groups=groups)
            else:
                self.dbb_avg.add_module('avg', nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=padding))

            self.dbb_avg.add_module('avgbn', nn.BatchNorm2d(out_channels))


            if internal_channels_1x1_3x3 is None:
                internal_channels_1x1_3x3 = in_channels if groups < out_channels else 2 * in_channels   # For mobilenet, it is better to have 2X internal channels

            self.dbb_1x1_kxk = nn.Sequential()
            if internal_channels_1x1_3x3 == in_channels:
                self.dbb_1x1_kxk.add_module('idconv1', IdentityBasedConv1x1(channels=in_channels, groups=groups))
            else:
                self.dbb_1x1_kxk.add_module('conv1', nn.Conv2d(in_channels=in_channels, out_channels=internal_channels_1x1_3x3,
                                                            kernel_size=1, stride=1, padding=0, groups=groups, bias=False))
            self.dbb_1x1_kxk.add_module('bn1', BNAndPadLayer(pad_pixels=padding, num_features=internal_channels_1x1_3x3, affine=True))
            self.dbb_1x1_kxk.add_module('conv2', nn.Conv2d(in_channels=internal_channels_1x1_3x3, out_channels=out_channels,
                                                            kernel_size=kernel_size, stride=stride, padding=0, groups=groups, bias=False))
            self

該程序文件是一個名為"rep_block.py"的模塊文件,主要包含了一個名為"DiverseBranchBlock"的類。該類是一個繼承自nn.Module的模型類,用于定義一個多樣分支塊。

該模塊文件中還包含了一些輔助函數(shù)和類,如"transI_fusebn"、“transII_addbranch”、“transIII_1x1_kxk"等用于處理卷積和批歸一化操作的函數(shù),以及"conv_bn”、“IdentityBasedConv1x1”、"BNAndPadLayer"等用于定義卷積、批歸一化和填充操作的類。

"DiverseBranchBlock"類的構(gòu)造函數(shù)接受一些參數(shù),包括輸入通道數(shù)、輸出通道數(shù)、卷積核大小、步長、填充、膨脹率、分組數(shù)等。在構(gòu)造函數(shù)中,根據(jù)是否部署模型,會選擇不同的操作路徑。如果是部署模型,則使用nn.Conv2d定義一個卷積層;否則,使用conv_bn函數(shù)定義一個卷積和批歸一化的組合層,并定義了其他一些輔助操作層。

該類還包含了一些方法,如"get_equivalent_kernel_bias"用于獲取等效的卷積核和偏置,"switch_to_deploy"用于切換到部署模式,"forward"用于前向傳播計算輸出,"init_gamma"用于初始化gamma參數(shù),"single_init"用于單一初始化參數(shù)。

總體來說,該程序文件定義了一個多樣分支塊的模型類,提供了一些輔助函數(shù)和類來支持模型的構(gòu)建和操作。

6.系統(tǒng)整體結(jié)構(gòu)

根據(jù)以上分析,該程序是一個番茄病蟲害檢測系統(tǒng)的項目,主要包含了訓(xùn)練和預(yù)測兩個主要功能。整體構(gòu)架如下:

  • models:包含了模型的定義和實現(xiàn),如common.py、experimental.py、tf.py、yolo.py等文件。
  • utils:包含了各種輔助功能和工具函數(shù),如activations.py、augmentations.py、autoanchor.py、autobatch.py等文件。
  • extra_modules:包含了一些額外的模塊和功能,如rep_block.py、RFAConv.py等文件。
  • backbone:包含了不同的神經(jīng)網(wǎng)絡(luò)模型的實現(xiàn),如revcol.py、SwinTransformer.py、VanillaNet.py等文件。
  • code:包含了訓(xùn)練和預(yù)測的主要代碼文件,如train.py、predict.py等文件。

下面是每個文件的功能概述:

文件路徑 功能概述
predict.py 用于預(yù)測的程序文件,包含預(yù)測結(jié)果的后處理方法和示例代碼。
train.py 用于訓(xùn)練目標檢測模型的程序文件,包含數(shù)據(jù)集構(gòu)建、數(shù)據(jù)加載器構(gòu)建、模型屬性設(shè)置等方法。
backbone/revcol.py 實現(xiàn)了一個深度學習的神經(jīng)網(wǎng)絡(luò)模型,包含多個子網(wǎng)絡(luò)和層級。
backbone/SwinTransformer.py 實現(xiàn)了Swin Transformer模型,用于圖像分類任務(wù)。
backbone/VanillaNet.py 實現(xiàn)了VanillaNet模型,用于構(gòu)建一個基本的神經(jīng)網(wǎng)絡(luò)模型。
extra_modules/rep_block.py 定義了一個多樣分支塊的模型類,提供了輔助函數(shù)和類來支持模型的構(gòu)建和操作。
extra_modules/RFAConv.py 實現(xiàn)了RFAConv模塊,用于改進YOLOv8目標檢測系統(tǒng)。
extra_modules/init.py 空文件,用于標識extra_modules為一個Python模塊。
extra_modules/ops_dcnv3/setup.py 用于安裝DCNv3模塊的配置文件。
extra_modules/ops_dcnv3/test.py 用于測試DCNv3模塊的功能的測試腳本。
extra_modules/ops_dcnv3/functions/dcnv3_func.py 實現(xiàn)了DCNv3模塊的功能函數(shù)。
extra_modules/ops_dcnv3/functions/init.py 空文件,用于標識functions為一個Python模塊。
extra_modules/ops_dcnv3/modules/dcnv3.py 實現(xiàn)了DCNv3模塊的模型類。
extra_modules/ops_dcnv3/modules/init.py 空文件,用于標識modules為一個Python模塊。
models/common.py 包含了一些通用的模型定義和實用函數(shù)。
models/experimental.py 包含了一些實驗性的模型定義和實用函數(shù)。
models/tf.py 包含了一些TensorFlow模型定義和實用函數(shù)。
models/yolo.py 包含了YOLO模型的定義和實用函數(shù)。
models/init.py 空文件,用于標識models為一個Python模塊。
utils/activations.py 包含了各種激活函數(shù)的定義。
utils/augmentations.py 包含了數(shù)據(jù)增強的函數(shù)和類。
utils/autoanchor.py 包含了自動錨框生成的函數(shù)和類。
utils/autobatch.py 包含了自動批處理的函數(shù)和類。
utils/callbacks.py 包含了一些回調(diào)函數(shù)的定義。
utils/datasets.py 包含了數(shù)據(jù)集的定義和處理函數(shù)。
utils/downloads.py 包含了文件下載的函數(shù)和類。
utils/general.py 包含了一些通用的輔助函數(shù)。
utils/loss.py 包含了損失函數(shù)的定義。
utils/metrics.py 包含了評估指標的定義。
utils/plots.py 包含了繪圖函數(shù)的定義。
utils/torch_utils.py 包含了一些PyTorch的輔助函數(shù)。
utils/init.py 空文件,用于標識utils為一個Python模塊。
utils/aws/resume.py 包含了AWS上的恢復(fù)功能的函數(shù)和類。
utils/aws/init.py 空文件,用于標識aws為一個Python模塊。
utils/flask_rest_api/example_request.py 包含了Flask REST API的示例請求函數(shù)。

7.YOLOv8簡介

YOLOv8目標檢測算法繼承了YOLOv1系列的思考,是一種新型端到端的目標檢測算法,盡管現(xiàn)在原始檢測算法已經(jīng)開源,但是鮮有發(fā)表的相關(guān)論文.YOLOv8的網(wǎng)絡(luò)結(jié)構(gòu)如圖所示,主要可分為Input輸入端、Backbone骨干神經(jīng)網(wǎng)絡(luò)、Neck 混合特征網(wǎng)絡(luò)層和Head預(yù)測層網(wǎng)絡(luò)共4個部分.
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能
YOLO目標檢測算法是一種端到端的One-Slage 目標檢測算法,其核心思想是將圖像按區(qū)域分塊進行預(yù)測。YOLO將輸入圖像按照32x32的大小劃分成若干個網(wǎng)格,例如416x416的圖像將被劃分為13x13個網(wǎng)格。當目標物體的中心位于某個網(wǎng)格內(nèi)時,該網(wǎng)格就會負責輸出該物體的邊界框和類別置信度。每個網(wǎng)格可以預(yù)測多個邊界框和多個目標類別,這些邊界框和類別的數(shù)量可以根據(jù)需要進行設(shè)置。YOLO算法的輸出是一個特征圖,包含了每個網(wǎng)格對應(yīng)的邊界框和類別置信度的信息呵。本文采用YOLO最新的YOLOv8模型,其是2022年底發(fā)布的最新YOLO系列模型,采用全新的SOTA模型,全新的網(wǎng)絡(luò)主干結(jié)構(gòu),如圖1所示。
整個網(wǎng)絡(luò)分為Backbone 骨干網(wǎng)絡(luò)部分和Head頭部網(wǎng)絡(luò)部分。YOLOv8汲取了前幾代網(wǎng)絡(luò)的優(yōu)秀特性,骨干網(wǎng)絡(luò)和 Neck部分遵循CSP的思想,將YOLOv5中的C3模塊被替換成了梯度流更豐富C2模塊,去掉YOLOv5中 PAN-FPN上采樣階段中的卷積結(jié)構(gòu),將Backbone不同階段輸出的特征直接送入了上采樣操作,模型提供了N/S/M/L/X尺度的不同大小模型,能夠滿足不同領(lǐng)域業(yè)界的需求。本文基于YOLOv8模型設(shè)計番茄病蟲害檢測系統(tǒng),通過配置模型參數(shù)訓(xùn)練番茄圖像,得到能夠用于部署應(yīng)用的最優(yōu)模型。
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

8.感受野注意力卷積(RFAConv)

標準卷積操作回顧

標準的卷積操作是構(gòu)造卷積神經(jīng)網(wǎng)絡(luò)的基本構(gòu)件。它利用具有共享參數(shù)的滑動窗口提取特征信息,克服了全連通層構(gòu)造神經(jīng)網(wǎng)絡(luò)固有的參數(shù)多、計算開銷大的問題。設(shè) X R∈C×H×W
表示輸入特征圖,其中C、H、W分別表示特征圖的通道數(shù)、高度、寬度。為了清楚地演示卷積核的特征提取過程,我們使用 C = 1 的例子。從每個接受域滑塊中提取特征信息的卷積運算可以表示為:
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

這里,F(xiàn)i 表示計算后每個卷積滑塊得到的值,Xi 表示每個滑塊內(nèi)對應(yīng)位置的像素值,K表示卷積核,S表示卷積核中的參數(shù)個數(shù),N表示接收域滑塊的總數(shù)。可以看出,每個滑塊內(nèi)相同位置的 feature共享相同的參數(shù)Ki。因此,標準的卷積運算并不能捕捉到不同位置所帶來的信息差異,這最終在一定程度上限制了卷積神經(jīng)網(wǎng)絡(luò)的性能。

空間注意力回顧

目前,空間注意機制是利用學習得到的注意圖來突出每個特征的重要性。與前一節(jié)類似,這里以 C=1為例。突出關(guān)鍵特征的空間注意機制可以簡單表述為:這里,F(xiàn)i 表示加權(quán)運算后得到的值。xi 和Ai 表示輸入特征圖和學習到的注意圖在不同位置的值,N為輸入特征圖的高和寬的乘積,表示像素值的總數(shù)。
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

空間注意與標準卷積運算

將注意力機制整合到卷積神經(jīng)網(wǎng)絡(luò)中,可以提高卷積神經(jīng)網(wǎng)絡(luò)的性能。通過對標準卷積運算和現(xiàn)有空間注意機制的研究,我們認為空間注意機制有效地克服了卷積神經(jīng)網(wǎng)絡(luò)固有的參數(shù)共享的局限性。目前卷積神經(jīng)網(wǎng)絡(luò)中最常用的核大小是 1 × 1和3 × 3。在引入空間注意機制后,提取特征的卷積操作可以是 1 × 1或3 × 3卷積操作。為了直觀地展示這個過程,在 1 × 1卷積運算的前面插入了空間注意機制。通過注意圖對輸入特征圖(Re-weight“×”)進行加權(quán)運算,最后通過 1 × 1卷積運算提取接收域的滑塊特征信息。整個過程可以簡單地表示如下:
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

這里卷積核K僅代表一個參數(shù)值。如果取A i× ki 的值作為一種新的卷積核參數(shù),有趣的是它解決了 1×1卷積運算提取特征時的參數(shù)共享問題。然而,關(guān)于空間注意機制的傳說到此結(jié)束。當空間注意機制被插入到3×3卷積運算前面時。具體情況如下:
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

如上所述,如果取A的值 i × ki (4)式作為一種新的卷積核參數(shù),完全解決了大規(guī)模卷積核的參數(shù)共享問題。然而,最重要的一點是,卷積核在提取每個接受域滑塊的特征時,會共享一些特征。換句話說,每個接收域滑塊內(nèi)都有一個重疊。仔細分析后會發(fā)現(xiàn)A12= a21, a13 = a22, a15 = a24……,在這種情況下,每個滑動窗口共享空間注意力地圖的權(quán)重。因此,空間注意機制沒有考慮整個接受域的空間特征,不能有效地解決大規(guī)模卷積核的參數(shù)共享問題。因此,空間注意機制的有效性受到限制。

創(chuàng)新空間注意力和標準卷積操作

該博客提出解決了現(xiàn)有空間注意機制的局限性,為空間處理提供了一種創(chuàng)新的解決方案。受RFA的啟發(fā),一系列空間注意機制被開發(fā)出來,可以進一步提高卷積神經(jīng)網(wǎng)絡(luò)的性能。RFA可以看作是一個輕量級即插即用模塊,RFA設(shè)計的卷積運算(RFAConv)可以代替標準卷積來提高卷積神經(jīng)網(wǎng)絡(luò)的性能。因此,我們預(yù)測空間注意機制與標準卷積運算的結(jié)合將繼續(xù)發(fā)展,并在未來帶來新的突破。
接受域空間特征:為了更好地理解接受域空間特征的概念,我們將提供相關(guān)的定義。接收域空間特征是專門為卷積核設(shè)計的,并根據(jù)核大小動態(tài)生成。如圖1所示,以3×3卷積核為例。在圖1中,“Spatial Feature”指的是原始的Feature map?!敖邮苡蚩臻g特征”是空間特征變換后的特征圖。

番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

由不重疊的滑動窗口組成。當使用 3×3卷積內(nèi)核提取特征時,接收域空間特征中的每個 3×3大小窗口代表一個接收域滑塊。接受域注意卷積(RFAConv):針對接受域的空間特征,我們提出了接受域注意卷積(RFA)。該方法不僅強調(diào)了接收域滑塊內(nèi)不同特征的重要性,而且對接收域空間特征進行了優(yōu)先排序。通過該方法,完全解決了卷積核參數(shù)共享的問題。接受域空間特征是根據(jù)卷積核的大小動態(tài)生成的,因此,RFA是卷積的固定組合,不能與卷積操作的幫助分離,卷積操作同時依賴于RFA來提高性能,因此我們提出了接受場注意卷積(RFAConv)。具有3×3大小的卷積核的RFAConv整體結(jié)構(gòu)如圖所示。
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

目前,最廣泛使用的接受域特征提取方法是緩慢的。經(jīng)過大量的研究,我們開發(fā)了一種快速的方法,用分組卷積來代替原來的方法。具體來說,我們利用相應(yīng)大小的分組卷積來動態(tài)生成基于接受域大小的展開特征。盡管與原始的無參數(shù)方法(如PyTorch提供的nn.())相比,該方法增加了一些參數(shù),但它的速度要快得多。注意:如前一節(jié)所述,當使用 3×3卷積內(nèi)核提取特征時,接收域空間特征中的每個 3×3大小窗口表示一個接收域滑塊。而利用快速分組卷積提取感受野特征后,將原始特征映射為新的特征。最近的研究表明。交互信息可以提高網(wǎng)絡(luò)性能,如[40,41,42]所示。同樣,對于RFAConv來說,通過交互接受域特征信息來學習注意圖可以提高網(wǎng)絡(luò)性能。然而,與每個接收域特征交互會導(dǎo)致額外的計算開銷,因此為了最小化計算開銷和參數(shù)的數(shù)量,我們使用AvgPool來聚合每個接收域特征的全局信息。然后,使用 1×1 組卷積操作進行信息交互。最后,我們使用softmax來強調(diào)每個特征在接受域特征中的重要性。一般情況下,RFA的計算可以表示為:
番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

這里gi×i 表示一個大小為 i×i的分組卷積,k表示卷積核的大小,Norm表示歸一化,X表示輸入的特征圖,F(xiàn)由注意圖 a相乘得到 rf 與轉(zhuǎn)換后的接受域空間特征 Frf。與CBAM和CA不同,RFA能夠為每個接受域特征生成注意圖。卷積神經(jīng)網(wǎng)絡(luò)的性能受到標準卷積操作的限制,因為卷積操作依賴于共享參數(shù),對位置變化帶來的信息差異不敏感。然而,RFAConv通過強調(diào)接收域滑塊中不同特征的重要性,并對接收域空間特征進行優(yōu)先級排序,可以完全解決這個問題。通過RFA得到的feature map是接受域空間特征,在“Adjust Shape”后沒有重疊。因此,學習到的注意圖將每個接受域滑塊的特征信息聚合起來。換句話說,注意力地圖不再共享在每個接受域滑塊。這完全彌補了現(xiàn)有 CA和CBAM注意機制的不足。RFA為標準卷積內(nèi)核提供了顯著的好處。而在調(diào)整形狀后,特征的高度和寬度是 k倍,需要進行 stride = k的k × k卷積運算來提取特征信息。RFA設(shè)計的卷積運算RFAConv為卷積帶來了良好的增益,對標準卷積進行了創(chuàng)新。
此外,我們認為現(xiàn)有的空間注意機制應(yīng)該優(yōu)先考慮接受域空間特征,以提高網(wǎng)絡(luò)性能。眾所周知,基于自注意機制的網(wǎng)絡(luò)模型[43,44,45]取得了很大的成功,因為它解決了卷積參數(shù)共享的問題,并對遠程信息進行建模。然而,自注意機制也為模型引入了顯著的計算開銷和復(fù)雜性。我們認為,將現(xiàn)有的空間注意機制的注意力引導(dǎo)到接受場空間特征上,可以以類似于自我注意的方式解決長期信息的參數(shù)共享和建模問題。與自我關(guān)注相比,這種方法需要的參數(shù)和計算資源少得多。答案如下:(1)將以接收場空間特征為中心的空間注意機制與卷積相結(jié)合,消除了卷積參數(shù)共享的問題。(2)現(xiàn)有的空間注意機制已經(jīng)考慮了遠程信息,可以通過全局平均池或全局最大池的方式獲取全局信息,其中明確考慮了遠程信息。因此,我們設(shè)計了新的 CBAM和CA模型,稱為RFCBAM和RFCA,它們專注于接受域空間特征。與RFA類似,使用最終的k × k stride = k 的卷積運算來提取特征信息。這兩種新的卷積方法的具體結(jié)構(gòu)如圖 3所示,我們稱這兩種新的卷積操作為 RFCBAMConv和RFCAConv。與原來的CBAM相比,我們在RFCBAM中使用SE attention來代替CAM。因為這樣可以減少計算開銷。此外,在RFCBAM中,通道注意和空間注意不是分開執(zhí)行的。相反,它們是同時加權(quán)的,使得每個通道獲得的注意力地圖是不同的。

番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

9.系統(tǒng)整合

下圖完整源碼&數(shù)據(jù)集&環(huán)境部署視頻教程&自定義UI界面

番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8,YOLO,目標跟蹤,人工智能

參考博客《番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8》

10.參考文獻


[1]林文樹,張金生,何乃磊.基于改進YOLO v4的落葉松毛蟲侵害樹木實時檢測方法[J].農(nóng)業(yè)機械學報.2023,54(4).DOI:10.6041/j.issn.1000-1298.2023.04.031 .

[2]銀霞,葉紹澤.基于卷積神經(jīng)網(wǎng)絡(luò)的嵌入式排水管道缺陷檢測系統(tǒng)[J].城市勘測.2023,(2).DOI:10.3969/j.issn.1672-8262.2023.02.043 .

[3]安小松,宋竹平,梁千月,等.基于CNN-Transformer的視覺缺陷柑橘分選方法[J].華中農(nóng)業(yè)大學學報.2022,41(4).

[4]王道累,李明山,姚勇,等.改進SSD的光伏組件熱斑缺陷檢測方法[J].太陽能學報.2023,44(4).DOI:10.19912/j.0254-0096.tynxb.2021-1470 .

[5]胡定一.基于深度學習的缺陷柑橘分類識別檢測方法研究[D].2021.文章來源地址http://www.zghlxwxcb.cn/news/detail-758041.html

到了這里,關(guān)于番茄病蟲害檢測系統(tǒng):融合感受野注意力卷積(RFAConv)改進YOLOv8的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包