【Python 进阶】抽象基类(Abstract Base Class)
abc
模块和抽象基类(Abstract Base Class)的概念:
本文的示例代码来源于 break-a-scene.
abc
是 Python 标准库中的一个模块,全称是 “Abstract Base Classes”(抽象基类)。- 它提供了一种定义抽象类和抽象方法的机制。
- 在以下代码中,
AttentionControl
类继承自abc.ABC
,表示这是一个抽象基类。
让我详细解释一下关键点:
- 抽象基类的作用:
- 定义了一个接口规范
- 强制子类必须实现某些方法
- 不能直接实例化,必须通过子类来实现
- 在代码中的具体应用:
class AttentionControl(abc.ABC):@abc.abstractmethoddef forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedError
@abc.abstractmethod
装饰器标记forward
方法为抽象方法- 任何继承
AttentionControl
的子类必须实现forward
方法 - 如果子类没有实现这个方法,在实例化时会报错
- 实际使用示例:
# 错误示例 - 会报错
controller = AttentionControl() # 不能直接实例化抽象类# 正确示例 - 需要实现抽象方法
class MyController(AttentionControl):def forward(self, attn, is_cross: bool, place_in_unet: str):# 实现具体的逻辑return attn
这种设计模式的好处是:
- 确保所有子类都实现了必要的方法
- 提供了一个统一的接口规范
- 方便代码的维护和扩展
在这个项目中,AttentionControl
作为抽象基类,定义了注意力控制的基本接口,而具体的实现(如 AttentionStore
、AttentionReplace
等)都是它的子类,各自实现了不同的注意力控制策略。
让我解释一下这两种实例化的区别:
controller = AttentionControl()
会报错,因为:
AttentionControl
是一个抽象基类(Abstract Base Class)- 它包含抽象方法
forward
(被@abc.abstractmethod
装饰) - 抽象类不能直接实例化,必须通过子类来实现
self.controller = AttentionStore()
是合法的,因为:
AttentionStore
是AttentionControl
的子类- 它实现了所有必需的抽象方法(包括
forward
方法) - 子类可以正常实例化
让我们看看代码中的具体实现:
# 父类(抽象基类)
class AttentionControl(abc.ABC):@abc.abstractmethoddef forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedError# 子类(具体实现)
class AttentionStore(AttentionControl):def forward(self, attn, is_cross: bool, place_in_unet: str):key = f"{place_in_unet}_{'cross' if is_cross else 'self'}"if attn.shape[1] <= 32**2:self.step_store[key].append(attn)return attn
这就像是一个"合同":
AttentionControl
定义了一个"合同",要求所有子类必须实现forward
方法AttentionStore
签署了这个"合同",通过实现forward
方法来满足要求- 因此
AttentionStore
可以实例化,而AttentionControl
不能
这种设计模式的好处是:
- 确保所有注意力控制器都实现了必要的方法
- 提供了统一的接口规范
- 方便代码的维护和扩展
- 可以在运行时检查类型是否正确
所以简单来说:
AttentionControl()
会报错,因为它是一个"合同模板"AttentionStore()
可以正常工作,因为它是一个"已签署的合同"
继承 abc.ABC
的好处
让我解释一下为什么 AttentionControl
要继承 abc.ABC
:
- 不是绝对必要的,但是继承
abc.ABC
有几个重要好处:
# 方式1:继承 abc.ABC
class AttentionControl(abc.ABC):@abc.abstractmethoddef forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedError# 方式2:不继承 abc.ABC
class AttentionControl:def forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedError
- 继承
abc.ABC
的主要好处:
a) 强制抽象方法实现:
# 如果不继承 abc.ABC,子类可以不实现 forward 方法
class BadController(AttentionControl):pass # 这不会报错# 如果继承 abc.ABC,子类必须实现 forward 方法
class GoodController(AttentionControl):def forward(self, attn, is_cross: bool, place_in_unet: str):return attn # 必须实现
b) 提供类型检查:
# 继承 abc.ABC 后,可以用于类型检查
def process_controller(controller: AttentionControl):# 确保 controller 实现了所有必要的方法pass
c) 更好的代码文档:
- 明确表示这是一个抽象基类
- 表明这个类是用来被继承的
- 表明这个类定义了接口规范
- 实际应用中的区别:
# 不继承 abc.ABC 的问题
class AttentionControl:def forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedErrorclass BadController(AttentionControl):pass # 可以实例化,但会报错controller = BadController() # 可以创建实例
controller.forward() # 运行时才会报错# 继承 abc.ABC 的好处
class AttentionControl(abc.ABC):@abc.abstractmethoddef forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedErrorclass BadController(AttentionControl):pass # 直接报错,不能实例化controller = BadController() # 直接报错,不能创建实例
- 为什么选择继承
abc.ABC
:
a) 更早的错误检测:
- 在类定义时就能发现错误
- 而不是在运行时才发现
b) 更清晰的接口定义:
- 明确表示这是一个抽象基类
- 明确哪些方法必须被实现
c) 更好的代码维护:
- 更容易理解代码结构
- 更容易发现潜在问题
d) 更好的类型提示:
- IDE 可以提供更好的代码补全
- 静态类型检查工具可以工作
所以,虽然继承 abc.ABC
不是绝对必要的,但它提供了:
- 更好的错误检测
- 更清晰的接口定义
- 更好的代码维护性
- 更好的类型提示
这些好处使得代码更加健壮和可维护,特别是在大型项目中。
继承的好处
为什么 AttentionStore
要继承 AttentionControl
,以及这样做的好处:
- 必须这么做吗?
- 不是必须的,但这是一个很好的设计模式
- 如果不继承,也可以直接实现所有功能
- 但继承
AttentionControl
提供了更好的代码结构和可维护性
- 这样做的好处:
class AttentionControl(abc.ABC):def __call__(self, attn, is_cross: bool, place_in_unet: str):if self.cur_att_layer >= self.num_uncond_att_layers:h = attn.shape[0]attn[h // 2 :] = self.forward(attn[h // 2 :], is_cross, place_in_unet)self.cur_att_layer += 1if self.cur_att_layer == self.num_att_layers + self.num_uncond_att_layers:self.cur_att_layer = 0self.cur_step += 1self.between_steps()return attn
a) 代码复用:
AttentionControl
提供了通用的注意力控制逻辑- 子类只需要实现特定的
forward
方法 - 避免了重复编写相同的代码
b) 统一接口:
- 所有注意力控制器都遵循相同的接口
- 确保所有控制器都有必要的方法
- 方便其他代码使用这些控制器
c) 扩展性:
- 可以轻松添加新的注意力控制器
- 只需要继承
AttentionControl
并实现forward
方法 - 不需要重写所有逻辑
d) 维护性:
- 如果需要修改基础逻辑,只需要修改
AttentionControl
- 所有子类都会自动获得更新
- 减少了代码重复和潜在的错误
- 实际应用示例:
# 基础控制器
class AttentionControl(abc.ABC):@abc.abstractmethoddef forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedError# 存储控制器
class AttentionStore(AttentionControl):def forward(self, attn, is_cross: bool, place_in_unet: str):# 只实现存储逻辑key = f"{place_in_unet}_{'cross' if is_cross else 'self'}"if attn.shape[1] <= 32**2:self.step_store[key].append(attn)return attn# 替换控制器
class AttentionReplace(AttentionControl):def forward(self, attn, is_cross: bool, place_in_unet: str):# 实现替换逻辑return torch.einsum("hpw,bwn->bhpn", attn_base, self.mapper)
这种设计模式的好处是:
- 代码更加模块化
- 更容易维护和扩展
- 减少了代码重复
- 提供了统一的接口
- 方便添加新的功能
所以,虽然不是必须的,但继承 AttentionControl
是一个很好的设计选择,它提供了更好的代码结构和可维护性。
AttentionControl
和 AttentionStore
的差异
- 基础功能差异:
# AttentionControl - 基础抽象类
class AttentionControl(abc.ABC):def step_callback(self, x_t):return x_t # 基础实现,直接返回输入def between_steps(self):return # 空实现@abc.abstractmethoddef forward(self, attn, is_cross: bool, place_in_unet: str):raise NotImplementedError # 必须由子类实现# AttentionStore - 具体实现类
class AttentionStore(AttentionControl):def forward(self, attn, is_cross: bool, place_in_unet: str):# 具体实现:存储注意力值key = f"{place_in_unet}_{'cross' if is_cross else 'self'}"if attn.shape[1] <= 32**2:self.step_store[key].append(attn)return attndef between_steps(self):# 具体实现:合并注意力存储if len(self.attention_store) == 0:self.attention_store = self.step_storeelse:for key in self.attention_store:for i in range(len(self.attention_store[key])):self.attention_store[key][i] += self.step_store[key][i]self.step_store = self.get_empty_store()
- 属性差异:
# AttentionControl 的属性
self.cur_step = 0
self.num_att_layers = -1
self.cur_att_layer = 0# AttentionStore 额外添加的属性
self.step_store = self.get_empty_store() # 存储当前步骤的注意力
self.attention_store = {} # 存储累积的注意力
- 主要功能差异:
AttentionControl
:
- 提供基础的注意力控制框架
- 管理注意力层的计数和步骤
- 定义抽象接口
- 不存储任何注意力值
AttentionStore
:
- 实现具体的注意力存储功能
- 提供注意力值的累积和平均
- 管理注意力值的存储结构
- 添加了存储相关的属性和方法
- 新增方法:
# AttentionStore 特有的方法
@staticmethod
def get_empty_store():# 创建空的存储结构return {"down_cross": [], "mid_cross": [], "up_cross": [],"down_self": [], "mid_self": [], "up_self": []}def get_average_attention(self):# 计算平均注意力return {key: [item / self.cur_step for item in self.attention_store[key]]for key in self.attention_store}
总结差异:
-
功能定位:
AttentionControl
:基础框架,定义接口AttentionStore
:具体实现,专注于存储功能
-
实现程度:
AttentionControl
:抽象类,部分方法为空实现AttentionStore
:具体类,所有方法都有完整实现
-
存储能力:
AttentionControl
:不存储数据AttentionStore
:提供完整的存储和管理功能
-
使用场景:
AttentionControl
:作为基类,定义规范AttentionStore
:实际使用,存储注意力值
这种设计体现了面向对象编程中的"抽象与具体"的关系,通过继承实现了代码的复用和扩展。
相关文章:
【Python 进阶】抽象基类(Abstract Base Class)
abc 模块和抽象基类(Abstract Base Class)的概念: 本文的示例代码来源于 break-a-scene. abc 是 Python 标准库中的一个模块,全称是 “Abstract Base Classes”(抽象基类)。它提供了一种定义抽象类和抽象方法的机制。在以下代码…...
Armv7l或树莓派32位RPI 4B编译faiss
pip3 install faiss-cpu当然找不到预编译的包 手动下载 git clone https://github.com/facebookresearch/faiss.git cd faiss #能需要切换到特定版本标签,例如 v1.7.1,这个版本Cmake 3.18可以过,因为apt install安装的cmake只更新到这里&am…...

嵌入式开发STM32 -- 江协科技笔记
1.背景介绍及基础认知 8大输入输出 斯密特触发器:高于设定阈值输出高电平,低于设定阈值输出低电平 有关上拉输入、下拉输入、推挽输出、开漏输出、复用开漏输出、复用推挽输出以及浮空输入、模拟输入的区别 1、上拉输入:上拉就是把电位拉高…...

[网页五子棋][用户模块]客户端开发(登录功能和注册功能)
文章目录 客户端开发登录功能htmlcsscommon.csslogin.css jQuery引入 jquery 运行程序注册功能 客户端开发 登录功能 html <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport&…...
nt!MiInitializeSystemCache函数分析之PointerPte->u.List.NextEntry的由来
第一部分: 1: kd> dd 0xc0304200 c0304200 c10c0000 00000000 00000000 00000000 c0304210 00000000 00000000 00000000 00000000 c0304220 00000000 00000000 00000000 00000000 c0304230 00000000 00000000 00000000 00000000 c0304240 00000000 00000000…...

MQTT协议,EMQX部署,MQTTX安装学习
一、MQTT概述 1.什么是MQTT MQTT是一种基于“发布订阅“”模式的消息传输协议。 消息:设备和设备之间传输的数据,或者服务和服务之间要传输的数据。 协议:传输数据时所遵循的规范。 2.常见的通讯模式 (1)客户端-服…...
如何理解UDP 和 TCP 区别 应用场景
UDP与TCP的定义、特性、使用场景及对比表格 定义 UDP(User Datagram Protocol)是一种无连接的传输层协议,提供不可靠的数据报服务。 TCP(Transmission Control Protocol)是一种面向连接的传输层协议,提供…...

60天python训练计划----day40
DAY 40 训练和测试的规范写法 知识点回顾: 彩色和灰度图片测试和训练的规范写法:封装在函数中展平操作:除第一个维度batchsize外全部展平dropout操作:训练阶段随机丢弃神经元,测试阶段eval模式关闭dropout 一.单通道图…...

干泵,干式螺杆真空泵
干式真空泵: 无油干式机械真空泵(又简称干式机械泵)是指泵能从大气压力下开始抽气,又能将被抽气体直接排到大气中去,泵腔内无油或其他工作介质,而且泵的极限压力与油封式真空泵同等量级或者接近的机械真空泵…...

Tailwind CSS 实战:基于 Kooboo 构建 AI 对话框页面(五):语音合成输出与交互增强
Tailwind CSS 实战,基于Kooboo构建AI对话框页面(一) Tailwind CSS 实战,基于Kooboo构建AI对话框页面(二):实现交互功能 Tailwind CSS 实战,基于 Kooboo 构建 AI 对话框页面&#x…...

职业本科院校无人机专业人才培养解决方案
2023年的中央经济工作会议强调了以科技创新推动现代化产业体系构建的重要性,并提出发展生物制造、商业航天、低空经济等战略性新兴产业。低空经济,依托民用无人机等低空飞行器,在多场景低空飞行活动的牵引下,正逐步形成一个辐射广…...
利用机器学习优化数据中心能效
数据中心作为现代社会的数字基础设施,支撑着云计算、大数据分析、人工智能等关键技术的发展。然而,随着数据中心规模的不断扩大,其能源消耗问题也日益凸显。如何提高数据中心的能源效率,降低运营成本,同时减少环境影响…...

软件评测机构如何保障质量?检测资质、技术实力缺一不可
软件评测机构在保障软件质量上起着关键作用,对软件行业的健康发展极为关键。它们采用专业的技术手段和严格的评估流程,对软件的运行效果、功能等多方面进行细致的审查,为开发者和使用者提供了客观、公正的参考依据。 检测资质正规软件评测机…...
微软开源bitnet b1.58大模型,应用效果测评(问答、知识、数学、逻辑、分析)
微软开源bitnet b1.58大模型,应用效果测评(问答、知识、数学、逻辑、分析) 目 录 1. 前言... 2 2. 应用部署... 2 3. 应用效果... 3 1.1 问答方面... 3 1.2 知识方面... 4 1.3 数字运算... 6 1.4 逻辑方面... …...
ubuntu 安装上传的 ffmpeg_7.1.1.orig.tar.xz并使用
在 Ubuntu 系统上离线安装 make 需要提前准备好所有依赖包。以下是详细的操作步骤: 准备工作:在有网络的机器上下载所需软件包 查找依赖关系 在有网络的 Ubuntu 机器上(需与目标机器相同版本)执行: # 获取 make 及其依…...
Web3怎么开发类似MetaMask的钱包
开发一个类似MetaMask的钱包,关键就是要利用以太坊提供的官方接口和标准,主要涉及以下几点: 1. 你要用到的以太坊官方接口和规范 JSON-RPC API 以太坊节点(如Geth、OpenEthereum等)通过JSON-RPC接口暴露各种功能&…...

Linux多线程(六)之线程控制4【线程ID及进程地址空间布局】
文章目录 线程ID及进程地址空间布局线程局部存储 线程ID及进程地址空间布局 pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。 该线程ID和前面说的线程ID不是一回事。 前面讲的线程ID属于进程调度的范畴。 因为线程是轻量级进程ÿ…...

1.什么是node.js、npm、vue
一、Node.js 是什么? 😺 定义: Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,让你可以在浏览器之外运行 JavaScript 代码,主要用于服务端开发。 😺从计算机底层说:什么是“运…...

Xamarin入门笔记(Xamarin已经被MAUI取代)
初级代码游戏的专栏介绍与文章目录-CSDN博客 Xamarin入门 概述 环境 Android开发环境比较简单,自带模拟器,实体机打开开发者模式即可。 iOS开发环境比较复杂,必须搭配Mac电脑,Windows连接Mac开发可能有问题(比如发…...

排查Oracle文件打开数过多
Oracle数据库在运行过程中,会打开大量的文件以执行其操作,包括数据文件、控制文件、日志文件等。如果Oracle用户打开的文件数过多,可能会引起系统性能下降。下面将深入分析Oracle用户文件打开数的优化策略,以帮助数据库管理员&…...

应用层协议http(无代码版)
目录 认识URL urlencode 和 urldecode HTTP 协议请求与响应格式 HTTP 的请求方法 GET 方法 POST 方法 HTTP 的状态码 HTTP 常见 Header Location 关于 connection 报头 HTTP版本 远程连接服务器工具 setsockopt 我们来学习应用层协议http。 虽然我们说, 应用层协…...

8.5 Q1|广州医科大学CHARLS发文 甘油三酯葡萄糖指数累积变化与 0-3期心血管-肾脏-代谢综合征人群中风发生率的相关性
1.第一段-文章基本信息 文章题目:Association between cumulative changes of the triglyceride glucose index and incidence of stroke in a population with cardiovascular-kidney-metabolic syndrome stage 0-3: a nationwide prospective cohort study 中文标…...
交叉编译tcpdump工具
1.导出交叉编译工具链 export PATH$PATH:/opt/rockchip/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin 下载源码包libpcap-1.10.5,配置、并编译安装。 github仓库地址 ./configure --hostarm-linux CCarm-linux-gnueabihf-gcc --prefix$PWD/install …...
【Python-Day 20】揭秘Python变量作用域:LEGB规则与global/nonlocal关键字详解
Langchain系列文章目录 01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...
golang 柯里化(Currying)
使用场景:参数在语义上属于不同组,Go 语法无法在单次调用中声明多组可变参数,通过柯里化可以实现分步接收参数。 有的参数是在不同时间段产生,使用Currying可以让函数记住(缓存)参数,避免应用代…...

无人机停机坪运行技术分析!
一、运行方式 1. 自动折叠与展开 部分停机坪采用二次折叠设计,通过传动组件实现自动折叠,缩小体积便于运输;展开后最大化停机面积,适应不同任务需求。例如,珠海双捷科技的专利通过两次折叠使停机坪体积最小化&#x…...
comfyui 工作流中 视频长度和哪些参数有关? 生成15秒的视频,再加上RTX4060 8G显卡,尝试一下
想再消费级显卡上生成15秒长视频,还是比较慢的,不过动漫的画质要求比较低 在ComfyUI中生成15秒视频需综合考虑视频参数配置、模型选择和硬件优化,尤其针对RTX 4060 8G显存的限制。 ⏱️ 一、影响视频长度的核心参数 总帧数(video_…...

【Java Web】速通HTML
参考笔记: JavaWeb 速通HTML_java html页面-CSDN博客 目录 一、前言 1.网页组成 1 结构 2 表现 3 行为 2.HTML入门 1 基本介绍 2 基本结构 3. HTML标签 1 基本说明 2 注意事项 4. HTML概念名词解释 二、HTML常用标签汇总 + 案例演示 1. 字体标签 font (1)定义 (2)案例 2…...

在线制作幼教早教行业自适应网站教程
你想知道怎么做自适应网站吗?今天就来教你在线用模板做个幼教早教行业的网站哦。 首先得了解啥是自适应网站。简单说呢,自适应网站就是能自动匹配不同终端设备的网站,像手机、平板、电脑等。那如何做幼早教自适应网站呢? 在乔拓云…...
WSL 开发环境搭建指南:Java 11 + 中间件全家桶安装实战
在WSL(Windows Subsystem for Linux)环境下一站式安装开发常用工具,能极大提升工作效率。接下来我将分步为你介绍如何在WSL中安装Java 11、Maven、Redis、MySQL、Nacos、RabbitMQ、RocketMQ、Elasticsearch(ES)和Node.…...