皮皮网

【七指共振源码】【试金石指标源码】【openwrt内核源码路径】bloom 源码

来源:多模态源码 时间:2024-11-23 12:15:52

1.BitMap原理与实现
2.Catlike Coding Custom SRP学习之旅——11Post Processing
3.TensorRT-LLM(持续更新)
4.布隆过滤器(Bloom Filter)详解
5.手把手教你微调百亿大模型:基于Firefly微调Qwen1.5-14b
6.深入源码解析LevelDB

bloom 源码

BitMap原理与实现

        比较经典的问题是: 在只能够使用2G的内存中,如何完成以下操作:

        ①:对亿个不重复的整数进行排序。

        ②:找出亿个数字中重复的数字。

        无论是排序还是找重复的数字都需要将这亿个数字加入到内存中在去进行操作,很明显,题目给出的2G内存限制说明了在这样的场景下是不能够将所有数都加入到内存中的

        * 4/(* * ) = 3.G

        那么这时候就需要用到 BitMap结构了

        bitMap使用一个bit为0/1作为map的value来标记一个数字是否存在,而map的key值正是这个数字本身。

        相比于一般的数据结构需要用4个byte去存储数值本身,相当于是节省了 4*8:1 = 倍的内存空间

        bitMap不一定要用bit数组,可以使用 int,long等等的基本数据类型实现,因为其实质都是在bit位上存数据,用哪种类型只是决定了最终实现出来的BitMap的内置数组中单个元素存放数据的多少

            例如:java中的BitSet使用Long数组

        BitMap的实现当然少不了位运算,先来明确几个常见位运算,这是实现BitMap的基础:

        set(bitIndex): 添加操作

            1 .确定该数处于数组中的哪个元素的位上

             int wordIndex = bitIndex >> 5;

        因为我用的是int[]实现,所以这里右移 5 位(2^5 = )

            2 .确定相对于该元素中的位置偏移

             int bitPosition = bitIndex & ((1 << 5) - 1);

        这里相当于是 bitIndex % (1<<5)的取模运算,因为当取模运算的除数是2的次幂,所以可以使用以下的位运算来计算,提升效率(对比HashMap的容量为什么总是2的幂次方的问题,HashMap求下标时也是使用 hash&(n-1))

        tips: 位运算的优先级是低于+,-等等的,所以要加上括号,防止发生不可描述的错误

            3 .将该位置1

             bits[wordIndex] |= 1 << bitPosition;

        相当于是将指定位置处的bit值置1,其他位置保持不变,也就是将以这个bitIndex为key的位置为1

        tips: 这里是参考了网上的各位大佬的文章,取余 + 按位或,又对比了下BitSet的源码:

             words[wordIndex] |= (1L << bitIndex);

        没有取余操作,直接|,这两个一样吗?答案当然是一样的

        举个栗子:

             1 << == 1<<     

             1L << ==1L<<

        即对于int和long型数据,直接左移其位数相当于是附带了对其的取模操作

        总结:使用Bit-map的思想,我们可以将存储空间进行压缩,而且可以对数字进行快速排序、去重和查询的操作。

        Bloom Fliter是Bit-map思想的一种扩展,它可以在允许低错误率的场景下,大大地进行空间压缩,是一种拿错误率换取空间的数据结构

        当一个元素加入布隆过滤器中的时候,会进行哪些操作:

        当我们需要判断一个元素是否存在于布隆过滤器的时候,会进行哪些操作:

        然后,一定会出现这样一种情况:不同的字符串可能哈希出来的位置相同(可以适当增加位数组大小或者调整我们的哈希函数来降低概率),因此:布隆过滤器可能会存在误判的情况

        总结来说就是: 布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。

        Bloom Filter的应用: 常用于解决缓存穿透等场景。

Catlike Coding Custom SRP学习之旅——Post Processing

       来到了后处理环节,这是渲染管线中关键的一环。后处理技术能够显著提升画面效果,比如色调映射、Bloom、抗锯齿等,七指共振源码都能在后处理中实现。除了改善整体画面效果,后处理还能用于实现描边等美术效果。本文将主要介绍后处理堆栈和Bloom效果等内容。

       考虑到篇幅和工作量,本文将从第4章节后半部分开始,以及未来的章节,主要提炼原教程的内容,尽量减少篇幅和实际代码。在我的Github工程中,包含了对源代码的详细注释,需要深入了解代码细节的读者可以查看我的Github工程。对于文章中的错误,欢迎读者批评指正。

       以下是原教程链接和我的Github工程:

       CatlikeCoding-SRP-Tutorial

       我的Github工程

       1. 后处理堆栈(Post-FX Stack)

       FX,全称是Special Effects,即特殊效果,也称为VFX(Visual Special Effects),即视觉特效。参考维基百科,视觉效果(Visual effects,简称VFX)是在**制作中,在真人动作镜头之外创造或操纵图像的过程。游戏很多技术都会沿用影视技术上的一些技术,比如在色调映射时,可以采用ACES(**色调映射)等。关于Special Effects为什么叫FX,而不是SE,网上似乎只是因为FX谐音Effects,让人不知道从哪吐槽。

       通常来说,试金石指标源码因为后处理会包含很多不同的效果,如色调映射、Bloom、抗锯齿等等,因此后处理在渲染管线中的结构往往是一个堆栈式的结构(URP中也是如此,使用了Post Process Volume)。因此,在本篇中,我们将搭建这样一个堆栈结构,并实现Bloom效果。

       1.1 配置资源(Settings Asset)

       首先,我们定义PostFXSettings资源,即Scriptable Object,将其作为渲染管线的一项可配置属性,这样便于我们配置不同的后处理堆栈,并可以方便地切换。

       1.2 栈对象(Stack Object)

       类似于Light和Shadows,我们同样使用一个类来存储包括Camera、ScriptableRenderContext、PostFXSettings,并在其中执行后处理堆栈。

       1.3 使用堆栈(Using the Stack)

       在进行后处理前,我们首先需要获取当前摄像机画面的标识RenderTargetIdentifier,RenderTargetIdentifier用于标识CommandBuffer的RenderTexture。在这里,我们使用一个简单的int来标识sourceRT。

       对于一个后处理效果而言,其实现过程说来很简单,传入一个矩形Mesh(其纹理即当前画面),使用一个Shader渲染该矩形Mesh,将其覆盖回Camera的RT上,我们通过Blit函数来实现该功能。

       1.4 强制清除(Forced Clearing)

       因为我们将摄像机渲染到了中间RT上,我们虽然会在每帧结束时释放该RT空间,但是基于Unity自身对RT的管理策略,其并不会真正地清除该RT,openwrt内核源码路径因此我们在下一帧时,该RT中会留存上一帧的渲染结果,导致了每一帧画面都是在前一帧的结果之上绘制的。

       1.5 Gizmos

       我们还需要在后处理前后绘制不同的Gizmos部分,这部分略~

       1.6 自定义绘制(Custom Drawing)

       使用Blit方法绘制后处理,实际上会绘制一个矩形,也就是2个三角面,即6个顶点。但我们完全可以只用一个三角面来绘制整个画面,因此我们使用自定义的绘制函数代替Blit。

       1.7 屏蔽部分FX(Don't Always Apply FX)

       目前,我们对于所有摄像机都执行了后处理。但是,我们希望只对Game视图和Scene视图摄像机进行后处理,并对不同Scene视图提供单独的开关控制。很简单,通过判断摄像机类型来屏蔽。

       1.8 复制(Copying)

       接下来,完善下Copy Pass。我们在片元着色器中,对原画面进行采样,并且由于其不存在Mip,我们可以指定mip等级0进行采样,避免一部分性能消耗。

       2. 辉光(Bloom)

       目前,我们已经实现了后处理堆栈的框架,接下来实现一个Bloom效果。Bloom效果应该非常常见,也是经常被用于美化画面,其主要作用就是让画面亮的区域更亮。

       2.1 Bloom金字塔(Bloom Pyramid)

       为了实现Bloom效果,我们需要提取画面中亮的像素,并让这些亮的像素影响周围暗的像素。因此,需要首先实现RT的降采样。通过降采样,光通传奇源码我们可以很轻易地实现模糊功能。

       2.2 配置辉光(Configurable Bloom)

       通常来说,我们并不需要降采样到很小的尺寸,因此我们将最大降采样迭代次数和最小尺寸作为可配置选项。

       2.3 高斯滤波(Gaussian Filtering)

       目前,我们使用双线性滤波来实现降采样,这样的结果会有很多颗粒感,因此我们可以使用高斯滤波,并且使用更大的高斯核函数,通过9x9的高斯滤波加上双线性采样,实现x的模糊效果。

       2.4 叠加模糊(Additive Blurring)

       对于Bloom的增亮,我们直接将每次降采样后的Pyramid一步步叠加到原RT上,即直接让两张不同尺寸的以相同尺寸采样,叠加颜色,这一步也叫上采样。

       2.5 双三次上采样(Bicubic Upsampling)

       在上采样过程中,我们使用了双线性采样,这样可能依然会导致块状的模糊效果,因此我们可以增加双三次采样Bicubic Sampling的可选项,以此提供更高质量的上采样。

       2.6 半分辨率(Half Resolution)

       由于Bloom会渲染多张Pyramid,因此其消耗是比较大的,其实我们完全没必要从初始分辨率开始降采样,从一半的分辨率开始采样的效果也很好。

       2.7 阈值(Threshold)

       目前,我们对整个RT的每个像素都进行了增亮,这让这个画面看起来过曝了一般,但其实Bloom只需要对亮的区域增亮,本身暗的地方就不需要增亮了。

       2.8 强度(Intensity)

       最后,提供一个Intensity选项,控制Bloom的整体强度。

       结束语

       大功告成,我们在渲染管线中增加了后处理堆栈,以及实现了一个Bloom效果,深耕云游戏源码其实在做完这篇之后,我觉得这个渲染管线才算基本上达成了大部分需要的功能,也算是一个里程碑吧。

TensorRT-LLM(持续更新)

       TRT-LLM(NVIDIA官方支持)是一款用于在NVIDIA GPU平台上进行大模型推理部署的工具。

       其整体流程是将LLM构建为engine模型,支持多种大模型,如单机单卡、单机多卡(NCCL)、多机多卡,以及量化(8/4bit)等功能。

       TRT-LLM的runtime支持chat和stream两种模式,并支持python和cpp(可以直接使用cpp,也可以使用cpp的bybind接口)两种模式的runtime。

       构建离线模型可以通过example下的各个模型的build.py实现,而运行模型则可通过example下的run.py进行。

       TRT-LLM默认支持kv-cache,支持PagedAttention,支持flashattention,支持MHA/MQA/GQA等。

       在cpp下,TRT-LLM实现了许多llm场景下的高性能cuda kernel,并基于TensorRT的plugin机制,支持各种算子调用。

       与hugging face transformers(HF)相比,TRT-LLM在性能上提升2~3倍左右。

       TRT-LLM易用性很强,可能与其LLM模型结构比较固定有关。

       TRT-LLM的weight_only模式仅仅压缩模型体积,计算时依旧是dequant到input.dtype做计算。

       TRT-LLM的量化:W4A(表示weight为4bit,输入数据即activation为fp)。

       LLM模型推理,性能损耗大头在data 搬移,即memory bound,compute bound占比较少。

       TRT-LLM运行时内存可以通过一下参数调整,使用适合当前业务模型的参数即可。

       TRT-LLM对于Batch Manager提供了.a文件,用于支持in-flight batching of requests,来较小队列中的数据排队时间,提高GPU利用率。

       当前支持(0.7.1)的模型如下:

       tensorrt llm需要进行源码编译安装,官方提供的方式为通过docker进行安装。

       docker方式编译可以参考官方文档,此处做进一步说明。使用docker方式,会将依赖的各种编译工具和sdk都下载好,后面会详细分析一下docker的编译过程。

       编译有2种包,一种是仅包含cpp的代码包,一种是cpp+python的wheel包。

       docker的整个编译过程从如下命令开始:调用make,makefile在 docker/Makefile 下面,里面主要是调用了docker命令来进行构建。

       后续非docker方式编译llm,也是基于上述docker编译。

       一些小技巧:在编译llm过程中,会通过pip install一些python包,llm脚本中默认使用了NVIDIA的源,我们可以替换为国内的源,速度快一些。

       整个过程就是将docker file中的过程拆解出来,直接执行,不通过docker来执行。

       编译好的文件位于:build/tensorrt_llm-0.5.0-py3-none-any.whl。

       默认编译选项下的一些编译配置信息如下:

       以官方样例bloom为例:bloom example

       核心在于:编译时使用的环境信息和运行时的环境信息要一致,如:python版本,cuda/cudnn/nccl/tensorrt等。

       环境安装后以后,参考官方bloom样例,进行模型下载,样例执行即可。

       最终生成的engine模型:

       以chatglm2-6b模型为基础,进行lora微调后,对模型进行参数合并后,可以使用tensortrt-llm的example进行部署,合并后的模型的推理结果和合并前的模型的推理结果一致。

       lora的源码不在赘述,主要看一下lora模型参数是如何合并到base model中的:

       lora模型如下:

       base模型如下:

       模型构建是指将python模型构建为tensort的engine格式的模型。

       整体流程如下:

       整体流程可以总结为:

       可以看出,原理上和模型转换并没有区别,只是实现方式有差异而已。

       pytorch模型参数如何加载在tensortrt-llm中?关于量化参数加载

       1. 先提取fp格式的参数

       2. 调用cpp的实现进行参数量化

       整体而言,模型参数加载的关键在于:算子weight一一对应,拷贝复制。

       每种模型,都需要搭建和pytorch严格一致的模型架构,并将算子weight严格对应的加载到tensortrt-llm模型中

       即:关键点在于:熟悉原始pytorch模型结构和参数保存方式,熟悉tensorrt-llm的模型结构和参数设定方法。

       模型构建成功后,有两个文件:config.json文件推理时会用到,主要内容如下:模型参数信息和plugin信息。

       在模型构建好后,就可以做模型推理,推理流程如下:

       TRT-LLM Python Runtime分析

       1. load_tokenizer

       2. parse_input

       基于 tokenizer 对输入的text做分词,得到分词的id

       3. runner选择&模型加载

       4.推理

       5. 内存管理

       TRT-layer实现举例

       (1)对tensorrt的接口调用:以cast算子为例:functional.py是对TensorRT python API接口的调用

       调用tensorrt接口完成一次推理计算

       (2)TRT-LLM python侧对cpp侧的调用

       调到cpp侧后,就会调用cpp侧的cuda kernel

       trtllm更新快,用了一些高版本的python特性,新的trtllm版本在python3.8上,不一定能跑起来

布隆过滤器(Bloom Filter)详解

       布隆过滤器(Bloom Filter),一种年由布隆提出的高效数据结构,用于判断元素是否在集合中。其优势在于空间效率和查询速度,但存在误判率和删除难题。布隆过滤器由长二进制数组和多个哈希函数构成,新元素映射位置置1。判断时,若所有映射位置均为1,则认为在集合;有0则判断不在。尽管可能产生误报,但通过位数组节省空间,比如MB内存可处理亿长度数组。常用MurmurHash哈希算法,如mmh3库,它的随机分布特性使其在Redis等系统中广泛使用。

       在Scrapy-Redis中,可以将布隆过滤器与redis的bitmap结合,设置位长度为2的次方,通过setbit和getbit操作实现。将自定义的bloomfilter.py文件添加到scrapy_redis源码目录,并在dupefilter.py中进行相应修改。需要注意的是,爬虫结束后可通过redis_conn.delete(key名称)释放空间。使用时,只需将scrapy_redis替换到项目中,遵循常规的Scrapy-Redis设置即可。

手把手教你微调百亿大模型:基于Firefly微调Qwen1.5-b

       本文旨在引导新手通过使用Firefly项目微调Qwen1.5-b模型,学习大模型的微调流程。此教程不仅适用于微调llama、ziya、bloom等模型,同时Firefly项目正在逐步兼容更多开源大模型,如InternLM、CPM-bee、ChatGLM2等。此教程是大模型训练的步步指引,即使你是训练大模型的新手,也能通过本文快速在单显卡上训练出自己的大模型。

       访问Firefly项目链接:ewRedisBitSet(store*redis.Client,keystring,bitsuint)*redisBitSet{ return&redisBitSet{ store:store,key:key,bits:bits,}}

       到这里位数组操作就全部实现了,接下来看下如何通过 k 个散列函数计算出 k 个位点

       k 次散列计算出 k 个位点

//k次散列计算出k个offsetfunc(f*Filter)getLocations(data[]byte)[]uint{ //创建指定容量的切片locations:=make([]uint,maps)//maps表示k值,作者定义为了常量:fori:=uint(0);i<maps;i++{ //哈希计算,使用的是"MurmurHash3"算法,并每次追加一个固定的i字节进行计算hashValue:=hash.Hash(append(data,byte(i)))//取下标offsetlocations[i]=uint(hashValue%uint(f.bits))}returnlocations}

       插入与查询

       添加与查询实现就非常简单了,组合一下上面的函数就行。

//添加元素func(f*Filter)Add(data[]byte)error{ locations:=f.getLocations(data)returnf.bitSet.set(locations)}//检查是否存在func(f*Filter)Exists(data[]byte)(bool,error){ locations:=f.getLocations(data)isSet,err:=f.bitSet.check(locations)iferr!=nil{ returnfalse,err}if!isSet{ returnfalse,nil}returntrue,nil}改进建议

       整体实现非常简洁高效,那么有没有改进的空间呢?

       个人认为还是有的,上面提到过自动计算最优 m 与 k 的数学公式,如果创建参数改为:

       预期总数量expectedInsertions

       期望误差falseProbability

       就更好了,虽然作者注释里特别提到了误差说明,但是实际上作为很多开发者对位数组长度并不敏感,无法直观知道 bits 传多少预期误差会是多少。

//NewcreateaFilter,storeisthebackedredis,keyisthekeyforthebloomfilter,//bitsishowmanybitswillbeused,mapsishowmanyhashesforeachaddition.//bestpractices://elements-meanshowmanyactualelements//whenmaps=,formula:0.7*(bits/maps),bits=*elements,theerrorrateis0.<1e-4//fordetailederrorratetable,see/zeromicro/go-zero

       欢迎使用 go-zero 并 star 支持我们!

微信交流群

       关注『微服务实践』公众号并点击 交流群 获取社区群二维码。

自然语言处理大模型BLOOM模型结构源码解析(张量并行版)

       BLOOM模型结构解析,采用Megatron-DeepSpeed框架进行训练,张量并行采用1D模式。基于BigScience开源代码仓库,本文将详细介绍张量并行版BLOOM的原理和结构。

       单机版BLOOM解析见文章。

       模型结构实现依赖mpu模块,推荐系列文章深入理解mpu工具。

       Megatron-DeepSpeed张量并行工具代码mpu详解,覆盖并行环境初始化、Collective通信封装、张量并行层实现、测试以及Embedding层、交叉熵实现与测试。

       Embedding层:Transformer Embedding层包含Word、Position、TokenType三类,分别将输入映射为稠密向量、注入位置信息、类别信息。通常,位置信息通过ALiBi注入,无需传统Position Embedding,TokenType Embedding为可选项。张量并行版BLOOM Embedding层代码在megatron/model/language_model.py,通过参数控制三类Embedding使用。

       激活函数:位于megatron/model/utils.py,BLOOM激活函数采用近似公式实现。

       掩码:张量并行版模型用于预训练,采用Causal Mask确保当前token仅见左侧token。掩码实现于megatron/model/fused_softmax.py,将缩放、mask、softmax融合。

       ALiBi:位置信息注入机制,通过调整query-key点积中静态偏差实现。8个注意力头使用等比序列m计算斜率,个头则有不同序列。实现于megatron/model/transformer.py。

       MLP层:全连接层结构,列并行第一层,行并行第二层,实现于megatron/model/transformer.py。

       多头注意力层:基于标准多头注意力添加ALiBi,简化版代码位于megatron/model/transformer.py。

       并行Transformer层:对应单机版BlookBlock,实现于megatron/model/transformer.py。

       并行Transformer及语言模型:ParallelTransformer类堆叠多个ParallelTransformerLayer,TransformerLanguageModel类在开始添加Embedding层,在末尾添加Pooler,逻辑简单,代码未详述。

       相关文章系列覆盖大模型研究、RETRO、MPT、ChatGLM-6B、BLOOM、LoRA、推理工具测试、LaMDA、Chinchilla、GLM-B等。