【Python 进阶2】抽象方法和实例调用方法

news2025/6/5 10:42:04

抽象方法和实例调用方法

对比表格:

特性抽象方法 (forward)实例调用方法 (call)
定义方式@abc.abstractmethod 装饰器特殊方法名 __call__
调用方式不能直接调用,必须通过子类实现可以直接调用对象:controller(attn, ...)
实现要求必须由子类实现,否则无法实例化可以在基类中实现,子类可以覆盖
主要功能定义具体业务逻辑(如存储注意力)处理通用流程(如计数、步骤控制)
代码位置在子类中实现(如 AttentionStore在基类中实现(AttentionControl
使用场景需要子类提供不同实现时需要统一接口时
错误处理在类定义时检查在运行时检查
代码复用每个子类都需要实现所有子类共享基类实现

以下面代码片段为例

class AttentionControl(abc.ABC):
    def step_callback(self, x_t):
        return x_t

    def between_steps(self):
        return

    @property
    def num_uncond_att_layers(self):
        return 0

    @abc.abstractmethod
    def forward(self, attn, is_cross: bool, place_in_unet: str):
        raise NotImplementedError

    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 += 1
        if self.cur_att_layer == self.num_att_layers + self.num_uncond_att_layers:
            self.cur_att_layer = 0
            self.cur_step += 1
            self.between_steps()
        return attn

    def reset(self):
        self.cur_step = 0
        self.cur_att_layer = 0

    def __init__(self):
        self.cur_step = 0
        self.num_att_layers = -1
        self.cur_att_layer = 0
  1. 抽象方法:

    • 是接口定义
    • 强制子类实现
    • 提供具体功能
  2. 实例调用方法:

    • 是统一接口
    • 处理通用逻辑
    • 调用抽象方法

具体的调用差异

forward__call__ 的区别和调用时机:

  1. 基本区别:
# forward 是抽象方法,需要子类实现
@abc.abstractmethod
def forward(self, attn, is_cross: bool, place_in_unet: str):
    raise NotImplementedError

# __call__ 是实例调用方法,可以直接调用对象
def __call__(self, attn, is_cross: bool, place_in_unet: str):
    # 调用 forward 并处理其他逻辑
    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)
    # ... 其他逻辑
  1. 调用时机:

__call__ 的调用:

controller = AttentionStore()
# 直接调用对象时会触发 __call__
result = controller(attn, is_cross=True, place_in_unet="down")

forward 的调用:

# forward 是在 __call__ 内部被调用的
# 不会直接调用 forward
  1. 工作流程:
# 1. 当调用 controller(attn, ...) 时,会触发 __call__
# 2. __call__ 方法会:
#    - 检查条件
#    - 调用 forward
#    - 更新计数器
#    - 处理步骤间逻辑
# 3. forward 方法(由子类实现)处理具体的注意力计算
  1. 实际应用示例:
# 在 AttentionStore 中
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

# 在 AttentionReplace 中
def forward(self, attn, is_cross: bool, place_in_unet: str):
    # 替换注意力值
    return torch.einsum("hpw,bwn->bhpn", attn_base, self.mapper)
  1. 为什么这样设计:

a) 分离关注点:

  • __call__ 处理通用逻辑(计数、步骤等)
  • forward 处理具体实现(存储、替换等)

b) 提供统一接口:

  • 所有控制器都可以像函数一样调用
  • 内部实现可以不同

c) 代码复用:

  • 通用逻辑在 __call__ 中实现一次
  • 子类只需要实现 forward
  1. 调用顺序:
# 1. 外部调用
controller(attn, is_cross=True, place_in_unet="down")

# 2. 触发 __call__
def __call__(self, attn, is_cross: bool, place_in_unet: str):
    # 3. 条件检查
    if self.cur_att_layer >= self.num_uncond_att_layers:
        # 4. 调用 forward
        attn[h // 2 :] = self.forward(attn[h // 2 :], is_cross, place_in_unet)
    # 5. 处理其他逻辑

这种设计的好处是:

  1. 提供了清晰的接口
  2. 分离了通用逻辑和具体实现
  3. 方便代码复用和维护
  4. 使代码结构更加清晰

所以,在这个例子中 forward__call__ 的区别在于:

  • __call__ 是外部接口,处理通用逻辑
  • forward 是内部实现,处理具体功能
  • 它们共同工作,提供了灵活且统一的接口

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

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

相关文章

Predixy的docker化

概述 当前已有一套redis cluster的集群&#xff0c;但是fs中的hiredis只能配置单实例redis。 AI了一下方案&#xff0c;可以使用redis的proxy组件来实现从hiredis到redis cluster的互通。 代码地址&#xff1a;https://github.com/joyieldInc/predixy Predixy特性介绍&…

C++ 之 多态 【虚函数表、多态的原理、动态绑定与静态绑定】

目录 前言 1.多态的原理 1.1虚函数表 1.2派生类中的虚表 1.3虚函数、虚表存放位置 1.4多态的原理 1.5多态条件的思考 2.动态绑定与静态绑定 3.单继承和虚继承中的虚函数表 3.1单继承中的虚函数表 3.2多继承(非菱形继承)中的虚函数表 4.问答题 前言 需要声明的&#x…

【JavaWeb】Maven、Servlet、cookie/session

目录 5. Maven6. Servlet6.1 Servlet 简介6.2 HelloServlet6.3 Servlet原理6.4 Mapping( **<font style"color:rgb(44, 44, 54);">映射 ** )问题6.5 ServletContext6.6 HttpServletResponse<font style"color:rgb(232, 62, 140);background-color:rgb(…

Rust 编程实现猜数字游戏

文章目录 编程实现猜数字游戏游戏规则创建新项目默认代码处理用户输入代码解析 生成随机数添加依赖生成逻辑 比较猜测值与目标值类型转换 循环与错误处理优化添加循环优雅处理非法输入​ 最终完整代码核心概念总结 编程实现猜数字游戏 我们使用cargo和rust实现一个经典编程练习…

关于神经网络中的激活函数

这篇博客主要介绍一下神经网络中的激活函数以及为什么要存在激活函数。 首先&#xff0c;我先做一个简单的类比&#xff1a;激活函数的作用就像给神经网络里的 “数字信号” 加了一个 “智能阀门”&#xff0c;让机器能学会像人类一样思考复杂问题。 没有激活i函数的神经网络…

CentOS_7.9 2U物理服务器上部署系统简易操作步骤

近期单位网站革新&#xff0c;鉴于安全加固&#xff0c;计划将原有Windows环境更新到Linux-CentOS 7.9&#xff0c;这版本也没的说&#xff08;绝&#xff09;了&#xff08;版&#xff09;官方停止更新&#xff0c;但无论如何还是被sisi的牵挂着这一大批人&#xff0c;毕竟从接…

短视频平台差异视角下开源AI智能名片链动2+1模式S2B2C商城小程序的适配性研究——以抖音与快手为例

摘要 本文以抖音与快手两大短视频平台为研究对象&#xff0c;从用户群体、内容生态、推荐逻辑三维度分析其差异化特征&#xff0c;并探讨开源AI智能名片链动21模式与S2B2C商城小程序在平台适配中的创新价值。研究发现&#xff0c;抖音的流量中心化机制与优质内容导向适合品牌化…

【笔记】Windows 下载并安装 ChromeDriver

以下是 在 Windows 上下载并安装 ChromeDriver 的笔记&#xff1a; ✅ Windows 下载并安装 ChromeDriver 1️⃣ 确认 Chrome 浏览器版本 打开 Chrome 浏览器 点击右上角 ︙ → 帮助 → 关于 Google Chrome 记下版本号&#xff0c;例如&#xff1a;114.0.5735.199 2️⃣ 下载…

Spark-Core Project

RDD转换算子总结 RDD转换算子分为Value类型、双Value类型和Key - Value类型。 1、Value类型 map&#xff1a;对数据逐条映射转换&#xff0c;可改变数据类型或值。如 dataRDD.map(num > num * 2 运行结果&#xff1a; 2&#xff09;mapPartitions&#xff1a;以分区为单位处…

Wireshark 使用教程:让抓包不再神秘

一、什么是 tshark&#xff1f; tshark 是 Wireshark 的命令行版本&#xff0c;支持几乎所有 Wireshark 的核心功能。它可以用来&#xff1a; 抓包并保存为 pcap 文件 实时显示数据包信息 提取指定字段进行分析 配合 shell 脚本完成自动化任务 二、安装与验证 Kali Linux…

JWT安全:接收无签名令牌.【签名算法设置为none绕过验证】

JWT安全&#xff1a;假密钥【签名随便写实现越权绕过.】 JSON Web 令牌 (JWT)是一种在系统之间发送加密签名 JSON 数据的标准化格式。理论上&#xff0c;它们可以包含任何类型的数据&#xff0c;但最常用于在身份验证、会话处理和访问控制机制中发送有关用户的信息(“声明”)。…

白银价格查询接口如何用Java进行调用?

一、什么是白银价格查询接口&#xff1f; 它聚焦于上海黄金交易所、上海期货交易所等权威市场&#xff0c;精准提供白银价格行情数据&#xff0c;助力用户实时把握市场脉搏&#xff0c;做出明智的投资决策。 二、应用场景 分析软件&#xff1a;金融类平台可以集成本接口&…

FreeBSD 14.3 候选版本附带 Docker 镜像和关键修复

新的月份已经到来&#xff0c;FreeBSD 14.3 候选发布版 1 现已开放测试&#xff0c;它带来了一些您可能会觉得有用的更新&#xff0c;特别是如果您对Docker容器感兴趣的话。RC1 版本中一个非常受欢迎的改进是&#xff0c;FreeBSD 项目已开始将官方开放容器计划 (OCI) 镜像发布到…

「Java教案」算术运算符与表达式

课程目标 1&#xff0e;知识目标 能够区分Java运算符的种类&#xff0c;例如&#xff0c;算术、赋值、关系、逻辑、位运算等。能够区分Java各类运算符的功能和使用场景。能够根据表达式的构成和计算规则&#xff0c;写出正确的表达式。能够根据运算符优先级与结合性&#xff…

论文写作核心要点

不要只读论文里的motivation和method 论文里的图表和统计特征 在论文里找到具有统计意义的东西&#xff0c;那么在语料里也肯定遵循这样的规律&#xff0c;我们就能用机器学习的方法&#xff0c; 我们再用不同方法解决&#xff0c;哪种方法好&#xff0c;就用哪种 实验分析 …

[java]eclipse中windowbuilder插件在线安装

目录 一、打开eclipse 二、打开插件市场 三、输入windowbuilder&#xff0c;点击install 四、进入安装界面 五、勾选我同意... 重启即可 一、打开eclipse 二、打开插件市场 三、输入windowbuilder&#xff0c;点击install 四、进入安装界面 五、勾选我同意... 重启即可

Ubuntu20.04服务器开启路由转发让局域网内其他电脑通过该服务器连接外网

要让你的 Ubuntu作为路由器&#xff0c;通过 Wi-Fi 上网&#xff0c;并给连接到 UsbNetwork 的设备提供网络&#xff0c;需要做以下配置&#xff1a; 1. 网络拓扑 [互联网] ← (Wi-Fi, wlo1) → [Ubuntu] ← (USB网络/USB以太网, UsbNetwork) → [设备]Ubuntu&#xff1a; Wi-…

【Oracle】TCL语言

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. TCL概述1.1 什么是TCL&#xff1f;1.2 TCL的核心功能 2. 事务基础概念2.1 事务的ACID特性2.2 事务的生命周期 3. COMMIT语句详解3.1 COMMIT基础语法3.2 自动提交与手动提交3.3 提交性能优化 4. ROLLBACK语句…

Windows | 总误按Num Lock?修改注册表永久禁用Numlk键使小键盘一直输入数字

先说需修改注册表的位置与键值 路径&#xff1a;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout\ 二进制键&#xff1a;Scancode Map 键值&#xff1a; 00 00 00 00 00 00 00 00 01 00 00 00 00 00 45 00 00 00 00 00 00 00 00 00如下图&#xff1a; …

2.RV1126-OPENCV Mat理解和AT函数

一.Mat概念 Mat 是整个图像存储的核心也是所有图像处理的最基础的类&#xff0c;Mat 主要存储图像的矩阵类型&#xff0c;包括向量、矩阵、灰度或者彩色图像等等。Mat由两部分组成&#xff1a;矩阵头&#xff0c;矩阵数据。矩阵头是存储图像的长度、宽度、色彩信息等头部信息&a…