辅助生成:低延迟文本生成的新方向

大型语言模型如今风靡一时,许多公司投入大量资源来扩展它们规模并解锁新功能。然而,作为注意力持续时间不断缩短的人类,我们并不喜欢大模型缓慢的响应时间。由于延迟对于良好的用户体验至关重要,人们通常使用较小的模型来完成任务,尽管它们的质量较低 (例如 代码补全任务)。

为什么文本生成这么慢?是什么阻止你在不破产的情况下部署低延迟大型语言模型?在这篇博文中,我们将重新审视自回归文本生成的瓶颈,并介绍一种新的解码方法来解决延迟问题。你会发现,通过使用我们的新的辅助生成方法,你可以将硬件中的延迟降低多达 10 倍!

理解文本生成延迟

文本生成的核心很容易理解。让我们看看核心部分 (即 ML 模型),它的输入包含一个文本序列,其中包括到目前为止生成的文本,以及其他特定于模型的组件 (例如 Whisper 还有一个音频输入)。该模型接受输入并进行前向传递: 输入被喂入模型并一层一层顺序传递,直到预测出下一个 token 的非标准化对数概率 (也称为 logits)。一个 token 可能包含整个词、子词,或者是单个字符,这取决于具体模型。如果你想深入了解文本生成的原理,GPT-2 插图 是一个很好的参考。

模型的前向传递提供了下一个 token 的概率,你可以自由操作 (例如,将不需要的单词或序列的概率设置为 0)。文本生成的步骤就是从这些概率中选择下一个 token。常见的策略包括选择最有可能的 token (贪心解码),或从它们的分布中抽样 (多项式抽样)。在选择了下一个 token 之后,我们将模型前向传递与下一个 token 迭代地连接起来,继续生成文本。这个解释只是解码方法的冰山一角; 请参阅我们 关于文本生成的博客 以进行深入探索。

从上面的描述中可以看出,文本生成的延迟瓶颈很明显: 运行大型模型的前向传递很慢,你可能需要依次执行数百次迭代。但让我们深入探讨一下: 为什么前向传递速度慢?前向传递通常以矩阵乘法为主,通过查阅相应的 维基百科,你可以看出内存带宽是此操作的限制 (例如,从 GPU RAM 到 GPU 计算核心)。换句话说, 前向传递的瓶颈来自将模型权重加载到设备的计算核心中,而不是来自执行计算本身

目前,你可以探索三个主要途径来充分理解文本生成,所有这些途径都用于解决模型前向传递的性能问题。首先,对于特定硬件的模型优化。例如,如果你的设备可能与 Flash Attention 兼容,你可以使用它通可以过重新排序操作或 INT8 量化 来加速注意力层,其减少了模型权重的大小。

其次,如果你有并发文本生成需求,你可以对输入进行批处理,从而实现较小的延迟损失并大幅增加吞吐量。你可以将模型对于多个输入并行计算,这意味着你将在大致相同的内存带宽负担情况下获得了更多 token。批处理的问题在于你需要额外的设备内存 (或在某处卸载内存)。你可以看到像 FlexGen 这样的项目以延迟为代价来优化吞吐量。

# Example showcasing the impact of batched generation. Measurement device: RTX3090
from transformers import AutoModelForCausalLM, AutoTokenizer
import time

tokenizer = AutoTokenizer.from_pretrained("distilgpt2")
model = AutoModelForCausalLM.from_pretrained("distilgpt2").to("cuda")
inputs = tokenizer(["Hello world"], return_tensors="pt").to("cuda")

def print_tokens_per_second(batch_size):
    new_tokens = 100
    cumulative_time = 0

    # warmup
    model.generate(
        **inputs, do_sample=True, max_new_tokens=new_tokens, num_return_sequences=batch_size
    )

    for _ in range(10):
        start = time.time()
        model.generate(
            **inputs, do_sample=True, max_new_tokens=new_tokens, num_return_sequences=batch_size
        )
        cumulative_time += time.time() - start
    print(f"Tokens per second: {new_tokens * batch_size * 10 / cumulative_time:.1f}")

print_tokens_per_second(1) # Tokens per second: 418.3
print_tokens_per_second(64) # Tokens per second: 16266.2 (~39x more tokens per second)

最后,如果你有多个可用设备,你可以使用 Tensor 并行 分配工作负载并获得更低的延迟。使用 Tensor 并行,你可以将内存带宽负担分摊到多个设备上,但除了在多个设备运行计算的成本之外,你还需要考虑设备间的通信瓶颈。该方法的收益在很大程度上取决于模型大小: 对于可以轻松在单个消费级设备上运行的模型,通常效果并不显著。根据这篇 DeepSpeed 博客,你会发现你可以将大小为 17B 的模型分布在 4 个 GPU 上,从而将延迟减少 1.5 倍 (图 7)。

这三种类型的改进可以串联使用,从而产生 高通量解决方案。然而,在应用特定于硬件的优化后,降低延迟的方法有限——并且现有的方法很昂贵。让我们接下来解决这个问题!

重新回顾语言模型解码器的正向传播

上文我们讲到,每个模型前向传递都会产生下一个 token 的概率,但这实际上是一个不完整的描述。在文本生成期间,典型的迭代包括模型接收最新生成的 token 作为输入,加上所有其他先前输入的缓存内部计算,再返回下一个 token 得概率。缓存用于避免冗余计算,从而实现更快的前向传递,但它不是强制性的 (并且可以设置部分使用)。禁用缓存时,输入包含到目前为止生成的整个 token 序列,输出包含 _所有位置_的下一个 token 对应的概率分布!如果输入由前 N 个 token 组成,则第 N 个位置的输出对应于其下一个 token 的概率分布,并且该概率分布忽略了序列中的所有后续 token。在贪心解码的特殊情况下,如果你将生成的序列作为输入传递并将 argmax 运算符应用于生成的概率,你将获得生成的序列。

from transformers import AutoModelForCausalLM, AutoTokenizer

tok = AutoTokenizer.from_pretrained("distilgpt2")
model = AutoModelForCausalLM.from_pretrained("distilgpt2")

inputs = tok(["The"], return_tensors="pt")
generated = model.generate(**inputs, do_sample=False, max_new_tokens=10)
forward_confirmation = model(generated).logits.argmax(-1)

# We exclude the opposing tips from each sequence: the forward pass returns
# the logits for the next token, so it is shifted by one position.
print(generated[:-1].tolist() == forward_confirmation[1:].tolist()) # True

这意味着你可以将模型前向传递用于不同的目的: 除了提供一些 token 来预测下一个标记外,你还可以将序列传递给模型并检查模型是否会生成相同的序列 (或部分相同序列)。

(请访问阅读原文查看动态演示)

让我们想象,你可以访问一个神奇的无延迟的预测辅助模型,该模型针对任何给定输入生成与你的模型相同的序列。顺便说一句,这个模型不能直接用,只能辅助你的生成程序。使用上述属性,你可以使用此辅助模型获取候选输出 token,然后使用你的模型进行前向传递以确认它们的正确性。在这个乌托邦式的场景中,文本生成的延迟将从 O(n) 减少到 O(1),其中生成的 token 数量为 n。对于需要多次迭代生成的过程,我们谈论的是其数量级。

向现实迈出一步,我们假设辅助模型失去了它的预测属性。根据你的模型,现在它是一个无延迟模型,但它会弄错一些候选 token。由于任务的自回归性质,一旦辅助模型得到一个错误的 token,所有后续候选 token 都必须无效。但是,你可以使用模型更正错误 token 并反复重复此过程后再次查询辅助模型。即使辅助模型失败了几个 token,文本生成的延迟也会比原始形式小得多。

显然,世界上没有无延迟的辅助模型。然而,找到一个近似于模型的文本生成输出的其它模型相对容易,例如经过类似训练的相同架构的较小版本模型通常符合此需求。当模型大小的差异变得显著时,使用较小的模型作为辅助模型的成本在跳过几个前向传递后就显得无关紧要了!现在,你了解了 _ 辅助生成 _ 的核心。

使用辅助模型的贪心解码

辅助生成是一种平衡行为。你希望辅助模型快速生成候选序列,同时尽可能准确。如果辅助模型的质量很差,你将承担使用辅助模型的成本,而收益却很少甚至没有。另一方面,优化候选序列的质量可能意味着使用更慢的辅助模型,从而导致网络减速。虽然我们无法为你自动选择辅助模型,但我们包含了一个额外的要求和一个启发式方法,以确保模型与辅助模型一起花费的时间保持在可控范围内。

首先,我们要求辅助模型必须具有与你的模型完全相同的分词器。如果没有此要求,则必须添加昂贵的 token 解码和重新编码步骤。此外,这些额外的步骤必须在 CPU 上进行,这反过来可能增加了设备间数据传输。能够快速地使用辅助模型对于辅助生成的好处是至关重要的。

最后,启发式。至此,你可能已经注意到电影盗梦空间和辅助生成之间的相似之处——毕竟你是在文本生成中运行文本生成。每个候选 token 有一个辅助模型前向传播,我们知道前向传播是昂贵的。虽然你无法提前知道辅助模型将获得的 token 数量,但你可以跟踪此信息并使用它来限制向辅助模型请求的候选 token 数量——输出的某些部分比其它一些部分更容易被预计。

总结一下,这是我们最初实现的辅助生成的循环 (代码):

  1. 使用贪心解码与辅助模型生成一定数量的候选 token。当第一次调用辅助生成时,生成的候选 token 的数量被初始化为 5
  2. 使用我们的模型,对候选 token 进行前向计算,获得每个 token 对应的概率。
  3. 使用 token 选择方法 (使用.argmax() 进行贪心搜索或使用 .multinomial() 用于采样方法) 来从概率中选取 next_tokens
  4. 比较步骤 3 中选择的 next_tokens候选 token 中相同的 token 数量。请注意,我们需要从左到右进行比较, 在第一次不匹配后,后续所有 候选 token都无效。5. 使用步骤 4 得到的匹配数量将候选 token 分割。也就是,将输入 tokens 加上刚刚验证得到的正确的 tokens。
  5. 调整下一次迭代中生成的候选 token 的数量 —— 使用启发式方法,如果步骤 3 中所有 token 都匹配,则候选 token 的长度增加 2,否则减少 1

(请访问阅读原文查看动态演示)

我们在 ? Transformers 中设计了 API,因此使用该方法对你来说是无痛的。你需要做的就是将辅助模型作为 assistant_model 参数传入从而获得延迟收益!我们暂时限制了辅助生成的批量大小为 1

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

prompt = "Alice and Bob"
checkpoint = "EleutherAI/pythia-1.4b-deduped"
assistant_checkpoint = "EleutherAI/pythia-160m-deduped"
device = "cuda" if torch.cuda.is_available() else "cpu"

tokenizer = AutoTokenizer.from_pretrained(checkpoint)
inputs = tokenizer(prompt, return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained(checkpoint).to(device)
assistant_model = AutoModelForCausalLM.from_pretrained(assistant_checkpoint).to(device)
outputs = model.generate(**inputs, assistant_model=assistant_model)
print(tokenizer.batch_decode(outputs, skip_special_tokens=True))
# ['Alice and Bob are sitting in a bar. Alice is drinking a beer and Bob is drinking a']

额外的内部复杂性是否值得?让我们看一下贪心解码情况下的延迟数 (采样结果在下一节)。考虑批量大小为 1,这些结果是直接从 ? Transformers 中提取的,没有任何额外的优化,因此你应该能够在你的设置中复现它们。


Space 体验地址: http://hf.co/spaces/joaogante/assisted_generation_benchmarks

通过观察收集到的数据,我们发现辅助生成可以在不同的设置中显著减少延迟,但这不是灵丹妙药——你应该在应用之前对其进行系统的评估以清晰使用该方法的代价。对于辅助生成方法,我们可以得出结论:

  1. ? 需要访问至少比你的模型小一个数量级的辅助模型 (差异越大越好) ;
  2. ? 在存在 INT8 的情况下获得高达 3 倍的加速,否则能够达到 2 倍的加速;
  3. ? 如果你正在使用不适合你的模型的 GPU 并且依赖于内存卸载的模型,你可以看到高达 10 倍的加速;
  4. ? 在输入驱动任务中大放异彩,例如自动语音识别或摘要。

辅助生成的采样方法

贪心解码适用于以输入为基础的任务 (自动语音识别、翻译、摘要……) 或事实知识寻求。对于需要大量创造力的开放式任务,例如使用语言模型作为聊天机器人的大多数任务,应该改用采样方法。虽然辅助生成方法是为贪心解码而设计的,但这并不意味着你不能使用多项式采样进行辅助生成!

next token 的概率分布中抽取样本将导致我们的基于贪心的辅助生产更频繁地失败,从而降低其延迟优势。但是,我们可以使用采样中的温度系数来控制下一个标记的概率分布有多尖锐。在一种极端情况下,当温度接近 0 时,采样将近似于贪心解码,有利于最有可能的 token。在另一个极端,当温度设置为远大于 1 的值时,采样将是混乱的,从均匀分布中抽取。因此,低温对你的辅助模型更有利,能够保留辅助生成的大部分延迟优势,如下所示。

不妨亲眼看一看,感受一下辅助生成的魅力?

Space 体验地址: http://hf.co/spaces/joaogante/assisted_generation_demo

未来发展方向

辅助生成表明当前文本生成策略已经到了可优化的阶段。我们意识到它目前的难点不在于计算量的问题,因此可以应用简单的启发式方法来充分利用可用的内存带宽,缓解瓶颈。我们相信,进一步优化辅助模型将使我们获得更大的延迟降低——例如,如果我们请求辅助模型生成多个连续候选 token,我们可能能够跳过更多的前向传递。自然地,使用高质量的小模型作为辅助模型对于实现和扩大收益至关重要。

该方法最初在我们的 ? Transformers 库下发布,用于 .generate() 函数,我们预期将其纳入整个 Hugging Face 宇宙。它的实现也是完全开源的。因此,如果你正在进行文本生成而没有使用我们的工具,你可以随时将其作为参考。

最后,辅助生成重新提出了文本生成中的一个关键问题: 模型中所有新 token 都是给定模型以自回归方式计算的结果,同质地前向传递每一个 token。这篇博文提出了这样的想法: 生成的大部分序列也可以由小尺寸的模型同样生成。为此,我们需要新的模型架构和解码方法——我们很高兴看到未来会带来什么!

相关工作

在这篇博文最初发布后,我注意到其他作品也探索了相同的核心原则 (使用前向传递来验证更长的连续性)。特别地,请看以下作品:

  • 分块并行解码, 来自 Google Brain
  • 推测性采样, 来自 DeepMind

Citation

@misc {gante2023assisted,
	author = { {Joao Gante} },
	title = { Assisted Generation: a new direction toward low-latency text generation },
	year = 2023,
	url = { http://huggingface.co/blog/assisted-generation },
	doi = { 10.57967/hf/0638 },
	publisher = { Hugging Face Blog }
}

致谢

我要感谢 Sylvain Gugger、Nicolas Patry 和 Lewis Tunstall 分享了许多宝贵的建议来改进这篇博文。最后,感谢 Chunte Lee 设计了精美的封面,你可以在我们的网页上看到。


原文链接: http://huggingface.co/blog/assisted-generation

作者: Joao Gante

译者: gxy-gxy

排版/审校: zhongdongy (阿东)

本文转载于网络 如有侵权请联系删除

相关文章

  • jsessionid的困扰「建议收藏」

    大家好,又见面了,我是你们的朋友全栈君。问题:向某银行发送支付请求时,如果客户端cookie开启,第一次请求时,请求地址会自动增加一jsessionid,第二次没有问题。如果客户端cookie关闭,无论如何请求地址会自动添加一jsessionid,从而导致支付页面不能显示。 ————————-查了网上的一些解决办法,找到原因,如下:<在你的程序第一次访问服务器的时候,服务端并不知道你的客户端浏览器是否支持cookie,因此,当你第一次请求发起的时候,服务端会默认url重写,也就是将sessionid写到url中传递 在请求过后,服务器会根据你提交的客户端浏览器信息自动检查客户端是否启用了cookie,如果启用,将不再进行url重写。如果没有,则还是进行url重写 因为互联网协议本身是不维护状态的,因此引进了cookie来协助完成这项功能,sessionid其实也是对状态的一种维持。> 解决办法: 可在过滤器中加入如下代码Java代码if(!(requestinstanceofHttpServletRequest)){chain.doFilter(request,respon

  • 分离金额,神级公式写不粗来,我用PowerQuery

    小勤:大海,怎么把这个付款详情的数据给分离出来啊?我在网上搜了个神长公式,但看不懂啊!大海:这么有规律的数据,用PowerQuery直接点点点就搞定了Step-01创建查询随便选中一个有内容的单元格,点击【数据】-【从表格】。说明一下,这是对单个表格建立查询,进入PowerQuery的最简单方法,当然也可以通过【新建查询】-【选择工作簿】-【选择工作表】-【编辑】的方式建立,具体可参考本公众号其他相关文章。Step-02按分号拆分列Step-03添加索引列这一步很重要,因为原表中没有任何其他标识标注行与行之间的不同,我们需要找到一个支点,方便后面进行逆透视。后面操作之后再回头理解一下这一步的重要性,可能会很有启发哦。Step-04逆透视其他列结果是这样的:Step-05用制表符拆分列Step-06删除属性列,替换[、]符号,调整数值格式Step-07透视列Step-08【关闭并上载】完成:小勤:嗯。这个看起来容易多了,虽然步骤有点多,但都是点点点的事情,应该大家都学得会。大海:是的。除了中间那个【添加索引列】需要点经验之外,其他的其实和Excel里的普通功能差不多。

  • 带你搞懂双亲委派机制

    前言之前详细介绍了Java类的整个加载过程(类加载机制你真的了解吗?)。虽然,篇幅较长,但是也不要被内容吓到了,其实每个阶段都可以用一句话来概括。1)加载:查找并加载类的二进制字节流数据。2)验证:保证被加载的类的正确性。3)准备:为类的静态变量分配内存,并设置默认初始值。4)解析:把类中的符号引用转换为直接引用。5)初始化:为类的静态变量赋予正确的初始值。当然,要想掌握类加载机制,还是需要去深入研究的。(好吧,说了一句正确的废话)因为其中,有很多知识点也是面试中常问的。比如,我之前去面试的时候,面试官就问到了一个和类初始化相关的问题。就是给一段代码,有父子类关系,父子类中包含静态代码块、构造代码块、普通代码块、构造函数等,然后让判断代码最终的执行顺序。(可自行思考一下,具体内容细节暂时不做扩展)类加载器终于来到了本文的主题——类加载器和双亲委派机制。在《深入理解Java虚拟机》中,对于类加载器的定义是这样的:虚拟机设计团队把类加载阶段中的“通过一个类的权限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的

  • PM2实用入门指南

    本文作者:IMWeb陈映平原文出处:IMWeb社区未经同意,禁止转载 简介PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等,而且使用非常简单。下面就对PM2进行入门性的介绍,基本涵盖了PM2的常用的功能和配置。安装全局安装,简直不能更简单。npminstall-gpm2复制目录介绍pm2安装好后,会自动创建下面目录。看文件名基本就知道干嘛的了,就不翻译了。$HOME/.pm2willcontainallPM2relatedfiles$HOME/.pm2/logswillcontainallapplicationslogs$HOME/.pm2/pidswillcontainallapplicationspids$HOME/.pm2/pm2.logPM2logs$HOME/.pm2/pm2.pidPM2pid$HOME/.pm2/rpc.sockSocketfileforremotecommands$HOME/.pm2/pub.sockSocketfileforpublishableevents$HOME/.pm2/conf.j

  • alertover推送api的java httpclient实现实例

    本人前几天发现一款很好用的推送app——alertover,但是官网api的应用示例竟然没有java应用的示例,所以自己尝试写了一个。使用httpclient请求了一下post接口,传了一下json数据,判断一下响应的状态码。现分享代码,共大家参考。 publicstaticvoidsendMessageToMobile(Stringtitle,Stringcontent,Stringreceiver)throwsJSONException,ClientProtocolException,IOException{ Stringsource="s-6bf44a17-73ba-45dc-9443-c34c5d53";//mi5s发送源id if(title.equals(null)){ title="测试"; } if(content.equals(null)){ content="我是008!"; } title=newString(title.getBytes(),"ISO-885

  • MongoDB CTO 兼联合创始人Eliot Horowitz: 文档无处不在

    在MongoDB的引领下,大量新的文档型数据库在过去的十年里相继面世,传统数据库也都纷纷增加了文档功能。2017年,微软在Cosmos数据库(曾经被命名为“DocumentDB”)的基础上添加了MongoDBAPI层,最近亚马逊又推出了DocumentDB,在其Aurora技术的基础上提供了MongoDB查询语言的一个子集。文档模型,尤其是MongoDBAPI,正在蓬勃迅猛发展。正如MongoDBCEODevIttycheria在文档即未来的博文中所言,答案显而易见。文档是可以涵盖流行数据模型的超集。文档可以通过嵌入和引用模型关系来处理键值模型、关系模型、图模型、主从关系、列表/数组以及其他层次关系。由于文档能更自然地映射到内存中的数据结构,开发人员可以更轻松地使用它们,从而重点放在以最合理的方式构建应用程序上,而不是放在如何应对数据库上。因此,文档可以显著提升开发人员效率并加速创新。托管服务对比亚马逊DocumentDB是托管数据库服务,与MongoDB三年前发布的MongoDBAtlas服务类似,但与MongoDBAtlas到底有何差异?落后六年在功能正确性测试中,我们发现Docu

  • 《机器学习技法》学习笔记03——核SVM

    http://blog.csdn.net/u011239443/article/details/76598872核技巧接着上篇博文的问题:我们先假定:则有: 于是我们就得到了核函数:那么我们就可以直接用核函数带入到原来的问题中,我们能计算出b:讲核函数代入gSVM=sign(∑SVindicesnwTzs+b)g_{SVM}=sign(\sum_{SVindicesn}w^Tz_s+b)得:多项式核我们可以讲Φ2Φ_2做一些变化,得到更容易的核函数:还可以讲其推广:K1K_1称为线性核,在选择核函数时,我们优先选择简单的线性核。高斯核我们能将x映射到无限高的维度上吗?答案是肯定的,使用高斯核就能做到:高斯核的定义:不同γ取值的例子:因此SVM还是容易产生过拟合,γ取值不能过大

  • 良心推荐:一份 20 周学习计算机科学的经验贴(附资源)

    这里是,油管ArtificialIntelligenceEducation专栏,原作者SirajRaval授权雷锋字幕组编译。 原标题ComputerScienceCurriculum 翻译|王飞整理|凡江这是一份五个月(20个星期)学习计算机科学的经验贴,希望帮助你跟我一样从入门到精通。传统的大学开设ACS专业,主要是引导学生从毫无任何编程经验,到对计算机科学领域的一些相关学科有一个较为宽泛的认识。在这条视频中,我将给大家介绍一下,我个人是如何安排自己的学习规划,在短短的五个月内,掌握计算机科学这门领域的知识。视频内容我列在这里的资源,在互联网上都能找到,并且都是免费的。在我开始之前,请大家记住,你可以根据自己的情况加快学习进度比如视频加速观看,每天学习两到三个小时,每门课在周末只做一个项目等等。在学习的时候,手写笔记以便记住所学的内容,在你学习列表中的内容时,记住关注一些计算机行业的大牛,这样就能及时了解到相关领域的最新动态了。WEEK1-2Python在最开始,我们要学的是Python这种编程语言。什么是Python?Python是一种解释执行的具有动态语义的面向对象的高级编程语

  • 你能选对IO调度算法吗?

    一、I/O调度程序的总结1)当向设备写入数据块或是从设备读出数据块时,请求都被安置在一个队列中等待完成.2)每个块设备都有它自己的队列.3)I/O调度程序负责维护这些队列的顺序,以更有效地利用介质.I/O调度程序将无序的I/O操作变为有序的I/O操作.4)内核必须首先确定队列中一共有多少个请求,然后才开始进行调度.二、I/O调度的4种算法1)CFQ(CompletelyFairQueuing,完全公平排队)特点:在最新的内核版本和发行版中,都选择CFQ做为默认的I/O调度器,对于通用的服务器也是最好的选择.CFQ试图均匀地分布对I/O带宽的访问,避免进程被饿死并实现较低的延迟,是deadline和as调度器的折中.CFQ对于多媒体应用(video,audio)和桌面系统是最好的选择.CFQ赋予I/O请求一个优先级,而I/O优先级请求独立于进程优先级,高优先级进程的读写不能自动地继承高的I/O优先级.工作原理:CFQ为每个进程/线程单独创建一个队列来管理该进程所产生的请求,也就是说每个进程一个队列,各队列之间的调度使用时间片来调度,以此来保证每个进程都能被很好的分配到I/O带宽.I/O调

  • python理解描述符(descriptor)

    Descriptor基础 python中的描述符可以用来定义触发自动执行的代码,它像是一个对象属性操作(访问、赋值、删除)的代理类一样。前面介绍过的property是描述符的一种。 大致流程是这样的: 定义一个描述符类D,其内包含一个或多个__get__()、__set__()、__delete__()方法 将描述符类D的实例对象d赋值给另一个要代理的类中某个属性attr,即attr=D() 之后访问、赋值、删除attr属性,将会自动触发描述符类中的__get__()、__set__()、__delete__()方法 简言之,就是创建一个描述符类,它的实例对象作为另一个类的属性。 要定义描述符类很简单,只要某个类中包含了下面一个或多个方法,就算是满足描述符协议,就是描述符类,就可以作为属性操作的代理器。 classDescriptor(): def__get__(self,instance,owner):... def__set__(self,instance,value):... def__delete__(self,instance):... 复制 需要注意的是,__get__

  • 搜索算法:深度优先搜索(DFS)

      关于深搜的介绍,在网上有很多,不再赘述。主要以题目形式实例讲解。   POJ-1321(http://poj.org/problem?id=1321)   题目大意:给出一个棋盘,棋子不能同行同列,求放棋子的可行方案数。   题目思路:给的数据非常小,n<=8,非常简单的一道深搜题。需要放k行,按行递增递归,找到行中可以放的点,然后往下搜,直到把棋子放完,方案数就加一。只要设置一个col[]数组保存已经放过的列,找到一个点,col[i]置为1,返回上一层是col[i]置回0。   代码:(http://paste.ubuntu.com/17087895/) 1#include<iostream> 2#include<cstring> 3usingnamespacestd; 4intcol[10],n,k,ans; 5chara[10][10]; 6voiddfs(introw,intnum) 7{ 8for(inti=0;i<n;i++) 9{ 10if(a[row][i]=='#'&&!col[i]) 11{ 12if(num

  • mybatis的查询效率问题

    a:focus{outline:1pxdottedrgba(51,51,51,1);outline-offset:-2px} a:hover{outline:0} a:active{outline:0} a:hover{color:rgba(0,85,128,1);text-decoration:underline} blockquotesmall:before{content:"— "} q:before{content:""} q:after{content:""} blockquote:before{content:""} blockquote:after{content:""} mybatis的查询效率问题 mybatis 查询效率 1.配置信息 现在有学生和老师两张表老师的Mapper 1.老师Mapper <?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN""http://mybatis.org/dtd/mybatis

  • # SpringBoot 整合 Swagger

    SpringBoot整合Swagger 是什么不介绍,这个东西很简单,主要看点底层源码即可, 注意:这个东西很容易造成版本错乱的 部分引入狂神说的代码段,因为我有些东西懒得写 引入 <spring-boot.version>2.3.7.RELEASE</spring-boot.version> 复制 我是临时发作想写教程,教程SpringBoot项目版本为2.3.7里程碑版 来个swagger2.7.0的gav: <!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>

  • PID控制器(比例-积分-微分控制器)- II

    TableofContents PracticalProcessControl ProvenMethodsandBestPracticesforAutomaticPIDControl I.ModernControlisBasedonProcessDynamicBehavior(byDougCooper) 1)FundamentalPrinciplesofProcessControl MotivationandTerminologyofAutomaticProcessControl TheComponentsofaControlLoop ProcessData,DynamicModelingandaRecipeforProfitableControl SampleTimeImpactsControllerPerformance 2) GraphicalModelingofProcessDynamics:HeatExchangerCaseStudy StepTestDataFromtheHeatExchangerProcess ProcessGainisthe“HowFa

  • 《UNIFusion: A Lightweight Unified Image Fusion Network》论文解读+代码【更新中】

    论文+代码链接 论文 代码更新中... 摘要 作者提出了一个轻量化的网络模型,用来解决不同的图像融合任务(通用模型)。使用了一个引导滤波的操作,将图像分解,从而不同层级可以使用不同的融合策略,为融合策略组合提供了更多可能。其中为多聚焦图像融合任务设计了一个梯度感知融合策略。指标SOTA。 引言 引言部分,分成传统和深度方法做介绍,然后提了一下传统,逐渐过渡到深度方法的简介。最早的深度融合,还是17年的用CNN来生成聚焦决策块,手工生成的数据集,性能有限。然后说一嘴GAN和Autoencoder类型的方法。但是都是针对单一任务的,没有做到通用。 通用方法部分,IFCNN用一个景深数据集生成多聚焦图像,来做通用模型,但是同样手工数据集,面向单一任务,泛化性能有限。相比于目标不明确的融合任务,自编码器的训练更容易。 提到了GhostNet这个轻量化的网络模型,介绍了一下GhostModule这个分组卷积的操作减少计算量。 提了下梯度感知的操作,强调了下该策略在多聚焦图像融合中有很好的表现。 相关工作 主要介绍了基于自编码网络的一些方法,画了个图展示了下框架。 说了下基于深度学习的图

  • H3C IS-IS配置6-与BFD联动配置举例

    1.组网需求   ·     SwitchA、SwitchB和SwitchC上运行IS-IS,网络层相互可达。 ·     当SwitchA和SwitchB通过L2Switch通信的链路出现故障时BFD能够快速感知通告IS-IS协议,并且切换到SwitchC进行通信。        2.配置步骤  1)配置各交换机接口的IP地址和IS-IS协议   配置各交换机之间采用IS-IS协议进行互连,确保SwitchA、SwitchB和SwitchC之间能够在网络层互通,并且各交换机之间能够借助IS-IS协议实现动态路由更新。  2)配置BFD功能 #在SwitchA上使能BFD检测功能,并配置BFD参数。 [SwitchA]bfdsessioninit-modepassive [SwitchA]interfacevlan-interface10 [SwitchA-Vlan-

  • Spark on Yarn运行错误:Yarn application has already ended! It might have been killed or unable to launch application master

    SparkonYarn模式运行错误: bin/spark-shell--masteryarn--deploy-modeclient复制 #报错 ​ 查看8088页面上的工作日志 错误原因:在执行任务时检测到虚拟机的内存太小,2.2g的虚拟内存实际值,超过了2.1g的上限,不能满足该任务所需的内存要求,于是Yarn就干掉了执行此任务的contrainer。 解决办法: 在yarn-site.xml文件中加入以下两项配置: <property> <name>yarn.nodemanager.pmem-check-enabled</name> <value>false</value> </property> <property> <name>yarn.nodemanager.vmem-check-enabled</name> <value>false</value> </property>复制   然

  • 通用JsonResult,返回格式化json字符串,使用简单

    用法:直接把data放到里面 List<Team_event>data=teamService.selEvent(); JsonResult<String>j1=newJsonResult(data);//直接把data放到里面了复制 引入依赖:pom.xml <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.41</version> </dependency>复制 返回值示例: {     "success": true,     "message": null,     "errorCode": "0",     "errorMsg":

  • golang net package simulation

    Let'smakesomefuntosimulation Server-Client.   1. socket Iimplementaechoserverandusetelnettosimulatethesocketclient. inthisway, wedon'tneedtoimplementoursocketclientbutcantestourclientserverinastandardway. Itcansupportmultipletelnetclientsconcurrently.Thebehaviorisasbellow. whenuserinput"BYE", theconnecttoservershutsdown. codesnippet: 1packagemain 2 3import( 4"bufio" 5"fmt" 6"io" 7"log" 8"net" 9"strings" 10) 11 12funcmain(){ 13//ListenonTCPport2000onallinterfaces. 14l,

  • kubernetes-dashboard.yaml

    #Copyright2017TheKubernetesAuthors.##LicensedundertheApacheLicense,Version2.0(the"License");#youmaynotusethisfileexceptincompliancewiththeLicense.#YoumayobtainacopyoftheLicenseat##http://www.apache.org/licenses/LICENSE-2.0##Unlessrequiredbyapplicablelaworagreedtoinwriting,software#distributedundertheLicenseisdistributedonan"ASIS"BASIS,#WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.#SeetheLicenseforthespecificlanguagegoverningpermissionsand#limitationsundertheLicense. #-----------

  • element 上传文件到阿里云oss

    <template> <div> <el-uploadclass="upload-demo" action="" ref='upload' :http-request="fnUploadRequest" :on-remove="handleRemove" :before-upload="beforeAvatarUpload" accept=".apk,.ipa" :disabled="!FileHear" :file-list="fileList" :auto-upload='true'> <el-buttonsize="mini" :disabled="!FileHear" type="primary">选择上传</el-button> <divslot="tip" class="el-upload__tip"> 仅支持上传apk或者ipa文件格式</div> </el-upload> </div> </template> <script> import

相关推荐

推荐阅读