Faster-RCNN代码解读4:辅助文件解读

news2024/10/6 14:35:56

Faster-RCNN代码解读4:辅助文件解读

前言

​ 因为最近打算尝试一下Faster-RCNN的复现,不要多想,我还没有厉害到可以一个人复现所有代码。所以,是参考别人的代码,进行自己的解读。

代码来自于B站的UP主(大佬666),其把代码都放到了GitHub上了,我把链接都放到下面了(应该不算侵权吧,毕竟代码都开源了_):

b站链接:https://www.bilibili.com/video/BV1of4y1m7nj/?vd_source=afeab8b555e5eb1bfa1e7f267262cbf2

GitHub链接:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing

目的

​ 其实UP主已经做了很好的视频讲解了他的代码,只是有时候我还是喜欢阅读博客来学习,另外视频很长,6个小时,我看的时候容易睡着_,所以才打算写博客记录一下学习笔记。

目前完成的内容

第一篇:VOC数据集详细介绍

第二篇:Faster-RCNN代码解读2:快速上手使用

第三篇:Faster-RCNN代码解读3:制作自己的数据加载器

第四篇:Faster-RCNN代码解读4:辅助文件解读(本文)

目录结构

文章目录

    • Faster-RCNN代码解读4:辅助文件解读
      • 1. 前言:
      • 2. split_data.py文件:
      • 3. plot_curve.py文件:
      • 4. draw_box_utils.py文件:
      • 5. backbone文件夹下的文件:
      • 6. train_mobilenetv2.py文件:
      • 7. 总结:

1. 前言:

​ 本篇主要介绍的文件有:

split_data.py
plot_curve.py
draw_box_utils.py
train_mobilenetv2.py
backbone文件下的文件

​ 这些文件除去train_mobilenetv2.py外都是一些辅助的文件,读懂它们可以帮助我们后面理解Faster-RCNN的代码内容。

2. split_data.py文件:

​ 这个文件的主要作用:**制作自己的train.txt和val.txt文件。**其中,train.txt和val.txt文件就是VOC数据集ImageSets\Main\里的train.txt和val.txt文件,里面的数据分别是训练集和测试集的图片名字。

​ 其实这个文件作用并不大,因为数据集已经为我们提供了训练集和测试集的划分。不过,如果你用的自己的数据集,就可以用到它,它可以给你一个参考思路。

​ 下面,进行解读:

​ 首先,指定数据集的路径并验证该路径是否存在:

# 指定数据集地址
files_path = "./VOCdevkit/VOC2012/Annotations"
assert os.path.exists(files_path), "path: '{}' does not exist.".format(files_path)

​ 然后,设置训练集和测试集的比例:

# 设置验证集比例
val_rate = 0.5

​ 接着,将文件前缀和后缀分开,这是因为VOC数据集一个特点就是一张图片的注释、图像等文件前缀都是相同的:

# 切割文件名: 2007_000027.xml ---- [2007_000027,xml],即获得2007_000027文件名字
files_name = sorted([file.split(".")[0] for file in os.listdir(files_path)])
# 获取总数
files_num = len(files_name)

​ 然后,使用random.sample随机采取所需的验证图片,该函数返回验证图片的索引,并迭代将训练图片和验证图片分开保存:

# 随机采取指定比例的数据,获取索引,并放入不同的列表中
val_index = random.sample(range(0, files_num), k=int(files_num*val_rate))
train_files = []
val_files = []
# 将上面采集的放入对应的列表中
for index, file_name in enumerate(files_name):
    # 如果索引在验证集的索引集合中
    if index in val_index:
        # 加入验证列表
        val_files.append(file_name)
    else:
        # 否则,加入训练集列表中
        train_files.append(file_name)

​ 最后,将上述内容保存到文件中即可:

# 将之保存到文件中
try:
    train_f = open("train.txt", "x")
    eval_f = open("val.txt", "x")
    train_f.write("\n".join(train_files))
    eval_f.write("\n".join(val_files))
except FileExistsError as e:
    print(e)
    exit(1)

3. plot_curve.py文件:

​ 这个文件是画图文件,其画的是损失函数、学习率和mAP图像

​ 其实,这个文件很简单,主要的代码都是涉及matplotlib库的使用,所以不需要多说什么,可以看我写的代码注释:

def plot_loss_and_lr(train_loss, learning_rate):
    try:
        # 根据长度设置x轴的值
        x = list(range(len(train_loss)))
        fig, ax1 = plt.subplots(1, 1)   # 创建画布,注意只有一个
        ax1.plot(x, train_loss, 'r', label='loss')  # 画损失函数图
        # 美化图像
        ax1.set_xlabel("step")
        ax1.set_ylabel("loss")
        ax1.set_title("Train Loss and lr")
        plt.legend(loc='best')

        ax2 = ax1.twinx() # 启用右坐标轴
        ax2.plot(x, learning_rate, label='lr')  # 画学习率图
        ax2.set_ylabel("learning rate")
        ax2.set_xlim(0, len(train_loss))  # 设置横坐标整数间隔
        plt.legend(loc='best')

        handles1, labels1 = ax1.get_legend_handles_labels()  # 返回图例的句柄和标签,比如 legend为 loss,那么l就为loss
        handles2, labels2 = ax2.get_legend_handles_labels()
        plt.legend(handles1 + handles2, labels1 + labels2, loc='upper right')

        fig.subplots_adjust(right=0.8)  # 防止出现保存图片显示不全的情况
        # 保存图像
        fig.savefig('./loss_and_lr{}.png'.format(datetime.datetime.now().strftime("%Y%m%d-%H%M%S")))
        plt.close()
        print("successful save loss curve! ")
    except Exception as e:
        print(e)


def plot_map(mAP):
    try:
        # 根据长度设置x轴的值
        x = list(range(len(mAP)))
        plt.plot(x, mAP, label='mAp')   # 画mAP图
        # 美化图像
        plt.xlabel('epoch')
        plt.ylabel('mAP')
        plt.title('Eval mAP')
        plt.xlim(0, len(mAP))
        plt.legend(loc='best')
        # 保存
        plt.savefig('./mAP.png')
        plt.close()
        print("successful save mAP curve!")
    except Exception as e:
        print(e)

​ 我这里说一下上面涉及到的,而我们一般又不使用的代码。

  • ax1.twinx():作用是启用右坐标轴。

​ 如果你用过origin或者对画图了解一点,应该知道右坐标轴的意思(见下图),只是这个函数你可能没见过,其作用就是启用右坐标轴并返回一个操作对象。

在这里插入图片描述

  • ax1.get_legend_handles_labels():作用是返回这个坐标轴的图例句柄(即操作对象)和标签(即图例内容)

​ 这个说起来难以理解,但是举个例子就简单了。比如上图右上角的第一条曲线就是一个图例,其内容/标签值就是第一条曲线而句柄就是操作对象,如果返回的对象为空,表示这个图没有使用图例。

4. draw_box_utils.py文件:

​ 这个文件的主要作用就是画出图像的边界框、类别信息和mask信息

​ 首先,看最下面的函数draw_objs

draw_objs函数

作用:画出所有对象的边界框和mask

​ 输入的参数:

参数意义
image需要绘制的图片
boxes目标边界框信息
classes目标类别信息
scores目标概率信息
masks目标mask信息
category_index类别与名称字典
box_thresh过滤的概率阈值,默认为0.1
mask_thresh同上,只是过滤的对象为mask,默认为0.5
line_thickness边界框宽度
font字体类型
font_size字体大小
draw_boxes_on_image是否将边界框画在图像上,默认为True
draw_masks_on_image是否将mask画在图像上,默认为Fasle

​ 首先,过滤掉哪些概率值较低的边界框:

# 过滤掉低概率的目标
idxs = np.greater(scores, box_thresh)
# 需要同时处理boxes、classes、scores、masks
boxes = boxes[idxs]
classes = classes[idxs]
scores = scores[idxs]
if masks is not None:
    masks = masks[idxs]

​ 接着,判断过滤后,是否全部过滤掉,如果全部过滤掉就不需要画了:

# 如果boxes长度为0,表示所有的框都过滤了,就不需要画了
if len(boxes) == 0:
    return image

​ 然后,随机从定义的颜色列表中抽取颜色,生成一个待使用的颜色列表:

# 从定义的颜色列表中抽取颜色 
# ImageColor.getrgb 获取颜色的rgb值
colors = [ImageColor.getrgb(STANDARD_COLORS[cls % len(STANDARD_COLORS)]) for cls in classes]

​ 接着,开始画边界框,看注释即可:

# 如果需要画边界框
if draw_boxes_on_image:
    # 创建画图对象
    draw = ImageDraw.Draw(image)
    # 开始迭代绘图,因为一张图不知一个对象,所以需要画出所有的框
    for box, cls, score, color in zip(boxes, classes, scores, colors):
        # 边界框的坐标
        left, top, right, bottom = box
        # 绘制目标边界框,顺时针画图
        draw.line([(left, top), (left, bottom), (right, bottom),
                   (right, top), (left, top)], width=line_thickness, fill=color)
        # 绘制类别和概率信息
        draw_text(draw, box.tolist(), int(cls), float(score), category_index, color, font, font_size)

​ 最后,画mask:

if draw_masks_on_image and (masks is not None):
	# 画出所有的mask
    image = draw_masks(image, masks, colors, mask_thresh)

​ 其中上面的draw_textdraw_masks是文件中的另外两个函数,下面进行讲解。

draw_text函数

作用:将目标边界框和类别信息绘制到图片上,是draw_obj的辅助函数

​ 输入参数:

参数意义
draw画图对象,可以使用画直线等等方法
box一个边界框,里面有坐标信息
cls对象的类别,为int值,需要使用category_index转为字符串值
score对象的类别概率值
category_index不同的索引对应的类别信息
color使用的颜色
font字体
font_size字大小

​ 首先,由于需要画文字,即需要创建文字对象:

# 创建字体对象,如果创建失败(比如作者用的字体你没有),就使用默认的字体
try:
    font = ImageFont.truetype(font, font_size)
except IOError:
	font = ImageFont.load_default()

​ 接下来,就是获取边界框的坐标信息并设置文字要显示在边界框的哪个位置:

# 获取坐标
left, top, right, bottom = box
# 将数字的类别转为真实的类别信息,并加上概率值构成“ person 99% ”这样的字符串
display_str = f"{category_index[str(cls)]}: {int(100 * score)}%"
# 设置字体的高度
display_str_heights = [font.getsize(ds)[1] for ds in display_str]
display_str_height = (1 + 2 * 0.05) * max(display_str_heights)

# 如果文字的高度没有超过图像最高点
if top > display_str_height:
    # 设置文字的坐标
    text_top = top - display_str_height
    text_bottom = top
else:
	# 如果超过了,就设置文字的坐标为边界框的下面
	text_top = bottom
	text_bottom = bottom + display_str_height

​ 最后,就是将边界框和文字画在图像上:

 # 开始画
for ds in display_str:
	# 获取文字的宽和高
	text_width, text_height = font.getsize(ds)
	margin = np.ceil(0.05 * text_width)
    # 画一个矩形
    draw.rectangle([(left, text_top),
                    (left + text_width + 2 * margin, text_bottom)], fill=color)
    # 画文字
    draw.text((left + margin, text_top),
              ds,
              fill='black',
              font=font)
    left += text_width

draw_masks函数:

​ 这个函数比较简单,看注释即可:

def draw_masks(image, masks, colors, thresh: float = 0.7, alpha: float = 0.5):
    # 将图像转为array值
    np_image = np.array(image)
    # 过滤下mask
    masks = np.where(masks > thresh, True, False)

    # colors = np.array(colors)
    img_to_draw = np.copy(np_image)
    # TODO: There might be a way to vectorize this
    # 将mask区域改变颜色
    for mask, color in zip(masks, colors):
        img_to_draw[mask] = color
    
    out = np_image * (1 - alpha) + img_to_draw * alpha
    # 最后,将array转为图像
    return fromarray(out.astype(np.uint8))

5. backbone文件夹下的文件:

​ 这个文件夹下的内容就是**骨干CNN架构的内容。**其下有四个主要的文件:

resnet50+fpn
vgg
mobilenetv2
feature-pyramid-network

​ 这四个文件,其实没有什么好说的,因为都是根据网络架构来实现,对于我们来说,并不是很重要。当然,如果你感兴趣,可以在网络找到对应的架构图,然后参考代码自己实现,都是可以的。

6. train_mobilenetv2.py文件:

​ 这个文件和train_res50_fpn.py内容上都是相同的,代码大体也相似,作用就是训练backbone文件夹下的CNN架构。这里我以train_mobilenetv2.py来解读一下具体的内容。

main函数

​ 首先,肯定是指定一些参数变量,比如指定GPU、指定是否存在权重保存文件夹、指定预处理方、指定采用的数据集、batch_size大小等等:

# 指定GPU设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print("Using {} device training.".format(device.type))

# 用来保存coco_info的文件
# coco_info文件:
results_file = "results{}.txt".format(datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))

# 检查保存权重文件夹是否存在,不存在则创建
if not os.path.exists("save_weights"):
    os.makedirs("save_weights")

# 指定数据增强方式,即随机水平翻转(框和图片都要翻转)
data_transform = {
    "train": transforms.Compose([transforms.ToTensor(),
                                 transforms.RandomHorizontalFlip(0.5)]),
    "val": transforms.Compose([transforms.ToTensor()])
}

# 指定VOC数据集地址----需要修改
VOC_root = "./"  # VOCdevkit
aspect_ratio_group_factor = 3
batch_size = 8 # batch size大小
amp = False  # 是否使用混合精度训练,需要GPU支持

# 检查VOC数据集是否存在,否则报错
if os.path.exists(os.path.join(VOC_root, "VOCdevkit")) is False:
    raise FileNotFoundError("VOCdevkit dose not in path:'{}'.".format(VOC_root))

​ 接着,定义数据集和数据集的加载器(看注释):

# 加载数据集,使用我们自己定义的加载器来加载
# VOCdevkit -> VOC2012 -> ImageSets -> Main -> train.txt
train_dataset = VOCDataSet(VOC_root, "2012", data_transform["train"], "train.txt")
train_sampler = None

# 是否按图片相似高宽比采样图片组成batch
# 使用的话能够减小训练时所需GPU显存,默认使用
if aspect_ratio_group_factor >= 0:
    train_sampler = torch.utils.data.RandomSampler(train_dataset)
    # 统计所有图像高宽比例在bins区间中的位置索引
    group_ids = create_aspect_ratio_groups(train_dataset,k=aspect_ratio_group_factor)
    # 每个batch图片从同一高宽比例区间中取
    train_batch_sampler = GroupedBatchSampler(train_sampler, group_ids, batch_size)

# 使用多少个线程去加载图片
nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])
print('Using %g dataloader workers' % nw)

# 注意这里的collate_fn是自定义的,因为读取的数据包括image和targets,不能直接使用默认的方法合batch
if train_sampler:
    # 如果按照图片高宽比采样图片,dataloader中需要使用batch_sampler
    train_data_loader = torch.utils.data.DataLoader(train_dataset,
                                                   batch_sampler=train_batch_sampler, # 与sampler类似,但是一次只返回一个batch的indices(索引),需要注意的是,一旦指定了这个参数,那么batch_size,shuffle,sampler,drop_last就不能再制定了(互斥——Mutually exclusive)
                                                    pin_memory=True, # 如果设置为True,那么data loader将会在返回它们之前,将tensors拷贝到CUDA中的固定内存(CUDA pinned memory)中
                                                    num_workers=nw,  # 多线程读取数据
                                                    collate_fn=train_dataset.collate_fn)  #  将一个list的sample组成一个mini-batch的函数
else:
    train_data_loader = torch.utils.data.DataLoader(train_dataset,
                                                    batch_size=batch_size,
                                                    shuffle=True,
                                                    pin_memory=True,
                                                    num_workers=nw,
                                                    collate_fn=train_dataset.collate_fn)

# 加载验证集数据集
# VOCdevkit -> VOC2012 -> ImageSets -> Main -> val.txt
val_dataset = VOCDataSet(VOC_root, "2012", data_transform["val"], "val.txt")
val_data_loader = torch.utils.data.DataLoader(val_dataset,
                                              batch_size=1,
                                              shuffle=False,
                                              pin_memory=True,
                                              num_workers=nw,
                                              collate_fn=val_dataset.collate_fn)

​ 然后,将定义模型并将模型放入GPU中,顺带定义一些变量:(注意,此时的模型为Faster-RCNN模型,只是里面的CNN架构为mobilenetv2

# 创建模型,类别为固定的20+一个背景
model = create_model(num_classes=21)
# print(model)

# 放入GPU中
model.to(device)

# 梯度缩放,即有些梯度很小,计算机无法存储完,就会下溢,这时将梯度放大,即可存储下来
scaler = torch.cuda.amp.GradScaler() if amp else None

# 定义一些变量,主要用于后面的画图
train_loss = [] # 训练损失
learning_rate = []  # 学习率
val_map = []    # 验证集的mAP值

下面就是重头戏了,就是训练网络。作者这里采取如下的训练思路:首先,冻结CNN架构的权重(即让这部分不求梯度),然后用于训练RPN网络,这一阶段只训练5个epoch。然后,解冻CNN架构的权重,开始训练整个网络,这里需要注意,作者认为CNN架构最前面的几层是公用,又加上数据不多,因此前面几层不参与训练,即将其冻结权重。

​ 有了这个思路,看代码就很简单了,具体的可以看注释内容:

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#  first frozen backbone and train 5 epochs                   #
#  首先冻结前置特征提取网络权重(backbone),训练rpn以及最终预测网络部分 #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# 不求backbone的梯度,即不调节它们
for param in model.backbone.parameters():
    param.requires_grad = False

# define optimizer
# 确定要优化的参数
params = [p for p in model.parameters() if p.requires_grad]
# 定义优化器
optimizer = torch.optim.SGD(params, lr=0.005,
                            momentum=0.9, weight_decay=0.0005)

# 在前5个epoch训练对后面的参数微调
init_epochs = 5
for epoch in range(init_epochs):
    # train for one epoch, printing every 10 iterations
    mean_loss, lr = utils.train_one_epoch(model, optimizer, train_data_loader,
                                          device, epoch, print_freq=50,
                                          warmup=True, scaler=scaler)
    train_loss.append(mean_loss.item())
    learning_rate.append(lr)

    # 在测试集上验证
    coco_info = utils.evaluate(model, val_data_loader, device=device)

    # 训练信息写入文件
    with open(results_file, "a") as f:
        # 写入的数据包括coco指标还有loss和learning rate
        result_info = [f"{i:.4f}" for i in coco_info + [mean_loss.item()]] + [f"{lr:.6f}"]
        txt = "epoch:{} {}".format(epoch, '  '.join(result_info))
        f.write(txt + "\n")

	val_map.append(coco_info[1])  # pascal mAP
    
# 保存权重
torch.save(model.state_dict(), "./save_weights/pretrain.pth")

# # # # # # # # # # # # # # # # # # # # # # # # # # # #
#  second unfrozen backbone and train all network     #
#  解冻前置特征提取网络权重(backbone),接着训练整个网络权重  #
# # # # # # # # # # # # # # # # # # # # # # # # # # # #

# 冻结backbone部分底层权重:认为前面几层是公用的特征+data很少,训练整个网络不够,因此冻结部分层(官方实现方法)
for name, parameter in model.backbone.named_parameters():
    split_name = name.split(".")[0]
    if split_name in ["0", "1", "2", "3"]:
        parameter.requires_grad = False # 冻结
	else:
		parameter.requires_grad = True  # 解冻

# 确定哪些参数需要训练
params = [p for p in model.parameters() if p.requires_grad]
# 定义优化器
optimizer = torch.optim.SGD(params, lr=0.005,
                            momentum=0.9, weight_decay=0.0005)
# 学习调整方法,每三次调整一次,乘以0.33
lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
                                               step_size=3,
                                               gamma=0.33)
# 开始训练,调整参数
num_epochs = 20
for epoch in range(init_epochs, num_epochs+init_epochs, 1):
    # 开始训练一个epoch,每50次迭代打印依次损失值
    mean_loss, lr = utils.train_one_epoch(model, optimizer, train_data_loader,
                                          device, epoch, print_freq=50,
                                          warmup=True, scaler=scaler)
    # 保存平均损失和当前学习率
    train_loss.append(mean_loss.item())
    learning_rate.append(lr)

    # 更新学习率
    lr_scheduler.step()

    # 在测试集上验证
    coco_info = utils.evaluate(model, val_data_loader, device=device)

    # 将训练信息写入文件
    with open(results_file, "a") as f:
        # 写入的数据包括coco指标还有loss和learning rate
        result_info = [f"{i:.4f}" for i in coco_info + [mean_loss.item()]] + [f"{lr:.6f}"]
        txt = "epoch:{} {}".format(epoch, '  '.join(result_info))
        f.write(txt + "\n")

	val_map.append(coco_info[1])  # pascal mAP

	# 仅保存最后5个epoch的权重
	# 还需要保存一些优化器、学习率等的参数
    if epoch in range(num_epochs+init_epochs)[-5:]:
        save_files = {
            'model': model.state_dict(),
            'optimizer': optimizer.state_dict(),
            'lr_scheduler': lr_scheduler.state_dict(),
            'epoch': epoch}
        torch.save(save_files, "./save_weights/mobile-model-{}.pth".format(epoch))

​ 最后,就是画出损失函数、学习率和mAP图像即可:

# 画损失函数图和学习率图
if len(train_loss) != 0 and len(learning_rate) != 0:
    from plot_curve import plot_loss_and_lr
    plot_loss_and_lr(train_loss, learning_rate)

# 画mAP图
if len(val_map) != 0:
    from plot_curve import plot_map
    plot_map(val_map)

create_model函数:

​ 这个函数是上面main函数中的创建模型函数。

​ 这个函数里面涉及到了很多其它的函数,我会在下一篇进行讲解,这里仅仅做概述:

def create_model(num_classes):
    # https://download.pytorch.org/models/vgg16-397923af.pth
    # 如果使用vgg16的话就下载对应预训练权重并取消下面注释,接着把mobilenetv2模型对应的两行代码注释掉
    # vgg_feature = vgg(model_name="vgg16", weights_path="./backbone/vgg16.pth").features
    # backbone = torch.nn.Sequential(*list(vgg_feature._modules.values())[:-1])  # 删除features中最后一个Maxpool层
    # backbone.out_channels = 512
    
    # 拥有预训练权重
    # https://download.pytorch.org/models/mobilenet_v2-b0353104.pth
    # backbone采用mobilenetv2
    backbone = MobileNetV2(weights_path="./backbone/mobilenet_v2.pth").features
    # 设置输出数目
    backbone.out_channels = 1280  # 设置对应backbone输出特征矩阵的channels
    
    # 生成anchor
    # size即尺寸
    # aspect_ratios即缩放因子
    anchor_generator = AnchorsGenerator(sizes=((32, 64, 128, 256, 512),),
                                        aspect_ratios=((0.5, 1.0, 2.0),))
    
    # 生成roi
    roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=['0'],  # 在哪些特征层上进行roi pooling
                                                    output_size=[7, 7],   # roi_pooling输出特征矩阵尺寸
                                                    sampling_ratio=2)  # 采样率
    # 创建Faster-RCNN模型,并指定相关参数
    model = FasterRCNN(backbone=backbone,
                       num_classes=num_classes,
                       rpn_anchor_generator=anchor_generator,
                       box_roi_pool=roi_pooler)

    return model

​ 这里需要注意的是AnchorsGenerator中的size参数有五个值,而在原论文中只有三个值128, 256, 512,加上三个缩放因子,就生成3*3=9个anchors。这里有五个值,是作者改变的,可能是方便小目标的检测。

7. 总结:

​ 上面解读的文件中,最重要的就是train_mobilenetv2.py文件,这个文件就是训练Faster-RCNN的文件,只是采用的CNN架构为mobilenetV2。

​ 另外,值得一提的是:如果后期你要调试代码,查看变量的值,就需要运行该文件。

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

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

相关文章

我的创作纪念日:Unity CEO表示生成式AI将是Unity近期发展重点,发布神秘影片预告

PICK 未来的AI技术将会让人类迎来下一个生产力变革,这其中也包括生成型AI的突破性革新。各大公司也正在竞相推出AIGC工具,其中微软的Copilot、Adobe的Firefly、Github的chatGPT等引起了人们的关注。然而,游戏开发领域似乎还没有一款真正针对性…

vector容器

1、vector简介 vector 和 arry 非常相似,唯一存在的不同是 vector 是动态分配内存空间,随着元素的增加空间自动增加,但是 arry 是静态的 wector:单端动态数组容器,只允许在一端进行操作 2、vector的使用 需要引进头…

PyTorch深度学习实战 | 基于多层感知机模型和随机森林模型的某地房价预测

简介: 在现实生活中,除了分类问题外,也存在很多需要预测出具体值的回归问题,例如年龄预测、房价预测、股价预测等。相比分类问题而言,回归问题输出类型为一个连续值,如下表所示为两者的区别。在本文中&…

打造高效自动化测试流程:Jenkins+Allure+Pytest环境搭建和实战

引言 自动化测试已经成为软件开发中不可或缺的一部分。而在自动化测试中,Jenkins、Allure和Pytest这三个工具的组合可以说是非常流行和实用的。 Jenkins作为持续集成工具,可以充分利用其丰富的插件体系来搭建自动化测试环境; Allure则为我们…

怎么把jpg转换成pdf格式?实用又简单的方法来了

在工作和学习中,我们常常需要发送一些重要的图片给别人,这些图片可能包含学习资料或者重要的文件内容。但是发送多个JPG图片既不方便又不直观,所以我们需要将它们转换成PDF格式,以便于发送和查看。如果你不知道如何进行JPG到PDF的…

UI学习路线图2023完整版(适合自学)

作为数字时代中不可或缺的职业之一,UI设计师在今天和未来都有着广阔的职业前景。UI设计师有高需求行业、薪资高、职位晋升空间大、多样化的工作机会、职业发展空间大等许多优势,也有很多小伙伴想自学UI设计,但是不知道自己怎么学,…

服务器节点之间 如何实现自动化文件同步?

大数据、云计算、物联网的发展,使得企业能够拥有的数据急剧增加。面对快速变化和增长的庞大数据,如何高效地管理、利用数据对于企业来说至关重要。 但是,数据传输模式单一、自动化程度低、传输效率低下等难题,阻碍着企业对其数字…

TensorFlow 1.x 深度学习秘籍:6~10

原文:TensorFlow 1.x Deep Learning Cookbook 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 不要担心自己的形象,只关心如…

高级UI之Android事件分发机制原理及源码分析

前言 在 Android 中,事件分发机制是一块很重要的知识点, 掌握这个机制能帮你在平时的开发中解决掉很多的 View 事件冲突问题,这个问题也是面试中问的比较多的一个问题了,本篇就来总结下这个知识点。 事件分发原因 Android 中页…

RK3399平台开发系列讲解(外设篇)Camera OV13850配置过程

🚀返回专栏总目录 文章目录 一、DTS 配置二、驱动说明三、配置原理四、cam_board.xml沉淀、分享、成长,让自己和他人都能有所收获!😄 📢我们以 OV13850/OV5640 摄像头为例,讲解在该开发板上的配置过程。 一、DTS 配置 isp0: isp@ff910000 {…status = "okay&quo…

R-CNN(Region with CNN feature)

目录 1. 介绍 2. R-CNN 2.1 SS(Selective Search) 算法 生成候选框 2.2 CNN 提取特征 2.3 SVM 分类 非极大值抑制 2.4 回归器微调候选框 3. R-CNN 的缺点 1. 介绍 目标识别的发展历史如图 2. R-CNN RCNN 是两阶段目标检测的鼻祖,类似于深度学习开山之作Al…

第03章_流程控制语句

第03章_流程控制语句 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模…

算法记录 | Day32 贪心算法

122.买卖股票的最佳时机II 贪心算法 思路: 把利润分解为每天为单位的维度,而不是从0天到第3天整体去考虑! 那么根据prices可以得到每天的利润序列:(prices[i] - prices[i - 1])…(prices[1] - prices[0])。 如图:…

PyCharm+PyQt5+pyinstaller打包labelImg.exe

0 开头 labelImg是一款标注软件,作为一个开源项目,它的源码可以在github上找到。官方仓库地址为: https://github.com/heartexlabs/labelImg 小白安装时的最新版本编译出来的界面长这样: 之前在小白的博客里,也教过…

Spring学习5

一、代理模式 代理模式就是AOP的底层! 1.代理模式的分类 静态代理动态代理2.静态代理 角色分析: 抽象角色:一般使用接口或者抽象类来解决真实角色:被代理的角色代理角色:代理真实角色后,一般会做一些附属操…

走进小程序【七】微信小程序【常见问题总结】

文章目录🌟前言🌟小程序登录🌟unionid 和 openid🌟关键Api🌟登录流程设计🌟利用现有登录体系🌟利用OpenId 创建用户体系🌟利用 Unionid 创建用户体系🌟授权获取用户信息流…

JVM内存模型详解

JVM内存模型和Java内存模型都是面试的热点问题,名字看感觉都差不多,实际上他们之间差别还是挺大的。 通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与多线程编程相关mikechen。 什么是JVM JVM是Java Virtual …

【教学类-30-04】10以内减法题不重复(一页两份)(包括6以内、7以内、8以内、9以内、10以内减法题 只抽取25个)

作品展示 ——10以内不重复减法题 需求: 1、制作10以内减法题 材料准备: Word模板 代码展示: 6、7、8、9、10以内减法一页两份(10以内减法一页两份(6以内、7以内、8以内、9以内、10以内不重复减法题) 时间…

文件访问被拒绝?5个解决方法!

案例:文件访问被拒绝 【朋友们,想问问大家的电脑有遇到过文件访问被拒绝的情况吗?真的太头疼了,大家都是怎么解决的呢?】 在日常使用电脑和操作文件时,有时我们可能会遇到文件访问被拒绝的情况。这可能会…

Scala框架Akka学习

Scala框架Akka 文章目录Scala框架AkkaAkka概述Akka特点Akka与Scala.actors.Actor的关系Akka模型介绍Actor模型的优点Akka模型的核心概念如何创建Actor添加依赖在Akka中,Actor负责通信,在Actor中有一些重要的生命周期方法**akka的架构原理**创建Actor的步…