12月18日至19日,火山引擎FORCE原动力大会在上海举行,会议上最引人关注的无疑是豆包视觉理解模型的发布。该模型为大模型家族新增了视觉理解能力,结合了图像识别、推理和文字识别等多种能力,打破了传统视觉理解的边界。通过加入视觉理解,大模型可以像人类一样认识和理解现实世界,拓展了人工智能的应用场景。尤其是在中文的通用知识和文字识别中,豆包视觉理解模型的表现领先全球,仅次于GPT-4o。 "Image 29" (https://wm-ai.oss-cn-shanghai.aliyuncs.com/test/1e81ab40-9d60-4418-829e-5cfbb121a9a0.png) 豆包视觉理解模型具备卓越的内容识别能力,可以准确识别图像中的物体、场景及其关系,甚至能够通过影子的形状辨认动物,识别物体间的空间布局。此外,它的OCR能力更是行业领先,可以从图片中提取和理解文字信息,包括日常图像和复杂的表格图像。 模型还具备强大的推理能力,能够进行复杂的图片推理任务,处理图表、数学问题、代码图像等复杂场景,快速提取关键信息,提高分析效率。 "Image 30" (https://wm-ai.oss-cn-shanghai.aliyuncs.com/test/e421fefe-f0a5-41be-a677-f43cb839bae3.jpg) 在理解和推理方面,豆包视觉理解模型表现出色,能够处理多个图像内容并提供详细的描述。它可以生成各种创作内容,包括产品描述、广告文案和故事脚本,甚至可以根据用户提供的图片生成符合用户需求的文案。 "Image 31" (https://wm-ai.oss-cn-shanghai.aliyuncs.com/test/b2d61afe-e891-496d-9523-83c182fe9b6c.jpg) 豆包视觉理解模型不仅提升了AI在视觉领域的应用能力,也为更多行业提供了可能的技术突破。通过与智能终端、金融、消费、汽车等行业的合作,豆包大模型正在加速推广,成为推动行业AI发展的关键力量。 通过技术创新和市场的广泛应用,豆包大模型的能力得到了充分验证,预计将在更多领域取得成功。 "Image 33" (https://wm-ai.oss-cn-shanghai.aliyuncs.com/test/9e877a13-c285-4845-8704-7f9abe7a4199.png) 此次大会还展示了豆包大模型家族的全面升级,其中包括提升了语音生成、3D生成和视频生成等能力,进一步加强了AI在多个行业的应用。 "Image 34" (https://wm-ai.oss-cn-shanghai.aliyuncs.com/test/050f04ab-7aff-4abd-a3f5-6923e7f4b898.jpg) 随着豆包视觉理解模型的推出,未来将推动大模型在各行各业的深入应用,推动AI技术的快速发展。
桃树、杏树、梨树,你不让我,我不让你,都开满了花赶趟儿。红的像火,粉的像霞,白的像雪。花里带着甜味儿;闭了眼,树上仿佛已经满是桃儿、杏儿、梨儿。花下成千成百的蜜蜂嗡嗡地闹着,大小的蝴蝶飞来飞去。野花遍地是:杂样儿,有名字的,没名字的,散在草丛里,像眼睛,像星星,还眨呀眨的。朱自清在写《春》的时候,或许也没有完全认清春天的所有花,以至于写出了“有名字的,没名字的,散在草丛中”这样的句子。如今,时代变了。人手一部手机的我们,遇到不认识的花,随时随地就可以打开手机百度识图功能来完成识图。“杂样儿的,有名字的,有名字的,有名字的,有名字的 ... 都散落在手机里,像眼睛,像星星,还眨呀眨的”!而让我们如此轻松加愉悦的完成识图功能的,便是手机背后运行的大量卷积神经网络,或者说是CNN网络。大家好啊,我是董董灿。上篇文章Resnet图像识别入门——卷积的特征提取介绍了通过卷积这一算法进行特征提取的原理和应用。接下来,沿着Resnet50这个神经网络,介绍一下这个图像分类网络,以及它的核心思想——残差结构。为什么叫Resnet50研究AI网络的人拥有网络命名权。比如我研究出来一个网络,效果很好,要发一篇论文来介绍这个网络,论文中需要给网络起个名字,并且希望这个名字可以流传很广。那么,简单、好记同时又能概括网络思想的名字肯定是首选。Resnet50 就是这样的名字,这个网络的核心思想,就藏在名字里。Res + net + 50,Res 是 Residual (残差)的缩写,50 指的是整个网络中有50个卷积层。下图是Resnet50的网络结构图,可以看到,从第一层到最后一层,总共50个卷积算法。 那么Res(Residual)残差又是个什么东西呢?残差结构所谓残差结构,其实就是在正常的神经网络中,增加一个 short cut 分支结构,也称为高速公路。比如上图中,左侧是正常的卷积层,一层层往下传,在右侧增加一条连线,使得整个网络结构形成了一个残差结构。这样,网络的输出不再是单纯卷积的输出F(x),而是卷积的输出和前面输入的叠加F(x) + X。为什么要增加残差结构在前面说过,深度卷积神经网络在网络深度不断加深的过程中 ,神经网络会学到不同的特征。但是,能无限制地加深么?比如使用1000层卷积层进行网络的训练的。答案显然是不行的。原因在于神经网络训练的过程是不断与目标值进行拟合的过程,直到拟合的误差降低到人们的预期,代表着神经网络训练完毕,一个会识图的AI就诞生了。但是在实际训练过程中,数据的传递除了从网络前端往后传之外,还需要将最后一层与目标值的误差传回到网络前端,从而进行下一轮的训练,得到更小的误差,这一过程成为神经网络的反向传播。在往回传的过程中,由于误差本身就很小,如果卷积层数过多,在经过激活函数时,很容易发生误差传着传着就消失了,称为梯度消失。梯度消失的原因有很多种,不好的激活函数、过深的网络层数等都有可能导致误差消失。想象一下,上一轮训练结果的误差传不回来,下一轮如何在上一轮的基础上进行进一步优化训练?结果就会导致怎么训练神经网络最终的结果都无法收敛。AI根本训练不出来!残差来救场残差结构这个时候就可以发挥作用!想象一下,这个高速公路的存在,可以使得输入数据无损地通过。如果左侧卷积层学习到的数据不够好,那么叠加上无损通过的原始数据,依然保留了原始数据,不至于丢掉原始数据。而如果左侧卷积层学习到的效果很好,那么依然会保留着学习到的数据,下面的卷积层依然可以在这些数据基础上进一步学习优化。反向传递也是一样,高速公路的存在,可以确保即使很小的误差也能传递过来,从而避免了梯度消失的发生。说回Resnet50,这个网络就是通过50层卷积的计算,外加残差结构连接,来完成图像分类的。实际上,目前各大公司直接使用Resnet50进行图像分类是很少的,大多数公司会在这个网络的基础上,结合自家公司的业务场景进行改造,或者直接借鉴Resnet50的网络设计思想,重新设计新的网络,以期获得更加高效的识图效果。看到这,你或许能够了解,当我们打开百度识图完成图像识别时,它的背后,可能不是Resnet50这一网络,但肯定是有卷积和残差这两个算法! Resnet ,简单,暴力,有效Resnet50网络的结构其实说简单,它很简单,而且算法思想也很简洁,就是50层卷积的计算,依据卷积局部感受野这一特性,抽取出图像的不同特征,通过最后一层卷积(或者叫做全连接)将图片进行分类。这样的网络设计,分类效果很好,使得 Resnet50 多次在图像分类大赛中夺冠!Resnet50除了大量使用了卷积这一算法之外,一个简单暴力的残差结构的应用,使得该网络无论在训练还是推理过程中,其效果都极为出彩!从此,残差这一结构,受到了人们的关注,以至于,有人开始专门研究不同层之间的残差连接。结合上一章的内容,一句话总结一下Resne50的核心就是:灵魂在于卷积算法和残差结构,而卷积算法的灵魂是特征抽取。好啦,残差结构就介绍到这。后面会继续拆解Resnet50这一网络中的经典算法和思想。欢迎持续关注。
大家好啊,我是董董灿。经常看我文章的同学,可能知道最近我在做一个小项目——《从零手写Resnet50实战》。从零开始,用最简单的程序语言,不借用任何第三方库,完成Resnet50的所有算法实现和网络结构搭建,最终将下面这只猫识别出来。不幸的是,在刚搭建完网络之后,就试着运行了一下自己的神经网络,识别结果是错的。没办法,只能用 torch 搭了一个官方的网络,和我手写的神经网络,一层一层进行结果比对,然后调试(从零手写Resnet50实战——利用 torch 识别出了虎猫和萨摩耶)。幸运的是,在经过一个数据一个数据对比之后,我的神经网络。出猫了!它竟然真的将猫识别出来了! 我的神经网络出猫现场在从1000个分类得分中,将最大值的索引(第282号)挑出来之后,查询分类文件,便得到了分类结果:tiger cat。这个网络我没用 softmax。因为 softmax 的作用是将结果“大的变得更显著,小的变得更微弱”,并不会改变结果的相对大小。我直接从最后一个全连接层的输出,去找了最大值索引。softmax的作用可以参考softmax原理。过程记录识别出猫的过程,说难也不是太难,说简单但又有不少坑。最难的在于出猫失败,查找原因的过程,是真的一层一层的进行结果对比。好在我封装了一个对比函数,能帮助我在重要的网络节点,验证我的网络是否正确。下面是出猫全流程记录。首层 Conv2d + 第一个 BatchNorm2d + MaxPool 验证正确。第一个 Layer 验证正确,共 10 个 Conv2d。第二个 Layer 验证正确,共 13 个 Conv2d。第三个 Layer 验证正确,共 19 个 Conv2d。第四个 Layer 验证正确,共10个卷积。AvgPool 和 FC 层也都验证正确。整个验证过程还是挺痛苦的,但是看着一层层的打出来“succ”(success的缩写,说明和官方结果是一致的),还是很有成就感,并且挺治愈的。下面简单说一下我在出猫过程中遇到的那些坑保存权值文件 layout 搞错torch 默认的图片数据摆放格式是 NCHW,而我习惯写算法的方式是NHWC。因此,在前期将图片导出时,没有考虑自己算法实现的习惯,而是将权值直接 flatten之后保存了。结果就是,再将权值从文件中读入内存参与运算时,数据读取不正确。结果肯定是错的。意识到这一点之后,因为我算法都已经写好,而且不想改了,于是,将保存权值的逻辑,在 flatten 之前,添加了一个 transpose 操作,将权值从NCHW 转为 NHWC,然后保存。BatchNorm2d 的均值和方差使用错误BatchNorm2d的算法实现有多种,特别需要注意的是需要区分该算法是在训练时用的还是推理时用的。训练和推理时用的BatchNorm2d虽然公式是一样的,但实现方式却大不一样。主要区别在于:训练时均值和方差需要根据本次的数据进行实时计算推理是使用的均值和方差是模型保存好的参数,在 torch 模型中,分别为 BatchNorm2d.running_mean 和 BatchNorm2d.running_var。而我在最开始的算法实现时,均值和方差是自己手算的(对应的训练过程),而没有使用模型保存的均值和方差。结果便是每层BatchNorm算出来的结果都差一点,这一点误差在层与层之间传递,导致到最后的识别结果中,误差被放大。正是因为这个误差被逐层放大,就把猫识别成了一个水桶。残差结构问题上一篇文章从零手写Resnet50实战——利用 torch 识别出了虎猫和萨摩耶分析残差结构可能会有问题。实际验证残差结构没问题,就是一个简单地加法。有问题的是上一层的BatchNorm2d,计算错误了。那为什么计算错了,当时的分析仍然能和官方的计算结果对上呢?是因为当时的官方计算忘了一个 model.eval() 调用。该调用会告诉模型运行在推理模式而不是训练模式。而如果我不调用,显然用的训练模式,恰巧的 BatchNorm2d 的第一次实现,手算均值和方差,就对应了训练模式的算法。于是结果刚好对上了,但这样最终识别的图片分类肯定还是错误的。基本就遇到了这3个问题,在把这3个问题解决了之后,整个预测过程运行了大约40分钟,猫就被顺理成章的预测出来了。于是,项目的第一阶段,就这么完成了。下面会开启本项目的第二阶段——神经网络性能优化。用C++ 重新实现一遍所有算法:因为C++性能要比 python 手写的算法性能好很多重点优化卷积的性能:目前40多分钟有将近39分钟的实践花在了卷积上使用C++实现的版本争取在数秒内完成一张图片的推理因为本次有2/3的坑都是BatchNorm算法引起的,后面会写一篇BatchNorm算法的文章,欢迎继续关注。出猫,看起来也很简单。欢迎持续关注本博主文章和本系列,一起从零开始,学算法,做实践项目。 这是一个可以写到简历上,亮瞎面试官双眼的项目哦。
如果让你设计一个可以识别图像的神经网络,你会怎么做?我之前问过自己这个问题,思来想去,我的答案是:我可能不知道如何下手。突然有一天,当我把Resnet50这个网络的所有算法都写完一遍之后,我突然觉得,只要我深入了解了这些算法的原理,或许这个网络我也能设计出来。于是,我有了一个大胆的想法:从头开始,拆解一个典型的图像识别网络是怎么工作的,以及它里面所涉及的背景知识和算法原理。你可能会想,看懂这些需要什么知识呢?其实不需要太深奥的数学知识。我尽可能把每一步写的通俗易懂,这个过程中我会搜集一些资料,也是一个不断完善自己知识体系的过程。这个网络,就用Resnet50吧。像素要实现图像识别,最离不开的,就是像素。其实我们都知道,图像是由像素组成的。实际上,神经网络计算,算的就是像素之间的关系,以及这些关系背后可能隐藏的图片信息。相机摄像头像素2000万,拍出来的照片肯定比像素1000万的要清晰,我们更容易看到图片中的物体是什么。这是为什么?因为像素越多,像素之间的关系(色彩,轮廓)越丰富,我们所能看到的信息就越多,自然而然获取到的信息就多。但是,你有没有发现。当我们去看一张图片时,我们绝对不是盯着某一个像素或某几个像素看,而是看了整个图像的大部分区域,或者说,我们看到了大部分像素。因为只有看到了大部分的图片,才能知道图中是座山。正所谓,聚沙成山,绝不是少了一粒沙,山就不是山,多了一粒沙,就变成了山。上图哆啦A梦,虽然不是很清晰,像素点数也很少,但一眼望去,依然可以分清是哆啦A梦,甚至,用手捂住一半的图像,依然可以。这是因为人们对于图像信息的识别,是建立在对像素局部性分析的基础上的。像素局部性所谓局部性,通俗点说,就是眼睛或大脑会将相邻的像素或大片的像素连接起来分析,从而组合成嘴巴,然后是耳朵,最后是哆啦A梦。而一个人工神经网络识别图片的过程,大致就是如此:神经网络模拟的,就是人们看到图片之后的信息处理过程。当我们盯着一个图片看时,我们首先会获取到图片的细节特征,比如哆啦A梦红色的大嘴巴。但是如果仅仅盯着大嘴巴,又反而让人有一种“只缘身在此山中”的感觉,并不能看到整个图片的全貌,因此还需要看一下图像的轮廓。于是,眼睛看图片就有了以下两个过程:瞳孔放大,盯着某一处细节(如大嘴巴)看瞳孔缩小,模糊的看一张图片的大致轮廓两个过程看到的信息,在大脑中叠加,那就看清楚了,是哆啦A梦。那么神经网络是否可以模拟这种瞳孔放大、缩小的方式呢?很幸运,可以,那就是利用卷积核。卷积运算模拟人眼感受野卷积核投影在原始图片上的区域,称之为感受野。通过设计不同大小的卷积核,就能获得不同大小的感受野。如此,卷积核就可以很直观的模拟瞳孔张开、缩小的过程。并且大量的实验和论文表明,卷积这一针对图像局部性识别的算法,可以非常有效的模拟人眼识别物体的过程。关于卷积算法以及卷积核的设计,后面会专门写文章,欢迎持续关注本系列。色彩分量RGB回到像素这一话题。你有没有想过,为什么一张图片会是彩色的。学过摄影的小明同学可能这时会回答:因为图片是由RGB三种颜色来表示的,每个像素实际是不同的R/G/B分量的叠加,混合起来,就表示成了不同的颜色。回答正确。我们人眼可以很直观的看到红色和蓝色,可以察觉到一张图片的色彩和轮廓。那么,如果让计算机来处理图片,它又是如何知道色彩和轮廓的呢?其实对于计算机来说,一张图片存在在内存中,只是一堆数据,计算机是无法知道这堆数据代表的是什么。这就需要人为的给这堆数据一种表示方法,让计算机知道:哦,这1/3的数据是红色分量,这1/3的是蓝色分量,剩下1/3的数据是绿色分量。还得让计算机知道,一些数据(像素)组合起来,可能代表的是个“帽子”。怎么做呢数据在计算机的存储中,最常见的存储方式是连续存储的。比如在C语言编程中,我们可以定义一个数组,那么数组在内存中的位置是连续的。int data[10] = {0,1,2,3,4,5,6,7,8,9}; 内存怎么理解,它就是一排连着的门牌号的宿舍。门牌号为101里面住着的,是data的第一个数据0;门牌号102里面住着的,是data的第二个数据1,...,以此类推。只不过,在计算机存储器中,没有门牌号,有的都是地址。这个时候,计算机根本就不关心数据是啥,计算机用到的时候,就把数据从内存对应的地址中取出来用。如何取数据这就需要人们为数据存储设计一种格式,告诉计算机,这堆数据大概是什么样的。只有这样,通过这种人为约定的方式,计算机才能正确的取到R分量或者B分量。对于一张图片来说,最常见的两个参数是长和宽,一般用H(height) 和 W(width) 来表示,那么RGB三个分量,看作是3个通道(channel),一般用 C 来表示。如此一来,一张长宽分别是224像素和224像素的RGB图像,就可以用 HWC = [224, 224, 3]来表示。两张类似的图片就用 NHWC = [2, 224, 224, 3]表示,其中N代表图片张数。友好的数据表示方法,可以减少大量的计算复杂度。虽然这样表示不太利于人们的直观理解,但是计算机处理这种数据是十分方便的。在目前主流的深度学习框架中,对于图片的数据格式,基本都支持了NHWC或NCHW这种数据摆放格式。说到底,都是为了更高效地进行图片数据的处理和运算。像素女神熟悉OpenCV或者计算机视觉的同学,可能对于上面的RGB分量中的女神很熟悉。没错,在很多的教程中,这位女神不止一次的出场。这位女士名叫 Lena。电气电子工程师学会图像处理汇刊 (IEEE Transactions on Image Processing)主编曾在1996年1月出版的一期中解释道,Lena的流行,因为她是一张好的测试图片,其中包含了很多细节,平滑区域,阴影和纹理。当然,另外一个原因就是漂亮美女的图片自然受到男性居多的研究领域的欢迎。
大家好啊,我是董董灿。这是从零手写Resnet50实战的第3篇文章。请跟着我的思路,一点点地手动搭建一个可以完成图片分类的神经网络,而且不依赖第三方库,完全自主可控的手写算法。如对网络中的算法和原理不太熟悉,请移步万字长文解析Resnet50的算法原理。我的目标是,识别出下面的这张图片是一只猫:项目地址:从零手写resnet50。正文上一篇文章权值另存为,我们已经把Resnet50中的所有权值参数都保存到txt中了。接下来,把上图中猫的图片导入到内存中。# 使用 Pillar 库来导入图片 # 仅使用该库导入图片 # 不使用该库进行任何其他的计算操作 from PIL import Image # 读打开图片并读入到 img 中 img = Image.open('../cat.jfif') # 将图片resize成长宽为(224,224)的图片 img = img.resize((224, 224)) 这里说一下为什么要做 resize?因为 Resnet50 首层卷积,接收的是一个 3 通道的图片数据。如果图片长宽太大,会使得卷积运算量过大,运行速度很慢,这一点在本文后面的实验可以看出来。而且在试验 Resnet50 中,一个很常见的使用小图做运算的方法,便是将不规则大小的图片 resize 成(224,224)。其中两个 224 分别代表图片的长和宽,3 代表图片有 3 个通道。在将图片导入到内存中之后,剩下的就是要将图片数据输入到神经网络中。但在此,需要先将核心算法完成,才能搭建成神经网络。手写算法之——卷积在Resnet50中,存在 6 种算法,分别是卷积(Convolution,Conv)批归一化(Batch Normal,BN)池化(Pooling)激活(Relu)加法(Add)全连接(Fully Connected, FC)其中,Conv 和 FC 可以看作一类:都是在某些维度做乘累加计算;Pooling与卷积类似,只不过少了channel维度的累加。BN是对输入数据的做批归一化操作,算法实现也不太难;而激活和加法就更简单了,属于两行代码就能搞定的算法。所以,擒贼先擒王,先手写一个卷积算法试试水。# 使用NHWC的 layout 来计算 # 卷积暂时不考虑 dilation 的存在 # 因为Resnet50中的卷积都不带 dilation 参数 def my_conv2d(img, weight, hi, wi, ci, co, kernel, stride, pad): ''' img:输入图片数据 weight:权值数据(卷积核) hi:输入图片高度-height wi:输入图片宽度-width ci:输入图片通道-channel,与weight的channel一致 co:输出图片通道-channle,与weight的个数一致 kernel:卷积核的大小 stride:卷积核在输入图片上滑动步长 pad:输入图片周围补充的pad值 ''' # 通过输入参数计算输出图片的长和宽 # 在 Resnet50 中,卷积核在 h 方向和 w 方向的 # 尺寸都是一样的,pad 也都是一样的,因此, # 这里用一个值来代表。 ho = (hi + 2 * pad - kernel) // stride + 1 wo = (wi + 2 * pad - kernel) // stride + 1 # 将权值数据 reshape 成 co, kh, kw, ci 的形式 weight = np.array(weight).reshape(co, kernel, kernel, ci) # 在输入图片周围补充pad值 img_pad = np.pad(img, ((pad, pad), (pad, pad), (0, 0)), 'constant') # 初始化输出图片 img_out = np.zeros((ho, wo, co)) # 下面是卷积计算的核心逻辑 # 其效果类似于 nn.conv2d for co_ in range(co): for ho_ in range(ho): in_h_origin = ho_ * stride - pad for wo_ in range(wo): in_w_origin = wo_ * stride - pad filter_h_start = max(0, -in_h_origin) filter_w_start = max(0, -in_w_origin) filter_h_end = min(kernel, hi - in_h_origin) filter_w_end = min(kernel, wi - in_w_origin) acc = float(0) for kh_ in range(filter_h_start, filter_h_end): hi_index = in_h_origin + kh_ for kw_ in range(filter_w_start, filter_w_end): wi_index = in_w_origin + kw_ for ci_ in range(ci): in_data = img[hi_index][wi_index][ci_] weight_data = weight[co_][kh_][kw_][ci_] acc = acc + in_data * weight_data img_out[ho_][wo_][co_] = acc return img_out 上面是手写的一个卷积算法,采用了最原始的堆叠循环的方式,没有对算法做任何的优化。之所以这么写,是因为这样可以很清晰地看到卷积的计算过程。将图片输入给卷积进行运算在定义完上述卷积运算后,就可以将上一步导入的图片,输入给卷积,计算一下试试水了。# 读入图片并转换为指定大小 img = Image.open('../cat.jfif') img = img.resize((224, 224)) # 将Pillow Image对象转换为numpy数组 # data is layout as NHWC out = np.array(img) # 这个函数用来从保存的权值文件中读取权值数据 def get_weight_from_file(f): k = [] with open(f, 'r') as f_: lines = f_.readlines() for l in lines: k.append(float(l)) return k import datetime # resnet50 第一次卷积的权值保存在项目中的路径 file_name = "../model_parser/dump_txt/resnet50_conv1_weight.txt" # 将权值加载到内存中,赋值给K k = get_weight_from_file(file_name) # 打印当前时间戳 print(datetime.datetime.now()) # 调用手写的卷积进行计算,输出卷积结果 out = my_conv2d(out, k, 224, 224, 3, 64, 7, 2, 3) # 打印计算完成的时间戳 print(datetime.datetime.now()) # 打印卷积计算结果的 shape print(out.shape) 上面在调用 my_conv2d 之前,加了两个时间戳打印,看一下这个卷积运算的耗时。$ 2023-04-13 08:21:20.473301 $ 2023-04-13 08:23:00.855593 从时间戳上可以看到,两个时间戳之间的间隔在1分多钟,说明这个卷积运算消耗了1分多钟,这可能与我用的虚拟机配置很低有关。不过这种循环堆叠的卷积实现方式,很耗时是真的。在卷积运算完之后,把这一层的输出的 shape 也打印出来。$ (112, 112, 64) 可以看到,卷积的输出 shape 为 (112, 112, 64),通道数由输入图片的 3 通道变成了 64 通道,是因为使用了 64 个卷积核。这里64个通道,实际上可以理解为这一层卷积在原始输入图片的像素之间,抽取出了 64 个特征出来。 至于是什么特征,我也不知道,有可能是猫的鼻子和耳朵。至于上面说的卷积运算耗时的问题,暂时先不管他。在完成整网的推理,正确识别出来猫之后,我会继续将算法都优化一遍的。后面还有 Pooling, Bn 算法的手写,写完之后,就可以按照 Resnet50 的结构,搭出神经网络来了。今天,离识别出来猫,又进了一步。
1. 如果想要在某个模型基础上做全参数微调,究竟需要多少显存?这个问题首先需要了解 BF16 和 FP16, BF16 是对 FP32 单精度浮点数截断数据,即用 8bit 表示指数,7bit 表示小数。FP16 半精度浮点数,用 5bit 表示指数,10bit 表示小数。与单精度相比,采用 BF16/FP16 吞吐量可以翻倍,内存需求可以减半。这两者精度上差异不一样,BF16 可表示的整数范围更广泛,但是尾数精度较小;FP16 表示整数范围较小,但尾数精度较高。通常微调用 bf16,推理用 fp16,当在模型大小为 XB 且参数精度为半精度,推理所需显存约为 X 的两倍,而全参数微调所需显存约为推理所需显存的四倍,包括模型推理(一倍)、梯度(一倍)、优化器(两倍),也就是 X 的八倍。2. 为什么SFT之后感觉LLM傻了?数据分布偏差:在 SFT 过程中,采用的微调数据集可能与模型在预训练期间所接触的数据存在较大差异,可能会削弱模型的表现,这种分布的不一致可能会导致模型在应对新任务时做出错误或不精确的预测。标注异常:在微调数据集中可能存在标注错误或标签不精确的情况(即使质量较低的数据集很少也会对模型产生负面影响)。这类不准确的标签可能会对模型的性能造成不利影响,使得模型表现出不合逻辑或错误的行为。过度拟合现象:如果用于微调的数据集规模较小,或者模型的参数量过于庞大,可能会导致模型对微调数据集过拟合,从而使得模型在新样本上的表现力下降。这种过度拟合的问题可能使得模型对微调数据集中的特定实例过分敏感,而不能有效地推广到新的、更广泛的数据上。数据集多样性不足:用于微调的数据集可能没有足够的多样性,未能覆盖模型在执行新任务时可能遇到的各种输入类型。这种多样性的缺失可能会导致模型在遇到与微调数据集显著不同的新输入时,表现出困惑或做出错误的决策。3. SFT 指令微调数据如何构建?原始数据采集:需要收集与目标任务相关的原始数据。可以涵盖了从对话实例、分类项到生成任务的数据样本,具体依据目标任务而定。要注意保证数据集既具备足够的代表性也要有广泛的多样性,这对于增强模型的泛用性至关重要。通常我们需要训练模型的对话能力,因此我们就要考虑多收集单轮对话和多轮对话的数据集。数据标注:对采集到的原始数据执行打标操作,给予每一个数据样本恰当的标签或是目标输出。打标的形式将基于您的具体任务而定,可能包括分类标签、文本生成内容或是对话反应等。保障打标工作的精确性与一致性。数据集分割:对已打标的数据执行分割,以便区分出训练集、验证集和测试集。通常将大量数据指定为训练用途,取一小部分进行模型性能验证,以最终评估模型泛化性能。数据预处理:针对任务需求对数据进行必要的预处理步骤。这可能包括文本清理、分词处理、去除无用词汇、词根提取等操作。确保最终的数据格式满足模型输入的规范,同时将数据转换成适合模型训练的格式。4. 领域模型 Continue PreTrain 数据选取?收集垂直领域数据:首先搜集与目标专业领域密切相关的数据,可以包括网络爬虫获取数据、特定行业文档或企业内部的信息资源等。这类数据能够丰富模型的专业知识库和语言理解能力,进而提升模型在该领域的性能表现。领域专家参与打标:可以让领域专家对相关数据进行精确筛选和打标。这一步骤涉及各类任务,如类别归纳、实体识别、关系提取等,旨在为模型训练提供精确无误的监督数据。使用伪标签:在无法获得领域专家支持或数据打标成本较高时,可以利用自动化技术生成伪标签。例如,运用已预训练的模型对特定领域数据作出预测,并将这些预测结果作为伪标签用于进一步训练。通常会通过 ChatGPT 生成相关数据进行知识蒸馏。保证数据均衡:在选择数据时,要关注数据的平衡性,不仅要灌输垂直领域的数据,还应该添加一定比例的通用领域数据。对于样本量不足的类别,可考虑应用数据增强或过采样技术,以实现数据量的平衡。5. 领域数据训练后,通用能力往往会有所下降,如何缓解模型遗忘通用能力?如果仅仅使用领域数据集进行模型训练,模型很容易出现灾难性遗忘现象,为了解决这个问题通常在领域训练的过程中加入通用数据集。但对于领域数据集和通用数据集应该按照什么比例目前还没有一个准确的答案。如果领域数据集数据量没有那么多时,一般领域数据与通用数据的比例在1:5到1:10之间。6. 领域模型Continue PreTrain ,如何让模型在预训练过程中学习到更多的知识?增大数据收集范围:收集垂直领域数据可以来自互联网、论文、书籍等等多个方面的数据。将这些数据混合在一起进行预训练,可以使得模型在预训练阶段习得足够的专业知识。大规模数据:使用更大规模的数据进行预训练,可以让模型接触到更多的语言和知识。可以从互联网上爬取大量的文本数据,或者利用公开的语料库进行预训练。7. 进行SFT操作的时候,基座模型选用Chat还是Base?在进行 SFT 时,大模型选用 Chat 还是 Base 作为基座,需要根据SFT的数据量决定。如果数据量小于 10k,建议选用 Chat 模型作为基座进行微调;如果有 100k 的数据,建议在 Base 模型上进行微调。8. 领域模型微调指令&数据输入格式要求?指令数据一般为 json 格式,包含 Instruction、Input、Output 三个字段(可以为空),每行一条样本。Instruction(指令):Instruction 是对模型的输入文本或问题进行进一步说明或约束的指令。它可以是一种特定的格式或标记,用于告诉模型如何处理输入数据,或者提供一些额外的信息,以便模型更好地理解和生成输出。Instruction的作用是为了描述任务。Input(输入):Input 是模型实际接收的文本或数据。提供了指令待处理的对象,用于生成输出。Response(输出):Response 是 LLM 生成的输出文本或回答。它是模型对 Instruction 和 Input 的处理结果。 Response 的内容取应当是理想的文本、回答、建议、解释等形式。9. 领域模型微调领域评测集构建?领域模型数据集通常通过构建专业知识选择题数据集来进行评测,例如医学领域大语言模型测评数据集 CMB 包含了医师考试、护理考试、医学考研等六类考试的题目。方便对模型的专业领域知识能力进行快速评测。但由于领域模型很有可能语义理解能力较差导致难以理解题目而无法正确作答。另一种方式是构建主观题数据集,模型完成作答后由专业人员根据一定标准进行打分。10. 领域模型词表扩增是不是有必要的?不一定要扩充词表,但有些领域比较特殊,需要扩充词表。领域特定词汇:对于目标领域内存在的专有术语或特殊词汇,若这些并不存在标准预训练模型的数据中,扩展词表就是有必要的。将这类特殊术语纳入模型的词库,能够增强模型对这些术语的理解与处理能力。领域特定上下文:在特定的领域任务中,一个词的含义可能会由其所处的上下文决定。以医疗领域为例,一个术语在不同情境下可能代表着不同的事物。当领域特定任务中的上下文与预训练模型原训练数据中的上下文存在差异时,词表的扩充就能帮助模型更精确地理解和应对特定领域的上下文。11. 如何训练自己的大模型?数据收集和预处理:首先收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者其他途径获得的数据。然后,对数据进行预处理和清洗,包括数据去重、有害数据集去除等。同时将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。模型架构选择:根据任务的特点和目标,选择适合的开源模型架构。目前国内外有较多的开源 LLM 模型可供开发者使用,包括国外的 LLaMa、BLOOM,国内的 ChatGLM、Baichuan,或者其他机构基于开源框架训练得到的模型。可以根据自己的数据量、计算资源、任务需求来选择相应的模型进行微调。模型训练和调参:训练包含二次预训练、SFT、RLHF 等方式,同时可以选择是全参数训练或者部分参数训练。确定好训练方式后使用训练集对模型进行训练。训练过程中,需要选择合适的优化器、损失函数和学习率等超参数,并进行适当的调整和优化。12. 训练中文大模型有啥经验?如果模型在预训练阶段就包含足够的中文如 ChatGLM、Baichuan,可以直接利用其进行微调,如果模型在预训练阶段无中文或者中文数据含量较少的模型如 LLaMA,需要对其 tokenizer 进行修改,添加中文字词,同时进行二次预训练使其充分理解中文再进行 SFT 微调。13. 指令微调的好处?行为引导:大模型的行为往往不易解释和控制。借助指令微调,我们可以输入特别的指令或设定限制,这样不仅可以引导模型行为,还使其更好地满足特定任务的要求,如在创造性任务中,通过指令导向控制内容的风格和长度等。数据效率:大模型训练通常依赖于大量数据,但在一些特定的任务或领域里,关键数据往往不够充足或难以采集。指令微调可以使我们仅利用少量特定任务的数据,结合大型模型的通用数据预训练知识,达到在数据受限的条件下也能够取得优异的性能。14. 预训练和微调哪个阶段注入知识的?知识是在预训练阶段注入的,而微调阶段是指在特定任务上的训练,以使预训练模型的通用知识和特定任务的要求相结合,使模型在特定任务上表现更好。15. 想让模型学习某个领域或行业的知识,是应该预训练还是应该微调?如果想让大语言模型学习某个特定领域或行业的知识,通常建议进行微调而不是预训练。预训练阶段是在大规模通用数据上进行的,旨在为模型提供通用的语言理解和表示能力。预训练模型通常具有较强的泛化能力,可以适用于多个不同的任务和领域。在微调阶段,可以使用特定领域的数据对预训练模型进行进一步训练和调整,以使模型更好地适应目标领域的特点和需求。微调可以帮助模型更深入地理解特定领域的术语、概念和语境,并提升在该领域任务上的性能。微调通常需要较少的任务数据,因为预训练模型已经具备了一定的语言理解和泛化能力。但是,如果模型基座本身并没有具备太多相关领域知识则需要对模型做预训练后进行微调。16. 多轮对话任务如何微调模型?方法一User1、Assistant1、User2、Assistant2、User3 的文本都视为模型的输入部分,将 Assistant3 的文本视为模型的预测部分,只有 Assistant3 部分的 loss 参与权重更新。这种方法的弊端在于,没有充分利用多轮对话的训练数据,Assistant1 和 Assistant2 的内容没有参与模型训练,这部分数据在训练时被浪费了。并且对于很多多轮对话数据而言,中间的 Assitant 回复部分的信息量更丰富详细,最后一个 Assitant 回复部分往往是”谢谢“、”不客气“等诸如此类的较为简短的文本。如果只使用这部分文本训练模型,会严重影响模型的训练效果。方法二将一条多轮对话数据,拆分成多条数据。例如将以上示例拆分成如下三条数据。相比方法一,方法二能够更加充分利用多轮对话中每一个 Assistant 的回复内容。但是弊端在于,需要将一个包含n轮对话的数据,拆分成n条数据,训练效率降低了n倍,训练方法不高效。方法三Firefly 项目训练多轮对话模型时,采取了一种更加充分高效的方法。如下图所示,将一条多轮对话数据拼接之后,输入模型,并行计算每个位置的 loss,只有 Assistant 部分的 loss 参与权重更新,项目地址。为什么这种做法是可行的?答案在于因果语言模型的 attention mask。以 GPT 为代表的 Causal Language Model(因果语言模型),这种模型的 attention mask 是一个对角掩码矩阵,每个 token 在编码的时候,只能看到它之前的 token,看不到它之后的 token。所以 User1 部分的编码输出,只能感知到 User1 的内容,无法感知到它之后的文本,可以用来预测 Assistant1 的内容。而 User2 部分的编码输出,只能看到 User1、Assistant1、User2 的内容,可以用来预测 Assistant2 的内容,依此类推。对于整个序列,只需要输入模型一次,便可并行获得每个位置的 logits,从而用来计算 loss。17. 微调后的模型出现能力劣化,灾难性遗忘是怎么回事?灾难性遗忘是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中,原因如下:数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。参数更新冲突:微调过程中,对新任务进行训练时,模型参数会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。设置了过多的 epoch:随着 epoch 的上升,对旧任务的遗忘也会越多,通常 epoch 只用设置为 1(具体需要看数据量大小和任务需求)。18. 微调模型需要多大显存?全参数微调:当在模型大小为 XB 且参数精度为半精度,推理所需显存约为 X 的两倍,而全参数微调所需显存约为推理所需显存的四倍,包括模型推理(一倍)、梯度(一倍)、优化器(两倍),也就是 X 的八倍。LoRA 微调:相比于全参数微调,LoRA 占用显存降低约 67.5%。QLoRA 微调:可在 48GB 显存的显卡上微调 65B 的模型。19. LLM 进行 SFT 操作的时候在学习什么?任务特定的标签预测:在有监督微调中,模型会根据给定的任务,学习预测相应的标签或目标。通常会将基座模型训练成对话模型。垂直领域知识学习:使模型更好地适应目标领域的特点和需求。微调可以帮助模型更深入地理解特定领域的术语、概念和语境,并提升在该领域任务上的性能。特征提取和表示学习:微调过程中,模型会通过学习任务相关的表示来提取有用的特征。这些特征可以帮助模型更好地区分不同的类别或进行其他任务相关的操作。20. 预训练和 SFT 操作有什么不同目标:预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是将大量的知识灌入模型之中,同时让模型学会句子接龙。有监督微调的目标是在特定的任务上进行训练,在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求(如将 Base 模型训练为 Chat 模型)。数据:在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。21. 样本量规模增大,训练出现 OOM 错误如何解决?减少批量大小(Batch Size):将批量大小减小可以减少每个训练步骤中所需的内存量。但较小的批量大小可能会导致训练过程中的梯度估计不稳定,但可以通过增加梯度积累步数来弥补这一问题。内存优化技术:使用一些内存优化技术可以减少模型训练过程中的内存占用。例如,使用混合精度训练(Mixed Precision Training)可以减少模型参数的内存占用,或采用 Freeze、LoRA 的方式进行训练。减少模型规模:如果内存问题仍然存在,可以考虑选择规模更小的模型。虽然这可能会导致模型性能的一定损失,但可以在一定程度上减少内存需求。增加硬件资源:可以考虑增加硬件资源,例如更换显存更大的显卡,或者增加显卡的数量以实现并行训练,减小单卡压力。数据处理和加载优化:优化数据处理和加载过程可以减少训练过程中的内存占用。例如,可以使用数据流水线技术来并行加载和处理数据,减少内存中同时存在的数据量。
1. 什么是思维链提示?思维链(Chain-of-thought,CoT),指的是一系列有逻辑关系的思考步骤,形成一个完整的思考过程。人在日常生活中,随时随地都会用思维链来解决问题,比如工作、读书经常用到的思维导图,就是为了尽可能全面拆解步骤,不忽略重要细节,从而充分地考虑问题。这种步骤分解的方式用在提示学习中,就被称为思维链提示,将大语言模型的推理过程,分解成一个个步骤,直观地展现出来,这样开发人员可以在LLM推理出现错误时,就及时地修复。2. 思维链提示本质是什么?思维链提示的本质就是把一个多步骤推理问题,分解成很多个中间步骤,分配给更多的计算量,生成更多的 token,再把这些答案拼接在一起进行求解。3. 思维链提示与标准的提示学习方法有什么不同?“思路链提示”方法是在少样本学习中,在输入-输出对的输出部分提供一系列中间推理步骤,来增强语言模型的复杂推理能力。具体来说,“思路链提示”是在标准的少样本学习中,在每一个输入-输出对后面添加该输出的生成过程。这里的生成过程就是一系列从输入到输出的中间语言推理步骤。例如,在一个算术词题的解答中,会给出每一步的计算过程,而不仅仅只给出最终答案。在一个需要常识推理的问题中,会给出一系列的语言推论步骤。与只给出最终输出的标准提示学习不同,“思路链提示”提供了从输入到输出的完整推理路径。这模拟了人类逐步思考解决复杂问题的过程。4. 思维链提示为什么可以提高语言模型的复杂推理能力?它的优势在哪里?分解复杂问题:将多步推理任务分解成多个简单的子任务,降低问题难度。提供步骤示范:为每一推理步骤提供了语言表达,示范了如何逐步推理。引导组织语言:语言表达引导模型学习组织语言进行逻辑推理。加强逻辑思维:让模型模拟人类逻辑思维的过程,强化逻辑推理能力。调动背景知识:语言表达可以激活模型的背景常识,帮助推理。提供解释性:使模型的推理过程可解释,便于 debugging。适用范围广:原则上适用于任何文本到文本的任务。单模型多任务:基于同一模型就可以做思路链提示,无需针对每一个任务微调。少样本学习:只需要给出几个示范示例,不需要大量标注数据。5. 思维链提示适用场景有哪些?思维链提示主要适用于需要复杂推理的领域,例如数学、常识和符号推理等。思维链提示可以帮助大语言模型生成一系列推理步骤,从而解决多步骤的问题,提高准确率和可解释性。思维链提示也可以与其他技术结合,例如行动指令、检索、组装等,让大语言模型具备更强的执行能力和知识生成能力。6. 思维链提示目前还存在哪些不足点?生成的思路链不一定事实准确,需要进一步改进提高事实性。思路链提示的成功依赖于较大规模的语言模型,使用成本较高。思路链的标注成本较高,不易大规模应用。可以考虑自动生成思路链。思路链的提示示例易受提示工程影响,结果变化大。可以探索更稳健的提示方法。思路链并不能完全反映模型的计算过程,理解内在机制需要更深入研究。思路链提示在一些简单任务上的效果提升有限,可以扩展应用范围。7. 思维链提示对推动语言模型复杂推理能力研究有哪些启发和影响?为增强语言模型推理能力提供了新的思路。证明了语言表达的中间推理步骤对语言模型的重要作用。显示了模型规模增长对产生正确思路链的 importance。表明了探索语言内在的逻辑结构的巨大价值和潜力。展示了语言模型的惊人推理潜力,通过简单提示就能实现强大的推理。8. 思维链提示对实现真正的通用人工智能仍面临哪些挑战?思路链的质量和正确性仍需提高。对语言模型内在推理机制理解不够。推广到更多不同类型的推理任务上。需要更大规模的模型作为支撑。需要提高样本效率,降低使用成本。9. 如何通过增加模型规模来获得语言模型强大的思路链推理能力的?这与模型获得的哪些能力有关?算术运算能力的提升:参数量越大的语言模型,其基本的算数运算能力越强,可以更准确地完成思路链中的算术推理。语义理解能力的增强:模型规模越大,可以建立更丰富的词汇语义信息,有助于分析理解问题语义。逻辑推理能力的增强:参数量提升可以增强模型的逻辑推理建模能力,有助于构建合理的推理链。知识表示能力的扩展:规模更大的模型可以学习更丰富的知识,提供问题所需的相关背景常识。长依赖建模能力的提高:参数量的增加可以增强模型学习长距离依赖的能力,有利于推理链的生成。抽象建模和泛化能力增强:更大模型可以学到更抽象的知识表示,并应用到新问题上。计算资源和数据集规模的提升:计算资源增加可以支持训练更大模型,大数据集可以提供更丰富的学习素材。10. 你认为可以在哪些其他方面应用“思路链提示”这一思路来提升语言模型的能力?复杂问题解决:例如数学题或逻辑推理等需要多步推理的问题。思路链可以帮助语言模型分解问题,逐步解决。程序合成:可以提示语言模型先输出每一行代码的自然语言说明,然后再输出实际代码,从而合成程序。翻译:可以提示语言模型先输出源语言到目标语言的逐词翻译,然后整合生成完整的翻译结果。总结:可以提示语言模型先输出段落的主题句,然后输出段落的要点,最后生成完整的总结。创作:如创作故事或诗歌,可以提示思路链,让语言模型按照故事情节或诗歌主题逐步创作。问答:可以提示思路链让语言模型解释其推理过程,而不仅仅给出结果,提高问答的透明度。对话:在闲聊对话中提示思路链,让语言模型的回复更合乎逻辑,而不仅是无意义的应答。可解释的预测:在进行预测任务时,让语言模型输出导致预测结果的推理链,提高可解释性。11. 如果需要你对思维链提示进行改进,你觉得你会改进哪些地方?提示的泛化能力有限:当前的提示方式过于依赖具体的示例,泛化能力有限,需要更多提示示例才能适应新的任务。未来研究可以探索如何用更少示例或从零示例中泛化。提示编写需要专业知识:思路链提示当前需要人工编写,需要一定专业知识。可以探索自动生成提示的方法。结果正确性无法保证:思路链不保证完全正确,可能导致错误结果。可以结合验证器提高正确性。评估任务范围有限:目前主要在算术推理上评估,可以拓展到更多语言任务上验证效果。模型规模大:当前只在千亿和百亿参数量级模型上见效,可以研究在小模型上应用的方法。12. 思维链提示未来研究方向?提高提示泛化能力,减少人工参与。在更多语言任务中验证效果,评估推理能力。在小型模型上也实现类似推理提升的技术。结合验证器等手段提高生成的事实准确性。用提示的思路探索不同的模型结构设计。
1. 什么是 LangChain?LangChain 是围绕 LLMs(大语言模型)建立的一个框架,其自身并不开发 LLMs,它的核心理念是为各种 LLMs 实现通用的接口,把 LLMs 相关的组件“链接”在一起,简化 LLMs 应用的开发难度,方便开发者快速地开发复杂的 LLMs 应用。LangChain 主要支持 Models、Prompts、Memory、Indexes、Cahins、Agents 六个组件。2. LangChain 包含哪些 核心概念?1. LangChain 中 Components and Chains 是什么?在LangChain 中,Component 是一种模块化的构建块,可以相互组合以构建强大的应用程序。 而 Chain 则是由一系列 Components 或其他 Chains 组合而成的,用于完成特定的任务。2. LangChain 中 Prompt Templates 是什么?Prompt Templates是一种可复制的生成Prompt的方式,包含一个文本字符串,可以接受来自终端用户的一组参数并生成Prompt。Prompt Templates可以包含指令、少量示例和一个向语言模型提出的问题。我们可以使用Prompt Templates技术来指导语言模型生成更高质量的文本,从而更好地按照需求完成的任务。3. LangChain 中 Example Selectors 是什么?Example Selectors 的主要作用就是从给定的 examples 中选择需要的 examples 出来提供给大模型使用,从而减少会话的token数目。4. LangChain 中 Output Parsers 是什么?Output Parsers 模块可以使模型输出的期望的结构化文本,、 LangChain中的output parsers一共有七个,分别是List parser、Datetime parser、Enum parser、Pydantic (JSON) parser、Structured output parser、Retry parser、Auto-fixing parser。前四种parser用于常见的格式输出转换,Structured output parser用于多字段输出时使用,最后的两种是对于格式转换失败之后的修复措施。5. LangChain 中 Indexes and Retrievers 是什么?Indexes 是指为了使LLM与文档更好地进行交互而对其进行结构化的方式。 在链中,索引最常用于“检索”步骤中,该步骤指的是根据用户的查询返回最相关的文档: 索引不仅可用于检索,还可用于其他目的,检索可以使用除索引之外的其他逻辑来查找相关文档。Retrievers 是一个接口,它根据非结构化查询返回文档。它比向量存储更通用。检索器不需要能够存储文档,只需返回(或检索)它。向量存储可以用作检索器的骨干,但也有其他类型的检索器。6. LangChain 中 Chat Message History 是什么?ChatMessageHistory 类负责记住所有以前的聊天交互数据,然后可以将这些交互数据传递回模型、汇总或以其他方式组合。 这有助于维护上下文并提高模型对对话的理解。7. LangChain 中 Agents and Toolkits 是什么?Agent 是在LangChain 中推动决策制定的实体。 他们可以访问一套工具,并可以根据用户输入决定调用哪个工具。 Tookits 是一组工具,当 Agent 和 Tookits 一起使用时,可以完成特定的任务。Agent 负责使用适当的工具运行代理。3. 什么是 LangChain Agent?LangChain Agent 指使用 LangChain 构建的智能体,Agent 核心思想是使用LLM作为大脑自动思考,自动决策选择执行不同的动作,最终完成我们的目标任务,例如数据收集、数据处理、决策支持等。 Agent 可以是自主的,具备一定程度的智能和自适应性,以便在不同的情境中执行任务。4. LangChain 支持哪些功能?LangChain 可以轻松管理与语言模型的交互,将多个组件链接在一起,并集成额外的资源,例如 API 和数据库。LangChain 为特定用例提供了多种组件,例如个人助理、文档问答、聊天机器人、查询表格数据、与 API 交互、提取、评估和汇总。5. 什么是 LangChain model?LangChain model 是一种抽象,表示框架中使用的不同类型的模型。LangChain 中的模型主要分为三类:LLM(大型语言模型) :这些模型将文本字符串作为输入并返回文本字符串作为输出。它们是许多语言模型应用程序的支柱。聊天模型( Chat Model) :聊天模型由语言模型支持,但具有更结构化的 API。他们将聊天消息列表作为输入并返回聊天消息。这使得管理对话历史记录和维护上下文变得容易。文本嵌入模型(Text Embedding Models) :这些模型将文本作为输入并返回表示文本嵌入的浮点列表。这些嵌入可用于文档检索、聚类和相似性比较等任务。6. LangChain 包含哪些特点?组件化:为使用语言模型提供抽象层,以及每个抽象层的一组实现。组件是模块化且易于使用的,无论开发是否使用LangChain框架的其余部分。现成的链:结构化的组件集合,用于完成特定的高级任务7. LangChain 存在问题及方法方案1. LangChain 低效的令牌使用问题Langchain的一个重要问题是它的令牌计数功能,对于小数据集来说,它的效率很低。虽然一些开发人员选择创建自己的令牌计数函数,但也有其他解决方案可以解决这个问题。替代解决方案:Tiktoken是OpenAI开发的Python库,用于更有效地解决令牌计数问题。它提供了一种简单的方法来计算文本字符串中的令牌,而不需要使用像Langchain这样的框架来完成这项特定任务。2. LangChain 文档的问题文档是任何框架可用性的基石,而Langchain因其不充分且不准确的文档而受到指责。误导性的文档可能导致开发项目的代价高昂的,并且还经常有404错误页面。这可能与Langchain还在快速发展有关,作为快速的版本迭代,文档的延后性可以理解,只能说希望以后尽快完善吧。3. LangChain 太多概念容易混淆,过多的“辅助”函数问题Langchain的代码库因很多概念让人混淆而备受诟病,这使得开发人员很难理解和使用它。这种问题的一个方面是存在大量的“helper”函数,仔细检查就会发现它们本质上是标准Python函数的包装器。开发人员可能更喜欢提供更清晰和直接访问核心功能的框架,而不需要复杂的中间功能。4. LangChain 行为不一致并且隐藏细节问题LangChain隐藏重要细节和行为不一致,这可能导致生产系统出现意想不到的问题。例Langchain ConversationRetrievalChain的一个方面,它涉及到输入问题的重新措辞。这种重复措辞有时会非常广泛,甚至破坏了对话的自然流畅性,使对话脱离了上下文。5. LangChain 缺乏标准的可互操作数据类型问题Langchain缺乏表示数据的标准方法。这种一致性的缺乏可能会阻碍与其他框架和工具的集成,使其难以在更广泛的机器学习工具生态系统中工作。8. LangChain 代替方案LlamaIndex是一个数据框架,它可以很容易地将大型语言模型连接到自定义数据源。它可用于存储、查询和索引数据,还提供了各种数据可视化和分析工具。Deepset Haystack是另外一个开源框架,用于使用大型语言模型构建搜索和问答应用程序。它基于Hugging Face Transformers,提供了多种查询和理解文本数据的工具。
1. 什么是 Graph RAG?Graph RAG 是由悦数图数据提出的概念,是一种基于知识图谱的检索增强技术,通过构建图模型的知识表达,将实体和关系之间的联系用图的形式进行展示,然后利用大语言模型 LLM进行检索增强。通过图技术构建知识图谱提升 In-Context Learning 的全面性为用户提供更多的上下文信息,能够帮助大语言模型(LLM)更好地理解实体间的关系,提升自己的表达和推理能力。2. 为什么需要 Graph RAG?身处信息爆炸时代,如何从海量信息中获取准确全面的搜索结果,并以更直观、可读的方式呈现出来是大家期待达成的目标。传统的搜索增强技术受限于训练文本数量、质量等问题,对于复杂或多义词查询效果不佳,更无法满足 ChatGPT 等大语言模型应用带来的大规模、高并发的复杂关联查询需求。知识图谱可以减少基于嵌入的语义搜索所导致的不准确性。“保温大棚”与“保温杯”,尽管在语义上两者是存在相关性的,但在大多数场景下,这种通用语义(Embedding)下的相关性很高,进而作为错误的上下文而引入“幻觉”。这时候,可以利用领域知识的知识图谱来缓解这种幻觉。3. Graph RAG 思路介绍?Graph RAG 将知识图谱等价于一个超大规模的词汇表,而实体和关系则对应于单词。通过这种方式,Graph RAG 在检索时能够将实体和关系作为单元进行联合建模。4. 用代码实现 Graph RAG ?一个简单的 Graph RAG 思想在于,对用户输入的query提取实体,然后构造子图形成上下文,最后送入大模型完成生成,如下代码所示:def simple_graph_rag(query_str, nebulagraph_store, llm): entities = _get_key_entities(query_str, llm) graph_rag_context = _retrieve_subgraph_context(entities) return _synthesize_answer( query_str, graph_rag_context, llm)5. Graph RAG 排序优化方式是什么?基于知识图谱召回的方法可以和其他召回方法一起融合,但这种方式在图谱规模很大时其实是有提升空间的。突出的缺点在于:子图召回的多条路径中可能会出现多种不相关的。实体识别阶段的精度也有限,采用关键词提取还比较暴力,方法也值得商榷。这种方式依赖于一个基础知识图谱库,如果数据量以及广度不够,有可能会引入噪声。因此,还可以再加入路径排序环节,可参考先粗排后精排的方式,同样走过滤逻辑。例如,在粗排阶段,根据问题 query 和候选路径 path 的特征,对候选路径进行粗排,采用 LightGBM 机器学习模型,保留 top n 条路径,在精排阶段,采用预训练语言模型,计算 query 和粗排阶段 的 path 的语义匹配度,选择得分 top2-top3 答案路径作为答案。