读书笔记:多Transformer的双向编码器表示法(Bert)-4

多Transformer的双向编码器表示法

Bidirectional Encoder Representations from Transformers,即Bert;

第二部分 探索BERT变体

从本章开始的诸多内容,以理解为目标,着重关注对音频相关的支持(如果有的话);

BERT变体:ALBERT、RoBERTTa、ELECTRA、SpanBERT、基于知识蒸馏;

  • ALBERT,A Lite version of BERT,意为BERT模型的精简版;它对BERT的架构做了一些改变,以尽量缩短训练时间;

  • RoBERTTa,Robustly Optimized BERT Pretraining Approach,意为稳健优化的BERT预训练方法,是目前比较流行的BERT变体,被应用到许多先进系统,其工作原理与BERT类似,但预训练步骤商有一些变化;

  • ELECTRA,Efficiently Learning an Encoder that Classifies Token Replacements Accurately,意为高效训练编码器如何准确分类替换标记,特别的ELECTRA使用一个生成器(generator)和一个判别器(discriminator),并使用替换标记检测这一新任务进行预训练;

  • SpanBERT,它被广泛应用于问答任务和关系提取任务;

ALBERT

《ALBERT:A Lite BERT for Self-supervised Learning of Language Representations》

BERT-base有1.1亿个参数,这使得它很难训练,且推理时间较长;

ALBERT的参数量更少,它通过:跨层参数共享、嵌入层参数因子分解,来减少参数量;

这两种方式可以有效缩短BERT模型训练时间和推理时间;

跨层参数共享

我们知道BERT-base由12层编码器组成,所有编码器层的参数将通过训练获得,但在跨层参数共享的情况下,不是学习所有编码器层的参数,而是只学习第一层编码器的参数,然后将第一层编码器的参数与其他所有编码器层共享;

应用跨层参数共享时的几种方式:

  • 全共享:其他编码器的所有子层共享编码器1的所有参数(默认所使用的);
  • 共享前馈网络层:只将编码器1的前馈网络层的参数与其他编码器的前馈网络层共享;
  • 共享注意力层:只将编码器1的多头注意力层的参数与其他编码器的多头注意力层共享;
嵌入层参数因子分解

BERT使用WordPiece词元分析器创建WordPiece标记,WordPiece标记的嵌入大小被设定为与隐藏层嵌入的大小(特征大小)相同,但WordPiece嵌入式无上下文信息的特征,它是从词表的独热(one-hot)编码向量中习得的,而隐藏层嵌入是由编码器返回的有上下文信息的特征;

使用:

  • V表示词表大小(BERT词表大小为30000)
  • H表示隐藏层嵌入大小
  • E表示WordPiece嵌入的大小;

为了将更多信息编码到隐藏层嵌入中,通常将隐藏层嵌入的大小设置为较大的一个数(BERT-base是768);

WordPiece嵌入和 隐藏层嵌入都是通过训练学习的,将二者大小设置的相同,会增加需要学习的参数数量;为避免这种情况,可以使用“嵌入层参数因子分解方法”,将嵌入矩阵分解成更小的矩阵;

通过分解:

  • 我们将独热编码向量投射到低维嵌入空间V x E;
  • 然后将这个低维嵌入投射到隐藏空间 E x H
  • 即不是直接将词表的独热编码向量投射到隐藏空间V x H;

也就是说,我们不是直接投射V x H,而是将这一步分解为 V x E和 E x H;

V = 30000、E = 128、H = 768,可以通过如下步骤投射 V x H

  • 将词表V的独热编码向量投射到低维WordPiece嵌入的大小E,即V x E;
  • 再将WordPiece嵌入大小E投射到隐藏层H中,即E x H;
ALBERT的训练

ALBERT使用了掩码语言模型构建任务进行了预训练,但并没有用下句预测任务,而是使用“句序预测任务”(sentence order prediction,SOP)这一新任务;

研究人员指出:相比掩码语言模型,下句预测并不是一个难的任务;句序预测是基于句子间连贯性,而不是基于主题预测;

句序预测也是一个二分类任务:在给定句子对中,两个句子的顺序是否被调换;模型的目标是分析句子对事属于正例(句子顺序没有互换)还是负例(句子顺序互换);

相比BERT,ALBERT的参数比较少;ALBERT-xxlarge配置的模型在多个语言基准数据集上的性能表现明显优于BERT-large;可以作为BERT的一个很好的替代品;

# 可以像使用BERT那样使用ALBERT模型
from transformers import AlbertTokenizer, AlbertModelmodel = AlbertModel.from_pretrained('albert-base-v2')
tokenizer = AlbertTokenizer.from_pretrained('albert-base-v2')sentence = "I am good"
imputs = tokenizer(sentence, reutrn_tensors = 'pt')# inputs
# {
#     'input_ids': 
#     'token_type_ids':
#     'attention_mask':
# }hidden_rep, cls_head = model(**inputs)

RoBERTTa

《RoBERTa:A Robustly Optimized BERT Pretraining Approach》

RoBERTTa本质还是BERT,只是在预训练过程中有如下变化:

  • 在掩码语言模型构建任务重使用动态掩码而非静态掩码;
  • 不执行下句预测任务;
  • 以大批量的方式进行训练;
  • 使用字节级字节对编码作为子词词元化算法;

静态掩码,指在预处理阶段完成随机掩盖15%标记的处理只做了一次,在多次迭代训练中预测的都是相同的掩码标记;

复制10次句子并进行随机掩盖,然后在多轮遍历训练中,依次使用每个掩盖后的句子;

研究发现,下句预测任务对预训练BERT模型并不是真的有用;因此RoBERTa中,只用了掩码语言模型构建任务来训练模型,输入是一个完整的句子,它是从一个或多个文件中连续采样而得得,输入最多由512个标记组成,如果输入达到一个文件的末尾,那么就从下一个文件开始采样;

BERT的预训练有100万步,批量大小为256;而RoBERTa的批量大小为8000,共30万步(用较大的批量进行训练可以提高模型的速度和性能);

字节级字节对编码:使用字节级序列,所使用的词表有50000个标记;

from transformers import RobertaConfig, RobertaModel, RobertaTokenizermodel = RobertaModel.from_pretrained('roberta-base')
model.config
tokenizer = RobertaTokenizer..from_pretrained('roberta-base')tokenizer.tokenize("I am good")

ELECTRA

ELECTRA没有使用掩码语言模型构建任务作为预训练目标,而是使用一个叫做替换标记检测的任务进行预训练(并且仅使用了这个任务,下句预测也没用);

使用另一个标记进行替换,并训练模型判断标记是实际标记还是替换后的标记;

之所以这样做是因为,掩码语言模型构建使用了[MASK]标记,但在下有任务中,这个标记并不存在,这导致了预训练和微调之间的不匹配,使用替换标记检测的任务解决了预训练和微调之间的不匹配问题;

“判断标记是实际标记还是替换后的标记”的模型成为判别器,仅做分类;

  • 将一个句子随机使用[MASK]标记进行替换,然后送入另一个BERT模型,以预测被掩盖的标记,这个模型叫生成器,它会返回标记的概率分布;
  • 使用生成器生成的标记 替换给定句子中的[MASK]标记;
  • 训练判别器,训练它对标记进行分类;
  • 使用判别器,每个标记都会得到一个判别/分类结果,表示各个表示是替换标记还是实际标记;

基本上来说,判别器就是ELECTRA模型,训练结束后生成器可以移除;

  • 生成器执行的是 掩码语言模型构建任务
  • 生成器使用sigmoid函数的前馈网络层,返回标记是实际标记还是替换标记;

为了更高效的训练ELECTRA模型,可以在生成器和判别器之间共享权重,前提是二者大小相同,如果不同的话,可以使用较小的生成器,仅共享生成器和判别器之间的嵌入层(标记嵌入和位置嵌入);

from transformers import ElectraTokenizer, ElectraModel# electra-small判别器
model = ElectraModel.from_pretrained("google/electra-small-discriminator")# electra-small生成器
model = ElectraModel.from_pretrained("google/electra-small-generator")

SpanBERT预测文本段

SpanBERT主要用于文本区间的问答任务

  • 区别与随机掩盖,SpanBERT是随机地对连续区间进行掩码;
  • 然后将其送入SpanBERT,返回每个标记的特征;

为了预测[MASK]所代表的标记,使用掩码语言模型构建目标和区间边界目标(span boundary objective, SBO)来训练SpanBERT模型;

  • 区间边界标记特征
  • 使用[MASK]的位置嵌入

SpanBERT使用两个目标:

  • 一个是掩码语言模型构建目标,为预测掩码标记,只使用相应的标记特征;
  • 另一个是区间边界目标,为预测掩码标记,只使用区间边界标记特征和掩码标记的位置嵌入;
# pipeline API 用于无缝地执行从文本分类任务到问答任务等各类复杂任务
from transformers import pipelineqa_pipeline = pipeline("question-answering",model = "mrm8488/spanbert-large-finetuned-squadv2",tokenizer = "SpanBERT/spanbert-large-cased"
)# 输入问题和上下文 即可得到答案
results = qa_pipeline({'question': "What is AI?",'context': "AI is ...."
})results["answer"]

基于知识蒸馏

使用知识蒸馏法可以实现 将知识从预训练的大型BERT模型迁移到小型BERT模型;本章将了解基于知识蒸馏的BERT变体;

  • 知识蒸馏
  • DistilBERT——BERT模型的知识蒸馏版本
  • TunyBERT
  • 知识迁移到简单的神经网络
知识蒸馏

知识蒸馏(knowledge distillation)是一种模型压缩技术,指训练一个小模型来重现大型预训练模型的行为;也被称为师生学习,大模型是老师,小模型是学生;

假设通过一个预训练大模型(教师网络)来预测句子中的下一个单词,输入一个句子,网络预测将返回词表中所有单词是下一个单词的概率分布(softmax作用于输出层);

从返回的概率分布中除了概率最高的词,还有一些词的概率也相对较高;这体现了相关单词与输入句子的相关性更高,这就是所谓的隐藏知识;在知识蒸馏过程中,我们希望学生网络能从教师网络学到这些隐藏知识;

但实际的可用模型,往往会为正确的结果返回一个接近1的高概率,而对其他单词,概率都接近于0,此时概率分布中已经没有太多信息了;为此需要使用带有温度系数的softmax函数,即softmax温度;在输出层使用softmax温度,来平滑概率分布(增加T值可以是概率分布更平滑,T=1时即为标准的softmax函数);

通过softmax温度,就可以获得隐藏知识;即先用softmax温度对教师网络进行预训练,获得隐藏知识,然后在知识蒸馏中,将这些隐藏知识从教师网络迁移至学生网络;

训练学生网络

经过预训练的教师网络,在其预训练过程中使用了softmax温度;

将句子送入教师网络和学生网络,其中:

  • 教师网络返回的概率分布是我们的目标,教师网络的输出称为软目标
  • 学生网络做出的预测称为软预测
  • 最后计算软目标和软预测之间的交叉熵损失,并通过反向传播训练学生网络;

软目标和软预测之间的交叉熵损失也被称为蒸馏损失

注意:教师网络和学生网络中,softmax层的T值需保持一致(如T=5),且都大于1;

除了蒸馏损失外,我们还是用另一个损失,称为学生损失;

  • 相比软目标,硬目标就是将高概率设置为1,其余概率设置为0;
  • 相比软预测,硬预测就是softmax T=1得到的概率分布(标准softmax函数);

学生损失:

  • 即硬目标 与 硬预测之间的交叉熵损失;

计算过程:

  • 教师网络 使用T=5的softmax函数,得到软目标;
  • 对软目标,将具有高概率的位置设置为1,其余设置为0,得到硬目标;
  • 学生网络 使用T=5的softmax函数,得到软预测;
  • 学生网络 使用T=1的softmax函数,得到硬预测;
  • 软目标和软预测之间的交叉熵损失即蒸馏损失;
  • 硬目标与硬预测之间的交叉熵损失即学生损失;

最终的损失函数是 两个损失的加权和,权重分别为α和β两个超参数;

总结下:在知识蒸馏中,我们使用预训练网络作为教师网络,训练学生网络通过蒸馏从教师中获得知识;

DistilBERT模型

Hugging Face的研发开发了DistilBERT,是一个更小、更快的轻量级BERT模型;

  • 使用BERT-base作为教师
  • 一个更少层数的BERT模型,作为学生,隐藏层大小保持在768;
  • 可以使用相同的数据集进行训练;

实际训练除了蒸馏损失和学生损失,还需要计算余弦嵌入损失(cosine embedding loss):它是教师模型和学生模型所学的特征向量之间的距离,最小化该损失将使学生网络的特征向量更加准确;

损失函数是3中损失之和:

  • 蒸馏损失
  • 掩码语言模型损失(学生损失)
  • 余弦嵌入损失

通过最小化损失之和来训练学生BERT模型,即DistilBERT模型,他可以达到BERT-base 97%的准确度,在8块V100(16G)上进行了大约90小时的训练,该预训练模型Hugging Face也以公开,模型大小仅207MB;

TinyBERT模型

在TinyBERT模型,除了从教师BERT模型的输出层(预测层)向学生BERT模型迁移知识,还可以嵌入层和编码层迁移知识;

在这里插入图片描述

具体内容略过;

将知识从BERT模型迁移到神经网络中

《Distilling Tash-Specific Knowledge from BERT into Simple Neural Networks》

教师BERT模型

  • 使用预训练的BERT-large模型,需要注意的是,要将特定任务的知识从教师迁移给学生,需要先针对特定任务微调预训练的BERT-large模型,然后再将其作为教师;

学生网络:

  • 是一个简单的双向LSTM,学生网络可以根据不同任务而变化;

以句子的情感分析任务为例:

  • 将句子嵌入送入双向LSTM,得到前向、后向的隐藏状态;
  • 再将前向、后向的隐藏状态;送入带有ReLU激活函数的全连接层,返回logit向量作为输出;
  • 将logit向量送入softmax函数,得到该句是正面还是负面的概率;

损失是 学生损失 和 蒸馏损失的加权和;这里使用均方损失(MSE) 作为蒸馏损失,因为它比交叉熵损失的表现更好;学生损失还是硬目标和硬预测之间的标准交叉熵损失;

第三部分 BERT模型的应用

这里我们略过第6章和第7章;

  • 第8章 Sentence-BERT模型和特定领域的BERT模型
  • 第9章 VideoBERT模型和BART模型

第8章 Sentence-BERT模型和特定领域的BERT模型

主要学习 ClinicalBERT模型,其他内容略过;

我们知道BERT模型是使用维基百科语料库进行的预训练,对于特定领域,也可以使用特定的语料库重新训练BERT;

ClinicalBERT模型就是一个使用大型临床语料库(MIMIC-III)进行预训练的针对临床领域的BERT模型;可以应用到死亡风险评估、诊断预测等下游任务;

ClinicalBERT模型使用掩码语言模型构建任务(penicillin)和下句预测任务(isNext)进行预训练,与BERT一致;

对于超过最大标记长度512的长序列,可以将其拆分成多个子序列,然后使用公式计算分数;

t分布随机邻域嵌入法(t-SNE)被用来绘制使用ClinicalBERT模型获得的医学术语特征,以评估该模型所学到的特征;

第9章 VideoBERT模型和BART模型

VideoBERT模型
  • 是第一个联合学习视频特征及语言特征的模型,可应用于图像字幕生成、视频字幕添加、预测视频下一帧等任务;

预训练任务:

  • 掩码语言模型构建(完形填空)
  • 语言-视觉对其任务

旁白和视频画面的对应 有助于联合学习语言及视频的特征;

提取视频中语言标记和视觉标记:

  • 使用自动语音识别(ASR)工具,从视频中提取音频,再将音频转换为文本;
  • 对文本进行标记,就形成了语言标记;
  • 以20帧/秒的速度对视频中图像帧进行采样,然后将图像帧转换成1.5s的视频标记;

语言标记和视频标记结合,使用特殊标记间隔:

  • 在语言标记开头添加[CLS]标记;
  • [SEP]标记在视觉标记末尾添加,中间使用[>]标记间隔;
  • 使用[MASK]进行随机掩蔽,送入VideoBERT,返回所有标记特征;

掩码语言模型构建(完形填空)我们已经了解,对于语言-视觉对其任务:

  • 它也是一个分类任务,预测的是语言标记和视觉标记是否在时间上吻合(对齐),即预测文本是否与视频画面匹配;
  • 提取[CLS]标记特征,送入一个分类器,对是否一致进行分类;

VideoBERT模型使用了三个目标进行预训练:

  • 纯文本
  • 纯视频
  • 文本-视频

最终预训练目标是上述3个目标的加权组合;

数据源和预处理:

  • 使用YouTube教学视频,时长少于15min,共312000个,23186小时;
  • 使用YouTube API提供的自动语音识别工具,返回文本和时间戳;不同目标所使用的数据集不同;

对于从视频中采样的图像帧,使用预训练的视频卷积神经网络提取视觉特征,并使用分层的K均值算法对视觉特征进行标记;

VideoBERT模型应用:

  • 预测下一个视觉标记;
  • 由文本生成视频;
  • 生成视频字幕;
BART模型

基于Transformer架构,本质是一个降噪自编码器,通过重建受损文本进行训练的;

带有编码器和解码器的Transformer模型,将受损文本送入编码器学习,将学习得到的特征发送给解码器;解码器获得编码器生成的特征,重建原始文本;

  • 双向编码器
  • 自回归解码器(单向的)

BART模型通过最小化重建损失来训练,也就是原始文本和解码器的生成文本之间的交叉熵损失

BART模型与BERT模型不同,在BERT中,只是将被掩盖的标记送入编码器,然后将编码器的结果送入前馈网络层,用前馈网络层来预测被掩盖的标记;而在BART中,将编码器的结果反馈给解码器,由其生成或构建原始句子;

集中破坏文本增噪方法:

  • 标记掩盖:用[MASK]随机替换一些标记
  • 标记删除
  • 标记填充:用一个[MASK]掩盖连续的标记
  • 句子重排:随机打乱橘子顺序
  • 文档论换:随机选择文档中的一个标记作为文档的开始,然后将所选标记之前的所有标记添加到文档的末尾;
# 文本摘要任务应用
from transformers import BartTokenizer, BartForConditionalGenerationmodel = BartForConditionalGeneration.from_pretrained('facebook/bart-large-cnn')
tokenizer = BartTokenizer.from_pretrained('facebook/bart-large-cnn')text = """
...
"""# 对文本进行标记
inputs = tokenizer([text], max_length=1025, return_tensors='pt')# 获取摘要ids(即模型生成的标记ID)
summary_ids = model.generate(inputs['input_ids'], num_beams=4, max_length=100, early_stopping=True)# 对摘要进行解码
summary = ([tokenizer.decode(i, skip_special_tokens=True, clean_up_tokenization_spaces=False) for i in summary_ids])print(summary)

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

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

相关文章

Docker基础操作容器

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(exited)的容器重新启动。 因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器。 新建并启动 所需要的命令主要…

使用tailwindcss来构建以及引入外部组件

使用tailwindcss来构建以及引入外部组件 使用tailwindcss来构建以及引入外部组件 前言构建组件 核心思想可行方案不可行方案 可行方案详解 custom css selector Functions & Directivesadd prefixadd scoped不打包 构建demo链接相关issues 前言 我们在日常的开发中&am…

1、AM64xx的SDK重新编译lib文件

当需要修改AM64XX的SDK提供的源文件时,如果要在自己的工程使用,需要重新编译出lib,下面是编译lib的具体方法: 因为没有ccs编译出lib的工程,所以需要再命令行模式下生成lib文件 1、配置好gmake环境 如果安装了ccs&am…

隔离上网,安全上网

SDC沙盒数据防泄密系统(安全上网,隔离上网) •深信达SDC沙盒数据防泄密系统,是专门针对敏感数据进行防泄密保护的系统,根据隔离上网和安全上网的原则实现数据的代码级保护,不会影响工作效率,不…

SP605官方开发板不能扫到链的问题

很早之前的板子,近些天需要重新搞FPGA,所以又拿出来,应该以前都是在win7下开发,现在都win10了,vivado都不支持sp6,所以先得下载一个14.7版本,但是出现了新的问题,就是不能扫到链。 …

本文整理了Debian 11在国内的几个软件源。

1.使用说明 一般情况下,将/etc/apt/sources.list文件中Debian默认的软件仓库地址和安全更新仓库地址修改为国内的镜像地址即可,比如将deb.debian.org和security.debian.org改为mirrors.xxx.com,并使用https访问,可使用…

sqli-lab靶场通关

文章目录 less-1less-2less-3less-4less-5less-6less-7less-8less-9less-10 less-1 1、提示输入参数id,且值为数字; 2、判断是否存在注入点 id1报错,说明存在 SQL注入漏洞。 3、判断字符型还是数字型 id1 and 11 --id1 and 12 --id1&quo…

智能工业通信解决方案!钡铼BL124实现Modbus转Ethernet/IP互联!

钡铼技术BL124 Modbus转Ethernet/IP协议网关是一款专为工业自动化领域而设计的先进设备。它提供了可靠的通信解决方案,能够将Modbus通信协议与Ethernet/IP通信协议进行高效转换,实现不同类型设备之间的无缝集成和通信。 添加图片注释,不超过 …

【AI】深度学习——前馈神经网络——全连接前馈神经网络

文章目录 1.1 全连接前馈神经网络1.1.1 符号说明超参数参数活性值 1.1.2 信息传播公式通用近似定理 1.1.3 神经网络与机器学习结合二分类问题多分类问题 1.1.4 参数学习矩阵求导链式法则更为高效的参数学习反向传播算法目标计算 ∂ z ( l ) ∂ w i j ( l ) \frac{\partial z^{…

前端预览、下载二进制文件流(png、pdf)

前端请求设置 responseType: “blob” 后台接口返回的文件流如下&#xff1a; 拿到后端返回的文件流后&#xff1a; 预览 <iframe :src"previewUrl" frameborder"0" style"width: 500px; height: 500px;"></iframe>1、预览 v…

理解http中cookie!C/C++实现网络的HTTP cookie

HTTP嗅探&#xff08;HTTP Sniffing&#xff09;是一种网络监控技术&#xff0c;通过截获并分析网络上传输的HTTP数据包来获取敏感信息或进行攻击。其中&#xff0c;嗅探器&#xff08;Sniffer&#xff09;是一种用于嗅探HTTP流量的工具。 在HTTP嗅探中&#xff0c;cookie是一…

【Redis】Redis性能优化:理解与使用Redis Pipeline

原创不易&#xff0c;注重版权。转载请注明原作者和原文链接 文章目录 Pipeline介绍原生批命令(MSET, MGET) VS PipelinePipeline的优缺点一些疑问Pipeline代码实现 当我们谈论Redis数据处理和存储的优化方法时&#xff0c;「 Redis Pipeline」无疑是一个不能忽视的重要技术。…

Transformer预测 | Pytorch实现基于Transformer的时间序列预测(含单步与多步实验)

文章目录 效果一览文章概述模型描述程序设计单步实验多步实验参考资料效果一览 文章概述 Transformer预测 | Pytorch实现基于Transformer的时间序列预测(含单步与多步实验) Transformer-singlestep.py 包含单步预测模型 Transformer-multistep.py 包含多步预测模型 这是单步预…

基于ChatGPT+词向量/词嵌入实现相似商品推荐系统

最近一个项目有个业务场景是相似商品推荐&#xff0c;给一个商品描述(比如 WIENER A/B 7IN 5/LB FZN )&#xff0c;系统给出商品库中最相似的TOP 5种商品&#xff0c;这种单纯的推荐系统用词向量就可以实现&#xff0c;不过&#xff0c;这个项目特点是商品库巨大&#xff0c;有…

Python爬虫(二十二)_selenium案例:模拟登陆豆瓣

本篇博客主要用于介绍如何使用seleniumphantomJS模拟登陆豆瓣&#xff0c;没有考虑验证码的问题&#xff0c;更多内容&#xff0c;请参考&#xff1a;Python学习指南 #-*- coding:utf-8 -*-from selenium import webdriver from selenium.webdriver.common.keys import Keysimp…

材质、纹理、贴图的区别和关联

1、材质、纹理、贴图的概念 材质&#xff08;Material&#xff09;、纹理&#xff08;Texture&#xff09;、贴图&#xff08;Texture Map&#xff09;是计算机图形学中的三个概念&#xff0c;它们之间存在关系但也有一些区别。 材质&#xff08;Material&#xff09;是描述物…

算法进阶——字符串的排列

题目 输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数据范围&#xff1a;n<10 要求&#xff1a;空间复…

设计模式 - 中介者模式

目录 一. 前言 二. 实现 三. 优缺点 一. 前言 中介者模式又叫调停模式&#xff0c;定义一个中介角色来封装一系列对象之间的交互&#xff0c;使原有对象之间的耦合松散&#xff0c;且可以独立地改变它们之间的交互。 中介者模式可以使对象之间的关系数量急剧减少&#xff0…

nginx开启https配置之后网页无法访问问题处理

背景说明 最近新购服务器部署nginx之后按照之前的方式部署前端项目并配置https之后访问页面显示:无法访问.新的服务器ECS系统和之前相同,nginx安装方式也相同,nginx配置方式也是相同.但是访问还是显示无法访问.下面简单记录一下问题处理过程. 处理过程 1.https访问之后无法访问…

php+html+js+ajax实现文件上传

phphtmljsajax实现文件上传 目录 一、表单单文件上传 1、上传页面 2、接受文件上传php 二、表单多文件上传 1、上传页面 2、接受文件上传php 三、表单异步xhr文件上传 1、上传页面 2、接受文件上传php 四、表单异步ajax文件上传 1、上传页面 2、接受文件上传ph…