【目标检测】YOLOv5算法实现(七):模型训练

news2024/9/28 19:15:28

  本系列文章记录本人硕士阶段YOLO系列目标检测算法自学及其代码实现的过程。其中算法具体实现借鉴于ultralytics YOLO源码Github,删减了源码中部分内容,满足个人科研需求。
  本系列文章主要以YOLOv5为例完成算法的实现,后续修改、增加相关模块即可实现其他版本的YOLO算法。

文章地址:
YOLOv5算法实现(一):算法框架概述
YOLOv5算法实现(二):模型加载
YOLOv5算法实现(三):数据集加载
YOLOv5算法实现(四):损失计算
YOLOv5算法实现(五):预测结果后处理
YOLOv5算法实现(六):评价指标及实现
YOLOv5算法实现(七):模型训练
YOLOv5算法实现(八):模型验证
YOLOv5算法实现(九):模型预测(编辑中…)

本文目录

  • 1 引言
  • 2 超参数文件
  • 3 模型训练(train.py)

1 引言

  本篇文章综合之前文章中的功能,实现模型的训练。模型训练的逻辑如图1所示。
在这里插入图片描述

图1 模型训练流程

2 超参数文件

  YOLOv5中超参数主要包括学习率、优化器、置信度以及数据增强,源码中某一超参数文件及各参数含义如下所示:

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Hyperparameters for VOC training

# 学习率
lr0: 0.00334  # 初始学习率
lrf: 0.15135  # 最终学习率下降比例(lr0 * lrf)
# 优化器(SGD、Adam、AdamW)
momentum: 0.74832 # SGD momentum/Adam beta1
weight_decay: 0.00025 # optimizer weight decay 5e-4 ,权重衰变系数(防止过拟合)
# 热身训练(Warmup)
warmup_epochs: 3.3835 # 学习率热身epoch
warmup_momentum: 0.59462 # 学习率热身初始动量
warmup_bias_lr: 0.18657 # 学习率热身偏置学习率
# 损失增益
box: 0.02 # box loss gain
cls: 0.21638 # cls loss gain
cls_pw: 0.5 # cls BCELoss positive_weight
obj: 0.51728 # obj loss gain (scale with pixels)
obj_pw: 0.67198 # obj BCELoss positive_weight
fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
# 正样本匹配阈值
iou_t: 0.2 # IoU training threshold
anchor_t: 3.3744 # anchor-multiple threshold
# 数据增强
## HSV色彩空间增强
hsv_h: 0.01041
hsv_s: 0.54703
hsv_v: 0.27739
## 仿射变换
degrees: 0.0 #图像旋转
translate: 0.04591 #图像平移
scale: 0.75544 #图像仿射变换的缩放比例
shear: 0.0 #设置裁剪的仿射矩阵系数

3 模型训练(train.py)

def train(hyp):
    # ----------------------------------------------------------------------------------
    # hyp超参数解析
    # ----------------------------------------------------------------------------------
    # 训练设备
    device = torch.device(opt.device if torch.cuda.is_available() else "cpu")
    print("Using {} device training.".format(device.type))

    # 权重保存文件
    wdir = "weights" + os.sep  # weights dir

    # 损失和学习率记录txt, 损失和学习率变化曲线, 权重文件保存路径
    results_file, save_file_path, save_path \
        = opt.results_file, opt.save_file_path, opt.save_path

    # 模型结构文件
    cfg = opt.yaml
    # data文件路径, 其中存储了训练和验证数据集的路径
    data = opt.data
    # 训练批次
    epochs = opt.epochs
    batch_size = opt.batch_size
    # 初始化权重路径
    weights = opt.weights  # initial training weights
    # 训练和测试的图片大小
    imgsz_train = opt.img_size
    imgsz_test = opt.img_size
    # 图像要设置成32的倍数
    gs = 32  # (pixels) grid size
    assert math.fmod(imgsz_test, gs) == 0, "--img-size %g must be a %g-multiple" % (imgsz_test, gs)
    # ----------------------------------------------------------------------------------
    # ----------------------------------------------------------------------------------

    # 数据字典 "classes": 类别数, "train":训练数据集路径 "valid":验证数据集路径 "names": 类别名
    data_dict = parse_data_cfg(data)
    train_path = data_dict['train']
    val_path = data_dict['valid']
    # 类别数
    nc = opt.nc
    # Remove previous results
    for f in glob.glob(results_file):
        os.remove(f)

    # ----------------------------------------------------------------------------------
    # 模型初始化(加载预训练权重)
    # ----------------------------------------------------------------------------------
    # 初始化模型
    model = Model(cfg=cfg, ch=3, nc=nc).to(device)
    # 开始训练的epoch
    start_epoch = 0
    best_map = 0
    pretrain = False
    if weights.endswith(".pt") or weights.endswith(".pth"):
        pretrain = True
        ckpt = torch.load(weights, map_location=device)

        # load model
        try:
            ckpt["model"] = {k: v for k, v in ckpt["model"].items() if model.state_dict()[k].numel() == v.numel()}
            model.load_state_dict(ckpt["model"], strict=False)
        except KeyError as e:
            s = "%s is not compatible with %s. Specify --weights '' or specify a --cfg compatible with %s. " \
                "See https://github.com/ultralytics/yolov3/issues/657" % (opt.weights, opt.cfg, opt.weights)
            raise KeyError(s) from e


        # load results
        if ckpt.get("training_results") is not None:
            with open(results_file, "w") as file:
                file.write(ckpt["training_results"])  # write results.txt
        # 加载最好的map
        if "best_map" in ckpt.keys():
            best_map = ckpt['best_map']

        # epochs
        start_epoch = ckpt["epoch"] + 1
        if epochs < start_epoch:
            print('%s has been trained for %g epochs. Fine-tuning for %g additional epochs.' %
                  (opt.weights, ckpt['epoch'], epochs))
            epochs += ckpt['epoch']  # finetune additional epochs

        del ckpt

        hyp['lr0'] = hyp['lr0'] * hyp['lrf']

        print(colorstr('Pretrain') + ': Successful load pretrained weights.')
    # ----------------------------------------------------------------------------------
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # 定义优化器和学习率策略
    # ----------------------------------------------------------------------------------
    nbs = 64  # 训练多少图片进行一次反向传播
    accumulate = max(round(nbs / batch_size), 1)  # accumulate n times before optimizer update (bs 64)
    hyp['weight_decay'] *= batch_size * accumulate / nbs  # scale weight_decay
    # 定义优化器
    optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay'])
    # Scheduler
    if opt.cos_lr:
        lf = one_cycle(1, hyp['lrf'], epochs)  # cosine 1->hyp['lrf']
    else:
        lf = lambda x: (1 - x / epochs) * (1.0 - hyp['lrf']) + hyp['lrf']  # linear
    scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
    scheduler.last_epoch = start_epoch  # 指定从哪个epoch开始
    # ----------------------------------------------------------------------------------
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # 加载数据集
    # ----------------------------------------------------------------------------------
    train_dataset = LoadImagesAndLabels(train_path, imgsz_train, batch_size,
                                        augment=True,
                                        hyp=hyp,  # augmentation hyperparameters
                                        rect=False,  # rectangular training
                                        cache_images=opt.cache_images,)
    # dataloader
    num_workers = 0  # number of workers
    train_dataloader = torch.utils.data.DataLoader(train_dataset,
                                                   batch_size=batch_size,
                                                   num_workers=num_workers,
                                                   # Shuffle=True unless rectangular training is used
                                                   shuffle=not opt.rect,
                                                   pin_memory=True,
                                                   collate_fn=train_dataset.collate_fn)
    # 当需要根据map保存最好的权值时, 加载验证数据集
    val_dataset = LoadImagesAndLabels(val_path, imgsz_test, batch_size,
                                      hyp=hyp,
                                      rect=True,
                                      cache_images=opt.cache_images)
    val_dataloader = torch.utils.data.DataLoader(val_dataset,
                                                 batch_size=batch_size,
                                                 num_workers=num_workers,
                                                 pin_memory=True,
                                                 collate_fn=val_dataset.collate_fn)

    # train_dataset.labels (1203, ) 1203张图片中的所有标签(nt,5)
    # np.concatenate 在维度0上对所有标签进行拼接 (1880, 5)
    labels = np.concatenate(train_dataset.labels, 0)
    mlc = int(labels[:, 0].max())  # 最大的类别标签
    assert mlc < nc, f'Label class {mlc} exceeds nc={nc} in {data}. Possible class labels are 0-{nc - 1}'
    # ----------------------------------------------------------------------------------
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # 模型参数定义
    # ----------------------------------------------------------------------------------
    nl = model.model[-1].nl  # 输出特征图数量
    hyp['box'] *= 3 / nl  # scale to layers
    hyp['cls'] *= nc / 80 * 3 / nl  # scale to classes and layers
    hyp['obj'] *= (imgsz_test / 640) ** 2 * 3 / nl  # scale to image size and layers
    hyp['label_smoothing'] = opt.label_smoothing
    model.nc = nc  # attach number of classes to model
    model.hyp = hyp  # attach hyperparameters to model
    # ----------------------------------------------------------------------------------
    # ----------------------------------------------------------------------------------
    compute_loss = ComputeLoss(model)

    # ----------------------------------------------------------------------------------
    # 开始训练
    # ----------------------------------------------------------------------------------
    nb = len(train_dataloader)  # batches的数量, dataloader已经将data安装batch_size进行了打包
    nw = max(round(hyp['warmup_epochs'] * nb), 100)  # 热身训练的迭代次数, max(3 epochs, 100 iterations)
    last_opt_step = -1  # 最后一次更新参数的步数
    train_loss, train_box_loss, train_obj_loss, train_cls_loss = [], [], [], []
    learning_rate = []

    if opt.savebest:
        best_map = ComputeAP(model, val_dataloader, device=device)
        print(f"{colorstr('Initialize best_map')}: mAP@0.50 = {best_map: .5f}")

    print(f'Image sizes {imgsz_train} train, {imgsz_test} val\n'
                f'Using {num_workers} dataloader workers\n'
                f'Starting training for {epochs} epochs...')
    for epoch in range(start_epoch, epochs):
        model.train()

        # 训练过程中的信息打印
        metric_logger = utils.MetricLogger(delimiter="  ")
        metric_logger.add_meter('lr', utils.SmoothedValue(window_size=1, fmt='{value:.6f}'))
        header = 'Epoch: [{}]'.format(epoch)

        # 当前训练批次的平均损失
        mloss = torch.zeros(4, device=device)
        now_lr = 0.

        optimizer.zero_grad()

        # imgs: [batch_size, 3, img_size, img_size]
        # targets: [num_obj, 6] , that number 6 means -> (img_index, obj_index, x, y, w, h)
        # 其中(x, y, w, h)绝对作了缩放处理后的相对坐标
        # paths: list of img path(文件路径)
        for i, (imgs, targets, paths, _, _) in enumerate(metric_logger.log_every(train_dataloader, 50, header)):
            ni = i + nb * epoch  # number integrated batches (since train start)
            imgs = imgs.to(device).float() / 255.0  # uint8 to float32, 0 - 255 to 0.0 - 1.0

            # ----------------------------------------------------------------------------------
            # Warmup 热身训练
            # ----------------------------------------------------------------------------------
            if ni <= nw:
                xi = [0, nw]  # x interp
                # compute_loss.gr = np.interp(ni, xi, [0.0, 1.0])  # iou loss ratio (obj_loss = 1.0 or iou)
                accumulate = max(1, np.interp(ni, xi, [1, nbs / batch_size]).round())
                for j, x in enumerate(optimizer.param_groups):
                    # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0
                    x['lr'] = np.interp(ni, xi, [hyp['warmup_bias_lr'] if j == 0 else 0.0, x['initial_lr'] * lf(epoch)])
                    if 'momentum' in x:
                        x['momentum'] = np.interp(ni, xi, [hyp['warmup_momentum'], hyp['momentum']])
            # ----------------------------------------------------------------------------------
            # ----------------------------------------------------------------------------------

            # 前向传播
            pred = model(imgs)
            # 损失计算
            loss_dict = compute_loss(pred, targets.to(device))
            losses = sum(loss for loss in loss_dict.values())

            loss_items = torch.cat((loss_dict["box_loss"],
                                    loss_dict["obj_loss"],
                                    loss_dict["class_loss"],
                                    losses)).detach()
            mloss = (mloss * i + loss_items) / (i + 1)  # update mean losses

            # 反向传播
            losses *= batch_size
            losses.backward()

            # 每训练accumulate次进行参数更新
            if ni - last_opt_step >= accumulate:
                optimizer.step()
                optimizer.zero_grad()

            metric_logger.update(loss=losses, **loss_dict)
            now_lr = optimizer.param_groups[0]["lr"]
            metric_logger.update(lr=now_lr)
            # end batch ----------------------------------------------------------------------
        scheduler.step()


        train_loss.append(mloss.tolist()[-1])
        learning_rate.append(now_lr)
        result_mAP = ComputeAP(model, val_dataloader, device=device)
        voc_mAP = result_mAP[1]  # @0.50
        # write into txt
        with open(results_file, "a") as f:
            # box_loss, obj_clss, cls_loss, train_loss, lr
            result_info = [str(round(i, 4)) for i in [mloss.tolist()[0]]] + \
                          [str(round(i, 4)) for i in [mloss.tolist()[1]]] + \
                          [str(round(i, 4)) for i in [mloss.tolist()[2]]] + \
                          [str(round(i, 4)) for i in [mloss.tolist()[-1]]] + \
                          [str(round(now_lr, 6))] + [str(round(voc_mAP, 6))]
            txt = "epoch:{} {}".format(epoch, '  '.join(result_info))
            f.write(txt + "\n")
        if opt.savebest:
            if voc_mAP > best_map:
                print(f"{colorstr('Save best_map Weight')}: update mAP@0.50 from {best_map: .5f} to {voc_mAP: .5f}")
                best_map = voc_mAP
                with open(results_file, 'r') as f:
                    save_files = {
                        'model': model.state_dict(),
                        'optimizer': optimizer.state_dict(),
                        'training_results': f.read(),
                        'epoch': epoch,
                        'best_map': best_map
                    }
                    torch.save(save_files, save_path.format('best_map'))
        else:
            if (epoch + 1) % 20 == 0 or epoch == epochs - 1:
                with open(results_file, 'r') as f:
                    save_files = {
                        'model': model.state_dict(),
                        'training_results': f.read(),
                        'epoch': epoch}
                    torch.save(save_files, save_path.format(epoch))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    # -----------------------------------------
    file = "yolov5s"
    weight_file = f"weights/{file}"  # 权重存储文件
    result_file = f'results/{file}'  # 训练损失、mAP等保存文件
    if not os.path.exists(weight_file):
        os.makedirs(weight_file)
    if not os.path.exists(result_file):
        os.makedirs(result_file)
    # -----------------------------------------
    parser.add_argument('--epochs', type=int, default=300)
    parser.add_argument('--batch-size', type=int, default=4)
    parser.add_argument('--nc', type=int, default=3)
    yaml_path = f'cfg/models/{file}.yaml'
    parser.add_argument('--yaml', type=str, default=yaml_path, help="model.yaml path")
    parser.add_argument('--data', type=str, default='data/my_data.data', help='*.data path')
    parser.add_argument('--hyp', type=str, default='cfg/hyps/hyp.scratch-med.yaml', help='hyperparameters path')
    parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW'], default='SGD', help='optimizer')
    parser.add_argument('--cos-lr', type=bool, default=True, help='cosine LR scheduler')
    parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')
    parser.add_argument('--img-size', type=int, default=640, help='test size')
    parser.add_argument('--rect', action='store_true', help='rectangular training')
    parser.add_argument('--savebest', type=bool, default=False, help='only save best checkpoint')
    # 当内存足够时, 设置为True, 将数据集加载到内存中, 在训练时不用从磁盘中读取图片可以加快训练速度
    parser.add_argument('--cache-images', default=False, help='cache images for faster training')
    # 预训练权重
    weight = f'weights/{file}/{file}.pt'

    parser.add_argument('--weights', type=str, default=weight if os.path.exists(weight) else "", help='initial weights path')

    parser.add_argument('--device', default='cuda:0', help='device id (i.e. 0 or 0,1 or cpu)')


    # 结果保存路径

    time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
    results_file = f"./results/{file}/results{time}.txt"
    parser.add_argument("--results_file", default=results_file, help="save results files")
    save_file_path = f'./results/{file}/loss_and_lr{time}.png'
    parser.add_argument('--save_file_path', default=save_file_path, help="save loss and lr fig")
    save_path = f"./weights/{file}/{file}-" + "{}.pt"
    parser.add_argument('--save_path', default=save_path, help="weight save path")
    opt = parser.parse_args()

    # 检查文件是否存在
    opt.cfg = check_file(opt.yaml)
    opt.data = check_file(opt.data)
    opt.hyp = check_file(opt.hyp)
    print(opt)

    with open(opt.hyp) as f:
        hyp = yaml.load(f, Loader=yaml.FullLoader)

    train(hyp)

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

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

相关文章

随机过程——卡尔曼滤波学习笔记

一、均方预测和随机序列分解 考虑随机序列 使用预测 定义 称为的均方可预测部分。 若相互独立&#xff0c;则是均方不可预测的。 定义随机序列的新息序列 V(k)基于样本观测的条件均值为0&#xff0c;即均方不可预测。 V(k)与是正交的&#xff0c;即。 二、卡尔曼滤波 …

2024-01-11 部署Stable Diffusion遇挫记

点击 <C 语言编程核心突破> 快速C语言入门 部署Stable Diffusion遇挫记 前言一、一如既往的GitHub部署二、使用的感受总结 create by Stable Diffusion; prompt: fire water llama 前言 要解决问题: 由于近期的努力, 已经实现语音转文字模型, 通用chat迷你大模型的本地…

JVM基础(11)——G1垃圾回收器

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

一文了解2024年AMC8竞赛模拟考试安排的重点和注意事项(附资源)

各位报名参加2024年AMC8竞赛的家长和孩子们注意了&#xff01;今天到明天就可以参加AMC8竞赛的模拟考试了&#xff0c;本文结合本次模拟考试的常见问题为大家进行了梳理&#xff0c;站在参赛者的角度把2024年AMC8的模拟考试的关键事项和要点说清楚&#xff0c;让您最准确、快速…

大模型日报-20240113

击败 8 名人类规划师&#xff1a;清华团队提出强化学习的城市空间规划模型 https://mp.weixin.qq.com/s/GkL5peKCOJLh4pLjiTeIFw 近年来&#xff0c;以更加宜居为导向&#xff0c;「15 分钟城市」概念得到了更多关注&#xff0c;其核心是居民在 15 分钟内可步行或骑行到基本服…

88.乐理基础-记号篇-反复记号(二)D.C.、D.S.、Fine、Coda

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;87.乐理基础-记号篇-反复记号&#xff08;一&#xff09;反复、跳房子-CSDN博客 下图红色左括号框起来的东西&#xff0c;它们都相对比较抽象一点&#xff0c;这几个词都是意大利语 首先D.C.这个标记&#xff0c;然…

win11更改桌面默认存储路径

打开文件资源管理器 右击桌面点击属性 在属性中找到位置选项卡&#xff0c;在里面有一个移动&#xff0c;点击它选择你想要的位置 选好位置后点击应用&#xff0c;随后会出现一个进度条&#xff0c;跑完后点击确认 到这里就完成了桌面默认位置的转移

Pandas实战100例-专栏介绍

Pandas&#xff0c;Python数据科学的心脏&#xff0c;是探索和分析数据世界的强大工具。想象一下&#xff0c;用几行代码就能洞察庞大数据集的秘密&#xff0c;无论是金融市场趋势还是社交媒体动态。 通过Pandas&#xff0c;你可以轻松地整理、清洗、转换数据&#xff0c;将杂…

Python 全栈体系【四阶】(十二)

第四章 机器学习 十五、朴素贝叶斯 朴素贝叶斯是一组功能强大且易于训练的分类器&#xff0c;它使用贝叶斯定理来确定给定一组条件的结果的概率&#xff0c;“朴素”的含义是指所给定的条件都能独立存在和发生。朴素贝叶斯是多用途分类器&#xff0c;能在很多不同的情景下找到…

WSL不同版本的Ubuntu更换清华镜像,加速Ubuntu软件下载速度

文章目录 不同版本的Ubuntu使用清华镜像&#xff0c;加速Ubuntu软件下载速度1. 备份源软件配置文件2. 复制镜像源3. 修改软件源配置文件4. 更新软件包列表&#xff0c;升级软件包等内容5. 从仓库中下载其它软件可能存在的问题 不同版本的Ubuntu使用清华镜像&#xff0c;加速Ubu…

深入理解UML中的继承关系

深入理解UML中的继承关系 在面向对象的设计中&#xff0c;继承关系是构建清晰、可维护系统的关键。统一建模语言&#xff08;UML&#xff09;提供了一种标准化的方法来可视化这些关系。本文将深入探讨UML中的继承关系&#xff0c;并探讨它如何在代码中体现。 什么是继承关系&a…

【AI大模型应用开发】1.1 Prompt Engineering(提示词工程)- 用OpenAI API实战,优化方法论总结

书接上文 【AI大模型应用开发】1.0 Prompt Engineering&#xff08;提示词工程&#xff09;- 典型构成、原则与技巧&#xff0c;代码中加入Prompt&#xff0c;我们开始实战。 文章目录 0. 从最简单的开始0.1 通用代码封装0.2 使用 - 从最简单的Prompt开始0.2.1 temperature参数…

Git新手?这篇文章带你飞!基础操作一网打尽!

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读Git初识Git啥是版本控制系统&#xff1f;&#xff1f;集中式VS分布式 git使用…

Ubuntu 在线Swap扩容

1. 查看本机swap空间 free -h 2. 找一个较大的高速盘&#xff0c;创建swap的空间 mkdir /swap cd /swap sudo dd if/dev/zero ofswapfile bs50M count1k3.建swapfile&#xff0c;大小为bs*count 50M * 1k 50G 4.标记为Swap文件&#xff0c;让系统能识别交换文件。 sudo mk…

表单生成器基于(form-create-designer+ant design vue)

效果展示 1.源码地址&#xff1a; 前端&#xff1a;https://gitee.com/houshixin/form-design-ui 后端&#xff1a;https://gitee.com/houshixin/form-design-web 2.单独使用前端的时候就把请前后台的接口注释就可以 3.都启动的话&#xff1a; 1&#xff09;.先导入数据库 2.表…

统信UOS_麒麟KYLINOS与Windows通过Open SSH实现文件传输

原文链接&#xff1a;统信UOS/麒麟KYLINOS与Windows通过Open SSH实现文件传输 hello&#xff0c;大家好啊&#xff01;今天我要给大家介绍的是在统信UOS或麒麟KYLINOS操作系统与Windows系统之间通过Open SSH实现文件传输的方法。在日常工作中&#xff0c;我们经常需要在不同操作…

【JUC】JAVA线程小结

Java线程 前言——阅读10-20分钟&#x1f386;1.创建和运行线程ThreadRunableFutureTask多个线程运行方式 &#x1f4e3;2.不同操作系统查看进程线程的方法windowslinuxJava命令行 &#x1f680;3.java线程运行原理栈与栈帧线程上下文切换&#xff08;Thread Context Switch&am…

word写标书的疑难杂症总结

最近在解决方案工作&#xff0c;与office工具经常打交道&#xff0c;各种问题&#xff0c;在此最下记录&#xff1a; 1.word中文档距离文档顶端有距离调整不了 1.疑难杂症问题1&#xff0c;多个空格都是不能解决 #解决办法&#xff1a;word中--布局-下拉框---“版式”--“垂直…

机器人持续学习基准LIBERO系列5——获取显示深度图

0.前置 机器人持续学习基准LIBERO系列1——基本介绍与安装测试机器人持续学习基准LIBERO系列2——路径与基准基本信息机器人持续学习基准LIBERO系列3——相机画面可视化及单步移动更新机器人持续学习基准LIBERO系列4——robosuite最基本demo 1.更改环境设置 LIBERO-master/l…

MagnificAI的爆火之下 - AI时代,伟大的公司只需要2个人

这两天&#xff0c;Magnific AI又被推上风口浪尖。 起因是他们发布了全新的功能&#xff1a;将任何图像放大并增强至10,000 x 10,000 像素。 传说中的4K超清&#xff0c;也就4096像素&#xff0c;但是Magnific AI可以将一张600像素糊成智障的图片&#xff0c;几分钟的时间&…