Attention中存在的问题-错位对齐

本文是在学习RNN中Attention机制运用,所产生的一个问题,欢迎在评论区讨论。

在RNN网络中可以引入注意力机制来克服长距离依赖关系造成的困难,其网络示意图如下:
在这里插入图片描述

  1. 在这个新结构中,定义每个输出的条件概率为:
    𝑝(𝑦𝑖│𝑦1,⋯,𝑦𝑖−1, 𝒙)=𝑔(𝑦𝑖−1,𝑥𝑖,𝑐𝑖 )

  2. 其中𝑠𝑖为解码器RNN中的隐层状态:
    𝑠𝑖=𝑓(𝑠𝑖−1,𝑦𝑖−1,𝑐𝑖)

  3. 这里的上下文向量𝑐𝑖取决于注释向量序列 (encoder转化得到),通过使用注意力系数𝛼𝑖𝑗对 h𝑗 加权求得
    在这里插入图片描述

在RNN网络中attention的计算方式如下。其中函数a()为相似度计算函数,Si-1和hj是两个向量,因此最简单的相似度计算方式为点乘。
在这里插入图片描述

存在的问题

由于St的隐状态位置,因此采用St-1来代替近似,这导致一个问题,位置并未对齐。用一个例子说明这个问题:
下面图中添加了一句话:”Tom is a boy"
在这里插入图片描述
如果要计算"boy"和其它所有词的依赖权重aij,实际上使用的是"a"和其它词的相似度的权重。
在这个例子里,“boy"更依赖于"Tom”,但实际上使用的是"a"这个词计算权重aij,词"a"更依赖于词"is",因此最终计算"boy"时更多考虑了"is"的权重,这会产生较大的错位问题。

可能的解决的方法

  1. Transformer框架(参见《attention is all you need》)使用栈式编码器规避计算顺序依赖关系
  2. 对上层解码器中的隐状态S也采用一个双向RNN输出,来通过上下文计算依赖关系来减少误差。

如果你有更好的解决方案或者认为文本有误,欢迎在评论区提出~

import os import torch import sys import types import importlib.util from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig # --------------------- 配置项(根据硬件调整) --------------------- MODEL_PATH = r"E:\LocalAI\AIModel\DeepSeek\DeepSeekV2LiteChat" # 模型路径 USE_4BIT = True # 启用4-bit量化(显存需求降至约10GB) USE_8BIT = False # 8-bit量化(显存需求约20GB) MAX_NEW_TOKENS = 200 # 生成文本最大长度(降低内存压力) DEVICE = "cuda" if torch.cuda.is_available() else "cpu" # --------------------- 量化配置(4-bit/8-bit) --------------------- quantization_config = None if USE_4BIT or USE_8BIT: quantization_config = BitsAndBytesConfig( load_in_4bit=USE_4BIT, load_in_8bit=USE_8BIT, bnb_4bit_compute_dtype=torch.float16, bnb_4bit_quant_type="nf4", # 4-bit量化类型 bnb_8bit_quant_type="nf8" if USE_8BIT else None ) # --------------------- 加载模型(跳过Flash Attention--------------------- if sys.platform == "win32": if "flash_attn" not in sys.modules: # 创建一个 dummy 的 module spec dummy_spec = importlib.util.spec_from_loader("flash_attn", loader=None) dummy_module = types.ModuleType("flash_attn") dummy_module.__spec__ = dummy_spec # 根据模型代码中可能调用的函数名称添加 dummy 实现(仅返回 None) dummy_module.flash_attn_unpadded = lambda *args, **kwargs: None dummy_module.flash_attn_varlen_qkvpacked_func = lambda *args, **kwargs: None sys.modules["flash_attn"] = dummy_module # --------------------- 加载分词器 --------------------- tokenizer = AutoTokenizer.from_pretrained( MODEL_PATH, trust_remote_code=True, padding_side="left", # 左对齐避免生成错位 use_fast=True # 强制使用快速分词器 ) if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token # 确保有pad token # --------------------- 加载模型 --------------------- model = AutoModelForCausalLM.from_pretrained( MODEL_PATH, quantization_config=quantization_config, trust_remote_code=True ) # --------------------- 显存监控函数 --------------------- def print_gpu_memory(): if DEVICE == "cuda": allocated = torch.cuda.memory_allocated() / 1024**3 reserved = torch.cuda.memory_reserved() / 1024**3 print(f"[显存] 已分配: {allocated:.2f} GB | 保留: {reserved:.2f} GB") else: print("当前使用CPU运行") # --------------------- 轻量生成函数 --------------------- def light_generate(prompt: str): print("\n" + "="*30 + " 生成开始 " + "="*30) # 精简输入处理 inputs = tokenizer( f"<|startoftext|>User: {prompt}\nAssistant:", return_tensors="pt", max_length=512, # 限制输入长度 truncation=True ).to(DEVICE) # 低资源生成参数 outputs = model.generate( inputs.input_ids, max_new_tokens=MAX_NEW_TOKENS, do_sample=True, temperature=0.3, # 降低随机性 top_p=0.9, repetition_penalty=1.1, # 减少重复 pad_token_id=tokenizer.eos_token_id ) # 清理显存 torch.cuda.empty_cache() # 解码结果 generated = tokenizer.decode( outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True ) return generated.strip() # --------------------- 测试运行 --------------------- if __name__ == "__main__": print_gpu_memory() # 初始显存状态 # 测试样例(短文本验证基础功能) test_prompts = [ "请输出我问过你的问题" ] for prompt in test_prompts: print(f"\n[输入] {prompt}") try: reply = light_generate(prompt) print(f"[输出] {reply}") except RuntimeError as e: if "CUDA out of memory" in str(e): print("[错误] 显存不足!请尝试减小 MAX_NEW_TOKENS 或启用4-bit量化") else: print(f"[错误] {str(e)}") print_gpu_memory() # 每次生成后显存状态 这是我的代码
最新发布
04-01
<think>嗯,用户给了一段Python代码,是关于加载和运行DeepSeek模型的,可能在使用过程中遇到了问题,或者想了解代码的结构和功能。我需要仔细分析这段代码,理解各个部分的作用,然后解释给用户。 首先,用户可能想知道这段代码的整体结构。代码主要分为配置项、量化配置、加载模型、显存监控、生成函数和测试运行几个部分。我需要逐一解释这些部分的功能。 用户导入了os、torch、sys等模块,还有transformers库的AutoTokenizer和AutoModelForCausalLM,以及BitsAndBytesConfig。这些是用来加载模型和进行量化的关键库。可能用户对量化不太熟悉,需要解释4-bit和8-bit量化的作用,比如减少显存占用。 接下来是配置项部分,MODEL_PATH指向本地模型路径,USE_4BIT和USE_8BIT是量化选项,MAX_NEW_TOKENS控制生成文本长度。DEVICE根据CUDA是否可用选择设备。这里需要说明量化如何帮助降低显存需求,比如4-bit量化显存降至10GB左右,而8-bit需要约20GB,这对硬件资源有限的用户很重要。 然后是量化配置的生成,使用BitsAndBytesConfig设置参数,比如load_in_4bit、compute_dtype为float16,量化类型nf4或nf8。需要解释这些参数的意义,以及如何影响模型加载和运行效率。 加载模型部分,用户处理了Windows系统下的flash_attn模块问题。可能因为某些依赖在Windows上不支持,所以创建了虚拟模块来避免错误。这里需要说明这段代码的作用是绕过Flash Attention的缺失,确保模型能正常加载。 加载分词器时,trust_remote_code=True可能涉及安全风险,需要提醒用户注意。padding_side设为left是为了生成时对齐正确,use_fast启用快速分词器提升效率。如果pad_token不存在,就用eos_token代替,确保填充正常。 加载模型时使用from_pretrained,并传入量化配置。这部分需要说明如何根据配置加载量化后的模型,以及trust_remote_code的必要性。 显存监控函数print_gpu_memory使用torch.cuda方法来查看显存使用情况,帮助用户调试显存不足的问题。生成函数light_generate中,输入处理添加了<startoftext>标记,可能模型需要特定的格式才能正确生成。生成参数如temperature、top_p和repetition_penalty的作用是控制生成文本的多样性和重复性,用户可能需要调整这些参数来优化输出。 测试运行部分,用户用了一个测试提示“请输出我问过你的问题”,可能想验证模型是否能正确响应。但根据代码中的处理,模型生成的回复可能无法记住之前的对话,因为每次生成都是独立的。这里需要指出这种设计的局限性,或者用户是否有意图实现多轮对话。 用户可能的深层需求是优化模型在本地运行时的资源消耗,尤其是在显存有限的情况下。他们可能遇到显存不足的错误,或者生成结果不理想。需要建议如何调整参数,比如减小MAX_NEW_TOKENS,启用量化,或者调整生成参数来平衡资源使用和生成质量。 此外,代码中的异常处理部分捕获了CUDA显存错误,提示用户调整配置。这说明用户可能在运行过程中遇到了显存问题,需要指导他们如何根据错误信息进行调试。 最后,用户可能希望了解如何扩展代码,比如支持多轮对话,或者提高生成质量。需要指出当前代码是单轮交互,若需多轮需维护对话历史,并注意上下文长度限制。 总结,用户的代码是一个针对DeepSeek模型的高效加载和生成示例,重点在于资源管理和配置优化。需要详细解释各部分功能,指出潜在问题,并提供调整建议,帮助用户更好地理解和使用代码。</think>以下是对您提供的代码的逐步解析与优化建议: 一、代码结构分析 $$代码主要分为以下模块:$$ 1. 配置模块(量化参数/硬件配置) 2. 模型加载模块(含Windows兼容处理) 3. 显存监控模块 4. 文本生成模块 5. 测试运行模块 二、关键配置说明 1. 量化配置(显存优化核心) - 4-bit量化公式:$n_{\text{bits}} = \lceil \log_2(\text{量化级别}) \rceil$ - 当前配置使显存占用降低约75%(对比原始FP32) - 建议优先启用4-bit量化(若显卡支持) 2. 显存优化参数 ```python MAX_NEW_TOKENS = 200 # 控制生成文本长度与显存消耗呈线性关系 temperature = 0.3 # 温度参数调节公式:$p_i^{1/T}$ ``` 三、Windows兼容性处理 ```python # 通过创建虚拟模块绕过Flash Attention依赖 # 数学表达:$\text{flash\_attn} \notin \mathbb{M} \Rightarrow \text{创建}\phi(\text{flash\_attn})$ if sys.platform == "win32": if "flash_attn" not in sys.modules: ... # 创建虚拟实现 ``` 四、生成过程数学原理 $$ p(w_t | w_{1:t-1}) = \text{softmax}(\frac{h_t}{T}) $$ 其中: - $T$:温度参数(当前=0.3,降低输出随机性) - $h_t$:语言模型隐藏层输出 五、改进建议 1. 多轮对话支持(需维护对话历史) ```python # 对话状态保持公式:$H_t = H_{t-1} \cup \{q_t, a_t\}$ dialogue_history = [] ``` 2. 动态温度调节(根据生成质量调整) ```python def adaptive_temperature(history_len): return max(0.3, 0.7 * math.exp(-history_len/10)) # 指数衰减公式 ``` 3. 显存优化进阶方案 - 使用梯度检查点:`model.gradient_checkpointing_enable()` - 启用CPU卸载:`device_map="auto"` 六、运行监控建议 1. 使用公式估算显存消耗: $$ M_{\text{total}} = M_{\text{model}} + M_{\text{activations}} + M_{\text{cache}} $$ 2. 典型值参考: - 7B模型4-bit量化:≈10GB - 13B模型4-bit量化:≈16GB 七、错误处理增强 ```python except RuntimeError as e: if "CUDA out of memory" in str(e): # 显存不足时自动降级方案 new_max_tokens = int(MAX_NEW_TOKENS * 0.8) print(f"自动调整MAX_NEW_TOKENS至{new_max_tokens}") ``` 八、安全建议 - `trust_remote_code=True` 需验证模型来源 - 建议添加:`use_safetensors=True`(如果模型支持) 该代码已实现基础推理功能,如需扩展为生产级应用,建议增加: 1. 流式输出支持 2. 生成终止条件控制 3. 输入内容安全检查 4. 性能监控指标(Tokens/s)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值