一、背景二、几种模型轻量化方法2.1、参数剪枝2.2、量化2.3、知识蒸馏一、背景前几章节中 AI大模型实战——从零开始构建一个具有100M参数规模的Transformer模型 这篇文章中最后通过 5MB 数据训练出的模型占用了大概 500M 的存储空间参数量约 1.2 亿当时为了节省时间只简单跑了一下这比较极端可以说大量的参数是浪费的这里我简单举个例子说明一下比如公式经过少量数据训练后我们只确定了 、…后面的参数都未经过训练所以其实是没用的。这种情况下这个公式就有了可优化的空间比如把之后的全部砍掉或者保留之前的之后的全部砍掉。放在模型中我们知道虽然参数量和训练数据量有很大关系但是参数量还和模型网络的设计息息相关当模型设计的层数比较深那么也是很有可能产生浪费的情况。这种情况下就可以对模型进行优化优化的目标是降低模型的复杂度包括参数量、占用空间。模型复杂度降低了那么就可以降低资源的消耗模型就可以运行在更低配置的设备上。二、几种模型轻量化方法2.1、参数剪枝参数剪枝是一种优化技术通过减少模型中的参数数量来降低复杂性和运行成本。剪枝通常涉及识别并删除那些对模型性能贡献较小的参数比如权重。一般来说是移除某些连接或整个神经元。下面我来详细介绍下参数剪枝步骤。加载已经训练好的模型一般包含模型架构和权重。选择剪枝策略决定是进行无结构剪枝还是结构剪枝。无结构剪枝就是移除单个权重它通常对硬件支持较差而结构剪枝就是移除整个过滤器或通道它可以更好地利用现代硬件优化。定义剪枝标准根据权重的重要性来决定哪些权重被剪枝。常见的标准包括权重的绝对值大小小的权重可能对输出影响较小可以被剪枝。实施剪枝应用剪枝标准修改模型的权重。这可以通过修改权重矩阵将选定的权重设为零来实现。我们选择无结构剪枝剪枝之前先执行以下代码打印一下参数。for name, param in model.named_parameters(): if param.requires_grad: print(name, param.numel()) plaintext positional_encoding 512embed.weight 50499072transformer_decoder.layers.0.self_attn.in_proj_weight 786432transformer_decoder.layers.0.self_attn.in_proj_bias 1536transformer_decoder.layers.0.self_attn.out_proj.weight 262144transformer_decoder.layers.0.self_attn.out_proj.bias 512transformer_decoder.layers.0.multihead_attn.in_proj_weight 786432transformer_decoder.layers.0.multihead_attn.in_proj_bias 1536transformer_decoder.layers.0.multihead_attn.out_proj.weight 262144............transformer_decoder.layers.5.norm1.bias 512transformer_decoder.layers.5.norm2.weight 512transformer_decoder.layers.5.norm2.bias 512transformer_decoder.layers.5.norm3.weight 512transformer_decoder.layers.5.norm3.bias 512fc.weight 50499072fc.bias 98631执行裁剪逻辑model load_model(models/transformer_decoder_model.pth)linear_layer model.fc# 应用无结构剪枝移除50%的权重prune.l1_unstructured(linear_layer, nameweight, amount0.5)torch.save(model.state_dict(), models/transformer_decoder_model_cut.pth)裁剪之后再打印下参数positional_encoding 512embed.weight 50499072transformer_decoder.layers.0.self_attn.in_proj_weight 786432transformer_decoder.layers.0.self_attn.in_proj_bias 1536transformer_decoder.layers.0.self_attn.out_proj.weight 262144transformer_decoder.layers.0.self_attn.out_proj.bias 512.........transformer_decoder.layers.5.norm1.bias 512transformer_decoder.layers.5.norm2.weight 512transformer_decoder.layers.5.norm2.bias 512transformer_decoder.layers.5.norm3.weight 512transformer_decoder.layers.5.norm3.bias 512fc.bias 98631fc.weight_orig 50499072fc.weight 变成了 fc.weight_orig是因为在 PyTorch 中使用 prune 模块进行剪枝后原始权重会被保留为 weight_orig而 weight 则变成了一个由原始权重和掩码运算得到的视图view。这是为了在训练过程中仍然可以访问和更新原始权重同时应用掩码来模拟权重被剪枝的效果。执行完剪枝后发现模型并没有减少甚至有可能会增大那是因为在 PyTorch 中剪枝实际上是通过在原有的模型参数上添加掩码来实现的而不是真正地移除那些参数。这意味着剪枝操作增加了额外的状态信息比如掩码从而可能导致模型文件总大小增加。为了确保剪枝效果永久化并减少模型的大小你需要在保存模型前将掩码应用到原始权重并移除剪枝带来的额外属性。使用 prune.remove 函数来把 weight_orig 替换回 weight并移除掩码。这一步确保了模型权重不再依赖于掩码然后保存简化模型即可。prune.remove(model.fc, weight)torch.save(model.state_dict(), models/transformer_decoder_model_cut.pth)剪枝完成模型的性能可能会有所下降需要通过再次训练或者微调模型恢复一部分性能损失最后再次评估模型性能确保它仍然满足应用要求。2.2、量化量化是把模型中的浮点类型的权重转换为低精度如 INT8 或 INT16的过程不仅可以减少模型的存储空间需求还能在某些硬件上加速模型的推理速度。这就好比我们开发语言里的精度转换比如 double/long 类型转 int 类型一般会损失精度至于影响大不大取决于这个变量本身存储的数值。模型量化也是一样前面我们讲过模型默认以 FP32 的精度存储数据也就是一个参数需要 32 位 4 个字节存储量化成 int8那么只需要 8 位 1 个字节来存储。存储量直接减少 75%。model AutoModel.from_pretrained(MODEL_PATH, trust_remote_codeTrue, ).quantize(4).cuda()量化一般有三种情况静态量化、动态量化、感知训练量化上面的这种应用的是自定义量化技术有点像静态量化又不完全是你可以看一下 quantize(4) 方法的源码。def quantize(model, weight_bit_width): Replace fp16 linear with quantized linear for layer in model.layers: layer.attention.query_key_value QuantizedLinear( weight_bit_widthweight_bit_width, weight_tensorlayer.attention.query_key_value.weight.to(torch.cuda.current_device()), bias_tensorlayer.attention.query_key_value.bias, in_featureslayer.attention.query_key_value.in_features, out_featureslayer.attention.query_key_value.out_features, biasTrue, dtypetorch.half, devicelayer.attention.query_key_value.weight.device, ) layer.attention.dense QuantizedLinear( weight_bit_widthweight_bit_width, weight_tensorlayer.attention.dense.weight.to(torch.cuda.current_device()), bias_tensorlayer.attention.dense.bias, in_featureslayer.attention.dense.in_features, out_featureslayer.attention.dense.out_features, biasTrue, dtypetorch.half, devicelayer.attention.dense.weight.device, )这个其实是把模型原来的层替换成新的自定义的 QuantizedLinear 层了感兴趣的话你可以继续阅读 QuantizedLinear 类的源码了解细节。2.2.1、静态量化静态量化是在模型的推理阶段将权重和激活数据从浮点数转换为低精度整数的过程。和动态量化不同静态量化会在推理前对模型的权重和激活数据进行量化通常需要一个校准步骤通过这一步可以决定最佳的量化参数。你可以参考我给出的示例代码。import torchimport torch.nn as nnimport torch.quantizationmodel TransformerDecoderModel(vocab_size10000, embed_size512, num_heads8, hidden_dim2048, num_layers6)model.eval()model_fp32_prepared torch.quantization.prepare(model)# 模型校准过程# 运行一些输入数据来校准模型for input_batch in calibration_dataset: model_fp32_prepared(input_batch)# 转换模型为量化版本model_int8 torch.quantization.convert(model_fp32_prepared)# 保存量化模型torch.save(model_int8.state_dict(), quantized_transformer_model.pth)因为模型的权重和激活函数都被量化了所以模型的整体性能可能会有影响所以在量化完后需要进行全面的测试。2.2.2、动态量化动态量化主要针对模型的权重进行量化每次输入时都会重新计算量化参数。这种方法通常用于模型的线性层全连接层和循环层如 LSTM。动态量化可以在不需要重新训练模型的情况下实现适合那些对推理速度有较高要求的应用场景。你可以看一个简单示例。import torchimport torch.nn as nnfrom torch.quantization import quantize_dynamicmodel TransformerDecoderModel(vocab_size10000, embed_size512, num_heads8, hidden_dim2048, num_layers6)model.eval() # 设置为评估模式# 这里指定了量化nn.Linear和nn.LSTM层使用8-bit的量化整数torch.qint8quantized_model quantize_dynamic( model, {nn.Linear}, # 指定量化的层类型 dtypetorch.qint8 # 指定量化的数据类型)# 保存量化模型torch.save(quantized_model.state_dict(), quantized_transformer_model.pth)2.2.3、感知训练量化感知训练量化是指在训练过程中应用量化效果使模型适应量化带来的精度损失。这种方法通常能保持或仅轻微影响模型的精度。在之前章节中 从零开始构建一个具有100M参数规模的Transformer模型 的例子中我们简单修改下模型定义的代码。import torchimport torch.nn as nnfrom torch.quantization import QuantStub, DeQuantStub, prepare_qat, convertclass TransformerDecoderModel(nn.Module): def __init__(self, vocab_size, embed_size, num_heads, hidden_dim, num_layers): ... self.quant QuantStub() # 在模型的前端进行激活的量化和反量化。 self.dequant DeQuantStub() # 在模型的后端进行激活的量化和反量化。 ...# 初始化模型model TransformerDecoderModel(vocab_size10000, embed_size512, num_heads8, hidden_dim2048, num_layers6)model.eval() # 评估模式# 启用QATmodel.qconfig torch.quantization.get_default_qat_qconfig(fbgemm)model prepare_qat(model)model.train()model.eval()model convert(model)# 保存量化模型torch.save(model.state_dict(), quantized_transformer_model.pth)不过这只是示例代码实际会更加复杂一点。除了量化外还有一种用得比较多的轻量化方法知识蒸馏接下来我们一起看下。2.3、知识蒸馏知识蒸馏是一种训练技术其中一个小的模型被叫做学生模型学习模仿一个大的已经训练好的模型这个模型通常叫做教师模型。通过这种方式小模型可以在保持较高性能的同时显著减少参数数量。我们来看下知识蒸馏的基本步骤。1、训练教师模型首先训练一个大型的高性能的教师模型。这个模型通常是尽可能地大和复杂以达到高准确率。2、定义学生模型设计一个比教师模型小得多的学生模型。学生模型的架构不必与教师模型相同但通常需要能够学习相似类型的特征。3、蒸馏过程使用教师模型的输出来训练学生模型。这通常涉及调整学生模型的损失函数使其不仅要学习真实的标签还要学习模仿教师模型的输出。4、 评估学生模型测试学生模型的性能确保它能够达到预期的精度同时具有更小的模型大小或更快的推理速度。假设我们有一个已经训练好的教师模型和一个较小的学生模型应该如何使用 PyTorch 实现知识蒸馏呢你可以看我给出的示例。import torchimport torch.nn as nnimport torch.optim as optim# 假设teacher_model和student_model已经定义并加载teacher_model.eval() # 确保教师模型在评估模式# 定义学生模型student_model StudentModel()# 损失函数和优化器criterion nn.MSELoss()optimizer optim.Adam(student_model.parameters(), lr0.001)# 数据加载器train_loader DataLoader(dataset, batch_sizebatch_size, shuffleTrue)# 蒸馏过程for epoch in range(num_epochs): student_model.train() for data, target in train_loader: optimizer.zero_grad() # 教师模型的输出 with torch.no_grad(): teacher_output teacher_model(data) # 学生模型的输出 student_output student_model(data) # 计算损失可以根据需要混合教师输出和真实标签 loss criterion(student_output, teacher_output) # 以教师模型的输出作为目标 # 反向传播和优化 loss.backward() optimizer.step()# 评估学生模型性能student_model.eval()# 进行测试和评估...如果你对前面学习的内容有印象的话其实知识蒸馏是很好理解的关键就在下面这一步loss criterion(student_output, teacher_output) # 以教师模型的输出作为目标之前我们计算损失的时候是以真实标签作为对比的而这里是以教师模型的输出作为对比为什么教师模型的输出比真实标签更适合知识蒸馏呢这是因为教师模型的输出通常是经过 Softmax 函数处理的概率分布被叫做“软标签”。相对于硬标签也就是真实标签0 或 1 的类别标签软标签能够提供关于各个类别相对可能性的更多信息。比如在分类任务中一个图像可能有 90% 的概率是猫10% 的概率是狗而不是简单地标记为“猫”。这种概率分布包含了数据的不确定性和类别之间相似性的信息有助于学生模型更全面地理解数据。常见的模型轻量化方法就是这些当然还有一些其他方式比如参数共享、低秩因子分解等技术也是可以用来减少模型大小的有兴趣的话你可以自己了解一下这里我就不再详细阐述了。01什么是AI大模型应用开发工程师如果说AI大模型是蕴藏着巨大能量的“后台超级能力”那么AI大模型应用开发工程师就是将这种能量转化为实用工具的执行者。AI大模型应用开发工程师是基于AI大模型设计开发落地业务的应用工程师。这个职业的核心价值在于打破技术与用户之间的壁垒把普通人难以理解的算法逻辑、模型参数转化为人人都能轻松操作的产品形态。无论是日常写作时用到的AI文案生成器、修图软件里的智能美化功能还是办公场景中的自动记账工具、会议记录用的语音转文字APP这些看似简单的应用背后都是应用开发工程师在默默搭建技术与需求之间的桥梁。他们不追求创造全新的大模型而是专注于让已有的大模型“听懂”业务需求“学会”解决具体问题最终形成可落地、可使用的产品。CSDN粉丝独家福利给大家整理了一份AI大模型全套学习资料这份完整版的 AI 大模型学习资料已经上传CSDN朋友们如果需要可以扫描下方二维码点击下方CSDN官方认证链接免费领取【保证100%免费】02AI大模型应用开发工程师的核心职责需求分析与拆解是工作的起点也是确保开发不偏离方向的关键。应用开发工程师需要直接对接业务方深入理解其核心诉求——不仅要明确“要做什么”更要厘清“为什么要做”以及“做到什么程度算合格”。在此基础上他们会将模糊的业务需求拆解为具体的技术任务明确每个环节的执行标准并评估技术实现的可行性同时定义清晰的核心指标为后续开发、测试提供依据。这一步就像建筑前的图纸设计若出现偏差后续所有工作都可能白费。技术选型与适配是衔接需求与开发的核心环节。工程师需要根据业务场景的特点选择合适的基础大模型、开发框架和工具——不同的业务对模型的响应速度、精度、成本要求不同选型的合理性直接影响最终产品的表现。同时他们还要对行业相关数据进行预处理通过提示词工程优化模型输出或在必要时进行轻量化微调让基础模型更好地适配具体业务。此外设计合理的上下文管理规则确保模型理解连贯需求建立敏感信息过滤机制保障数据安全也是这一环节的重要内容。应用开发与对接则是将方案转化为产品的实操阶段。工程师会利用选定的开发框架构建应用的核心功能同时联动各类外部系统——比如将AI模型与企业现有的客户管理系统、数据存储系统打通确保数据流转顺畅。在这一过程中他们还需要配合设计团队打磨前端交互界面让技术功能以简洁易懂的方式呈现给用户实现从技术方案到产品形态的转化。测试与优化是保障产品质量的关键步骤。工程师会开展全面的功能测试找出并修复开发过程中出现的漏洞同时针对模型的响应速度、稳定性等性能指标进行优化。安全合规性也是测试的重点需要确保应用符合数据保护、隐私安全等相关规定。此外他们还会收集用户反馈通过调整模型参数、优化提示词等方式持续提升产品体验让应用更贴合用户实际使用需求。部署运维与迭代则贯穿产品的整个生命周期。工程师会通过云服务器或私有服务器将应用部署上线并实时监控运行状态及时处理突发故障确保应用稳定运行。随着业务需求的变化他们还需要对应用功能进行迭代更新同时编写完善的开发文档和使用手册为后续的维护和交接提供支持。03薪资情况与职业价值市场对这一职业的高度认可直接体现在薪资待遇上。据猎聘最新在招岗位数据显示AI大模型应用开发工程师的月薪最高可达60k。在AI技术加速落地的当下这种“技术业务”的复合型能力尤为稀缺让该职业成为当下极具吸引力的就业选择。AI大模型应用开发工程师是AI技术落地的关键桥梁。他们用专业能力将抽象的技术转化为具体的产品让大模型的价值真正渗透到各行各业。随着AI场景化应用的不断深化这一职业的重要性将更加凸显也必将吸引更多人才投身其中推动AI技术更好地服务于社会发展。CSDN粉丝独家福利给大家整理了一份AI大模型全套学习资料这份完整版的 AI 大模型学习资料已经上传CSDN朋友们如果需要可以扫描下方二维码点击下方CSDN官方认证链接免费领取【保证100%免费】