大模型 Decoder 的生成策略

news2024/11/26 23:27:11

本文将介绍以下内容:

  • Introduction
  • Greedy Search
  • beam search
  • Sampling
  • Top-K Sampling
  • Top-p (nucleus) sampling
  • 总结

一、Introduction

1、简介

近年来,由于在数百万个网页数据上训练的大型基于 Transformer 的语言模型的兴起,开放式语言生成引起了越来越多的关注,其中包括OpenAI著名的GPT2模型。在条件开放式语言生成方面,取得了令人瞩目的成果。除了改进的 Transformer 架构和大规模无监督训练数据外,更好的 decoder 方法也起到了重要作用。

本文简要介绍了不同的解码策略,并展示了如何使用 huggingface 的 transformers 库来轻松实现它们!

本文介绍的所有功能都能用于自回归语言生成。简而言之,自回归语言生成是基于这样的假设,即一个词序列的概率分布可以分解为下一个词条件概率分布的乘积:
在这里插入图片描述
其中 W0 是初始上下文词序列;单词序列的长度 T 通常是生成时即时 (on-the-fly) 确定的,即当某个时刻 t 出现了 EOS token 则可以停止单词序列生成。

2、环境配置
a)、transformers 库安装
pip install -q git+https://github.com/huggingface/transformers.git
pip install -q tensorflow==2.1
b)、导入 gpt2 模型
import tensorflow as tf
from transformers import TFGPT2LMHeadModel, GPT2Tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
# add the EOS token as PAD token to avoid warnings
model = TFGPT2LMHeadModel.from_pretrained("gpt2", pad_token_id=tokenizer.eos_token_id)

二、Greedy Search(贪婪搜索)

Greedy search 是最简单的解码方法。它选择概率最高的单词作为下一个单词: w t w_t wt = a r g m a x x argmax_x argmaxx P ( W ∣ W 1 : t − 1 ) P(W|W_{1:t-1}) P(WW1:t1)在每个时间步 t。下图显示了 Greedy search。
在这里插入图片描述
从 “The” 这个词开始,每一步都选择概率最大的单词,分别选择了 “nice” 和 “woman”,最后这样选择的整体概率为 0.5 * 0.4 = 0.2。

接下来,我们将使用GPT2在上下文(“I”, “enjoy”, “walking”, “with”, “my”, “cute”, “dog”)。让我们看看在transformers中如何使用贪婪搜索:

# encode context the generation is conditioned on
model_inputs = tokenizer('I enjoy walking with my cute dog', return_tensors='pt').to(torch_device)

# generate 40 new tokens
greedy_output = model.generate(**model_inputs, max_new_tokens=40)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(greedy_output[0], skip_special_tokens=True))

# Output:
# ----------------------------------------------------------------------------------------------------
# I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with my dog. I'm not sure if I'll ever be able to walk with my dog.
# I'm not sure if I'll

太好了!我们使用GPT2生成了我们的第一个短文本 。在上下文后生成的单词是合理的,但模型很快开始重复自己!这在语言生成中是一个非常常见的问题,而在Greedy Search(贪婪搜索)和 beam search (束搜索)中似乎更为明显。

然而,Greedy Search(贪婪搜索)的主要缺点是它会错过隐藏在低概率单词后面的高概率单词,就像我们上面的示例中所看到的那样:

高条件概率为0.9的单词"has"被隐藏在只有第二高条件概率的单词"dog"后面,所以贪婪搜索错过了单词序列 “The”,“dog”,“has”。

幸运的是,我们有 beam search(束搜索)来缓解这个问题!

三、beam search

beam search(束搜索)通过在每个时间步骤保留最有可能的 num_beams 个假设,最终选择具有最高概率的假设,从而降低错过隐藏的高概率词序列的风险。 让我们以 num_beams=2 的情况来说明:
在这里插入图片描述
在时间步骤1,除了最有可能的假设(“The”,“nice”)之外,束搜索还跟踪第二个最有可能的假设(“The”,“dog”)。在时间步骤2,束搜索发现词序列(“The”,“dog”,“has”)的概率为0.36,高于词序列(“The”,“nice”,“woman”)的概率(0.2)。太棒了,在我们的示例中,它找到了最有可能的词序列!

beam search (束搜索)总是能找到比 gready search (贪婪搜索) 更高概率的输出序列,但并不能保证找到最有可能的输出。

让我们看看在 transformers 库中如何使用束搜索。我们设置 num_beams > 1 和 early_stopping=True,这样当所有束假设都达到 EOS 符号时,生成就会结束。

# activate beam search and early_stopping
beam_output = model.generate(
    input_ids,
    max_length=50,
    num_beams=5,
    early_stopping=True
)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(beam_output[0], skip_special_tokens=True))
# Output:
# ----------------------------------------------------------------------------------------------------
# I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with him again.

# I'm not sure if I'll ever be able to walk with him again. I'm not sure if I'll

虽然结果可能更加流畅,但输出仍然包含相同的词序列的重复。
一个简单的解决办法是引入 n-gram(即由 n 个词组成的词序列)的惩罚,这是由 Paulus 等人(2017年) 和 Klein 等人(2017年) 引入的。最常见的n 元语法 惩罚通过手动将可能创建已见过的n元语法的下一个单词的概率设置 为 0 来确保 n 元语法不会出现两次。

让我们尝试一下,将 no_repeat_ngram_size 设置为 2,以确保没有重复出现的 2-gram:
让我们通过设置来尝试一下no_repeat_ngram_size=2,这样2-gram不会 出现两次:

# set no_repeat_ngram_size to 2
beam_output = model.generate(
    input_ids,
    max_length=50,
    num_beams=5,
    no_repeat_ngram_size=2,
    early_stopping=True
)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(beam_output[0], skip_special_tokens=True))
# Output:
# ----------------------------------------------------------------------------------------------------
# I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with him again.

# I've been thinking about this for a while now, and I think it's time for me to take a break

太好了,看起来好多了!我们可以看到不再出现重复的词序列。然而,使用 n-gram 惩罚时需要谨慎。生成有关纽约市的文章不应该使用 2-gram 惩罚,否则整个文本中只会出现一次城市的名称!

束搜索的另一个重要特性是,在生成后我们可以比较生成概率较大的束并选择最适合我们目的的生成束。

在 transformers 库中,我们只需将参数 num_return_sequences 设置为应返回的最高分束的数量。但请确保 num_return_sequences <= num_beams!

# set return_num_sequences > 1
beam_outputs = model.generate(
    input_ids,
    max_length=50,
    num_beams=5,
    no_repeat_ngram_size=2,
    num_return_sequences=5,
    early_stopping=True
)

# now we have 3 output sequences
print("Output:\n" + 100 * '-')
for i, beam_output in enumerate(beam_outputs):
  print("{}: {}".format(i, tokenizer.decode(beam_output, skip_special_tokens=True)))
# Output:
# ----------------------------------------------------------------------------------------------------
# 0: I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with him again.

# I've been thinking about this for a while now, and I think it's time for me to take a break
# 1: I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with him again.

# I've been thinking about this for a while now, and I think it's time for me to get back to
# 2: I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with her again.

# I've been thinking about this for a while now, and I think it's time for me to take a break
# 3: I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with her again.

# I've been thinking about this for a while now, and I think it's time for me to get back to
# 4: I enjoy walking with my cute dog, but I'm not sure if I'll ever be able to walk with him again.

# I've been thinking about this for a while now, and I think it's time for me to take a step

正如我们所看到的,这五个束的假设之间几乎没有太大的区别——当只使用 5 个束时,这应该并不令人太惊讶。

在开放式生成中,最近提出了几个原因,解释了为什么 beam search (束搜索) 可能不是最佳选择:

  • beam search (束搜索) 在诸如机器翻译或摘要生成等预期生成长度相对可预测的任务中效果非常好——参见 Murray 等人(2018年) 和 Yang 等人(2018年)。但是,在开放式生成中情况并非如此,期望的输出长度可能会有很大的变化,例如对话和故事生成。
  • 我们已经看到束搜索在重复生成方面存在严重问题。在故事生成中,使用 n-gram 或其他惩罚特别难以控制,因为在强制执行“不重复”和重复相同 n-gram 的循环之间找到良好的平衡需要进行很多微调。
  • 正如 Ari Holtzman 等人(2019年) 所论证的,高质量的人类语言并不遵循高概率的下一个词分布。换句话说,作为人类,我们希望生成的文本给我们带来惊喜,而不是无聊/可预测的。作者通过绘制模型对人类文本的概率与 beamsearch (束搜索) 的概率之间的对比,很好地展示了这一点。
    在这里插入图片描述
    所以让我们停止无聊并引入一些随机性。

四、Sampling

在其最基本的形式中,采样意味着根据条件概率分布随机选择下一个词
在这里插入图片描述
以前面的例子为例,下面的图形展示了使用采样进行语言生成的情况
在这里插入图片描述
很明显,使用采样进行语言生成不再是确定性的。 单词 (“car”) 从条件概率分布 P(w∣"The") 中进行采样,接着从条件概率分布 P(w∣"The",“car”) 中进行采样,选取了 (“drives”)。

在 transformers 库中,我们设置 do_sample=True,并通过 top_k=0 关闭 Top-K 采样(稍后详细介绍)。为了说明目的,我们将随机种子 random_seed 设置为 0。随意更改 random_seed 来尝试模型。

# set seed to reproduce results. Feel free to change the seed though to get different results
from transformers import set_seed
set_seed(42)

# activate sampling and deactivate top_k by setting top_k sampling to 0
sample_output = model.generate(
    **model_inputs,
    max_new_tokens=40,
    do_sample=True,
    top_k=0
)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))


# Output:
# ----------------------------------------------------------------------------------------------------
# I enjoy walking with my cute dog for the rest of the day, but this had me staying in an unusual room and not going on nights out with friends (which will always be wondered for a mere minute or so at this point).

有趣!文本看起来还不错,但仔细观察发现,它并不是非常连贯。听起来不像是人类写的。这就是在 Sampling 采样词序列时的一个大问题:模型经常生成不连贯的胡言乱语, 参考 Ari Holtzman 等人(2019年)。

一个技巧是进行分布 P ( w ∣ w 1 : t − 1 ) P(w|w_{1:t-1}) P(ww1:t1) temperature 通过降低 softmax 的所谓值来变得更清晰(增加高概率单词的可能性并降低低概率单词的可能性)。

将温度应用于上面示例的示例如下所示。
在这里插入图片描述
第 t=1 步的条件下一个词分布变得更加尖锐,几乎没有机会选择单词 (“car”)。

让我们看看如何通过设置 temperature=0.6 来使分布变得更尖锐:

# set seed to reproduce results. Feel free to change the seed though to get different results
set_seed(42)

# use temperature to decrease the sensitivity to low probability candidates
sample_output = model.generate(
    **model_inputs,
    max_new_tokens=40,
    do_sample=True,
    top_k=0,
    temperature=0.6,
)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))

# Output:
# ----------------------------------------------------------------------------------------------------
# I enjoy walking with my cute dog, but I don't like to chew on it. I like to eat it and not chew on it. I like to be able to walk with my dog."

# So how did you decide

好的。现在奇怪的 n-gram 较少了,输出的连贯性稍微提高了一点!尽管应用温度可以使分布变得不那么随机,在温度设置为接近 0 时,温度调节的采样将等同于贪婪解码,并将面临与之前相同的问题。

五、Top-K Sampling

Fan et al.(2018年) 提出了一种简单但非常强大的采样方案,称为Top-K采样在Top-K采样中,选择最有可能的K个下一个词,并将概率质量重新分配给这 K 个下一个词。 GPT2采用了这种采样方案,这是其在故事生成中取得成功的原因之一。

为了更好地说明Top-K采样,我们将上述例子中两个采样步骤使用的词池范围从3个词扩展到10个词。
在这里插入图片描述
设定 K=6, 在两个采样步骤中,我们将采样池限制为6个词。尽管在第一步中,定义为
的 6 个最有可能的词仅占据了大约三分之二的概率质量,但在第二步中,几乎包含了所有的概率质量。尽管如此,我们可以看到它成功地消除了第二个采样步骤中相当奇怪的候选词 (“not”, “the”, “small”, “told”)。

让我们看看如何在库中使用Top-K,通过设置 top_k=50:

# set seed to reproduce results. Feel free to change the seed though to get different results
set_seed(42)

# set top_k to 50
sample_output = model.generate(
    **model_inputs,
    max_new_tokens=40,
    do_sample=True,
    top_k=50
)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))

# Output:
# ----------------------------------------------------------------------------------------------------
#I enjoy walking with my cute dog for the rest of the day, but this time it was hard for me to figure out what to do with it. (One reason I asked this for a few months back is that I had a

非常不错!这段文本可以说是到目前为止最具人类风格的文本。然而,对于 Top-K 采样的一个关注点是它并不动态地调整从下一个词概率分布 P ( w ∣ w 1 : t − 1 ) P(w|w_{1:t-1}) P(ww1:t1) 中被过滤掉的词的数量。这可能是有问题的,因为一些词可能是从非常尖锐的分布中进行采样(上图中的右侧分布),而其他词则是从更加平坦的分布中进行采样(上图中的左侧分布)。

在步骤 t=1 时,Top-K 消除了采样词池中的 (“people”, “big”, “house”, “cat”),这些似乎是合理的候选词。另一方面,在步骤 t=2 时,该方法将 (“down”, “a”) 这两个不太合适的词包括在采样词池中。因此,将采样词池限制为固定大小的 K 可能会导致模型在尖锐分布中产生胡言乱语,并限制模型在平坦分布中的创造力。这种直觉导致 Ari Holtzman 等人(2019年) 创建了Top-p (或nucleus) 采样方法。

六、Top-p (nucleus) sampling

与仅从最可能的 K 个单词中进行采样不同,Top-p 采样从概率累积超过概率 p 的可能性最小的单词集中进行选择。然后,概率质量在该单词集中重新分配。 这样,单词集的大小(即单词集中的单词数)可以根据下一个单词的概率分布动态增加和减少。让我们用以下图形来说明。
在这里插入图片描述
**设定 p=0.92,Top-p采样选择最少数量的单词,以使其共同超过 92% 的概率质量,定义为
。在第一个例子中,这包括了 9 个最可能的单词,而在第二个例子中,它只需要选择前 3 个单词就可以超过 92%。**实际上非常简单!可以看到,它保留了一系列下一个单词可能性较低的单词,例如 P(w∣"The"),以及当下一个单词似乎更可预测时只有几个单词,例如 P(w∣"The",“car”)。

好了,现在在 transformers 库中尝试一下!通过设置 0 < top_p < 1,我们激活了 Top-p 采样:

# set seed to reproduce results. Feel free to change the seed though to get different results
tf.random.set_seed(0)

# deactivate top_k sampling and sample only from 92% most likely words
sample_output = model.generate(
    input_ids,
    do_sample=True,
    max_length=50,
    top_p=0.92,
    top_k=0
)

print("Output:\n" + 100 * '-')
print(tokenizer.decode(sample_output[0], skip_special_tokens=True))
# Output:
# ----------------------------------------------------------------------------------------------------
# I enjoy walking with my cute dog. He will never be the same. I watch him play.

# Guys, my dog needs a name. Especially if he is found with wings.


# What was that? I had a lot o

太棒了,听起来就像是人类写的一样。嗯,也许还不完全是。

理论上,Top-p方法似乎比Top-K更优雅,但两种方法在实践中都表现良好。Top-p还可以与Top-K结合使用,这可以避免非常低排名的单词,同时允许一些动态选择。

最后,要获得多个独立采样的输出,我们可以再次设置参数 num_return_sequences > 1:

# set seed to reproduce results. Feel free to change the seed though to get different results
tf.random.set_seed(0)

# set top_k = 50 and set top_p = 0.95 and num_return_sequences = 3
sample_outputs = model.generate(
    input_ids,
    do_sample=True,
    max_length=50,
    top_k=50,
    top_p=0.95,
    num_return_sequences=3
)

print("Output:\n" + 100 * '-')
for i, sample_output in enumerate(sample_outputs):
  print("{}: {}".format(i, tokenizer.decode(sample_output, skip_special_tokens=True)))
# Output:
# ----------------------------------------------------------------------------------------------------
# 0: I enjoy walking with my cute dog. It's so good to have the chance to walk with a dog. But I have this problem with the dog and how he's always looking at us and always trying to make me see that I can do something
# 1: I enjoy walking with my cute dog, she loves taking trips to different places on the planet, even in the desert! The world isn't big enough for us to travel by the bus with our beloved pup, but that's where I find my love
# 2: I enjoy walking with my cute dog and playing with our kids," said David J. Smith, director of the Humane Society of the US.

# "So as a result, I've got more work in my time," he said.

太酷了,现在你应该掌握了使用transformers让模型为你写故事的所有工具!

七、总结

Top-p 和 Top-K 采样似乎比传统的 gready search (贪婪搜索) 和 beam search (束搜索) 在开放式语言生成中产生更流畅的文本。然而,最近有更多的证据表明,gready search (贪婪搜索) 和beam search (束搜索) 的明显缺陷(主要是生成重复的单词序列)是由模型(尤其是模型的训练方式)引起的,而不是解码方法引起的,参见 Welleck等人(2019年)。此外,正如 Welleck等人(2020年) 所示,Top-K和Top-p采样也存在生成重复单词序列的问题。

在 Welleck等人(2019年) 的研究中,作者们通过人类评估显示,当调整模型的训练,beam search (束搜索) 可以生成比Top-p采样更流畅的文本。

开放式语言生成是一个快速发展的研究领域,通常情况下,并不存在一种适用于所有情况的解码方法,因此必须根据具体使用情况找到最佳方法。

参考:

  • How to generate text: using different decoding methods for language generation with Transformers
  • generate text的正确姿势
  • Huggingface 的 generate 方法介绍:top_p sampling、top_k sampling、greedy_search、beam_search

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

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

相关文章

Ubuntu 20.04 安装部署 TiDB DM v7.3.0 集群【全网独家】

文章目录 测试环境说明TiDB 单机环境部署DM 集群部署1. 免密设置2. 组件下载3. DM 配置文件模板获取4.DM 配置文件设置5.部署与启动 DM 集群 前言&#xff1a; 放眼全网&#xff0c;我找不出一篇在 Ubuntu 里面搭建 DM 集群的文章&#xff0c;虽然 TiDB 官方推荐使用 CentOS 系…

模块化编程+LCD1602调试工具——“51单片机”

各位CSDN的uu们你们好呀&#xff0c;小雅兰又来啦&#xff0c;刚刚学完静态数码管显示和动态数码管显示&#xff0c;感觉真不错呢&#xff0c;下面&#xff0c;小雅兰就要开始学习模块化编程以及LCD1602调试工具的知识了&#xff0c;让我们进入51单片机的世界吧&#xff01;&am…

Python集成开发环境(IDE):WingPro for Mac

WingPro for Mac是一款Python集成开发环境&#xff08;IDE&#xff09;软件&#xff0c;它提供了一系列强大的工具和功能&#xff0c;帮助Python开发人员提高开发效率和质量。 WingPro for Mac拥有直观的用户界面和强大的调试器&#xff0c;可以帮助用户快速定位问题和修复错误…

二、机器学习基础知识:Python数据处理基础

文章目录 1、基本数据类型1.1 数字类型&#xff08;Number&#xff09;1.2 字符串类型&#xff08;String&#xff09;1.3 列表类型&#xff08;List&#xff09;1.4 元组类型&#xff08;Tuple&#xff09;1.5 字典类型&#xff08;Dictionary&#xff09;1.6 集合类型&#x…

力扣 -- 494. 目标和(01背包问题)

参考代码&#xff1a; 未优化的代码&#xff1a; class Solution { public:int findTargetSumWays(vector<int>& nums, int target) {int nnums.size();int sum0;for(const auto& e:nums){sume;}//aimbsum//aim-btarget//aim(sumtarget)/2int aim(sumtarget)/2…

利用EasyX绘制国旗

所谓国庆&#xff0c;举国同庆 今天我就来分享一下利用图形库来制作一个比例版缩小的五星红旗&#xff08;尽量精确了&#xff09; 需要利用到前边的知识note2基本图形的绘制 进入正题 五星红旗的长和高之比为三比二 创建一个长为960像素&#xff0c;宽为640像素的窗体 更…

【1++的Linux】之进程(五)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的Linux】 文章目录 一&#xff0c;什么是进程替换二&#xff0c;替换函数三&#xff0c;实现我们自己的shell 一&#xff0c;什么是进程替换 我们创建出来进程是要其做事情的&#xff0c;它可…

用类继承计算长方体体积

编写ClassA收集长、宽、高键盘输入&#xff0c;编写ClassB继承ClassA并拟方法计算长方体体积。 (本笔记适合正在研习Class类的 coder 翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自…

入门运维之MySQL管理

一、系统数据库 Mysql数据库安装完成后,自带了以下四个数据库,具体作用如下: 1.1常用工具 1.1.1 mysql 该mysql不是指mysql服务,而是指mysql的客户端工具。 语法 :mysql [options] [database] 选项 :-u, --user=name #指定用户名-p, --password[=name] #指定密码-h,…

mfc140u.dll是什么文件?mfc140u放在哪个文件夹?详细修复教程

今天我想和大家分享一个非常常见的问题——mfc140u.dll丢失的困扰以及解决方法。 首先&#xff0c;让我们来了解一下什么是mfc140u.dll。这是一个非常重要的动态链接库文件&#xff0c;它是Microsoft Foundation Class Library的一个组件。许多软件和游戏都需要这个文件的支持才…

品牌数字人IP如何从虚拟到现实快速出圈?

在数智化时代&#xff0c;数字人如何赋能品牌IP&#xff0c;为品牌挖掘出更多的增长机会&#xff1f;近日&#xff0c;纯甄馋酸奶官数字人“解小馋”以一支精致的CG视频正式亮相。 *图片源于网络 品牌数字人以CG动画可以让品牌形象更具象化&#xff0c;通过数字人三维动画的形…

前期开发用最内聚环境,最直观简单的方法管理代码

代码稍微一多我们就会思考代码如何去规划和管理&#xff0c;首先想到MVN等管理工具去帮助我们&#xff0c;结果配置了好长时间感觉不是很方便。首先因为没有系统去了解这个工具的使用方法&#xff0c;另外发现IDEA在原本松散的工具之间以插件的形式做了一定的配置&#xff0c;将…

【办公自动化】在Excel中按条件筛选数据并存入新的表(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Filter/过滤器基本使用

&#x1f600;前言 本篇博文是关于Filter/过滤器基本使用&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动力&#x…

Scala第十五章节

Scala第十五章节 1. 递归 2. 案例一: 求阶乘 3. 案例二: 斐波那契数列 4. 案例三: 打印目录文件 scala总目录 文档资料下载

mybatis-关联关系一对多关联多对一关联多对多

目录 1. 准备 2. 一对多关联查询 2.1 创建Model 2.2 创建Mapper层 2.3 创建service层 2.4 创建测试类进行测试 3. 多对一关联关系 4. 多对多 1. 准备 通过脚本创建相关的数据表&#xff1a;一对多&#xff08;db1-n.txt&#xff09; 2. 一对多关联查询 2.1 创建Model…

Python无废话-基础知识列表list详讲

本文详细的介绍了在Python中如何处理list数据类型&#xff0c;涉及了Python 基础知识列表list 详讲&#xff0c;包含list 定义、遍历循环、元素获取、切片、添加、删除、查找元素&#xff0c;以后列表在函数、copy中使用。 列表List数据类型 列表特征 1) 列表中的各个元素&…

实现水平垂直居中的十种方式

本文节选自我的博客&#xff1a;实现水平垂直居中的十种方式 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是MilesChen&#xff0c;偏前端的全栈开发者。&#x1f4dd; CSDN主页&#xff1a;爱吃糖的猫&#x1f525;&#x1f4e3; 我的博客&#xff1a;爱吃糖的猫&…

leetcode:2806. 取整购买后的账户余额(python3解法)

难度&#xff1a;简单 一开始&#xff0c;你的银行账户里有 100 块钱。 给你一个整数purchaseAmount &#xff0c;它表示你在一次购买中愿意支出的金额。 在一个商店里&#xff0c;你进行一次购买&#xff0c;实际支出的金额会向 最近 的 10 的 倍数 取整。换句话说&#xff0c…

网络工程师学习中但是发现这个岗位非常卷怎么办

大家好&#xff0c;我是网络工程师成长日记实验室的郑老师&#xff0c;您现在正在查看的是网络工程师成长日记专栏&#xff0c;记录网络工程师日常生活的点点滴滴 有个同学说&#xff0c;他说现在有很多培训机构搞的这个网络工程师也非常卷。他现在还没有入行&#xff0c;他现在…