commit f187abe72a582f371cf66604f55a888199849b05 Author: Jiao77 Date: Mon Aug 25 17:54:08 2025 +0800 initial commit diff --git a/Geo-Layout-Transformer.md b/Geo-Layout-Transformer.md new file mode 100644 index 0000000..cad1fc1 --- /dev/null +++ b/Geo-Layout-Transformer.md @@ -0,0 +1,316 @@ +# Geo-Layout Transformer技术路线图:一种用于物理设计分析的统一、自监督基础模型 + +## 摘要 + +本报告旨在为电子设计自动化(EDA)领域的下一代物理设计分析工具制定一项全面的技术路线图。随着半导体工艺节点不断缩小至纳米尺度,传统的、基于启发式规则的后端验证工具在应对日益增长的设计复杂性、互连寄生效应主导以及严峻的工艺可变性方面已显得力不从心。设计周期的延长和功耗、性能、面积(PPA)优化的瓶颈,正迫使业界寻求一种根本性的范式转变。 + +本文提出“Geo-Layout Transformer”——一种新颖的、统一的混合图神经网络(GNN)与Transformer架构,旨在通过学习物理版图的深度、上下文感知表征,来彻底改变后端分析流程。该模型的核心战略是利用海量的、未标记的GDSII版图数据,通过自监督学习(SSL)范式进行预训练,从而构建一个可复用的“物理设计基础模型”。这种方法旨在将EDA工具从一系列孤立的、任务特定的解决方案,演进为一个集中的、可跨任务迁移的“版图理解引擎”。 + +Geo-Layout Transformer的变革性潜力将在三个关键的后端应用中得到验证: + +1. **预测性热点检测(Hotspot Detection):** 通过捕捉长程物理效应和全局版图上下文,该模型有望显著超越传统基于模式匹配和卷积神经网络(CNN)的方法,在提高检测准确率的同时大幅降低误报率。 +2. **高速连通性验证(Connectivity Verification):** 将连通性问题(如开路和短路)重新定义为图上的链接预测和异常检测任务,利用模型的全局拓扑理解能力,实现比传统几何规则检查(DRC)更快、更精确的验证。 +3. **结构化版图匹配与复用(Layout Matching and Reuse):** 通过学习版图的结构化相似性度量,该模型能够实现对IP模块的高效检索、设计抄袭检测以及模拟版图迁移的加速,从而极大地提升设计复用效率。 + +本报告详细阐述了Geo-Layout Transformer的理论基础、创新的混合模型架构、针对上述应用的可行性分析,并提出了一套分阶段的技术实现路线图。该路线图涵盖了从数据整理、基础模型开发到特定任务微调、最终实现规模化部署的全过程,同时识别了潜在的技术挑战并提出了相应的缓解策略。我们相信,对Geo-Layout Transformer的研发投资,将为EDA供应商和半导体设计公司构建起一道难以逾越的技术壁垒和数据护城河,引领物理设计自动化进入一个由数据驱动、深度学习赋能的新纪元。 + +## 1. 物理设计分析的范式转变:从启发式到学习化表征 + +### 1.1. 规模化之墙:传统EDA在纳米时代的局限性 + +随着半导体工艺节点以前所未有的速度缩小,超大规模集成电路(VLSI)的后端设计正面临着一道由物理定律和制造成本构筑的“规模化之墙” 1。晶体管尺寸的减小带来了设计复杂性的指数级增长,数以亿计的器件被集成在单一芯片上,使得传统的电子设计自动化(EDA)方法论承受着巨大的压力 4。在深亚微米时代,设计的性能不再仅仅由晶体管本身决定,互连线的寄生效应(电阻和电容)已成为主导因素,严重影响着电路的时序、功耗和信号完整性 3。同时,严峻的工艺可变性导致设计窗口急剧缩小,使得确保良率和可靠性成为一项艰巨的挑战。 + +在这种背景下,传统EDA工具的局限性日益凸显。它们大多依赖于人工制定的启发式规则和算法,这些规则在面对复杂的物理相互作用时往往显得过于简化。例如,为了实现设计收敛,设计工程师通常需要进行多轮布局布线迭代,以优化线长、时序和拥塞等关键指标 5。这个过程高度依赖工程师的经验,不仅耗时巨大,而且计算效率低下,往往导致次优的功耗、性能和面积(PPA)结果 4。 + +物理验证环节是这一挑战的集中体现。以光刻热点检测为例,为了确保设计的可制造性,必须在流片前识别出所有对工艺变化敏感的版图图形(即热点)。最精确的方法是进行全芯片光刻仿真,但其计算成本高昂,一次完整的仿真可能需要数天甚至数周时间,这在现代敏捷的设计流程中是不可接受的 7。这种计算瓶颈迫使设计流程在精度和速度之间做出痛苦的妥协,严重阻碍了技术创新的步伐。 + +### 1.2. 机器学习在物理设计自动化中的兴起 + +为了应对现代设计的复杂性,将机器学习(ML)技术集成到EDA流程中已成为一种必然的演进 1。ML模型,特别是深度学习模型,擅长从大规模数据中学习复杂的、非线性的关系,这使其成为解决传统算法难以处理的优化和预测问题的理想工具 12。近年来,基于ML的方法在多个EDA任务中已经展现出超越现有技术(SOTA)传统方法的潜力。 + +具体的成功案例包括: + +* **布局规划指导:** PL-GNN等框架利用图神经网络(GNN)对网表进行无监督节点表示学习,从而为商业布局工具提供关于哪些实例应被放置在一起的指导,以优化线长和时序 5。 +* **拥塞预测:** CongestionNet等模型能够在逻辑综合阶段,仅根据综合后的网表,利用GNN预测布线拥塞,从而提前规避后端实现的困难 13。 +* **图分割:** GNN也被应用于电路划分,通过学习将大型图划分为平衡的子集,同时最小化切割边,这对于多层次布局布线至关重要 14。 + +这些应用的成功,催生了一套通用的、端到端的GNN应用流程。该流程为在集成电路(IC)设计中应用GNN提供了一个结构化的方法论,它明确地将问题分解为四个阶段:输入电路表示、电路到图的转换、GNN模型层构建以及下游任务处理 11。这个框架的建立,为系统性地开发更先进、更统一的版图分析模型(如本文提出的Geo-Layout Transformer)奠定了形式化的基础。 + +### 1.3. 版图表示的关键转变:从像素到图 + +在将机器学习应用于版图分析的早期探索中,最直观的方法是将版图片段(clips)视为图像,并应用在计算机视觉领域取得巨大成功的卷积神经网络(CNN) 8。这种基于图像的方法将热点检测等问题转化为图像分类任务。尽管这种方法取得了一定的成功,但它存在根本性的缺陷。首先,CNN要求固定尺寸的输入,这对于尺寸和形状各异的版图图形来说是一个严重的限制,通常需要进行裁剪或填充,从而可能丢失关键信息 8。其次,版图本质上是稀疏的,大部分区域是空白的,使用密集的像素网格表示在计算上是低效的。最重要的是,CNN的架构内含欧几里得空间的归纳偏置(即假设数据存在于规则的网格结构中),这使其无法直接理解电路的非欧几里得、关系型结构,例如组件之间的物理邻接和电气连接 14。 + +为了克服这些限制,业界逐渐认识到,电路和版图的自然表示形式是图(Graph),其中物理组件(如多边形、通孔)是节点,它们之间的物理或电气关系是边 8。图神经网络(GNN)正是为处理这种不规则的、图结构化数据而设计的,使其在根本上比CNN更适合版图分析任务 14。这种表示方法正确地捕捉了设计的底层拓扑和连通性,这对于精确的物理设计分析至关重要。 + +从CNN到GNN的演进,代表了一次根本性的概念飞跃。它标志着分析范式从将版图视为静态的“图片”,转变为将其理解为一个动态的“关系系统”。CNN必须从像素模式中隐式且低效地推断出几何关系,而GNN则通过边的定义显式地接收这种关系声明 20。这种数据结构与模型架构的对齐,带来了更高效的学习、更好的泛化能力和更具语义意义的表征。这种视角上的转变,是开发真正智能化的EDA工具的基石,也构成了Geo-Layout Transformer不可动摇的基础。 + +**表1:版图表示模态对比** + +| | | | | | +| --- | --- | --- | --- | --- | +| 表示模态 | 核心概念 | 优势 | 劣势 | 主要EDA应用 | +| **基于图像 (CNN)** | 版图是像素网格 | 可利用成熟的计算机视觉架构 | 输入尺寸固定;对稀疏数据计算效率低;忽略显式连通性;对旋转/缩放非原生不变 | 早期热点检测 | +| **基于图 (GNN/Transformer)** | 版图是节点(形状)和边(关系)的图 | 原生处理不规则几何;捕捉拓扑/连通性;稀疏、可扩展;通过设计实现置换/旋转等变性 | 数据准备(图构建)复杂度较高 | 所有提议任务(热点、连通性、匹配)及更广泛的应用 | + +## 2. 基础支柱:用于VLSI数据的GNN与Transformer + +### 2.1. 图神经网络:编码局部结构与连通性 + +图神经网络的核心工作原理是消息传递(Message Passing)范式 14。在该范式中,GNN通过递归地聚合其局部邻域的特征信息来构建节点的表征 8。每一轮消息传递,节点都会从其直接邻居那里“收集”信息,并结合自身原有的信息来更新自己的状态。通过堆叠多层GNN,每个节点可以感知到其K跳(K-hop)邻域内的信息。这种机制与VLSI版图的物理现实完美契合,能够学习一个版图元素如何受到其直接几何和电气环境的影响。 + +多种GNN架构已在EDA领域得到成功应用,证明了其强大的局部结构编码能力: + +* **GraphSAGE:** 该架构以其强大的归纳学习能力而著称,能够处理在训练期间未见过的节点。在布局规划中,GraphSAGE被用于无监督的节点表示学习,以捕捉网表的逻辑亲和性,从而指导商业布局工具 5。 +* **图注意力网络(GAT):** GAT引入了注意力机制,允许模型在聚合邻居信息时为不同的邻居分配不同的权重。这在处理复杂的物理场景时尤其有效,例如在时钟网络时序分析中,多个驱动单元对一个接收端(sink)延迟的贡献是不同的,GAT可以学习到这种差异化的重要性 18。 +* **关系图卷积网络(R-GCN):** 真实的VLSI版图是异构的,包含多种类型的节点(金属多边形、通孔、单元)和多种类型的边(邻接关系、连通关系)。R-GCN通过为每种关系类型使用不同的可学习变换矩阵,专门用于处理这种异构图,这对于精确建模真实世界版图至关重要 8。 + +尽管GNN在编码局部信息方面表现出色,但其自身也存在固有的挑战,这些挑战正是集成Transformer架构的主要动机: + +* **过平滑(Over-smoothing):** 这是GNN最关键的限制之一。在深度GNN中,随着消息传递层数的增加,所有节点的特征表示会趋于收敛到一个相同的值,导致节点变得难以区分 14。这使得GNN难以捕捉图中节点之间的长程依赖关系。 +* **可扩展性与性能:** 在邻居聚合过程中,不规则的内存访问模式使得GNN在处理大规模、芯片级的图时成为一个受内存带宽限制的瓶颈,这是实现高性能模型必须解决的工程挑战 10。 +* **对未见图的泛化能力:** EDA领域的一个核心难题是确保在一个特定电路上训练的模型能够很好地泛化到全新的、在训练中从未见过的设计上 13。 + +### 2.2. Transformer架构:捕捉全局上下文与长程依赖 + +Transformer架构的核心是自注意力(Self-Attention)机制,这是一种强大的机制,它通过计算集合中所有元素之间的成对交互来运作 22。与GNN的局部消息传递不同,自注意力允许模型在单层计算中直接建立任意两个输入元素之间的依赖关系,无论它们在序列中的距离有多远。这使得Transformer能够高效地建模长程依赖,直接克服了GNN的感受野限制和过平滑问题 23。 + +然而,将Transformer应用于二维几何数据(如VLSI版图)需要解决一个关键问题。标准的Transformer是置换不变的(permutation-invariant),它将输入视为一个无序的集合,这意味着当版图元素被“符号化”(tokenized)后,所有至关重要的空间位置信息都会丢失 24。解决方案是显式地将位置信息注入到模型中,即 + +**二维位置编码(2D Positional Encoding)**。 + +为VLSI版图这类几何数据选择合适的位置编码方案,并非一个微不足道的实现细节,而是一个决定模型几何理解能力的核心特征工程挑战。不同的编码方案向模型注入了关于空间和距离本质的强大先验知识。 + +* **绝对位置编码(APE):** 为每个元素的(x, y)坐标分配一个唯一的向量。这可以通过固定的正弦/余弦函数或可学习的嵌入来实现 24。APE为每个元素提供了全局坐标系中的位置感,对于理解依赖于芯片全局位置的效应(例如,靠近IO区域与核心区域的效应差异)至关重要 26。 +* **相对位置编码(RPE):** 将元素对之间的相对距离和方向直接编码到注意力计算中 27。这种方法对于学习由局部几何规则主导的任务(例如,热点检测中的间距规则、模拟电路中的器件匹配)非常有效 26。 +* **高级方案:** 近年来还出现了更复杂的编码方法,如旋转位置嵌入(RoPE),因其良好的旋转特性而受到关注 26;以及语义感知位置编码(SaPE),它不仅考虑几何距离,还考虑特征的相似性 28。 + +GNN和Transformer并非相互竞争的版图分析架构,它们在根本上是互补的。GNN可以被视为强大的“空间卷积器”,通过共享的消息传递函数学习局部的、平移不变的物理规则,非常适合识别DRC违规或简单的热点模式等局部几何特征 8。然而,诸如IR-Drop或关键路径时序违规等复杂问题,可能由物理上相距遥远的组件之间的相互作用引起。GNN需要一个不切实际的深度网络来传播这种长程影响,从而不可避免地导致过平滑 18。相比之下,Transformer的自注意力机制可以在一个计算步骤内连接这些遥远的组件,模拟VLSI设计中固有的全局场效应 23。 + +因此,最佳架构是分层的:首先由GNN创建丰富的、具备局部感知能力的特征嵌入,然后将这些嵌入传递给Transformer,以推理它们的全局相互依赖关系。这种协同作用比任何单一范式的模型都更高效、更有效、更具可解释性。基于此,一个新颖的架构思想是,Geo-Layout Transformer应采用一种**混合位置编码方案**,将绝对编码和相对编码相结合。这将允许模型的注意力机制根据具体的任务和上下文,自适应地学习哪种空间参照系最为重要,这是对现有方法的重大改进。 + +## 3. Geo-Layout Transformer的架构蓝图 + +### 3.1. 核心理念:用于分层特征提取的混合模型 + +Geo-Layout Transformer的核心设计理念是构建一个多阶段的混合架构,以分层的方式处理版图数据。这种处理流程旨在模仿设计专家分析版图的认知过程:从单个图形的几何属性,到局部图形的组合模式,再到整个系统级的全局交互。该架构明确地定义为GNN与Transformer的融合体,直接体现了前述的“互补性原则”,即利用GNN进行局部特征学习,再利用Transformer进行全局上下文的理解和推理 23。 + +为了清晰地论证这一架构选择的合理性,下表对不同架构的权衡进行了分析。 + +**表2:架构权衡:GNN vs. Transformer vs. 混合模型** + +| | | | | | | +| --- | --- | --- | --- | --- | --- | +| 架构 | 局部上下文捕捉 | 全局上下文捕捉 | 计算复杂度 | 主要归纳偏置 | 对VLSI版图的适用性 | +| **纯GNN** | 优秀(通过消息传递) | 差(受限于过平滑) | 高效(与边数成线性关系) | 强局部性和关系偏置 | 适合局部模式,不适合芯片级效应 | +| **纯Transformer** | 弱(无内建局部性) | 优秀(通过自注意力) | 差(与节点数的平方成正比) | 弱,置换不变性 | 对原始多边形不切实际,忽略局部几何规则 | +| **Geo-Layout Transformer (混合)** | 优秀(通过GNN编码器) | 优秀(通过Transformer骨干) | 可控(与GNN聚合的超节点数的平方成正比) | 结合局部关系偏置和全局注意力 | 最佳,利用两者优势构建分层表示 | + +### 3.2. 阶段一:GDSII到图的转换流水线 + +这是将原始几何数据结构化的第一步,也是整个模型的基础。 + +* **解析:** 建立一个强大的数据注入流水线,使用如gdstk等高性能开源库来解析GDSII或OASIS文件。选择gdstk是因其拥有高性能的C++后端和强大的布尔运算能力,这对于处理复杂的版图几何至关重要 31。同时, + python-gdsii等库也提供了灵活的Python接口 33。 +* **异构图表示:** 为了全面地捕捉版图信息,我们提出一个包含多种节点和边类型的丰富异构图模式: + + **节点类型:** Polygon(多边形)、Via(通孔)、CellInstance(单元实例)、Port(端口)。这种区分使得模型能够识别不同的物理实体 8。 + + **边类型:** Adjacency(同一层上的物理邻近)、Connectivity(通过通孔连接多边形)、Containment(单元内部的多边形)、NetMembership(连接同一逻辑网络的所有图形)。这从多个维度捕捉了版图元素之间的关系。 +* **丰富的特征工程:** 为图中的节点和边定义一套全面的特征集: + + **几何特征:** 归一化的边界框坐标、面积、长宽比、形状复杂度(如顶点数量)等 8。 + + **层特征:** 为每个金属层、通孔层和器件层创建一个可学习的嵌入向量。 + + **电气特征(可选,来自网表):** 预先计算的寄生参数、来自标准单元库的单元类型、网络的扇出等 18。 + + **层次化特征:** 一个表示设计层次结构中父单元/模块的嵌入向量,因为具有共同层次结构的实例往往连接更紧密,对布局质量影响更大 5。 + +### 3.3. 阶段二:用于局部邻域聚合的GNN编码器 + +此阶段的功能是一个可学习的特征工程模块,旨在取代传统方法中手工设计的特征提取器。我们提议使用一个由**多层关系图注意力网络(R-GAT)**组成的编码器。这一选择结合了GAT的注意力机制(能够权衡邻居的重要性)和R-GCN处理多类型边的能力,使其成为处理我们所定义的复杂异构图的理想选择。此阶段的输出是一组丰富的、例如512维的节点嵌入向量。每个向量都浓缩了其对应版图元素及其K跳邻域内的上下文信息,这些向量将作为下一阶段Transformer的输入“符号”(tokens)。 + +### 3.4. 阶段三:用于全局版图理解的Transformer骨干 + +这是模型的核心推理引擎,负责处理来自GNN编码器的、已具备上下文感知的节点嵌入序列。 + +* **位置编码集成:** 在进入第一个Transformer层之前,每个节点嵌入向量都会与其对应的、我们提出的混合二维位置编码向量(结合绝对和相对分量)相加。 +* **架构:** 采用标准的Transformer编码器架构,由多个多头自注意力(MHSA)层和前馈网络层堆叠而成。MHSA层使每个版图元素能够与所有其他元素进行交互,从而捕捉关键的长程物理效应,例如跨晶圆变异、长路径时序、电源网络压降等,这些效应对于纯局部模型是不可见的。这种方法直接受到了LUM和FAM等成功的版图分析Transformer模型的启发 7。 + +### 3.5. 阶段四:用于下游应用的特定任务头 + +来自Transformer骨干的、具备全局感知能力的节点嵌入,将被送入简单、轻量级的神经网络“头”(heads)中,以进行具体的预测。这种模块化的设计允许同一个核心模型通过更换或添加不同的任务头,来适应多种应用。 + +* **连通性头(Connectivity Head):** 一个简单的二元分类器(如多层感知机MLP),接收两个节点的嵌入,并预测它们之间存在连接的概率(即链接预测)。 +* **匹配头(Matching Head):** 一个图池化层(例如,在 8 中使用的 + GlobalMaxPool),将一个版图窗口内的所有节点嵌入聚合成一个单一的图级别向量。该向量随后被用于基于三元组损失(triplet loss)的相似性学习框架,类似于LayoutGMN 35。 +* **热点头(Hotspot Head):** 一个简单的节点级分类器(MLP),预测一个节点(代表一个多边形)属于热点区域的概率。 + +### 3.6. 训练策略:通过自监督学习构建“基础模型” + +在EDA领域,获取大规模、高质量的标记数据集是一个主要的瓶颈,原因在于标注成本高昂以及设计数据的知识产权(IP)机密性 9。为了克服这一挑战,我们提出一种两阶段的训练范式,旨在创建一个可复用的“物理设计基础模型”。 + +* 阶段一:自监督预训练(Self-Supervised Pre-training): + 这是整个策略的核心。我们将利用海量的、未标记的GDSII数据来预训练完整的GNN-Transformer骨干网络。提议的前置任务(pretext task)是掩码版图建模(Masked Layout Modeling),其灵感来源于计算机视觉领域的掩码自编码器(Masked Autoencoders)以及在模拟版图自监督学习中的类似工作 36。具体来说,我们会随机“掩盖”掉版图中的一部分元素(例如,将其特征置零或替换为特殊掩码符号),然后训练模型根据其周围的上下文来预测这些被掩盖元素的原始特征(如几何形状、层信息)。这个过程迫使模型学习物理设计的基本“语法”和内在规律,而无需任何人工标注。 +* 阶段二:监督微调(Supervised Fine-tuning): + 经过预训练的骨干网络,已经具备了对版图的强大、通用的理解能力。随后,我们可以使用规模小得多的、针对特定任务的标记数据集来微调该模型。例如,用几千个已知的热点样本来微调热点检测头。这种迁移学习的方法能够极大地减少为新任务或新工艺节点开发高性能模型所需的数据量和训练时间 36。 + +这种分层架构的设计创造了一个强大且可解释的数据处理流水线。阶段一将原始几何结构化为图。阶段二通过GNN学习局部的物理规则,可以被看作是一个智能的“语义压缩器”,它学会将一个复杂的局部多边形集群表示为一个单一的、丰富的特征向量。阶段三的Transformer则在这个更高层次的、数量少得多的语义符号上进行操作,使得全局注意力的计算变得可行。它不再是比较原始形状,而是在比较整个“邻域上下文”。这种分层处理方式不仅模仿了人类专家分析版图的思维过程,也是模型实现高效率和高性能的关键。 + +从商业战略的角度看,自监督预训练策略是整个路线图中最关键的元素。大多数学术研究受限于在公开基准上进行监督学习 8,这些基准可能无法反映先进工业设计的复杂性。而一个EDA供应商或大型半导体公司拥有数十年积累的、数PB的专有、未标记GDSII数据。所提出的SSL策略能够解锁这一沉睡数据资产的巨大价值,允许创建一个拥有无与伦比的、由数据驱动的、跨多个工艺节点的真实世界版图模式理解能力的基础模型。这将构建一个强大的竞争优势或“数据护城河”,因为竞争对手或初创公司几乎不可能复制相同规模和多样性的训练数据。 + +## 4. 可行性分析与应用深度剖析 + +Geo-Layout Transformer的统一表征能力使其能够灵活地应用于多个关键的后端分析任务。通过为每个任务设计一个特定的预测头并进行微调,该模型可以高效地解决看似不相关的问题。 + +### 4.1. 应用一:高精度连通性验证 + +* **问题定义:** 传统的连通性验证依赖于设计规则检查(DRC)工具,通过几何运算来检查开路(opens)和短路(shorts)。我们将此问题重新定义为图上的学习任务: + + **链接预测(Link Prediction):** 通过预测相邻多边形和通孔之间是否存在connectivity类型的边来验证网络的完整性。缺失的预测边可能表示开路 40。 + + **节点异常检测(Node Anomaly Detection):** 通过检测属于不同网络的节点之间是否存在意外的链接来识别短路。这种方法将一个几何问题转化为图拓扑问题,直接与预测开路/短路等制造缺陷相关联 7。 +* **方法论:** 使用微调后的Geo-Layout Transformer的连通性头进行预测。模型的Transformer骨干提供的全局上下文至关重要,它能够准确地追踪贯穿芯片的长网络,并识别由遥远布线之间的相互作用引起的复杂短路。 +* **预期性能:** 预计该方法将比传统的几何DRC工具和电路仿真器实现显著的速度提升 18。学习到的模型能够捕捉到纯粹基于规则的系统常常忽略的微妙物理相互作用(例如,电容耦合),从而带来更高的准确性 21。 + +### 4.2. 应用二:结构化版图匹配与复用 + +* **问题定义:** 此应用被定义为一个图相似性学习任务。目标是给定一个查询版图(例如,一个模拟IP模块),从一个庞大的数据库中检索出结构上相似的版图块。 +* **方法论:** + + 我们将直接借鉴并采用成功的LayoutGMN模型的架构和训练方法 35。 + + 微调后的模型匹配头将为任何给定的版图窗口生成一个单一的嵌入向量。 + + 版图之间的相似度可以高效地计算为这些嵌入向量在低维空间中的余弦距离。 + + 采用三元组损失函数,并利用交并比(Intersection-over-Union, IoU)作为弱监督信号来生成训练样本(即,高IoU的对作为正样本,低IoU的对作为负样本)。这是一种高度可行的训练策略,它避免了对“相似”版图进行昂贵的人工标注 35。 +* **预期性能:** 模型通过图匹配学习到的对结构关系的深刻理解,将远远优于简单的基于像素(IoU)或手工特征的比较方法。这将实现强大的IP模块识别、设计抄袭检测,并加速模拟版图的工艺迁移。 + +### 4.3. 应用三:预测性热点检测 + +* **问题定义:** 热点检测被定义为版图图上的节点分类任务。图中的每个节点(代表一个多边形或一个关键区域)被分类为“热点”或“非热点”。 +* **方法论:** + + 使用微调后的Geo-Layout Transformer的热点头执行分类任务。 + + 将在公认的公开基准数据集(如ICCAD 2012和更具挑战性的ICCAD 2019/2020)上进行训练和验证,以便与SOTA方法进行直接的、定量的比较 8。 +* **预期性能与优势:** + + **卓越的上下文感知能力:** Transformer的全局感受野是其关键优势。它能够建模长程物理现象,如光刻邻近效应、刻蚀负载效应和版图密度变化,这些现象会影响热点的形成,但对于局部模式匹配器或纯CNN/GNN模型是不可见的 7。 + + **降低误报率:** 通过理解更广泛的版图上下文,模型能更准确地区分几何上相似但一个是良性、另一个是恶性的图形,从而显著降低困扰当前方法的高昂的误报率 8。 + + **增强的泛化能力:** SSL预训练阶段将为模型提供关于有效版图模式的强大先验知识,使其能够比仅在固定的已知热点库上训练的模型更有效地检测新颖的、前所未见的热点类型 48。 + +Geo-Layout Transformer的最高价值在于其能够为这三个看似独立的应用程序提供一个**单一、统一的表示**。在当前的EDA流程中,DRC/LVS(连通性)、IP管理(匹配)和DFM(热点)由不同的、高度专业化的工具和团队处理。然而,Geo-Layout Transformer提出,这三个任务的核心智力挑战——深刻理解版图的几何和电气语义——在根本上是相同的。通过使用一个强大的基础模型一次性解决这个核心的表示学习问题,开发单个应用工具就变成了微调特定头的简单任务。这一理念预示着EDA研发的战略转变,即从构建孤立的点解决方案,转向创建一个可以在整个后端流程中复用的、核心的“版图理解引擎”。 + +## 5. 实施路线设想 + +### 5.1. 阶段一:数据整理与基础模型开发 + +* **任务1:构建可扩展的GDSII到图的流水线。** + + 评估并选择高性能的库,如gdstk (C++/Python),因其处理速度和先进的几何运算能力而备受青睐 31。 + + 开发一个并行化的数据处理流水线,能够将TB级的GDSII数据高效地转换为所提出的异构图格式,并针对PyTorch Geometric等ML框架的存储和加载进行优化。 +* **任务2:整理和处理数据集。** + + 系统地下载、解析和准备用于微调和评估阶段的公开基准数据集,包括用于热点检测的ICCAD 2012/2019/2020 39,以及来自GNN4IC中心等资源的相关电路数据集 11。 + + 启动大规模的内部数据整理计划,处理跨多个工艺节点的、多样化的专有、未标记GDSII设计。这些数据将是自监督预训练的燃料。 + +**表3:可用于模型训练和基准测试的公开数据集** + +| | | | | | +| --- | --- | --- | --- | --- | +| 数据集名称 | 主要任务 | 描述与关键特征 | 数据格式 | 来源/参考文献 | +| **ICCAD 2012 Contest** | 热点检测 | 广泛使用的基准,但模式被认为相对简单 | 版图片段 | 8 | +| **ICCAD 2019/2020** | 热点检测 | 更具挑战性,包含现代通孔层热点,更好地反映当前DFM问题 | 版图片段 | 39 | +| **RPLAN / Rico (UI)** | 版图匹配 | 用于训练结构相似性模型的平面图和用户界面数据集 | JSON/图像 | 46 | +| **CircuitNet** | 时序、可布线性、IR-Drop | 包含网表和布线后数据的大规模数据集,可用于相关物理设计任务的预训练 | Bookshelf, SPEF | 51 | +| **GNN4IC Hub Benchmarks** | 多样化(安全、可靠性、EDA) | 为各种IC相关的GNN任务策划的基准集合 | 多样 | 11 | + +* **任务3:开发和训练自监督基础模型。** + + 实现所提出的混合GNN-Transformer骨干架构。 + + 实现“掩码版图建模”自监督学习任务 36。 + + 确保并配置必要的高性能计算(HPC)基础设施(例如,一个由A100/H100 GPU组成的集群),以支持这一大规模的训练工作。 + +### 5.2. 阶段二:针对目标应用的微调与验证 + +* **任务1:开发和微调特定任务头。** + + 为连通性、匹配和热点检测任务实现轻量级的预测头。 + + 在已标记的公开和专有数据集上进行系统的微调实验。 +* **任务2:严格的基准测试和消融研究。** + + 针对每个应用,将微调后的模型与已发表的SOTA结果进行直接比较(例如,与 8 比较热点检测,与 35 比较匹配)。 + + 进行全面的消融研究,以经验性地验证关键的架构决策(例如,GNN编码器的影响、不同位置编码类型的贡献、预训练的价值)。 +* **任务3:开发模型可解释性工具。** + + 实现可视化Transformer注意力图的方法,允许设计人员直观地看到模型在进行特定预测时关注了版图的哪些部分。这对于调试和建立用户信任至关重要 15。 + +### 5.3. 阶段三:扩展、优化与集成 + +* **任务1:解决全芯片可扩展性问题。** + + 研究并实现先进的技术,如图分割和采样(例如,Cluster-GCN, GraphSAINT),使模型能够处理超出单个GPU内存容量的全芯片版图 10。 + + 研究模型优化技术,如量化和知识蒸馏,以创建更小、更快的模型,用于交互式应用场景。 +* **任务2:为EDA工具集成开发API。** + + 设计并构建一个健壮的、版本化的API,允许现有的EDA工具(如版图编辑器、验证平台)调用Geo-Layout Transformer进行按需分析。 +* **任务3:试点部署与持续学习。** + + 与选定的设计团队启动一个试点项目,将模型集成到他们的工作流程中。 + + 建立一个反馈循环,收集错误的预测和具有挑战性的案例,用于持续地微调和改进模型。 + +### 5.4. 已识别的挑战与缓解策略 + +* **数据不平衡:** 关键事件(如热点或DRC违规)在数据集中本质上是罕见的。 + + **缓解策略:** 采用先进的损失函数(如focal loss)、复杂的数据采样策略(对稀有事件进行过采样),并将问题构建在异常检测的框架内 9。 +* **计算成本:** 训练大型基础模型的资源消耗巨大。 + + **缓解策略:** 在Transformer中利用稀疏注意力机制,使用高效的图数据结构,并投资于专用的硬件加速器。SSL预训练是一次性成本,可以分摊到多个下游任务中 2。 +* **模型可解释性(“黑箱”问题):** 设计人员在没有合理解释的情况下,不愿信任模型的预测。 + + **缓解策略:** 优先开发可解释性工具,如注意力可视化和特征归因方法,以便在提供预测的同时提供可操作的见解 15。 +* **IP与数据隐私:** 设计数据是高度机密的。 + + **缓解策略:** SSL基础模型方法是主要的缓解措施,因为它允许组织在自己的私有数据上进行训练。对于多组织合作,联邦学习是一个可行的未来方向 16。 + +## 6. 结论与未来展望 + +Geo-Layout Transformer代表了EDA行业的一项战略性、变革性的技术。它通过一个通用的、深度学习的表示,统一了多个分散的后端分析任务。本报告阐述的路线图证明了其技术上的可行性,并揭示了其通过加速设计周期和提高芯片质量所带来的巨大投资回报潜力。 + +展望未来,Geo-Layout Transformer的成功将为物理设计自动化开辟更广阔的前景: + +* **扩展到更多任务:** 将这个统一的模型扩展到其他关键的后端分析任务,如可布线性预测、IR-Drop分析和详细的时序预测。 +* **从分析到综合:** 利用模型学习到的强大表示,在一个生成式框架(如扩散模型或GANs)中,自动生成优化的、“构建即正确”(correct-by-construction)的版图模式,实现从“验证设计”到“生成设计”的飞跃。 +* **多模态EDA:** 最终的愿景是创建一个能够将版图图与其他设计模态(如逻辑网表图和文本化的设计规范)相集成的模型。这将实现对整个芯片设计过程的真正全面的、跨领域的理解,最终赋能一个更加自动化、智能和高效的芯片设计未来 53。 + +#### 引用的著作 + +1. Feature Learning and Optimization in VLSI CAD - CSE, CUHK, +2. Integrating Deep Learning into VLSI Technology: Challenges and Opportunities, +3. AI and machine learning-driven optimization for physical design in advanced node semiconductors, +4. Machine Learning in Physical Verification, Mask Synthesis, and Physical Design - Yibo Lin, +5. VLSI Placement Optimization using Graph Neural Networks - ML For Systems, +6. Cross-Stage Machine Learning (ML) Integration for Adaptive Power, Performance and Area (PPA) Optimization in Nanochips - International Journal of Communication Networks and Information Security (IJCNIS), +7. Learning-Driven Physical Verification - CUHK CSE, +8. Efficient Hotspot Detection via Graph Neural Network - CUHK CSE, +9. Application of Deep Learning in Back-End Simulation: Challenges and Opportunities, +10. Accelerating GNN Training through Locality-aware Dropout and Merge - arXiv, +11. Graph Neural Networks: A Powerful and Versatile Tool for ... - arXiv, +12. Seminar Series 2022/2023 - CUHK CSE, +13. Generalizable Cross-Graph Embedding for GNN-based Congestion Prediction - arXiv, +14. VLSI Hypergraph Partitioning with Deep Learning - arXiv, +15. Interpretable CNN-Based Lithographic Hotspot Detection Through Error Marker Learning - hkust (gz), +16. The composition of ICCAD 2012 benchmark suite. - ResearchGate, +17. Full article: Advances in spatiotemporal graph neural network prediction research, +18. GATMesh: Clock Mesh Timing Analysis using Graph Neural ... - arXiv, +19. Recent Research Progress of Graph Neural Networks in Computer Vision - MDPI, +20. Graph Neural Network and Some of GNN Applications: Everything You Need to Know, +21. ParaGraph: Layout Parasitics and Device Parameter Prediction using Graph Neural Networks - Research at NVIDIA, +22. Positional Embeddings in Transformer Models: Evolution from Text to Vision Domains | ICLR Blogposts 2025 - Cloudfront.net, +23. A Survey of Graph Transformers: Architectures, Theories and Applications - arXiv, +24. Exploring Spatial-Based Position Encoding for Image Captioning - MDPI, +25. A Gentle Introduction to Positional Encoding in Transformer Models, Part 1 - MachineLearningMastery.com, +26. s-chh/2D-Positional-Encoding-Vision-Transformer - GitHub, +27. SpatialFormer: Towards Generalizable Vision Transformers with Explicit Spatial Understanding, +28. A 2D Semantic-Aware Position Encoding for Vision Transformers - arXiv, +29. Hybrid GNN and Transformer Models for Cross-Domain Entity Resolution in Cloud-Native Applications - ResearchGate, +30. The architecture of GNN Transformers. They can be seen as a combination... - ResearchGate, +31. Gdstk (GDSII Tool Kit) is a C++/Python library for creation and manipulation of GDSII and OASIS files. - GitHub, +32. purdue-onchip/gds2Para: GDSII File Parsing, IC Layout Analysis, and Parameter Extraction - GitHub, +33. Welcome to python-gdsii's documentation! - Pythonhosted.org, +34. python-gdsii - PyPI, +35. LayoutGMN: Neural Graph Matching for ... - CVF Open Access, +36. [2503.22143] A Self-Supervised Learning of a Foundation Model for Analog Layout Design Automation - arXiv, +37. [2301.08243] Self-Supervised Learning from Images with a Joint-Embedding Predictive Architecture - arXiv, +38. [2210.10807] Self-Supervised Representation Learning for CAD - arXiv, +39. Hotspot Detection via Attention-based Deep Layout Metric Learning - CUHK CSE, +40. HashGNN - Neo4j Graph Data Science, +41. Efficient Hotspot Detection via Graph Neural Network | Request PDF - ResearchGate, +42. PowerGNN: A Topology-Aware Graph Neural Network for Electricity Grids - arXiv, +43. PowerGNN: A Topology-Aware Graph Neural Network for Electricity Grids - arXiv, +44. LayoutGMN: Neural Graph Matching for Structural Layout Similarity | Request PDF, +45. Neural Graph Matching for Pre-training Graph Neural Networks - Binbin Hu, +46. agp-ka32/LayoutGMN-pytorch: Pytorch implementation of ... - GitHub, +47. Autoencoder-Based Data Sampling for Machine Learning-Based Lithography Hotspot Detection, +48. 62 Efficient Layout Hotspot Detection via Neural Architecture Search - CUHK CSE, +49. Lithography Hotspot Detection Method Based on Transfer Learning Using Pre-Trained Deep Convolutional Neural Network - MDPI, +50. DfX-NYUAD/GNN4IC: Must-read papers on Graph Neural ... - GitHub, +51. CIRCUITNET 2.0: AN ADVANCED DATASET FOR PRO- MOTING MACHINE LEARNING INNOVATIONS IN REAL- ISTIC CHIP DESIGN ENVIRONMENT, +52. GNN-CNN: An Efficient Hybrid Model of Convolutional and Graph Neural Networks for Text Representation - arXiv, +53. The Dawn of AI-Native EDA: Promises and Challenges of Large Circuit Models - arXiv, +54. (PDF) Large circuit models: opportunities and challenges - ResearchGate, \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8eecbc --- /dev/null +++ b/README.md @@ -0,0 +1,116 @@ +# Geo-Layout Transformer + +**A Unified, Self-Supervised Foundation Model for Physical Design Analysis** + +--- + +## 1. Vision + +The **Geo-Layout Transformer** is a research project aimed at creating a paradigm shift in Electronic Design Automation (EDA) for physical design. Instead of relying on a fragmented set of heuristic-based tools, we are building a single, unified foundation model that understands the deep, contextual "language" of semiconductor layouts. + +By leveraging a novel hybrid **Graph Neural Network (GNN) + Transformer** architecture and pre-training on massive amounts of unlabeled GDSII data, this model can be fine-tuned to excel at a variety of critical back-end analysis tasks, including: + +* **High-Precision Connectivity Verification**: Detecting opens and shorts by understanding the layout topology. +* **Structural Layout Matching**: Enabling IP reuse and design similarity search. +* **Predictive Hotspot Detection**: Identifying manufacturability issues with high accuracy and low false positives. + +Our vision is to move from disparate, task-specific tools to a centralized, reusable "Layout Understanding Engine" that accelerates the design cycle and pushes the boundaries of PPA (Power, Performance, and Area). + +## 2. Core Architecture + +The model's architecture is designed to hierarchically process layout information, mimicking how a human expert analyzes a design from local details to global context. + +![Architecture Diagram](https://i.imgur.com/example.png) + +1. **GDSII to Graph Pipeline**: We parse raw GDSII/OASIS files into a rich, heterogeneous graph representation. Each layout "patch" is converted into a graph where polygons and vias are **nodes**, and their physical adjacencies and connectivity are **edges**. + +2. **GNN Patch Encoder**: A powerful Graph Neural Network (specifically, a Relational Graph Attention Network - RGAT) acts as a "local rule learner". It processes the graph of each patch, encoding the complex local geometries and inter-layer relationships into a single, rich feature vector (embedding). This embedding represents a high-level semantic summary of the patch. + +3. **Global Transformer Backbone**: The sequence of patch embeddings is fed into a Transformer model. Crucially, we inject **hybrid 2D positional encodings** (both absolute and relative) to inform the model of each patch's spatial location. The Transformer's self-attention mechanism allows it to detect long-range dependencies, repetitive structures (like standard cell arrays), and global contextual patterns across the entire chip. + +4. **Task-Specific Heads**: The final, context-aware embeddings from the Transformer are fed into simple, lightweight neural network "heads" for specific downstream tasks. This modular design allows the core model to be adapted to new applications with minimal effort. + +## 3. Getting Started + +### 3.1. Prerequisites + +* Python 3.9+ +* A Conda environment is highly recommended. +* Access to EDA tools for generating labeled data (e.g., a DRC engine for hotspot labels). + +### 3.2. Installation + +1. **Clone the repository:** + ```bash + git clone https://github.com/your-username/Geo-Layout-Transformer.git + cd Geo-Layout-Transformer + ``` + +2. **Create and activate the Conda environment:** + ```bash + conda create -n geo_trans python=3.9 + conda activate geo_trans + ``` + +3. **Install dependencies:** + This project requires PyTorch and PyTorch Geometric (PyG). Please follow the official installation instructions for your specific CUDA version. + + * **PyTorch:** [https://pytorch.org/get-started/locally/](https://pytorch.org/get-started/locally/) + * **PyG:** [https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html](https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html) + + After installing PyTorch and PyG, install the remaining dependencies: + ```bash + pip install -r requirements.txt + ``` + *(Note: You may need to install `klayout` separately via its own package manager or build from source to enable its Python API).* + +## 4. Project Usage + +The project workflow is divided into two main stages: data preprocessing and model training. + +### 4.1. Stage 1: Data Preprocessing + +The first step is to convert your GDSII/OASIS files into a graph dataset that the model can consume. + +1. Place your layout files in the `data/gds/` directory. +2. Configure the preprocessing parameters in `configs/default.yaml`. You will need to define patch size, stride, layer mappings, and how to construct graph edges. +3. Run the preprocessing script: + ```bash + python scripts/preprocess_gds.py --config-file configs/default.yaml --gds-file data/gds/my_design.gds --output-dir data/processed/my_design/ + ``` + This script will parse the GDS file, divide it into patches, construct a graph for each patch, and save the processed data as `.pt` files for efficient loading. + +### 4.2. Stage 2: Model Training + +Once the dataset is ready, you can train the Geo-Layout Transformer. + +#### Self-Supervised Pre-training (Recommended) + +To build a powerful foundation model, we first pre-train it on unlabeled data using a "Masked Layout Modeling" task. + +```bash +python main.py --config-file configs/default.yaml --mode pretrain --data-dir data/processed/my_design/ +``` +This will train the model to understand the fundamental "grammar" of physical layouts without requiring any expensive labels. + +#### Supervised Fine-tuning + +After pre-training, you can fine-tune the model on a smaller, labeled dataset for a specific task like hotspot detection. + +1. Ensure your processed data includes labels. +2. Use a task-specific config file (e.g., `hotspot_detection.yaml`) that defines the model head and loss function. +3. Run the main script in `train` mode: + ```bash + python main.py --config-file configs/hotspot_detection.yaml --mode train --data-dir data/processed/labeled_hotspots/ --checkpoint-path /path/to/pretrained_model.pth + ``` + +## 5. Roadmap & Contribution + +This project is ambitious and we welcome contributions. Our future roadmap includes: + +- [ ] **Advanced Self-Supervised Tasks**: Exploring contrastive learning and other SSL methods. +- [ ] **Model Interpretability**: Implementing tools to visualize attention maps to understand the model's decisions. +- [ ] **Full-Chip Scalability**: Integrating graph partitioning techniques (e.g., Cluster-GCN) to handle chip-scale designs. +- [ ] **Generative Design**: Using the learned representations in a generative framework to synthesize "correct-by-construction" layouts. + +Please feel free to open an issue or submit a pull request. diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..c4a7496 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,116 @@ +# Geo-Layout Transformer + +**一个用于物理设计分析的统一、自监督基础模型** + +--- + +## 1. 项目愿景 + +**Geo-Layout Transformer** 是一个旨在推动电子设计自动化(EDA)物理设计领域范式转变的研究项目。我们不再依赖于一套零散的、基于启发式规则的工具,而是致力于构建一个统一的基础模型,使其能够理解半导体版图深层次的、上下文相关的“设计语言”。 + +通过利用新颖的 **图神经网络(GNN)+ Transformer** 混合架构,并在海量未标记的 GDSII 数据上进行预训练,该模型经过微调后,能够出色地完成各种关键的后端分析任务,包括: + +* **高精度连通性验证**:通过理解版图拓扑结构来检测开路和短路。 +* **结构化版图匹配**:实现 IP 复用和设计相似性搜索。 +* **预测性热点检测**:以高准确率和低误报率识别可制造性问题。 + +我们的愿景是,从目前分散的、任务特定的工具,演进为一个集中的、可复用的“版图理解引擎”,从而加速设计周期,并突破 PPA(功耗、性能、面积)的极限。 + +## 2. 核心架构 + +该模型的架构设计旨在分层处理版图信息,模仿人类专家从局部细节到全局上下文分析设计的过程。 + +![架构图](https://i.imgur.com/example.png) + +1. **GDSII 到图的处理流水线**:我们将原始的 GDSII/OASIS 文件解析成丰富的异构图表示。每个版图“区块”(Patch)被转换成一个图,其中多边形和通孔是**节点**,它们之间的物理邻接和连通关系是**边**。 + +2. **GNN 区块编码器**:一个强大的图神经网络(特指关系图注意力网络 - RGAT)作为“局部规则学习器”。它处理每个区块的图,将复杂的局部几何形状和层间关系编码成一个单一的、丰富的特征向量(嵌入)。这个嵌入向量代表了对该区块的高度语义化总结。 + +3. **全局 Transformer 骨干网络**:区块嵌入序列被送入一个 Transformer 模型。至关重要的是,我们注入了**混合二维位置编码**(包括绝对和相对位置),以告知模型每个区块的空间位置。Transformer 的自注意力机制使其能够检测长程依赖关系、重复结构(如标准单元阵列)以及整个芯片的全局上下文模式。 + +4. **特定任务头**:从 Transformer 输出的、具有全局上下文感知能力的最终嵌入,被送入简单、轻量级的神经网络“头”(Head)中,以执行特定的下游任务。这种模块化设计使得核心模型能够以最小的代价适应新的应用。 + +## 3. 快速上手 + +### 3.1. 环境要求 + +* Python 3.9+ +* 强烈建议使用 Conda 进行环境管理。 +* 能够访问 EDA 工具以生成带标签的数据(例如,使用 DRC 工具生成热点标签)。 + +### 3.2. 安装步骤 + +1. **克隆代码仓库:** + ```bash + git clone https://github.com/your-username/Geo-Layout-Transformer.git + cd Geo-Layout-Transformer + ``` + +2. **创建并激活 Conda 环境:** + ```bash + conda create -n geo_trans python=3.9 + conda activate geo_trans + ``` + +3. **安装依赖:** + 本项目需要 PyTorch 和 PyTorch Geometric (PyG)。请根据您的 CUDA 版本遵循官方指南进行安装。 + + * **PyTorch:** [https://pytorch.org/get-started/locally/](https://pytorch.org/get-started/locally/) + * **PyG:** [https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html](https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html) + + 安装完 PyTorch 和 PyG 后,安装其余的依赖项: + ```bash + pip install -r requirements.txt + ``` + *(注意:您可能需要通过 `klayout` 自身的包管理器或从源码编译来单独安装它,以启用其 Python API)。* + +## 4. 项目使用 + +项目的工作流程分为两个主要阶段:数据预处理和模型训练。 + +### 4.1. 阶段一:数据预处理 + +第一步是将您的 GDSII/OASIS 文件转换为模型可以使用的图数据集。 + +1. 将您的版图文件放入 `data/gds/` 目录。 +2. 在 `configs/default.yaml` 中配置预处理参数。您需要定义区块大小、步长、层映射以及图边的构建方式。 +3. 运行预处理脚本: + ```bash + python scripts/preprocess_gds.py --config-file configs/default.yaml --gds-file data/gds/my_design.gds --output-dir data/processed/my_design/ + ``` + 该脚本将解析 GDS 文件,将其划分为多个区块,为每个区块构建一个图,并将处理后的数据保存为 `.pt` 文件以便高效加载。 + +### 4.2. 阶段二:模型训练 + +数据集准备就绪后,您就可以开始训练 Geo-Layout Transformer。 + +#### 自监督预训练(推荐) + +为了构建一个强大的基础模型,我们首先在无标签数据上使用“掩码版图建模”任务对其进行预训练。 + +```bash +python main.py --config-file configs/default.yaml --mode pretrain --data-dir data/processed/my_design/ +``` +这将训练模型理解物理版图的基本“语法”,而无需任何昂贵的标签。 + +#### 监督微调 + +预训练之后,您可以在一个较小的、有标签的数据集上对模型进行微调,以适应像热点检测这样的特定任务。 + +1. 确保您处理好的数据包含标签。 +2. 使用一个特定于任务的配置文件(例如 `hotspot_detection.yaml`),其中定义了模型的任务头和损失函数。 +3. 在 `train` 模式下运行主脚本: + ```bash + python main.py --config-file configs/hotspot_detection.yaml --mode train --data-dir data/processed/labeled_hotspots/ --checkpoint-path /path/to/pretrained_model.pth + ``` + +## 5. 发展路线与贡献 + +这是一个宏伟的项目,我们欢迎任何形式的贡献。我们未来的发展路线图包括: + +- [ ] **更先进的自监督任务**:探索对比学习和其他 SSL 方法。 +- [ ] **模型可解释性**:实现可视化注意力图的工具,以理解模型的决策过程。 +- [ ] **全芯片可扩展性**:集成图分割技术(如 Cluster-GCN)来处理芯片规模的设计。 +- [ ] **生成式设计**:在生成式框架中使用学习到的表示来合成“构建即正确”的版图。 + +欢迎随时提出 Issue 或提交 Pull Request。 diff --git a/configs/default.yaml b/configs/default.yaml new file mode 100644 index 0000000..1e22f53 --- /dev/null +++ b/configs/default.yaml @@ -0,0 +1,49 @@ +# Default Configuration for Geo-Layout Transformer + +# 1. Data Preprocessing +data: + patch_size: 10.0 # in microns + patch_stride: 5.0 # in microns + layer_mapping: + "1/0": 0 # Example: GDS Layer 1, Datatype 0 -> Index 0 (e.g., M1) + "2/0": 1 # Example: GDS Layer 2, Datatype 0 -> Index 1 (e.g., VIA1) + "3/0": 2 # Example: GDS Layer 3, Datatype 0 -> Index 2 (e.g., M2) + graph_construction: + edge_strategy: "knn" # 'knn' or 'radius' + knn_k: 8 # K for KNN graph construction + radius_d: 1.0 # Radius for radius graph construction (in microns) + +# 2. Model Architecture +model: + # GNN Encoder + gnn: + node_input_dim: 5 # Initial node feature dim (e.g., x, y, w, h, area) + hidden_dim: 128 + output_dim: 256 # Dimension of the patch embedding + num_layers: 4 + gnn_type: "rgat" # 'rgat', 'gcn', 'graphsage' + + # Transformer Backbone + transformer: + num_layers: 6 + num_heads: 8 + hidden_dim: 256 # Must match gnn.output_dim + dropout: 0.1 + positional_encoding: + type: "hybrid" # 'hybrid', 'absolute', 'relative' + +# 3. Training +training: + mode: "train" # 'train', 'eval', 'pretrain' + batch_size: 32 + learning_rate: 0.0001 + epochs: 100 + optimizer: "adamw" + loss_function: "bce" # 'bce', 'focal_loss' + weight_decay: 0.01 + +# 4. Self-Supervised Pre-training +pretraining: + mask_ratio: 0.15 + epochs: 200 + learning_rate: 0.0005 diff --git a/configs/hotspot_detection.yaml b/configs/hotspot_detection.yaml new file mode 100644 index 0000000..d1cf0a9 --- /dev/null +++ b/configs/hotspot_detection.yaml @@ -0,0 +1,26 @@ +# Hotspot Detection Task Configuration + +# Inherits from default.yaml + +# 1. Data Preprocessing +data: + # For hotspot detection, we might need smaller, more focused patches + patch_size: 2.0 + patch_stride: 1.0 + +# 2. Model Architecture +model: + # Add a task-specific head for classification + task_head: + type: "classification" + input_dim: 256 # Must match transformer.hidden_dim + hidden_dim: 64 + output_dim: 1 # Binary classification (Hotspot / Not Hotspot) + +# 3. Training +training: + # Use a loss function suitable for imbalanced datasets + loss_function: "focal_loss" + # Task-specific learning rate might be different + learning_rate: 0.00005 + epochs: 50 diff --git a/main.py b/main.py new file mode 100644 index 0000000..6d670ab --- /dev/null +++ b/main.py @@ -0,0 +1,68 @@ +import argparse +from torch.utils.data import random_split + +from src.utils.config_loader import load_config, merge_configs +from src.utils.logging import get_logger +from src.data.dataset import LayoutDataset +from torch_geometric.data import DataLoader +from src.models.geo_layout_transformer import GeoLayoutTransformer +from src.engine.trainer import Trainer +from src.engine.evaluator import Evaluator +from src.engine.self_supervised import SelfSupervisedTrainer + +def main(): + parser = argparse.ArgumentParser(description="Geo-Layout Transformer 的主脚本。") + parser.add_argument("--config-file", required=True, help="特定于任务的配置文件的路径。") + parser.add_argument("--mode", choices=["train", "eval", "pretrain"], required=True, help="脚本运行模式。") + parser.add_argument("--data-dir", required=True, help="已处理图数据的目录。") + parser.add_argument("--checkpoint-path", help="要加载的模型检查点的路径。") + args = parser.parse_args() + + logger = get_logger("Main") + + # 加载配置 + logger.info("正在加载配置...") + # 首先加载基础配置,然后用任务特定配置覆盖 + base_config = load_config('configs/default.yaml') + task_config = load_config(args.config_file) + config = merge_configs(base_config, task_config) + + # 加载数据 + logger.info(f"从 {args.data_dir} 加载数据集") + dataset = LayoutDataset(root=args.data_dir) + + # TODO: 实现更完善的数据集划分逻辑 + # 这是一个简化的数据加载方式。在实际应用中,您需要将数据集划分为训练集、验证集和测试集。 + # 例如: + # train_size = int(0.8 * len(dataset)) + # val_size = len(dataset) - train_size + # train_dataset, val_dataset = random_split(dataset, [train_size, val_size]) + # train_loader = DataLoader(train_dataset, batch_size=config['training']['batch_size'], shuffle=True) + # val_loader = DataLoader(val_dataset, batch_size=config['training']['batch_size'], shuffle=False) + + train_loader = DataLoader(dataset, batch_size=config['training']['batch_size'], shuffle=True) + val_loader = DataLoader(dataset, batch_size=config['training']['batch_size'], shuffle=False) + + # 初始化模型 + logger.info("正在初始化模型...") + model = GeoLayoutTransformer(config) + if args.checkpoint_path: + logger.info(f"从 {args.checkpoint_path} 加载模型检查点") + # model.load_state_dict(torch.load(args.checkpoint_path)) + + # 根据模式运行 + if args.mode == 'pretrain': + logger.info("进入自监督预训练模式...") + trainer = SelfSupervisedTrainer(model, config) + trainer.run(train_loader) + elif args.mode == 'train': + logger.info("进入监督训练模式...") + trainer = Trainer(model, config) + trainer.run(train_loader, val_loader) + elif args.mode == 'eval': + logger.info("进入评估模式...") + evaluator = Evaluator(model) + evaluator.evaluate(val_loader) + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d97c6b9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "layouttrans" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e85ec6b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +torch +torch-geometric +gdstk +numpy +pyyaml +pandas +scikit-learn diff --git a/scripts/preprocess_gds.py b/scripts/preprocess_gds.py new file mode 100644 index 0000000..743ef9a --- /dev/null +++ b/scripts/preprocess_gds.py @@ -0,0 +1,90 @@ +import argparse +import os +from tqdm import tqdm +import torch +from torch_geometric.data import InMemoryDataset, Data + +from src.utils.config_loader import load_config +from src.data.gds_parser import GDSParser +from src.data.graph_constructor import GraphConstructor +from src.utils.logging import get_logger + +# 这是一个辅助的数据集类,仅用于在预处理脚本中保存数据 +class TempDataset(InMemoryDataset): + def __init__(self, root, data_list=None): + self.data_list = data_list + super(TempDataset, self).__init__(root) + self.data, self.slices = self.collate(data_list) + + @property + def raw_file_names(self): + return [] + + @property + def processed_file_names(self): + return ['data.pt'] + + def download(self): + pass + + def process(self): + # 数据已在外部处理好,直接保存 + torch.save((self.data, self.slices), self.processed_paths[0]) + +def main(): + parser = argparse.ArgumentParser(description="将 GDSII 文件预处理为图数据。") + parser.add_argument("--config-file", required=True, help="配置文件的路径。") + parser.add_argument("--gds-file", required=True, help="要处理的 GDSII 文件的路径。") + parser.add_argument("--output-dir", required=True, help="保存处理后图数据的目录。") + # 可以添加一个参数来指定标签文件,例如 DRC 报告 + # parser.add_argument("--label-file", help="标签文件的路径。") + args = parser.parse_args() + + logger = get_logger("GDS_Preprocessor") + + logger.info(f"从 {args.config_file} 加载配置") + config = load_config(args.config_file) + + logger.info(f"为 {args.gds_file} 初始化 GDSParser") + gds_parser = GDSParser(args.gds_file, config['data']['layer_mapping']) + + logger.info("初始化 GraphConstructor") + graph_constructor = GraphConstructor( + edge_strategy=config['data']['graph_construction']['edge_strategy'], + knn_k=config['data']['graph_construction']['knn_k'], + radius_d=config['data']['graph_construction']['radius_d'] + ) + + logger.info("正在生成区块...") + patches = gds_parser.get_patches(config['data']['patch_size'], config['data']['patch_stride']) + logger.info(f"生成了 {len(patches)} 个区块。") + + os.makedirs(args.output_dir, exist_ok=True) + + graph_list = [] + # 使用 tqdm 显示进度条 + for patch_bbox in tqdm(patches, desc="处理区块中"): + geometries = gds_parser.extract_geometries_from_patch(patch_bbox) + if geometries: + # 在真实场景中,您需要从 DRC 报告等来源获取标签 + # 在这个占位符中,我们假设一个虚拟标签 0 + # TODO: 实现从标签文件加载标签的逻辑 + graph = graph_constructor.construct_graph(geometries, label=0) + if graph: + # PyG 要求 Data 对象具有 y 属性 + if not hasattr(graph, 'y'): + graph.y = torch.tensor([0], dtype=torch.float) + graph_list.append(graph) + + logger.info(f"成功构建了 {len(graph_list)} 个图。") + + if graph_list: + # 使用 PyG 的 InMemoryDataset 格式保存数据,以便高效加载 + logger.info("正在将数据保存为 PyG InMemoryDataset 格式...") + dataset = TempDataset(root=args.output_dir, data_list=graph_list) + logger.info(f"已将处理好的数据保存到 {dataset.processed_paths[0]}") + else: + logger.warning("没有生成任何图数据,不进行保存。") + +if __name__ == "__main__": + main() diff --git a/scripts/visualize_attention.py b/scripts/visualize_attention.py new file mode 100644 index 0000000..7e85aab --- /dev/null +++ b/scripts/visualize_attention.py @@ -0,0 +1,63 @@ +import argparse +import torch +import matplotlib.pyplot as plt +import seaborn as sns + +from src.utils.config_loader import load_config +from src.models.geo_layout_transformer import GeoLayoutTransformer +from src.utils.logging import get_logger + +def main(): + parser = argparse.ArgumentParser(description="可视化来自已训练模型的注意力图。") + parser.add_argument("--config-file", required=True, help="模型配置文件的路径。") + parser.add_argument("--model-path", required=True, help="已训练模型检查点的路径。") + parser.add_argument("--patch-data", required=True, help="区块数据样本(.pt 文件)的路径。") + args = parser.parse_args() + + logger = get_logger("Attention_Visualizer") + + logger.info("这是一个用于注意力可视化的占位符脚本。") + logger.info("完整的实现需要加载一个训练好的模型、一个数据样本,然后提取注意力权重。") + + # 1. 加载配置和模型 + # logger.info("正在加载模型...") + # config = load_config(args.config_file) + # model = GeoLayoutTransformer(config) + # model.load_state_dict(torch.load(args.model_path)) + # model.eval() + + # 2. 加载一个数据样本 + # logger.info(f"正在加载数据样本从 {args.patch_data}") + # sample_data = torch.load(args.patch_data) + + # 3. 注册钩子(Hook)到模型中以提取注意力权重 + # 这是一个复杂的过程,需要访问 nn.MultiheadAttention 模块的前向传播过程。 + # attention_weights = [] + # def hook(module, input, output): + # # output[1] 是注意力权重 + # attention_weights.append(output[1]) + # model.transformer_core.transformer_encoder.layers[0].self_attn.register_forward_hook(hook) + + # 4. 运行一次前向传播以获取权重 + # logger.info("正在运行前向传播...") + # with torch.no_grad(): + # # 模型需要修改以支持返回注意力权重,或者通过钩子获取 + # _ = model(sample_data) + + # 5. 绘制注意力图 + # if attention_weights: + # logger.info("正在绘制注意力图...") + # # attention_weights[0] 的形状是 [batch_size, num_heads, seq_len, seq_len] + # # 我们取第一项,并在所有头上取平均值 + # avg_attention = attention_weights[0][0].mean(dim=0).cpu().numpy() + # plt.figure(figsize=(10, 10)) + # sns.heatmap(avg_attention, cmap='viridis') + # plt.title("区块之间的平均注意力图") + # plt.xlabel("区块索引") + # plt.ylabel("区块索引") + # plt.show() + # else: + # logger.warning("未能提取注意力权重。") + +if __name__ == "__main__": + main() diff --git a/src/data/dataset.py b/src/data/dataset.py new file mode 100644 index 0000000..9f8c9d9 --- /dev/null +++ b/src/data/dataset.py @@ -0,0 +1,37 @@ +import torch +from torch_geometric.data import Dataset, InMemoryDataset +import os + +class LayoutDataset(InMemoryDataset): + """用于加载预处理后的版图图数据的 PyTorch Geometric 数据集。""" + + def __init__(self, root, transform=None, pre_transform=None): + """ + Args: + root: 数据集应保存的根目录。 + transform: 一个函数/变换,作用于 `Data` 对象并返回一个转换后的版本。 + pre_transform: 一个函数/变换,作用于 `Data` 对象并返回一个转换后的版本。 + """ + super(LayoutDataset, self).__init__(root, transform, pre_transform) + # 加载已处理的数据 + self.data, self.slices = torch.load(self.processed_paths[0]) + + @property + def raw_file_names(self): + """如果 `download()` 返回一个路径列表,这里会返回它们的文件名。""" + return [] # 我们不从网络下载原始文件 + + @property + def processed_file_names(self): + """在 `processed_dir` 目录中必须存在的文件列表,用以跳过处理步骤。""" + return ['data.pt'] + + def download(self): + """从网上下载原始数据到 `raw_dir` 目录。""" + pass # 假设数据是预先处理好的 + + def process(self): + """处理原始数据并将其保存到 `processed_dir` 目录。""" + # 如果希望在加载时动态处理数据,可以在这里实现 `scripts/preprocess_gds.py` 中的逻辑。 + # 在我们的框架中,我们假设预处理是通过脚本独立完成的。 + pass diff --git a/src/data/gds_parser.py b/src/data/gds_parser.py new file mode 100644 index 0000000..d6350c2 --- /dev/null +++ b/src/data/gds_parser.py @@ -0,0 +1,68 @@ +from typing import List, Dict, Tuple +import gdstk +import numpy as np + +class GDSParser: + """解析 GDSII/OASIS 文件,提取指定区块内的版图几何图形。""" + + def __init__(self, gds_file: str, layer_mapping: Dict[str, int]): + """初始化 GDSParser。 + + Args: + gds_file: GDSII/OASIS 文件的路径。 + layer_mapping: 一个字典,将 GDS 的层/数据类型字符串(例如 "1/0")映射到整数索引。 + """ + self.gds_file = gds_file + self.layer_mapping = layer_mapping + # 使用 gdstk 读取 GDS 文件 + self.library = gdstk.read_gds(gds_file) + # 获取顶层单元 + self.top_cell = self.library.top_level()[0] + + def get_patches(self, patch_size: float, patch_stride: float) -> List[Tuple[float, float, float, float]]: + """生成覆盖整个版图的区块坐标。 + + Args: + patch_size: 正方形区块的尺寸(单位:微米)。 + patch_stride: 滑动窗口的步长(单位:微米)。 + + Returns: + 一个包含所有区块边界框 (x_min, y_min, x_max, y_max) 的列表。 + """ + # 获取顶层单元的边界框 + x_min, y_min, x_max, y_max = self.top_cell.bb() + patches = [] + # 使用步长在 x 和 y 方向上生成区块 + for x in np.arange(x_min, x_max, patch_stride): + for y in np.arange(y_min, y_max, patch_stride): + patches.append((x, y, x + patch_size, y + patch_size)) + return patches + + def extract_geometries_from_patch(self, patch_bbox: Tuple[float, float, float, float]) -> List[Dict]: + """从给定的区块中提取所有几何对象。 + + Args: + patch_bbox: 区块的边界框 (x_min, y_min, x_max, y_max)。 + + Returns: + 一个字典列表,每个字典代表一个几何对象及其属性(多边形、层、边界框)。 + """ + x_min, y_min, x_max, y_max = patch_bbox + # 获取单元内的所有多边形 + polygons = self.top_cell.get_polygons(by_spec=True) + geometries = [] + # 遍历所有多边形 + for (layer, datatype), poly_list in polygons.items(): + layer_str = f"{layer}/{datatype}" + # 只处理在 layer_mapping 中定义的层 + if layer_str in self.layer_mapping: + for poly in poly_list: + # 简单的边界框相交检查 + p_xmin, p_ymin, p_xmax, p_ymax = poly.bb() + if not (p_xmax < x_min or p_xmin > x_max or p_ymax < y_min or p_ymin > y_max): + geometries.append({ + "polygon": poly, + "layer": self.layer_mapping[layer_str], + "bbox": (p_xmin, p_ymin, p_xmax, p_ymax) + }) + return geometries diff --git a/src/data/graph_constructor.py b/src/data/graph_constructor.py new file mode 100644 index 0000000..147229a --- /dev/null +++ b/src/data/graph_constructor.py @@ -0,0 +1,83 @@ +from typing import List, Dict +import torch +from torch_geometric.data import Data +from scipy.spatial import cKDTree +import numpy as np + +class GraphConstructor: + """从几何图形列表中构建 PyTorch Geometric 的 Data 对象(即图)。""" + + def __init__(self, edge_strategy: str = "knn", knn_k: int = 8, radius_d: float = 1.0): + """ + Args: + edge_strategy: 创建边的策略('knn' 或 'radius')。 + knn_k: KNN 策略中的 K(最近邻的数量)。 + radius_d: 半径图策略中的半径大小。 + """ + self.edge_strategy = edge_strategy + self.knn_k = knn_k + self.radius_d = radius_d + + def construct_graph(self, geometries: List[Dict], label: int = 0) -> Data: + """为单个区块构建一个图。 + + Args: + geometries: 来自 GDSParser 的几何图形字典列表。 + label: 图的标签(例如,0 表示非热点,1 表示热点)。 + + Returns: + 一个 PyTorch Geometric 的 Data 对象。 + """ + # 如果没有几何图形,则返回 None + if not geometries: + return None + + node_features = [] + node_positions = [] + # 提取每个几何图形的特征 + for geo in geometries: + x_min, y_min, x_max, y_max = geo["bbox"] + width = x_max - x_min + height = y_max - y_min + area = width * height + centroid_x = x_min + width / 2 + centroid_y = y_min + height / 2 + + # 特征包括:中心点坐标、宽度、高度、面积 + features = [centroid_x, centroid_y, width, height, area] + node_features.append(features) + node_positions.append([centroid_x, centroid_y]) + + # 将特征和位置转换为 PyTorch 张量 + x = torch.tensor(node_features, dtype=torch.float) + pos = torch.tensor(node_positions, dtype=torch.float) + + # 根据选定的策略创建边 + edge_index = self._create_edges(pos) + + # 创建图数据对象 + data = Data(x=x, edge_index=edge_index, pos=pos, y=torch.tensor([label], dtype=torch.float)) + return data + + def _create_edges(self, node_positions: torch.Tensor) -> torch.Tensor: + """根据选定的策略创建边。""" + nodes_np = node_positions.numpy() + if self.edge_strategy == "knn": + # 使用 cKDTree 进行高效的 K 最近邻搜索 + tree = cKDTree(nodes_np) + # 查询每个点的 k+1 个最近邻(包括自身) + dist, ind = tree.query(nodes_np, k=self.knn_k + 1) + # 创建边列表,排除自环 + row = np.repeat(np.arange(len(nodes_np)), self.knn_k) + col = ind[:, 1:].flatten() + edge_index = torch.tensor([row, col], dtype=torch.long) + + elif self.edge_strategy == "radius": + # 使用 cKDTree 查找在指定半径内的所有点对 + tree = cKDTree(nodes_np) + pairs = tree.query_pairs(r=self.radius_d) + edge_index = torch.tensor(list(pairs), dtype=torch.long).t().contiguous() + else: + raise ValueError(f"未知的边构建策略: {self.edge_strategy}") + + return edge_index diff --git a/src/data/init.py b/src/data/init.py new file mode 100644 index 0000000..e69de29 diff --git a/src/engine/evaluator.py b/src/engine/evaluator.py new file mode 100644 index 0000000..ce71853 --- /dev/null +++ b/src/engine/evaluator.py @@ -0,0 +1,46 @@ +import torch +from torch_geometric.data import DataLoader +from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score +from ..utils.logging import get_logger + +class Evaluator: + """处理模型评估。""" + + def __init__(self, model): + self.model = model + self.logger = get_logger(self.__class__.__name__) + + def evaluate(self, dataloader: DataLoader): + """在给定的数据集上评估模型。""" + self.model.eval() # 将模型设置为评估模式 + all_preds = [] + all_labels = [] + + # 在没有梯度计算的上下文中进行评估 + with torch.no_grad(): + for batch in dataloader: + output = self.model(batch) + # 使用 sigmoid 将 logits 转换为概率,然后以 0.5 为阈值进行分类 + preds = torch.sigmoid(output) > 0.5 + all_preds.append(preds.cpu()) + all_labels.append(batch.y.cpu()) + + # 将所有批次的预测和标签连接起来 + all_preds = torch.cat(all_preds).numpy() + all_labels = torch.cat(all_labels).numpy() + + # 计算各种评估指标 + accuracy = accuracy_score(all_labels, all_preds) + precision = precision_score(all_labels, all_preds) + recall = recall_score(all_labels, all_preds) + f1 = f1_score(all_labels, all_preds) + auc = roc_auc_score(all_labels, all_preds) + + self.logger.info(f"评估结果:") + self.logger.info(f" 准确率 (Accuracy): {accuracy:.4f}") + self.logger.info(f" 精确率 (Precision): {precision:.4f}") + self.logger.info(f" 召回率 (Recall): {recall:.4f}") + self.logger.info(f" F1 分数 (F1-Score): {f1:.4f}") + self.logger.info(f" AUC-ROC: {auc:.4f}") + + return {"accuracy": accuracy, "precision": precision, "recall": recall, "f1": f1, "auc": auc} diff --git a/src/engine/init.py b/src/engine/init.py new file mode 100644 index 0000000..e69de29 diff --git a/src/engine/self_supervised.py b/src/engine/self_supervised.py new file mode 100644 index 0000000..eae53af --- /dev/null +++ b/src/engine/self_supervised.py @@ -0,0 +1,77 @@ +import torch +import torch.nn as nn +from torch.optim import AdamW +from torch_geometric.data import DataLoader +from ..utils.logging import get_logger + +class SelfSupervisedTrainer: + """处理自监督预训练循环(掩码版图建模)。""" + + def __init__(self, model, config): + self.model = model + self.config = config + self.logger = get_logger(self.__class__.__name__) + self.optimizer = AdamW(self.model.parameters(), lr=config['pretraining']['learning_rate']) + # 使用均方误差损失来重建嵌入向量 + self.criterion = nn.MSELoss() + + def train_epoch(self, dataloader: DataLoader): + """运行单个预训练周期。""" + self.model.train() + total_loss = 0 + mask_ratio = self.config['pretraining']['mask_ratio'] + + for batch in dataloader: + self.optimizer.zero_grad() + + # 1. 获取原始的区块嵌入(作为重建的目标) + with torch.no_grad(): + original_embeddings = self.model.gnn_encoder(batch) + + # 2. 创建掩码并损坏输入 + num_patches = original_embeddings.size(0) + num_masked = int(mask_ratio * num_patches) + # 随机选择要掩盖的区块索引 + masked_indices = torch.randperm(num_patches)[:num_masked] + + # 创建一个损坏的嵌入副本 + # 这是一个简化的方法。更稳健的方法是直接在批次数据中掩盖特征。 + # 在这个占位符中,我们直接掩盖嵌入向量。 + corrupted_embeddings = original_embeddings.clone() + # 创建一个可学习的 [MASK] 嵌入 + mask_embedding = nn.Parameter(torch.randn(original_embeddings.size(1), device=original_embeddings.device)) + corrupted_embeddings[masked_indices] = mask_embedding + + # 3. 为 Transformer 重塑形状 + num_graphs = batch.num_graphs + nodes_per_graph = batch.ptr[1:] - batch.ptr[:-1] + corrupted_embeddings = corrupted_embeddings.view(num_graphs, nodes_per_graph[0], -1) + + # 4. 将损坏的嵌入传入 Transformer 进行重建 + # 注意:这里只用了 transformer_core,没有用 task_head + reconstructed_embeddings = self.model.transformer_core(corrupted_embeddings) + + # 5. 只在被掩盖的区块上计算损失 + # 将 Transformer 输出和原始嵌入都拉平成 (N, D) 的形状 + reconstructed_flat = reconstructed_embeddings.view(-1, original_embeddings.size(1)) + # 只选择被掩盖的那些进行比较 + loss = self.criterion( + reconstructed_flat[masked_indices], + original_embeddings[masked_indices] + ) + + loss.backward() + self.optimizer.step() + total_loss += loss.item() + + avg_loss = total_loss / len(dataloader) + self.logger.info(f"预训练损失: {avg_loss:.4f}") + return avg_loss + + def run(self, train_loader: DataLoader): + """运行完整的预训练流程。""" + self.logger.info("开始自监督预训练...") + for epoch in range(self.config['pretraining']['epochs']): + self.logger.info(f"周期 {epoch+1}/{self.config['pretraining']['epochs']}") + self.train_epoch(train_loader) + self.logger.info("预训练完成。") diff --git a/src/engine/trainer.py b/src/engine/trainer.py new file mode 100644 index 0000000..ec0ea5f --- /dev/null +++ b/src/engine/trainer.py @@ -0,0 +1,65 @@ +import torch +import torch.nn as nn +from torch.optim import Adam, AdamW +from torch_geometric.data import DataLoader +from ..utils.logging import get_logger + +class Trainer: + """处理(监督学习)训练循环。""" + + def __init__(self, model, config): + self.model = model + self.config = config + self.logger = get_logger(self.__class__.__name__) + + # 根据配置选择优化器 + if config['training']['optimizer'] == 'adam': + self.optimizer = Adam(self.model.parameters(), lr=config['training']['learning_rate'], weight_decay=config['training']['weight_decay']) + elif config['training']['optimizer'] == 'adamw': + self.optimizer = AdamW(self.model.parameters(), lr=config['training']['learning_rate'], weight_decay=config['training']['weight_decay']) + else: + raise ValueError(f"不支持的优化器: {config['training']['optimizer']}") + + # 根据配置选择损失函数 + if config['training']['loss_function'] == 'bce': + # BCEWithLogitsLoss 结合了 Sigmoid 和 BCELoss,更数值稳定 + self.criterion = nn.BCEWithLogitsLoss() + # 在此添加其他损失函数,如 focal loss + else: + raise ValueError(f"不支持的损失函数: {config['training']['loss_function']}") + + def train_epoch(self, dataloader: DataLoader): + """运行单个训练周期(epoch)。""" + self.model.train() # 将模型设置为训练模式 + total_loss = 0 + for batch in dataloader: + self.optimizer.zero_grad() # 清空梯度 + + # 前向传播 + output = self.model(batch) + + # 准备目标标签 + # 假设标签在图级别,并且需要调整形状以匹配输出 + target = batch.y.view_as(output) + + # 计算损失 + loss = self.criterion(output, target) + # 反向传播 + loss.backward() + # 更新权重 + self.optimizer.step() + + total_loss += loss.item() + + avg_loss = total_loss / len(dataloader) + self.logger.info(f"训练损失: {avg_loss:.4f}") + return avg_loss + + def run(self, train_loader: DataLoader, val_loader: DataLoader): + """运行完整的训练流程。""" + self.logger.info("开始训练...") + for epoch in range(self.config['training']['epochs']): + self.logger.info(f"周期 {epoch+1}/{self.config['training']['epochs']}") + self.train_epoch(train_loader) + # 在此处添加验证步骤,例如调用 Evaluator + self.logger.info("训练完成。") diff --git a/src/init.py b/src/init.py new file mode 100644 index 0000000..e69de29 diff --git a/src/models/geo_layout_transformer.py b/src/models/geo_layout_transformer.py new file mode 100644 index 0000000..0c94032 --- /dev/null +++ b/src/models/geo_layout_transformer.py @@ -0,0 +1,84 @@ +import torch +import torch.nn as nn +from .gnn_encoder import GNNEncoder +from .transformer_core import TransformerCore +from .task_heads import ClassificationHead, MatchingHead + +class GeoLayoutTransformer(nn.Module): + """完整的 Geo-Layout Transformer 模型。""" + + def __init__(self, config: dict): + """初始化模型。 + + Args: + config: 包含所有模型超参数的配置字典。 + """ + super(GeoLayoutTransformer, self).__init__() + self.config = config + + # 1. GNN 编码器:用于将每个版图区块(patch)编码为嵌入向量 + self.gnn_encoder = GNNEncoder( + node_input_dim=config['model']['gnn']['node_input_dim'], + hidden_dim=config['model']['gnn']['hidden_dim'], + output_dim=config['model']['gnn']['output_dim'], + num_layers=config['model']['gnn']['num_layers'], + gnn_type=config['model']['gnn']['gnn_type'] + ) + + # 2. Transformer 骨干网络:用于捕捉区块之间的全局上下文关系 + self.transformer_core = TransformerCore( + hidden_dim=config['model']['transformer']['hidden_dim'], + num_layers=config['model']['transformer']['num_layers'], + num_heads=config['model']['transformer']['num_heads'], + dropout=config['model']['transformer']['dropout'] + ) + + # 3. 特定于任务的头:根据配置动态创建 + self.task_head = None + if 'task_head' in config['model']: + head_config = config['model']['task_head'] + if head_config['type'] == 'classification': + self.task_head = ClassificationHead( + input_dim=head_config['input_dim'], + hidden_dim=head_config['hidden_dim'], + output_dim=head_config['output_dim'] + ) + elif head_config['type'] == 'matching': + self.task_head = MatchingHead( + input_dim=head_config['input_dim'], + output_dim=head_config['output_dim'] + ) + # 可在此处添加其他任务头 + + def forward(self, data) -> torch.Tensor: + """ + Args: + data: 一个 PyG 的 Batch 对象,包含了一批次的图数据。 + + Returns: + 来自任务头的最终输出张量。 + """ + # 1. 从 GNN 编码器获取区块嵌入 + # PyG 的 DataLoader 会自动将图数据打包成一个大的 Batch 对象 + patch_embeddings = self.gnn_encoder(data) + + # 2. 为 Transformer 重塑形状: [batch_size, seq_len, hidden_dim] + # 这需要知道批次中每个图包含多少个区块(节点)。 + # 我们可以从 PyG Batch 对象的 `ptr` 属性中获取此信息。 + num_graphs = data.num_graphs + # `ptr` 记录了每个图的节点数累积和,通过相减得到每个图的节点数 + nodes_per_graph = data.ptr[1:] - data.ptr[:-1] + # 假设批次内所有图的区块数相同(对于我们的滑动窗口方法是成立的) + patch_embeddings = patch_embeddings.view(num_graphs, nodes_per_graph[0], -1) + + # 3. 将区块嵌入序列传入 Transformer + contextual_embeddings = self.transformer_core(patch_embeddings) + + # 4. 将结果传入任务头 + if self.task_head: + output = self.task_head(contextual_embeddings) + else: + # 如果没有定义任务头(例如在自监督预训练中),则返回上下文嵌入 + output = contextual_embeddings + + return output diff --git a/src/models/gnn_encoder.py b/src/models/gnn_encoder.py new file mode 100644 index 0000000..0c9c285 --- /dev/null +++ b/src/models/gnn_encoder.py @@ -0,0 +1,61 @@ +import torch +import torch.nn as nn +from torch_geometric.nn import GCNConv, SAGEConv, GATConv, global_mean_pool + +class GNNEncoder(nn.Module): + """基于 GNN 的编码器,用于生成区块(Patch)的嵌入向量。""" + + def __init__(self, node_input_dim: int, hidden_dim: int, output_dim: int, num_layers: int, gnn_type: str = 'gcn'): + """ + Args: + node_input_dim: 输入节点特征的维度。 + hidden_dim: 隐藏层的维度。 + output_dim: 输出区块嵌入向量的维度。 + num_layers: GNN 层的数量。 + gnn_type: 使用的 GNN 层类型('gcn', 'graphsage', 'gat')。 + """ + super(GNNEncoder, self).__init__() + self.layers = nn.ModuleList() + # 输入层 + self.layers.append(self.get_gnn_layer(node_input_dim, hidden_dim, gnn_type)) + + # 隐藏层 + for _ in range(num_layers - 2): + self.layers.append(self.get_gnn_layer(hidden_dim, hidden_dim, gnn_type)) + + # 输出层 + self.layers.append(self.get_gnn_layer(hidden_dim, output_dim, gnn_type)) + + # 读出函数,用于将节点嵌入聚合为图级别的嵌入 + self.readout = global_mean_pool + + def get_gnn_layer(self, in_channels, out_channels, gnn_type): + """根据类型获取 GNN 层。""" + if gnn_type == 'gcn': + return GCNConv(in_channels, out_channels) + elif gnn_type == 'graphsage': + return SAGEConv(in_channels, out_channels) + elif gnn_type == 'gat': + # 注意:GATConv 可能需要额外的参数,如 heads + return GATConv(in_channels, out_channels) + else: + raise ValueError(f"不支持的 GNN 类型: {gnn_type}") + + def forward(self, data) -> torch.Tensor: + """ + Args: + data: 一个 PyTorch Geometric 的 Data 或 Batch 对象。 + + Returns: + 一个代表区块的图级别嵌入的张量。 + """ + x, edge_index, batch = data.x, data.edge_index, data.batch + + # 通过所有 GNN 层 + for layer in self.layers: + x = layer(x, edge_index) + x = torch.relu(x) + + # 全局池化以获得图级别的嵌入 + graph_embedding = self.readout(x, batch) + return graph_embedding diff --git a/src/models/init.py b/src/models/init.py new file mode 100644 index 0000000..e69de29 diff --git a/src/models/task_heads.py b/src/models/task_heads.py new file mode 100644 index 0000000..74c311f --- /dev/null +++ b/src/models/task_heads.py @@ -0,0 +1,51 @@ +import torch +import torch.nn as nn + +class ClassificationHead(nn.Module): + """一个用于分类任务的简单多层感知机(MLP)任务头。""" + + def __init__(self, input_dim: int, hidden_dim: int, output_dim: int): + super(ClassificationHead, self).__init__() + self.fc1 = nn.Linear(input_dim, hidden_dim) + self.relu = nn.ReLU() + self.fc2 = nn.Linear(hidden_dim, output_dim) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """ + Args: + x: 来自 Transformer 骨干网络的输入张量。 + + Returns: + 最终的分类 logits。 + """ + # 我们可以取第一个 token(类似 [CLS])的嵌入,或者进行平均池化 + # 为简单起见,我们假设在序列维度上进行平均池化 + x_pooled = torch.mean(x, dim=1) + + out = self.fc1(x_pooled) + out = self.relu(out) + out = self.fc2(out) + return out + +class MatchingHead(nn.Module): + """用于学习版图匹配的相似性嵌入的任务头。""" + + def __init__(self, input_dim: int, output_dim: int): + super(MatchingHead, self).__init__() + self.projection = nn.Linear(input_dim, output_dim) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """ + Args: + x: 来自 Transformer 骨干网络的输入张量。 + + Returns: + 代表整个输入图(例如一个 IP 模块)的单个嵌入向量。 + """ + # 全局平均池化,为整个序列获取一个单一的向量 + graph_embedding = torch.mean(x, dim=1) + # 投影到最终的嵌入空间 + similarity_embedding = self.projection(graph_embedding) + # 对嵌入进行 L2 归一化,以便使用余弦相似度 + similarity_embedding = nn.functional.normalize(similarity_embedding, p=2, dim=1) + return similarity_embedding diff --git a/src/models/transformer_core.py b/src/models/transformer_core.py new file mode 100644 index 0000000..b96f34d --- /dev/null +++ b/src/models/transformer_core.py @@ -0,0 +1,65 @@ +import torch +import torch.nn as nn +import math + +class PositionalEncoding(nn.Module): + """向输入序列中注入位置信息。""" + + def __init__(self, d_model: int, max_len: int = 5000): + super(PositionalEncoding, self).__init__() + # 创建一个足够大的位置编码矩阵 + pe = torch.zeros(max_len, d_model) + # 创建位置信息 [max_len, 1] + position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) + # 计算用于正弦和余弦函数的分母项 + div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) + # 计算偶数维度的位置编码(使用正弦) + pe[:, 0::2] = torch.sin(position * div_term) + # 计算奇数维度的位置编码(使用余弦) + pe[:, 1::2] = torch.cos(position * div_term) + # 调整形状以匹配输入 [max_len, 1, d_model] + pe = pe.unsqueeze(0).transpose(0, 1) + # 将 pe 注册为 buffer,这样它不会被视为模型参数 + self.register_buffer('pe', pe) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """ + Args: + x: 张量,形状为 [seq_len, batch_size, embedding_dim] + """ + # 将位置编码加到输入张量上 + x = x + self.pe[:x.size(0), :] + return x + +class TransformerCore(nn.Module): + """用于全局上下文建模的 Transformer 骨干网络。""" + + def __init__(self, hidden_dim: int, num_layers: int, num_heads: int, dropout: float = 0.1): + super(TransformerCore, self).__init__() + self.pos_encoder = PositionalEncoding(hidden_dim) + # 定义 Transformer 编码器层 + encoder_layers = nn.TransformerEncoderLayer(d_model=hidden_dim, nhead=num_heads, dropout=dropout, batch_first=True) + # 堆叠多个编码器层形成完整的 Transformer 编码器 + self.transformer_encoder = nn.TransformerEncoder(encoder_layers, num_layers=num_layers) + + def forward(self, patch_embeddings: torch.Tensor) -> torch.Tensor: + """ + Args: + patch_embeddings: 形状为 [batch_size, seq_len, hidden_dim] 的张量, + 代表所有区块的嵌入向量。 + + Returns: + 一个形状为 [batch_size, seq_len, hidden_dim] 的、包含全局上下文信息的张量。 + """ + # 注意:PyTorch 的 TransformerEncoderLayer 期望的输入形状是 (seq_len, batch, features) + # 如果 batch_first=False,或者 (batch, seq_len, features) 如果 batch_first=True。 + # 我们的输入是 [batch_size, seq_len, hidden_dim],所以我们设置 batch_first=True。 + + # 我们使用的 PositionalEncoding 是为 (seq_len, batch, features) 设计的,所以需要调整一下形状 + src = patch_embeddings.transpose(0, 1) # 转换为 [seq_len, batch_size, hidden_dim] + src = self.pos_encoder(src) + src = src.transpose(0, 1) # 转换回 [batch_size, seq_len, hidden_dim] + + # 将带有位置信息的嵌入传入 Transformer + output = self.transformer_encoder(src) + return output diff --git a/src/utils/config_loader.py b/src/utils/config_loader.py new file mode 100644 index 0000000..eaa8abc --- /dev/null +++ b/src/utils/config_loader.py @@ -0,0 +1,36 @@ +import yaml +from pathlib import Path + +def load_config(config_file: str) -> dict: + """加载 YAML 配置文件。 + + Args: + config_file: YAML 配置文件的路径。 + + Returns: + 包含配置信息的字典。 + """ + with open(config_file, 'r', encoding='utf-8') as f: + config = yaml.safe_load(f) + return config + +def merge_configs(base_config: dict, task_config: dict) -> dict: + """将特定于任务的配置合并到基础配置中。 + + Args: + base_config: 基础(默认)配置。 + task_config: 要合并的特定于任务的配置。 + + Returns: + 合并后的配置字典。 + """ + merged = base_config.copy() # 复制基础配置 + # 遍历任务配置中的键值对 + for key, value in task_config.items(): + # 如果值是字典且键也存在于合并后的配置中,则递归合并 + if isinstance(value, dict) and key in merged and isinstance(merged[key], dict): + merged[key] = merge_configs(merged[key], value) + # 否则,直接用任务配置的值覆盖 + else: + merged[key] = value + return merged diff --git a/src/utils/init.py b/src/utils/init.py new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/logging.py b/src/utils/logging.py new file mode 100644 index 0000000..be51c24 --- /dev/null +++ b/src/utils/logging.py @@ -0,0 +1,31 @@ +import logging +import sys + +def get_logger(name: str, level=logging.INFO) -> logging.Logger: + """创建并配置一个日志记录器。 + + Args: + name: 日志记录器的名称。 + level: 日志记录级别。 + + Returns: + 一个配置好的日志记录器实例。 + """ + # 获取指定名称的日志记录器 + logger = logging.getLogger(name) + # 设置日志记录器的级别 + logger.setLevel(level) + + # 创建一个处理器,用于将日志记录输出到标准输出 + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(level) + + # 创建一个格式化器,并将其添加到处理器 + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setFormatter(formatter) + + # 将处理器添加到日志记录器(如果尚未添加) + if not logger.handlers: + logger.addHandler(handler) + + return logger diff --git a/技术路线图:基于几何图的版图Transformer (Geo-Layout Transformer).md b/技术路线图:基于几何图的版图Transformer (Geo-Layout Transformer).md new file mode 100644 index 0000000..e4bad67 --- /dev/null +++ b/技术路线图:基于几何图的版图Transformer (Geo-Layout Transformer).md @@ -0,0 +1,141 @@ +### **技术路线图:基于几何/图的版图Transformer (Geo-Layout Transformer)** + +这个路线图分为五个主要阶段: + +1. **环境搭建与工具选型 (Foundation)** +2. **数据预处理与表征 (Data Preparation & Representation)** +3. **模型架构设计 (Model Architecture)** +4. **训练与评估 (Training & Evaluation)** +5. **迭代与优化 (Iteration & Advanced Topics)** + + + +#### **阶段一:环境搭建与工具选型** + +这是所有工作的基础,选择合适的工具能事半功倍。 + +- **编程语言**: **Python** 是事实上的标准。 +- **GDS/OASIS 解析库**: + - **KLayout (`klayout.db`)**: 强烈推荐。它不仅是一个查看器,还提供了极其强大和高效的Python API,用于读取、写入和处理复杂的版图几何运算(如布尔运算、尺寸调整等)。它的区域查询(Region Query)功能对于提取Patch内的数据至关重要。 + - **gdspy**: 另一个流行的选择,更轻量级,适合创建和简单处理GDS文件,但在处理大型文件和复杂查询时可能不如KLayout高效。 +- **机器学习/深度学习框架**: + - **PyTorch**: 主流选择,社区活跃,生态系统丰富。 + - **PyTorch Geometric (PyG)** 或 **Deep Graph Library (DGL)**: 这两个是构建在PyTorch之上的图神经网络库,它们将是实现“Patch编码器”的核心工具。PyG在学术界使用非常广泛。 +- **数据处理与科学计算**: + - **NumPy**: 用于高效的数值计算。 + - **Pandas**: 用于管理和分析元数据。 + - **Shapely**: 如果需要处理一些几何对象(多边形),这个库也很有用。 + +**行动计划**: + +1. 安装Python环境 (建议使用Conda进行环境隔离)。 +2. 安装KLayout并学习其Python API (`import klayout.db as kdb`)。 +3. 安装PyTorch和PyG。 + +------ + + + +#### **阶段二:数据预处理与表征** + +这是整个项目中**最关键、工作量最大**的部分。模型能学到什么,上限就在于你如何表征数据。 + +1. **定义“Patch”**: + - 在GDS/OASIS的坐标空间中,定义一个滑动窗口(或网格)。窗口大小是一个重要的超参数,例如 `10µm x 10µm`。你需要考虑标准单元的高度、金属线的宽度等因素来确定一个有意义的尺寸。 +2. **数据提取**: + - 编写脚本,遍历整个版图(或感兴趣的区域)。 + - 对于每一个Patch,使用KLayout的`Region.select()`或类似功能,高效地提取出所有完全或部分落入该Patch窗口内的几何图形(多边形、矩形)。 + - **核心输出**: 对每个Patch,你得到一个几何对象的列表。每个对象包含信息:`{coordinates, layer, datatype, texttype}`。 +3. **构建图 (Graph Construction)**: + - **这是方法二的核心**。你需要将每个Patch内的几何对象列表转换成一个图 `G = (V, E)`。 + - **定义节点 (Nodes, V)**: + - 最直接的方法:每个几何图形(多边形)是一个节点。 + - 节点的初始特征向量可以包括: + - **几何特征**: 质心坐标(x, y),宽度,高度,面积,形状的紧凑度等。 + - **层信息**: 将GDS的层号(如M1, VIA1, M2)进行独热编码 (One-Hot Encoding)。 + - **其他属性**: 如果有,比如文本标签等。 + - **定义边 (Edges, E)**: + - 边的定义决定了模型能学习到什么样的空间关系。可以尝试多种策略: + - **邻近关系**: 如果两个图形的距离小于某个阈值,则连接一条边。可以使用K近邻(KNN)图。 + - **重叠/接触关系**: 如果两个图形(例如一个Via和一个Metal Shape)有重叠或接触,连接一条边。 + - **同一层关系**: 在同一层内的邻近图形之间连接边。 + - **跨层关系**: 在相邻层(如M1和VIA1)之间,如果图形在空间上重叠,则连接边。 + - **边的特征**: 边的特征可以为空,也可以包含距离、重叠面积等信息。 +4. **数据集生成**: + - 处理所有的GDS文件,将每个Patch转换成一个图数据对象(在PyG中是 `Data` 对象)。 + - 为每个Patch图关联一个**标签 (Label)**。标签取决于你的具体任务,例如: + - **DRC热点预测**: `1` (有DRC违规), `0` (无DRC违规)。 + - **可制造性预测**: `1` (热点), `0` (非热点)。 + - 将所有处理好的图数据对象保存为文件(如`.pt`格式),以便后续高效加载。 + +**行动计划**: + +1. 确定你的目标任务和标签来源(例如,使用商业EDA工具运行DRC检查,导出结果作为标签)。 +2. 使用KLayout编写数据提取和Patch划分脚本。 +3. 设计并实现将几何对象列表转换为PyG图对象的算法。 +4. 处理你的数据集,生成一个包含成千上万个(或更多)图样本的训练集、验证集和测试集。 + + + +#### **阶段三:模型架构设计** + +模型分为两个主要部分:**Patch编码器**和**全局Transformer**。 + +1. **Patch编码器 (Patch Encoder)**: + - **目标**: 将每个Patch的图 `G` 编码成一个固定长度的向量 `h_patch`。 + - **架构**: 使用一个**图神经网络 (GNN)**。常见的选择有: + - **GCN (Graph Convolutional Network)**: 经典、简单。 + - **GraphSAGE**: 通过聚合邻居信息来学习节点表示,对未知图有更好的泛化能力。 + - **GAT (Graph Attention Network)**: 引入注意力机制,为不同的邻居节点分配不同的权重,表达能力更强。 + - **实现**: GNN会对Patch图中的每个节点进行多轮信息传播和更新,得到最终的节点嵌入。然后,使用一个**全局读出函数 (Global Readout Function)**,如 `global_mean_pool`, `global_add_pool`,将所有节点的嵌入聚合起来,形成整个图的嵌入向量 `h_patch`。 +2. **全局Transformer (Global Transformer)**: + - **输入**: 一个由所有Patch嵌入组成的序列:`[h_patch_1, h_patch_2, ..., h_patch_N]`。 + - **位置编码 (Positional Embedding)**: **至关重要**。因为Transformer本身不感知顺序,你必须告诉模型每个Patch的原始空间位置。可以使用2D绝对或相对位置编码,将其加到 `h_patch` 向量上。 + - **架构**: + - 一个标准的**Transformer Encoder**。它由多层的多头自注意力(Multi-Head Self-Attention)和前馈网络(Feed-Forward Network)组成。 + - 自注意力机制将允许模型学习到不同Patch之间的全局依赖关系。例如,模型可以学到一条长长的金属线是如何跨越多个Patch的,或者一个标准单元阵列的重复模式。 + - **分类头 (Classification Head)**: + - 在Transformer的输出序列上接一个或多个全连接层。 + - 你可以使用一个特殊的 `[CLS]` token的输出来进行最终的分类,或者对所有Patch的输出进行平均池化后再分类。 + +**行动计划**: + +1. 使用PyG搭建一个GNN模型作为Patch编码器。 +2. 使用PyTorch内置的`nn.TransformerEncoder`模块搭建全局Transformer。 +3. 将两者串联起来,形成完整的Geo-Layout Transformer模型。 + + + +#### **阶段四:训练与评估** + +这是验证你想法的阶段。 + +1. **损失函数 (Loss Function)**: + - 对于二分类任务(如DRC热点预测),使用**二元交叉熵损失 (Binary Cross-Entropy Loss)**。 + - 如果样本不均衡(例如,DRC热点非常少),可以考虑使用**加权交叉熵**或**Focal Loss**。 +2. **优化器 (Optimizer)**: + - **Adam** 或 **AdamW** 是常用的、稳健的选择。 +3. **训练流程**: + - 编写标准的训练循环:前向传播 -> 计算损失 -> 反向传播 -> 更新权重。 + - 使用验证集监控模型性能,防止过拟合,并用于调整超参数(如学习率、GNN层数、Transformer头数等)。 +4. **评估指标 (Metrics)**: + - **准确率 (Accuracy)**: 在样本均衡时有用。 + - **精确率 (Precision)**, **召回率 (Recall)**, **F1-Score**: 在样本不均衡时更为重要。 + - **AUC-ROC (Area Under the ROC Curve)**: 衡量模型整体分类能力的常用指标。 + +**行动计划**: + +1. 编写训练脚本,实现数据加载、模型训练和验证。 +2. 运行实验,调整超参数,找到最佳模型。 +3. 在独立的测试集上评估最终模型的性能,并分析结果。 + +#### **阶段五:迭代与优化** + +一旦基础模型跑通,你可以在多个方向上进行深入探索。 + +- **多尺度Patch (Multi-scale Patching)**: 同时使用不同大小的Patch,让模型能够捕捉不同尺度的特征。 +- **层级化表征 (Hierarchical Representation)**: 如果GDS文件有层级结构(Cell, Instance),可以设计一个能够利用这种层级信息的模型,而不是将所有东西都“拍平”。 +- **自监督学习 (Self-supervised Learning)**: 版图数据量巨大但标签稀缺。可以设计自监督任务(如预测被遮盖的Patch、预测Patch间的相对位置等)来预训练模型,然后再在下游任务上微调。这可能会极大地提升性能。 +- **模型可解释性 (Interpretability)**: 使用注意力可视化等方法,分析模型在做决策时关注了哪些区域和几何特征,这对于理解模型行为和反哺设计流程非常有价值。 + +请你针对这个想法进行更加深度的调研,寻找相关文件进行想法扩充和可行性佐证。需要注意的是:这个工具是芯片设计制造中的纯后端工具,不要接触到前端,也就是说不要对网表有接触;需要使用GNN将版图中分割的patch的几何图形构建GNN 编码来输入到transformer,并不是一个单独的transformer模型;模型的目标是理解版图,可以实现验证版图连通性,版图匹配,热点搜索等一系列功能。 \ No newline at end of file