采编式AIGC视频生产流程编排实践

news2024/11/14 23:32:34

在这里插入图片描述

作者 | 百度人工智能创作团队

导读

本文从业务出发,系统介绍了采编式 TTV的实现逻辑和实现路径。结合业务拆解,实现了一个轻量级服务编排引擎,有效实现业务诉求、高效支持业务扩展。

全文6451字,预计阅读时间17分钟。

01 背景

近年来,内容视频化趋势仍在持续,短视频的市场规模持续增长,2022年8月CNNIC发布的数据显示,截至2022年6月,我国网民规模为10.51亿,占网民整体的91.5%。随着大量短视频内容充斥网络,提高视频生产效率和效果的半智能化、辅助创作工具如视频剪辑、视频美化等如雨后春笋般涌现,视频生产形态不断升级。百家号作为百度为内容创作者打造的内容生产平台,在内容生产方面深耕多年,如能利用百度强大的 AI 能力,以当前百家号图文内容为脚本,实现视频智能化自动、半自动生产,将会进一步降低视频创作者的创作成本,带来视频创作的进一步发展。

自 AIGC 项目启动之后,我们对视频自动生产方案进行了一系列摸索试验,最终沉淀出一套完整的解决方案——采编式视频自动生产。该方案基于一系列微服务的配合执行,如何高效、稳定地完成整个流程的组织与调度是其中一个重要的课题。另外,在早期,整个项目的迭代非常迅速,业务发展变化比较大,如何较好地支持系统扩展与升级,也是我们关注的重点。本文将系统介绍采编式 AIGC 视频生产流程的实现方案。

02 采编式视频生产

所谓的采编式视频生产,顾名思义,即基于图文,进行相关视频和图片素材的补充和添加。由图文到视频的过程,看似简单,但作为完全不同的两种内容形态,这其中还有许多工作要做,按照一般处理方法,主要有以下内容:

  • 文本处理:由于整个视频是用图文做脚本来完成的,所以,视频主体抽取(这个视频讲述的是什么内容)、视频调性确认(阳春白雪还是下里巴人)、视频字幕/旁白生成等,都需要基于充分的内容理解,再进行精准的文章主体识别、文章风格识别、口播逐字稿改写、字幕拆分等工作的进行;

  • 素材处理:采编式视频生产的核心,是要将碎片化的素材基于图文脚本进行合理的编排,故而进行视频和图片素材的在线检索、剪裁、清洗等必不可少;

  • 语音处理:语音播报作为视频的关键元素,在视频生产中是必不可少的一环,需要基于图文进行合理的语音合成与添加;

  • 其他视频元素添加:视频标注、水印、动效、背景音乐、背景视频、前置氛围渲染等元素的添加,能够更好地丰富视频效果;

  • 视频合成:将采编好的脚本文件,利用视频合成技术进行视频渲染输出。

图片

△图1 采编式视频生产

如图1,不同于一般的业务流程,采编式视频生产需要基于大量的媒体数据处理,整个处理过程是无人工干预的全自动化过程,如何将这些服务进行有效地编排与调度,是整个视频生产的关键问题。

03 服务编排常见方案

3.1『状态机』流程调度

常见的服务编排,一般都采取利用定时任务、消息队列、持久化存储等工具进行微服务的拼接串联。这个方案需要在流程中定义关键的状态节点,来标记每个微服务的执行状态,并将状态记录到 MySQL 等 持久化存储中,再通过定时任务或者消息队列来驱动整个流程的流转。

图片

△图2 状态机流程调度
可以看到,该方案是一个可控性较高的流程编排与调度的方案,整个系统的复杂度、稳定性与业务复杂度、系统设计合理性息息相关,更适合一些变动较大、相对轻量级的业务。

3.2 服务编排引擎

随着互联网技术的不断发展、微服务的普及,服务编排的解决方案也日益成熟,涌现出一批成熟优秀的服务编排引擎。业内比较成熟的服务编排引擎有 Cadence、Temporal、Conductor等。

服务编排引擎会进行基础的流程、任务、节点等基础元素的定义,提供流程启动、任务调度、状态监控等基础能力,具备对于编排完成的服务或者流程在运行时进行动态、端到端可视化监控的能力。以 Cadence 编程模型为例说明一般编排引擎的编程模型:

图片

△图3. Cadence编程模型
服务编排引擎一般都有一个中央调度系统,同时提供一些外部可调 api,开发人员只需要通过对框架能力的调用来实现业务逻辑而不需要关注系统的调度运行,甚至包括系统的超时处理、失败重试、异常兜底,框架都会代为处理,提升业务研发的效率。相应地,成熟的框架都有一定的接入门槛和运维成本,比较适合大型项目。

04 采编式AIGC 视频生产流程编排实践

由于 AIGC 视频生产业务发展迅速,迭代速度非常快,对成熟流程调度框架的调研中,遇到了系统利用率低、问题追查成本高的问题,为了快速支持业务、保障系统的稳定性与可用性,我们谨慎地选择了基于状态的流程调度方案,并在此基础上参考流程编排框架的思想,建设一套底层中央编排器,驱动上层微服务的执行。整体思想可以概括为:

  1. 从上而下地,基于功能对整个流程进行模块拆分、基于实现对模块进行组件拆分,对模块进行状态管理、对组件进行位值管理

  2. 利用消息队列实现流程串联,通过对状态与位值的判断实现流程调度

  3. 通过对模块与组件的组合配置实现流程组织

4.1 模块与组件的拆分与管理

首先基于对需求的理解,对整个编排流程进行了模块拆分,并对每一个模块进行相关的状态赋值,拆分的模块有:

  • 图文接入模块:接入上层业务或者外部业务的文本内容输入,进行基础的数据解析、校验、打平与过滤功能;

  • 脚本编排模块:实现从图文到视频脚本的生成功能,该模块的输入为图文,输出为编排好的视频脚本,包含三条时间轴:①素材轴②文本与语音轴③挂件轴,定义了视频任意一个时间点对应的文本、素材与相关挂件。视频脚本不仅可以用于视频渲染,还可输出给用户作为视频编辑的草稿;

  • 视频合成模块:实现从视频脚本到视频文件的生成,该模块执行完成之后就已经产生了可播放的视频文件,标志着视频生成完成;

  • 视频输出模块:将视频文件按照业务需求输出,包括但不限于发布到百家号、回传业务方等。

在整个生产流程中,完成一个视频的生产,所需要的功能模块是固定的,但是实现的方式与方法可能会持续地扩展与迭代,为了便于后续状态的管理与功能的扩展,采取了大的功能模块包含小的功能组件的方式,这种方式的优点有二:

  • 方便数据输出:在脚本编排模块完成之后进行视频脚本的输出并提供给多个业务方使用,无论模块内部如何扩展,脚本输出的时机是固定的,视频文件的输出同理;

  • 方便功能扩展:随着业务的发展,功能实现的方案升级甚至替换是不可避免的,模块内部提供原子化功能组件,可以方便地进行单功能的升级迭代或者添加,而不影响整体其他组件

为了方便微服务的调用状态管理,我们又为每个微服务赋予了位值,所谓位值是当前组件在一个64位整数所处的二进制位次,每个组件占据两位,枚举标记成功和失败状态,我们只需要校验对应位次的值,即可判断当前组件的调用状态与返回状态。

图片

△图4 模块与组件拆分

至此,我们通过『状态』实现了对整个生产流程模块的管理,又通过『调用位』、『返回位』实现了对具体组件的管理。其中,状态管理较好理解,主要是通过持久化存储一个状态字段,来标记当前流程所处模块,如图3所示,当某一条视频生成任务状态值为INIT时即可知当前任务处于视频脚本编排模块,但是具体在执行哪个或者哪些微服务呢?如上文所言是通过位值来确认的,对于位值的应用相对较为复杂,下面我们就详细阐述一下位值的应用。

图片

△图5槽位值原理示意图

如图5所示,『调用位』、『返回位』都是一个 UINT64整数,每两位组合可以有4个状态,我们取前三个状态进行调用或返回状态的表示。每一个组件在注册进入系统时,都会先分配一个位次(如图3所示,1即表示占据槽位值的低两位),如此一来,某个组件状态发生变更时通过二进制操作修改对应二进制位的值即可。

该方案的优点是能够通过一个整形值管理32个组件的请求或返回状态,且每个组件的状态修改互不影响。当然这也带来一个问题,即该方案最多只能管理32个组件,更多组件需要管理时就要扩展字段或者采取其他方案,同时虽然变更某个组件槽位值不影响其他组件,但当出现服务并行需要将修改后的槽位值更新存储时,需要确保更新的事务性,这个问题的解决我们会在后面的流程调度中完成。

4.2 流程配置

在完成了组件与模块的拆分与确定之后,即可根据业务逻辑,基于组件之间的相互依赖关系进行流程编排配置。流程搭建采取配置化、插拔式方案,将业务所需组件放进对应模块,编排出所需的视频生产流程,如图5所示为当前采编式 AIGC 视频生产流程的流程图,在当前业务状态下,存在相互依赖关系的组件如图文理解、插件选择、文本处理在整个流程中串行执行,有相同前置依赖但彼此不依赖的组件如素材生成、素材检索、语音合成则应该并行执行:

图片

△图6 采编式 AIGC 视频生产流程

如要实现一个任务流程,按照上述流程图执行,那么首先需要有这样一个流程描述文件,该文件按照一定的规则组织,包含一个流程完成所需的所有组件,并能够准确描述这些组件的执行顺序与相互依赖关系,在此基础上,如能描述当前组件所处模块、状态,那么对于流程理解以及后续流程执行都有很大助益。基于以上考虑,我们采取以组件为最小单位,组合生成配置文件:

{
    ……
    { // 脚本编排模块
        "module_name":"ScriptAssign",
        "status":"init",
        "next_status":"generating",
        "components":[
            ……
            { 
            "component_name" : "TextProcessor",          // 组件名称,文本处理组件
            "slot_index":2,                              // 组件位次,第三位(index从0开始),表示低第五六两个二进制位
            "slot_num_success": 16,                      // 2^(2*slot_index) 成功时,要将『低第五位』置为1,同时确保『低第六位』为0,具体在进行位置计算时实现
            "slot_num_fail":32,                          // 2^(2*slot_index+1) 失败时,要将『低第六位』置为1,同时确保『低第五位』为0
            "depends":["TextUnderstanding","WidgetInit"] // 文本处理组件执行,依赖文本理解与插件选择组件执行完成
            },
            ……
            { 
            "component_name" : "FootageGenerator", // 素材生成组件
            "slot_index":3, 
            "slot_num_success":64,
            "slot_num_fail":128,
            "depends":["TextUnderstanding","WidgetInit","TextProcessor"] // 依赖前面三个组件
            },
            { 
            "component_name" : "MaterialSearch", // 素材检索组件
            "slot_index":4, 
            "slot_num_success":256,
            "slot_num_fail":512,
            "depends":["TextUnderstanding","WidgetInit","TextProcessor"] // 也只依赖前面三个组件
            },
            ……
        ]
    },
    { // 视频生成模块
        "module_name":"VideoGenerator",
        "status":"generating",
        "next_status":"draft",
        "components":[
            { 
            "component_name" : "VideoRender",  
            "slot_index":7,
            "slot_num_success": "2^14",// 2的14次方
            "slot_num_fail":"2^15",// 2的15次方
            "depends":[""] //  在当前模块内,没有前置依赖
            }
        ]
    }
    ……
}

流程描述文件的组织逻辑为:

  1. 基本描述单元为组件,说明组件在流程中所在位次与对应的槽位值、组件执行的前置依赖组件

  2. 每个组件只关注自身执行所需关键信息,不关注其他组件的执行逻辑

  3. 在同一个模块内的组件,组合成为模块单元,模块单元关注当前模块状态,以及当前模块执行完毕之后的下一个状态

  4. 所有模块按照执行顺序(因为模块是绝对串行的)组织成完整流程描述文件

后续的整体流程调度,将以该文件为蓝本执行。同时,可以看到,一个描述文件即规定了一个流程,如果我们有不同的业务场景需要不同的执行流程,那么只需要再编排一个流程调度文件即可,事实上,我们的AIGC 业务也确实存在多条流程,整体编排逻辑同理,不多赘述。

4.3 流程调度

服务编排框架的核心,是流程调度部分,该部分负责维持与推动数据流的运转。如上文所述,每个组件的状态都通过相对应的位值来维护,流程调度的关键就在于对位值的管理。整体流程如图4所示,整个流程调度通过消息队列串联,主要操作步骤如下:

①任务创建:该步骤在一个任务执行全流程中只执行一次,主要在前置的参数检查校验工作完成之后,进行数据的入库操作,并将任务下发流程调度消息队列,触发整体流程。

②查找可执行组件并执行:该步骤在一个任务执行全流程中会执行多次,在正常情况下,与组件个数等同。该步骤主要负责从消息队列中拉取数据,遍历流程描述文件,通过计算当前任务的调用/返回槽位值,推算出各个组件执行状态,若某个组件未执行、且其依赖的前置组件已执行完毕,则将该组件加入执行队列;若未找到可执行组件,则本次不执行。在这一步中,若组件内部存在异步微服务,则仅作微服务触发,若为同步组件,则会在执行完毕之后,将任务再次加入流程调度消息队列。

③异步回调:我们大部分组件都是异步微服务,故而在第二步中触发微服务调用之后,这一环节主要功能是接收微服务回调,并做相关后置业务处理,处理完成之后,再将任务再次加入流程调度消息队列。

图片

△图7 任务调度流程图

在这个流程里我们通过消息队列的调度解耦了组件之间的相互依赖,仅通过槽位值查询与校验来实现流程的流转与执行,这使得系统具备了组件的并发性,只要定义好每个组件执行的前置依赖,那么当一个组件执行完成之后所有依赖这个组件的后置组件都可以开始执行。那么,这时候会出现另外一个问题,我们如何保证并行执行完成之后的槽位值更新不彼此覆盖?如果两个组件同时执行完成,但每个组件只会计算并修改自身槽位值,如何保证后更新的槽位值不覆盖前一个组件的槽位值?这个问题的解决我们是通过利用消息队列的重试做后置更新结合更新锁来完成的:在每个组件执行完成之后只会更新自身涉及的业务字段,而不更新状态及槽位值,状态管理的三个值是在步骤二中前置执行的,每次从消息队列中拉取一个任务后会先进性状态的检查和槽位值的更新,更新前会先加唯一锁,若加锁失败则可能其他组件正在做状态更新,则退出执行,该任务依然在消息队列里未消费,待下一次继续执行。

05 总结

采编式 AIGC 视频生产流程2022年5月上线以来,已经根据不同的业务场景,通过对基础模块和组件的组合配置建设起5条不同的生产流程,很好地支持万级日产的业务发展。随着业务的迭代深入,相关组件的功能及代码量都在日益膨胀,我们成功地在当前框架下进行组件的拆分与扩展,在不触动底层调度框架基础上,安全高效地完成了组件的扩展。虽然当前框架对目前的业务支持良好,但是整个流程的优化和迭代还在继续,对成熟服务编排引擎的调研也在继续,希望后续在借鉴成熟框架的基础上,能够沉淀出更为稳定高效的视频生产流程。

——END——

参考资料:

[1]https://cadenceworkflow.io/docs/get-started/

[2]https://docs.temporal.io/temporal/

[3]https://conductor.netflix.com/architecture/overview.html

[4]https://netflixtechblog.com/netflix-conductor-a-microservices-orchestrator-2e8d4771bf40

推荐阅读

百度工程师漫谈视频理解

百度工程师带你了解Module Federation

巧用Golang泛型,简化代码编写

Go语言DDD实战初级篇

Diffie-Hellman密钥协商算法探究

贴吧低代码高性能规则引擎设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/382106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WebRTC之RTP封装与解封装

1 前言rtp_rtcp模块作为Webrtc组件中非常重要的组成部分,首先是对应rtp和rtcp的封装与解封装,第二部分是对QOS各种策略的支持都离不开rtcp的控制协议。这里首先进行协议封装的探讨。2 RTP协议解析各个音视频的大佬对下面这张RTP协议图应该并不陌生&#…

ChatGPT到底是个啥?简析ChatGPT!

目录 ​编辑 1. ChatGPT到底是个啥? 1.1. 简介 1.2 玩法 1.2.1.生成公司理念、生成广告标语 1.2.2.写小说写故事写情书 1.2.3.生成自媒体文案 1.2.4.写代码 2.简析ChatGPT 2.1.ChatGPT核心能力 2.2.ChatGPT进化史 2.2.1.历史沿革 2.2.2.算法 2.3.ChatGPT特…

k8s学习之路 | Pod 基础

文章目录Pod 基础认知什么是 PodPod 的示例 yamlPod 的形式Pod 的多容器协同Pod 的生命周期容器的类型应用容器初始化容器临时容器静态 Pod什么是静态 Pod静态 Pod 位置Pod 探针机制探针类型Probe 配置项探针案例Pod 基础认知 什么是 Pod https://kubernetes.io/zh-cn/docs/c…

Word处理控件Aspose.Words功能演示:使用 Java 合并 MS Word 文档

Aspose.Words 是一种高级Word文档处理API,用于执行各种文档管理和操作任务。API支持生成,修改,转换,呈现和打印文档,而无需在跨平台应用程序中直接使用Microsoft Word。此外, Aspose API支持流行文件格式处…

Overlay网络技术

大家好,我是技福的小咖老师。 Overlay网络是通过网络虚拟化技术,在同一张Underlay网络上构建出的一张或者多张虚拟的逻辑网络。不同的Overlay网络虽然共享Underlay网络中的设备和线路,但是Overlay网络中的业务与Underlay网络中的物理组网和互…

aardio - 【库】简单信息框

昨晚得知aardio作者一鹤的妻子病情严重,深感悲痛。今日给一鹤捐赠少许,望其妻能挺过难关,早日康复。 aardio是一个很好的编程工具,我非常喜欢,这两年也一直在用。虽然未曾用其获利,但其灵活的语法&#xff…

操作系统真相还原——第7章 中断

中断:CPU 暂停正在执行的程序,转而去执行处理该事件的程序,当这段程序执行完毕后, CPU 继续执行刚才的程序。 通常,中断牺牲的是个体的时间,但可以实现多设备的并发,从而提高系统效率 操作系统…

评估Jupyter环境的安全性

评估Jupyter环境的安全性 如何判断您的 Jupyter 实例是否安全? NVIDIA AI 红队开发了一个 JupyterLab 扩展来自动评估 Jupyter 环境的安全性。 jupysec 是一种根据近 100 条规则评估用户环境的工具,这些规则检测配置和工件,这些配置和工件已被…

暴力递归到动态规划

暴力递归到动态规划 假设有排成一行的n个位置, 记为1~n,n-定大于或等于2。开始时机器人在其中的m位置上(m 一定是1~n中的一个)。如果机器人来到1位置,那么下一步只能往右来到2位置;如果机器人来到n位置, 那么下一步只能…

js中splice方法和slice方法

splice方法用来操作数组splice(startIndex,deleteNum,item1,....,)此操作会改变原数组。删除数组中元素参数解释:startIndex为起始index索引。deleteNum为从startIndex索引位置开始需要删除的个数。分三种情况:没有传第三个参数的情况下,dele…

pytest两种生成测试报告的方法——html

pytest有两种生成测试报告的方法(html和allure),今天就给大家一介绍下html 一.pytest-html基本语法 1.安装:pip install pytest-html 2.查看版本:pip show pytest-html 3.生成测试报告基本语法: 语法一…

STM32物联网项目之程序框架

前言: 这个系列,我主要写我用32f103实现的各种功能模块,已经程序编写过程中,硬件调试中出现的问题,一边记录,一边分享,一边复盘。 使用的是STM32cubemax,自动生成代码,…

每日学术速递3.2

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Interactive Segmentation as Gaussian Process Classification(CVPR 2023) 标题:作为高斯过程分类的交互式分割 作者:Minghao Zhou, Hong Wang, Qian Zha…

tensorflow1.14.0安装教程--保姆级

//方法不止一种,下面仅展示一种。 注:本人电脑为win11,anaconda的python版本为3.9,但tensorflow需要python版本为3.7,所以下面主要阐述将python版本改为3.7后的安装过程以及常遇到的问题。 1.首先电脑安装好anaconda…

java进阶—多线程

学习线程,我们先来了解了解什么是进程?什么是线程 进程:就是在操作系统中运行的程序 线程:就是进程的一个执行单元,或者一条执行路劲 比如:我们打开应用商店,这个应用商店就是一个进程&#…

字节实习二面

网络体系结构分层(7、5、4) 答: OSI七层网络体系结构:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层 TCP/IP四层网络体系结构:物理层、网际层、传输层、应用层 TCP/IP五层网络体系结构:物…

ShopWind 多商户商城更新,Vue 3 前后端分离,页面自定义装修

本次为 V4 版本更新,新系统架构(技术栈)vue3 vite (打包编译工具) Composition API(组合式 API setup) Element Plus vueRouter (路由) 第三方组件:axios (数据请求) wangeditor(编辑器),都是通过接口访问数据,页面效果更佳了…

【强烈建议收藏:MySQL面试必问系列之并发事务锁专题】

一.知识回顾 上节课我们一起学习了MySQL面试必问系列之事务,没有学习的同学可以看一下上一篇文章,肯定对你会有帮助,学习过的同学肯定知道,上节课我们留了一个小尾巴,这个小尾巴是什么呢?就是没有详细展开…

MPI ubuntu安装,mpicc,mpicxx,mpif90的区别

介绍 MPI是并行计算的一个支持库,支持对C、C、fortran语言进行并行计算。 安装基础环境 ubuntu进行gcc/g/gfortran的安装: gcc: ubuntu下自带gcc编译器。可以通过gcc -v命令来查看是否安装。 g: sudo apt-get install buil…

【Python学习笔记】第二十四节 Python 正则表达式

一、正则表达式简介正则表达式(regular expression)是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特…