百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

[OpenCV实战]8 深度学习目标检测网络YOLOv3的训练

toyiye 2024-06-21 11:54 11 浏览 0 评论

深度学习目标检测网络YOLOv3的训练

YOLOv3是计算机视觉中最受欢迎的实时目标检测器之一。在这个循序渐进的教程中,我们从如何使用YOLOv3训练1类物体探测器的简单案例开始。本教程是以初学者为中心编写的。建立自己的雪人检测器。

在这篇文章中,我们将分享训练过程,有助于训练的脚本以及一些公开的雪人图像和视频。您可以使用相同的过程来训练具有多个对象的对象检测器。

特别要注意的是,训练yolov3最好在linux下进行,同时所有涉及到输入路径的都最好使用绝对路径。

1 数据集

与任何深度学习任务一样,第一个最重要的任务是准备数据集。我们将使用Google的OpenImagesV4数据集中的雪人图像,这些图像可在线公开获取。它是一个非常大的数据集,包含大约600种不同的对象类。数据集还包含这些对象的边界框注释。总的来说,数据集超过500GB,但我们只会下载带有“雪人”对象的图像。

我们不拥有这些图像的版权,因此我们遵循共享源图像而不是图像文件本身的标准做法。OpenImages具有每个图像的原始URL和许可证信息。任何使用此数据(学术,非商业或商业)的风险均由您自行承担。

OpenImagesV4详细介绍:

http://storage.googleapis.com/openimages/web/challenge.html

然后你可以进入这个网站看看各种所有分类图像什么样子

https://storage.googleapis.com/openimages/web/challenge_visualizer/index.html?set=detection&c=%2Fm%2F04zwwv

1.1 下载openImages雪人数据[约1.5小时]

首先,我们需要安装awscli。必须用python3


linux: sudo pip3 install awscli

windows: pip3 install awscli

然后我们需要得到相关的 openImages下载文件,类描述文件class-descriptions-boxable.csv和下载信息文件train- annotations-bbox.csv(1.11GB)。

https://storage.googleapis.com/openimages/2018_04/class-descriptions-boxable.csv

https://storage.googleapis.com/openimages/2018_04/train/train-annotations-bbox.csv

接下来,将上述.csv文件移动到与下载的代码相同的文件夹,然后使用以下脚本下载数据。

Windows和linux下运行不一样,但是都有在python3环境下运行文件,且都需要在命令行调用。

图像将下载到JPEGImages文件夹中,相应的标签文件将写入标签文件夹label。下载将在539张图像上获得770个雪人实例。下载大约需要1.5小时,具体取决于互联网速度。JPEGImages和标签一起应小于136 MB。但是下载速度很慢。

对于多类对象检测器,您需要为每个类提供更多样本,您可能还需要获取test-annotations-bbox.csv和validation-annotations-bbox.csv文件,然后在python脚本中修改runMode并将其重新运行到为每个班级获得更多图像。但在我们目前的雪人案例中,770个案例就足够了。

runMode有train,validation,test三个数据集,每次只能下载一个数据


runMode = "train"

#runMode = "validation "

#runMode = "test"

对于类别可以一次性下载多个类别数据,如下所示。其中类别名从上面可视网站查询,注意区分大小写。


classes = ["Snowman", "Car"]

#classes = ["Snowman"]

1.2 训练集测试集拆分

任何机器学习训练过程都涉及首先将数据随机分成两组(三组)。

训练集:这是我们训练模型的数据的一部分。根据您拥有的数据量,您可以随机选择70%到90%的数据进行培训。

测试集:这是我们测试模型的数据的一部分。通常,这是数据的10-30%。没有图像同时为训练集和测试集的一部分。

我们将JPEGImages文件夹中的图像分割成训练集和测试集。您可以使用splitTrainAndTest.py脚本执行此操作,如下所示,将JPEGImages文件夹的完整路径作为参数传递。

2 Darknet

在本教程中,我们使用Darknet。这是一个用C语言编写的深度学习框架。

2.1 下载并构建Darknet

我们首先在您的系统上下载并构建它。


cd ~

git clone https://github.com/pjreddie/darknet

cd darknet

make

2.2 修改代码以定期保存模型文件

在我们确保原始仓库在您的系统中编译之后,让我们进行一些小修改以存储中间权重。在文件examples / detector.c中,更改train_detector函数,大概在130行到140行之间。


if(i%10000==0 || (i < 1000 && i%100 == 0))

改为


if(i%1000==0 || (i < 2000 && i%200 == 0))

改动的意思是,原始训练过程在每100次训练后保存网络权重,直到前1000次。然后接下来仅在每10000次训练后才保存。在我们的例子中,由于我们只训练一个类,我们希望我们的训练收敛得更快。因此,为了密切监视进度,我们在每200次迭代后保存,直到达到2000,然后接下来在每1000次迭代后保存。完成上述更改后,再次使用make命令重新编译darknet。

2.3 数据注释

我们在labels文件夹中共享带有注释的标签文件。标签文件中的每个行条目表示图像中的单个边界框,并包含有关该框的以下信息:


<object-class-id> <center-x> <center-y> <width> <height>

第一个字段object-class-id是表示类别的整数。范围从0到(类别总数-1)。在我们目前的情况下,由于我们只有一类雪人,因此总是设置object-class-id为0。

center-x和center-y分别是边界框中心的x和y坐标,除以图像宽度和高度后的结果。

width和height分别是边界框的宽度和高度,除以图像宽度和高度后的结果。

让我们考虑一个带有以下符号的示例:


x-边界框中心的x坐标(以像素为单位)

y-边界框中心的y坐标(以像素为单位)

w-边界框的宽度(以像素为单位)

h-边界框的高度(以像素为单位)

W-整个图像的宽度(以像素为单位)

H-整个图像的高度(以像素为单位)

然后我们计算标签文件中的注释值,如下所示:


center-x= x /W.

center-y= y /H.

width= w /W.

height= h /H.

以上四个变量取值范围都是0到1之间的浮点值。

3 模型训练

3.1 下载预训练模型

当训练自己的物体探测器时,最好利用在非常大的数据集上训练的模型进行微调,即使大型数据集可能不包含您要检测的对象。这个过程称为迁移学习。我们使用预先训练的模型,而不是从头开始学习,该模型包含在ImageNet上训练的卷积权重。使用这些权重作为起始权重,我们的网络可以更快地学习。我们现在将它下载到我们的darknet文件夹中。

微调模型下载地址:

https://pjreddie.com/media/files/darknet53.conv.74

3.2 数据文件

在文件darknet.data中,我们需要提供有关对象检测器的规范和一些相关路径的信息。


classes = 1

train  = /path/to/snowman/snowman_train.txt

valid  = /path/to/snowman/snowman_test.txt

names = /path/to/snowman/classes.names

backup = /path/to/snowman/weights/

您需要提供之前生成的文件snowman_train.txt和snowman_test.txt的绝对路径,这些文件分别包含用于训练(训练参数)和验证(有效参数)的文件列表。

该名称字段表示其中包含的所有类的名称的文件的路径。我们已经包含了classes.names文件,其中包含类名“snowman”。您需要设定绝对路径。最后,对于备份参数,我们需要提供现有目录的路径,在训练过程中存储中间权重文件。

3.3 配置训练参数

与darknet.data和classes.names文件一起,YOLOv3还需要配置文件darknet- yolov3.cfg。它也包含在我们的代码库中。它基于演示配置文件yolov3-voc.cfg,用于训练VOC数据集。所有重要的训练参数都存储在此配置文件中。

3.3.1 batch和subdivisions


[net]

# Testing

# batch=1

# subdivisions=1

# Training

batch=64

subdivisions=16

通常训练数百万张图像并不罕见。训练过程涉及基于其在训练数据集上的loss来迭代地更新神经网络的权重。一次使用训练集中的所有图像来更新权重是不切实际的(也是不必要的)。因此,在一次迭代中使用一小部分图像,该子集称为批量大小。当批量大小设置为64时,这意味着在一次迭代中使用64个图像来更新神经网络的参数。

即使您可能希望使用批量大小batch=64来训练您的神经网络,您可能没有足够的内存使用批量大小为64的GPU。幸运的是,Darknet允许您指定一个名为subdivisions的变量,subdivisions是细分大小的意思。subdivision让您可以处理GPU中batch批量大小的一小部分。您可以使用subdivisions=1开始训练,如果出现内存不足错误,请将细分参数增加2的倍数(例如2,4,8,16),即每次batch/subdivisions张图像,在处理完所有batch个图像后才更新参数。在测试期间,批次和细分都设置为1。

3.3.2 Width, Height, Channels

这些配置参数指定输入图像大小和通道数。


width=416

height=416

channels=3

在训练之前,首先将输入训练图像宽高。这里我们使用默认值416×416。如果我们将其增加到608×608,结果可能会有所改善,但是训练也需要更长的时间。channels=3表示我们将处理3通道RGB输入图像,即彩色图像。

3.3.3 Momentum and Decay

配置文件包含一些控制权重更新方式的参数。


momentum=0.9

decay=0.0005

在上一节中,我们提到了如何基于一小批图像而不是整个数据集更新神经网络的权重。由于这个原因,权重更新波动很大。这就是为什么使用参数动量momentum来惩罚迭代之间的大的权重变化的原因。典型的神经网络具有数百万个权重,因此它们可以轻松地过度拟合任何训练数据。过度拟合意味着它将在训练数据和测试数据上做得很好。这几乎就像神经网络记住了训练集中所有图像的答案,但实际上并没有学到基本概念。缓解此问题的方法之一是加入惩罚权重。参数衰减decay控制此惩罚权重。默认值可以正常工作,但如果您注意到过度拟合,可能需要调整此值。用默认值就行了。

3.3.4 Learning Rate, Steps, Scales, Burn In


learning_rate=0.001

policy=steps

steps=3800

scales=.1

burn_in=400

参数学习率learning_rate根据当前批量数据控制我们应该学习的积极程度。通常,这是0.01到0.0001之间的数字。

在训练过程刚刚开始时,学习率需要很高。但是多次训练后,权重改变就不那么大。换句话说,学习率需要随着时间的推移而降低。在配置文件中,通过首先指定我们的学习速率降低策略是步骤来实现学习速率的降低。在上面的例子中,学习率将从0.001开始并在steps =3800次迭代中保持不变,然后它将乘以比例scales以获得新的学习率。我们也可以指定多个步骤和比例。

在上一段中,我们提到学习率需要在开始时较高而在之后较低。虽然这种说法基本上是正确的,但根据经验发现,如果我们在一开始就在短时间内获得较低的学习率,那么需要加大学习率加速训练,这种情况在微调时非常常见。这由burn_in参数控制加速训练。默认为0,

burn_in=400表示,从训练开始到第400次训练,由以下公式训练:


learning_rate * pow((float)batch_num / net.burn_in, net.power);

3.3.5 数据增强

我们知道数据收集需要很长时间。对于这篇博文,我们首先必须收集很多张图像,然后手动创建每个图像周围的边界框。

我们希望通过编写新数据来最大限度地利用这些数据。此过程称为数据扩充。例如,旋转了的雪人的图像仍然是雪人的图像。配置文件中的角度参数允许您以±角度随机旋转给定图像。同样,如果我们使用饱和度,曝光和色调来变换整个图片的颜色,它仍然是雪人的图片。


angle=0

saturation = 1.5

exposure = 1.5

hue=.1

我们使用默认值进行训练。

3.3.6 训练次数

最后,我们需要指定训练过程应该运行多少次训练。


max_batches=5200

对于多类对象检测器,max_batches数量更高,即我们需要运行更多批次(例如,在yolov3-voc.cfg中)。对于n类目标检测网络,建议至少运行2000n批次的训练。在我们只有1个类的情况下,3000似乎是max_batches的很合适数字。

3.3.7 类别数

需要修改类别数,即classes,不包括背景,本文只有一类,所以classes=1。在classes上方有filters修改,改为3 * (5+classes).

所用的classes都要改,与classes对应的filters也要改


[convolutional]
size=1
stride=1
pad=1
# filters = (num/3) * (5+classes)
filters=18
activation=linear

[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1

3.3.8 其他参数

通常训练时,只要配置以下上面的参数,最好用微调。如果想了解其他参数,见:

https://blog.csdn.net/ll_master/article/details/81487844

3.4 模型训练

转到darknet目录并使用以下命令启动它:

文件配置如下,其中darknet下的snowman目录下的文件如下图所示,darknet53.conv.74我放在darknet目录下,

添加图片注释,不超过 140 字(可选)


./darknet detector train /home/your/darknet/snowman/darknet.data
/home/your/darknet/snowman/darknet-yolov3.cfg darknet53.conv.74 2>&1|tee
/home/your/darknet/snowman/train.log

确保为系统中的darknet.data和darknet- yolov3.cfg文件提供正确的路径。我们还将训练日志保存到数据集目录中名为train.log的文件中,以便我们可以随着训练的进行而减少损失。

在训练时监视丢失的一种有用方法是在train.log文件中使用grep命令

grep "avg" ./snowman/train.log

它显示批次编号,当前批次中的损失,当前批次的平均损失,当前学习率,批次所用的时间以及当前批次使用的图像。正如您在下面看到的那样,每个批次之前使用的图像数量增加了64。这是因为我们将批量大小设置为64。

添加图片注释,不超过 140 字(可选)

添加图片注释,不超过 140 字(可选)

正如我们所看到的,第400批的学习率从0逐渐增加到0.001。这就是burn_in的作用。它会留在那里直到第1000次训练再次变为0.0001。

3.5 模型停止训练

随着培训的进行,日志文件包含每批次中的损失loss。在损失达到某个阈值以下之后,可以停止训练。下面是针对我们的雪人目标检测器loss图。我们使用以下脚本生成绘图:

但实际的测试应该是使用学习的权重来查看mAP。原始的darknet代码没有计算mAP的代码。

添加图片注释,不超过 140 字(可选)

你可以在该网站下载带mAP计算功能的darknet改进版:

https://github.com/AlexeyAB/darknet

对于雪人目标检测器,我们在配置文件中只有5200次训练。所以你可能会让它一直运行到最后。我们最终训练的权重文件darknet- yolov3_final.weights的平均精确度(mAP)为70.37%。

3.6 模型测试

除了loss和mAP之外,我们应该始终在新数据上测试我们的权重文件并直观地查看结果,以确保我们对结果感到满意。在之前的文章中,我们描述了如何使用OpenCV测试YOLOv3模型。我们已经包含了测试雪人目标检测器的代码。您需要为object_detection_yolo.py中的modelConfiguration和modelWeights文件提供正确的路径,并使用图像或视频进行测试以进行雪人检测。

YOLOv3使用:

https://blog.csdn.net/LuohenYJ/article/details/88537253

4 代码

代码地址:

https://github.com/luohenyueji/OpenCV-Practical-Exercise

https://download.csdn.net/download/luohenyj/11025216

如果没有积分(系统自动设定资源分数)看看参考链接。我搬运过来的,大修改没有。

OpenImage获取Python3代码:

linux:


import csv
import subprocess
import os

runMode = "train"
classes = ["Snowman"]

with open('class-descriptions-boxable.csv', mode='r') as infile:
    reader = csv.reader(infile)
    dict_list = {rows[1]:rows[0] for rows in reader}

subprocess.run(['rm', '-rf', 'JPEGImages'])
subprocess.run([ 'mkdir', 'JPEGImages'])

subprocess.run(['rm', '-rf', 'labels'])
subprocess.run([ 'mkdir', 'labels'],)

for ind in range(0, len(classes)):
    
    className = classes[ind]
    print("Class " + str(ind) + " : " + className)

    commandStr = "grep " + dict_list[className] + " " + runMode + "-annotations-bbox.csv"
    print(commandStr)
    class_annotations = subprocess.run(commandStr.split(), stdout=subprocess.PIPE).stdout.decode('utf-8')
    class_annotations = class_annotations.splitlines()

    totalNumOfAnnotations = len(class_annotations)
    print("Total number of annotations : "+str(totalNumOfAnnotations))

    cnt = 0
    for line in class_annotations[0:totalNumOfAnnotations]:
        cnt = cnt + 1
        print("annotation count : " + str(cnt))
        lineParts = line.split(',')
        subprocess.run([ 'aws', 's3', '--no-sign-request', '--only-show-errors', 'cp', 's3://open-images-dataset/'+runMode+'/'+lineParts[0]+".jpg", 'JPEGImages/'+lineParts[0]+".jpg"])
        with open('labels/%s.txt'%(lineParts[0]),'a') as f:
            f.write(' '.join([str(ind),str((float(lineParts[5]) + float(lineParts[4]))/2), str((float(lineParts[7]) + float(lineParts[6]))/2), str(float(lineParts[5])-float(lineParts[4])),str(float(lineParts[7])-float(lineParts[6]))])+'\n')

windows:


import csv
import subprocess
import os

#要下的数据集rain,test,valid
runMode = "train"
#类别
classes = ["Snowman"]

with open('class-descriptions-boxable.csv', mode='r') as infile:
    reader = csv.reader(infile)
    dict_list = {rows[1]:rows[0] for rows in reader}

#删除以前下载的
subprocess.run(['rd', '/s/q', 'JPEGImages'],shell=True)
subprocess.run(['mkdir', 'JPEGImages'],shell=True)

subprocess.run(['rd', '/s/q', 'labels'],shell=True)
subprocess.run(['mkdir', 'labels'],shell=True)

for ind in range(0, len(classes)):
    
    className = classes[ind]
    print("Class " + str(ind) + " : " + className)
    
    strs = dict_list[className]
    commandStr = "findstr /r "+ '"\<' + strs + '\>"' + " " + runMode + "-annotations-bbox.csv"

    class_annotations = subprocess.run(commandStr, stdout=subprocess.PIPE,shell=True).stdout.decode('utf-8')
    class_annotations = class_annotations.splitlines()
    print(commandStr.split(','))
    #多少张图像被下载
    totalNumOfAnnotations = len(class_annotations)
    print("Total number of annotations : "+str(totalNumOfAnnotations))

    cnt = 0
    for line in class_annotations[0:totalNumOfAnnotations]:
        cnt = cnt + 1
        print("annotation count : " + str(cnt))
        lineParts = line.split(',')
        subprocess.run([ 'aws', 's3', '--no-sign-request', '--only-show-errors', 'cp', 's3://open-images-dataset/'+runMode+'/'+lineParts[0]+".jpg", 'JPEGImages/'+lineParts[0]+".jpg"],shell=True)
        with open('labels/%s.txt'%(lineParts[0]),'a') as f:
            f.write(' '.join([str(ind),str((float(lineParts[5]) + float(lineParts[4]))/2), str((float(lineParts[7]) + float(lineParts[6]))/2), str(float(lineParts[5])-float(lineParts[4])),str(float(lineParts[7])-float(lineParts[6]))])+'\n')

数据集分割:


import random
import os
import subprocess
import sys

image_dir='/home/your/darknet/OpenImage/JPEGImages'
def split_data_set():

    f_val = open("snowman_test.txt", 'w')
    f_train = open("snowman_train.txt", 'w')
    
    path, dirs, files = next(os.walk(image_dir))
    data_size = len(files)

    ind = 0
    data_test_size = int(0.1 * data_size)
    test_array = random.sample(range(data_size), k=data_test_size)
    
    for f in os.listdir(image_dir):
        if(f.split(".")[1] == "jpg"):
            ind += 1
            
            if ind in test_array:
                f_val.write(image_dir+'/'+f+'\n')
            else:
                f_train.write(image_dir+'/'+f+'\n')


split_data_set()

draw loss:


import matplotlib.pyplot as plt

log='train.log'
lines = []
for line in open(log):
    if "avg" in line:
        lines.append(line)

iterations = []
avg_loss = []

print('Retrieving data and plotting training loss graph...')
for i in range(len(lines)):
    lineParts = lines[i].split(',')
    iterations.append(int(lineParts[0].split(':')[0]))
    avg_loss.append(float(lineParts[1].split()[0]))

fig = plt.figure()
for i in range(0, len(lines)):
    plt.plot(iterations[i:i+2], avg_loss[i:i+2], 'r.-')

plt.xlabel('Batch Number')
plt.ylabel('Avg Loss')
fig.savefig('training_loss_plot.png', dpi=300)

print('Done! Plot saved as training_loss_plot.png')

5 参考

https://www.learnopencv.com/training-yolov3-deep-learning-based-custom-object-detector/


引用链接

[1] http://storage.googleapis.com/openimages/web/challenge.html: http://storage.googleapis.com/openimages/web/challenge.html

[2] https://storage.googleapis.com/openimages/web/challenge_visualizer/index.html?set=detection&c=%2Fm%2F04zwwv: https://storage.googleapis.com/openimages/web/challenge_visualizer/index.html?set=detection&c=%2Fm%2F04zwwv

[3] https://storage.googleapis.com/openimages/2018_04/class-descriptions-boxable.csv : https://storage.googleapis.com/openimages/2018_04/class-descriptions-boxable.csv

[4] https://storage.googleapis.com/openimages/2018_04/train/train-annotations-bbox.csv : https://storage.googleapis.com/openimages/2018_04/train/train-annotations-bbox.csv

[5] https://pjreddie.com/media/files/darknet53.conv.74: https://pjreddie.com/media/files/darknet53.conv.74

[6] https://blog.csdn.net/ll_master/article/details/81487844: https://blog.csdn.net/ll_master/article/details/81487844

[7] https://github.com/AlexeyAB/darknet : https://github.com/AlexeyAB/darknet

[8] https://blog.csdn.net/LuohenYJ/article/details/88537253 : https://blog.csdn.net/LuohenYJ/article/details/88537253

[9] https://github.com/luohenyueji/OpenCV-Practical-Exercise : https://github.com/luohenyueji/OpenCV-Practical-Exercise

[10] https://download.csdn.net/download/luohenyj/11025216 : https://download.csdn.net/download/luohenyj/11025216

[11] https://www.learnopencv.com/training-yolov3-deep-learning-based-custom-object-detector/ : https://www.learnopencv.com/training-yolov3-deep-learning-based-custom-object-detector/

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码