分类 二、深度学习 下的文章

本文档分三个阶段:1、政策文档抽取QA问答 2、结构化数据融合大语言模型问答 3、自动化部署

一、政策文档抽取QA问答

由于格式复杂、标准多样,非结构化数据处理起来既困难又耗时。面对海量非结构化数据,如果没有自动化解决方案,人工手动处理将面临巨大挑战。

1.传统的QA问答抽取算法(非大模型)

传统的QA生成框架需要三个流程:pdf/word问答转txt、文档分块、问题生成,三个流程分别涉及到不同的技术
1.pdf问答转txt
文本转化:可以通过技术PyPDF2,pdfminer,textract,slate,直接提取文本内容。
2.文档分块
通过规则,通过分割算法方案
参考:https://github.com/chschock/textsplit
有相关论文在做文本分割算法
3.Learning to Ask模型
基于模型在中文问答语料DuReader数据上和已经结构化的政策QA问答数据集上微调,得到通用Learning to Ask模型;
DuReader数据数据集主要包含的QA问答对,可以用此数据集中的答案生成问题来微调模型。
此模型的输入为:上面文档分块的txt文本
输出为:对应的问题Q

2.基于大模型的QA问答抽取算法

本版本只实现了word文档的抽取,

(1)读取word文档内容

注意通过python-docx可以读取docx文件

pip install python-docx

(2)清洗待抽取的文档内容

去除无法提取(容易出错的)的部分:表格、图片、流程图

(3)对待抽取内容分块

python-docx 可以提取word文档的段落,按照段落组待提取的内容分块,经过实验每个块字数,实验结果每块在500-600左右的字数提取效果最好。

(4)写prompt内容,抽取返回特定格式

本版本使用百川2-13b模型作为抽取大模型,关键的prompt为:

prompt = "你是湖南省政策文档QA问答提取助手,需要提取的内容如下:" + cont + "抽取的内容结束"
new_query = [{"role":"system","content":prompt},{"role":"user","content":"参考上面内容,尽可能多的提取QA问答json数据,Q为对应问题,以问号结尾,A为对应答案,必须返回json格式
,格式为:[{\"Q\":抽取的问题,\"A\":抽取的答案},{\"Q\":抽取的问题,\"A\":抽取的答案}]"}]

其中,cont为待提取块文本内容。
实例:
待提取内如如下:

3 政策总体情况
【长沙市】个人待遇政策


(1)目前辖区内已开展的业务
职工:药店购药、普通门诊、普通住院、单病种住院、意外伤害住院、门特、特殊药品、门诊急诊、
生育门诊、生育住院
离休:普通门诊、普通住院
居民:门诊统筹、门特、普通住院、单病种住院、意外伤害住院、门诊两病、特殊药品、居民生育
住院、门诊急诊


(2)参保人存在险种划分
职工:职工基本医疗保险、职工大病互助保险、公务员医疗补助保险、职工生育保险。
离休:离休基本医疗保险
居民:居民基本医疗保险、居民大病



(3)具体基金分类和享受待遇人群分类
职工基金分类:职工基本医疗保险统筹基金、职工大病互助保险基金、公务员医疗补助基金、职工
享受待遇人群:在职、退休
离休基金分类:离休基金、个人账户金
离休享受待遇人群:离休、老红军、二乙伤残军人
居民基金分类:居民统筹基金、居民大病保险基金、医疗救助基金、特惠保金、医院减免金、财政
兜底金
居民享受待遇人群:新生儿、在校学生、大学生、未成年人、农村居民、非从业居民、老年居民。

提取之后的结果如下:

{
  "data": [
    {
      "question": "长沙市的个人待遇政策有哪些业务项目?",
      "answer": "目前辖区内已开展的业务包括:职工的药店购药、普通门诊、普通住院、单病种住院、意外伤害住院、门特、特殊药品、门诊急诊、生育门诊、生育住院;离休人员的普通门诊和普通住院;居民的门诊统筹、门特、普通住院、单病种住院、意外伤害住院、门诊两病、特殊药品、居民生育住院、门诊急诊。"
    },
    {
      "question": "职工参保人存在哪些险种划分?",
      "answer": "职工参保人存在以下险种划分:职工基本医疗保险、职工大病互助保险、公务员医疗补助保险、职工生育保险。"
    },
    {
      "question": "离休参保人存在哪些险种划分?",
      "answer": "离休参保人存在以下险种划分:离休基本医疗保险。"
    },
    {
      "question": "居民参保人存在哪些险种划分?",
      "answer": "居民参保人存在以下险种划分:居民基本医疗保险、居民大病保险。"
    },
    {
      "question": "职工基金的分类和享受待遇人群有哪些?",
      "answer": "职工基金分为职工基本医疗保险统筹基金、职工大病互助保险基金、公务员医疗补助基金。享受待遇的人群包括在职和退休人员。"
    },
    {
      "question": "离休基金的分类和享受待遇人群有哪些?",
      "answer": "离休基金分为离休基金和个人账户金。享受待遇的人群包括离休、老红军和二乙伤残军人。"
    },
    {
      "question": "居民基金的分类和享受待遇人群有哪些?",
      "answer": "居民基金分为居民统筹基金、居民大病

(5)大模型返回结果后置处理

通过正则对提取的后置内容做处理.

二、结构化数据融合大语言模型问答

1.抽取QA问答数据和历史问答合并

将新抽取的QA问答数据和已经存在QA问答库数据出重合并

2.训练检索模型(可以省略)

将合并后的QA问答数据中的问题库,调用同义不同问检索模型,训练同义不同问模型。如果之前的问题库数据量已经够多了,可以不用训练,直接推理就行。

3.检索后的top5数据用大模型回答

将检索模型检索的结果,给到大模型,同时将用户问题给到大模型,让大模型回答相关问题。

三、自动化部署(待开发)

整个自动化部署可以通过shell脚本,pipeline处理整个过程

自动化部署主要涉及到两个方面:1.增量数据处理 2.服务的重启

1.增量数据处理

(1)可以通过python 脚本,将提取的QA问答对数据从mysql(大模型抽取后后端开发放到数据库中)同步到服务器端本地文件中。
(2)和之前的QA问答对合并处理。
(3)并将对应的问题,通过同义不同问模型转为embedding问题向量。

2.服务的重启

数据处理完成后,服务启动的时候会初始化模型和数据到内存中,所以需要重启服务。主要重启的服务有:
(1)rasa框架服务器,主要提供对话的pipeline处理
(2)对话大模型服务,要重新加载数据

时间:从结构化一个政策文档10页word文档,到可以在大模型中访问,预计抽取可能2-5分钟,中间数据处理和服务重启预计2-5分钟,整体10分钟内可以完成。

方案一、图形学渲染技术

这种方法的优点是驱动人物快速,不需要合成视频。这种方式又可以分为两种,一种是把3d模型放到客户端,一种是把模型放到服务器端。

1.把模型放到客户端(不对应口型)

(1)实现方式

这种方式还有一种更简单的方法,比如让设计师设计几个gif图片,或者矢量图,开口讲话的时候一张图片,不开口讲话的时候另一张图片。

把模型放到客户端的方式,可以用3d模型工具,例如:Blender、Maya或3ds Max,ue5等,生成一个比较小的3d模型,用户每次加载的时候,放到客户端(h5),模型大小大概10多M,可以通过前端js,three.js来控制模型。

(2)实现的样例

1)中国电信:
微信图片_20231115175419.jpg

https://szr.ai.chinatelecom.cn:8093/
2)一个demo
微信截图_20231115175510.png
https://manghe151.sxqichuangkeji.com/h5/Digital1.html
到我的文件夹下看视频,以及数字人模型
在线数字人转换工具:https://3dconvert.nsdt.cloud/conv/to/glb

(3)相关技术文档

模型实例参考:https://manghe151.sxqichuangkeji.com/h5/Digital1.html
参考实现方式:https://blog.csdn.net/weixin_48594833/article/details/132598537
参考代码:

<!DOCTYPE html>
<!-- saved from url=(0053)https://manghe151.sxqichuangkeji.com/h5/Digital1.html -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        
        <title></title>
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <script async="" src="./manghe151.sxqichuangkeji.com_h5_Digital1_files/es-module-shims.js"></script>
        <style>
            .dbox {
                width: 100vw;
                height: 100vh;
                box-sizing: border-box;
            }
            * {
                margin: 0px;
            }
        </style>
    </head>
    <body>
        <div class="dbox" id="dbox">

        <canvas data-engine="three.js r148" width="1914" height="936" style="display: block; width: 1914px; height: 936px;"></canvas></div>
    
    <script src="./manghe151.sxqichuangkeji.com_h5_Digital1_files/uni.webview.1.5.2.js"></script> 
     <script>
//         {type="importmap"
//             "imports": {
//                 "three": "./three/build/three.module.js"
//             }
//         }
     </script>
    <script type="module">        
         import * as THREE from "./three/build/three.module.js";
        
        import {
            GLTFLoader
        } from './three/jsm/loaders/GLTFLoader.js';
        import { DRACOLoader    } from './three/jsm/loaders/DRACOLoader.js';

        
        let h = document.getElementById("dbox").clientHeight;
        let w = document.getElementById("dbox").clientWidth;
        //创建一个三维场景
        const scene = new THREE.Scene();
        //创建一个长方体


        //创建相机
        const camera = new THREE.PerspectiveCamera(45, w / h, 0.1, 4000);
        camera.position.set(0, 0.6, 3.8);
        camera.lookAt(0, 0, 0);

        let ambientLight = new THREE.AmbientLight(0xffffff, 1); //设置环境光
        scene.add(ambientLight); //将环境光添加到场景中
//         let pointLight = new THREE.PointLight(0xffffff, 0.5, 1);
//         pointLight.position.set(0, 30, 10); //设置点光源位置
//         scene.add(pointLight); //将点光源添加至场景

        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.1);
        directionalLight.position.set(0, 30, 10);
        scene.add(directionalLight);

        //创建渲染器
        const renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true,
            logarithmicDepthBuffer: true
        });
        renderer.setSize(w, h);
//         renderer.setPixelRatio(window.devicePixelRatio);
        renderer.shadowMap.enabled = true;
        renderer.outputEncoding = THREE.sRGBEncoding;
        renderer.textureEncoding = THREE.sRGBEncoding;
        document.getElementById("dbox").appendChild(renderer.domElement);



        const loader = new GLTFLoader();

        const clock = new THREE.Clock();

        window.IdleAction = null;
        window.walkAction = null;
        window.walkAction1 = null;
         let mixer = null;
        
         const dracoLoader = new DRACOLoader();
              dracoLoader.setDecoderPath('./three/jsm/libs/draco/gltf/');
              loader.setDRACOLoader(dracoLoader);
        loader.load('https://ptcgtext.oss-cn-chengdu.aliyuncs.com/people2.glb', function(gltf) {
//             console.log('人的模型', gltf);

            // 返回的场景对象gltf.scene插入到threejs场景中
            gltf.scene.position.y=-1.6;
            gltf.scene.position.x=0;
            gltf.scene.scale.set(2.6, 2.6, 2.6)
            mixer = new THREE.AnimationMixer(gltf.scene);
            gltf.scene.traverse(function(child) {
                if (child.isMesh) {
                    child.castShadow = true;
                     child.receiveShadow = true;
        
                }
            });
            wait(gltf);
            
        })

        
        function wait(gltf){
            loader.load('./model/glb/movement.glb', function(gltfmovement) {
                console.log('待机模型', gltfmovement);
                // 返回的场景对象gltf.scene插入到threejs场景中    
                window.IdleAction = mixer.clipAction(gltfmovement.animations[0]);
                window.IdleAction.play();
                hand_fn(gltf);
                
            })
        }
        
        
        function hand_fn(gltf){
            loader.load('./model/glb/mouth1.glb', function(gltfmovement) {
                // console.log('这个手动作数据', gltfmovement);
                // 返回的场景对象gltf.scene插入到threejs场景中
                window.walkAction1 = mixer.clipAction(gltfmovement.animations[0]);
                window.walkAction1.stop();
                speak(gltf);
            })
        }
        
        function speak(gltf){
            loader.load('./model/glb/mouth.glb', function(gltfmovement) {
                // console.log('口型模型', gltfmovement);
                // 返回的场景对象gltf.scene插入到threejs场景中
                window.walkAction = mixer.clipAction(gltfmovement.animations[0]);
                window.walkAction.stop();
                scene.add(gltf.scene);
                animate();
            })
        }
        
    
        
        function animate() {

            const delta = clock.getDelta();
            mixer.update(delta);

            renderer.render(scene, camera);
            //转动,可以忽略
            window.requestAnimationFrame(animate);
            // scene.rotation.y += 0.01;
        }
        
        
    </script>
    <script>
            
        function getMessage(result){//应用向网页传递消息

            if(result==1){
              window.walkAction.play();
              window.walkAction1.play();
            }
            if(result==2){
              window.walkAction.stop(); 
              window.walkAction1.stop();
            }
        }
        
    </script>

方案二、视频合成的方式

2D真人视频合成
优点:输入一个真人图片或者真人视频经过训练,生成一个真人视频
缺点:需要GPU较多,需要分段生成。

方案三 .把模型放到服务器端(可以对应上口型,视频推流方式在客户端显示)

互动数字人(对应开放平台的“客服助理”场景)使用阿里云RTC渠道,平台会将数字人渲染的视频流推到RTC服务器,客户可以使用RTC的客户端SDK进行拉流播放对应视频流;
微信截图_20231116164859.png

微信截图_20231116165442.png

微信截图_20231116165550.png
3d建模使用:虚幻引擎(ue5)

1、后端开发接入服务端 API 接入篇
  
2、前端引入视频流接入篇 集成到网页端数字人视频流
  
3、前端接入语音收音能力,通过RTC上传到虚拟数字人开放平台,即可实现与数字人的语音交互

前后端数据流程图:

p505166.png

参考阿里数字人:
https://help.aliyun.com/document_detail/447761.html?spm=a2c4g.451451.0.0.db0c37a7WlBWlm

口型驱动插件

微信截图_20231116150656.png
参考:https://www.yiihuu.com/a_11791.html

模型视频推流

利用像素流送可以在用户不可见的电脑上远程运行虚幻引擎应用程序。举例而言,这台电脑可以是机构中的一台实体电脑,也可以是云端服务提供的虚拟机。虚幻引擎将使用该电脑可用的资源(CPU、GPU、内存等)来运行游戏逻辑并渲染每一帧。它会不断将此渲染输出编码到一个媒体流送中,再通过一个轻量级的网页服务堆栈进行传递。用户即可在其他电脑和移动设备上运行的标准网页浏览器中查看直播流送。

推流组件:
(1)像素流送插件 - 此插件在虚幻引擎中运行。其使用H.264视频压缩对每个渲染帧的最终结果进行编码,将这些视频帧随游戏音频一同打包到媒体流送中,并通过直接点对点连接将该流送发送到一个或多个连线的浏览器上。

(2)信令和Web服务器- 信令和Web服务器负责交涉浏览器和像素流送插件之间的连接,将播放媒体流送的HTML和JavaScript环境提供给浏览器。

参考:
https://docs.unrealengine.com/5.1/zh-CN/customizing-the-player-web-page-in-unreal-engine/
https://blog.csdn.net/H_1512826122/article/details/129400685

BGE是由北京智源人工智能研究院提出的新的embedding模型。

BGE的训练主要由组成:

(1)通用文本上进行预训练;

(2)通用文本上finetinue(采用unlabeled数据);

(3)特定任务上finetinue(采用有labeled数据);

一、预训练

在预训练阶段,作者选择在Wudao数据集上进行,采用的模型架构为RetroMAE[2]。

RetroMAE的模型架构为非对称的encoder-decoder结构。为什么是非对称的呢?因为它的encoder部分是由bert组成(12层transformer的encoder),而它的decoder部分仅有由一层transformer的decoder构成。

在encoder阶段,对sentence进行15%~30%的mask,通过encoder得到句子向量的表示(也就是encoder的[CLS] token):
,在decoder部分,句子被进一步加大噪音,mask的比例为50%~70%,通过增加mask的比例来提升任务的复杂性。而整个预训练的任务则为:在encoder阶段,对被掩码的部分进行重构,也就是MLM(Masked Language Modeling),在decoder阶段对整个句子进行重构,整体loss函数为:
微信截图_20240807143152.png
微信截图_20240807143053.png

相比于transformer中的decoder结构,RetroMAE的作者在这一部分做了一些改进,在文章中称为enhanced-decoder。

微信截图_20240807143958.png

微信截图_20240807144034.png

二、通用文本上finetune

在这个阶段采用的是unlabled data,相信大家跟我一样感到很好奇,标签都没有,那怎么训练模型呢。其实这个unlabled data更准确的说采用的其实是伪标签,整理数据获得伪标签主要有2个步骤:1. 收集大量pair数据,如title-passage;2. 用text2vec-chinese计算文本的相似度,再卡阈值(paper中采用0.43作为阈值),过滤掉置信度比较低的pair;最后形成了100 million pairs这样庞大的数据集。
有了数据之后,模型训练,采用的是大名鼎鼎的对比学习方式:
微信截图_20240807143806.png

三、特定任务上finetinue

在下游任务上进行finetune会存在着一个问题:有些样本可能会互相矛盾,举个例子,一对pair在某个任务上是相似的,而在另一个任务上可能就不相似了。争对这个问题,作者提出了两点解决方案:1. 不同的任务加上不同的指令;2.进行难负例挖掘;最后再在进行改造后的数据集上进行finetune。

一、环境安装

在 pip install -r requirements.txt 时候报错:

 ERROR: Failed building wheel for pyaudio
Successfully built python_speech_features
Failed to build pyaudio
ERROR: Could not build wheels for pyaudio, which is required to install pyproject.toml-based projects

解决办法:

conda install -c conda-forge portaudio
pip install pyaudio

参考:
https://blog.csdn.net/jiaoyangwm/article/details/133743405
https://codeantenna.com/a/5jP2RktVnp
https://blog.csdn.net/matt45m/article/details/134046424

一、数字人定义

数字人是指以数字形式存在于数字空间中,具有拟人或真人的外貌、行为和特点的虚拟人物,也称之为虚拟形象、数字虚拟人、虚拟数字人等。数字人的核心技术 主要包括计算机图形学、动作捕捉、图像渲染、AI等。数字人可以打造更完美的人设,为品牌带来正向价值。互联网、金融、电商平台、消费品牌、汽车出行等领 域纷纷推出数字人,用于品牌营销、智能客服等方向。

二、数字人分类

数字人可以按照不同维度进行分类。

1.人物图形资源的维度

数字人可分为2D和3D两大类,2D、2.5D、3D这三种,2D是最常见的用一段语音去驱动一张照片,2.5D比2D多一些肢体动作,3D是UE建模

2.外形上

可分为2D真人、2D卡通、3D卡通、3D风格化、3D写实、3D超写实、3D高保真等多种。

写实和风格化之间的显著区别是,写实你被限制使事物看起来“真实”,就是要强化他们的视觉语言。风格化里您可以自由发挥的形状和颜色,夸大或删除细节,在任何方向增强外观和感觉。这样做将打破现实的幻觉,因为它不再被视写实的,它将不属于我们的世界。
bdc_r.jpg
c225c2ec.png

3.驱动的维度

可分为真人驱动和AI驱动两种。 根据商业和功能维度,可分为内容/IP型、功能服务型和虚拟分身等三种。

三、技术开发流程

1.人物形象采集(视频采集/3D扫描)

(1)人物建模
建模技术发展推动外貌更接近人的超写实数字人制作
门槛和周期进一步下降
(2)物理仿真
物理仿真算法迭代推动服装动态展示趋向真实

(3)人物渲染
渲染引擎的迭代发展和GPU算力的提升推动数字人渲
染画面更加精细和实时化

(4)声音建模

1.素材采集

(1)图片采集
(2)视频采集
(3)声音采集

2.素材清洗

(1)视频降噪
(2)音频降噪
(2)背景分离
(3)人物提取

3.数字人建模

(1)动作捕捉模型
肢体动作建模

(2)面捕模型
面部捕捉技术向更简单的硬件、更细腻的表情、更自动化的流程方向发展
(3)嘴型模型
嘴型和音频映射建模
(4)ASR模型
音频与文本建模
(5)AI驱动模型
AI驱动算法,通过语音驱动肢体动作、面部表情、嘴型细节关联映射,数据进行模型
训练,得到相关模型,并智能合成

4.结果合成

(1)图像合成模型
(2)语音合成
(3)视频合成
(4)3D渲染

四、开源算法

1.Gan方案的

(1) Wav2Lip:

优缺点:开源可复现
https://github.com/Rudrabha/Wav2Lip

(2)PaddleBoBo :不推荐

优缺点:使用的Wav2Lip,只能在woindows系统
https://github.com/JiehangXie/PaddleBoBo

2.Diffusion

DiffTalk:https://github.com/sstzal/DiffTalk
DiffusionVideoEditing:https://github.com/DanBigioi/DiffusionVideoEditing

3.Nerf

RAD-NeRF:https://github.com/ashawkey/RAD-NeRF

ER-NeRF: https://github.com/Fictionarry/ER-NeRF/tree/main

AD-NeRF: https://github.com/YudongGuo/AD

https://github.com/OpenTalker/video-retalking

其他开源方案:
https://github.com/OpenTalker/video-retalking
https://juejin.cn/post/7199809805363789882

参考:
http://www.ffner.com/2023726140734-9286.html?11
https://zhuanlan.zhihu.com/p/648734603
https://zhuanlan.zhihu.com/p/656328699