【完整源码+数据集+部署教程】【天线&运输】直升机战机类型识别目标检测系统源码&数据集全套:改进yolo11-CSP-EDLAN

背景意义

随着现代战争的日益复杂化,空中作战力量的有效识别与分类变得愈发重要。直升机作为一种灵活多变的空中作战平台,其在战场上的作用不可小觑。为了提升对直升机及其他空中目标的识别能力,基于深度学习的目标检测技术应运而生。其中,YOLO(You Only Look Once)系列模型因其高效的实时检测能力而备受关注。YOLOv11作为该系列的最新版本,具备更强的特征提取能力和更快的推理速度,适合在复杂的战场环境中进行直升机类型的识别。

本研究旨在基于改进的YOLOv11模型,构建一个高效的直升机战机类型识别目标检测系统。该系统将利用"Helicopters-of-DC"数据集,该数据集包含5500张图像,涵盖了多种直升机型号,包括A139、AS50、CH47等共计3类目标。通过对这些图像的深入分析与处理,系统能够在多种环境下准确识别不同类型的直升机及其他空中目标,如气球、鸟类和飞机等。这不仅为军事侦察提供了技术支持,也为无人机等新型空中作战平台的应用提供了数据基础。

此外,随着人工智能技术的快速发展,基于YOLOv11的目标检测系统在实际应用中的潜力巨大。其不仅可以应用于军事领域,还可以扩展到民用航空安全、交通监控等多个领域。通过本研究的实施,将推动目标检测技术的进一步发展,为相关领域的研究提供新的思路和方法。综上所述,本项目不仅具有重要的学术价值,也具备广泛的应用前景。

图片效果



数据集信息

本项目所使用的数据集名为"Helicopters-of-DC",旨在为改进YOLOv11的直升机战机类型识别目标检测系统提供支持。该数据集包含丰富的直升机及相关飞行器图像,经过精心标注,以确保模型训练的准确性和有效性。数据集分为三个主要部分:训练集、验证集和测试集,分别存放于指定的路径下。训练集包含大量的图像数据,供模型学习和优化;验证集用于在训练过程中监测模型的性能;测试集则用于最终评估模型的泛化能力。

该数据集涵盖了24个类别,具体包括多种直升机型号,如A139、AS50、B06、B412、B429、CH47等,以及一些其他飞行器,如鸟类和飞机。这些类别的选择不仅考虑了直升机的多样性,还包括了一些可能在训练和测试过程中出现的干扰目标,以增强模型的鲁棒性。通过对这些类别的精确标注,数据集为目标检测任务提供了丰富的样本,帮助模型更好地识别和分类不同类型的直升机。

数据集的设计遵循了BY-NC-SA 4.0的许可协议,确保了其在学术研究和开发中的合理使用。数据集的版本为3,反映了其在不断更新和完善的过程中所积累的经验和反馈。通过利用"Helicopters-of-DC"数据集,研究人员能够有效地训练和评估YOLOv11模型,从而提升直升机战机类型识别的准确性,为相关领域的应用提供更为强大的技术支持。




核心代码

以下是经过简化并添加详细中文注释的核心代码部分:

import os

import torch

from ultralytics.engine.validator import BaseValidator

from ultralytics.utils.metrics import DetMetrics, box_iou

from ultralytics.utils import LOGGER, ops

class DetectionValidator(BaseValidator):

"""

继承自BaseValidator类,用于基于检测模型的验证。

"""

复制代码
def __init__(self, dataloader=None, save_dir=None, args=None):
    """初始化检测模型所需的变量和设置。"""
    super().__init__(dataloader, save_dir, args)
    self.metrics = DetMetrics(save_dir=self.save_dir)  # 初始化检测指标
    self.iouv = torch.linspace(0.5, 0.95, 10)  # 定义IoU向量用于mAP计算

def preprocess(self, batch):
    """对YOLO训练的图像批次进行预处理。"""
    # 将图像数据转移到设备上并进行归一化处理
    batch["img"] = batch["img"].to(self.device, non_blocking=True) / 255
    # 将其他相关数据转移到设备上
    for k in ["batch_idx", "cls", "bboxes"]:
        batch[k] = batch[k].to(self.device)
    return batch

def postprocess(self, preds):
    """对预测输出应用非极大值抑制(NMS)。"""
    return ops.non_max_suppression(
        preds,
        self.args.conf,
        self.args.iou,
        multi_label=True,
        max_det=self.args.max_det,
    )

def update_metrics(self, preds, batch):
    """更新检测指标。"""
    for si, pred in enumerate(preds):
        npr = len(pred)  # 当前预测的数量
        pbatch = self._prepare_batch(si, batch)  # 准备当前批次的数据
        cls, bbox = pbatch.pop("cls"), pbatch.pop("bbox")  # 获取真实标签
        if npr == 0:
            continue  # 如果没有预测结果,跳过

        # 处理预测结果
        predn = self._prepare_pred(pred, pbatch)  # 准备预测数据
        stat = dict(conf=predn[:, 4], pred_cls=predn[:, 5])  # 记录置信度和预测类别
        stat["tp"] = self._process_batch(predn, bbox, cls)  # 计算真阳性
        self.stats["tp"].append(stat["tp"])  # 更新统计信息

def _process_batch(self, detections, gt_bboxes, gt_cls):
    """
    返回正确的预测矩阵。
    """
    iou = box_iou(gt_bboxes, detections[:, :4])  # 计算IoU
    return self.match_predictions(detections[:, 5], gt_cls, iou)  # 匹配预测与真实标签

def get_stats(self):
    """返回指标统计信息和结果字典。"""
    stats = {k: torch.cat(v, 0).cpu().numpy() for k, v in self.stats.items()}  # 转换为numpy数组
    if len(stats) and stats["tp"].any():
        self.metrics.process(**stats)  # 处理指标
    return self.metrics.results_dict  # 返回结果字典

def print_results(self):
    """打印每个类别的训练/验证集指标。"""
    pf = "%22s" + "%11i" * 2 + "%11.3g" * len(self.metrics.keys)  # 打印格式
    LOGGER.info(pf % ("all", self.seen, self.nt_per_class.sum(), *self.metrics.mean_results()))  # 打印总体结果

代码说明:

类的定义:DetectionValidator类用于YOLO模型的验证,继承自BaseValidator。

初始化方法:__init__方法中初始化了一些重要的变量和检测指标。

预处理方法:preprocess方法对输入的图像批次进行预处理,包括将图像数据归一化和转移到指定设备。

后处理方法:postprocess方法使用非极大值抑制(NMS)来过滤预测结果。

更新指标:update_metrics方法根据预测结果和真实标签更新检测指标。

处理批次:_process_batch方法计算IoU并匹配预测与真实标签。

获取统计信息:get_stats方法返回当前的指标统计信息。

打印结果:print_results方法打印每个类别的验证结果。

通过这些核心部分的注释,可以更好地理解YOLO模型验证的过程和各个方法的功能。

这个程序文件 val.py 是一个用于YOLO(You Only Look Once)目标检测模型验证的实现。它继承自 BaseValidator 类,提供了一系列方法来处理数据、计算指标和输出结果。

在初始化时,DetectionValidator 类接收一些参数,包括数据加载器、保存目录、进度条、参数和回调函数。它设置了一些必要的变量,如每类的目标数量、是否使用COCO数据集、类别映射等,并初始化了用于计算检测指标的 DetMetrics 实例。

preprocess 方法负责对输入的图像批次进行预处理,包括将图像转换为合适的格式和范围,并根据需要进行自动标注的准备。

init_metrics 方法初始化评估指标,确定数据集的类型(是否为COCO),并准备混淆矩阵和其他统计信息。

get_desc 方法返回一个格式化的字符串,用于总结YOLO模型的类指标。

postprocess 方法应用非极大值抑制(NMS)来处理模型的预测输出,以去除冗余的检测框。

_prepare_batch 和 _prepare_pred 方法分别用于准备输入批次和预测结果,以便进行后续的指标计算。

update_metrics 方法负责更新模型的检测指标,包括处理每个批次的预测结果和真实标签,并根据需要保存结果到文件。

finalize_metrics 方法设置最终的指标值和混淆矩阵。

get_stats 方法返回计算得到的指标统计信息,并更新每个类别的目标数量。

print_results 方法打印训练或验证集的每个类别的指标结果,并在需要时绘制混淆矩阵。

_process_batch 方法计算正确的预测矩阵,用于评估模型的性能。

build_dataset 和 get_dataloader 方法用于构建YOLO数据集和返回数据加载器,以便进行验证。

plot_val_samples 和 plot_predictions 方法用于绘制验证图像样本和预测结果,并将其保存为图像文件。

save_one_txt 方法将YOLO检测结果保存为文本文件,采用规范化的坐标格式。

pred_to_json 方法将YOLO的预测结果序列化为COCO格式的JSON文件,以便进行进一步的评估。

eval_json 方法评估YOLO输出的JSON格式结果,并返回性能统计信息,使用COCO API计算mAP(平均精度)。

整个程序的结构清晰,功能完备,涵盖了YOLO模型验证的各个方面,包括数据处理、指标计算、结果输出等,适合用于目标检测任务的模型评估。

10.3 kagn_conv.py

以下是经过简化并添加详细中文注释的核心代码部分:

import torch

import torch.nn as nn

from functools import lru_cache

class KAGNConvNDLayer(nn.Module):

def init (self, conv_class, norm_class, conv_w_fun, input_dim, output_dim, degree, kernel_size,

groups=1, padding=0, stride=1, dilation=1, dropout: float = 0.0, ndim: int = 2):

super(KAGNConvNDLayer, self).init()

复制代码
    # 初始化参数
    self.inputdim = input_dim  # 输入维度
    self.outdim = output_dim    # 输出维度
    self.degree = degree         # 多项式的度数
    self.kernel_size = kernel_size  # 卷积核大小
    self.padding = padding       # 填充
    self.stride = stride         # 步幅
    self.dilation = dilation     # 膨胀
    self.groups = groups         # 分组卷积的组数
    self.base_activation = nn.SiLU()  # 基础激活函数
    self.conv_w_fun = conv_w_fun  # 卷积权重函数
    self.ndim = ndim             # 数据的维度
    self.dropout = None          # Dropout层

    # 根据维度选择合适的Dropout层
    if dropout > 0:
        if ndim == 1:
            self.dropout = nn.Dropout1d(p=dropout)
        elif ndim == 2:
            self.dropout = nn.Dropout2d(p=dropout)
        elif ndim == 3:
            self.dropout = nn.Dropout3d(p=dropout)

    # 验证输入参数的有效性
    if groups <= 0:
        raise ValueError('groups must be a positive integer')
    if input_dim % groups != 0:
        raise ValueError('input_dim must be divisible by groups')
    if output_dim % groups != 0:
        raise ValueError('output_dim must be divisible by groups')

    # 创建基础卷积层和归一化层
    self.base_conv = nn.ModuleList([conv_class(input_dim // groups,
                                               output_dim // groups,
                                               kernel_size,
                                               stride,
                                               padding,
                                               dilation,
                                               groups=1,
                                               bias=False) for _ in range(groups)])

    self.layer_norm = nn.ModuleList([norm_class(output_dim // groups) for _ in range(groups)])

    # 多项式权重的形状
    poly_shape = (groups, output_dim // groups, (input_dim // groups) * (degree + 1)) + tuple(
        kernel_size for _ in range(ndim))

    # 初始化多项式权重和beta权重
    self.poly_weights = nn.Parameter(torch.randn(*poly_shape))
    self.beta_weights = nn.Parameter(torch.zeros(degree + 1, dtype=torch.float32))

    # 使用Kaiming均匀分布初始化卷积层权重
    for conv_layer in self.base_conv:
        nn.init.kaiming_uniform_(conv_layer.weight, nonlinearity='linear')

    nn.init.kaiming_uniform_(self.poly_weights, nonlinearity='linear')
    nn.init.normal_(
        self.beta_weights,
        mean=0.0,
        std=1.0 / ((kernel_size ** ndim) * self.inputdim * (self.degree + 1.0)),
    )

def beta(self, n, m):
    # 计算beta值,用于Legendre多项式
    return (
        ((m + n) * (m - n) * n ** 2) / (m ** 2 / (4.0 * n ** 2 - 1.0))
    ) * self.beta_weights[n]

@lru_cache(maxsize=128)  # 使用缓存避免重复计算Legendre多项式
def gram_poly(self, x, degree):
    # 计算Legendre多项式
    p0 = x.new_ones(x.size())  # p0 = 1

    if degree == 0:
        return p0.unsqueeze(-1)

    p1 = x  # p1 = x
    grams_basis = [p0, p1]  # 存储多项式基

    for i in range(2, degree + 1):
        p2 = x * p1 - self.beta(i - 1, i) * p0  # 递归计算
        grams_basis.append(p2)
        p0, p1 = p1, p2  # 更新p0和p1

    return torch.cat(grams_basis, dim=1)  # 返回所有多项式基

def forward_kag(self, x, group_index):
    # 前向传播过程
    basis = self.base_conv[group_index](self.base_activation(x))  # 计算基础卷积

    x = torch.tanh(x).contiguous()  # 将输入标准化到[-1, 1]

    if self.dropout is not None:
        x = self.dropout(x)  # 应用Dropout

    grams_basis = self.base_activation(self.gram_poly(x, self.degree))  # 计算Gram多项式基

    # 使用卷积权重函数计算输出
    y = self.conv_w_fun(grams_basis, self.poly_weights[group_index],
                        stride=self.stride, dilation=self.dilation,
                        padding=self.padding, groups=1)

    y = self.base_activation(self.layer_norm[group_index](y + basis))  # 归一化并激活

    return y

def forward(self, x):
    # 前向传播,处理输入
    split_x = torch.split(x, self.inputdim // self.groups, dim=1)  # 按组分割输入
    output = []
    for group_ind, _x in enumerate(split_x):
        y = self.forward_kag(_x.clone(), group_ind)  # 计算每组的输出
        output.append(y.clone())
    y = torch.cat(output, dim=1)  # 合并所有组的输出
    return y

代码说明:

KAGNConvNDLayer: 这是一个自定义的卷积层,支持多维卷积(1D、2D、3D),结合了Legendre多项式的计算和分组卷积的特性。

初始化参数: 在构造函数中,初始化输入输出维度、卷积参数、激活函数等,并创建相应的卷积和归一化层。

beta和gram_poly方法: 计算Legendre多项式和相关的beta值,用于后续的卷积计算。

forward_kag方法: 实现了每个组的前向传播逻辑,包括基础卷积、Dropout、Gram多项式计算和最终输出的归一化。

forward方法: 将输入按组分割,依次计算每组的输出,并合并结果。

这个程序文件 kagn_conv.py 定义了一组用于卷积神经网络的自定义层,主要包括多维卷积层的实现。程序中使用了 PyTorch 框架,利用其提供的模块和功能来构建卷积层。核心类是 KAGNConvNDLayer,它是一个通用的多维卷积层,可以根据需要扩展为一维、二维或三维卷积层。

在 KAGNConvNDLayer 的构造函数中,首先初始化了一些参数,包括输入和输出维度、卷积核大小、步幅、填充、扩张、分组等。根据输入的维度,选择相应的 dropout 方法。接着,程序会检查分组数是否为正整数,并确保输入和输出维度可以被分组数整除。

该类还定义了基础卷积层和归一化层,使用 nn.ModuleList 来存储多个卷积和归一化层,以支持分组卷积。接下来,程序定义了多项式权重和 beta 权重,并使用 Kaiming 均匀分布初始化这些权重,以提高训练的起始效果。

beta 方法用于计算与 Legendre 多项式相关的 beta 值,而 gram_poly 方法则用于计算给定输入和多项式阶数的 Gram 多项式。为了避免重复计算,gram_poly 方法使用了 LRU 缓存。

在 forward_kag 方法中,首先对输入应用基础激活函数,然后进行线性变换。接着,将输入归一化到 [-1, 1] 的范围,以便进行稳定的 Legendre 多项式计算。随后,如果设置了 dropout,则对输入应用 dropout。接下来,计算 Gram 基础并通过卷积权重函数进行卷积操作,最后通过归一化层和激活函数得到输出。

forward 方法将输入张量按组分割,并对每个组调用 forward_kag 方法进行处理,最后将所有组的输出拼接在一起。

此外,程序还定义了三个具体的卷积层类:KAGNConv3DLayer、KAGNConv2DLayer 和 KAGNConv1DLayer,分别用于三维、二维和一维卷积。这些类通过调用 KAGNConvNDLayer 的构造函数,传入相应的卷积和归一化类来实现具体的卷积操作。

整体而言,这个程序文件提供了一种灵活的方式来实现多维卷积层,结合了多项式特性和分组卷积的优势,适用于各种深度学习任务。

10.4 shiftwise_conv.py

以下是代码中最核心的部分,并附上详细的中文注释:

import math

import torch

import torch.nn as nn

import torch.nn.functional as F

def get_conv2d(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias):

创建一个2D卷积层

return nn.Conv2d(

in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias

)

def get_bn(channels):

创建一个批归一化层

return nn.BatchNorm2d(channels)

class Mask(nn.Module):

def init (self, size):

super().init ()

初始化权重参数,范围在-1到1之间

self.weight = torch.nn.Parameter(data=torch.Tensor(*size), requires_grad=True)

self.weight.data.uniform_(-1, 1)

复制代码
def forward(self, x):
    # 通过sigmoid函数对权重进行归一化,并与输入x相乘
    w = torch.sigmoid(self.weight)
    masked_wt = w.mul(x)
    return masked_wt

class ReparamLargeKernelConv(nn.Module):

def init (self, in_channels, out_channels, kernel_size, small_kernel=5, stride=1, groups=1, small_kernel_merged=False, Decom=True, bn=True):

super(ReparamLargeKernelConv, self).init ()

self.kernel_size = kernel_size

self.small_kernel = small_kernel

self.Decom = Decom

padding = kernel_size // 2 # 计算填充大小

复制代码
    if small_kernel_merged:  # 如果合并小卷积
        self.lkb_reparam = get_conv2d(
            in_channels=in_channels,
            out_channels=out_channels,
            kernel_size=kernel_size,
            stride=stride,
            padding=padding,
            dilation=1,
            groups=groups,
            bias=True,
        )
    else:
        if self.Decom:  # 如果使用分解
            self.LoRA = conv_bn(
                in_channels=in_channels,
                out_channels=out_channels,
                kernel_size=(kernel_size, small_kernel),
                stride=stride,
                padding=padding,
                dilation=1,
                groups=groups,
                bn=bn
            )
        else:
            self.lkb_origin = conv_bn(
                in_channels=in_channels,
                out_channels=out_channels,
                kernel_size=kernel_size,
                stride=stride,
                padding=padding,
                dilation=1,
                groups=groups,
                bn=bn,
            )

        if (small_kernel is not None) and small_kernel < kernel_size:
            self.small_conv = conv_bn(
                in_channels=in_channels,
                out_channels=out_channels,
                kernel_size=small_kernel,
                stride=stride,
                padding=small_kernel // 2,
                groups=groups,
                dilation=1,
                bn=bn,
            )
    
    self.bn = get_bn(out_channels)  # 批归一化层
    self.act = nn.SiLU()  # 激活函数

def forward(self, inputs):
    # 前向传播
    if hasattr(self, "lkb_reparam"):
        out = self.lkb_reparam(inputs)  # 使用重参数化卷积
    elif self.Decom:
        out = self.LoRA(inputs)  # 使用LoRA卷积
        if hasattr(self, "small_conv"):
            out += self.small_conv(inputs)  # 加上小卷积的输出
    else:
        out = self.lkb_origin(inputs)  # 使用原始卷积
        if hasattr(self, "small_conv"):
            out += self.small_conv(inputs)  # 加上小卷积的输出
    return self.act(self.bn(out))  # 返回经过激活和归一化的输出

def get_equivalent_kernel_bias(self):
    # 获取等效的卷积核和偏置
    eq_k, eq_b = fuse_bn(self.lkb_origin.conv, self.lkb_origin.bn)
    if hasattr(self, "small_conv"):
        small_k, small_b = fuse_bn(self.small_conv.conv, self.small_conv.bn)
        eq_b += small_b  # 累加偏置
        eq_k += nn.functional.pad(small_k, [(self.kernel_size - self.small_kernel) // 2] * 4)  # 对小卷积核进行填充
    return eq_k, eq_b

def switch_to_deploy(self):
    # 切换到部署模式
    if hasattr(self, 'lkb_origin'):
        eq_k, eq_b = self.get_equivalent_kernel_bias()  # 获取等效卷积核和偏置
        self.lkb_reparam = get_conv2d(
            in_channels=self.lkb_origin.conv.in_channels,
            out_channels=self.lkb_origin.conv.out_channels,
            kernel_size=self.lkb_origin.conv.kernel_size,
            stride=self.lkb_origin.conv.stride,
            padding=self.lkb_origin.conv.padding,
            dilation=self.lkb_origin.conv.dilation,
            groups=self.lkb_origin.conv.groups,
            bias=True,
        )
        self.lkb_reparam.weight.data = eq_k  # 设置卷积核权重
        self.lkb_reparam.bias.data = eq_b  # 设置偏置
        self.__delattr__("lkb_origin")  # 删除原始卷积属性
        if hasattr(self, "small_conv"):
            self.__delattr__("small_conv")  # 删除小卷积属性

代码说明

get_conv2d 和 get_bn: 这两个函数分别用于创建卷积层和批归一化层。

Mask: 该类定义了一个掩码机制,通过sigmoid函数对权重进行归一化,并与输入相乘。

ReparamLargeKernelConv: 这是一个自定义的卷积层,支持大卷积核和小卷积核的组合。根据参数选择不同的卷积方式(重参数化、分解或原始卷积),并在前向传播中处理输入。

前向传播: 根据模型的配置,选择合适的卷积层进行计算,并在最后应用激活函数和批归一化。

get_equivalent_kernel_bias: 该方法用于获取等效的卷积核和偏置,方便在部署时使用。

switch_to_deploy: 切换到部署模式,优化模型以提高推理速度。

这个程序文件 shiftwise_conv.py 实现了一个用于深度学习卷积操作的模块,主要包括了大核卷积和小核卷积的组合,以及通过参数重参数化(Reparameterization)来优化卷积层的性能。文件中定义了多个类和函数,下面对其进行逐一说明。

首先,文件导入了必要的库,包括 math、torch 及其子模块 torch.nn 和 torch.nn.functional。这些库提供了构建神经网络所需的基础功能。

接下来,定义了一个函数 get_conv2d,用于创建一个二维卷积层。该函数接受多个参数,如输入通道数、输出通道数、卷积核大小、步幅、填充、扩张、分组和是否使用偏置等。它会根据给定的卷积核大小计算填充,并返回一个 nn.Conv2d 对象。

get_bn 函数用于创建一个批归一化层,接受通道数作为参数。

Mask 类是一个自定义的模块,它的构造函数初始化了一个可训练的权重参数,并在前向传播中通过 Sigmoid 函数对权重进行激活,随后将其与输入相乘,形成一个掩码效果。

conv_bn_ori 函数用于创建一个包含卷积层和可选的批归一化层的序列。根据传入的参数,构建相应的卷积层并添加批归一化层。

LoRAConvsByWeight 类实现了一个特殊的卷积结构,它结合了大核和小核卷积的特性,并通过权重进行通道的混洗。该类的构造函数中,首先计算了填充和索引,然后定义了多个卷积层和掩码层。在前向传播中,输入数据经过小卷积层后,输出被分成多个部分,并通过 forward_lora 方法进行处理,最终将处理后的结果相加。

forward_lora 方法负责处理每个分组的输出,计算数据的重新排列和填充,并根据需要进行批归一化。

rearrange_data 方法用于重新排列数据,计算填充和滑动窗口的起始位置,以确保卷积操作的正确性。

shift 方法用于计算填充、窗口的起始索引等参数,以确保卷积操作不改变特征图的大小。

conv_bn 函数是一个工厂函数,根据传入的卷积核大小创建相应的卷积和批归一化层,支持大核和小核的组合。

fuse_bn 函数用于将卷积层和批归一化层融合,返回融合后的卷积核和偏置。

ReparamLargeKernelConv 类是该文件的核心部分,它实现了一个重参数化的大核卷积层。构造函数中根据输入参数创建卷积层,并根据需要添加小卷积层。前向传播方法根据条件选择不同的卷积路径,并在最后应用激活函数和批归一化。

该类还包含 get_equivalent_kernel_bias 方法,用于获取融合后的卷积核和偏置,以及 switch_to_deploy 方法,用于在部署时将卷积层转换为重参数化的形式,以提高推理效率。

整体来看,这个文件实现了一个灵活且高效的卷积模块,支持多种卷积核组合和重参数化策略,适用于深度学习模型的构建和优化。

源码文件

源码获取

欢迎大家点赞、收藏、关注、评论 啦 、查看👇🏻获取联系方式👇🏻

相关推荐
C嘎嘎嵌入式开发5 小时前
(21)100天python从入门到拿捏《XML 数据解析》
xml·开发语言·python
蓝博AI6 小时前
基于卷积神经网络的香蕉成熟度识别系统,resnet50,vgg16,resnet34【pytorch框架,python代码】
人工智能·pytorch·python·神经网络·cnn
小白银子6 小时前
零基础从头教学Linux(Day 54)
linux·windows·python
不爱搬砖的码农6 小时前
宝塔面板部署Django:使用Unix Socket套接字通信的完整教程(附核心配置与问题排查)
python·django·unix
滑水滑成滑头6 小时前
**发散创新:探索零信任网络下的安全编程实践**随着信息技术的飞速发展,网络安全问题日益凸显。传统的网络安全防护方式已难以
java·网络·python·安全·web安全
JA+6 小时前
vue 实时数据表格组件 (stk-table-vue)
前端·javascript·vue.js
丁浩6666 小时前
Python机器学习---1.数据类型和算法:线性回归
开发语言·python·机器学习·线性回归
那年窗外下的雪.6 小时前
鸿蒙ArkUI布局与样式进阶(十二)——自定义TabBar + class类机制全解析(含手机商城底部导航案例)
开发语言·前端·javascript·华为·智能手机·harmonyos·arkui
H_z_q24016 小时前
Python动态类型、运算符、输入处理及算法编程问答
python