深度学习之视觉处理

CNN

  • 视觉处理三大任务:分类、目标检测、图像分割
  • 上游:提取特征,CNN
  • 下游:分类、目标、分割等,具体的任务

概述

  • 卷积神经网络是深度学习在计算机视觉领域的突破性成果。在计算机视觉领域, 往往我们输入的图像都很大,使用全连接网络的话,计算的代价较高 。另外图像也很难保留原有的特征 ,导致图像处理的准确率不高
  • 卷积神经网络(Convolutional Neural Network,CNN)是一种专门用于处理具有网格状结构数据 的深度学习模型。最初,CNN主要应用于计算机视觉任务,但它的成功启发了在其他领域应用,如自然语言处理等。
  • 卷积神经网络(Convolutional Neural Network)是含有卷积层 的神经网络. 卷积层的作用就是用来自动学习、提取图像的特征。

CNN网络 主要有三部分构成:卷积层、池化层和全连接层构成 ,其中卷积层负责提取图像中的局部特征 ;池化层用来大幅降低 运算量并特征增强 ;全连接层类似神经网络的部分,用来输出想要的结果。

全连接的局限性

  • 全连接神经网络并不太适合处理图像数据

参数量巨大

  • 全连接结构计算量非常大,假设我们有1000×1000的输入,如果隐藏层也是1000×1000大小的神经元,由于神经元和图像每一个像素连接,则参数量会达到惊人的1000×1000×1000×1000,仅仅一层网络就已经有个参数。

表达能力太有限

  • 全连接神经网络的角色只是一个分类器,如果将整个图片直接输入网络,不仅参数量大,也没有利用好图片中像素的空间特性,增加了学习难度,降低了学习效果。

卷积思想

  • 卷:从左往右,从上往下
  • 积:乘积,求和

概念

局部连接
  • 局部连接可以更好地利用图像中的结构信息,空间距离越相近的像素其相互影响越大。
  • 根据局部特征完成目标的可辨识性
权重共享
  • 图像从一个局部区域学习到的信息应用到其他区域。
  • 减少参数,降低学习难度。

卷积层

卷积核

1.卷积核是卷积运算过程中必不可少的一个"工具",在卷积神经网络中,卷积核是非常重要的,它们被用来提取图像中的特征。

2.卷积核其实是一个小矩阵,在定义时需要考虑以下几方面的内容:

  • 卷积核的个数:卷积核(过滤器)的个数决定了其输出特征矩阵的通道数
  • 卷积核的值:卷积核的值是自定义的,根据想要提取的特征来进行设置,后续进行更新。
  • 卷积核的大小:常见的卷积核有1×1、3×3、5×5等,一般都是奇数 × 奇数。

3.下图就是一个3×3的卷积核:

卷积计算

卷积计算过程

1.卷积的过程是将卷积核在图像上进行滑动计算,每次滑动到一个新的位置时,卷积核和图像进行点对点的计算,并将其求和得到一个新的值,然后将这个新的值加入到特征图中,最终得到一个新的特征图。

  • input 表示输入的图像
  • filter 表示卷积核, 也叫做滤波器
  • input 经过 filter 的得到输出为最右侧的图像,该图叫做特征图
  • 左上角的点计算方法:
  • 按照上面的计算方法可以得到最终的特征图为:

2.卷积的重要性在于它可以将图像中的特征与卷积核进行卷积操作,从而提取出图像中的特征

3.可以通过不断调整卷积核的大小、卷积核的值和卷积操作的步长,可以提取出不同尺度和位置的特征。

python 复制代码
# 面相对象的模块化编程
from matplotlib import pyplot as plt
import os
import torch.nn as nn
import torch


def test001():
    # __file__当前文件
    current_path = os.path.dirname(__file__)
    print(current_path)
    img_path = os.path.join(current_path, '..\data','1.png')
    print("img_path:",img_path)
    # 转换为相对路径
    img_path = os.path.realpath(img_path)
    print("img_realpath:",img_path)

    # 使用plt读取图片
    img = plt.imread(img_path)
    print(img.shape)
    # 转换为张量:HWC-->CHW-->NCHW 链式调用
    # 深拷贝原图在进行链式操作,返回一个新值
    img = torch.Tensor(img).permute(2,0,1).unsqueeze(0)

    # 创建卷积核
    conv = nn.Conv2d(
        in_channels=4,# 输入通道数
        out_channels=1,# 输出通道数
        # 如果要产出32个特征图,那么就需要32个卷积核,每个卷积核的通道数为这个卷积核的通道数为4
        # out_channels=32,# 输出通道数
        kernel_size=3,# 卷积核大小
        # kernel_size=(5,3),# 卷积核大小
        stride=1,# 步长
        padding=0 # 填充
        # bias=True
)
    # 使用卷积核,对图像进行卷积操作
    out = conv(img)
    # 把图片显示出来
    print(out.shape)
    # out[0][0]: 806, 574
    # out[0][0]:其中含有梯度等元素
    # detach叶子结点,数据的引用,只指向源数据,不包含梯度等其他元素
    plt.imshow(out[0][0].detach().numpy(), cmap='gray')
    # 取第32个卷积核的输出显示
    # plt.imshow(out[0][31].detach().numpy(), cmap='gray')

    plt.show()

# 作为主机模块执行
if __name__ == '__main__':
    test001()
python 复制代码
# 面相对象的模块化编程
from matplotlib import pyplot as plt
import os
import torch.nn as nn
import torch


def test001():
    # __file__当前文件
    current_path = os.path.dirname(__file__)
    print(current_path)
    img_path = os.path.join(current_path, '..\data','1.png')
    print("img_path:",img_path)
    # 转换为相对路径
    img_path = os.path.realpath(img_path)
    print("img_realpath:",img_path)

    # 使用plt读取图片
    img = plt.imread(img_path)
    print(img.shape)
    # 转换为张量:HWC-->CHW-->NCHW 链式调用
    # 深拷贝原图在进行链式操作,返回一个新值
    img = torch.Tensor(img).permute(2,0,1).unsqueeze(0)

    # 创建卷积核
    conv = nn.Conv2d(
        in_channels=4,# 输入通道数
        # 如果要产出32个特征图,那么就需要32个卷积核,每个卷积核的通道数为这个卷积核的通道数为4
        out_channels=32,# 输出通道数
        kernel_size=(5,3),# 卷积核大小
        stride=1,# 步长
        padding=0,# 填充
        bias=True
)
    # 使用卷积核,对图像进行卷积操作
    out = conv(img)

    # 输出128个特征图
    conv2 = nn.Conv2d(
        in_channels=32,# 输入通道数
        out_channels=128,# 输出通道数
        # 如果要产出32个特征图,那么就需要32个卷积核,每个卷积核的通道数为这个卷积核的通道数为4
        kernel_size=(5,3),# 卷积核大小
        stride=1,# 步长
        padding=0,
        bias=True
    )
    out = conv2(out)
    # 把图片显示出来
    print(out.shape)
    # out[0][0]: 806, 574
    # out[0][0]:其中含有梯度等元素
    # detach叶子结点,数据的引用,只指向源数据,不包含梯度等其他元素
    # 取第32个卷积核的输出显示
    plt.imshow(out[0][31].detach().numpy(), cmap='gray')

    plt.show()

# 作为主机模块执行
if __name__ == '__main__':
    test001()
卷积计算底层实现
  • 并不是水平和垂直方向的循环。
  • 下图是卷积的基本运算方式:
  • 卷积真正的计算过程如下图:

边缘填充

Padding
  • 通过上面的卷积计算,我们发现最终的特征图比原始图像要小 ,如果想要保持图像大小不变, 可在原图周围 添加padding来实现,更重要的,边缘填充还更好的保护了图像边缘数据的特征。

步长Stride

  • 按照步长为1来移动卷积核
  • 如果我们把 Stride 增大为2
  • stride太小:重复计算较多,计算量大,训练效率降低 ; stride太大:会造成信息遗漏,无法有效提炼数据背后的特征;

多通道卷积计算

数字图像的标识
  • 图像在计算机眼中是一个矩阵,通道越多,可以表达的特征就越丰富
具体计算实现

1.计算方法

  • 当输入有多个通道(Channel), 例如RGB三通道, 此时要求卷积核需要有相同的通道数。
  • 卷积核通道与对应的输入图像通道进行卷积。
  • 将每个通道的卷积结果按位相加得到最终的特征图。

多卷积核卷积计算

  • 实际对图像进行特征提取时, 我们需要使用多个卷积核 进行特征提取。这个多个卷积核可以理解为从不同到的视角、不同的角度对图像特征进行提取。所有卷积核输出值决定了卷积和有几个

特征图大小

1.输出特征图的大小与以下参数息息相关:

  • size: 卷积核/过滤器大小,一般会选择为奇数,比如有 1×1, 3×3, 5×5
  • Padding: 零填充的方式
  • Stride: 步长

2.例:

  • 输入图像大小: W x W
  • 卷积核大小: F x F
  • Stride: S
  • Padding: P
  • 输出图像大小: N x N

3.例:

  • 图像大小: 5 x 5
  • 卷积核大小: 3 x 3
  • Stride: 1
  • Padding: 1
  • (5 - 3 + 2) / 1 + 1 = 5, 即得到的特征图大小为: 5 x 5

连续卷积

卷积参数共享

数据是32×32×3的图像,用 10 个 5×5×3 的filter来进行卷积操作,所需的权重参数有多少个呢?

  • 5×5×3 = 75,表示每个卷积核只需要75个参数。
  • 10个不同的卷积核,就需要10*75 = 750个卷积核参数。
  • 如果还考虑偏置参数b,最终需要 750+10=760 个参数。

局部特征提取

  • 通过卷积操作,CNN具有局部感知性,能够捕捉输入数据的局部特征,这在处理图像等具有空间结构的数据时非常有用。

PyTorch卷积层神经网络

python 复制代码
import torch
import torch.nn.functional as F


class MyNet(torch.nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        # 第一层卷积:30 (W - K + 2P) /S + 1:输出的宽高,因为此时是矩阵就计算一个表就行
        self.conv1 = torch.nn.Conv2d(
            in_channels=1, # 输入通道
            out_channels=32, # 输出的通道
            kernel_size=3, # 卷积核大小
            padding= 0, # 填充
            stride=1, # 步长
        )
        # 第二层,输出128个通道:28 (W - K + 2P) /S + 1
        self.conv2 = torch.nn.Conv2d(
            in_channels=32, # 输入通道
            out_channels=128, # 输出的通道
            kernel_size=3, # 卷积核大小
            padding= 0, # 填充
            stride=1, # 步长
        )
        # 第三个通道,输出512个通道:26 (W - K + 2P) /S + 1
        self.conv3 = torch.nn.Conv2d(
            in_channels=128, # 输入通道
            out_channels=512, # 输出的通道
            kernel_size=3, # 卷积核大小
            padding= 0, # 填充
            stride=1, # 步长
        )
        # 线性层做分类判断,10分类
        self.fc = torch.nn.Linear(512*26*26, 10)

    def forward(self, x):
        # 卷积层
        x = F.relu(self.conv1(x))
        print(x.shape)
        x = F.relu(self.conv2(x))
        x = F.relu(self.conv3(x))
        # 输出NCHW,然后做全连接
        # x.size(0):输出的有几个N
        x = x.view(x.size(0), -1)
        print(x.shape)
        # 输入的数据有四条,每条数据10个输出值
        x = self.fc(x)
        # 每条数据进行激活,每条数据有10分类
        x = torch.nn.Softmax(dim=1)(x)
        return x


if __name__ == '__main__':
    # N = 4 C=1 H=32 W=32
    input = torch.randn(4,1,32,32)
    model = MyNet()
    out = model(input)
    print(out)

池化层

概述

1.池化层 (Pooling) 降低维度 , 缩减模型大小,提高计算速度. 即: 主要对卷积层学习到的特征图进行下采样(SubSampling)处理。

2.池化层主要有两种:

(1)最大池化 max pooling

  • 最大池化是从每个局部区域中选择最大值作为池化后的值,这样可以保留局部区域中最显著的特征。最大池化在提取图像中的纹理、形状等方面具有很好的效果。

(2)平均池化 avgPooling

  • 平均池化是将局部区域中的值取平均作为池化后的值,这样可以得到整体特征的平均值。平均池化在提取图像中的整体特征、减少噪声等方面具有较好的效果。

池化层计算

整体结构

计算

步长Stride

  • 计算方法和卷积核步长计算方法一致

边缘填充Padding

多通道池化计算

  • 在处理多通道输入数据时,池化层对每个输入通道分别池化,而不是像卷积层那样将各个通道的输入相加。这意味着池化层的输出和输入的通道数是相等。

池化层的作用

1.池化操作的优势有:

  • 通过降低特征图的尺寸,池化层能够减少计算量,从而提升模型的运行效率。
  • 池化操作可以带来特征的平移、旋转 等不变性,这有助于提高模型对输入数据的鲁棒性
  • 池化层通常是非线性操作,例如最大值池化,这样可以增强网络的表达能力,进一步提升模型的性能。

2.池化也有缺点:

  • 池化操作会丢失一些信息,这是它最大的缺点;

池化API

API请参考具体官方文档:torch.nn --- PyTorch 2.5 documentationhttps://pytorch.org/docs/stable/nn.html#padding-layers

python 复制代码
import torch
import torch.nn as nn

def test01():
    torch.manual_seed(1)
    # 输入的特征图数据
    input = torch.randint(0, 255, (1, 64, 224, 224), dtype=torch.float)
    print(input[0][0][0:4,:5])
    
    # 池化核
    pool = nn.MaxPool2d(
        kernel_size=2, # 池化核大小
        stride=2, # 步长
        return_indices=True# 返回索引
        )
    # 对数据进行池化操作
    out, indices = pool(input)
    print(indices)
    print(out.shape)


if __name__ == '__main__':
    test01()

整体结构

  • 卷积池化全连接神经网络框架
python 复制代码
import torch
import torch.nn as nn

class numberModel(nn.Module):
    def __init__(self):
        super(numberModel, self).__init__()
        # 卷积层
        self.C1 = nn.Sequential(nn.Conv2d(
            in_channels=1, # 输入通道
            out_channels=6, # 输出通道
            kernel_size=5, # 卷积核大小
            stride=1, # 步长
            padding=0 # 填充
        ), nn.ReLU())
        # 池化层
        self.S2 = nn.MaxPool2d(kernel_size=2,stride=2,padding=0)
        # 卷积层
        self.C3 = nn.Sequential(nn.Conv2d(
            in_channels=6, # 输入通道
            out_channels=16, # 输出通道
            kernel_size=5, # 卷积核大小
            stride=1, # 步长
            padding=0 # 填充
        ), nn.ReLU())
        # 全连接层
        self.FC1 = nn.Sequential(nn.Linear(16*5*5,120, bias=True), nn.ReLU())
        self.FC2 = nn.Sequential(nn.Linear(120,84, bias=True), nn.ReLU())
        self.out = nn.Sequential(nn.Linear(84,10, bias=True), nn.Softmax(dim=1))
    def forward(self, x):
        x = self.C1(x)
        x = self.S2(x)
        x = self.C3(x)
        x = self.S2(x)
        x = x.view(x.size()[0],-1) # 自动计算的数量批次Batch
        x = self.FC1(x)
        x = self.FC2(x)
        x = self.out(x)
        return x
if __name__ == '__main__':
    torch.manual_seed(1)
    # 网络
    model = numberModel()
    # 输入数据 NCHW
    input = torch.randn(1, 1, 32, 32)
    # 输出结果
    output = model(input)
    print(output)
"""
tensor([[0.1055, 0.0958, 0.1093, 0.0939, 0.0942, 0.0990, 0.1092, 0.0956, 0.0874,
         0.1102]], grad_fn=<SoftmaxBackward0>)
"""

特征图变化

卷积知识扩展

卷积结果

二维卷积

  • 分单通道版本和多通道版本。
单通道版本
  • 之前所讲卷积相关内容其实真正意义上叫做二维卷积(单通道卷积版本),即只有一个通道的卷积。
多通道版本
  • 彩色图像拥有R、G、B这三层通道,因此我们在卷积时需要分别针对这三层进行卷积
  • 最后将三个通道的卷积结果进行合并(元素相加),得到卷积结果

三维卷积(3D)

  • 二维卷积是在单通道的一帧图像上进行滑窗操作,输入是高度H宽度W的二维矩阵。
  • 而如果涉及到视频上的连续帧或者立体图像中的不同切片,就需要引入深度通道,此时输入就变为高度H宽度W*深度C的三维矩阵。
  • 不同于二维卷积核只在两个方向上运动,三维卷积的卷积核会在三个方向上运动,因此需要有三个自由度
  • 这种特性使得三维卷积能够有效地描述3D空间中的对象关系,它在一些应用中具有显著的优势,例如3D对象的分割以及医学图像的重构等。

反卷积

  • 卷积是对输入图像及进行特征提取,这样会导致尺寸会越变越小 ,而反卷积是进行相反操作。并不会完全还原到跟输入图一样,只是保证了与输入图像 尺寸一致,主要用于向上采样。从数学上看,反卷积相当于是将卷积核转换为稀疏矩阵后进行转置计算 。也被称为转置卷积
反卷积计算过程
  • 在2x2的输入图像上使用【步长1、边界全0填充】的3x3卷积核,进行转置卷积(反卷积)计算,向上采样后输出的图像大小为4x4。语义分割里面就需要反卷积还原到原始图像大小。
反卷积底层计算

空洞卷积(膨胀卷积)

扩大感受野 ,在卷积核矩阵的元素之间插入空格**"膨胀"内核** ,形成**"空洞卷积"** (或称膨胀卷积 ),并用膨胀率参dilationL 表示要扩大内核的范围,即在内核元素之间插入dilation -1个空格。当dilation=1 时,则内核元素之间没有插入空格,变为标准卷积。图中是dilation=2的空洞卷积。

  • 代码实现过程
python 复制代码
import torch
import torch.nn as nn

def test01():
    torch.manual_seed(1)
    #输入数据
    x = torch.randn(1, 1, 7, 7)
    # 创建一个卷积核
    conv = nn.Conv2d(
        in_channels=1, # 输入通道数
        out_channels=1, # 输出通道数
        kernel_size=3, # 卷积核大小
        stride=1, # 步长
        padding=0, # 填充
        dilation=2 # 卷积核的步长
        )
    out = conv(x)
    print(out.shape)

if __name__ == '__main__':
    test01()

"""
torch.Size([1, 1, 3, 3])
"""

可分离卷积

空间可分离卷积
  • 空间可分离卷积是将卷积核分解为两项独立的核分别进行操作。在数学中我们可以将矩阵分解:
  • 所以对3x3的卷积核,我们同样可以拆分成 3x1 和 1x3 的两个卷积核,对其进行卷积,且采用可分离卷积的计算量比标准卷积要少。
  • 代码实现过程
python 复制代码
import torch
import torch.nn as nn

class nomalModel(nn.Module):
    def __init__(self):
        super(nomalModel, self).__init__()
        self.conv1 = nn.Conv2d(
            in_channels=1, # 输入通道
            out_channels=1, # 输出通道
            kernel_size=3, # 卷积核大小
            stride=1, # 步长
            padding=0,# 填充
            bias=False # 是否使用偏置
        )

    def forward(self, x):
        out = self.conv1(x)
        return out
        
class waveModel(nn.Module):
    def __init__(self):
        super(waveModel, self).__init__()
        self.conv1 = nn.Conv2d(
            in_channels=1, # 输入通道
            out_channels=1, # 输出通道
            kernel_size=(3,1), # 卷积核大小
            stride=1, # 步长
            padding=0,# 填充
            bias=False, # 是否使用偏置
            groups=1 # 分组卷积
        )
        self.conv2 = nn.Conv2d(
            in_channels=1, # 输入通道
            out_channels=1, # 输出通道
            kernel_size=(1,3), # 卷积核大小
            stride=1, # 步长
            padding=0,# 填充
            bias=False, # 是否使用偏置
            groups=1 # 分组卷积
        )
    def forward(self, x):
        out = self.conv1(x)
        out = self.conv2(out)
        return out


if __name__ == '__main__':
    model1 = nomalModel()
    # 打印参数
    for name, param in model1.named_parameters():
        print(name, param.shape)
    print("======================")
    model2 = waveModel()
    for name, param in model2.named_parameters():
        print(name, param.shape)

"""
conv1.weight torch.Size([1, 1, 3, 3]) 3*3
======================
conv1.weight torch.Size([1, 1, 3, 1])3
conv2.weight torch.Size([1, 1, 1, 3])3  ==>3+3
"""
深度可分离卷积

1.深度可分离卷积由两部组成:深度卷积核1x1卷积

  • 输入图的每一个通道,我们都使用了对应的卷积核进行卷积。 通道数量 = 卷积核个数

  • 完成卷积后,对输出内容进行1x1的卷积

  • 代码实现

python 复制代码
import torch
import torch.nn as nn

class normalModel(nn.Module):
    def __init__(self):
        super(normalModel, self).__init__()
        self.conv1 = nn.Conv2d(
            in_channels=8, # 输入通道
            out_channels=8,# 输出通道
            kernel_size=3, # 卷积核大小
            stride=1, # 步长
            padding=0, # 填充
            bias=False # 是否使用偏置
        )


    def forward(self, x):
        out = self.conv1(x)
        return out

class deepModel(nn.Module):
    def __init__(self) -> None:
        super(deepModel, self).__init__()
        self.conv1 = nn.Conv2d(
            in_channels=8, # 输入通道
            out_channels=8,# 输出通道
            kernel_size=3, # 卷积核大小
            stride=1, # 步长
            padding=0, # 填充
            bias=False, # 是否使用偏置
            groups=8 # 分组卷积 卷积核数量等于输入通道的数量8/8 = 1
        )
        self.conv2 = nn.Conv2d(
            in_channels=8, # 输入通道
            out_channels=8,# 输出通道
            kernel_size=1, # 卷积核大小
            stride=1, # 步长
            padding=0, # 填充
            bias=False # 是否使用偏置
        )

    def forward(self, x):
        x = self.conv1(x)
        out = self.conv2(out)
        return out
if __name__ == '__main__':
    conv1 = normalModel()
    for name, param in conv1.named_parameters():
        print(name, param.shape) # 576
    print("======================")
    conv2 = deepModel()
    for name, param in conv2.named_parameters():
        print(name, param.shape) # 136

"""
conv1.weight torch.Size([8, 8, 3, 3])
======================
conv1.weight torch.Size([8, 1, 3, 3])
conv2.weight torch.Size([8, 8, 1, 1])
"""

扁平卷积

  • 扁平卷积是将标准卷积拆分成为3个1x1的卷积核,然后再分别对输入层进行卷积计算。
  • 标准卷积参数量XYC,计算量为MNCXY
  • 拆分卷积参数量(X+Y+C),计算量为MN(C+X+Y)

分组卷积

  • 2012年,AlexNet论文中最先提出来的概念,当时主要为了解决GPU显存不足问题,将卷积分组放到两个GPU中并行执行。
  • 在分组卷积中,卷积核被分成不同的组,每组负责对相应的输入层进行卷积计算,最后再进行合并。

混洗分组卷积

  • 分组卷积中最终结果会按照原先的顺序进行合并组合,阻碍了模型在训练时特征信息在通道间流动,削弱了特征表示。混洗分组卷积,主要是将分组卷积后的计算结果混合交叉在一起输出。

多通道卷积与偏执

卷积核卷完之后,偏置矩阵就会与输出特征矩阵相加,得到本次卷积的最终结果。

有两个结论:

  • 输入特征的通道数决定了卷积核的通道数(卷积核通道个数=输入特征通道个数)。
  • 卷积核的个数决定了输出特征矩阵的通道数与偏置矩阵的通道数(卷积核个数=输出特征通道数=偏置矩阵通道数)。

感受野

理解感受野

  • 字面意思是感受的视野范围,如果堆叠3个3 x 3的卷积层,并且保持滑动窗口步长为1,其感受野就是7×7的了, 这跟一个使用7x7卷积核的结果是一样的

感受野的作用

  • 假设输入大小都是h × w × C,并且都使用C个卷积核(得到C个特征图),可以来计算 一下其各自所需参数
相关推荐
明明真系叻9 分钟前
2025.4.20机器学习笔记:文献阅读
人工智能·笔记·机器学习
学术小八31 分钟前
2025年机电一体化、机器人与人工智能国际学术会议(MRAI 2025)
人工智能·机器人·机电
爱的叹息34 分钟前
关于 雷达(Radar) 的详细解析,涵盖其定义、工作原理、分类、关键技术、应用场景、挑战及未来趋势,结合实例帮助理解其核心概念
人工智能·分类·数据挖掘
许泽宇的技术分享36 分钟前
.NET MCP 文档
人工智能·.net
anscos1 小时前
Actran声源识别方法连载(二):薄膜模态表面振动识别
人工智能·算法·仿真软件·actran
-曾牛1 小时前
【LangChain4j快速入门】5分钟用Java玩转GPT-4o-mini,Spring Boot整合实战!| 附源码
java·开发语言·人工智能·spring boot·ai·chatgpt
token-go1 小时前
[特殊字符] KoalaAI 1.0.23 震撼升级:GPT-4.1免费畅享,AI革命触手可及!
人工智能
云卓SKYDROID2 小时前
无人机避障与目标识别技术分析!
人工智能·无人机·科普·高科技·云卓科技·激光避障
chuangfumao2 小时前
解读《人工智能指数报告 2025》:洞察 AI 发展新态势
人工智能·搜索引擎·百度
可爱の小公举2 小时前
自然语言处理(NLP)领域大图
人工智能·自然语言处理