[UVM源代码研究] 聊聊UVM中的callback机制

news2024/11/14 18:04:27

1. callback机制是什么?

以最高效的方式完成芯片验证,一直以来都是验证人员的首要目标,那么最直接的方式就是环境的移植和重用,一个优秀的验证工程师,在开发环境的过程中,一定会考虑环境的继承和重用。
继承(extend)这个我们在实际工作中经常使用,主要是为了在原有功能的基础上扩展一些新的功能,比如我们的testcase一般都是从一个base_test继承而来的,如果继续将testcase继续细分,又会产生一些中间的function_base_test,主要目的是为了将一些公共的功能属性抽取出来提炼成公共的变量或方法供所有相关的testcase继承使用,这便是“继承”在环境复用时的主要用途。
除了继承,UVM还提供了一个callback机制,他的主要应用场景在于环境开发者预知部分功能在将来会存在多种使用场景,需要在环境中预留一个可扩展的hook,相当于针对部分功能函数或任务进行override,这不同于继承,虽然继承的时候也可以override其中的virtual方法,但是比起“大动干戈”对整个类继续继承扩展,如果有那么一种机制能够只是对局部的方法进行精准扩展,那么代码的可读性和灵活度将大大提升,callback机制就是用来完成这种精准扩展的。
callback机制比起上面的继承覆盖来说,区别主要在于环境开发者为环境使用者提前预留好了hook供使用者根据使用的需要进行扩展,这就要求环境开发者对环境的使用场景进行提前布局,需要有一些提前预见性。比起继承覆盖来说,callback机制更像是对简单粗暴的继承覆盖一刀切所进行的一次微创手术,环境开发者前期需要多付出一些effort,后期就可以一劳永逸了。
可以举几个例子说明下,什么场景下适合用callback机制,什么场景下只能用继承覆盖进行扩展。
先说一个典型的callback机制的应用场景。
我们在写driver的时候的run_phase流程一般是这样的:

virtual task run_phase(uvm_phase phase);
    ...
    while(1) begin
       ...
       seq_item_port.get_next_item(tr);
       ...
       drive_tr(tr);
       ...
       seq_item_port.item_done();
    end
    ...
endtask

环境开发者在开发这么个driver的时候应该考虑的问题就是当收到包之后到发包之前,是不是要预留给使用者这么一个功能,就是对包进行一些预处理,例如注错功能,这样后期一旦需要进行注错时只需要把这个预处理的注错功能进行定制化的扩展就可以了,否者的话就只能从driver继承一个新的driver对run_phase进行override了,所以环境开发者可以在driver_tr(tr)调用之前添加一个pre_drive()的函数对包进行预处理,这个pre_drive()函数体的具体实现留给环境使用者去完成,这便是callback机制的典型的应用场景。
再看一个只能用继承覆盖而不能用callback机制的典型场景,还是以driver为例,例如我们需要开发一个DDR2的driver,开发完成了我们可能还不知道未来的DDR3、DDR4…具体长什么样,所以我们无法提前预留好hook给未来新的driver功能做扩展,但是通常我们知道的是一般这种产品的迭代一般都是向下兼容的,也就是说ddr3一定是兼容ddr2的全部功能,所以说在ddr2上能跑pass的case在ddr3上一定也是可以跑pass的,未来需要在原有ddr2的环境上升级到ddr3时,我们就需要将ddr2_driver继承产生ddr3_driver,然后重写其中的run_phase()乃至driver_tr()一些列的方法,使用factory机制将ddr3_driver去override ddr2_driver再把所有ddr2环境中的case全部跑一遍。对于这种使用场景就只能用继承覆盖,而不能用callback机制,callback机制最大的特点就是他的预见性,即对类中的局部方法的精准覆盖。
callback的概念有点类似于c语言的接口,如果想要实现某个功能,如果c语言有接口函数,那么直接调用接口,改写接口函数而实现用户需求的功能。而uvm的callback也是类似的思想,环境的开发者在一些组件中预留好接口,而在开发的过程中将这些接口函数嵌入到环境开发里,这样如果有用户想要实现满足自身需求的功能,只需要改写这个接口函数,即可达到自己的验证目的。

2. callback机制如何实现?

真如上文提到的,callback机制是环境开发者给环境使用者预留的hook,方便环境使用者对环境进行定制化的扩展。这就决定了callback机制的实现需要环境开发者和使用者共同换成,我们在讨论callback机制的实现步骤的时候就需要明确分工。
使用callback的简单步骤如下:

  • 定义一个uvm_callback空壳类,并定义相关的callback方法(声明为virtual以便扩展覆盖,后期也可以根据实际需要扩充更多的callback方法);环境开发者
  • 在UVM组件中注册上面定义的callback空壳类,并在组件代码恰当的位置内嵌callback方法;环境开发者
  • 从UVM callback空壳类扩展用户自定义的uvm_callback类,并根据实际需求重写其中的callback方法;环境使用者
  • 在验证环境中创建并添加uvm_callback实例。环境使用者

3. callback机制示例

还是以driver为例,先看看环境开发者需要做什么。图1是driver文件中的代码示例。
在这里插入图片描述
图1 driver文件代码示例

代码中的3-6行定义的pkt_process_callback类就是上文所述的环境开发者定义的空壳callback类,预留给环境使用者扩展的方法是pkt_pre_trans()任务,目的是让环境使用者根据自己的需要在发包之前对包做一些定制化的处理。这样便完成了步骤1的工作。
my_driver类中callback相关的代码是15行和33行,完成了callback类的注册以及callback方法的调用,这两个宏我们在后面的源代码分析时会具体介绍都做了什么,这里先理解成完成了步骤2的callback空壳类的注册以及callback方法的内嵌。
如此一来,callback机制环境开发者的相关工作就完成了,下面看环境使用者所需完成工作的代码示例,如图2所示。
在这里插入图片描述
图2 testcase文件示例

代码4-11行完成了从环境开发者定义的空壳callback类继承而来的环境开发者自定义的callback类,其中对方法pkt_process_callback()进行了重写,这里有个小的知识点,那就是扩展类中的方法pkt_process_callback并没有使用virtual进行修饰,这是因为SystemVerilog的语法规定了virtual方法在扩展类中被自动继承virtual属性,所以在扩展类里原有的virtual修饰的方法可以省去virtual修饰符。如此便完成了步骤3的工作。
代码的第25行完成了callback类的创建,这里创建必须使用factory机制的type_id::create()方法进行创建,方便后续对callback类的扩展override。31行将callback类添加到了相应的callback池子里了,后续源代码分析会对add()函数完成的具体工作和callback实现机制进行具体的分析。这样便完成了步骤4的工作。
经过上述4个步骤,我们便实现了对my_driver功能的扩展,在my_tc里发包的时候就会对包进行预处理,将包的payload强行改为32’h555aaa并添加打印信息,实现了最简单的一个callback机制的应用。

4. callback机制源代码分析

我们先看下UVM源代码中uvm_callback的定义,如图3所示。
在这里插入图片描述
图3 src/base/uvm_callback.svh中的的关于类uvm_callback的代码截图

uvm_callback本身作为用户自定义的callback类的基类,直接例化uvm_callback没有任何意义。类中除了定义了打开和关闭callback相关的功能(m_enabled),并没有其他具体的功能实现,甚至连m_enabled是如何控制callback的打开和关闭都没有提及。我们接着往下看。
回到一开始我们讲述环境开发者所做的步骤1和2,步骤1只是从uvm_callback继承产生了新的callback类,并添加了一个callback方法,并没有什么可讲的。
步骤2中的`uvm_register_cb宏定义如图4所示。
在这里插入图片描述
图4 src/macros/uvm_callback_defines.svh中宏uvm_register_cb相关的代码截图

相当于把图1中15行的代码转化为下面的代码。

static local bit m_register_cb_pkt_process_callback = uvm_callbacks#(my_driver, pkt_process_callback)::m_register_pair("my_driver", "pkt_process_callback");

由图2中38-40行的介绍可知要想使用uvm_callback源代码中的相关方法,首先必须对type-callback对进行注册,这个配对关系包含了uvm_callback类以及其callback方法所被使用的类(以下简称容器类),例如本例中的pkt_process_callback和my_driver,uvm_register_cb宏实现了将uvm_callback类(pkt_process_callback)注册到容器类(my_driver)中。
`uvm_register_cb宏等价于声明了一个静态的本地bit类型的变量 m_register_cb_pkt_process_callback,并且调用参数化的uvm_callbacks类中的静态方法m_register_pair进行了初始化,初始化即对上面提到的type-callback对进行注册。而这个uvm_callbacks类我们在第4步uvm_callback类创建的时候正是用的其中的静态方法add,下面我们来正式揭开这个uvm_callbacks类的庐山真面目,如图5所示。
在这里插入图片描述
图5 src/base/uvm_callback.svh中的关于类uvm_callbacks的代码截图

uvm_callbacks继承链条上的相关类如图6、图7所示。
在这里插入图片描述
图6 src/base/uvm_callback.svh中的关于类uvm_typed_callbacks的代码截图

在这里插入图片描述
图7 src/base/uvm_callback.svh中的关于类uvm_callbacks_base的代码截图

从上面UVM源代码中关于uvm_callbacks类以及uvm_register_cb宏相关的描述中我们可以得出如下结论:

  • 参数化的类uvm_callbacks和uvm_register_cb宏对应的两个参数T和CB是配对关系,T表示用户自定义的callback类中callback方法是在哪个类中被调用的,缺省值为uvm_object类型(虽然绝大多数情况下我们都是用的它的子类uvm_component类型的扩展类),CB表示与用户自定义的uvm_callback类,缺省值为基类型uvm_callback。
  • 参数化的uvm_typed_callback类只包含了容器类型,而与具体的uvm_callback类型无关,这就决定了该类可以匹配任何类型的uvm_callback类,他只跟容器类型T相关,其中定义的uvm_queue用来存放注册在容器类T中的所有uvm_callback对象,并且提供了诸多接口方法供uvm_callbacks类继承使用。
  • uvm_callbacks_base作为一个单例模式类,它比uvm_typed_callback类更为抽象,uvm_typed_callback类使用uvm_queue类型存放了参数化的容器类型T所包含的所有uvm_callback类型,而uvm_callbacks_base则使用uvm_pool类型存放了容器类和uvm_queue所组成的键值对,它可以容纳所有uvm_callback类的type-uvm_callback配对关系。
  • uvm_callbacks类继承了uvm_typed_callback类和uvm_callbacks_base类的所有属性和方法,并且绝大多数属性和方法都是静态类型的,加上uvm_callbacks_base类的单例属性,这样我们便可以使用uvm_callbacks类直接引用其中的静态属性和方法了,这其中比较重要的几个方法如图8所示。

在这里插入图片描述
图8 src/base/uvm_callback.svh中的几个常用方法的代码截图

下面依次对图8中的这几个函数做介绍。
uvm_callbacks类中定义的相关变量如图9所示,484-485行定义了两个类型super_type和this_type方便后面简化代码,而其中的m_inst就是this_type类型,它也使用了单例模式用于type-callback对的全局共享。

在这里插入图片描述
图9 src/base/uvm_callback.svh中uvm_callbacks类中定义的变量的代码截图

首先看m_register_pair函数,其中涉及的两个变量m_typeid和m_cb_typeid都是uvm_typeid_base类型,uvm_typeid_base的定义如图10所示,它实现了一个简化版的类似于factory机制的类映射表,其中包含了3个static类型的变量,分别是字符串类型typename以及两个key-value互换的关联数组。而m_typeid和m_cb_typeid的初始化则是通过544行调用get()函数间接调用uvm_typeid_base参数化的子类uvm_typeid中的get()函数获取的,而m_typeid和m_cb_typeid在使用uvm_typeid创建时的参数则分别对应着uvm_callbacks的两个参数T和CB,get()函数实现如图11所示。

在这里插入图片描述
图10 src/base/uvm_callback.svh中uvm_typeid_base类及其子类的代码截图

在这里插入图片描述
图11 src/base/uvm_callback.svh中get()函数实现的代码截图

这样通过uvm_register_cb宏调用m_register_pair函数便实现了uvm_callback类CB和容器类T的配对关系,如果没有指定CB类型(使用缺省值uvm_callback),映射关系则保存在uvm_typeid_base类的静态变量联合数组typeid_map和type_map中,如果指定了CB类型,则将type-callback对信息保存在uvm_callbacks_base中定义的m_this_type队列中。注册完成后会将m_regitsered变量置为1,方便后续查阅type-callback对的注册情况。
简而言之就是uvm_register_cb宏实现了将uvm_callback类与容器类绑定,并将绑定信息储存在uvm_callbacks类中的相关变量中。
下面继续看看add和delete这两个静态函数,字面意思就是添加和删除。add函数实现将用户自定义的callback对象cb添加到obj对象中,并且obj允许是一个null类型(调用该callback对象中的callback方法时第一个参数也用null即可,uvm_do_callbacks(null, CB, METHOD))。同一个obj对象可以注册多个uvm_callback对象,多个uvm_callback对象执行顺序由uvm_apprepend类型的参数ordering指定,枚举类型uvm_apprepend有两个值UVM_APPEND和UVM_PREPEND,UVM_APPEND作为缺省值,表示当前添加的uvm_callback对象在前面添加的uvm_callback对象后面执行,UVM_PREPEND反之。这里就不对add/delete函数的细节做具体介绍了,感兴趣的可以自行研究。
如此一来,关于UVM源代码中uvm_callback实现的4个步骤我们只剩`uvm_do_callbacks这个宏没有介绍了,这涉及到了callback方法是如何被调用执行的,如图12所示。

在这里插入图片描述
图12 src/macros/uvm_callback_defines.svh中宏uvm_do_callbacks相关的代码截图

由宏描述不难得出以下结论:

  • uvm_do_callbacks 本质上调用了uvm_do_obj_callbacks,将其中的参数OBJ使用了缺省值this,区别在于this这个参数仅仅对uvm_component适用,而对于像sequence这种uvm_object类型中如果想调用uvm_callback方法的话则不能使用 uvm_do_callbacks 宏,而必须使用uvm_do_obj_callbacks,对应的OBJ参数可以使用null或者指定对应的注册了该uvm_callback类的uvm_component,这个有点像在sequence中使用uvm_config_db#(T)::get(OBJ, )的第一个参数,OBJ也是不能用this的,可以用null或者p_sequencer/m_sequencer。这里可以看看UVM源代码中还有个小错误就是133行的示例用法中宏函数的第1、2两个参数用反了,第一个参数应该是component,第二个参数是uvm_callback。uvm_do_obj_callbacks实现了将一个与uvm_object类型关联的uvm_callback类在某个类型T中执行起来。
  • uvm_do_callbacks和uvm_do_obj_callbacks宏都会迭代的调用其中注册的所有uvm_callback对象中的指定方法METHOD,调用顺序由add时候指定的顺序决定。关于迭代器uvm_callback_iter类也定义在文件uvm_callback.svh中,这里就不展开讲解了,感兴趣的同学可以自行查阅。
    回调函数的执行(步骤2)本质上都是依赖于步骤1、3、4上对callback相关类的定义、注册、创建、添加后在某个特定的时间点被调用执行的。
  • 关于回调函数的执行有时候还会添加相关的控制变量来控制回调函数的开关,例如synopsis家的VIP中包含了很多供用户扩展使用的callback接口,相关的callback函数一般都会在configure中有个对应的enable变量控制其打开和关闭,这样callback的实现就包含了对应configure的enable以及callback类的继承实现两部分共同完成了。

如此一来,上文提到的UVM callback实现的4个步骤在UVM源代码中的具体实现我们便全部介绍完毕了。

5. 总结

本文通过一个具体的例子引出对UVM源代码中callback的实现机制进行了粗浅的分析,虽说不能让大家看完后对UVM中的callback机制有醍醐灌顶的感觉,但相信同学们看完在后面使用uvm_callback的时候应该会有一个更为立体的理解。

6.附录

大家在网上经常看到的关于UVM callback机制的应用基本上都是在driver或者monitor等uvm_component的扩展类中实现的,而在uvm_object的扩展类中使用则很少见到,既然上面在介绍宏uvm_do_obj_callbacks已经提到了相关应用,这里就在最后附上一段代码示例,介绍下如何在sequence中实现UVM的callback机制,相信大家看完之后应该会有更为深刻的理解,重要代码片段用红色框标出。

在这里插入图片描述
图13 将空uvm_callback类注册到vseq_0中,并在需要的位置通过宏uvm_do_obj_callbacks调用回调方法

在这里插入图片描述
图14 创建用户自定义的callback类并重写回调方法,将新的callback类添加到对应的type-callback对中

在这里插入图片描述
图15 仿真结果显示新的回调方法在sequence中被自动调用

这里需要注意的是不要混淆宏uvm_do_obj_callbacks的参数T和OBJ,T表示的是callback注册所在的类,而OBJ则是T的一个关联实例,相应的在uvm_callbacks#(T, CB)::add(cb, obj)添加type-callback对的时候也需要将obj与宏uvm_do_obj_callbacks中的OBJ参数匹配上。
在前面driver中使用callback的示例中,T用my_driver表示,OBJ则是用默认的driver的实例env.i_agt.drv,那么在my_driver中调用对应的回调方法是第三个参数就必须也是env.i_agt.drv,示例中使用的是宏uvm_do_callbacks缺省了OBJ参数,使用的是值this指代的就是当前类my_driver的对象。
同理,在sequence中使用宏uvm_do_obj_callbacks的OBJ参数也需要与uvm_callbacks#(T, CB)::add()的第二个参数保持一致,我们在宏uvm_do_obj_callbacks传递的OBJ参数值为null,那么在uvm_callbacks#(T, CB)::add()的第二个参数也为null。当然我们还可以有下面一种选择,就是把callback注册在sequence对应的sequencer中,所有的T都换成virtual_sequencer,对应的则使用virtual_sequencer的实例,方法类似于上述my_driver的用例,达到的效果相同,如图16、17所示,两种用法的差别部分用红色框标出。

在这里插入图片描述
图16 sequence中将uvm_callback注册到对应sequencer中代码1

在这里插入图片描述
图17 sequence中将uvm_callback注册到对应sequencer中代码2

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

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

相关文章

c++ 智能指针shared_ptr与make_shared

shared_ptr是C11引入的一种智能指针,‌它允许多个shared_ptr实例共享同一个对象,‌通过引用计数来管理对象的生命周期。‌当最后一个持有对象的shared_ptr被销毁时,‌它会自动删除所指向的对象。‌这种智能指针主要用于解决资源管理问题&…

简单小案例分析

一、容器和实例关系 <div class"app"><h1>Hello,{{name}}</h1> </div> <div class"app"><h1>Hello,{{name}}</h1> </div><script>//创建Vue实例new Vue({el:".app", //el用于指定当前V…

北大延毕硕士×INFJ | 我解脱了

前言 拿了双证&#xff0c;我终于能静下心来复盘一下我延毕一年的经历了。 给后面也许有相同困境的朋友们做个参考或者心理疏导作用。 延毕的原因 我延毕的主要原因是论文研三的时候论文没有完成&#xff0c;我们专业的论文一般是6个月全身心投入可以完成。我这个人是典型的…

7月24日JavaSE学习笔记

序列化版本控制 序列化&#xff1a;将内存对象转换成序列&#xff08;流&#xff09;的过程 反序列化&#xff1a;将对象序列读入程序&#xff0c;转换成对象的方式&#xff1b;反序列化的对象是一个新的对象。 serialVersionUID 是一个类的序列化版本号 private static fin…

77.WEB渗透测试-信息收集-框架组件识别利用(1)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;76.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;16&#xff09; java&#xff…

The Llama 3 Herd of Models.Llama 3 模型论文全文

现代人工智能(AI)系统是由基础模型驱动的。本文提出了一套新的基础模型,称为Llama 3。它是一组语言模型,支持多语言、编码、推理和工具使用。我们最大的模型是一个密集的Transformer,具有405B个参数和多达128K个tokens的上下文窗口。本文对Llama 3进行了广泛的实证评价。我们…

【Django】前端技术HTML常用标签(开发环境vscode)

文章目录 安装两个常用插件HTML常用标签定义文档类型DOCTYPE网页的结构html/head//title/body/div标题h1/h2/h3/h4/h5分割线hr段落 p列表ul/li&#xff0c;ol/li超链接a文本span图片img按钮button表格table&#xff08;table、tr、th、td&#xff09;表单form 安装两个常用插件…

深度学习环境配置——总结下近期遇到的”坑“

文章目录 1. 问题1&#xff1a;硬件选择的误区2. 问题2&#xff1a;操作系统的适配难题3. 问题3&#xff1a;深度学习框架的安装陷阱4. 问题4&#xff1a;CUDA与cuDNN的版本匹配问题5. 问题5&#xff1a;网络配置的瓶颈6. 问题6&#xff1a;数据预处理的技巧7. 问题7&#xff1…

CVPR`24 | 4D编辑哪家强?浙大首次提出通用指导4D编辑框架:Instruct 4D-to-4D

文章链接&#xff1a;https://arxiv.org/pdf/2406.09402 项目地址&#xff1a;https://immortalco.github.io/Instruct-4D-to-4D/ 今天和大家一起学习的是Instruct 4D-to-4D&#xff0c;可以通过2D扩散模型实现4D感知和时空一致性&#xff0c;以生成高质量的指令引导的动态场景…

用户使用算力共享平台流程

目录 用户使用算力共享平台流程 一、用户注册与认证 二、接入算力资源 三、任务发布与管理 四、商业调度与资源分配 五、任务执行与结果验证 六、支付与结算 七、评价与信誉建立 算力架构概述 “以案赋能” | 首届“华彩杯”算力应用创新大赛全国总决赛获奖案例选编

【JUC】Java锁介绍

文章目录 阿里锁开发规范乐观锁和悲观锁悲观锁乐观锁 synchronized 类锁、对象锁synchronized有三种应用方式锁相关的8种案例演示&#xff08;对象锁、类锁&#xff09;标准访问ab两个线程&#xff0c;请问先打印邮件还是短信&#xff1f;sendEmail钟加入暂停3秒钟&#xff0c;…

【Python机器学习】决策树的构造——递归构建决策树

我们可以采用递归的原则处理数据集&#xff0c;递归结束的条件是&#xff1a;程序遍历完所有划分数据集的属性&#xff0c;或者每个分支下的所有实例都具有相同的分类。如果所有实例具有相同的分类&#xff0c;则得到一个叶子节点或者终止块。任何到达叶子节点的数据必然属于叶…

软考:软件设计师 — 7.软件工程

七. 软件工程 1. 软件工程概述 &#xff08;1&#xff09;软件生存周期 &#xff08;2&#xff09;软件过程 软件开发中所遵循的路线图称为 "软件过程"。 针对管理软件开发的整个过程&#xff0c;提出了两个模型&#xff1a;能力成熟度模型&#xff08;CMM&#…

uniapp引入自定义图标

目录 一、选择图标&#xff0c;加入购物车 二、下载到本地 三、导入项目 四、修改字体引用路径 五、开始使用 这里以扩展iconfont图标为例 官网&#xff1a;iconfont-阿里巴巴矢量图标库 一、选择图标&#xff0c;加入购物车 二、下载到本地 直接点击下载素材&#xff0…

mysql中You can’t specify target table for update in FROM clause错误

mysql中You can’t specify target table for update in FROM clause错误 You cannot update a table and select directly from the same table in a subquery. mysql官网中有这句话&#xff0c;我们不能在一个语句中先在子查询中从某张表查出一些值&#xff0c;再update这张表…

matplotlib 画图函数,最常用的

并排显示2个图片 import os import numpy as np from PIL import Image import matplotlib.pyplot as pltimage1 Image.open(a.png) image2 Image.open(a2.png)# Create a figure with two subplots (1 row, 2 columns) fig, axes plt.subplots(1, 2, figsize(10, 5))# Di…

使用Log4Net和中间件记录接口访问日志

一、功能概述 Log4Net log4net 是一个用于.NET应用程序的日志记录框架。它允许开发人员在他们的应用程序中记录各种信息&#xff0c;以便追踪应用程序的运行状态、排查问题和分析性能。log4net的主要作用包括&#xff1a; 日志记录: 记录应用程序的运行时信息&#xff0c;如调…

【单片机毕业设计选题24081】-路灯无线数据采集器

系统功能: 手机开启2.4G WiFi热点后再给系统上电 系统操作说明&#xff1a; 上电后OLED显示 “欢迎使用智能路灯系统请稍后”&#xff0c;两秒后显示Connecting...表示 正在连接阿里云&#xff0c;正常连接阿里云后显示第一页面&#xff0c;如长时间显示Connecting...请 检…

复现open-mmlab的mmsegmentation详细细节

复现open-mmlab的mmsegmentation详细细节 1.配置环境2.数据处理3.训练 1.配置环境 stage1&#xff1a;创建python环境 conda create --name openmmlab python3.8 -y conda activate openmmlabstage2&#xff1a;安装pytorch&#xff08;这里我是以torch1.10.0为例&#xff09…

昇思25天学习打卡营第22天|Pix2Pix实现图像转换

Pix2Pix图像转换学习总结 概述 Pix2Pix是一种基于条件生成对抗网络&#xff08;cGAN&#xff09;的深度学习模型&#xff0c;旨在实现不同图像风格之间的转换&#xff0c;如从语义标签到真实图像、灰度图到彩色图、航拍图到地图等。这一模型由Phillip Isola等人在2017年提出&…