目标检测之数据训练

标签: 无 分类: 机器学习 创建时间:2024-09-06 03:51:23 更新时间:2024-10-31 11:33:29

1.前言

对搜集到的数据进行标注之后,就可以进行数据训练了。

2.数据划分

如果使用 label studio 进行的标注,可能还需要对数据集进行划分,划分为 train(训练集)、test(测试集)和 val(验证集)。在data目录下划分数据集,通常将数据集划分为训练集(70%)、验证集(20%)和测试集(10%)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# 将图片和标注数据按比例切分为 训练集和测试集
import shutil
import random
import os
import argparse


# 检查文件夹是否存在
def mkdir(path):
if not os.path.exists(path):
os.makedirs(path)

def main(image_dir, txt_dir, save_dir):
# 创建文件夹
mkdir(save_dir)
images_dir = os.path.join(save_dir, 'images')
labels_dir = os.path.join(save_dir, 'labels')

img_train_path = os.path.join(images_dir, 'train')
img_test_path = os.path.join(images_dir, 'test')
img_val_path = os.path.join(images_dir, 'val')

label_train_path = os.path.join(labels_dir, 'train')
label_test_path = os.path.join(labels_dir, 'test')
label_val_path = os.path.join(labels_dir, 'val')

mkdir(images_dir);
mkdir(labels_dir);
mkdir(img_train_path);
mkdir(img_test_path);
mkdir(img_val_path);
mkdir(label_train_path);
mkdir(label_test_path);
mkdir(label_val_path);

# 数据集划分比例,训练集75%,验证集15%,测试集15%,按需修改
train_percent = 0.8
val_percent = 0.1
test_percent = 0.1

total_txt = os.listdir(txt_dir)
num_txt = len(total_txt)
list_all_txt = range(num_txt) # 范围 range(0, num)

num_train = int(num_txt * train_percent)
num_val = int(num_txt * val_percent)
num_test = num_txt - num_train - num_val

train = random.sample(list_all_txt, num_train)
# 在全部数据集中取出train
val_test = [i for i in list_all_txt if not i in train]
# 再从val_test取出num_val个元素,val_test剩下的元素就是test
val = random.sample(val_test, num_val)

print("训练集数目:{}, 验证集数目:{},测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
for i in list_all_txt:
name = total_txt[i][:-4]

srcImage = os.path.join(image_dir, name + '.jpg')
srcLabel = os.path.join(txt_dir, name + '.txt')

if i in train:
dst_train_Image = os.path.join(img_train_path, name + '.jpg')
dst_train_Label = os.path.join(label_train_path, name + '.txt')
shutil.copyfile(srcImage, dst_train_Image)
shutil.copyfile(srcLabel, dst_train_Label)
elif i in val:
dst_val_Image = os.path.join(img_val_path, name + '.jpg')
dst_val_Label = os.path.join(label_val_path, name + '.txt')
shutil.copyfile(srcImage, dst_val_Image)
shutil.copyfile(srcLabel, dst_val_Label)
else:
dst_test_Image = os.path.join(img_test_path, name + '.jpg')
dst_test_Label = os.path.join(label_test_path, name + '.txt')
shutil.copyfile(srcImage, dst_test_Image)
shutil.copyfile(srcLabel, dst_test_Label)


if __name__ == '__main__':
"""
python split_datasets.py --image-dir my_datasets/color_rings/imgs --txt-dir my_datasets/color_rings/txts --save-dir my_datasets/color_rings/train_data
"""
parser = argparse.ArgumentParser(description='split datasets to train,val,test params')
parser.add_argument('--image-dir', type=str,default=r'D:\zlc\gitee\yolov8\data\yolov8\images', help='image path dir')
parser.add_argument('--txt-dir', type=str,default=r'D:\zlc\gitee\yolov8\data\yolov8\labels' , help='txt path dir')
parser.add_argument('--save-dir', default=r'D:\zlc\gitee\yolov8\data\yolov8\split',type=str, help='save dir')
args = parser.parse_args()
image_dir = args.image_dir
txt_dir = args.txt_dir
save_dir = args.save_dir

main(image_dir, txt_dir, save_dir)

最后形成了如下文件夹

参考文章:
【1】.YOLOV8训练自定义数据集 1.将标注数据按照类别划分到不同的文件目录;2.按照比例划分训练集与验证集;3.数据集按照既定格式进行整理;4.装ultralytics包;5.开始训练;
【2】.YOLOv8实例分割训练自己的数据集保姆级教程 这里有数据分割的代码,还挺好用的。

3.新建配置文件

在 data 文件夹下新建一个数据加载配置文件 smoke.yaml

1
2
3
4
5
6
train: /home/mango/ultralytics/data/images/train
val: /home/mango/ultralytics/data/images/val
# number of classes
nc: 1
# class names
names: ['smoke'']

这里要说明的是,如果有多个类,那么names的配置需要和yolo的 classes.txt 或者 notes.json 里面的类别顺序一致。

3.训练

训练模型有四种方式,也可以说是三种,第四种和第三种其实一样的。考虑到命令行模式下下载模型可能有点慢,所以先在官方仓库下载好模型,并放入新建的 weights (文件路径:/home/mango/ultralytics/weights)目录下。

  • (1)参数重写
    使用命令行执行命令,可以提前下载 yolov8n.pt 模型文件,也可以不下载,如果没有下载的话,或者指定目录的pt文件不存在,会自动下载
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    yolo task=detect mode=train model=yolov8n.pt data=data/yolov8/smoke.yml batch=4 epochs=100 imgsz=640 workers=16 device=0
    ```

    以上参数解释如下:
    task:选择任务类型,可选['detect', 'segment', 'classify', 'init']
    mode: 选择是训练、验证还是预测的任务蕾西 可选['train', 'val', 'predict']
    model: 选择yolov8不同的模型配置文件,可选yolov8s.yaml、yolov8m.yaml、yolov8l.yaml、yolov8x.yaml
    data: 选择生成的数据集配置文件
    epochs:指的就是训练过程中整个数据集将被迭代多少次,显卡不行你就调小点。
    batch:一次看完多少张图片才进行权重更新,梯度下降的mini-batch,显卡不行你就调小点。

    - (2)重写配置文件
    新建配置文件,或者到 ultralytics/yolo/cfg/default.yaml 复制即可,或者使用命令: yolo copy-cfg, 它会自动生成一个 default_copy.yaml (目录地址:/home/mango/ultralytics/default_copy.yaml),根据自身需求,修改相应参数,例如:修改 model、data、epochs、batch
    ```yml
    model: weights/yolov8n.pt # path to model file, i.e. yolov8n.pt, yolov8n.yaml
    data: data/person.yaml # path to data file, i.e. coco128.yaml
    epochs: 20 # number of epochs to train for
    batch: 8 # number of images per batch (-1 for AutoBatch)

然后在终端输入下列代码行命令即可开始训练,还可以使用 yolo cfg=default_copy.yaml imgsz=320 batch=8 的方式修改 imgz、batch 等参数信息。

1
yolo cfg=default_copy.yaml
  • (3)自定义 train.py 文件,执行训练

    1
    2
    3
    4
    5
    6
    from ultralytics import YOLO
    # 加载模型
    # model = YOLO("yolov8n.yaml") # 从头开始构建新模型
    model = YOLO("weights/yolov8n.pt") # 加载预训练模型(推荐用于训练)
    # Use the model
    results = model.train(data="data/person.yaml", epochs=20, batch=8) # 训练模型
  • (4) 官方提供的 train.py 文件
    这个和第三种其实一样,只不过是官方已经提供了训练脚本了,进入 ultralytics/yolo 目录下,复制 person.yaml、yolov8n.pt 到 /ultralytics/yolo/v8/detect 目录,修改 ultralytics/yolo/cfg/default.yaml 的 model、data 路径及其他参数信息

    1
    python train.py
参考文章:
【1】.YOLOv8训练自己的数据集(超详细)
【2】.基于YOLOv8训练自定义数据集 这篇文章用的是 voc 转为了 yolo 格式,但是有一个地方让我非常的困惑,就是在配置文件这个步骤里面,他新建一个mydata.yaml文件,然后修改了,接着选择了一个yolov8x.yaml模型,也修改了里面的配置文件,但是在接下去的模型训练步骤中,他又重新下载了预训练模型,然后没有改,直接就输入命令进行训练了。那么在配置文件中,修改的yolov8x.yaml有什么意义呢?下载模型的意义又是什么呢?
【3】.从零到一:使用YOLOv8训练自定义目标检测模型 1.收集数据集;2.收集数据集;3.划分数据集;4.配置训练环境,编辑配置文件(如yolov8s.yaml),设置网络结构、训练轮次、学习率、优化器等参数,创建一个data.yaml文件,指定数据集路径、类别名称等信息。;5.训练模型;6.评估模型;7.模型部署与应用;
【4】.【YOLO】YOLOv8训练自定义数据集(4种方式) 这里我赶紧写的还是挺清楚的

8.训练参数

我从官网摘录了全部的训练参数,方便查阅。

  • model,指定用于训练的模型文件。接受 .pt 预训练模型或 .yaml 配置文件的路径。对于定义模型结构或初始化权重至关重要,默认:None
  • data,数据集配置文件的路径(例如,coco8.yaml)。该文件包含特定于数据集的参数,包括训练和验证数据的路径、类名称和类数量,默认:None
  • epochs,训练时期总数。每个时期代表对整个数据集的完整遍历。调整此值可能会影响训练持续时间和模型性能。训练数据集需要重复训练多少次, yolov5 推荐初始为 300 个, 而 yolov8推荐初始为500, 如果发现有过拟合overfit, 则适当减少, 如果没有overfit, 则增加到600、1200. 如果使用 CPU, 为了缩短时间epochs可从100开始试. 过拟合最优先的应对策略是增加验证集比例和增加验证集多样性。默认:100
  • time,最大训练时间(以小时为单位)。如果设置,这将覆盖 epochs 参数,允许训练在指定的持续时间后自动停止。对于时间有限的训练场景很有用,默认:None
  • patience,在提前停止训练之前等待验证指标没有改善的时期数。当性能达到稳定水平时停止训练,有助于防止过度拟合。为 EarlyStopping 的 epoch 数量, 默认为 patience=50 , 如果要禁用早停特性, 设置0即可。默认:100
  • batch,批大小,具有三种模式:设置为整数(例如,batch=16)、60% GPU 内存利用率的自动模式(batch=-1)或具有指定利用率的自动模式(batch=0.70),batch size 为一次前向传播送入模型的图片数量, 完成后将做反向传递, 进行weight/bias参数调整, batch size 取值必须为2的n次方, 最小值为2. 这个参数应使用硬件支持的最大 batch size, 比如64开始, 如果不爆内存/显存问题, 则增加到 128、256, batch size越大 batchNorm 效果越好, 精度越高。默认:16
  • imgsz,训练的目标图像大小。所有图像在输入模型之前都会调整为该尺寸。影响模型精度和计算复杂度。这个参数非常重要,用来将实际图像统一缩放到一个固定的尺寸送入到网络,imgsz 参数必须是 32 的倍数,train/val/test/predict 不要求有相同的原始图像尺寸, 但最好差异不要太大。通常 imgsz 越大效果也越好, 但这并不绝对, 如果被检查物非常小, img size 太大反而不行。采用较大 imgsz, 比较容易爆显存同时训练速度也会降低, 如果原始图像是38402160这样高清图像,最好还是设置 imgsz=1280, 这个数值应该是速度和准确性比较好的平衡点。通常设置 imgsz=640 是一个很好的选择, yolo会自动将我们的图像缩放到640640的尺寸, 方法是:将图像的长边缩放到640, 图像的短边按照长边缩放的比例缩放, 如果不足640, 则在短边两侧自动padding黑色像素。yolov8 预训练模型基于 640 尺寸的图像训练, 如果我们的数据集为高清图像, 可以采用 yolov8 P6模型, 这个系列的模型文件分别为yolov8m6, yolov8l6, yolov8x6。默认:640
  • save,能够保存训练检查点和最终模型权重。对于恢复训练或模型部署很有用,默认:True
  • save_period,保存模型检查点的频率,以纪元指定。值为 -1 将禁用此功能。对于在长时间训练期间保存临时模型很有用,默认:-1
  • cache,启用在内存 (True/ram)、磁盘 (disk) 中缓存数据集图像,或禁用它 (False)。通过减少磁盘 I/O 来提高训练速度,但代价是增加内存使用量,默认:False
  • device,指定用于训练的计算设备:单个 GPU (device=0)、多个 GPU (device=0,1)、CPU (device=cpu) 或 Apple 芯片的 MPS (device=mps),默认:None
  • workers,用于数据加载的工作线程数(如果是多 GPU 训练,则按 RANK 计算)。影响数据预处理和输入模型的速度,在多 GPU 设置中特别有用,默认:8
  • project,保存训练输出的项目目录的名称。允许组织存储不同的实验,默认:None
  • name,训练运行的名称。用于在项目文件夹中创建子目录,其中存储训练日志和输出,默认:None
  • exist_ok,如果为 True,则允许覆盖现有项目/名称目录。对于迭代实验很有用,无需手动清除以前的输出,默认:False
  • pretrained,确定是否从预训练模型开始训练。可以是布尔值或指向从中加载权重的特定模型的字符串路径。提高训练效率和模型性能,默认:True
  • optimizer,选择训练优化器。选项包括 SGD、Adam、AdamW、NAdam、RAdam、RMSProp 等,或者 auto 用于根据模型配置自动选择。影响收敛速度和稳定性,默认:‘auto’
  • verbose,在训练期间启用详细输出,提供详细的日志和进度更新。对于调试和密切监控训练过程很有用,默认:False
  • seed,设置训练的随机种子,确保使用相同配置运行时结果的可重复性,默认:0
  • deterministic,强制使用确定性算法,确保可重复性,但由于对非确定性算法的限制,可能会影响性能和速度,默认:True
  • single_cls,在训练期间将多类数据集中的所有类视为单个类。对于二元分类任务或关注对象存在而不是分类时很有用,默认:False
  • rect,启用矩形训练,优化批次组成以最小化填充。可以提高效率和速度,但可能会影响模型精度。yolo在进行训练之前总是会将图像按letterbox方式做resize, 所以缩放后的图像仍然保留原来真实的长宽比例. 如果rect设置为False(缺省), 表示yolo会统一将它们resize成一个正方形, 该取值适合原始图像宽高差异不大的情况; 如果rect=True, yolo resize的结果将是一个长方形而不是正方形, 比较适合原始图像宽高差异较大的情况, 在这种情况下, 如果仍然缩放到宽高相等, 图像中padding的区域就会很大, 浪费GPU算力, rect如果取值为True时候, imgsz参数应该同时设置宽高两个值。默认:False
  • cos_lr,利用余弦学习率调度程序,根据历元的余弦曲线调整学习率。有助于管理学习率以实现更好的收敛,默认:False
  • close_mosaic,在最后 N 个时期禁用马赛克数据增强,以在完成之前稳定训练。设置为 0 将禁用此功能,默认:10
  • resume,从上次保存的检查点恢复训练。自动加载模型权重、优化器状态和历元计数,无缝地继续训练,默认:False
  • amp,启用自动混合精度 (AMP) 训练,减少内存使用,并可能加快训练速度,同时对准确性的影响最小,默认:True
  • fraction,指定用于训练的数据集的比例。允许对完整数据集的子集进行训练,这对于实验或资源有限时很有用,默认:1.0
  • profile,在训练期间启用 ONNX 和 TensorRT 速度分析,对于优化模型部署非常有用,默认:False
  • freeze,通过索引冻结模型的前 N ​​层或指定层,减少可训练参数的数量。对于微调或迁移学习很有用,默认:None
  • lr0,初始学习率(即SGD=1E-2,Adam=1E-3)。调整该值对于优化过程至关重要,会影响模型权重更新的速度。学习率是梯度下降的步长系数。默认:0.01
  • lrf,最终学习率作为初始学习率的一部分 = (lr0 * lrf),与调度程序结合使用,随时间调整学习率,学习率是梯度下降的步长系数。默认:0.01
  • momentum,Adam 优化器的 SGD 或 beta1 动量因子,影响当前更新中过去梯度的合并,默认:0.937
  • weight_decay,L2 正则化项,惩罚大权重以防止过度拟合,默认:0.0005
  • warmup_epochs,学习率预热的纪元数,逐渐将学习率从低值增加到初始学习率,以在早期稳定训练,默认:3.0
  • warmup_momentum,预热阶段的初始动量,在预热期间逐渐调整到设定的动量,默认:0.8
  • warmup_bias_lr,预热阶段偏差参数的学习率,有助于稳定初始时期的模型训练,默认:0.1
  • box,损失函数中框损失分量的权重,影响准确预测边界框坐标的程度,默认:7.5
  • cls,总损失函数中分类损失的权重,影响正确类别预测相对于其他组件的重要性,默认:0.5
  • dfl,分布焦点损失的权重,在某些YOLO版本中用于细粒度分类,默认:1.5
  • pose,用于姿势估计训练的模型中姿势损失的权重,影响对准确预测姿势关键点的重视,默认:12.0
  • kobj,姿态估计模型中关键点客观性损失的权重,平衡检测置信度和姿态精度,默认:2.0
  • label_smoothing,对目标标签的混合应用标签平滑、软化硬标签以及标签上的均匀分布,可以提高泛化能力,默认:0.0
  • nbs,损失标准化的标称批量大小,默认:64
  • overlap_mask,确定分割掩码在训练期间是否应重叠,适用于实例分割任务,默认:True
  • mask_ratio,分割掩模的下采样率,影响训练期间使用的掩模的分辨率,默认:4
  • dropout,分类任务中正则化的丢弃率,通过在训练期间随机省略单元来防止过度拟合,0.0
  • val,在训练期间启用验证,允许在单独的数据集上定期评估模型性能,默认:True
  • plots,生成并保存训练和验证指标图以及预测示例,提供对模型性能和学习进度的可视化洞察,默认:False
  • train/val/test/predict,超参最好要一致, 不一致的参数有可能会引起predict显著变化
  • task,参数默认为 detect,可以传递 task 如:[detect、classify、segment]
  • mode,参数默认为train, train模式下默认包含 val, ,mode 有:[train、predict、val、export]
参考文章:
【1】.Train Settings 训练参数设置
【2】. 机器视觉 - yolo 调参 1.大小目标的分类;2.yolov8 模型文件。3.模型训练通用规则。4.yolov8 参数设置技巧。
【3】.超详细YOLOv8训练参数、说明详解 YOLOv8训练模式的一些显著特点:自动数据集下载、多GPU支持、超参数配置、可视化和监控。这里有训练参数的说明,可以进行相应的表格参考。

9.结果分析

开始的时候,我没有做过完整的一个训练,于是我就不太清楚,到底训练的结果在哪里呢?这个让我找了好多的资料。在很多的文章中,会提到一个 weights/best.pt ,我想应该就是这个最后的模型了吧。训练完成之后,会生成一个 detect/train3/weights/best.pt ,这个就可以作为相关配置。

  • confusion_matrix_normalized.png和confusion_matrix.png
    confusion_matrix_normalized.png和confusion_matrix.png表示各个类别对应的混淆矩阵,其中confusion_matrix_normalized.png表示归一化后的混淆矩阵,confusion_matrix.png表示各类别数值对应的混淆矩阵。混淆矩阵是对分类问题预测结果的总结。使用计数值汇总正确和不正确预测的数量,并按每个类进行细分,显示了分类模型进行预测时会对哪一部分产生混淆。通过这个矩阵可以方便地看出机器是否将两个不同的类混淆了,把一个类错认成了另一个。

  • P_curve.png(准确率曲线)
    表示准确率precision和置信度confidence的关系图,其中细线代表每个类别的精度曲线,粗线代表所有类别平均精度曲线。当判定概率超过置信度阈值时,各个类别识别的准确率。当置信度越大时,类别检测越准确,但是这样就有可能漏掉一些判定概率较低的真实样本。
    意思就是,当我设置置信度为某一数值的时候,各个类别识别的准确率。可以看到,当置信度越大的时候,类别检测的越准确。这也很好理解,只有confidence很大,才被判断是某一类别。但也很好想到,这样的话,会漏检一些置信度低的类别。

  • R_curve.png(召回率曲线)
    表示召回率recall和置信度confidence之间的关系,其中细线代表每个类别的召回率曲线,粗线代表所有类别平均召回率曲线。recall(召回率)表示真实为positive的准确率,即正样本有多少被找出来了(召回了多少)。
    当置信度越小的时候,类别检测的越全面(不容易被漏掉,但容易误判)。

  • PR_curve.png(PR曲线)
    PR曲线表示体现精确率和召回率的关系,其中细线代表每个类别的PR曲线,粗线代表所有类别平均PR曲线。P代表的是precision(精准率),R代表的是recall(召回率)。一般情况下,将recall设置为横坐标,precision设置为纵坐标。PR曲线下围成的面积即AP,所有类别AP平均值即mAP.因此我们希望:在准确率很高的前提下,尽可能的检测到全部的类别。因此希望我们的曲线接近(1,1),即希望PR曲线的面积尽可能接近1。如果PR图的其中的一个曲线A完全包住另一个学习器的曲线B,则可断言A的性能优于B,当A和B发生交叉时,可以根据曲线下方的面积大小来进行比较。一般训练结果主要观察精度和召回率波动情况(波动不是很大则训练效果较好)Precision和Recall往往是一对矛盾的性能度量指标;及一个的值越高另一个就低一点。

  • F1_curve.png(F1曲线)
    表示是置信度confidence与F1之间的关系曲线。一般来说,置信度阈值(该样本被判定为某一类的概率阈值)较低的时候,很多置信度低的样本被认为是真,召回率高,精确率低;置信度阈值较高的时候,置信度高的样本才能被认为是真,类别检测的越准确,即精准率较大(只有confidence很大,才被判断是某一类别),所以前后两头的F1分数比较少。

  • val_batch0_labels与val_batch0_pred
    val_batch0_labels.png表示验证集真实的标签情况示例。

参考文章:
【1】.YOLOv8训练自定义数据集模型 data.yaml主要是保存训练数据集的目录,类别数,类别名,这里还提供了训练时的一些参数调整
【2】.yolov8模型训练结果分析以及如何评估yolov8模型训练的效果 1.目标检测性能指标;2.混淆矩阵;3.精确率和召回率;4.损失函数;
【3】.YOLOv8 训练 预测 更改save输出位置 全网首发 更改ultralytics库里的 yaml 文件: /ultralytics/yolo/cfg/default.yaml,添加字段:save_dir
【4】.YOLOv8 实现 任意目录下 命令行训练
【5】.如何使用YOLOV8训练自己的目标检测模型 model.train()函数可以指定的训练参数有很多,这里也列出来了。训练成功。经过一段时间等待之后,在目录下的runs文件夹下会自动生成训练过程记录,包含模型权重、混淆矩阵、PR曲线、loss曲线等。
【6】.YOLOv8训练好的pt文件如何用来预测
【7】.yolov8实战第二天——yolov8训练过程、结果分析(保姆式解读)
【8】.YOLOv8如何使用训练好的模型对验证集进行评估及评估参数详解

问题

1.Compile with TORCH_USE_CUDA_DSA to enable device-side assertions

在执行 yolov8 训练的时候,出现了这个问题。本来我的 batch 为64,后来我降到了16,也还是不行。而且我做其他的训练的时候,就不会出现这个问题。RuntimeError: CUDA error: device-side assert triggered CUDA kernel errors might be asynchronously reported at some other API call, so the stacktrace below might be incorrect. For debugging consider passing CUDA_LAUNCH_BLOCKING=1 Compile with TORCH_USE_CUDA_DSA to enable device-side assertions.

1
yolo task=detect mode=train model=yolov8n.pt data=data/yolov8/smoke.yml batch=64 epochs=100 imgsz=640 workers=16 device=0

【解决方案】
这个问题就是因为我标签里面其实是个2分类问题,最后在写配置文件的时候,我只写了一个类别,如下错误示范。

1
2
3
4
5
6
train: D:/zlc/gitee/yolov8/data/yolov8/split/images/train
val: D:/zlc/gitee/yolov8/data/yolov8/split/images/val
# number of classes
nc: 1
# class names
names: ['soil']

正确的配置

1
2
3
4
# number of classes
nc: 2
# class names
names: ['soil','smoke']
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。