OAK相机如何将 YOLO NAS 模型转换成blob格式?

news2024/12/22 20:19:38

编辑:OAK中国
首发:oakchina.cn
喜欢的话,请多多👍⭐️✍
内容可能会不定期更新,官网内容都是最新的,请查看首发地址链接。

▌前言

Hello,大家好,这里是OAK中国,我是助手君。

最近咱社群里有几个朋友在将yolo转换成blob的过程有点不清楚,所以我就写了这篇博客。(请夸我贴心!咱的原则:合理要求,有求必应!)

1.其他Yolo转换及使用教程请参考
2.检测类的yolo模型建议使用在线转换(地址),如果在线转换不成功,你再根据本教程来做本地转换。

.pt 转换为 .onnx

使用下列脚本将 YOLO NAS 模型转换为 onnx 模型,若已安装 openvino_dev,则可进一步转换为 OpenVINO 模型:

安装依赖:

pip install super_gradients

示例用法:

python export_yolo_nas.py -m yolo_nas_s -imgsz 640 
usage: export_yolo_nas.py [-h] [-m {yolo_nas_s,yolo_nas_m,yolo_nas_l}] [-imgsz IMG_SIZE [IMG_SIZE ...]]
                         [-op OPSET] [-n NAME] [-o OUTPUT_DIR] [-b] [-s] [-sh SHAVES]
                         [-t {docker,blobconverter,local}]

Tool for converting YOLO NAS models to the blob format used by OAK

optional arguments:
  -h, --help            show this help message and exit
  -m {yolo_nas_s,yolo_nas_m,yolo_nas_l}, -i {yolo_nas_s,yolo_nas_m,yolo_nas_l}, -w {yolo_nas_s,yolo_nas_m,yolo_nas_l}, --input_model {yolo_nas_s,yolo_nas_m,yolo_nas_l}
                        model name (default: yolo_nas_s)
  -imgsz IMG_SIZE [IMG_SIZE ...], --img-size IMG_SIZE [IMG_SIZE ...]
                        image size (default: [640, 640])
  -op OPSET, --opset OPSET
                        opset version (default: 12)
  -n NAME, --name NAME  The name of the model to be saved, none means using the same name as the input
                        model (default: None)
  -o OUTPUT_DIR, --output_dir OUTPUT_DIR
                        Directory for saving files, none means using the same path as the input model
                        (default: None)
  -b, --blob            OAK Blob export (default: False)
  -s, --spatial_detection
                        Inference with depth information (default: False)
  -sh SHAVES, --shaves SHAVES
                        Inference with depth information (default: None)
  -t {docker,blobconverter,local}, --convert_tool {docker,blobconverter,local}
                        Which tool is used to convert, docker: should already have docker
                        (https://docs.docker.com/get-docker/) and docker-py (pip install docker)
                        installed; blobconverter: uses an online server to convert the model and should
                        already have blobconverter (pip install blobconverter); local: use openvino-dev
                        (pip install openvino-dev) and openvino 2022.1 (
                        https://docs.oakchina.cn/en/latest
                        /pages/Advanced/Neural_networks/local_convert_openvino.html#id2) to convert
                        (default: blobconverter)

export_yolo_nas.py :

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import argparse
import json
import time
import warnings
from io import BytesIO
from pathlib import Path

import torch
import torch.nn as nn

warnings.filterwarnings("ignore")

ROOT = Path(__file__).resolve().parent

yolo_nas = [
    "yolo_nas_s",
    "yolo_nas_m",
    "yolo_nas_l",
]


class DetectNAS(nn.Module):
    """YOLO-NAS Detect head for detection models"""

    def __init__(self, old_detect):
        super().__init__()
        self.num_classes = old_detect.num_classes  # number of classes
        self.reg_max = old_detect.reg_max
        self.num_heads = old_detect.num_heads
        self.proj_conv = old_detect.proj_conv

        for i in range(self.num_heads):
            setattr(self, f"head{i + 1}", getattr(old_detect, f"head{i + 1}"))

    def forward(self, feats):
        output = []
        for i, feat in enumerate(feats):
            b, _, h, w = feat.shape
            height_mul_width = h * w
            reg_distri, cls_logit = getattr(self, f"head{i + 1}")(feat)

            reg_dist_reduced = torch.permute(reg_distri.reshape([-1, 4, self.reg_max + 1, height_mul_width]), [0, 2, 3, 1])
            reg_dist_reduced = nn.functional.conv2d(nn.functional.softmax(reg_dist_reduced, dim=1), weight=self.proj_conv).squeeze(1)

            # cls and reg
            pred_scores = cls_logit.sigmoid()
            pred_conf, _ = pred_scores.max(1, keepdim=True)
            pred_bboxes = torch.permute(reg_dist_reduced, [0, 2, 1])
            output.append(torch.cat([pred_bboxes.reshape([-1, 4, h, w]), pred_conf, pred_scores], dim=1))
        return output


def parse_args():
    parser = argparse.ArgumentParser(
        description="Tool for converting Yolov8 models to the blob format used by OAK",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        "-m",
        "-i",
        "-w",
        "--input_model",
        type=str,
        help="model name ",
        default="yolo_nas_s",
        choices=yolo_nas,
    )
    parser.add_argument(
        "-imgsz",
        "--img-size",
        nargs="+",
        type=int,
        default=[640, 640],
        help="image size",
    )  # height, width
    parser.add_argument("-op", "--opset", type=int, default=12, help="opset version")

    parser.add_argument(
        "-n",
        "--name",
        type=str,
        help="The name of the model to be saved, none means using the same name as the input model",
    )
    parser.add_argument(
        "-o",
        "--output_dir",
        type=Path,
        help="Directory for saving files, none means using the same path as the input model",
    )
    parser.add_argument(
        "-b",
        "--blob",
        action="store_true",
        help="OAK Blob export",
    )
    parser.add_argument(
        "-s",
        "--spatial_detection",
        action="store_true",
        help="Inference with depth information",
    )
    parser.add_argument(
        "-sh",
        "--shaves",
        type=int,
        help="Inference with depth information",
    )
    parser.add_argument(
        "-t",
        "--convert_tool",
        type=str,
        help="Which tool is used to convert, docker: should already have docker (https://docs.docker.com/get-docker/) and docker-py (pip install docker) installed; blobconverter: uses an online server to convert the model and should already have blobconverter (pip install blobconverter); local: use openvino-dev (pip install openvino-dev) and openvino 2022.1 ( https://docs.oakchina.cn/en/latest /pages/Advanced/Neural_networks/local_convert_openvino.html#id2) to convert",
        default="blobconverter",
        choices=["docker", "blobconverter", "local"],
    )

    parse_arg = parser.parse_args()

    if parse_arg.name is None:
        parse_arg.name = parse_arg.input_model

    if parse_arg.output_dir is None:
        parse_arg.output_dir = ROOT.joinpath(parse_arg.input_model)

    parse_arg.output_dir = parse_arg.output_dir.resolve().absolute()

    parse_arg.output_dir.mkdir(parents=True, exist_ok=True)

    parse_arg.img_size *= 2 if len(parse_arg.img_size) == 1 else 1  # expand

    if parse_arg.shaves is None:
        parse_arg.shaves = 5 if parse_arg.spatial_detection else 6

    return parse_arg


def export(input_model, img_size, output_model, opset, **kwargs):
    t = time.time()
    from super_gradients.training import models

    # Load PyTorch model
    model = models.get("yolo_nas_s", pretrained_weights="coco")

    labels = model._class_names  # get class names
    labels = labels if isinstance(labels, list) else list(labels.values())

    # check num classes and labels
    assert model.num_classes == len(labels), f"Model class count {model.num_classes} != len(names) {len(labels)}"

    # Replace with the custom Detection Head

    model.heads = DetectNAS(model.heads)

    num_branches = model.heads.num_heads

    # Input
    img = torch.zeros(1, 3, *img_size)

    model.eval()
    model.prep_model_for_conversion(input_size=[1, 3, *img_size])

    y = model(img)  # dry runs

    # ONNX export
    try:
        import onnx

        print()
        print("Starting ONNX export with onnx %s..." % onnx.__version__)
        output_list = ["output%s_yolov6r2" % (i + 1) for i in range(num_branches)]
        with BytesIO() as f:
            torch.onnx.export(
                model,
                img,
                f,
                verbose=False,
                opset_version=opset,
                input_names=["images"],
                output_names=output_list,
            )

            # Checks
            onnx_model = onnx.load_from_string(f.getvalue())  # load onnx model
            onnx.checker.check_model(onnx_model)  # check onnx model

        try:
            import onnxsim

            print("Starting to simplify ONNX...")
            onnx_model, check = onnxsim.simplify(onnx_model)
            assert check, "assert check failed"

        except ImportError:
            print(
                "onnxsim is not found, if you want to simplify the onnx, "
                + "you should install it:\n\t"
                + "pip install -U onnxsim onnxruntime\n"
                + "then use:\n\t"
                + f'python -m onnxsim "{output_model}" "{output_model}"'
            )
        except Exception:
            print("Simplifier failure")

        onnx.save(onnx_model, output_model)
        print("ONNX export success, saved as:\n\t%s" % output_model)

    except Exception:
        print("ONNX export failure")

    # generate anchors and sides
    anchors = []

    # generate masks
    masks = dict()

    print("anchors:\n\t%s" % anchors)
    print("anchor_masks:\n\t%s" % masks)
    export_json = output_model.with_suffix(".json")
    export_json.write_text(
        json.dumps(
            {
                "nn_config": {
                    "output_format": "detection",
                    "NN_family": "YOLO",
                    "input_size": f"{img_size[0]}x{img_size[1]}",
                    "NN_specific_metadata": {
                        "classes": model.num_classes,
                        "coordinates": 4,
                        "anchors": anchors,
                        "anchor_masks": masks,
                        "iou_threshold": 0.3,
                        "confidence_threshold": 0.5,
                    },
                },
                "mappings": {"labels": labels},
            },
            indent=4,
        )
    )
    print("Anchors data export success, saved as:\n\t%s" % export_json)

    # Finish
    print("Export complete (%.2fs).\n" % (time.time() - t))


def convert(convert_tool, output_model, shaves, output_dir, name, **kwargs):
    t = time.time()

    export_dir: Path = output_dir.joinpath(name + "_openvino")
    export_dir.mkdir(parents=True, exist_ok=True)

    export_xml = export_dir.joinpath(name + ".xml")
    export_blob = export_dir.joinpath(name + ".blob")

    if convert_tool == "blobconverter":
        from zipfile import ZIP_LZMA, ZipFile

        import blobconverter

        blob_path = blobconverter.from_onnx(
            model=str(output_model),
            data_type="FP16",
            shaves=shaves,
            use_cache=False,
            version="2022.1",
            output_dir=export_dir,
            optimizer_params=[
                "--scale=255",
                "--reverse_input_channel",
                "--use_new_frontend",
            ],
            download_ir=True,
        )

        with ZipFile(blob_path, "r", ZIP_LZMA) as zip_obj:
            for name in zip_obj.namelist():
                zip_obj.extract(
                    name,
                    output_dir,
                )
        blob_path.unlink()
    elif convert_tool == "docker":
        import docker

        export_dir_in_docker = Path("/io").joinpath(export_dir.name)
        export_xml_in_docker = export_dir_in_docker.joinpath(name + ".xml")
        export_blob_in_docker = export_dir_in_docker.joinpath(name + ".blob")

        client = docker.from_env()
        image = client.images.pull("openvino/ubuntu20_dev", tag="2022.1.0")
        docker_output = client.containers.run(
            image=image.tags[0],
            command=f'bash -c "mo -m {name}.onnx -n {name} -o {export_dir_in_docker} '
            + "--static_shape --reverse_input_channels --scale=255 --use_new_frontend "
            + "&& echo 'MYRIAD_ENABLE_MX_BOOT NO' | tee /tmp/myriad.conf >> /dev/null "
            + "&& /opt/intel/openvino/tools/compile_tool/compile_tool -m "
            + f"{export_xml_in_docker} -o {export_blob_in_docker} -ip U8 -VPU_NUMBER_OF_SHAVES {shaves} "
            + f'-VPU_NUMBER_OF_CMX_SLICES {shaves} -d MYRIAD -c /tmp/myriad.conf"',
            remove=True,
            volumes=[
                f"{output_dir}:/io",
            ],
            working_dir="/io",
        )
        print(docker_output.decode("utf8"))
    else:
        import subprocess as sp

        # OpenVINO export
        print("Starting to export OpenVINO...")
        OpenVINO_cmd = "mo --input_model %s --output_dir %s --data_type FP16 --scale 255 --reverse_input_channel" % (output_model, export_dir)
        try:
            sp.check_output(OpenVINO_cmd, shell=True)
            print("OpenVINO export success, saved as %s" % export_dir)
        except sp.CalledProcessError:
            print("")
            print("OpenVINO export failure!")
            print("By the way, you can try to export OpenVINO use:\n\t%s" % OpenVINO_cmd)

        # OAK Blob export
        print("Then you can try to export blob use:")
        blob_cmd = (
            "echo 'MYRIAD_ENABLE_MX_BOOT ON' | tee /tmp/myriad.conf"
            + "compile_tool -m %s -o %s -ip U8 -d MYRIAD -VPU_NUMBER_OF_SHAVES %s -VPU_NUMBER_OF_CMX_SLICES %s -c /tmp/myriad.conf"
            % (export_xml, export_blob, shaves, shaves)
        )
        print("%s" % blob_cmd)

        print("compile_tool maybe in the path: /opt/intel/openvino/tools/compile_tool/compile_tool, if you install openvino 2022.1 with apt")

    print("Blob file saved as:\n\t%s" % export_blob)
    print("Convert complete (%.2fs).\n" % (time.time() - t))


if __name__ == "__main__":
    args = parse_args()
    print(args)
    output_model = args.output_dir / (args.name + ".onnx")

    export(output_model=output_model, **vars(args))
    if args.blob:
        convert(output_model=output_model, **vars(args))

可以使用 Netron 查看模型结构:
在这里插入图片描述

▌转换

openvino 本地转换

onnx -> openvino

mo 是 openvino_dev 2022.1 中脚本,安装命令为 pip install openvino-dev

mo --input_model yolo_nas_s.onnx --scale 255 --reverse_input_channel

openvino -> blob

<path>/compile_tool -m yolo_nas_s.xml \
-ip U8 -d MYRIAD \
-VPU_NUMBER_OF_SHAVES 6 \
-VPU_NUMBER_OF_CMX_SLICES 6

在线转换

blobconvert 网页 http://blobconverter.luxonis.com/

  • 进入网页,按下图指示操作:
    在这里插入图片描述
  • 修改参数,转换模型:
    在这里插入图片描述
    1. 选择 onnx 模型
    2. 修改 optimizer_params--data_type=FP16 --scale 255 --reverse_input_channel
    3. 修改 shaves6
    4. 转换

blobconverter python 代码

blobconverter.from_onnx(
            "yolo_nas_s.onnx",	
            optimizer_params=[
                "--scale 255",
                "--reverse_input_channel",
            ],
            shaves=6,
        )

blobconvert cli

blobconverter --onnx yolo_nas_s.onnx -sh 6 -o . --optimizer-params "scale=255 --reverse_input_channel"

▌DepthAI 示例

正确解码需要可配置的网络相关参数:

  • setNumClasses – YOLO 检测类别的数量
  • setIouThreshold – iou 阈值
  • setConfidenceThreshold – 置信度阈值,低于该阈值的对象将被过滤掉
# coding=utf-8
import cv2
import depthai as dai
import numpy as np

numClasses = 80
model = dai.OpenVINO.Blob("yolo_nas_s.blob")
dim = next(iter(model.networkInputs.values())).dims
W, H = dim[:2]

output_name, output_tenser = next(iter(model.networkOutputs.items()))
if "yolov6" in output_name:
    numClasses = output_tenser.dims[2] - 5
else:
    numClasses = output_tenser.dims[2] // 3 - 5

labelMap = [
    # "class_1","class_2","..."
    "class_%s" % i
    for i in range(numClasses)
]

# Create pipeline
pipeline = dai.Pipeline()

# Define sources and outputs
camRgb = pipeline.create(dai.node.ColorCamera)
detectionNetwork = pipeline.create(dai.node.YoloDetectionNetwork)
xoutRgb = pipeline.create(dai.node.XLinkOut)
xoutNN = pipeline.create(dai.node.XLinkOut)

xoutRgb.setStreamName("image")
xoutNN.setStreamName("nn")

# Properties
camRgb.setPreviewSize(W, H)
camRgb.setResolution(dai.ColorCameraProperties.SensorResolution.THE_1080_P)
camRgb.setInterleaved(False)
camRgb.setColorOrder(dai.ColorCameraProperties.ColorOrder.BGR)

# Network specific settings
detectionNetwork.setBlob(model)
detectionNetwork.setConfidenceThreshold(0.5)

# Yolo specific parameters
detectionNetwork.setNumClasses(numClasses)
detectionNetwork.setCoordinateSize(4)
detectionNetwork.setAnchors([])
detectionNetwork.setAnchorMasks({})
detectionNetwork.setIouThreshold(0.5)

# Linking
camRgb.preview.link(detectionNetwork.input)
camRgb.preview.link(xoutRgb.input)
detectionNetwork.out.link(xoutNN.input)

# Connect to device and start pipeline
with dai.Device(pipeline) as device:
    # Output queues will be used to get the rgb frames and nn data from the outputs defined above
    imageQueue = device.getOutputQueue(name="image", maxSize=4, blocking=False)
    detectQueue = device.getOutputQueue(name="nn", maxSize=4, blocking=False)

    frame = None
    detections = []

    # nn data, being the bounding box locations, are in <0..1> range - they need to be normalized with frame width/height
    def frameNorm(frame, bbox):
        normVals = np.full(len(bbox), frame.shape[0])
        normVals[::2] = frame.shape[1]
        return (np.clip(np.array(bbox), 0, 1) * normVals).astype(int)

    def drawText(frame, text, org, color=(255, 255, 255), thickness=1):
        cv2.putText(
            frame, text, org, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), thickness + 3, cv2.LINE_AA
        )
        cv2.putText(
            frame, text, org, cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, thickness, cv2.LINE_AA
        )

    def drawRect(frame, topLeft, bottomRight, color=(255, 255, 255), thickness=1):
        cv2.rectangle(frame, topLeft, bottomRight, (0, 0, 0), thickness + 3)
        cv2.rectangle(frame, topLeft, bottomRight, color, thickness)

    def displayFrame(name, frame):
        color = (128, 128, 128)
        for detection in detections:
            bbox = frameNorm(
                frame, (detection.xmin, detection.ymin, detection.xmax, detection.ymax)
            )
            drawText(
                frame=frame,
                text=labelMap[detection.label],
                org=(bbox[0] + 10, bbox[1] + 20),
            )
            drawText(
                frame=frame,
                text=f"{detection.confidence:.2%}",
                org=(bbox[0] + 10, bbox[1] + 35),
            )
            drawRect(
                frame=frame,
                topLeft=(bbox[0], bbox[1]),
                bottomRight=(bbox[2], bbox[3]),
                color=color,
            )
        # Show the frame
        cv2.imshow(name, frame)

    while True:
        imageQueueData = imageQueue.tryGet()
        detectQueueData = detectQueue.tryGet()

        if imageQueueData is not None:
            frame = imageQueueData.getCvFrame()

        if detectQueueData is not None:
            detections = detectQueueData.detections

        if frame is not None:
            displayFrame("rgb", frame)

        if cv2.waitKey(1) == ord("q"):
            break

▌参考资料

https://www.oakchina.cn/tag/yolo/
https://docs.oakchina.cn/en/latest/
https://www.oakchina.cn/selection-guide/


OAK中国
| OpenCV AI Kit在中国区的官方代理商和技术服务商
| 追踪AI技术和产品新动态

戳「+关注」获取最新资讯↗↗

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

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

相关文章

数据库迁移同步 | 两地三中心到异地双活演变及关键技术探讨

两地三中心和异地多活都是分布式系统的关键技术&#xff0c;用于保证系统的高可用性和容错性。其中最关键的技术无疑是数据同步、同步防环和数据冲突解决。 异地容灾 & 两地三中心 两地三中心架构是一种分布式系统的架构模式&#xff0c;用于保证系统的高可用性和容错性。…

pom文件的project标签报错java.lang.OutOfMemoryError: GC overhead limit exceeded

1、pom文件的project标签报错java.lang.OutOfMemoryError: GC overhead limit exceeded&#xff0c;如何解决&#xff1f; 只需修改idea配置 调大内存&#xff0c;即可解决

git之gitk命令介绍

Gitk 是 Git 提供的一个 GUI 工具&#xff0c;可作为git图形化客户端使用。安装 Git 的时候会自动安装 Gitk 工具。打开git bash&#xff0c;输入 gitk 命令即可打开gitk工具。 Gitk 的主界面主要包含五个部分&#xff1a; 主菜单栏显示区提交信息显示区&#xff0c;显示提交…

【Nginx基础篇】Linux虚拟机安装nginx

目录 一、版本区别 二、编译安装 三、启动nginx 关于防火墙 四、安装成系统服务 一、版本区别 常用版本分为四大阵营 Nginx开源版 http://nginx.org/ Nginx plus 商业版 https://www.nginx.com openresty http://openresty.org/cn/ Tengine http://tengine.taobao.org/ …

BetaFlight统一硬件AOCODARC H7DUAL配置文件讨论

BetaFlight统一硬件AOCODARC H7DUAL配置文件讨论 1. 源由2. Review配置3. 分析整理3.1 生产商信息3.2 磁力计3.3 气压计3.4 陀螺仪3.5 串口RxTx3.6 板载Flash3.7 模拟OSD MAX74563.8 PPM接收机3.9 伺服器3.10 LED灯带3.11 蜂鸣器3.12 电机 X83.13 ADC(电压/电流/RSSI信号强度/空…

(六)Spring源码阅读:invokeBeanFactoryPostProcessors方法

一、概述 invokeBeanFactoryPostProcessors的执行顺序大致如下&#xff0c;先执行子类BeanDefinitionRegistryPostProcessor再执行父类BeanFactoryPostProcessor。而对于同一个类的执行顺序是先执行外部的集合再到子集&#xff0c;之后再到父集。更小维度执行的顺序按照order注…

私人图片云盘 - 本地快速搭建简单的EasyImage图床并实现公网访问

文章目录 1.前言2. EasyImage网站搭建2.1. EasyImage下载和安装2.2. EasyImage网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2 Cpolar内网穿透本地设置 4. 公网访问测试5. 结语 1.前言 一个好的图床&#xff0c;是网站或者文章图片能稳定显示的关键&…

学习网络安全如何避免成为脚本小子或者安全工具人

想要避免成为工具人或者脚本小子&#xff0c;你需要注意学习初期和工作初期的选择。 首先&#xff0c;在学习初期&#xff0c;打好基础最重要&#xff0c;避免成为脚本小子。 你可能发现很多人仅仅会写个Python然后会用工具&#xff0c;积累一点经验就可以找到一份还不错的工…

传奇人物《周兴和》书连载之67 不辱神圣的使命

不辱神圣的使命 这里&#xff0c;先前还是一个十分神秘的地方。 外人和车辆要想进入这片区域&#xff0c;那是绝对不允许的。这片区域隐于群山之中&#xff0c;且戒备森严&#xff0c;外人若想进入&#xff0c;那是要经过好几道政治审查和随身检查的。近年来&#xff0c;随着…

外卖项目优化-02-mysql主从复制、读写分离(shardingJdbc)、Nginx(反向代理,负载均衡)

文章目录 瑞吉外卖项目优化-Day02课程内容前言1. MySQL主从复制1.1 介绍1.2 搭建1.2.1 准备工作1.2.2 主库配置1.2.3 从库配置 1.3 测试 2. 读写分离案例 (shardingJdbc)2.1 背景介绍2.2 ShardingJDBC介绍2.3 数据库环境2.4 初始工程导入2.5 读写分离配置2.6 测试 3. 项目实现读…

GPT-4等大语言模型对教育的未来意味着什么?

‍ ‍ shadow Mixlab这些年举办了非常多的活动和workshop&#xff0c;都带有很强的教育属性。今天我抽空学习了可汗学院的《AI-for-Education》课程&#xff0c;非常有启发。我记录了精华内容&#xff0c;分享给大家。 课程地址&#xff1a; www.khanacademy.org/college-caree…

8086CPU汇编环境安装

之前是使用XP虚拟机中的DOS窗口&#xff0c;后来在B站上逛到的视频【《汇编语言》速成指南(全程敲代码)】中介绍了DOSBox这个软件&#xff0c;觉得很好用&#xff0c;使用方式记录在这里。 软件下载好是这样&#xff1a; 一、安装BOX程序 双击exe安装 &#xff0c;默认下一步…

看看好不好用,使用 Netty+SpringBoot 打造的 TCP 长连接通讯方案

项目背景 正文 一、项目架构 二、项目模块 三、业务流程 四、代码详解 五、测试 六、源码 后记 项目背景 最近公司某物联网项目需要使用socket长连接进行消息通讯。本猿为了解决这个问题&#xff0c;经过长时间的研究、调试和测试&#xff0c;最终找到了一个可行的方…

基于ASAM ODS标准的试验数字化平台-WDP

一 现状 随着现代测控技术的提高&#xff0c;数据结构变得越来越复杂多样&#xff0c;测量的数据量也在日益增大。此外&#xff0c;由于试验条件的限制&#xff0c;大多数企业的数据管理方式主要是通过各类电子文档将试验数据保存在每个工程师的移动电脑中&#xff0c;再进行汇…

【技术选型】Elasticsearch 和Solr那个香?

我们为什么在这里&#xff1f;我存在的目的是什么&#xff1f;我应该运动还是休息并节省能量&#xff1f;早起上班或晚起并整夜工作&#xff1f;我应该将炸薯条和番茄酱或蛋黄酱一起吃吗&#xff1f; 这些都是古老的问题&#xff0c;可能有也可能没有答案。其中一些是非常困难或…

值得关注!正在引领行业变革的15家AI明星创业公司

夕小瑶科技说 原创 作者 | 小戏、iven 星星之火&#xff0c;可以燎原。 在大模型横空出世的这个疯狂的春天&#xff0c;一场关于 AI 产品的革命也正在席卷全球。这边是大公司一个接一个模型搞军备竞赛&#xff0c;那边是各路豪强纷纷下场创业招兵买马。那么&#xff0c;除了咱…

PAT A1032 Sharing

1032 Sharing 分数 25 作者 CHEN, Yue 单位 浙江大学 To store English words, one method is to use linked lists and store a word letter by letter. To save some space, we may let the words share the same sublist if they share the same suffix. For example, l…

FreeRTOS:任务挂起和恢复

目录 一、任务挂起和恢复定义二、任务挂起2.1含义2.2任务挂起内部实现2.3函数vTaskSuspend() 三、任务恢复3.1含义3.2任务恢复内部实现3.3函数vTaskResume() 四、任务挂起和恢复实验4.1实验要求4.2程序代码 一、任务挂起和恢复定义 有时候我们需要暂停某个任务的运行&#xff…

代码随想录算法训练营第三十二天 | 利润题、覆盖范围题

122.买卖股票的最佳时机II 文档讲解&#xff1a;代码随想录 (programmercarl.com) 视频讲解&#xff1a;贪心算法也能解决股票问题&#xff01;LeetCode&#xff1a;122.买卖股票最佳时机II_哔哩哔哩_bilibili 状态&#xff1a;根本做不出来&#xff0c;思路太巧了。 思路 想获…

浅谈Java、PHP、C++编程的优缺点

Java 、PHP、C 编程语言都是非常流行的编程语言&#xff0c;在开发、Web 开发、移动应用开发等领域都有广泛的应用。本文将从以下几个方面分析 Java、PHP、C 编程语言的优缺点。 一、Java 编程语言的优缺点 优点 &#xff08;1&#xff09;具有跨平台特性&#xff0c;能够在不…