o
    i                     @   s   d dl Z d dlmZ d dlZd dlmZ d dlm  mZ G dd dej	Z
dej	dedeej	 fdd	Zdej	d
ee dedededdfddZdS )    N)Optionalc                	       sx   e Zd ZdZ		ddejdededef fdd	Zd
e	j
de	j
fddZdd ZdefddZedefddZ  ZS )
LoRALinearu  
    LoRA 线性层：直接持有 weight/bias，保持与 nn.Linear 相同的 state_dict key 结构。

    state_dict 结构：
        - weight: 原始权重（与 nn.Linear 一致）
        - bias: 原始偏置（与 nn.Linear 一致）
        - lora_A: LoRA 低秩矩阵 A
        - lora_B: LoRA 低秩矩阵 B

    这样设计的好处：加载预训练权重时无需做 key 转换。
          ?        baseralphadropoutc                    s  t    t|tjsJ d|j| _|j| _|| _|| _|dkr%|| nd| _	| j
dt| j	dd |j| _|j| _|dkrjtt|| j| _tt| j|| _tjj| jtdd tj| j n| d	d  | d
d  |dkrt|| _d S t | _d S )Nz,LoRALinear only supports wrapping nn.Linear.r   r   scalingF)
persistent   alora_Alora_B)super__init__
isinstancennLinearin_featuresout_featuresr   r   _base_scalingregister_buffertorchtensorweightbias	Parameterzerosr   r   initkaiming_uniform_mathsqrtzeros_register_parameterDropoutIdentityr	   )selfr   r   r   r	   	__class__ N/home/ubuntu/.local/lib/python3.10/site-packages/voxcpm/modules/layers/lora.pyr      s$   
&zLoRALinear.__init__xreturnc                 C   sV   t || j| j}| jdks| jd u r|S t t || j| j}|| || j  S )Nr   )	Flinearr   r   r   r   r   r	   r
   )r(   r-   resultlora_outr+   r+   r,   forward:   s
   zLoRALinear.forwardc                 C   sF   | j dkr| jdur!tjj| jtdd tj| j dS dS dS )u!   重置 LoRA 参数到初始状态r   Nr   r   )	r   r   r   r    r!   r"   r#   r$   r   r(   r+   r+   r,   reset_lora_parametersC   s   z LoRALinear.reset_lora_parametersenabledc                 C   s    | j |r| j dS d dS )uD   启用/禁用 LoRA（通过 scaling 控制，兼容 torch.compile）r   N)r
   fill_r   )r(   r6   r+   r+   r,   set_enabledI   s    zLoRALinear.set_enabledc                 C   s   | j  dkS )Nr   )r
   itemr4   r+   r+   r,   r6   N   s   zLoRALinear.enabled)r   r   )__name__
__module____qualname____doc__r   r   intfloatr   r   Tensorr3   r5   boolr8   propertyr6   __classcell__r+   r+   r)   r,   r   	   s$    $	r   rootnamer.   c                 C   sN   | d}t|dkr| S | }|dd D ]}t||s dS t||}q|S )us   
    根据类似 'layers.0.self_attn.q_proj' 的全名，返回 parent module（即 q_proj 的上一级）。
    .   N)splitlenhasattrgetattr)rD   rE   partsparentpr+   r+   r,   _get_parent_moduleS   s   

rP   target_submodule_namesr   r   r	   c          
      C   sp   t |  D ]/\}}t|tjsq|dd }||vrqt| |}|du r'qt||||d}	t|||	 qdS )u  
    在给定模块及其子模块中，对名字以 target_submodule_names 结尾的 Linear 层注入 LoRA。

    例如 target_submodule_names=["q_proj", "v_proj"] 时，
    会在所有名为 *.q_proj / *.v_proj 的 nn.Linear 上替换为 LoRALinear。
    rF   rH   N)r   r   r   r	   )	listnamed_modulesr   r   r   rI   rP   r   setattr)
rD   rQ   r   r   r	   	full_namemodule
short_namerN   
lora_layerr+   r+   r,   "apply_lora_to_named_linear_modulesb   s"   
rY   )r"   typingr   r   torch.nnr   torch.nn.functional
functionalr/   Moduler   strrP   rR   r>   r?   rY   r+   r+   r+   r,   <module>   s(    J