基于微调大语言模型的相机知识助手开发-常见问题解答

88 阅读32分钟

作为一个毕业设计项目,不仅得完成代码,还得经得起推敲,能够理解其核心思想。本篇文章就是回答一些关于本毕业设计可能涉及到的一些常见问题的回答。

1. 什么是过拟合?怎么解决过拟合问题?

过拟合:模型在训练集上表现得很好,在测试集上表现的不好的现象。

过拟合之所以会发生,往往是由于模型学到了太多的局部噪音,训练集本身质量不高,训练集的量不够等问题。

为了解决过拟合,常见的应对方法有:

  1. 增大训练集的数据量。增大训练集的数据量能有效减轻过拟合
  2. 使用正则化技术。用来解决过拟合的技术就称之为正则化技术,它是用来在模型学到太多的局部噪音时进行惩罚的。具体而言,在计算代价函数时,之前只考虑了预测值到实际值之间的差值,预测值距离实际值越近,那么代价函数就应该越小,具体的代价函数可以选择二次代价函数,交叉熵代价函数等。而正则化技术的作用是在计算代价函数时,不仅仅考虑预测值离实际值的差距,还会加上正则化项,当模型学到太多局部噪音时,正则化项就会很大,此时代价函数就会很大,而我们要求代价函数应该时越小越好,因此为了让代价函数变小,我们就应该让正则化项也变小,从而起到惩罚模型学到太多局部噪音的目的。

2. 什么是欠拟合,怎样解决欠拟合问题?

欠拟合指模型在训练集和测试集上的表现都不佳,无法学习到数据的基本规律

导致欠拟合的原因: 数据量少;数据质量不高;模型复杂度低

欠拟合的解决方法:

  1. 加大训练数据的量,获取更多,质量更高,更多样的数据训练模型,让模型获得更充分的学习。
  2. 增加模型的复杂度,比如将线性模型改为非线性模型,增加神经元数量,增加神经网络的层数
  3. 优化训练过程:增加训练轮数,减少正则化项的权重或者不使用正则化项

3. 常见的正则化技术有哪些?

  • L1正则化:正则化项是权重绝对值之和
  • L2正则化:正则化项时权重平方之和
  • Dropout:每次随机取神经网络中的一半神经元进行训练,迫使神经网络不依赖于特定神经元进行学习,提高神经元的泛化能力。

4. 你做的毕业设计里面,微调技术是怎样实现的(要能解释清楚流程,并自己用代码实现)

  • 第一步:搜集数据。由于我做的是问答模型,因此如果数据的结构是一问一答这种形式,相较于纯文本数据能获得更好的训练效果。因此需要收集大量相机相关的结构化数据。数据的具体结构是指instruction, input, output三部分,instruction用来说明任务类型或者指定角色,input指明任务的具体内容,output则是模型应该做出的回答。我采用了两种方式生成数据,一种是指定主题,例如尼康相机,佳能相机,曝光度等,调用deepseek和通义千问的api,让它们基于这些主题生成instruction结构的数据。另一种生成数据的方法是收集相机说明书的pdf版本和知乎上面有关摄影的帖子,对这些数据每500字进行一个切分,每500字生成一条数据。另外我还采用multiprocessing.dummy技术加速数据的生成过程,获得了几百倍的速度提升。
  • 第二步:数据清洗。虽然在调用api的过程中我已经指定了数据的格式,每部分的字数以及怎样换行等,但是生成的过程中还是会出现问题,比如instruction和input之间不应该出现换行,但是出现了换行等问题。我的解决方法是利用正则表达式对数据进行清洗。利用正则表达式里面的sub函数匹配到instrution + .... + \n + input的形式,替换为instruction+ ... + input的形式,去掉换行符。
  • 第三步:写训练代码。整个训练代码最重要的是process_func函数该怎么定义,它的作用是将人类可以读懂的文本数据利用分词器tokenzier转化为计算机可以读懂的token, 并把单条数据的格式转化成input_ids(每个词对应token), attention_mask(表明哪些部分有用,哪些部分没用), labels(根据input_ids转换而来,它所做的处理是就是把原instrcution和input部分转换为-100, 而outputs的labels部分与原input_ids一样保持不变)几部分,从而让pytorch可以识别并处理。
  • 第四步:设置训练参数。通过TrainingArguments函数设置训练参数,比如模型的存放路径,多少个批次打印一次损失函数,批次大小,几个批次计算一次梯度,训练轮数等。
  • 第五步训练:最好用GPU训练,CPU速度太慢了,我是在autodl上租用GPU来做的训练,通过阿里云盘实现训练数据在远程服务器和电脑本地之间的传输(比FileZilla)
  • 第六步:检测效果。可以直接用pipeline提问,查看模型训练之后的效果,也可以用gradio实现一个前端页面以后用网页的方式进行交互。事实证明经过训练之后的模型比预训练模型有着更好的效果。

5. 为什么要训练两个版本的模型,而不是把数据合在一起训练一个模型?

原本我是只训练了一个版本的模型,就是设定不同的主题放到一个列表中,然后用for循环循环这个列表,基于每个主题一次生成数据。然后用数据训练。和论文指导老师交流以后,老师让我搜集网上的文本生成,然后再做一个版本,看看效果,于是我就做了基于文本生成的第二个版本,相较于预训练模型均获得了更好的效果。之后有过合并数据一起训练的想法,但是再后来就开学出考研成绩了,所以就专心准备复试没怎么做毕业设计了。

6. 你是怎样设计学习率,训练轮数,批次大小等超参数的?(可继续列举,拓展其他的超参数)

简单来说,就是控制变量法。先根据直觉和经验设置常见的训练轮数,批次大小等,假定我现在要调节批次大小,那就控制其他超参数不变,调整批次大小后重新训练,观察最后结果中的损失函数是变小。如果变小,说明调整后的批次大小相比于原批次大小能取得的训练效果更好;调整其他超参数的逻辑以此类推。

如果问到了怎么调节学习率的,那就如实回答直接用的是默认学习率,然后回答一下学习率的用法, θt+1=θtη⋅∇L(θt) , 然后再回答控制变量法。

新参数 = 原参数 - 学习率 * 梯度

学习率是人为设定的,梯度是损失函数对每个参数求导得到的偏导数组成的向量。

参数下降的方向由梯度决定,步长由梯度大小和学习率共同决定。

反向传播算法用来计算梯度,具体过程是先正向传播计算损失函数,再反向传播逐层计算梯度。

梯度下降算法就是在反向传播算法的基础上,利用计算出来的梯度更新新的权重和偏置。

6.1. 梯度是损失函数对所有参数求偏导组成的向量,那它提供的方向应该跟所有的参数的方向有关,为什么可以用来更新单一参数?

从整体上来看,梯度方向就是损失函数在高维空间中的最快上升方向,而我们的目的是让损失函数减小,因此更新参数时应该减去学习率乘以梯度。

所有参数在同一时间更新,具体到单个参数,它的更新是由梯度中对应的偏导数分量决定的。

也就是说,新参数 = 原参数 - 学习率 * 梯度,这里做的是线性代数中的向量运算,而不是单个值的计算,可以一次用偏导数组成的梯度更新所有的参数。

6.2. 梯度下降算法本质上就是新参数 = 原参数 - 学习率 * 梯度这个公式吗

是的,你可以直接把梯度下降算法理解为新参数 = 原参数 - 学习率 * 梯度。

梯度下降算法是在反向传播算法的基础之上发挥作用的,因为反向传播算法用来计算梯度,有了梯度以后才可以用梯度下降算法。

7. 损失函数和代价函数是一个东西吗

如果非要严格区分的话,损失函数是计算单个样本的误差,代价函数计算的是整体样本误差的平均值。

但是事实上,这两个定义经常被混用,代码调用loss和function是一样的,所有大多数情况下不需要区分,直接等同混用就行了。

8. 为什么instruction结构要把数据分成instruction, input, output三部分?正常来讲不应该只分成input和output,分别对应问题和回答吗?

这个问题可以参考调用api的代码:

def generate_data(chunk):
    """数据生成函数(保留原实现)"""

    response = client.chat.completions.create(
        model="qwen-plus",
        messages=[
            {"role": "system", "content": "你是一名相机摄影专家,请根据提供的文本片段生成结构化数据"
             "若文本片段信息不够,也可以结合已知相机知识生成结构化数据"},
            {"role": "user", "content": 
             f"文本片段:{chunk}\n\n请生成:\nInstruction:(20字)Input:(50字概括)Output:(分3点,共180字)"
             "生成数据时只是利用到了文本片段中的信息,写input时就当文本片段不存在"
             "不需要说明“文本提供...”以及“文本包含...”,”文档包含“等字眼。"
             "不需要使用Markdown格式,只是普通的文本文件格式"}
        ],
        temperature=0.7,
        max_tokens=500,
        stream=False
    )
    ans_list.append(response.choices[0].message.content)
    return response.choices[0].message.content

我们在调用api的时候,需要先写system的内容content, 再写user的content,这里的system就对应instruction, user就对应input。

其实就是为了先用instruction告诉模型需要扮演的角色或者任务类型,再用input告诉模型具体的任务内容是什么。虽然在写process_func函数的时候把instruction和input部分合并了,但是在给ai提问时还是将提问的内容分为指定角色(instruction)加上任务具体内容(input)更好,更符合提问的习惯。

8.1. 使用因果语言模型时,为什么在process_func函数中要把instruction和input合并的部分的labels写成-100,定义成其他的值可以吗?

pytorch的CrossEntropyLoss默认将babels为-100的位置不参与损失函数计算

也就是说,instruction和input部分的labels只能设置成-100,不能设置成其他值,不能设置成-200, -300等等,这是由pytorch的机制决定的。

参与计算损失函数的部分应该是模型需要预测的部分,而instruction和input是提问,是已知的,只有output部分需要预测,因此只有output部分参与损失函数的计算。

正常来讲,词汇表中>=0的值才是合法值,因此-100肯定不合法,因此设置成-100只是为了显性地告诉模型,-100的位置不需要预测,因此不用参与损失函数的计算。

9. tokenizer的原理是什么,它的核心功能是将词转化为对应的token吗?还有没有其他的功能?

tokenizer.encode(text)可以将文本转化为token

tokenizer.decode(token)可以将token转化为文本

所以tokenizer的作用并不仅仅局限于文本到token的单向转化,可以利用encode和decode进行双向转化。

除了文本转token, token转文本以外,tokenizer还有其他的扩展功能:

  • 末尾添加eos_token, 表示结尾
  • 设置最大长度,小于最大长度就填充,大于最大长度就截断。

10. 你在做毕业设计的过程中遇到过的最大的困难是什么?列举三个

  1. 缺少显卡。单独去买一个显卡太贵了,最开始用的是google colab这个平台,它上面提供有免费的显卡。但是毕竟是免费,导致它有很多的时间限制,经常训练着训练着,显卡的使用时间就到了,然后给你停了,这次训练就白做了。后来解决方法是租用autodl上面的显卡,选择按量计费,一个小时2块钱,完全够用了,虽然还是有上传文件等待时间长的问题,但是在算力方面的问题是解决了。
  2. 缺少高质量数据。网上有很多开源的数据库,它们也是用instruction格式标注的,但是和相机的关系不大。hugging face上面开源的数据库有和相机相关的,但是要么是图片的数据库,要么不是中文,而且格式也不对。而且数据不适合一条条手动标注,因为几千条数据如果一条条手动标注的话就会浪费大量时间。最后是调用了deepseek和通义千问的api, 指定相机领域的主题,如曝光,白平衡,拍摄夜景等等,让它们基于这些主题生成数据,另一个方法是网上搜集各个厂商的相机说明书和相机相关的博客,基于这些文本每500字生成一条数据,并且用multiprocessing.dummy库加速数据生成速度,从几个小时压缩到1分钟以内。
  3. 版本兼容,版本匹配的问题。在写算法的过程中需要用到很多python的第三方库,比如transformers, datasets, pandas等等。但是之前出现过情况就是无论怎么修改训练代码,最后训练的时候都会报错。无论是问ai,查文档,都解决不了问题。持续了好几天,最后发现是不同第三方库之间的版本兼容问题,当我把datasets更新到最新版本以后,报错就消失了。所以版本兼容问题也困扰过我很长时间。

11. 什么是因果语言模型,为什么基于大语言模型微调的相机知识助手开发要用因果语言模型,不使用别的模型?常见的模型有哪些?它们有什么区别?

因果语言模型:模型在预测下一个词时,只能看到当前词之前的文本,不能根据未来的文本预测下一个词。

因果语言模型的核心机制就是单向注意力机制。

  • 因果语言模型, GPT-3, 单向注意力机制,文本生成,对话,续写
  • 自编码模型,BERT,双向注意力机制,文本分类
  • 序列到序列模型,T5,双向编码,单向解码,翻译,摘要,适合转换任务

12. DataCollator有什么用,为什么使用DataCollatorForSeq2Seq而不使用DataCollatorFor别的东西?为什么AutoModelForCausalLM,不用序列到序列,而DataCollator要用序列到序列?

DataCollator:将多个数据样本批量处理成模型的输入

DataCollator的种类:

  • DataCollatorForLanguageModeling: (Masked) 掩码语言,随机隐藏部分token,训练模型预测隐藏Token的能力
  • DataCollatorForSeq2Seq:用于序列到序列的任务,处理输入-输出对的格式,如对话,翻译等
  • DataCollatorForCausalLM:专为因果语言模型设计,处理自回归生成

根据任务类型选择模型,根据数据格式选择数据整理器

12.1. DataCollatorForCausalLM不能做到忽略labels为-100的损失计算?

这句话很重要:

DataCollatorForSeq2Seq会自动忽略label为-100的损失函数的计算,而DataCollatorForCausalLM不会忽略labels为-100的损失函数计算,而本微调算法过程中肯定得把问题部分忽略掉,因此只能用序列到序列的数据整器。

12.2. DataCollator的主要功能有填充,截断,生成注意力编码,而Tokenizer也能够填充,截断,生成注意力编码,所以DataCollator是否多余?

Tokenizer和DataCollator发挥作用的阶段不同。

  • Tokenzier是对单条数据的粗加工,将文本转化为Token
  • DataCollator是对数据的精加工,用来动态处理一个批次中的多个样本

相当于一条生成生产薯片的生产线上,Tokenzier的作用是将土豆切片,DataCollator油炸土豆片。二者都是必不可少的环节,只不过处理阶段不同。

12.3. 既然AutoModelForCausalLM和DataCollatorForSeq2Seq搭配更好,那DataCollatorForCausalLM存在的意义是什么?什么时候使用AutoModelForCausalLM和DataCollatorForCausalLM搭配?

DataCollatorForCausalLM和DataCollatorForSeq2Seq的核心区别是,用于因果语言模型的数据整理器不区分输入和输出,所有位置均需预测下一个词是什么,适用于文本续写;而用于序列到序列的数据整理其会区分输入和输出,可以不计算labels为-100的输入部分。

也就是说,process_func里面把输入部分的labels设置成-100,目的是不计算输入部分的损失函数,这个功能只能用DataCollatorForSeq2Seq实现。

总结一下:

  • 问答型任务用AutoModelForCausalLM + DataCollatorForSeq2Seq
  • 文本续写任务用AutoModelForCausalLM + DataCollatorForCausalLM
  • 翻译任务用AutoModelForSeq2Seq + DataCollatorForSeq2Seq

13. 什么是正则表达式?它有哪些应用场景?(回答的时候可以和xpath比较)

正则表达式,Regular Expression, 是一种用来搜集数据和清洗数据的工具。使用正则表达式的核心是根据原始数据中发现正确的匹配模式pattern, 然后根据pattern找到数据或者清洗数据。

import re

text = "我的生日:2003年6月18日。"

pattern = "生日:(.*?)。"

birthday = re.findall(pattern, text , re.DOTALL)

print(birthday)

无论是用findall查找数据,还是用sub替换或者清洗数据,pattern都是正则表达式的关键。

Xpath也可以用来收集数据,不过Xpath的使用逻辑和正则表达式不一样。正则表达式的核心逻辑式找到pattern, 而Xpath的核心是利用结构化的数据,主要是html写的网页。html中有很多标签,Xpath就是根据这些结构化的标签来提取数据。

如果是简单的网页,收集数据是用正则表达式和Xpath均可;

如果是复杂的网页,那此时想找到对应的Pattern就很困难,就不适合用正则表达式,只适合用Xpath;

如果是非结构化数据,不是网页,比如纯文本,那此时Xpath就失效,只能用正则表达式。

正则表达式是一种基于字符串模式匹配的工具

14. 你调用的是哪家公司的api? 为什么调用它?

刚开始使用的时deepseek的api。当时是春节之前,deepseek还没有那么火,速度还很快,效果价格都不错。后来deepseek爆火以后,api有段时间不能调用,后来即使恢复了速度也是很慢,很容易服务器繁忙。因此就转向了通义千问的api。通义千问效果也不错,而且价格便宜,最重要的是丝毫不卡,所以后来就主要使用通义千问。期间有考虑过使用ChatGPT的api,但是自己充钱的话价格太贵,淘宝买个几块钱的api又质量没有保证,无法使用,而且ChatGPT还有网络问题。所以现在主要是使用通义千问的api

15. 解释multiprocessing.dummy加速数据生成的原理?为什么不用multiprocessing,而要多加一个dummy?

生成一条数据时,将要求发送到服务器,服务器处理完后返回数据。这整个过程中,需要自己电脑CPU工作的时间其实很少,大部分时间都消耗在了网络传输和等待服务器生成数据上,因此它属于IO密集型任务,而不是计算密集型任务。IO密集型任务可以用多线程加速,计算密集型可以用多进程加速。

数据生成属于IO密集型,应该用多线程技术加速,也就对应着multiprocessing.dummy,而不用multiprocessing,因为multiprocessing对应多进程。

具体的加速原理是,既然一条数据的生成过程中只有一小部分时间使用CPU,其余时间都在等待服务器,那么在第一条数据等待服务器时生成第二条数据就可以使用CPU,将第一条数据的等待时间和第二条数据使用CPU的时间重叠。假定一共生成100条数据,可以用Pool设置100各线程,一个线程负责生成一条数据,如果不使用多线程技术,而是用For循环线性生成,那么必须等第一条数据生成完毕后才能去使用CPU,使用多线程技术后可以将第2,3,4,...... 100条数据的CPU使用时间和第一条数据的等待时间相重叠,最终效果就是整体花费的时间近似于一次等待服务器的时间。

16. 怎么判断两个版本的模型的效果好于刚开始的预训练模型?能举例说明吗?(用白平衡的例子说明)

比如提问:什么是白平衡?原模型回答白头,爱情等跟相机毫不相关的东西,效果差。

而微调后的模型效果:有具体操作,也有解释,效果明显好于原模型。

白平衡定义:描述显示器中红绿蓝混合后白色精确度的指标。

17. 为什么做相机领域而不做别的领域,比如为什么不做一个编程助手?

做相机领域一方面是因为我对相机比较感兴趣,我自己有一台相机,想提升拍照水平;另一方面是论文指导老师要求做的东西必须要有新意,不能做重复的东西,编程助手市面上已经有很多了。

17.1. 既然做相机,为什么不做多模块,不做图片生成?

按理来讲,相机方面的大模型应该与图片息息相关,但是目前能力有限,还做不出多模态的模型微调,单纯的文本生成模型难度低一些,还能做出来。日后等技术水平提高了可能会尝试做一个多模态模型。

18. 为什么用pipeline调用模型的时候要设置temperature和do_sample参数?它们分别有什么用?

temperature参数控制回答的稳定度。temperature的取值在0到1之间,越接近0越稳定,越接近1越不稳定。

do_sample控制每次生成的结果是否会变化,do_sample = True则同样的问题每次回答不一样,do_sample = False则相同的回答,每次生成的结果一样。

  • temperature: 控制输出分布的尖锐程度。temperature接近0,则优先选择概率最大的词,输出稳定;temperature接近1则保持原始概率分布;temperature大于1则优先选择低权重的词

temperature的取值可以大于1,大于1表示优先选择低权重的词。

只有当do_sample设置为True时,调节temperature才有效。因为一旦do_sample为False, 那么每次生成的结果必定一样,调不调节温度结果都一样。

19. 解释一下数据格式的演变过程?

  1. 最开始数据是instruction, input, output组成的结构化文本数据

  2. 然后用正则表达式匹配单条数据,用findall()函数放到一个列表中

  3. 用pandas讲这个列表转化为DataFrame, 列名分别是instruction, input, output

  4. 用datasets将DataFrame转化为数据库形式dataset

  5. 用定义好的process_func处理dataset, 这是对数据的粗加工,将文本数据转化为token, 并且经过process_func处理后单条数据就包含input_ids, attention_mask, labels三部分。

  6. 具体训练过程中,数据会交给data_collator动态处理,data_collator会将一个批次中的多条数据进行动态处理。

20. 介绍hugging face, 以及它和python中transformers库的关系

Hugging Face是全球最大的开源AI社区,拥有完善的人工智能生态,包括预训练模型,数据库,学习文档等等,方便开发者学习和使用人工智能。

transformers是Hugging Face开发的核心python库,用于简化预训练模型的使用和微调。

21. 你能解释transformers的实现原理吗?它和全连接神经网络,卷积神经网络,循环神经网络有什么区别?后几种神经网络的原理又是什么?

  1. transformers: 自注意力机制和位置编码。简单理解就是自注意力机制负责生成query, key, value三个矩阵,然后用softmax函数计算注意力得分;而位置编码就是用来弥补自注意力机制的无序性,通过正弦函数或可学习参数为输入序列添加位置信息。
  2. 全连接神经网络:除第一层外,每一层的单个神经元都与上一层的所有神经元连接,y = sigmoid(wx + b)。缺点在于把输入值排成一列,无法利用输入值的相对位置信息。而且参数量过大,无法捕捉局部或者序列化特征。

全连接神经网络的缺点都是和卷积神经网络比出来的。

  1. 卷积神经网络:卷积层通过滑动窗口(卷积核)提前局部特征,共享参数以减少参数量。池化层(比如使用最大池化)可以确保图片的平移不变性。
  2. 循环神经网络:(循环神经网络有用到门控机制,我记得deepseek v3也用到了这个机制,MoE,混合专家,根据门控机制选择专家)循环神经网络的核心原理是通过隐藏状态传递时序信息

21.1. 什么是softmax函数?相比于sigmoid函数它有什么优点?为什么计算softmax函数的时候要使用e而不是直接用数据本身进行计算?

softmax的一大优点就是输出可以表示概率分布,所有的可能性加起来刚好是1

sigmoid只能将各输入分别独立处理,而softmax可以实现各类别的相互影响(归一化,所有可能的概率加起来是1)

相比于sigmoid, softmax更适合用于多类别之间互相牵制,互相影响的情况,总体概率之和为1。而sigmoid不同类别的概率之和有可能超过1,这就不符合实际情况。

softmax使用e的目的是显著放大高得分的影响。比如如果某个类别得分为5, 那么不适用e那分子部分就是5,一旦使用e,分子部分就变成e^5,而e^5远大于5,这样就可以有效放大高的分的概率,由于整体概率之和为1,因此也能有效降低低得分的概率,使结果更有区分度,更显著。

21.2. 为什么参数量大就无法捕捉局部或者序列化特征?无法捕捉局部特征不应该是因为全连接层扁平化的输入忽略了输入的位置信息,这跟参数量无关吗?

我的理解是对的,全连接的神经网络无法有效捕捉局部信息主要是是跟输入的时候所作的扁平化处理有关,跟参数量大没什么关系,参数量大只是低效的副作用。

21.3. 详细介绍循环神经网络的原理,循环神经网络相比于全连接神经网络做了哪些改进?

循环神经网络的核心就是利用隐藏状态记录历史信息,全连接神经网络无法记录历史信息,而且要求每次输入的长度必须固定,而循环神经网络可以用隐藏状态记录历史信息,而且允许输入长度的变化。

22. 什么梯度下降算法?什么是反向传播算法?它们之间有什么关系?

它俩的使用是一先一后的关系,类似于同一流水线上的不同处理阶段。正确的顺序是先使用反向传播算法,正向传播计算损失函数,反向传播计算梯度,得到梯度以后再使用梯度下降算法,梯度下降算法的核心公式是新参数 = 原参数 - 学习率 * 梯度。梯度正是反向传播算法根据损失函数不断求偏导算出来的,基于链式法则,类似于复合函数求导。

注意一下批量梯度下降和小批量梯度下降的区别。批量梯度下降指的是用所有的样本数据来计算梯度,小批量梯度下降是指每次都只用一个batch来计算梯度。

22.1. 当使用小批量梯度下降时,不同的小批量计算出来的梯度应该不一样,那么最终的梯度应该选取哪次小批量的梯度,最后的操作时取平均值吗?

每个小批量更新得到的梯度直接就用来更新参数了,而不是把当前梯度存储下来。

最终确定的是参数,也就是权重和偏置,而不是梯度,梯度在每次计算出来以后就直接用于更新参数了。

22.2. Adam优化器是一种自适应学习率优化算法,是不是意味着adam优化器可以自动调节学习率?

目前对adam优化器的理解,不用深究其底层原理,只需要知道它的功能。

adam优化器有两个主要功能:

  1. 自动调节每个参数更新时的学习率
  2. 积累梯度方向,减少震荡,加速收敛

22.3. 优化器是什么,它可以用来调整超参数,比如学习率,批次大小吗?

优化器主要有两个作用:第一个是实现梯度下降算法,更新参数(只是权重和偏置这些参数,而不是超参数),第二个作用是加速收敛,积累历史梯度方向,避免陷入局部最小值。

所以优化器和超参数的设置并没有直接关系。神经网络层数,批次大小都需要手动设置,部分优化器如Adam可以自动调节学习率,但也仅限于学习率,优化器本身的作用是更新参数,加速收敛,和超参数的取值无关。

22.4. 为什么反向传播算法计算梯度时要反着计算而不是正向计算?为什么这样做可以降低计算量?举例说明

正向计算和反向计算的核心区别是计算的起点是x还是L

正向计算梯度和反向计算梯度相同点是都利用了链式法则,也就是对复合函数求导,但是区别在于正向计算梯度是从x开始计算的,而反向计算梯度是从L开始计算的。

23. 解释梯度爆炸和梯度消失的原因,以及对应的解决方案?

梯度消失和梯度爆炸的根源在于链式法则,多个梯度相乘。当多个连乘的梯度小于1时,最后的结果就无限接近0,导致梯度消失;当多个连乘的梯度大于1时,最后乘出来的结果就很大,导致梯度爆炸。

如果激活函数选择的是二次代价函数,可以通过将激活函数从sigmoid替换为ReLU来解决梯度消失的问题;

如果激活函数选择的是交叉熵代价函数,那么激活函数可以选择softmax以避免梯度消失;

解决梯度爆炸的方法:限制梯度最大值,比如Transformer限制为1

23.1. 为什么呢用ReLU替换sigmoid可以解决梯度消失的问题,用softmax替换sigmoid不能解决梯度消失的问题?

ReLU的厉害之处就在于它是max(0, x), 求导以后可以发现自变量小于0时导数为0,自变量大于0时导数为1,1再参与链式法则时,无论怎么计算都是1,不会发生连乘值越来越小的情况。

23.2. 二次代价函数搭配ReLU, 交叉熵代价函数搭配softmax, 这两种搭配都可以解决梯度消失的问题吗

二次代价函数+ReLU激活函数能否解决梯度消失的问题取决于任务的类型。回归任务可以解决梯度消失,分类任务不行。

交叉熵+Softmax可以解决梯度消失。

到底能不能解决梯度消失的问题不仅得看二次代价函数和激活函数的搭配,还得看任务的类型。

23.3. 交叉熵代价函数相比于二次代价函数的优势是什么?

二次代价函数常用于回归任务,交叉熵代价函数常用于分类任务。

当任务类型是分类任务时,交叉熵代价函数能避免梯度爆炸,加快训练速度,并且搭配softmax还能让分类结果具有可解释性。

24. 怎样扩展数据,常见的数据扩展方式有哪些?

如果是图片数据,可以通过顺时针或者逆时针旋转一个小角度得到新数据,或者上下左右各平移1个像素得到新数据。如果是文本数据,可以通过回译的方法得到新数据,比如中文到英文到中文。但是回译有可能出现翻译错误的情况,因此不太推荐。或者调用api, 把原数据一条条让AI保持意思不变,换一个说法。

25. 为什么毕业设计要选择做大语言模型微调,当时有考虑过别的选择吗?

最开始也不确定做什么,只是想做一个AI相关的。刚开始跟论文指导老师讨论的时候,想过从零开始构建神经网络,然后训练一个模型,就是不适用预训练模型;但是老师说重复造轮子没有意义,有预训练模型就直接用。还考虑过基于Bigram架构做一个模型,但是Bigram做出来的东西并不好,它只能根据前一个词预测下一个词,没有长文本的能力。最后在老师的建议和我的想法下,最终决定做一个大语言模型微调的项目。

26. 什么是激活函数?列举常见激活函数以及它们的优缺点

激活函数通用的功能是将线性变换转换为非线性变化,增强模型拟合复杂函数的能力。

常见激活函数:

  • sigmoid函数:1/(1 + e^(-x))它可以把wx+b压缩在0-1之间
  • softmax函数:e^zi求和分之e^z,实现归一化
  • ReLU函数:max(0,x),当x>0时,求完导导数为1,解决梯度消失问题
  • Tanh函数:(e^x - e^(-x)) / (e^x + e^(-x)) ,奇函数,关于(0,0)对称

deepseek回答:

激活函数是神经网络中的非线性变化组件,它的主要功能有1.将线性变换改为非线性变换 2.将输入映射到新的空间 3. 通过导数调节梯度,提高训练过程的稳定性。

用sigmoid极容易出现梯度消失的情况,因为sigmoid图像中导数最大值也只有0.25,连乘几次就很接近0了。

27. 什么是代价函数?列举常见代价函数并介绍它们的优缺点

代价函数用来指明损失函数的计算方法,就是通过哪种方式计算损失函数。

常见的代价函数有二次代价函数,交叉熵代价函数。二次代价函数适合做回归任务,交叉熵代价函数适合做分类任务。

deepseek回答:

代价函数 = 损失函数(直接等同就好了,不需要跟前面一样作硬性区分),用来量化预测值与真实值之间的差异。 代价函数越小,说明预测值越接近实际值,模型效果越好。