基于存内计算架构的模型部署与映射优化

news2024/11/15 12:18:26

先进计算大赛背景:

‘’存内计算”架构通过消除存储与计算单元间的物理距离,突破传统冯·诺依曼架构的限制,自2016年起受到广泛关注,被视为国产算力发展的关键技术。 ​ 在存内计算架构中,权重布局对提高存算单元利用率和计算效率至关重要,是编译阶段优化的重点。优化算法的效率、阵列面积利用率和计算效率是神经网络在存内计算芯片上部署的关键指标。简而言之,"存内计算"技术通过优化,权重布局,提升了芯片性能和资源利用效率。

存算一体技术要点:

存算一体被认为是一种新型计算架构,与经典的冯诺依曼架构不同,存储器 本身即可进行计算,将存储单元和计算单元合为一体,省去了计算过程中数据搬 运环节,消除了由于数据搬运带来的功耗和延迟,从而进一步提升计算能效。

以知存科技的模拟存算计算方案为例,,首先将被乘矩阵的参数提 前存入存算单元,然后将乘数向量输入,在水平方向上,乘数在存算单元中完成 与被乘数的乘法操作,在垂直方向上,每个存算单元的乘法结果累加,最后得到 输出向量。

之所以以矩阵计算为例,是因为矩阵对于机器学习系统而言极为关键,它为数据表示提供了一种既简单又高效的方法。举例来说,输入数据(如图像里的像素集合)或者模型内部不同层之间的运行机制均能够借助矩阵来表示。所以,矩阵相乘运算在深度学习模型的总计算量当中占据着相当大的比重。实际上,在诸多当下流行的Transformer模型,如BERT、CLIP以及ChatGPT中,矩阵乘法的运行时长大约占其总运行时长的45 - 60%。矩阵乘法在卷积运算的计算过程里起着重要的作用,而卷积运算又是大多数计算机视觉模型的基础,也是许多高性能计算应用的核心部分。

这里我们使用的create函数如下:

def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None):
    from pathlib import Path
​
    from models.common import AutoShape, DetectMultiBackend
    from models.experimental import attempt_load
    from models.yolo import ClassificationModel, DetectionModel, SegmentationModel
    from utils.downloads import attempt_download
    from utils.general import LOGGER, ROOT, check_requirements, intersect_dicts, logging
    from utils.torch_utils import select_device
​
    if not verbose:
        LOGGER.setLevel(logging.WARNING)
    check_requirements(ROOT / "requirements.txt", exclude=("opencv-python", "tensorboard", "thop"))
    name = Path(name)
    path = name.with_suffix(".pt") if name.suffix == "" and not name.is_dir() else name  
    try:
        device = select_device(device)
        if pretrained and channels == 3 and classes == 80:
            try:
                model = DetectMultiBackend(path, device=device, fuse=autoshape)  
                if autoshape:
                    if model.pt and isinstance(model.model, ClassificationModel):
                        LOGGER.warning(
                            "WARNING ⚠️ YOLOv3 ClassificationModel is not yet AutoShape compatible. "
                            "You must pass torch tensors in BCHW to this model, i.e. shape(1,3,224,224)."
                        )
                    elif model.pt and isinstance(model.model, SegmentationModel):
                        LOGGER.warning(
                            "WARNING ⚠️ YOLOv3 SegmentationModel is not yet AutoShape compatible. "
                            "You will not be able to run inference with this model."
                        )
                    else:
                        model = AutoShape(model)  # for file/URI/PIL/cv2/np inputs and NMS
            except Exception:
                model = attempt_load(path, device=device, fuse=False)  
        else:
            cfg = list((Path(__file__).parent / "models").rglob(f"{path.stem}.yaml"))[0]  
            model = DetectionModel(cfg, channels, classes)  # create model
            if pretrained:
                ckpt = torch.load(attempt_download(path), map_location=device)  # load
                csd = ckpt["model"].float().state_dict()  # checkpoint state_dict as FP32
                csd = intersect_dicts(csd, model.state_dict(), exclude=["anchors"])  
                model.load_state_dict(csd, strict=False)  
                if len(ckpt["model"].names) == classes:
                    model.names = ckpt["model"].names 
        if not verbose:
            LOGGER.setLevel(logging.INFO)  # reset to default
        return model.to(device)
​
    except Exception as e:
        help_url = "https://docs.ultralytics.com/yolov5/tutorials/pytorch_hub_model_loading"
        s = f"{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help."
        raise Exception(s) from e

除此之外,我们还要用到基于存算一体的深度学习编译工具链,他和传统的编译器可大有不同,传统编译器是一种能够把高级编程语言转换为低级目标语言的程序,其编译流程可划分为前端和后端这两个部分。在编译过程中,前端负责解析高级语言,进而生成抽象语法树与中间表示;后端则负责生成目标代码。 深度学习编译器与传统编译器类似,是一种用于将深度学习神经网络模型部署到硬件平台的工具。它处在深度学习框架与硬件设备之间,把深度学习框架中所描述的模型定义当作输入内容,然后在各类深度学习硬件上生成高效的代码实现并将其作为输出结果。它是连接软硬件的桥梁,有着重要意义。而我们的作品就是运用了次深度学习编译工具链。下图为深度学习编译工具链常用设计框架。

witin_mapper是知存科技自研的用于神经网络映射的编译软件栈,可以将量化后的神经网络模型映射到WTM2101 MPU加速器上,是一种包括RiscV和MPU的完整解决方案,可以完成算子和图级别的转换和优化,将预训练权重编排到存算阵列中,并针对网络结构和算子给出存算优化方案,同时将不适合MPU运算的算子调度到CPU上运算,实现整网的调度,让神经网络开发人员高效快捷的将训练好的算法运行在WTM2101芯片上,极大缩短模型移植的开发周期并提高算法开发的效率。

Links : https://github.com/witmem/Witmem-Toolchain-WTM2101


可用工具:

在最开始我们做了模型准备,这个是官方提供的,然后通过官网下载模型可视化工具Netron软件。为后续工作做准备。紧接着我们获取模型中数据依赖关系以及权重矩阵块参数,这个过程总体来说不难,但是由于个人原因,在这里花费了很多精力。然后我们对应onnx文件的权重矩阵块组信息以及矩阵块之间的数据处理先后关系。到这里,一大步就已经跨过去了。

接下来,开始进行编译映射工作。读取了上面输出的结果,用其实现紧密排布如下图,

后面输出结果,使用存算阵列情况与各个阵列内的排布情况,如下图:

  • core_id:“空矩形”的序号

  • index:环节一中解析得到的权重矩阵的数据依赖顺序

  • w_clo_start:权重矩阵的左上角在“空矩形”中的列方向位置

  • w_row_start:权重矩阵的左上角在“空矩形”中的行方向位置


配置验证:

对于这一步,我们团队主要测试存算阵列的执行效率,排布的合理性,比如是否超出存算阵列的范围,是否存在矩阵块面积重叠的情况,以及存算阵列的面积利用率。

下面的run函数是我们的键盘手提供的,它能够对多种输入源进行处理,然后根据设定的参数进行推理、后处理,并将结果进行保存或显示。

@smart_inference_mode()
def run(
    weights=ROOT / "yolov5s-cls.pt",  # model.pt path(s)
    source=ROOT / "data/images",  # file/dir/URL/glob/screen/0(webcam)
    data=ROOT / "data/coco128.yaml",  # dataset.yaml path
    imgsz=(224, 224),  # inference size (height, width)
    device="",  # cuda device, i.e. 0 or 0,1,2,3 or cpu
    view_img=False,  # show results
    save_txt=False,  # save results to *.txt
    nosave=False,  # do not save images/videos
    augment=False,  # augmented inference
    visualize=False,  # visualize features
    update=False,  # update all models
    project=ROOT / "runs/predict-cls",  # save results to project/name
    name="exp",  # save results to project/name
    exist_ok=False,  # existing project/name ok, do not increment
    half=False,  # use FP16 half-precision inference
    dnn=False,  # use OpenCV DNN for ONNX inference
    vid_stride=1,  # video frame-rate stride
):
    """Performs YOLOv3 classification inference on various input sources and saves or displays results."""
    source = str(source)
    save_img = not nosave and not source.endswith(".txt")  # save inference images
    is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)
    is_url = source.lower().startswith(("rtsp://", "rtmp://", "http://", "https://"))
    webcam = source.isnumeric() or source.endswith(".streams") or (is_url and not is_file)
    screenshot = source.lower().startswith("screen")
    if is_url and is_file:
        source = check_file(source)  # download
​
    # Directories
    save_dir = increment_path(Path(project) / name, exist_ok=exist_ok)  # increment run
    (save_dir / "labels" if save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir
​
    # Load model
    device = select_device(device)
    model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half)
    stride, names, pt = model.stride, model.names, model.pt
    imgsz = check_img_size(imgsz, s=stride)  # check image size
​
    # Dataloader
    bs = 1  # batch_size
    if webcam:
        view_img = check_imshow(warn=True)
        dataset = LoadStreams(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]), vid_stride=vid_stride)
        bs = len(dataset)
    elif screenshot:
        dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt)
    else:
        dataset = LoadImages(source, img_size=imgsz, transforms=classify_transforms(imgsz[0]), vid_stride=vid_stride)
    vid_path, vid_writer = [None] * bs, [None] * bs
​
    # Run inference
    model.warmup(imgsz=(1 if pt else bs, 3, *imgsz))  # warmup
    seen, windows, dt = 0, [], (Profile(), Profile(), Profile())
    for path, im, im0s, vid_cap, s in dataset:
        with dt[0]:
            im = torch.Tensor(im).to(model.device)
            im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32
            if len(im.shape) == 3:
                im = im[None]  # expand for batch dim
​
        # Inference
        with dt[1]:
            results = model(im)
​
        # Post-process
        with dt[2]:
            pred = F.softmax(results, dim=1)  # probabilities
​
        # Process predictions
        for i, prob in enumerate(pred):  # per image
            seen += 1
            if webcam:  # batch_size >= 1
                p, im0, frame = path[i], im0s[i].copy(), dataset.count
                s += f"{i}: "
            else:
                p, im0, frame = path, im0s.copy(), getattr(dataset, "frame", 0)
​
            p = Path(p)  # to Path
            save_path = str(save_dir / p.name)  # im.jpg
            txt_path = str(save_dir / "labels" / p.stem) + ("" if dataset.mode == "image" else f"_{frame}")  # im.txt
​
            s += "{:g}x{:g} ".format(*im.shape[2:])  # print string
            annotator = Annotator(im0, example=str(names), pil=True)
​
            # Print results
            top5i = prob.argsort(0, descending=True)[:5].tolist()  # top 5 indices
            s += f"{', '.join(f'{names[j]} {prob[j]:.2f}' for j in top5i)}, "
​
            # Write results
            text = "\n".join(f"{prob[j]:.2f} {names[j]}" for j in top5i)
            if save_img or view_img:  # Add bbox to image
                annotator.text([32, 32], text, txt_color=(255, 255, 255))
            if save_txt:  # Write to file
                with open(f"{txt_path}.txt", "a") as f:
                    f.write(text + "\n")
​
            # Stream results
            im0 = annotator.result()
            if view_img:
                if platform.system() == "Linux" and p not in windows:
                    windows.append(p)
                    cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO)  # allow window resize (Linux)
                    cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0])
                cv2.imshow(str(p), im0)
                cv2.waitKey(1)  # 1 millisecond
​
            # Save results (image with detections)
            if save_img:
                if dataset.mode == "image":
                    cv2.imwrite(save_path, im0)
                else:  # 'video' or 'stream'
                    if vid_path[i] != save_path:  # new video
                        vid_path[i] = save_path
                        if isinstance(vid_writer[i], cv2.VideoWriter):
                            vid_writer[i].release()  # release previous video writer
                        if vid_cap:  # video
                            fps = vid_cap.get(cv2.CAP_PROP_FPS)
                            w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
                            h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                        else:  # stream
                            fps, w, h = 30, im0.shape[1], im0.shape[0]
                        save_path = str(Path(save_path).with_suffix(".mp4"))  # force *.mp4 suffix on results videos
                        vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h))
                    vid_writer[i].write(im0)
​
        # Print time (inference-only)
        LOGGER.info(f"{s}{dt[1].dt * 1E3:.1f}ms")
​
    # Print results
    t = tuple(x.t / seen * 1e3 for x in dt)  # speeds per image
    LOGGER.info(f"Speed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)}" % t)
    if save_txt or save_img:
        s = f"\n{len(list(save_dir.glob('labels/*.txt')))} labels saved to {save_dir / 'labels'}" if save_txt else ""
        LOGGER.info(f"Results saved to {colorstr('bold', save_dir)}{s}")
    if update:
        strip_optimizer(weights[0])  # update model (to fix SourceChangeWarning)

通过以上的工作,在最后分析了权重矩阵的计算依赖关系。到这里我们的作品就差不多了。

存内计算开发者社区:存内计算开发者社区-CSDN社区云

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

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

相关文章

VBA技术资料MF198:禁用下拉拖放

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…

c++ day01

格式化输入 #include <iostream> #include<iomanip> using namespace std;int main() {double num1090.123456;cout<<"num"<<num<<endl;cout<<oct<<"num"<<num<<endl;cout<<hex<<&qu…

【C#】内存的使用和释放

在 C# 中&#xff0c;内存管理主要是由 .NET 的垃圾回收器&#xff08;Garbage Collector, GC&#xff09;自动处理的。然而&#xff0c;了解如何正确地使用和释放内存对于编写高效且可靠的代码非常重要。以下是一些关键点和最佳实践&#xff1a; 1. 内存分配 托管资源&#x…

如何查询论文的SCI检索号?

一、登录Web of Science 不要自己登录&#xff0c;需要选择机构为CHINA CERNET Federation&#xff0c;否则无法查询文章。 然后转到机构&#xff0c;选择对应的大学。 更具对应文章名查询文献。 二、查询文献名

python基础知识(六)--字典遍历、公共运算符、公共方法、函数、变量分类、参数分类、拆包、引用

字典遍历方法 函数名含义keys()以列表的形式&#xff0c;返回一个字典所有的键。values()以列表的形式&#xff0c;返回一个字典所有的值。items()返回由键值组成的序列&#xff0c;主要应用于遍历字典。 公共运算符 运算符描述支持的容器类型合并字符串、列表、元组*复制字符…

linux入门到实操-9 linux文件操作命令:创建文件、复制文件或文件夹、删除和移动文件、多种查看文件的方法

教程来源&#xff1a;B站视频BV1WY4y1H7d3 3天搞定Linux&#xff0c;1天搞定Shell&#xff0c;清华学神带你通关_哔哩哔哩_bilibili 整理汇总的课程内容笔记和课程资料&#xff08;包含课程同版本linux系统文件等内容&#xff09;&#xff0c;供大家学习交流下载&#xff1a;…

PHP限定post提交数据的次数

PHP限定post提交数据的次数。 在PHP中&#xff0c;你可以通过记录IP地址的提交次数并在会话或数据库中存储这些信息来实现这个需求。以下是一个简单的PHP示例&#xff0c;它使用会话来跟踪IP地址的提交次数。 <?php session_start(); // 获取用户的IP地址 $ip_address $…

迁移学习+多模态融合,小白轻松发一区!创新性拉满!

多模态研究如今愈发火热&#xff0c;已成为各大顶级会议的投稿热门。今天&#xff0c;我为大家提供一个多模态的创新思路&#xff1a;迁移学习与多模态融合。 迁移学习多模态融合方向的优势 1.提升模型性能&#xff1a;综合更多维度优势&#xff0c;跨模态互补 2.快速适应新…

计算机网络 --- 初识协议

序言 上一篇文章中 &#xff08;&#x1f449;点击查看&#xff09;&#xff0c;我们简单的了解了怎么寻找目标计算机&#xff0c;需要通过交换机&#xff0c;路由器等设备跨越多个网络来不断的转发我们需要传输的数据&#xff0c;直至到达目标计算机。  那我们设备之间数据是…

挖矿病毒排查演示

1、上传病毒文件到/opt目录中 2、把压缩文件名修改成virus.zip 3、检查一下/etc/passwd ​ root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:…

GeoGebra 與數學探索 3 GeoGebra 在微積分的探索與動態演示

Goal: GeoGebra 除了可以輕鬆的讓我們以即時動態反饋圖形的方式模擬探索幾何的問題, 或是幫我們驗證答案, 也可以進行數論、微積分、矩陣等等各方面的探索, 在問題尺度不大又需要即時以圖像視覺呈現探索過程的情況下, GeoGebra 其實優於以寫程式的方式進行探索. “Talk is che…

unordered_map/set(底层实现)——C++

目录 前言&#xff1a; 1.开散列 1. 开散列概念 2. 开散列实现 2.1哈希链表结构体的定义 2.2哈希表类即私有成员变量 2.3哈希表的初始化 2.4迭代器的实现 1.迭代器的结构 2.构造 3.* 4.-> 5. 6.&#xff01; 2.5begin和end 2.6插入 2.7Find查找 2.8erase删除 3.unordered_ma…

mybatisplus中id生成策略

使用Tableld(value,type) 1.typeIdType.AUTO自增主键 2.typeIdType.ASSIGN,雪花算法生成 mybatisplus id生成策略全局配置 配置表前缀以及id生成策略 mybatis-plus:global-config:db-config:id-type: autotable-prefix: :t_

热点|创邻图查询范式引爆LDBC TUC2024

2024年8月30日至31日&#xff0c;创邻科技Galaxybase团队联合蚂蚁集团TuGraph团队、阿里巴巴GraphScope团队共同主办第18届LDBC TUC会议。在本次会议中&#xff0c;来自全球图数据库领域的学者和技术专家做了很多精彩的分享&#xff0c;共同探讨图技术的最新进展。创邻科技Gala…

EC Shop安装指南 [ Apache PHP Mysql ]

这个是软件测试课上老师布置的一个作业&#xff0c;期间老师也出现了不少错误&#xff0c;所以还是有必要记录一下吧&#xff0c;凑一篇文章 主要是老师的文档以及自己的一些尝试记录&#xff0c;试错记录&#xff0c;解决方案等 主要介绍了Apache的安装&#xff0c;MySQL的安…

weblogic CVE-2020-14882 靶场攻略

漏洞描述 32 CVE-2020-14882 允许远程⽤户绕过管理员控制台组件中的身份验证。 CVE-2020-14883 允许经过身份验证的⽤户在管理员控制台组件上执⾏任何命令。 使⽤这两个漏洞链&#xff0c;未经身份验证的远程攻击者可以通过 HTTP 在 Oracle WebLogic 服务器上执⾏任意命令并…

基于协同过滤算法+PHP的新闻推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤算法PHPMySQL的新…

基于Java的房地产在线营销管理系统研究与实现

目录 前言 功能设计 系统实现 获取源码 博主主页&#xff1a;百成Java 往期系列&#xff1a;Spring Boot、SSM、JavaWeb、python、小程序 前言 随着信息技术的迅猛发展&#xff0c;互联网已经渗透到我们生活的方方面面&#xff0c;为各行各业带来了前所未有的变革。房地产…

条件编译代码记录

#include <iostream>// 基类模板 template<typename T> class Base { public:void func() {std::cout << "Base function" << std::endl;} };// 特化的子类 template<typename T> class Derived : public Base<T> { public:void…

8585 栈的应用——进制转换

### 思路 1. **初始化栈**&#xff1a;创建一个空栈用于存储转换后的八进制数的每一位。 2. **十进制转八进制**&#xff1a;将十进制数不断除以8&#xff0c;并将余数依次入栈&#xff0c;直到商为0。 3. **输出八进制数**&#xff1a;将栈中的元素依次出栈并打印&#xff0c;…