python卷积神经网络人脸识别示例实现详解

news2025/2/13 3:32:33

目录

一、准备

1)使用pytorch

2)安装pytorch

3)准备训练和测试资源

二、卷积神经网络的基本结构

三、代码实现

1)导入库

2)数据预处理

3)加载数据

4)构建一个卷积神经网络

 5)模型训练

6)模型测试

四、测试结果 

五、模型导出

1)保存模型的状态参数

 2)保存完整模型

 六、总结


一、准备

1)使用pytorch

为什么建议使用pytorch来构建卷积神经网络呢?因为pytorch是基于python开发的一个神经网络工具包,它已经实现了激活函数定义、权重矩阵定义、卷积计算、正向传播、反向传播、权重矩阵更新等神经网络的基本操作,而不需要我们再去编写代码实现这些功能,只需调用相应的函数就可以搭建好我们所需的网络结构。pytorch极大方便了我们构建神经网络,加快了神经网络开发速度,我们只需要关注网络的结构层次,而不用关心所建立的网络具体训练和预测过程。

2)安装pytorch

pytorch有CPU版和GPU版,GPU版需要使用到英伟达的显卡来加快网络速度,安装过程也稍显复杂。本文重点是对python卷积神经网络示例解析,因此安装CPU版。在pycharm开发工具的终端中直接执行命令:pip install torch torchvision torchaudio,即可完成pytorch的CPU版本安装。

3)准备训练和测试资源

因为使用pytorch开发卷积神经网络实现人脸识别,pytorch对数据存放有一定要求,因此需要将相关资源放在特定的目录结构下。训练目录和测试目录结构如下图所示,在文件夹中放入相应的图片资源即可。文件路径可以自行定义,但是同一个人的照片必须放在同一个文件夹下,pytorch根据该文件夹的名称自动将相应的图片资源归于一类。

二、卷积神经网络的基本结构

一个简单的卷积神经网络包括输入层、卷积层、池化层、扁平化层和全连接层。网络的复杂度体现在卷积、池化层的大小和数量上。卷积神经网络主要用于处理有大量数据输入的情景,如图像识别是最好的例子,可以极大减少运算量。下面以一个人脸识别的实际例子,详细讲解卷积神经网络的搭建流程。

三、代码实现

1)导入库

使用PyCharm工具新建一个.py文件,在文件中导入下面需要使用到的相关库。在导入下面的库前,需要确保已经安装好了pytorch相关依赖包。

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader

2)数据预处理

以下定义了一组针对图片进行预处理的方法,包括3个。第一个是将图像调整为100*100像素大小,这样我们就可以输入任何大小图片,并能保证数据输入到网络中的大小是一致的。第二个是将图像数据转换为张量格式,这时pytorch自定义的一种数据格式,可以简单理解为类似于多维向量。第三个是对图像进行归一化处理,其目的是使数据的均值为 0,标准差为 1。这样做可以加速模型的训练过程,提高模型的稳定性和收敛速度。函数参数如下:

  • mean:一个长度为 3 的列表,分别代表图像三个通道(RGB)的均值。这里 [0.485, 0.456, 0.406] 是在 ImageNet 数据集上统计得到的三个通道的均值。

  • std:一个长度为 3 的列表,分别代表图像三个通道(RGB)的标准差。[0.229, 0.224, 0.225] 是在 ImageNet 数据集上统计得到的三个通道的标准差。

 参数的取值可以直接使用上面提供的经验值。对于输入图像的每个像素RGB值 ,归一化后的像素RGB值 按照以下公式计算:

其中,mean 和 std 分别是对应通道的均值和标准差。

transform = transforms.Compose([
    transforms.Resize((100, 100)),  # 调整图像大小
    transforms.ToTensor(),  # 将图像转换为张量
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])  # 归一化
])

3)加载数据

使用dataset.ImageFolder()加载需要的训练图像和测试凸显数据。这里的数据路径需要注意,并没有到具体的文件名。比如在D:/zhaopian/train目录下,程序会自动读取该目录下的子文件夹,并将子文件夹中的图像数据归集到以该子文件夹命名的类别中。参数transform=transform就是调用上述第二步定义的数据预处理方法集,在读取每一张图像数据时将自动依次执行上述3个方法。并将最终转换好的数据返回。

创建数据加载器是为了便于网络训练时分批次加载数据,避免一次加载所有图像数据导致内存不足。

  • batch_size=32:指定每个批次中包含的数据样本数量。这里设置为 32,表示每次从 train_dataset 中取出 32 个样本组成一个批次进行训练。batch_size 的选择会影响模型的训练速度和性能,较大的 batch_size 可以加快训练速度,但可能会导致内存不足;较小的 batch_size 可以增加模型的泛化能力,但训练速度会变慢。

  • shuffle=True:一个布尔值,用于指定是否在每个训练周期(epoch)开始时打乱数据集的顺序。设置为 True 可以增加数据的随机性,避免模型学习到数据的特定顺序,有助于提高模型的泛化能力。

train_dataset = datasets.ImageFolder(root='D:/zhaopian/train', transform=transform)
test_dataset = datasets.ImageFolder(root='D:/zhaopian/test', transform=transform)
all_samples = test_dataset.samples
print("数据集中的类别:", train_dataset.classes)

# 创建数据加载器
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

4)构建一个卷积神经网络

自定义一个卷积神经网络类FaceCNN,继承自nn.Module。该网络包含两个卷积层,两个池化层,两个全连接层。在卷积层和全连接层之间均使用了相同的激活函数ReLU:

函数 nn.Conv2d(3, 16, kernel_size=3, padding=1) 的作用是定义一个二维卷积层,参数3表示输入的数据是3个通道,这里对应的是彩色图像的RGB三组数据,即每张图会有3个100*100的矩阵输入到该卷积层中。参数16表示该卷积层有16个卷积核,每个核的大小均是3*3(参数kernel_size=3确定的)的矩阵,这16个3*3的卷积核初始值是随机的,它的值是通过模型训练最终确定的,也就是神经网络中的权重矩阵。定义16个卷积核意味着什么呢?当一幅彩色图像输入该卷积层时,该图像有3组矩阵,每组矩阵与一个卷积核进行卷积,得到3个卷积后的矩阵,然后在将这3个卷积后的矩阵对应位置取平均值,得到一个最终的卷积均值矩阵。16个卷积核依次执行上述操作,则经过该卷积层后,会得到16个卷积均值矩阵。参数padding=1表示对输入数据进行扩充,1表示在数据四周加一行,填充的目的通常是为了保持输入和输出特征图的尺寸一致。那么,经过该卷积层后,最终会得到16个100*100的卷积均值矩阵。

函数nn.MaxPool2d(2)的作用是定义一个2*2的二维池化层,该池化层输出池中的最大值。在最大池化操作中,池化窗口会在输入特征图上滑动,对每个窗口内的元素进行操作。这里设置为 2,表示使用一个 2x2 的池化窗口。当池化窗口在特征图上滑动时,会选取每个 2x2 区域内的最大值作为该区域的输出值。此处需要注意的是,经过2*2的二维池化层后,输出的矩阵变为了50*50,因为池化层的步幅等于它的大小,这与卷积不同,卷积默认步幅为1。

函数nn.Conv2d(16, 32, kernel_size=3, padding=1) 用于定义第二个二维卷积层。在该卷积层中,前面两个参数分别是16和32,16对应的是前面的16个卷积核,因为一幅图像经过第一层卷积后会输出16组数据,所以此处第二层卷积时,输入的数据就是16组。32表示第二层卷积后输出32组50*50的矩阵。

函数nn.Linear(32 * 25 * 25, 128)的作用是定义一个全连接层,全连接层的每个神经元都与前一层的所有神经元相连接,通过对输入进行线性变换(加权求和)并加上偏置,实现从输入特征到输出特征的映射。第一个参数32 * 25 * 25=20000,表示输入数据的数量,128表示输出数据的数量。全连接层线性变换公式为:

 其中, x是输入向量,W 是权重矩阵,b 是偏置向量, y是输出向量。权重矩阵W的形状为 (20000, 128), b的形状为 (128,1)。W和b都是在模型训练中需要更新的矩阵。

在建立的神经网络中还定义了前向传播函数forward(),它由开发者自行设计数据在网络中传播的方向。图像数据首先经过第一个卷积层,然后通过激活函数,再进入第一个池化层,随后依次进入第二个卷积层,第二个激活函数,第二个池化层。x = x.view(-1, 32 * 25 * 25)的作用是将得到的数据展平为一维数据。从前面的输出可知,x是一组由32个25*25矩阵组成的数据集,x.view会将该数据集整合为一个一维数组,数组的元素总量保持不变。

数据在经过展平后,进入了第一全连接层,由网络结构可知,第一个全连接层输出的是一个128个元素的数组,数据量被极大压缩了。然后再次经过激活函数,随后进入第二个全连接层,第二个全连接层输出的数组由n个元素组成,n=len(train_dataset.classes),就是我们训练模型时提供的n个人数。但需要注意的是,此处输出的结果与人脸识别并无直接关系,我们需要对该结果进行进一步处理,让它与人脸对应起来。

class FaceCNN(nn.Module):
    def __init__(self):
        super(FaceCNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)  # 定义第一个二维卷积层
        self.relu1 = nn.ReLU()  # 定义第一个激活函数
        self.pool1 = nn.MaxPool2d(2)  # 定义第一个二维池化层
        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)  # 定义第二个二维卷积层
        self.relu2 = nn.ReLU()  # 定义第二个激活函数
        self.pool2 = nn.MaxPool2d(2)  # 定义第二个二维池化层
        self.fc1 = nn.Linear(32 * 25 * 25, 128)  # 定义第一个全连接层,展平后输出128个特征量
        self.relu3 = nn.ReLU()  # 定义第三个激活函数
        self.fc2 = nn.Linear(128, len(train_dataset.classes))  # 定义第二个全连接层,展平后输出n个特征量,n为人数

    def forward(self, x):
        x = self.pool1(self.relu1(self.conv1(x)))
        x = self.pool2(self.relu2(self.conv2(x)))
        x = x.view(-1, 32 * 25 * 25)
        x = self.relu3(self.fc1(x))
        x = self.fc2(x)
        return x

 5)模型训练

首先用自己定义卷积神经网络类实例化一个对象。然后定义一个损失函数,这里直接使用了pytorch库中提供的交叉熵损失函数对象,交叉熵损失函数(Cross-Entropy Loss)是分类问题中常用的一种损失函数,尤其适用于多分类任务。它能够有效衡量模型预测的概率分布与真实标签的概率分布之间的差异。该函数的具体实现比较复杂,如果不做算法研究,可以暂时不用管其具体实现,只需要知道在分类问题中适用该函数。

optimizer = optim.Adam(model.parameters(), lr=0.001) 这行代码在 PyTorch 中用于创建一个 Adam 优化器对象 optimizer,该优化器将用于更新模型 model 的参数。Adam(Adaptive Moment Estimation)是一种常用的优化算法,它结合了 AdaGrad 和 RMSProp 两种算法的优点。Adam 算法能够自适应地调整每个参数的学习率,同时利用梯度的一阶矩估计(均值)和二阶矩估计(方差)来更新参数。它具有收敛速度快、对不同类型的数据集和模型都有较好表现等优点,因此在深度学习中得到了广泛应用。我们同样也不需要去关心它的具体实现,PyTorch已经帮我们完成了相应的操作。其中的参数定义如下:

  • model.parameters():这是 optim.Adam 的第一个参数,它是一个生成器,用于返回模型 model 中所有需要更新的参数。在 PyTorch 中,模型的参数通常是可学习的张量,通过调用 model.parameters() 可以获取这些参数,优化器将根据这些参数的梯度信息来更新它们。

  • lr=0.001lr 是学习率(learning rate)的缩写,它是 optim.Adam 的一个重要超参数,用于控制每次参数更新的步长。学习率决定了模型在训练过程中朝着损失函数最小值前进的速度。这里将学习率设置为 0.001,表示每次更新参数时,参数的变化量是梯度乘以 0.001。如果学习率设置得过大,模型可能会跳过损失函数的最小值,导致无法收敛;如果学习率设置得过小,模型的训练速度会变得很慢。

# 初始化模型
model = FaceCNN()

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练模型
num_epochs = 20  # 训练10次
for epoch in range(num_epochs):
    model.train()  # 将模型设置为训练模式。
    running_loss = 0.0
    for i, (images, labels) in enumerate(train_loader):
        optimizer.zero_grad()  # 每次反向传播之前,将优化器中所有参数的梯度清零
        outputs = model(images)  # 自动调用模型的 forward 方法
        loss = criterion(outputs, labels)  # 计算损失值
        loss.backward()  # 调用 loss.backward() 开始反向传播过程,计算每个可训练参数的梯度,并将这些梯度存储在参数的 .grad 属性中。
        optimizer.step()  # 优化器会根据存储在参数 .grad 属性中的梯度,按照指定的优化算法更新模型的参数。
        running_loss += loss.item()

6)模型测试

模型测试的代码实现如下。测试时首先将模型设置为评估模式,在这里同样使用批量传入测试图像数据的方式。

_, predicted = torch.max(outputs.data, 1)用于找出在模型输出的结果outputs.data中,每一行数据的最大值在该行中的索引位置,torch.max 函数的第二个参数,指定了在哪个维度上进行最大值查找。这里设置为 1,表示在每一行(即每个样本)上查找最大值。需要进一步说明的是,由于我们采用批量处理的方式,outputs.data应是一个二维数组,每一行表示模型对一张图的处理结果。根据前面网络结构定义可知,若是输入3个人的人脸照片,则每一行应该有3个元素。这里取最大值,是因为模型输出的结果表征的是模型预测的概率,概率越大说明输入图像是对应人脸的概率越大。而对应的人脸在labels中表征,在本例中输入3个人的照片,则它是一个包含3个元素[0,1,2]的数组,每个值对应一个人。因此, torch.max找到最大值在每一行中的索引位置后,该位置也就表征了对应的人。

# 测试模型
model.eval()  # 将模型切换到评估模式。
correct = 0
total = 0
with torch.no_grad():  # 不计算导数
    for index, (images, labels) in enumerate(test_loader):
        outputs = model(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        labels_array = labels.numpy()
        predicted_array = predicted.numpy()
        # 计算当前批次的起始索引
        start_idx = index * test_loader.batch_size
        # 计算当前批次的结束索引
        end_idx = start_idx + images.size(0)
        # 获取当前批次的图像文件路径
        batch_samples = all_samples[start_idx:end_idx]
        # 提取图像文件名称
        batch_image_names = [sample[0].split('\\')[2] for sample in batch_samples]
        for i in range(len(predicted_array)):
            print(f'图名: {batch_image_names[i]}', f'实际名字: {train_dataset.classes[labels_array[i]]}',
                  f'预测名字: {train_dataset.classes[predicted_array[i]]}')
print(f'总测试数量: {total}', f'正确识别数量: {correct}')
print(f'Test Accuracy: {100 * correct / total}%')

四、测试结果 

从网络上随机下载了一些公开图片,对网路进行了训练和测试,得到结果如下。实际看神经网络的识别准确率还是比较高的。模型的完整代码和使用的资源可在这里下载。

五、模型导出

在完成神经网络模型训练后,需要将训练好的模型导出,以供后续使用,具体方法有两种。

1)保存模型的状态参数

在训练后的模型下加入下列代码,则模型中的所有参数均会保存到对应的.pth文件中。

torch.save(model.state_dict(), 'model_state_dict.pth')

在重新使用模型时,需要再次实例化模型对象,然后加载保存的模型参数。因此,重新使用时我们需要知道模型的结构定义,即重写FaceCNN类。

# 加载模型的状态字典
loaded_model = FaceCNN()
loaded_model.load_state_dict(torch.load('model_state_dict.pth'))
loaded_model.eval()  # 设置为评估模式

 2)保存完整模型

我们也可以直接保存完整的模型文件,在重新使用时直接加载该模型即可。这种方式简单,但缺少灵活性。

# 保存整个模型
torch.save(model, 'whole_model.pth')

# 加载整个模型
loaded_model = torch.load('whole_model.pth')
loaded_model.eval()  # 设置为评估模式

 六、总结

通过一个人脸识别示例,详细说明了利用pytorch模块搭建卷积神经网络的实现流程,并对代码进行了逐行解释。pytorch极大方便了神经网络开发,让开发人员可以不用关注网络中具体的算法实现,而更加侧重在网络模型搭建上。在本例试验测试中,模型的训练次数和网络结构参数的调整均会对图像识别的准确造成大幅度影响,仍需要通过大量测试优化网络结构参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2297131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

以Unity6.0为例,如何在Unity中开启DLSS功能

DLSS DLSS(NVIDIA 深度学习超级采样):NVIDIA DLSS 是一套由 GeForce RTX™ Tensor Core 提供支持的神经渲染技术,可提高帧率,同时提供可与原生分辨率相媲美的清晰、高质量图像。目前最新突破DLSS 4 带来了新的多帧…

CSDN 大模型 笔记

AI 3大范式:计算 发发 交互 L1 生成代码 复制到IDEA (22年12-23年6,7月份) L2 部分自动编程 定义class 设计interface 让其填充实现 (23年7,8月份) L3 通用任务 CRUD (24年) L4 高度自动编程 通用领域专有任务&#xf…

Stability AI 联合 UIUC 提出单视图 3D 重建方法SPAR3D,可0.7秒完成重建并支持交互式用户编辑。

Stability AI 联合 UIUC 提出一种简单而有效的单视图 3D 重建方法 SPAR3D,这是一款最先进的 3D 重建器,可以从单视图图像重建高质量的 3D 网格。SPAR3D 的重建速度很快,只需 0.7 秒,并支持交互式用户编辑。 相关链接 论文&#xf…

网易易盾接入DeepSeek,数字内容安全“智”理能力全面升级

今年农历新年期间,全球AI领域再度掀起了一波革命性浪潮,国产通用大模型DeepSeek凭借其强大的多场景理解与内容生成能力迅速“出圈”,彻底改写全球人工智能产业的格局。 作为国内领先的数字内容风控服务商,网易易盾一直致力于探索…

自动驾驶---如何打造一款属于自己的自动驾驶系统

在笔者的专栏《自动驾驶Planning决策规划》中,主要讲解了行车的相关知识,从Routing,到Behavior Planning,再到Motion Planning,以及最后的Control,笔者都做了相关介绍,其中主要包括算法在量产上…

聚焦 AUTO TECH China 2025,共探汽车内外饰新未来Automotive Interiors

全球汽车产业蓬勃发展的大背景下,汽车内外饰作为汽车重要组成部分,其市场需求与技术创新不断推动着行业变革。2025年11月20日至22日,一场备受瞩目的行业盛会 ——AUTO TECH China 2025 广州国际汽车内外饰技术展览会将在广州保利世贸博览馆盛…

Moretl 增量文件采集工具

永久免费: <下载> <使用说明> 用途 定时全量或增量采集工控机,电脑文件或日志. 优势 开箱即用: 解压直接运行.不需额外下载.管理设备: 后台统一管理客户端.无人值守: 客户端自启动,自更新.稳定安全: 架构简单,兼容性好,通过授权控制访问. 架构 技术架构: Asp…

支持多种网络数据库格式的自动化转换工具——VisualXML

一、VisualXML软件介绍 对于DBC、ARXML……文件的编辑、修改等繁琐操作&#xff0c;WINDHILL风丘科技开发的总线设计工具——VisualXML&#xff0c;可轻松解决这一问题&#xff0c;提升工作效率。 VisualXML是一个强大且基于Excel表格生成多种网络数据库文件的转换工具&#…

四、OSG学习笔记-基础图元

前一章节&#xff1a; 三、OSG学习笔记-应用基础-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/145514021 代码&#xff1a;CuiQingCheng/OsgStudy - Gitee.com 一、绘制盒子模型 下面一个简单的 demo #include<windows.h> #include<osg/Node&…

window 安装GitLab服务器笔记

目录 视频&#xff1a; 资源&#xff1a; Linux CeneOS7&#xff1a; VMware&#xff1a; Linux无法安装 yum install vim -y 1.手动创建目录 2.下载repo PS 补充视频不可复制的代码 安装GitLab *修改root用户密码相关&#xff08;我卡在第一步就直接放弃了这个操作&…

MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 基础篇 part 10

第10章_创建和管理表 DDL&#xff1a;数据定义语言。CREATE \ALTER\ DROP \RENAME TRUNCATE DML&#xff1a;数据操作语言。INSERT \DELETE \UPDATE \SELECT&#xff08;重中之重&#xff09; DCL&#xff1a;数据控制语言。COMMIT \…

前端如何判断浏览器 AdBlock/AdBlock Plus(最新版)广告屏蔽插件已开启拦截

2个月前AdBlock/AdBlock Plus疑似升级了一次 因为自己主要负责面对海外的用户项目&#xff0c;发现以前的检测AdBlock/AdBlock Plus开启状态方法已失效了&#xff0c;于是专门研究了一下。并尝试了很多方法。 已失效的老方法 // 定义一个检测 AdBlock 的函数 function chec…

html文件怎么转换成pdf文件,2025最新教程

将HTML文件转换成PDF文件&#xff0c;可以采取以下几种方法&#xff1a; 一、使用浏览器内置功能 打开HTML文件&#xff1a;在Chrome、Firefox、IE等浏览器中打开需要转换的HTML文件。打印对话框&#xff1a;按下CtrlP&#xff08;Windows&#xff09;或CommandP&#xff08;M…

科技查新过不了怎么办

“科技查新过不了怎么办&#xff1f;” “科技查新不通过的原因是什么&#xff1f;” 想必这些问题一直困扰着各位科研和学术的朋友们&#xff0c;尤其是对于查新经验不够多的小伙伴&#xff0c;在历经千难万险&#xff0c;从选择查新机构、填写线上委托单到付费&#xff0c;…

超详细的数据结构3(初阶C语言版)栈和队列。

文章目录 栈和队列1.栈1.1 概念与结构1.2 栈的实现 2. 队列2.1 概念与结构2.2 队列的实现 总结 栈和队列 1.栈 1.1 概念与结构 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只允许在固定的⼀端进行插⼊和删除元素操作。进⾏数据插⼊和删除操作的⼀端称为栈顶&#xff0c;另…

centos 7 关于引用stdatomic.h的问题

问题&#xff1a;/tmp/tmp4usxmdso/main.c:6:23: fatal error: stdatomic.h: No such file or directory #include <stdatomic.h> 解决步骤&#xff1a; 1.这个错误是因为缺少C编译器的标准原子操作头文件 stdatomic.h。在Linux系统中&#xff0c;我们需要安装开发工具…

Unity WebGL包体压缩

最近在开发webgl&#xff0c;踩了很多坑&#xff0c;先来说下包体的问题。 开发完之后发现unity将文件都合并到一个文件了&#xff0c;一共有接近100m。 这对网页端的体验来说是可怕的&#xff0c;因为玩家必须要加载完所有的文件才能进入&#xff0c;这样体验特别差。 于是想…

【对比测评】 .NET 应用的 Web 视图控件:DotNetBrowser 或 EO.WebBrowser

您是否需要 .NET 应用的 Web 视图控件&#xff1f;.NET 生态系统提供了很多东西&#xff0c;有免费的 Web 视图控件&#xff0c;既有开源的&#xff0c;也有专有的。还有一些商业 Web 视图 控件&#xff0c;也是企业经常选择的一种选项。 在这篇博文中&#xff0c;我们比较了商…

Redis 数据类型 String 字符串

Redis 中的 String 数据类型 是最基础且使用最广泛的数据类型之一。它本质上是一个字节序列&#xff0c;可以存储各种类型的数据&#xff0c;如字符串、整数、浮点数等&#xff0c;其字符串类型的值包含⼀般格式的字符串或者类似 JSON、XML 格式的字符串&#xff1b;还可以存储…

查询语句来提取 detail 字段中包含 xxx 的 URL 里的 commodity/ 后面的数字串

您可以使用以下 SQL 查询语句来提取 detail 字段中包含 oss.kxlist.com 的 URL 里的 commodity/ 后面的数字串&#xff1a; <p><img style"max-width:100%;" src"https://oss.kxlist.com//8a989a0c55e4a7900155e7fd7971000b/commodity/20170925/20170…