gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Elasticsearch
    • Kafka
    • Flink
    • 数据仓库
    • 数据挖掘
    • flume
    • Kafka
    • Hive
    • shardingsphere
    • solr
  • 开发博客
    • Android
    • php
    • python
    • 运维
    • 技术架构
    • 数据库
  • 程序员网赚
  • bug清单
  • 量化投资
  • 在线查询工具
    • 去行号
    • 在线时间戳转换工具
    • 免费图片批量修改尺寸在线工具
    • SVG转JPG在线工具

BERT:如何处理长文档

精品微信小程序开发门户,代码全部亲测可用

  • 首页   /  
  • 作者: east
  • ( 页面52 )
深度学习 4月 2,2022

BERT:如何处理长文档

BERT 的问题

BERT,即 Transformers 的双向编码器表示,目前是公众可以使用的最著名的预训练语言模型之一。事实证明,它在包括问答和分类在内的各种任务中非常有用。

但是,BERT 最多只能接受长度为 512 个标记的输入序列。这是一个很大的限制,因为许多常见的文档类型都比 512 个单词长得多。在这一点上,我们将解释和比较一些方法来克服这个限制,并使您更容易使用 BERT 处理更长的输入文档。

为什么 BERT 不能处理长文档?

BERT 继承了转换器的架构,转换器本身使用自注意力、前馈层、残差连接和层规范化作为其基础组件。如果您不熟悉变压器架构,您可以阅读Deep Learning 101: What is a Transformer and Why Should I Care? 在继续读本文之前。

bertarchitecture.png

BERT 和长输入文档的问题源于 BERT 架构的几个领域。

Transformer 本身是自回归的,BERT 的创建者指出,当使用超过 512 个令牌的文档时,性能会显着下降。所以,这个限制是为了防止低质量的输出。
自注意力模型的空间复杂度为 O(n²)。像这样的二次复杂性使得这些模式非常耗费资源进行微调。输入的时间越长,微调模型所需的资源就越多。二次复杂度使大多数用户的成本高得令人望而却步。
鉴于上述两点,BERT 使用基于较短输入序列的位置编码进行了预训练。这意味着该模型不能很好地推广到更长的序列,并且为收益递减而进行微调的费用意味着解决这个问题的方法有限。
但是我的文件很长,那我现在该怎么办?

幸运的是,您可以做一些事情来有效地使用 BERT 处理更长的输入文档。这里有一些经过验证的技术可以尝试。

修整输入序列

这可能是处理 BERT 和长输入文档时最常用的技术。鉴于 BERT 对多达 512 个令牌的文档表现良好,只需将较长的文档拆分为 512 个令牌块即可让您将长文档分段传递。

对于较长的连续文档(例如长新闻文章或研究论文),将完整长度的文档切成 512 个字块不会造成任何问题,因为文档本身组织良好并且专注于单个主题。但是,如果您的文本块不太连续(例如聊天机器人脚本或一系列推文),则中间可能有与核心主题无关的块。

平均段输出的投票

另一种常见的技术是将长文档分成相等长度的重叠段,并使用投票机制进行分类。这将缓解诸如对话记录之类的非连续文档所带来的问题。使用来自较大文档的各个块的投票将合并来自整个事物的信息。

这在实践中的工作方式是将文档分成段,并通过 BERT 运行每个段,以获得分类 logits。然后通过组合投票(每段一个),我们可以得到一个平均值,我们将其作为最终分类。

这里的缺点是你不能在任务上微调 BERT,因为损失是不可微的。即使存在重叠,您也会错过每个段之间的一些共享信息。这可能会产生特定于分析管道架构的下游影响。

结论

对长输入文档使用 BERT 取决于您的具体任务。有一些更新的模型——比如 RoBERTa——是为了解决 BERT 的弱点而创建的。我们将在以后的帖子中更多地讨论这些内容。对于需要来自整个文档的信息的复杂任务,或者您使用的是非连续文档,使用像 RoBERTa 这样的 BERT 变体可能是最佳解决方案。

作者 east
深度学习 3月 31,2022

BERT 模型的深度揭秘

2018 年,Google 提出了一种特殊的语言表示模型,称为“BERT”,代表“来自 Transformers 的双向编码器表示”。 以前的语言表示模型(例如 OpenAI GPT)使用单向方法(从左到右)来编码序列。 然而,这种方法是有限的,因为上下文只能从一个方向学习。

例如,考虑到这句话——“ The man was looking at the cloudy sky. The man witnessed a cloudy state of mind for the whole day 。” 在这里,无论考虑上下文或句子中单词的实际含义,之前的模型都会产生相同的单词“cloudy”嵌入。 而对于 BERT 模型,“多云”一词将根据不同的上下文具有不同的嵌入。

该模型在现实生活中的主要应用之一是提高对谷歌搜索引擎的查询理解。 早些时候,搜索引擎是基于关键字的,无法考虑可以提出相同问题的各种格式。 因此,在搜索引擎中使用 BERT 有助于显着改善查询结果。

BERT Example

需要注意的重要一点是,BERT 不是一种新的架构设计,而是一种新的训练策略。 由于 BERT 使用了论文中提出的 Transformer 的编码器部分——Attention Is All You Need,我们将花一些时间首先了解相同的内容,然后再讨论 BERT 不同阶段的详细工作。

变换器 – 编码器

1.1 简单多头注意力机制:

Transformer 中使用的最重要的概念是“注意”机制。 让我们看看下面的图片:

当我们第一次看到图像时,我们的大部分注意力都被绿色人物——自由女神像所吸引。

同样,当提供上下文(查询)时,我们不应该对每个输入给予同等的重视,而应该更多地关注一些重要的输入。

在这里,如果查询是关于建筑物的,那么我们的注意力就会放在背景上。

因此,我们将输入一个称为 Z 的新项,而不是普通的原始输入 x 到一个层,这将是所有单个输入 xi 的加权和。

在数学上它表示为,

其中 ai 是决定注意力的个体权重。

为了更好地理解注意力的概念,让我们引入以下变量——Q、K、V。Q 代表 Query,这是我们试图查看的上下文,Value 表示给定的输入(像素或文本特征), Key 是 Value 的编码表示。

例如,在上图中,如果:

Query = 绿色

Key=建筑

那么价值将是,

因此,为了形成对输入的注意力,我们需要将查询和键相关联并删除不相关的值。

再次考虑这个例子,

| The man was looking at the cloudy sky 。 (字数 = 8)

由于有 8 个单词,我们将有 8 个查询、8 个键和 8 个值。

Q = 8X512、K^T = 512X8、V = 8X512 和最后 d_k = 512 的维度。512 是作为输入馈送到编码器的固定维度数。

在等式中,Q 和 K 矩阵之间的点积将导致它们之间的相似度同时生成,而不是单独计算每个单词的相似度。 此外,我们在分母中有一个维度数的平方根,以便缩放完整值。 这将有助于确保顺利进行训练。

刚才我们理解的是简单的注意力,现在让我们继续理解
multi-head 注意力是什么意思?

多头注意力是转换器使用的一项功能,它为每个查询生成 h 个注意力,而不是一个注意力。使用 h attention 的主要原因是为特定查询获得 h 个不同的视角。考虑这么多角度将大大提高模型的整体准确性。对于输出,将所有 h 个注意力连接起来,然后输入到点积方程中。

1.2 跳过连接和层规范化:

编码器的另一个主要组成部分是跳过连接和归一化层。

跳过连接基本上是通过跳过中间的一些层将一层连接到另一层的残差块。引入跳跃连接的想法是解决深度神经网络中的退化问题(梯度消失)。跳过连接有助于网络的最佳训练。

层归一化类似于批量归一化,除了在层归一化中,归一化发生在同一层中的特征上。

下图展示了编码器的结构,展示了multi-head 注意力、跳过连接和层归一化的使用。

1.3 前馈网络:

如上图所示,层归一化的输出被馈送到一个全连接层、ReLU 层和另一个全连接层。这些操作分别应用于每个位置,因为每个输出都依赖于与其相关的相应注意力。

通过以上部分,您对编码器中存在的不同模块及其使用有了基本的了解。

在下一节中,让我们继续了解 BERT 的强大功能。

BERT 模型:

使用 BERT 的动机是解决这两个主要挑战:

对所有单词的深刻上下文理解。与转换器不同,它尝试实现双向词嵌入策略。
一个可以服务于多种目的的单一模型,因为从头开始为每个单独的任务进行训练,在计算上既昂贵又耗时。

理解输入:

输入包括分成标记的句子——T1、T2、… Tn。一开始,总是有一个 [CLS] 令牌。如果输入中有多个序列,则它们被 [SEP] 标记分割。输出令牌的数量与输入令牌的数量相同。请看下图以更好地理解。

输入嵌入包括三种——令牌嵌入、段嵌入和位置嵌入。

1、令牌嵌入——为了计算嵌入,输入令牌使用固有词汇表(大小 – 30,000 个令牌)转换为单词片段。 例如,“bullying”这个词将被拆分为“bully”和“ing”。
2、Segment Embeddings——这些嵌入确保了每个标记的序列标记,以确定标记属于哪个序列。 为了做到这一点,嵌入值添加了一个常量偏移量,其值决定了它所属的序列。
3、 位置嵌入——这有助于跟踪令牌的位置。

最终的嵌入将是 Token 嵌入、Segment 嵌入和位置嵌入的总和。

预训练和微调任务:

BERT 模型包括两个阶段——预训练和微调。

在预训练阶段,该模型使用两个 NLP 任务进行训练——(i) 掩蔽语言模型 (MLM) 和 (ii) 下一句预测 (NSP)。使用 Masked LM,解码器生成输入的向量表示,其中包含一些掩码单词。

例如,如果输入句子是——“ my cat is furry ”,那么掩码向量看起来像——“ my cat is  [MASK]”。

在这种策略中,80% 的时间单词会被屏蔽。 10% 的情况下,它会被一个随机词替换——“ my cat is human ”。在剩下的 10% 的时间里,这个词保持不变——“ my cat is furry ”。这种学习方法将使模型变得健壮,因为它将提高预测准确性。需要注意的一点是,模型不会被评估预测整个序列,而只会评估缺失的单词。

第二个 NLP 任务是 Next Sentence Prediction (NSP)。输入将包含两个句子——A 和 B。这个想法是预测第二个句子是否是第一个句子的后续。这样,模型将能够学习两个句子之间的关系。模型有 50% 的时间是连续的句子,其余 50% 的序列是随机设置的。查看下图以获取 NSP 任务的示例。

总而言之,这两个训练任务能够丰富学习序列的上下文信息和语义。

BERT 模型可以针对许多不同的任务进行微调——自然语言推理 (NLI)、问答、情感分析、文本分类等。在微调的同时,我们保持完整的架构相同,除了最后一层将在自定义数据上训练模型。添加一个浅层分类器或解码器可以完成这项工作。

预训练模型:

BERT 论文提出了以下预训练模型:-

BERT-Base, Uncased:12 层,768 隐藏,12 注意力头,110M 参数
BERT-Large, Uncased:24 层,1024 隐藏,16 注意力头,340M 参数

BERT-Base,Cased:12 层,768 隐藏,12 注意力头,110M 参数
BERT-Large,Cased:24 层,1024 隐藏,16 注意力头,340M 参数

代码实现:

现在,让我们使用 BERT 实现一个多标签文本分类模型。

多标签文本分类概述

那么,什么是多标签文本分类?它基本上是将文本分类为它所属的一个或多个类别。例如,考虑电影《神奇女侠》的影评——“在一个痴迷于有缺陷的英雄、不受欢迎的英雄和反英雄的娱乐环境中,戴安娜毫无歉意地是一个真正的英雄”。从这段文字可以预测,这部电影属于“奇幻”、“冒险”和“科幻”的类型。

因此,为了解决多标签分类任务,第一步是创建由清洁文本和单热编码目标向量组成的数据。例如,在上述情况下,目标向量可能看起来像 – [0,0,1,0,1,0,1,0,0…] 其中 1 代表类别 – 幻想、冒险和科幻,而 0代表剩余的缺席类别。第二步是创建词嵌入,最后在这些嵌入上训练模型。

使用 BERT 进行多标签文本分类:

第 1 步:安装:

使用以下命令在 google colab 上安装 simpletransformers 库:

!pip install simpletransformers

Simpletransformers 是一个建立在著名的变形金刚库 – Hugging Face 之上的库。这使得只使用几行代码就可以进行预处理、训练和评估。

第 2 步:加载和预处理数据:

我们将致力于有毒评论分类的 kaggle 挑战,其中文本需要分为六个类别——有毒、严重有毒、淫秽、威胁、侮辱和身份仇恨。数据集可以从这里下载。将下载的文件存储在您当前的工作目录中。我们将使用 train.csv 文件来创建训练和评估数据。

# Import statements

import pandas as pd
from sklearn.model_selection import train_test_split
from simpletransformers.classification import MultiLabelClassificationModel

# ’dir’ would be your current working directory
df = pd.read_csv('dir/train.csv') 
# taking nearly 15,000 samples out of nearly 1,50,000 samples
df= df.sample(frac=0.1) 

# Combining all the tags into a single list
df['labels'] = df[df.columns[2:]].values.tolist() 

# Removing '\n' from the text
df['text'] = df['comment_text'].apply(lambda x: x.replace('\n', ' ')) 

# Creating new dataframe consisting of just text and their labels
new_df = df[['text', 'labels']].copy() 

# Splitting the data into training and testing sets, 80% of data is kept for training and 20% for evaluation
train, eval = train_test_split(new_df, test_size=0.2)

第 3 步:加载预训练的 BERT 模型:

在这里,我们将使用 roberta 模型的预训练“roberta-base”版本。 RoBERTa 代表 Robustly Optimized BERT Pretraining Approach。 由于原始 BERT 模型的以下变化,RoBERTa 提高了性能——更长的训练、使用更多数据以及更长的训练序列、动态掩码模式以及从预训练任务中删除下一句预测目标。

'''
Description of params:
model_type: type of the model from the following {'bert', 'xlnet', 'xlm', 'roberta', 'distilbert'}

model_name: choose from a list of current pretrained models {roberta-base, roberta-large} roberta-base consists of 12-layer, 768-hidden, 12-heads, 125M parameters.
num_labels: number of labels(categories) in target values

args: hyperparameters for training. max_seq_length truncates the input text to 512. 512 because that is the standard size accepted as input by the model.
'''
model = MultiLabelClassificationModel('roberta', 'roberta-base', num_labels=6, args={'train_batch_size':2, 'gradient_accumulation_steps':16, 'learning_rate': 3e-5, 'num_train_epochs': 2, 'max_seq_length': 512})

步骤4:训练模型

# train_model is an inbuilt function which directly trains the data with the specified parameter args. Output_dir is the location for the model weights to be stored in your directory.

model.train_model(train, multi_label=True, output_dir='/dir/Output')

步骤5:评估模型

'''
Description of params: 

result: Label Ranking Average Precision (LRAP) is reported in the form of a dictionary 
model_outputs: Returns model predictions in the form of probabilities for each sample in the evaluation set
wrong_predictions: Returns a list for each incorrect prediction

'''

# eval_model is an inbuilt method which performs evaluation on the eval dataframe
result, model_outputs, wrong_predictions = model.eval_model(eval) 

# Converting probabilistic scores to binary - 0/1 values using 0.5 as threshold
for i in range(len(model_outputs)):
  for j in range(6):
    if model_outputs[i][j]<0.5:
      model_outputs[i][j] = 0
    else:
      model_outputs[i][j] = 1

第 6 步:预测:

test.csv 文件也将从此处下载到数据集中。 它只包含文本,不包含标签。

# Reading the test data for prediction
test_data = pd.read_csv('dir/test.csv')

# Replacing '\n' values in the text
predict_data = test_data.comment_text.apply(lambda x: x.replace('\n', ' '))

# Convert the dataframe to a list as the predict function accepts a list
predict_data = predict_data.tolist()

# Makes predictions for the test data
predictions, outputs = model.predict(predict_data) 

结论:

在本文中,我们深入探讨了 BERT 模型。 我们还对变压器使用的编码器模块有了基本的了解。 BERT 模型由于其双向编码的特性而被证明比其他以前的模型具有优势。 该模型经过预训练,可以针对自然语言推理 (NLI)、情感分析、多类/多标签文本分类等多项任务进行微调。 该模型通过大幅减少针对不同目的的不同模型从头开始训练的需求,无疑提高了多个领域的准确性。

作者 east
深度学习 3月 31,2022

为什么google应用bert模型到搜索及如何SEO

随着新BERT算法的实现,谷歌已经在谷歌搜索中出现的结果进行了另一种重要的排序调整。了解BERT算法更新对搜索结果造成的哪些更改,还有哪些方面没有造成改变, 对于SEO维护搜索中现有的结果至关重要,以及在搜索中建立新的排名。

谷歌不断调整其超级秘密搜索算法。一般来说,这些调整很小,不足导致大量搜索结果突然变化。 但BERT更新并非如此。BERT代表了Google对搜索结果内容策略有了地震般转变,肯定会影响每个公司的内容展示结果和SEO的方法。

随着BERT算法的引入,许多公司将看到搜索结果的突然变化,无论好坏。并考虑到许多公司今天接近内容营销的方式,“更糟糕的”案例可能更有可能。

什么是bert算法?

那么,BERT是什么,为什么现在改变?使用Google的Pandu Nayak,Google Clower和副总裁最近的博客文章的参考,最好回答这个问题,搜索谷歌搜索。来自他的博客文章:“随着我们研究团队的最新进展,在语言理解的科学中 – 通过机器学习使得可以实现重大改进,我们如何理解查询,代表过去五年中最大的飞跃和搜索历史上的最大跳跃之一。“

机器学习,解释模式和语音过程的数学方式和语言语言,正在推进搜索科学。该进步的一个结果是BERT,它代表来自变压器的双向编码器表示。根据Nayak的说法,“[BERT]使任何人能够培养自己的最先进的问题回答系统。”

在这篇文章的剩余部分中,我将更多地挖掘这个主题以及伯特将如何影响您的SEO和内容开发方法。以及这种变化如何改变您的短期和长期可见性和在搜索中的存在。

什么是机器学习?

根据Google的说法,Transformers (the “T” in BERT)是根据句子中的所有其他单词,而不是一个逐个地处理词语的模型。“这意味着BERT机器学习模型现在将通过检查之前和之后的单词来解析查询中的句子或短语的完整上下文。根据Google,这种上下文分析,而不是与主题的特定关键字关联,是了解搜索查询背后的意图的卓越过程。结果是Google的SEO更进一步的方法。

特别是关于以较长的对话为中心的查询,在当今由基于语音的设备驱动的搜索设备中变得越来越常见,如亚马逊的Alexa或Apple的Siri等,机器学习算法将能够更好地了解理解介词用于限定查询的句子的上下文含义和目的。

换句话说,Google搜索现在将能够更清楚地了解查询中一串单词的上下文。这意味着用户可以越来越多地搜索感觉自然,谷歌将能够更准确地理解和响应搜索查询。

在他的博客帖子中,谷歌的Nayak使用这个例子:“2019 Brazil traveler to USA needs a Visa。” Nayak指出,“to”这个词及其与其余查询的关系对于了解查询的含义至关重要。这是关于一个前往美国的巴西旅行而不是其他意思。它对官方旅行证件相关,而非对信用卡的需求有关。

Nayak指出,过去的谷歌算法的过去版本将无法使用“to”这个词来接受查询上下文的重要性。因此,使用旧算法,Google可能实际上可以返回关于前往巴西的美国公民的结果列表,而不是想要的展示方式。通过BERT,Google现在能够掌握这种级别的细节 – 使用“to”单词作为限定符 – 并返回查询的更相关的结果。

凭借其对上下文细微差别的新方法,BERT算法改变了SEO的策略,以及SEO的日常惯例,减少了关键字和关键字基于短语的SEO的权重值。关键词和短语在对竞争SEO排名的战略方向和理解方面仍然重要,因为它涉及高级内容策略和内容营销。但是,在改善排名方面,SEO的关键字分析方法现在具有较少的价值和影响。

了解这一变化的影响对于寻求前进的成功至关重要。这是因为BERT了解句子级别的搜索查询的上下文,包括Word Order和同义词。在BERT之前,谷歌依靠精确的关键字和关键字短语关联,以确定搜索排名和相关性。

BERT如何改变SEO策略?

要重申一个关键点,BERT将实心SEO策略的主要焦点从关注关键字和关键字短语的关注转移到主题的关键词。更广泛地关注关于搜索查询的主题相关性。

以下是您应该开始做的一些事情 – 或者应该停止执行 – 解决BERT算法的变化。

1、停止使用低质量的外包内容开发资源。现在,使用外包内容,写出的内容具有很少的知识或专业知识现在将损害您的SEO排名。这是因为搜索引擎不是基于关键字来排名,BERT现在考虑专业知识,权威和信任作为其核心资格排名因素。

2、制定主题重点的资源清单。正式确定您的主题重点,或将来将在未来。这就是:为什么:中小企业更有可能在会话语言中使用相关的行业行业行业和相关的同义词和短语。 BERT能够拿起这种级别的上下文协会,因为它与主题专业知识和权威有关。结果随着时间的推移将是更高且更有利的排名。

3、内容的质量与数量相比。在以前很长时间,内容营销人员已经不断通过更新内容来改善排名。内容新鲜度仍然重要,但现在,内容深度和质量问题超过发布一致性和更新。

BERT会改变我的搜索排名吗?

希望您现在有更好的掌握,现在BERT算法对SEO的当前状态和未来以及整体搜索排名的影响。下一个问题显然是“BERT改变了我在搜索中看到的结果?”

没有真正的“是”或“不”的方式来回答这个问题。真实的反应是“取决于”。

如果您只使用基于关键字的SEO,随着BERT算法的引入就更变旧的游戏规则。原本排名不错的公司突然大幅度下降。 (您正在监控您的搜索结果相对竞争对手的排名,不是吗?)

我该怎么SEO?

正如我之前提到的那样,这个问题的答案是“这取决于”。无论您的内容开发计划在哪个阶段,它可能会出现完善的速度。幸运的是,谷歌为我们提供了一些关于如何继续的指导。

让我们圈回电子邮件的E-A-T(专业知识,权威,值得信赖性)Litmus测试,以便在这篇文章中提到的内容。 E-A-T参考谷歌认为对网上合格内容的分类非常重要的三个战略内容柱。

“e”代表专业知识。如果您尚未使用中小企业作为您的内容开发的基石,则需要首先开始这样做。例如,在基于技术的公司中,中小企业可以是开发人员,程序员或产品经理。 “但我公司中的这些类型的人不是作家!”你可能会说。或者,“我们的开发人员没有时间编写2000字的博客帖子关于系统工程机器专有代码的重要性。”

请记住,搜索中的新标准并不是您内容的单词的方式,但它对有多权威和相关性。您的中小企业将适合BERT算法,以便完美地符合Google对内容的基线测试。

所以不是要求这些人自己写作,采访他们并记录谈话。如果他们是大多数中小企业,他们可以轻松地在与您的15分钟对话中生成2,000字的会话风格的博客文章。通过这种方法(关于主题的录制对话),您可以获得相关行业的行业术语,细微差别和上下文情绪,这将符合这个新的搜索时代内容。拍摄专家的访谈并转化为博客文章或新闻稿等。

只需这一步,您不仅处理了专业知识因素,而且通过采访贵公司或行业的权威者,您也在变得更有行业权威,以及符合E-A-T 内容策略。

通过在BERT算法的新时代应用E-A-T方法,您将在途中提高搜索排名,并在您网站的流量增加,而不是您思考的时间。

作者 east
Hive 3月 31,2022

Presto vs Hive:综合比较

Presto 和 Hive 之间的 5 个最大区别是:

1、Hive 允许用户插入自定义代码,而 Preso 不允许。
2、Presto 旨在符合 ANSI SQL,而 Hive 使用 HiveQL。
3、Presto 可以处理有限数量的数据,因此在生成大型报告时最好使用 Hive。
4、 Hive 通常可以容忍失败,但 Presto 不能。
5、 Hive 使用 map-reduce 架构并将数据写入磁盘,而 Presto 使用 HDFS 架构而不使用 map-reduce。

Presto 最初是一个 Facebook 项目,让工程师可以针对公司庞大的 (300PB) 数据仓库运行交互式分析查询。 Facebook 发布了 Presto 作为 Apache Software 下的开源工具。 在创建 Presto 之前,Facebook 以类似的方式使用 Hive。 在放弃它转而支持 Presto 之后,Hive 也成为了一个开源的 Apache 工具数据仓库工具。 如今,使用大数据的公司通常对 Presto 和 Hive 有强烈的偏好。 仔细比较表明,这些选项有一些相似之处和不同之处,但都没有管理和转换大数据所需的综合功能。

Presto 与 Hive:ANSI SQL 和 HiveQL
许多数据工程师在第一次尝试 Presto 时注意到的第一件事就是他们可以使用现有的 SQL 知识。 Presto 依靠标准 SQL 来执行查询、检索数据和修改数据库中的数据。只要您了解 SQL,就可以立即开始使用 Presto。许多人认为这是一种优势。

Apache Hive 使用类似于 SQL 的语言,但它有足够的差异,初学者需要重新学习一些查询。 HiveQL 代表 Hive 查询语言,它有一些奇怪的东西可能会让新用户感到困惑。但是,任何熟悉 SQL 的人都应该发现他们可以相对快速地掌握 HiveQL。

Apache 为 HiveQL 维护了一个全面的语言手册,因此您可以在忘记命令时随时查找它们。尽管如此,查找信息会分散注意力并降低效率。

Presto vs Hive:自定义代码
由于 Presto 在标准 SQL 上运行,因此您已经拥有所需的所有命令。一些工程师认为这是一个优势,因为他们可以快速执行数据检索和修改。

然而,无法插入自定义代码可能会给高级大数据用户带来问题。在这种情况下,Hive 提供了优于 Presto 的优势。假设您非常了解该语言,您可以在查询中插入自定义代码。您可能不需要经常这样做,但在需要时它会派上用场。

在花时间在 HiveQL 中编写自定义代码之前,请访问 Hive 插件页面并搜索类似的代码。有人可能已经编写了您的项目所需的代码。如果您找不到您需要的特定代码,您可能会找到一个只需要稍作改动即可执行您的独特命令的插件。

Presto 与 Hive:数据限制
很少有人会否认 Presto 在生成频繁报告时运行良好。不幸的是,Presto 任务可以存储的数据量是最大的。一旦你碰到那堵墙,Presto 的逻辑就会崩溃。如果您生成每小时或每天的报告,您几乎可以肯定依靠 Presto 来完成这项工作。请记住,Facebook 使用 Presto,而且该公司会生成大量数据。不过,你可以达到一个极限。

Hive 似乎没有数据限制,至少不会影响实际场景。这使得 Hive 成为生成每周或每月报告的公司更好的数据查询选项。涉及的数据越多,项目所需的时间就越长。不过,Hive 不会失败。它会一直工作,直到你的命令结束。

Presto vs Hive:HDFS 和将数据写入磁盘
架构在 Presto 和 Hive 之间的差异中起着重要作用。

Hive 和 MapReduce
Hive 使用 MapReduce,这意味着它过滤和排序任务,同时在分布式服务器上管理它们。然而,在 reduce 和 map 阶段之间,Hive 必须将数据写入磁盘。写入磁盘会强制 Hive 在继续执行下一个任务之前等待一小段时间。

MapReduce 在 Hive 中运行良好,因为它可以处理多个服务器上的任务。分配任务会提高速度。尽管如此,数据必须写入磁盘,这会惹恼一些用户。

幸运的是,MapReduce 为 Hive 带来了非凡的灵活性。它可以处理大量的数据格式。 MapReduce 还可以帮助 Hive 即使在遇到数据故障时也能继续工作。它将承认失败并在可能的情况下继续前进。

Presto 和 HDFS
Presto 具有不同的架构,这使得 Give 在某些情况下有用,而在其他情况下则很麻烦。 Presto 支持 Hadoop 分布式文件系统 (HDFS),这是一种非关系源,无需在任务之间将数据写入磁盘。相反,HDFS 架构在整个分布式系统中存储数据。由于它的数据不会被锁定在一个地方,Presto 可以在不停止将数据写入磁盘的情况下运行任务。

显然,HDFS 提供了几个优点。不过,毫不奇怪,您可能会遇到架构方面的挑战。 HDFS 不能像 MapReduce 一样容忍故障。当出现问题时,Presto 往往会迷失方向并关闭。这种情况并不经常发生,但您可能会因失败而损失数小时的工作时间。你可能会发现你可以追溯你的步骤,解决问题,然后从你离开的地方继续。即使使用该解决方案,用户也会浪费宝贵的时间来追踪故障的根源并诊断问题。

Presto vs Hive:结论
许多使用大数据的专业人士更喜欢 Hive 而不是 Presto,因为他们欣赏 Hive 的稳定性和灵活性。当您专业地处理大数据时,您会发现有时您想编写自定义代码以提高项目效率。

仅仅因为有些人更喜欢 Hive,并不一定意味着你应该打折 Presto。按预期使用时效果很好。 Presto 快速处理任务。只是不要要求它一次做太多事情。如果这样做,您将面临失败的风险。

作者 east
私域流量 3月 30,2022

品牌应如何利用TikTok

TikTok风靡全球。凭借其引人入胜的视频、有趣的挑战和娱乐功能,它现在是地球上热门的社交平台。随着越来越多的各个年龄段的人下载该应用程序,品牌和营销人员开始意识到 TikTok 是接触消费者和发展业务的重要工具。

什么是 TikTok?

TikTok 以前称为 Musical.ly,是一款简短的视频共享应用程序,允许用户创建、编辑和共享 15 或 60 秒的视频。 TikTokers 可以制作各种有趣的视频,展示他们对口型、跳舞和执行某些主题标签挑战。除了添加过滤器和特殊效果的选项外,该应用程序还为用户提供了多种声音和歌曲片段供您使用。视频创作者还可以将多个剪辑连接在一起,总录制时间长达 60 秒。然而,在 TikTok 的“为你”部分中,占主导地位的仍然是较短的剪辑,其中 75% 的用户时间都花在了那里。吉米·法伦、贾斯汀·比伯、卡迪·B 和其他许多名人都参与其中,制作了一些真正歇斯底里的片段。

TikTok 的月度新用户同比增长 275%。该应用程序已被下载超过 10 亿次,在全球拥有 8 亿月活跃用户。还应该吸引品牌的是用户平均每天在应用程序上花费 52 分钟。

谁在使用 TikTok?

如果您品牌的目标受众包括 13 到 30 岁之间的任何人,那么 TikTok 就是您需要实施的社交平台。在全球范围内,该应用的大多数月度用户年龄在 16 至 24 岁之间。 Z 世代被称为潮流引领者,他们代表了 60% 的 TikTok 用户。明年,美国将有 7400 万人成为 Z 世代的一部分。尽管 Z 世代代表了很大一部分用户,但年龄人口统计数据继续上升。现在,似乎每个人都在 TikTok!

将 TikTok 纳入您的营销策略

在一个过度饱和的品牌空间中,创造独特、引人入胜并引发参与的内容非常重要。通常,Z 世代对直销广告的反应并不热烈,因此营销传播必须真实且引人入胜。有了 TikTok,没有杂乱的广告意味着品牌有机会提供引人注目的活动。 TikTok 是一个有效的平台,可以在这个年轻、有前途的市场和涌入该平台的千禧一代中吸引新客户并建立社区意识。

品牌可以利用 TikTok 的方式

重要的是要提醒品牌,他们不应该为 Instagram 创建内容,然后将其发布到 TikTok。这不是充分利用社交应用程序的方式。他们应该利用这个平台的力量,创造出能引起 TikTok 观众共鸣的内容。

标签挑战

为 TikTokers 建立知名度和营销的有效方法之一是利用 Hashtag Challenges。品牌要么跳入 TikTok 拥有的挑战,要么创建自己的品牌竞赛,通过标签邀请其他人参与。品牌还可以利用 TikTok 的 Hashtag Challenge Plus 功能,让客户无需离开应用即可购买品牌的产品。平均而言,赞助 Hashtag Challenge 的品牌成本为 100,000 美元以上。

影响者营销

TikTok 创造了一个新的社交影响者群体,他们与品牌合作展示他们的创造力、激情和个性。在相对较短的时间内,这些影响者中的许多人已经建立了数百万的大量追随者。营销人员与这些有影响力的人合作,创造真实的内容,以有趣和有趣的方式突出品牌。目前 TikTok 上的一些顶级影响者包括 Loren Gray、Charli D’Amelio 和 Addison Rae。

广告

与某些社交网站的早期版本不同,TikTok 很容易向广告商张开双臂。该平台提供了一个专门的网站,其中包含案例研究以及大量信息和灵感,供品牌发起广告活动。信息流广告可以在 TikTok 上显示在现有用户视频的底部,也可以作为信息流中的剪辑显示。

品牌收购

品牌收购也可以在 TikTok 上加以利用。利用静止图像、GIF 和视频,赞助内容可以链接到品牌的登录页面或 TikTok Hashtag Challenge。请记住,接管是品类独有的,这意味着每天只有一个品牌可以接管一个品类。接管广告的价格从 20,000 美元到 200,000 美元不等。

品牌过滤器

您可以使用品牌滤镜和镜头有机地吸引观众。只需设计一个封装您的业务的 TikTok 过滤器。您的过滤器应该有趣、轻松、引人入胜且相关。只需在为您的视频选择滤镜时选择一个镜头,即可使用 10 天。

社交商务

TikTok 于 2019 年 11 月开始测试社交商务。此实施允许用户将电子商务网站的链接添加到他们的个人资料中,并提供将观众引导至购物网站的能力。在全球许多市场,TikTok 的社交商务无疑开始对亚马逊等传统电子商务玩家构成挑战。

成功使用 TikTok 的品牌

以下是一些充分利用 TikTok 的创造力发挥优势的品牌的好例子。

Chipotle

毫无疑问,Chipotle 一直在寻找战略性的 TikTok 机会。这家餐厅巨头非常适合创意社交平台。 2019 年,Chipotle 发起了#GuacDance 挑战,鼓励粉丝们展示他们受 Jean 博士的“鳄梨酱之歌”启发的类似鳄梨的舞蹈动作。该活动在六天内产生了 250,000 个视频提交和 4.3 亿个视频启动。它促进了 Chipotle的销售,提供了 800,000 单成交量。此外,他们的#ChipotleLidFlip 活动产生了惊人的 1.04 亿次视频观看。

E.L.F.化妆品

部分原因是它们的低价位,e.l.f.是 Z 世代受欢迎的化妆品品牌之一。2019 年,e.l.f.举办了一个名为#eyeslipsface 的赞助主题标签挑战赛。在这里,人们提交了自己跳舞、噘嘴、眨眼和对口型的剪辑,以配合适时的节拍和声音提示。这一挑战在短短一周内就产生了 16 亿(是的,10 亿)次观看。现在这些是严重的 TikTok 数字!

GUESS

GUESS 通过其成功的#InMyDenim 活动发起了第一个 TikTok 时尚收购活动,该活动要求人们以创造性的有趣方式炫耀他们的牛仔裤。 GUESS 利用影响者发起挑战,包括@ourfire、@madison_willow 等。从 2019 年开始,使用 #InMyDenim 标签的视频的观看次数和数量都达到了 3700 万次。

NBA

为庆祝 2019 年全明星周末,NBA 发起了一项名为#AllStarTalent 的挑战,鼓励球迷展示他们广泛的运动技能。该活动旨在让年轻球迷对观看所有令人难以置信的全明星赛事感到兴奋。并且曾经这样做过!该挑战在周末获得了超过 4200 万的观看次数,推动了该品牌的两倍有机增长。在短短六周内,该标签的视频浏览量就超过了 1.06 亿次。

TikTok引领新时代

在过去的几个月里,TikTok 的人气直线上升!然而,目前只有 4% 的美国社交营销人员正在利用 TikTok 的力量。 Z 世代将已经成为影响力大的一代!这个市场正在寻找真实、有趣和有趣的内容。利用真正了解您的受众心态的社交平台是一项宝贵的资产。 TikTok 让您的品牌以全新且令人兴奋的方式与您的受众建立联系。现在是将 TikTok 纳入您的营销策略的良好时机。

作者 east
大数据开发 3月 30,2022

怎样成为一名国外数据分析工程师

利用数据可以实现很多事情,从个性化营销活动到为自动驾驶汽车提供动力。 数据科学家负责分析数据并将其用于各种目的。 但是,他们需要高质量的数据来完成复杂的任务,例如预测业务趋势。 这就是数据工程师的用武之地。数据工程是收集和验证信息(数据)以便数据科学家可以使用它的科学。

数据工程师平均每年可以赚取 117,000 美元。 有时,他们甚至可以赚取高达 160,000 美元的年收入。 根据 Dice 的说法,企业比以往任何时候都更渴望聘请数据工程师。 2019 年,数据工程是最热门的科技工作,空缺职位数量同比增长 50%。

凭借出色的薪酬水平和高需求,数据工程可以成为一个有利可图的职业选择。

数据工程:职责是什么?

数据工程师设置和维护支持业务信息系统和应用程序的数据基础设施。他们可能会使用小型的东西,例如夫妻企业的关系数据库,或者大型的东西,例如财富 500 强公司的 PB 级数据湖。

作为其职责的一部分,数据工程师设计、构建和安装数据系统。这些系统为机器学习和人工智能分析提供了动力。他们还为大量数据任务开发信息流程。其中包括数据采集、数据转换和数据建模等。

无论是单人秀还是更大的团队,数据工程领域包括以下岗位:

数据架构师:数据架构师为整个组织或其特定部分设计数据管理系统。他们的工作使数据系统能够摄取、集成和管理业务洞察和报告所需的所有数据源。数据架构师的工作可能需要深入了解 SQL、NoSQL 和 XML 以及其他系统和工具。

数据库管理员:数据库管理员帮助设计和维护数据库系统。它们确保数据库系统为组织中的所有用户无缝运行。数据库管理员优化数据库以提高速度。他们还确保更新不会干扰工作流程,并且敏感信息是安全的。

数据工程师:数据工程师了解数据科学中使用的几种编程语言。其中包括 Java、Python 和 R 之类的。他们了解 SQL 和 NoSQL 数据库系统的来龙去脉。他们还了解如何使用分布式系统,例如 Hadoop。拥有如此广泛的知识使他们能够与数据架构师、数据库管理员和数据科学家合作。事实上,有时,他们可以自己扮演所有这些角色。从本质上讲,数据工程师负责为组织构建强大的集成数据基础架构。

数据科学家与数据工程师:有什么区别?

数据科学家使用统计建模和其他工具来分析数据。数据工程师专注于构建所需的基础架构,以生成和准备用于分析的数据

数据科学家与关键决策者密切合作,制定数据战略。数据工程师与数据科学家密切合作,为他们提供高质量的数据

数据科学家负责产生洞察力。数据工程师负责构建和维护向数据科学家提供数据的管道

数据科学家

数据科学家在现代企业中承担着许多职责。例如,帮助 Facebook 向您展示有针对性的广告、教机器人车辆自动驾驶以及帮助 Netflix 推荐完美的电影。他们的工作为公司带来了巨大的竞争优势。例如,由于通过数据分析更好地保留了客户,Netflix 每年可节省 10 亿美元。

数据科学家专注于统计建模和机器学习技术。他们开发图形显示、仪表板和其他方法来与组织中的决策者共享重要的商业智能。然而,每个数据科学家都需要访问高质量的数据,因此需要数据工程师。

数据工程师

数据工程师创建数据管道,将数据从一个系统连接到另一个系统。他们还负责将数据从一种格式转换为另一种格式,以便数据科学家可以从不同系统中提取数据进行分析。尽管数据工程师不像数据科学家那样引人注目,但在数据分析方面,他们同样重要(如果不是更重要的话)。

作为一个简单的类比,如果数据科学家是列车长,那么数据工程师就是将列车从 A 点送到 B 点的铁路网络的建设者。

现在,假设列车长想在没有铁路线的地方运送有效载荷。售票员需要铁路网络建设者将火车连接到新目的地。铁路建设者的建筑师将研究地形。他们将决定是否最好绕过、翻越或隧道穿过途中的任何山脉。他们可能会在河流上建造桥梁。他们将使用所有可用的工具来建造一条将火车连接到新目的地的铁路线。

简而言之,数据科学家通过编写查询与数据进行交互。他们负责为洞察力创建仪表板并制定机器学习策略。他们还直接与决策者合作,了解他们的信息需求并制定满足这些需求的策略。数据工程师构建和维护连接组织数据生态系统的数据基础设施。这些基础设施使数据科学家的工作成为可能。

数据工程师应该具备哪些技能?

1) 数据科学中使用的编程语言

数据工程师至少需要以下编程语言的专业知识:

SQL:设置、查询和管理数据库系统。 SQL 本身并不是一种“数据工程”语言,但数据工程师需要经常使用 SQL 数据库。

Python:创建数据管道、编写 ETL 脚本、建立统计模型和执行分析。与 R 一样,它是数据科学和数据工程的重要语言。这对于 ETL、数据分析和机器学习应用程序尤其重要。

R:分析数据,建立统计模型、仪表板和可视化展示。与 Python 一样,它是数据科学和数据工程的重要语言。它对于数据分析和机器学习应用程序特别有用。

这些脚本语言的知识使数据工程师能够排除故障并改进数据库系统。它还允许他们优化他们正在使用的业务洞察工具和机器学习系统。数据工程师也可以从熟悉 Java、NoSQL、Julia、Scala、MATLAB 和 TensorFlow 中受益。

2)关系和非关系数据库系统

数据工程师需要知道如何使用各种数据平台。 MySQL、PostgreSQL(混合 SQL 和 NoSQL 数据库)和 Microsoft SQL Server 等基于 SQL 的关系数据库系统 (RDBMS) 尤为重要。例如,他们应该对使用 SQL 构建和设置数据库系统感到自在。数据工程师还应该培养使用 NoSQL 数据库(如 MongoDB、Cassandra、Couchbase 等)的技能。

3) ETL 解决方案

数据工程师应该习惯于使用 ETL(提取、转换、加载)系统。 ETL 工具有助于提取、转换和加载数据到数据仓库。他们还应该了解如何使用 ETL 解决方案来协助将数据从一个存储系统或应用程序转换和迁移到另一个存储系统或应用程序。

4) 数据仓库

从各种业务系统中提取信息后,数据工程师可能需要准备信息以将其与数据仓库系统集成。如果他们想查询数据以获得深入的见解,数据集成至关重要。这可能涉及使用 Integrate.io 等 ETL 工具转换数据。

基于云的数据仓库构成了最先进的商业智能数据系统的支柱。数据工程师应该了解如何建立基于云的数据仓库。他们应该擅长将各种数据类型连接到它,并优化这些连接以提高速度和效率。

5) 数据湖

数据仓库只能处理结构化信息,例如关系数据库中的信息。关系数据库系统将数据存储在明确标识的列和行中。同时,数据湖可以处理任何类型的数据。这包括非结构化信息,例如流数据。 BI 解决方案可以连接到数据湖以获取有价值的见解。出于这个原因,许多公司正在将数据湖整合到他们的信息基础设施中。

要将机器学习算法应用于非结构化数据,了解如何集成数据并将其连接到商业智能平台非常重要。

6) 连接器

数据工程师开发连接各种信息系统的基本数据路径。因此,数据工程师应该对数据管道有很好的了解。他们应该知道如何帮助信息网络的不同部分相互通信。例如,他们应该能够使用 REST、SOAP、FTP、HTTP 和 ODBC,并了解尽可能高效地将一个信息系统或应用程序连接到另一个信息系统或应用程序的策略。

7) 数据摄取

数据摄取是指从不同来源提取数据。在提取过程中,数据工程师需要密切关注适用于情况的格式和协议——同时快速无缝地提取数据。

8) 配置商业智能系统

存储数据后,数据科学家建立信息源之间的重要联系。这些来源可以是数据仓库、数据集市、数据湖和应用程序。建立数据源之间的联系可能涉及将公司的数据暴露给用于商业智能的高级机器学习算法。数据工程师必须了解此过程如何为数据科学家的工作提供支持。

9) 构建仪表板以显示洞察和分析

许多商业智能和机器学习平台允许用户开发漂亮的交互式仪表板。这些仪表板展示了查询、人工智能预测等的结果。创建仪表板通常是数据科学家的责任。但是,数据工程师可以在此过程中协助数据科学家。许多 BI 平台和 RDBMS 解决方案允许用户通过拖放界面创建仪表板。不过,SQL、R 和 Python 的知识可以派上用场。它允许数据工程师协助数据科学家设置满足其需求的仪表板。

10) 机器学习

机器学习主要是数据科学家的领域。然而,由于数据工程师是构建支持机器学习系统的数据基础设施的人,因此他们对统计和数据建模感到满意是很重要的。此外,并非所有组织都会有数据科学家。因此,了解如何设置 BI 仪表板、部署机器学习算法以及独立提取深刻见解是很好的。

11) UNIX、Solaris 和 Linux 系统

未来的机器学习系统很可能是基于 UNIX 的。这是由于对硬件 root 访问的要求以及对 Windows 和 Mac OS 不提供的附加功能的需求。因此,如果数据工程师还没有这样做的话,他们现在会想要熟悉这些操作系统。

我如何学习成为一名数据工程师?

成为一名数据工程师没有明确的道路。尽管大多数数据工程师通过在工作中发展他们的技能来学习,但您可以通过自学、大学教育和基于项目的学习获得许多所需的技能。

无论您是在大学学习还是自己学习成为一名数据工程师,都有很多方法可以实现您的目标。

让我们来看看人们培养数据工程技能的四种方式:

1) 大学学位

成为数据工程师不需要大学教育。不过,获得正确的学位会有所帮助。对于数据工程师来说,工程、计算机科学、物理学或应用数学的学士学位就足够了。但是,您可能想攻读计算机工程或计算机科学的硕士学位。它将帮助您与其他求职者竞争——即使您之前没有数据工程师的工作经验。

2) 免费且廉价的在线课程

一些最好的数据工程师是通过免费且廉价的在线学习计划自学的。信不信由你,您可以通过在 YouTube 上观看视频来了解您需要了解的大部分内容。本文重点介绍了几个优秀的 YouTube 视频,这些视频有助于为成为数据工程师奠定基础。

以下是一些学习数据工程基础知识的免费在线课程:

数据工程初学者指南(第 1 部分)、(第 2 部分)、(第 3 部分):Medium 上的这些文章将帮助您了解数据工程和数据科学的基础知识。它们还将帮助您了解数据建模、数据分区以及提取、转换和加载 (ETL) 数据的策略。如果您想比我们在本文中的时间更深入,那么本指南是最好的起点。

Udacity 的数据工程纳米学位:Udacity 是一家围绕数学和技术提供高质量、免费的在线教育的公司。他们有一整条专门用于教授数据工程的课程。

随着您对学习的深入了解,您将需要掌握各种编码语言、操作系统和信息系统。以下是学习以下技能的免费资源列表:

如何使用 Linux,CS40​​1

如何使用 Python、SQL 和 NoSQL 进行编码

如何使用 Hadoop、MapReduce、Apache Spark 和机器学习

3) 基于项目的学习

找到完成在线数据工程课程的动机可能很困难。许多想成为数据科学家的人还没来得及干就辞职了。如果您遇到这种情况,请考虑基于项目的学习方法。

选择一个你觉得有趣的项目。学习完成项目所需的技能。基于项目的学习可以成为学习数据工程的更有趣和实用的方式。

要为基于项目的学习方法添加更多动力,请考虑写下您的工作和研究。打开一个 Medium 帐户并花一些时间创建一些关于数据工程主题的“操作指南”文章。您还可以将您的个人项目发布到 Github,并为 Github 上的开放项目做出贡献。这些行动 这样做将提高您对潜在雇主的数据工程街头信誉。

4) 专业认证

有许多数据科学和数据工程的专业认证课程。以下是数据工程中最受欢迎的证书课程列表:

供应商特定认证:Oracle、Microsoft、IBM、Cloudera 和许多其他数据科学技术公司为其产品提供有价值的认证培训。

认证数据管理专业人员 (CDMP):国际数据管理协会 (DAMA) 开发了 CDMP 计划作为一般数据库专业人员的证书。

Cloudera Certified Professional (CCP) 数据工程师:Cloudera CCP 称号是针对专业数据工程师的认证。它涵盖了数据转换、暂存和存储信息、数据摄取等主题。

谷歌云认证专业数据工程师:申请人成功通过两个小时的考试后,即可获得谷歌云数据工程师认证。

但是,这些课程可能没有您想象的那么有价值。数据工程是你边做边学的东西。雇用数据工程师的公司知道这一点。

如果您的雇主赞助您获得其中一项认证,那就太好了。但是,如果您是自学,请记住,边做边学比证书更有价值。

作者 east
php 3月 29,2022

使用PHP和Ajax进行交互

在PHP开发时,经常需要和前端进行交互。为了更好的用户体验,在不少场景需要和Ajax进行交互。

Ajax是一种在无须重新加载整个网页的情况下能够更新部分网页的技术。Ajax通过在后台与服务器进行少量数据交换可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下对网页的某部分进行更新。现代浏览器都内置了可以创建Ajax的对象。

XMLHttpRequest(Internet Explorer(IE 5和IE 6)使用ActiveX对象),这样使得我们可以很方便地创建一个Ajax对象,通过浏览器发起请求来与服务端交互。你可以使用new XMLHttpRequest()创建一个对象,如果是老版本的InternetExplorer(IE 5和IE 6),使用ActiveX对象(new ActiveXObject)即可。

可以使用new XMLHttpRequest()创建一个对象,如果是老版本的Internet Explorer(IE 5和IE 6),使用ActiveX对象(new ActiveXObject)即可。

创建完毕,可使用XMLHttpRequest对象的open()和send()方法向服务器发送请求。示例如下:

open()函数的标准语法是open(method, url, async),其规定了请求的类型method(GET或POST方法)、URL和是否异步处理(true异步,false同步)。send()包含一个参数,仅用于使用POST方法向服务端发送数据。使用POST可向服务器发送较大量的数据,并且POST方式比GET更稳定可靠,但GET方式比POST简单快捷。开发者可根据使用场景选择请求类型。Ajax指的是异步JavaScript和XML(Asynchronous JavaScriptand XML)。

XMLHttpRequest对象如果要用于Ajax,那么其open()方法的async参数就必须设置为true。对于Web开发人员来说,发送异步请求是一个巨大的进步。很多在服务器执行的任务都相当费时。Ajax出现之前,这可能会引起应用程序挂起或停止。通过Ajax、JavaScript无须等待服务器的响应,而是等待服务器响应时执行其他脚本,当响应就绪后对响应再进行处理。当使用async=true后,可以规定在响应结束后执行onreadystatechange事件中的函数。responseText存储从服务端取到的数据,如下面的例子所示:

<! DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function loadXMLDoc()
{
	var xmlhttp;
	if(window.XMLHttpRequest)
	{
		//IE 7+、Firefox、Chrome、Opera,Safari浏览器执行代码
		xmlhttp = new XMLHttpRequest();
	}
	else
	{
		//IE 6、IE 5浏览器执行代码
		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	xmlhttp.onreadystatechange=function()
	{
		if(xmlhttp.readyState == 4 && xml.status == 200)
		{
			document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
		}
	}
	xmlhttp.open("GET","hello.txt",true);
	xmlhttp.send();
}
</script>
</head>
<body>
<div id="myDiv"><h2>使用AJAX修改该文本内容</h2></div>
<button type="button" onclick="loadXMLDoc()">修改内容</button>
</body>
</html>

当单击按钮修改内容时便会通过Ajax发起请求取到hello.txt里的内容在页面显示。当请求被发送到服务器时,我们需要执行一些基于响应的任务。每当readyState改变时就会触发onreadystatechange事件,用户可自定义这个事件的回调函数。readyState存有XMLHttpRequest从0到4发生变化的状态。0表示请求未初始化,1表示服务器连接已经建立,2表示请求已经接收,3代表请求正在处理中,4表示请求已完成。status表示响应完成(readState为4)时此次响应的结果状态,200表示请求成功,404表示请求失败。


Ajax与服务端交互 :

在实际项目中使用Ajax与服务端交互,首先要约定传输数据使用的格式和规范,其中JSON数据格式是使用最为广泛的传输类型。一般的传输数据规范至少包含3个字段,即消息状态码(一般设置字段为status或code)、提示信息(msg)、消息体(data),当然字段的含义可由开发者根据需要自行设定。

<! DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function loadXMLDoc()
{
	var xmlhttp;
	if(window.XMLHttpRequest)
	{
		//IE 7+、Firefox、Chrome、Opera,Safari浏览器执行代码
		xmlhttp = new XMLHttpRequest();
	}
	else
	{
		//IE 6、IE 5浏览器执行代码
		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	xmlhttp.onreadystatechange=function()
	{
		if(xmlhttp.readyState == 4 )
		{
		  var data = eval('('+xmlhttp.responseText + ')');		
		}
		if(xmlhttp.status==200)
		{
			if(data.status == 0)
			{
				document.getElementById("name").value = data['data'].name;
				document.getElementById("age").value = data['data'].age;
				document.getElementById("company").value = data['data'].agecompany;
			}else{
			 alert(data.msg);
			}
		 }else if(xmlhttp.status==404){
		    alert('服务器上未找到该文件');
		 }
		}
	}
	xmlhttp.open("GET","hello.php",true);
	xmlhttp.send();
}
</script>
</head>
<body>
姓名:<input id='name'><br/>
年龄: <input id='age'><br/>
公司: <input id='company'><br/>
<button type="button" onclick="loadXMLDoc()">查询</button>
</body>
</html>

执行上面的程序将会向info.php发起请求。info.php里的代码如下:

<?php
$success = array('statuss'=>0,'msg'=>'success','data'=>array('name=>'chenxiaolong',
'age'=>'22','company'=>'360 company'));

echo json_encode($success);

?>
作者 east
深度学习 3月 29,2022

什么是Google BERT如何对它进行优化

听说过 Google 的新更新 BERT?如果您对搜索引擎优化 (SEO) 很感兴趣,您可能会拥有。在 SEO 世界中对 Google BERT 的炒作是有道理的,因为 BERT 使搜索更多地关注单词背后的语义或含义,而不是单词本身。

换句话说,搜索意图比以往任何时候都更加重要。谷歌最近更新的 BERT 影响了 SEO 世界,影响了十分之一的搜索查询,谷歌预计随着时间的推移,这将随着更多的语言和地区而增加。由于 BERT 将对搜索产生巨大影响,因此拥有高质量的内容比以往任何时候都更加重要。

为了使您的内容能够为 BERT(和搜索意图)发挥最佳效果,在本文中,我们将介绍 BERT 如何与搜索一起工作,以及如何使用 BERT 为您的网站带来更多流量。想与 SEO 专家交谈?与 WebFX 连接!

什么是 BERT?
BERT 代表来自 Transformers 的双向编码器表示。现在,这是一个包含一些非常技术性的机器学习术语的术语!

这是什么意思:

双向:BERT 同时对两个方向的句子进行编码
编码器表示:BERT 将句子翻译成它可以理解的词义表示
Transformers:允许 BERT 使用相对位置对句子中的每个单词进行编码,因为上下文在很大程度上取决于单词顺序(这是一种比准确记住句子如何输入框架更有效的方法)
如果你要改写它,你可以说 BERT 使用转换器来编码目标单词两侧的单词表示。从根本上说,BERT 是一个全新的、从未实现过的、最先进的自然语言处理 (NLP) 算法框架。这种类型的结构为谷歌的人工智能增加了一层机器学习,旨在更好地理解人类语言。

换句话说,通过这次新的更新,谷歌的人工智能算法可以以比以往更高水平的人类语境理解和常识来阅读句子和查询。虽然它对语言的理解程度不如人类,但它仍然是 NLP 在机器语言理解方面向前迈出的一大步。

BERT 不是什么
Google BERT 不会像之前的算法更新(如 Penguin 或 Panda)那样改变网页的判断方式。它不会将页面评为正面或负面。相反,它改进了对话式搜索查询中的搜索结果,因此结果更好地匹配其背后的意图。

BERT 历史
BERT 的存在时间比几个月前推出的 BIG 更新要长。自 2018 年 10 月发表研究论文 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 以来,自然学习处理 (NLP) 和机器学习 (ML) 社区一直在讨论它。不久之后,Google 发布了一个突破性的开源 NLP 框架,该框架基于 NLP 社区可以用来研究 NLP 并将其整合到他们的项目中的论文。

从那以后,出现了几个基于或合并了 BERT 的新 NLP 框架,包括谷歌和丰田的组合 ALBERT、Facebook 的 RoBERTa、微软的 MT-DNN 和 IBM 的 BERT-mtl。 BERT 在 NLP 社区引起的波澜占互联网上的大部分提及,但 BERT 在 SEO 世界中的提及正在获得牵引力。这是因为 BERT 专注于长尾查询中的语言以及像人类一样阅读网站,以便为搜索查询提供更好的结果。

BERT 是如何工作的?
Google BERT 是一个非常复杂的框架,理解它需要多年研究 NLP 理论和过程。搜索引擎优化世界不需要那么深入,但了解它在做什么以及为什么对于理解它将如何影响搜索结果从现在开始很有用。

因此,以下是 Google BERT 的工作原理:

谷歌 BERT 解释
以下是 BERT 如何从整体上查看句子或搜索查询的上下文:

BERT 接受查询
逐字逐句分解
查看单词之间所有可能的关系
构建一个双向地图,概述两个方向上的单词之间的关系
当单词彼此配对时,分析单词背后的上下文含义。
好的,为了更好地理解这一点,我们将使用以下示例:

每行代表“pandas”的含义如何改变句子中其他单词的含义,反之亦然。 关系是双向的,所以箭头是双向的。 当然,这是 BERT 如何看待上下文的一个非常非常简单的例子。

这个例子只检查我们的目标词“pandas ”和句子中其他有意义的片段之间的关系。 然而,BERT 分析句子中所有单词的上下文关系。 这张图可能更准确一点:

BERT 的类比
BERT 使用 Encoders 和 Decoders 来分析单词之间的关系。想象一下 BERT 如何作为翻译过程发挥作用,提供了一个很好的例子来说明它是如何工作的。您从输入开始,无论您想翻译成另一种语言的任何句子。

假设您想将上面的熊猫句子从英语翻译成韩语。不过,BERT 不懂英语或韩语,所以它使用编码器来翻译“熊猫除了竹子还吃什么?”变成它确实理解的语言。这种语言是它在分析语言的过程中为自己构建的语言(这是编码器表示的来源)。

BERT 根据单词的相对位置和对句子含义的重要性来标记单词。然后它将它们映射到一个抽象向量上,从而创建一种想象的语言。因此,BERT 将我们的英语句子转换为其想象的语言,然后使用解码器将想象的语言转换为韩语。

该过程非常适合翻译,但它也提高了任何基于 BERT 的 NLP 模型正确解析语言歧义的能力,例如:

代词参考
同义词和同音词
或具有多个定义的单词,例如“运行”
BERT 经过预训练
BERT 是经过预训练的,这意味着它有很多学习内容。但是使 BERT 与以前的 NLP 框架不同的一件事是 BERT 是在纯文本上进行预训练的。其他 NLP 框架需要一个由语言学家精心标记句法的单词数据库来理解单词。

语言学家必须将数据库中的每个单词标记为词性。这是一个严格而苛刻的过程,可能会在语言学家之间引发冗长的激烈辩论。词性可能很棘手,尤其是当词性由于句子中的其他单词而发生变化时。

BERT 自己做这件事,而且它是在无人监督的情况下做的,这使它成为世界上第一个这样做的 NLP 框架。它是使用维基百科训练的。那是超过 25 亿字!

BERT 可能并不总是准确的,但它分析的数据库越多,它的准确度就会越高。

BERT 是双向的
BERT 对句子进行双向编码。 简而言之,BERT 在一个句子中取一个目标词,并在任一方向查看围绕它的所有词。 BERT 的深度双向编码器在 NLP 框架中是独一无二的。

早期的 NLP 框架(例如 OpenAI GPT)仅在一个方向上对句子进行编码,在 OpenAI GPT 的情况下是从左到右。 后来的模型(如 ELMo)可以在目标词的左侧和右侧进行训练,但这些模型独立地连接编码。 这会导致目标词的每一侧之间的上下文断开。

另一方面,BERT 识别目标单词两侧所有单词的上下文,并且同时完成所有操作。 这意味着它可以完全看到和理解单词的含义如何影响整个句子的上下文。

单词如何相互关联(意味着它们一起出现的频率)是语言学家所说的搭配。

搭配词是经常一起出现的词——例如,“圣诞节”和“礼物”经常出现在每个词的几个词中。能够识别搭配有助于确定单词的含义。在我们之前的示例图像中,“trunk”可以有多种含义:

  • the main woody stem of a tree
  • the torso of a person or animal
  • a large box for holding travel items
  • the prehensile nose of an elephant
  • the storage compartment of a vehicle.

树的主要木质茎
人或动物的躯干
一个装旅行用品的大盒子
大象的鼻子
车辆的储藏室。
确定这句话中所用单词含义的唯一方法是查看周围的搭配。 “低音炮”通常与“汽车”一起出现,“后备箱”也是如此,因此根据上下文,“车辆储物箱”的定义可能是正确的答案。这正是 BERT 在查看句子时所做的。

它通过使用从预训练中学到的单词搭配来识别句子中每个单词的上下文。如果 BERT 单向阅读句子,则可能会错过识别低音炮和后备箱之间“汽车”的共享搭配。双向和整体查看句子的能力解决了这个问题。

BERT 使用变压器
BERT 的双向编码功能与转换器,这是有道理的。如果您还记得,BERT 中的“T”代表变压器。谷歌认为 BERT 是他们在变压器研究方面取得突破的结果。

谷歌将转换器定义为“处理与句子中所有其他单词相关的单词的模型,而不是按顺序一个接一个地处理。” Transformers 使用 Encoders 和 Decoders 来处理句子中单词之间的关系。 BERT 提取句子的每个单词,并赋予它单词含义的表示。每个单词的含义相互关联的强度由线条的饱和度来表示。

在下图的情况下,在左侧,“它”与“the”和“animal”的联系最紧密,在这种情况下识别“it”指的是什么。在右边,“it”与“street”的联系最为紧密。像这样的代词引用曾经是语言模型难以解决的主要问题之一,但 BERT 可以做到这一点

self attention diagram

来源 如果您是 NLP 爱好者,想知道什么是转换器及其工作原理背后的细节,您可以观看这段基于开创性文章的视频:Attention Is All You Need。

它们是一个很棒的视频和一篇优秀的论文(但老实说,它直接在我脑海中浮现)。对于我们其他麻瓜,BERT 背后的转换器的技术效果转化为更新,谷歌搜索可以更好地理解搜索结果背后的上下文,也就是用户意图。

BERT 使用掩码语言模型 (MLM)
BERT 的训练包括使用 Masked Language Modeling 预测句子中的单词。它的作用是掩盖句子中 15% 的单词,如下所示:

What do [MASK] eat other than bamboo?


然后,BERT 必须预测被掩码的词是什么。这做了两件事:它在单词上下文中训练 BERT,它提供了一种衡量 BERT 学习量的方法。被屏蔽的词阻止 BERT 学习复制和粘贴输入。

其他参数,例如向右移动解码器、下一个句子预测或回答上下文,有时是无法回答的问题也可以这样做。 BERT 提供的输出将表明 BERT 正在学习和实施其关于单词​​上下文的知识。

BERT 有什么影响?
这对搜索意味着什么?像 BERT 那样使用转换器双向映射查询尤为重要。

这意味着算法正在考虑诸如介词之类的单词背后的细微但有意义的细微差别,这些细微差别可能会极大地改变查询背后的意图。以这两个不同的搜索页面结果为例。我们将继续我们早期的熊猫和竹子主题。

关键字是:What do pandas eat other than bamboo

google search what do pandas eat other than bamboo

Panda bamboo

google search panda bamboo

请注意结果页面非常相似?几乎一半的有机结果是相同的,人们也问 (PAA) 部分有一些非常相似的问题。但是,搜索意图非常不同。

“熊猫竹”的范围很广,所以很难确定其意图,但它可能在想熊猫的竹子饮食。搜索页面非常好。另一方面,“熊猫除了竹子还吃什么”的搜索意图非常具体,搜索页面上的结果完全错过了。

唯一接近达到意图的结果可能有两个 PAA 问题:

大熊猫吃什么肉?
只吃竹子的大熊猫如何生存?
可以说是 Quora 的两个问题,其中一个很有趣:

可以训练熊猫吃竹子以外的食物吗?
熊猫吃人吗?
苗条的采摘,确实。在此搜索查询中,“其他”一词在搜索意图的含义中起着重要作用。在 BERT 更新之前,Google 的算法在返回信息时会定期忽略诸如“other than”之类的功能/填充词。

这导致搜索页面无法匹配像这样的搜索意图。由于 BERT 仅影响 10% 的搜索查询,因此在撰写本文时左侧页面并未受到 BERT 的影响也就不足为奇了。 Google 在其 BERT 解释页面上提供的这个示例显示了 BERT 如何影响搜索结果:

can you get medicine for someone pharmacy before and after

精选片段
BERT 将产生的最重要影响之一将是精选片段。精选片段是有机的,并且依赖于机器学习算法,而 BERT 完全符合要求。精选片段结果最常从第一个搜索结果页面中提取,但现在可能会有一些例外。

因为它们是有机的,很多因素都可以使它们发生变化,包括像 BERT 这样的新算法更新。使用 BERT,影响精选片段的算法可以更好地分析搜索查询背后的意图,并更好地将搜索结果与它们匹配。 BERT 也很可能能够获取冗长的结果文本,找到核心概念,并将内容总结为特色片段。

国际搜索
由于语言具有相似的基本语法规则,BERT 可以提高翻译的准确性。 BERT 每次学习翻译一种新语言时,都会获得新的语言技能。这些技能可以转移并帮助 BERT 翻译它从未见过的更高精度的语言。

如何针对 BERT 优化我的网站?
现在我们遇到一个大问题:如何针对 Google BERT 进行优化?简短的回答?

你不能。 BERT 是一个人工智能框架。它利用它获得的每一条新信息进行学习。

它处理信息和做出决策的速度意味着即使是 BERT 的开发人员也无法预测 BERT 将做出的选择。很可能,BERT 甚至不知道它为什么会做出这样的决定。如果它不知道,那么 SEO 就无法直接针对它进行优化。

但是,您可以在搜索页面中进行排名的方法是继续生成符合搜索意图的人性化内容。 BERT 的目的是帮助 Google 了解用户意图,因此针对用户意图进行优化将针对 BERT 进行优化。

所以,做你一直在做的事情。
研究你的目标关键词。
关注用户并生成他们想要看到的内容。
最终,当你写内容时,问问自己:

我的读者能否在我的内容中找到他们正在寻找的内容?

作者 east
大数据开发 3月 28,2022

国外MySQL数据仓库和数据库的8个常用 ETL 工具

在大数据时代,找到合适的 MySQL ETL 工具对于管理和分析数据至关重要。理想情况下,您需要一个能够让您轻松控制数据流、符合安全标准、与流行应用程序轻松集成并帮助团队中的每个成员构建数据管道而无需学习如何编码的解决方案。

有这么多用于 MySQL 数据仓库和数据库的 ETL 工具,您需要一个指南来帮助您选择适合您公司的选项是可以理解的。您探索的 ETL 解决方案越多,您选择的软件就越有可能使您的员工和经理能够从可靠的数据中做出明智、明智的选择。

为了帮助您选择适合您的 ETL 解决方案,这里汇总了一些可用的顶级 ETL 工具。

MySQL 数据仓库的 8个 ETL 工具:

DataExpress

Pentaho Kettle

csv2db

Apatar

Domo

AWS Glue

Benetel

Apache Spark

DataExpress

提供了许多使 MySQL 用户受益的功能。 它符合 HIPAA 和金融行业的安全要求。 DataExpress 还允许您创建数据传输计划。 设置时间表后,它将自动将数据从您的数据库传输到您的分析应用程序。

制作 DataExpress 的公司 DATA443 Risk Mitigation 有几个版本供您考虑。 不幸的是,这些选项迫使您承诺使用非常具体的软件形式。 你没有太多的灵活性。

此外,DATA443 风险缓解侧重于安全性。 这意味着 DataExpress 超出了大多数监管准则。 这也意味着 ETL 不是开发人员的主要关注点。

Pentaho Kettle

Pentaho Data Integration(或 Kettle)具有出色的用户界面,可以让没有经验的用户构建数据管道。您无需了解 SQL 或其他语言即可开始使用。这些特性使其成为商业智能和 MySQL ETL 的不错选择。

另一方面,它的一些最重要的缺陷包括:

限制您的设计的有限模板。

数据库连接超时之前令人沮丧的短暂时间。

无法真正识别问题的难以辨认的错误代码。

此选项的价格点意味着 Pentaho Kettle 可能并不适合所有人。

csv2db

如果您的需求有限,需要将 CSV 文件添加到 MySQL 数据库,那么 csv2db 可以为您工作。该工具只做一件事,但它做得非常好。

用户需要一些编码经验才能开始。 CSV2db 不是销售团队可以使用的解决方案类型。它专为希望以快速、简单的方式管理数据的技术专家而设计。

Apatar

Apatar 在 MySQL ETL 和商业智能数据分析方面相当简单。其为商业用户设计的开源软件提供对数据质量工具、集成工具等的访问。您不需要编码或数据管理经验即可使用该工具。但是,如果您确实知道如何编写脚本,则可以从 Apatar 获得更多的灵活性和自定义。

同样重要的是要注意 Apatar 没有得到很多更新。不要期望它与最新的应用程序集成。

Domo

您可能以前听说过 Domo。选择 Domo 有一些明显的优势。它比大多数 MySQL ETL 工具做得更多。例如,您可以使用它来分析和可视化数据。其他流行的用例包括将 Domo 数据引入 Amazon Redshift 并将 Domo 数据加载到 Google BigQuery。

通过包含数据分析和可视化功能,Domo 将自己定位为用户友好的选项。不幸的是,这正是该软件的不足之处。实际上,Domo 有一个陡峭的学习曲线和一个对新用户没有多大意义的用户界面。虽然它似乎是商业智能的绝佳选择,但它缺乏营销和销售专家做出数据驱动决策所需的直观功能。

AWS Glue

Amazon Web Services 是一项基于云的服务,提供 AWS Glue,这是一种利用 Python 作为其基础语言的实时 ETL 工具。当您想要完全无服务器时,AWS 是理想的选择。然而,这将是有代价的。您将按小时收费,以一秒为增量。

Benetl

Benetl 是一个免费的 MySQL ETL 工具。然而,它仍然是有代价的。您需要在编码和数据库管理方面拥有丰富的经验才能从 Benetl 获得任何东西。除了可以让您编写命令的屏幕之外,它几乎没有用户界面。要将 Benetl 连接到 MySQL,您需要下载核心软件未包含的驱动程序。对于没有计算机科学学位的人来说,即使创建 Benetl 帐户似乎也是不可能的。

Benetl 也只管理 csv、txt 和 xls 文件,这可能会给您和您的团队带来问题。

除非您是数据专家,否则您可能需要重新考虑 Benetl。尽管没有前期成本,但学习曲线非常陡峭,您最终可能会花费大量时间(以及金钱)试图弄清楚它。最好为适合您员工的软件付费。

Apache Spark

Apache Spark 是一个“闪电般快速”的统一分析引擎,能够快速高效地处理大型数据集。以速度着称的 Apache Spark 可以将工作负载的运行速度提高 100 倍。虽然功能强大,但 Apache Spark 不提供自动优化过程。如果自动化对您很重要,这是您需要考虑的事情,因为您需要手动优化代码。

这个开源 ETL 工具也不适合多用户环境,并且不提供自己的文件管理系统。

作者 east
深度学习 3月 27,2022

什么是BERT模型和作用?

Google 最近进行了一项重要的算法更新,称为 Google BERT,以更好地理解搜索并为更自然的语言查询生成结果。算法更新还将为他们的人工智能技术提供自然语言和搜索上下文。每天数十亿次的搜索将有助于增强 Google 的 AI 功能,从而改善搜索结果、提高对语音搜索的理解,并帮助 Google 更好地了解消费者行为。

向 Google BERT 打个招呼!

BERT 是谷歌自 2015 年推出 RankBrain 以来最大的搜索算法。事实上,谷歌表示这次更新代表了“过去五年来最大的飞跃,也是搜索领域最大的飞跃之一。” BERT 通过了解用户在更具会话结构的查询中的意图,使搜索更加集中。

让我们更好地了解 BERT,并了解它如何帮助优化您的搜索。

什么是 BERT?
BERT 是一种人工智能 (AI) 系统,代表 Transformers 的双向编码器表示。这种搜索进步是谷歌对转换器研究的结果,转换器是处理与句子中所有其他单词相关的单词的模型,而不是按顺序一个接一个地处理。简而言之,此更新侧重于短语而不是简单的单词。

在排名结果方面,BERT 将影响十分之一的搜索查询。此算法更新也被应用于帮助为世界各地的人们提供更好的搜索。通过从一种语言中学习,相关结果可以应用于许多其他语言。 Google 正在许多国家/地区使用 BERT 模型来改进片段,支持韩语、印地语和葡萄牙语等 70 多种语言。

BERT+
然而,BERT 不仅仅是一种搜索算法。它也是一个机器学习自然语言处理框架、一个不断发展的计算效率工具,以及一个开源研究项目和学术论文,于 2018 年 10 月首次发表,名称为 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding。

怎么运作
BERT 的美妙之处在于,无论单词的拼写方式或它们在查询中的顺序,它都能计算出您的搜索并显示相关信息。 BERT 能够基于句子中的整个单词集而不是传统的单词序列来训练语言模型,例如从左到右或从左到右和从右到左的组合。谷歌现在可以解决由许多具有多种含义的单词组成的模棱两可的短语。

此外,日常语言中存在细微差别,计算机并不完全理解人类的行为方式。因此,当搜索包含一个短语时,BERT 将解释它并根据句子的创建方式和发音给出结果。这很重要,因为即使是最简单的短语与单数单词相比也可能具有完全不同的含义。例如,在“纽约到洛杉矶”和“四分之一到九点”这样的短语中,“到”这个词有不同的含义,这可能会导致搜索引擎混淆。 BERT 区分这些细微差别以促进更相关的搜索。

RankBrain 仍在努力
RankBrain 是谷歌第一个用于理解查询的人工智能方法。它同时查看搜索和谷歌索引中的网页内容,以更好地理解单词的含义。 BERT 不会取代 RankBrain,它是更好地理解内容、自然语言和查询的扩展。 RankBrain 仍将被使用,但当 Google 认为在 BERT 的帮助下更适合查询时,搜索将使用新模型。似乎这句谚语是真的……两种搜索算法比一种更好!

更智能的搜索结果
作为谷歌最新的算法更新,BERT 通过更好地理解自然语言来影响搜索,尤其是在会话短语中。 BERT 将影响大约 10% 的查询以及自然排名和精选片段。所以这对谷歌……和我们所有人来说都是一件大事。有这么多问题,找到与我们的“正常”短语查询匹配的相关结果肯定会让我们的搜索体验更加轻松。搜索愉快!

作者 east
深度学习 3月 27,2022

深入了解 BERT 模型的代码-分解 Hugging Face Bert 实现

已经有很多关于如何从头开始创建简化的 Bert 模型及其工作原理的教程。 在本文中,我们将做一些稍微不同的事情——我们通过 BERT 的实际 Hugging face 实现分解其所有组件。


介绍
在过去的几年里,Transformer 模型彻底改变了 NLP 领域。 BERT (Bidirectional Encoder Representations from Transformers) 是最成功的 Transformer 之一——由于与 LSTM 的递归结构不同,通过注意力机制和训练时间更好地理解了上下文,它在性能上都优于以前的 SOTA 模型(如 LSTM), BERT 是可并行的。
现在不用再等了,让我们深入研究代码,看看它是如何工作的。 首先我们加载 Bert 模型并输出 BertModel 架构:

# with bertviz package we can output attentions and hidden states 
from bertviz.transformers_neuron_view import BertModel, BertConfig
from transformers import BertTokenizer

max_length = 256
config = BertConfig.from_pretrained("bert-base-cased", output_attentions=True, output_hidden_states=True, return_dict=True)
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
config.max_position_embeddings = max_length

model = BertModel(config)
model = model.eval()

display(model)
# output : 

BertModel(
  (embeddings): BertEmbeddings(
    (word_embeddings): Embedding(30522, 768, padding_idx=0)
    (position_embeddings): Embedding(256, 768)
    (token_type_embeddings): Embedding(2, 768)
    (LayerNorm): BertLayerNorm()
    (dropout): Dropout(p=0.1, inplace=False)
  )
  (encoder): BertEncoder(
    (layer): ModuleList(
      (0): BertLayer(
        (attention): BertAttention(
          (self): BertSelfAttention(
            (query): Linear(in_features=768, out_features=768, bias=True)
            (key): Linear(in_features=768, out_features=768, bias=True)
            (value): Linear(in_features=768, out_features=768, bias=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
          (output): BertSelfOutput(
            (dense): Linear(in_features=768, out_features=768, bias=True)
            (LayerNorm): BertLayerNorm()
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
        (intermediate): BertIntermediate(
          (dense): Linear(in_features=768, out_features=3072, bias=True)
        )
        (output): BertOutput(
          (dense): Linear(in_features=3072, out_features=768, bias=True)
          (LayerNorm): BertLayerNorm()
          (dropout): Dropout(p=0.1, inplace=False)
        )
      )
      (1): BertLayer(
        (attention): BertAttention(
          (self): BertSelfAttention(
            (query): Linear(in_features=768, out_features=768, bias=True)
            (key): Linear(in_features=768, out_features=768, bias=True)
            (value): Linear(in_features=768, out_features=768, bias=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
          (output): BertSelfOutput(
            (dense): Linear(in_features=768, out_features=768, bias=True)
            (LayerNorm): BertLayerNorm()
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
        (intermediate): BertIntermediate(
          (dense): Linear(in_features=768, out_features=3072, bias=True)
        )
        (output): BertOutput(
          (dense): Linear(in_features=3072, out_features=768, bias=True)
          (LayerNorm): BertLayerNorm()
          (dropout): Dropout(p=0.1, inplace=False)
        )
      )
      
      ......

      (11): BertLayer(
        (attention): BertAttention(
          (self): BertSelfAttention(
            (query): Linear(in_features=768, out_features=768, bias=True)
            (key): Linear(in_features=768, out_features=768, bias=True)
            (value): Linear(in_features=768, out_features=768, bias=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
          (output): BertSelfOutput(
            (dense): Linear(in_features=768, out_features=768, bias=True)
            (LayerNorm): BertLayerNorm()
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
        (intermediate): BertIntermediate(
          (dense): Linear(in_features=768, out_features=3072, bias=True)
        )
        (output): BertOutput(
          (dense): Linear(in_features=3072, out_features=768, bias=True)
          (LayerNorm): BertLayerNorm()
          (dropout): Dropout(p=0.1, inplace=False)
        )
      )
    )
  )
  (pooler): BertPooler(
    (dense): Linear(in_features=768, out_features=768, bias=True)
    (activation): Tanh()
  )
)

我们分别分析了 3 个部分:Embeddings、具有 12 个重复 Bert 层的 Encoder 和 Pooler。 最终我们将添加一个分类层。
伯特嵌入:
从原始文本开始,首先要做的是将我们的句子拆分为标记,然后我们可以将其传递给 BertEmbeddings。 我们使用基于 WordPiece 的 BertTokenizer——子词标记化可训练算法,有助于平衡词汇量和词汇量外的单词。 看不见的词被分成子词,这些子词是在分词器的训练阶段派生的(这里有更多详细信息)。 现在让我们从 20newsgroups 数据集中导入几个句子并标记它们

from sklearn.datasets import fetch_20newsgroups
newsgroups_train = fetch_20newsgroups(subset='train')
inputs_tests = tokenizer(newsgroups_train['data'][:3], truncation=True, padding=True, max_length=max_length, return_tensors='pt')

一旦句子被分割成标记,我们就会为每个标记分配一个具有代表性的数字向量,该向量在 n 维空间中表示该标记。每个维度都包含该单词的一些信息,因此如果我们假设特征是 Wealth、Gender、Cuddly,则模型在训练嵌入层之后,将使用以下 3 维向量表示例如单词 king:(0.98, 1, 0.01)和 cat (0.02, 0.5, 1)。然后我们可以使用这些向量来计算单词之间的相似度(使用余弦距离)并做许多其他事情。
注意:实际上,我们无法得出这些特征名称的真正含义,但以这种方式思考它们有助于获得更清晰的画面。
所以 word_embeddings 在这种情况下是一个形状矩阵 (30522, 768),其中第一个维度是词汇维度,而第二个维度是嵌入维度,即我们用来表示一个单词的特征的数量。对于 base-bert,它是 768,对于更大的型号,它会增加。一般来说,嵌入维度越高,我们可以更好地表示某些单词——这在一定程度上是正确的,在某些时候增加维度不会大大提高模型的准确性,而计算复杂度却可以。

model.embeddings.word_embeddings.weight.shape
output: torch.Size([30522, 768])

需要 position_embeddings 是因为,与 LSTM 模型不同,例如 LSTM 模型顺序处理令牌,因此通过构造具有每个令牌的顺序信息,Bert 模型并行处理令牌并合并每个令牌的位置信息,我们需要从 position_embeddings 矩阵添加此信息 . 它的形状是 (256, 768),其中前者表示最大句子长度,而后者是词嵌入的特征维度——因此根据每个标记的位置,我们检索相关向量。 在这种情况下,我们可以看到这个矩阵是学习的,但还有其他实现是使用正弦和余弦构建的。

model.embeddings.position_embeddings.weight.shapeoutput: torch.Size([256, 768])

token_type_embeddings 在这里是“冗余的”,来自 Bert 训练任务,其中评估了两个句子之间的语义相似性——需要这种嵌入来区分第一句和第二句。 我们不需要它,因为我们只有一个用于分类任务的输入句子。
一旦我们为句子中的每个单词提取单词嵌入、位置嵌入和类型嵌入,我们只需将它们相加即可得到完整的句子嵌入。 所以对于第一句话,它将是:

f1 = torch.index_select(model.embeddings.word_embeddings.weight, 0, inputs_tests['input_ids'][0])  # words embeddings
  + torch.index_select(model.embeddings.position_embeddings.weight, 0, torch.tensor(range(inputs_tests['input_ids'][0].size(0))).long()) \ # pos embeddings
 + torch.index_select(model.embeddings.token_type_embeddings.weight, 0, inputs_tests['token_type_ids'][0]) # token embeddings

对于我们的 3 个句子的 mini-batch,我们可以通过以下方式获取它们:

n_batch = 3
shape_embs = (inputs_tests['input_ids'].shape) + (model.embeddings.word_embeddings.weight.shape[1], )
w_embs_batch = torch.index_select(model.embeddings.word_embeddings.weight, 0, inputs_tests['input_ids'].reshape(1,-1).squeeze(0)).reshape(shape_embs)
pos_embs_batch = torch.index_select(model.embeddings.position_embeddings.weight, 0, 
                                    torch.tensor(range(inputs_tests['input_ids'][1].size(0))).repeat(1, n_batch).squeeze(0)).reshape(shape_embs)
type_embs_batch = torch.index_select(model.embeddings.token_type_embeddings.weight, 0, 
                                     inputs_tests['token_type_ids'].reshape(1,-1).squeeze(0)).reshape(shape_embs)
batch_all_embs = w_embs_batch + pos_embs_batch + type_embs_batch
batch_all_embs.shape # (batch_size, n_words, embedding dim)

接下来我们有一个 LayerNorm 步骤,它可以帮助模型更快地训练和更好地泛化。 我们通过令牌的均值嵌入和标准差对每个令牌的嵌入进行标准化,使其具有零均值和单位方差。 然后,我们应用经过训练的权重和偏差向量,以便可以将其转换为具有不同的均值和方差,以便训练期间的模型可以自动适应。 因为我们独立于其他示例计算不同示例的均值和标准差,所以它与批量归一化不同,后者的归一化是跨批次维度的,因此取决于批次中的其他示例。

# single example normalization
ex1 = f1[0, :]
ex1_mean = ex1.mean()
ex1_std = (ex1 - ex1_mean).pow(2).mean()
norm_example = ((ex1- ex1_mean)/torch.sqrt(ex1_std + 1e-12))
norm_example_centered = model.embeddings.LayerNorm.weight * norm_example + model.embeddings.LayerNorm.bias


def layer_norm(x, w, b):
    mean_x = x.mean(-1, keepdim=True)
    std_x = (x - mean_x).pow(2).mean(-1, keepdim=True)
    x_std = (x - mean_x) / torch.sqrt(std_x + 1e-12)
    shifted_x = w * x_std + b
    return shifted_x
  
# batch normalization
norm_embs = layer_norm(batch_all_embs, model.embeddings.LayerNorm.weight, model.embeddings.LayerNorm.bias

让我们最后应用 Dropout,我们用零替换一些具有一定 dropout 概率的值。 Dropout 有助于减少过度拟合,因为我们随机阻止来自某些神经元的信号,因此网络需要找到其他路径来减少损失函数,因此它学会了如何更好地泛化而不是依赖某些路径。 我们还可以将 dropout 视为一种模型集成技术,因为在每一步的训练过程中,我们随机停用某些神经元,最终形成“不同”的网络,最终在评估期间集成这些神经元。
注意:因为我们将模型设置为评估模式,我们将忽略所有的 dropout 层,它们仅在训练期间使用。 为了完整起见,我们仍将其包括在内。

norm_embs_dropout = model.embeddings.dropout(norm_embs)

我们可以检查我们是否获得了与模型相同的结果:

embs_model = model.embeddings(inputs_tests[‘input_ids’], inputs_tests[‘token_type_ids’])
torch.allclose(embs_model, norm_embs, atol=1e-06) # True

编码器
编码器是最神奇的地方。有 12 个 BertLayers,前一个的输出被馈送到下一个。这是使用注意力来创建与上下文相关的原始嵌入的不同表示的地方。在 BertLayer 中,我们首先尝试理解 BertAttention——在导出每个单词的嵌入之后,Bert 使用 3 个矩阵——Key、Query 和 Value,来计算注意力分数,并根据句子中的其他单词导出单词嵌入的新值;通过这种方式,Bert 是上下文感知的,每个单词的嵌入而不是固定的,上下文独立是基于句子中的其他单词推导出来的,并且在为某个单词推导新嵌入时其他单词的重要性由注意力分数表示。为了导出每个单词的查询和键向量,我们需要将其嵌入乘以经过训练的矩阵(查询和键是分开的)。例如,要导出第一句的第一个词的查询向量:

att_head_size = int(model.config.hidden_size/model.config.num_attention_heads)
n_att_heads = model.config.num_attention_heads
norm_embs[0][0, :] @ model.encoder.layer[0].attention.self.query.weight.T[:, :att_head_size] + \
                      model.encoder.layer[0].attention.self.query.bias[:att_head_size]

我们可以注意到,在整个查询和关键矩阵中,我们只选择了前 64 个 (=att_head_size) 列(原因将在稍后说明)——这是转换后单词的新嵌入维度,它小于原始嵌入 维度 768。这样做是为了减少计算负担,但实际上更长的嵌入可能会带来更好的性能。 实际上,这是降低复杂性和提高性能之间的权衡。
现在我们可以推导出整个句子的 Query 和 Key 矩阵:

Q_first_head = norm_embs[0] @ model.encoder.layer[0].attention.self.query.weight.T[:, :att_head_size] + \
               model.encoder.layer[0].attention.self.query.bias[:att_head_size] 
K_first_head = norm_embs[0] @ model.encoder.layer[0].attention.self.key.weight.T[:, :att_head_size] + \
               model.encoder.layer[0].attention.self.key.bias[:att_head_size]

为了计算注意力分数,我们将 Query 矩阵乘以 Key 矩阵,并将其标准化为新嵌入维度的平方根 (=64=att_head_size)。 我们还添加了一个修改后的注意力掩码。 初始注意掩码 (inputs[‘attention_mask’][0]) 是一个 1 和 0 的张量,其中 1 表示该位置有一个标记,0 表示它是一个填充标记。
如果我们从 1 中减去注意力掩码并将其乘以一个高负数,当我们应用 SoftMax 时,我们实际上将那些负值发送到零,然后根据其他值推导出概率。 让我们看下面的例子:
如果我们有一个 3 个标记 + 2 个填充的句子,我们会得到以下注意力掩码:[0,0,0, -10000, -10000]
让我们应用 SoftMax 函数:

torch.nn.functional.softmax(torch.tensor([0,0,0, -10000, -10000]).float())# tensor([0.3333, 0.3333, 0.3333, 0.0000, 0.0000])mod_attention = (1.0 – inputs[‘attention_mask’][[0]]) * -10000.0attention_scores = torch.nn.Softmax(dim=-1)((Q_first_head @ K_first_head.T)/ math.sqrt(att_head_size) + mod_attention)

让我们检查一下我们得到的注意力分数是否与我们从模型中得到的相同。 我们可以使用以下代码从模型中获取注意力分数:

as we defined output_attentions=True, output_hidden_states=True, return_dict=True we will get last_hidden_state, pooler_output, hidden_states for each layer and attentions for each layer
out_view = model(**inputs_tests)

out_view 包含:
last_hidden_state (batch_size, sequence_length, hidden_size) : 最后一个 BertLayer 输出的隐藏状态
pooler_output (batch_size, hidden_size) : Pooler 层的输出
hidden_states (batch_size, sequence_length, hidden_size):模型在每个 BertLayer 输出的隐藏状态加上初始嵌入
注意(batch_size、num_heads、sequence_length、sequence_length):每个 BertLayer 一个。 注意力 SoftMax 后的注意力权重

torch.allclose(attention_scores, out_view[-1][0][‘attn’][0, 0, :, :], atol=1e-06)) # True
print(attention_scores[0, :])
tensor([1.0590e-04, 2.1429e-03, .... , 4.8982e-05], grad_fn=<SliceBackward>)

注意分数矩阵的第一行表示,要为第一个标记创建新嵌入,我们需要注意权重 = 1.0590e-04 的第一个标记(对自身),权重 = 2.1429e-03 的第二个标记 等等。 换句话说,如果我们将这些分数乘以其他标记的向量嵌入,我们会得出第一个标记的新表示,但是,我们将使用下面计算的值矩阵,而不是实际使用嵌入。
值矩阵的推导方式与查询和键矩阵相同:

V_first_head = norm_embs[0] @ model.encoder.layer[0].attention.self.value.weight.T[:, :att_head_size] + \
              model.encoder.layer[0].attention.self.value.bias[:att_head_size]

然后我们将这些值乘以注意力分数以获得新的上下文感知词表示

new_embed_1 = (attention_scores @ V_first_head)

现在您可能想知道,为什么我们要从张量中选择前 64 个 (=att_head_size) 元素。 好吧,我们上面计算的是 Bert 注意力层的一个头,但实际上有 12 个。 这些注意力头中的每一个都会创建不同的单词表示(new_embed_1 矩阵),例如,给定以下句子“ I like to eat pizza in the Italian restaurants ”,在第一个头中,“pizza”一词可能主要关注前一个单词 ,单词本身以及后面的单词和剩余单词的注意力将接近于零。 在下一个头中,它可能会关注所有动词(like 和 eat),并以这种方式捕捉与第一个头不同的关系。
现在,我们可以以矩阵形式将它们一起推导,而不是单独推导每个头部:

Q = norm_embs @ model.encoder.layer[0].attention.self.query.weight.T + model.encoder.layer[0].attention.self.query.bias
K = norm_embs @ model.encoder.layer[0].attention.self.key.weight.T + model.encoder.layer[0].attention.self.key.bias
V = norm_embs @ model.encoder.layer[0].attention.self.value.weight.T + model.encoder.layer[0].attention.self.value.bias
new_x_shape = Q.size()[:-1] + (n_att_heads, att_head_size)
new_x_shape # torch.Size([3, 55, 12, 64])
Q_reshaped = Q.view(*new_x_shape)
K_reshaped = K.view(*new_x_shape)
V_reshaped = V.view(*new_x_shape)
att_scores = (Q_reshaped.permute(0, 2, 1, 3) @ K_reshaped.permute(0, 2, 1, 3).transpose(-1, -2))
att_scores = (att_scores/ math.sqrt(att_head_size)) + extended_attention_mask
attention_probs = torch.nn.Softmax(dim=-1)(att_scores)

第一个例子和第一个 head 的注意力和我们之前推导出的一样:

example = 0
head = 0
torch.allclose(attention_scores, attention_probs[example][head]) # True

我们现在将 12 个头的结果连接起来,并将它们传递给我们已经在嵌入部分中看到的一堆线性层、归一化层和 dropout,以获得第一层的编码器结果。

att_heads = []
for i in range(12):
  att_heads.append(attention_probs[0][i] @ V_reshaped[0, : , i, :])
output_dense = torch.cat(att_heads, 1) @ model.encoder.layer[0].attention.output.dense.weight.T + \
               model.encoder.layer[0].attention.output.dense.bias
output_layernorm = layer_norm(output_dense + norm_embs[0], 
                              model.encoder.layer[0].attention.output.LayerNorm.weight, 
                              model.encoder.layer[0].attention.output.LayerNorm.bias)
interm_dense = torch.nn.functional.gelu(output_layernorm @ model.encoder.layer[0].intermediate.dense.weight.T + \
                                        model.encoder.layer[0].intermediate.dense.bias)
out_dense = interm_dense @ model.encoder.layer[0].output.dense.weight.T + model.encoder.layer[0].output.dense.bias
out_layernorm  = layer_norm(out_dense + output_layernorm, 
                            model.encoder.layer[0].output.LayerNorm.weight, 
                            model.encoder.layer[0].output.LayerNorm.bias)

output_dense 我们只是通过线性层传递连接的注意力结果。然后我们需要进行归一化,但我们可以看到,我们不是立即对 output_dense 进行归一化,而是首先将其与我们的初始嵌入相加——这称为残差连接。当我们增加神经网络的深度时,即堆叠越来越多的层时,我们会遇到梯度消失/爆炸的问题,当梯度消失的情况下,模型无法再学习,因为传播的梯度接近于零初始层停止改变权重并改进。当权重因极端更新而最终爆炸(趋于无穷大)而无法稳定时,梯度爆炸的相反问题。现在,正确初始化权重和归一化有助于解决这个问题,但观察到的是,即使网络变得更加稳定,性能也会随着优化的困难而下降。添加这些残差连接有助于提高性能,即使我们不断增加深度,网络也变得更容易优化。 out_layernorm 中也使用了残差连接,它实际上是第一个 BertLayer 的输出。最后要注意的是,当我们计算 interterm_dense 时,在将 AttentionLayer 的输出传递到线性层之后,会应用非线性 GeLU 激活函数。 GeLU 表示为:

查看图表我们可以看到,如果由公式 max(input, 0) 给出的 ReLU 在正域中是单调的、凸的和线性的,那么 GeLU 在正域中是非单调的、非凸的和非线性的 正域,因此可以逼近更容易复杂的函数。

我们现在已经成功地复制了整个 BertLayer。 该层的输出(与初始嵌入的形状相同)进入下一个 BertLayer,依此类推。 总共有 12 个 BertLayers。 因此,将所有这些放在一起,我们可以从编码器中获得所有 3 个示例的最终结果:

n_batch = 3
tot_n_layers = 12
tot_n_heads = 12
shape_embs = (inputs_tests['input_ids'].shape) + (model.embeddings.word_embeddings.weight.shape[1], )
w_embs_batch = torch.index_select(model.embeddings.word_embeddings.weight, 
                                  0, inputs_tests['input_ids'].reshape(1,-1).squeeze(0)).reshape(shape_embs)
pos_embs_batch = torch.index_select(model.embeddings.position_embeddings.weight, 0, 
                                    torch.tensor(range(inputs_tests['input_ids'][1].size(0))).repeat(1, n_batch).squeeze(0)).reshape(shape_embs)
type_embs_batch = torch.index_select(model.embeddings.token_type_embeddings.weight, 0, 
                                     inputs_tests['token_type_ids'].reshape(1,-1).squeeze(0)).reshape(shape_embs)
batch_all_embs = w_embs_batch + pos_embs_batch + type_embs_batch
normalized_embs = layer_norm(batch_all_embs, model.embeddings.LayerNorm.weight, model.embeddings.LayerNorm.bias)
extended_attention_mask = inputs['attention_mask'].unsqueeze(1).unsqueeze(2)
extended_attention_mask = (1.0 - extended_attention_mask) * -10000.0
for layer_n in range(tot_n_layers):
 if layer_n == 0:
   # compute Q, K and V matrices
   Q = normalized_embs @ model.encoder.layer[layer_n].attention.self.query.weight.T + \ 
                         model.encoder.layer[layer_n].attention.self.query.bias
   K = normalized_embs @ model.encoder.layer[layer_n].attention.self.key.weight.T + \
                         model.encoder.layer[layer_n].attention.self.key.bias
   V = normalized_embs @ model.encoder.layer[layer_n].attention.self.value.weight.T + \
                         model.encoder.layer[layer_n].attention.self.value.bias
   # reshape
   new_x_shape = Q.size()[:-1] + (n_att_heads, att_head_size)
   Q_reshaped = Q.view(*new_x_shape)
   K_reshaped = K.view(*new_x_shape)
   V_reshaped = V.view(*new_x_shape)
   # compute attention probabilities
   att_scores = (Q_reshaped.permute(0, 2, 1, 3) @ K_reshaped.permute(0, 2, 1, 3).transpose(-1, -2))
   att_scores = (att_scores/ math.sqrt(att_head_size)) + extended_attention_mask
   attention_probs = torch.nn.Softmax(dim=-1)(att_scores)
   # concatenate attention heads
   att_heads = []
   for i in range(tot_n_heads):
    att_heads.append(attention_probs[:, i] @ V_reshaped[:, : , i, :])

   output_dense = torch.cat(att_heads, 2) @ model.encoder.layer[layer_n].attention.output.dense.weight.T + \
                                            model.encoder.layer[layer_n].attention.output.dense.bias
   # normalization + residual connection
   output_layernorm = layer_norm(output_dense + normalized_embs, 
                                 model.encoder.layer[layer_n].attention.output.LayerNorm.weight,
                                 model.encoder.layer[layer_n].attention.output.LayerNorm.bias)
   # linear layer + non linear gelu activation
   interm_dense = torch.nn.functional.gelu(output_layernorm @ model.encoder.layer[layer_n].intermediate.dense.weight.T + \
                                           model.encoder.layer[layer_n].intermediate.dense.bias)
   # linear layer
   out_dense = interm_dense @ model.encoder.layer[layer_n].output.dense.weight.T + model.encoder.layer[layer_n].output.dense.bias
   # normalization + residual connection
   out_layernorm = layer_norm(out_dense + output_layernorm, 
                              model.encoder.layer[layer_n].output.LayerNorm.weight, 
                              model.encoder.layer[layer_n].output.LayerNorm.bias)
 else:
   # compute Q, K and V matrices
   Q = out_layernorm @ model.encoder.layer[layer_n].attention.self.query.weight.T + \
                              model.encoder.layer[layer_n].attention.self.query.bias
   K = out_layernorm @ model.encoder.layer[layer_n].attention.self.key.weight.T + \
                              model.encoder.layer[layer_n].attention.self.key.bias
   V = out_layernorm @ model.encoder.layer[layer_n].attention.self.value.weight.T + \
                              model.encoder.layer[layer_n].attention.self.value.bias
   # reshape
   Q_reshaped = Q.view(*new_x_shape)
   K_reshaped = K.view(*new_x_shape)
   V_reshaped = V.view(*new_x_shape)
   # compute attention probabilities
   att_scores = (Q_reshaped.permute(0, 2, 1, 3) @ K_reshaped.permute(0, 2, 1, 3).transpose(-1, -2))
   att_scores = (att_scores/ math.sqrt(att_head_size)) + extended_attention_mask
   attention_probs = torch.nn.Softmax(dim=-1)(att_scores)
   # concatenate attention heads
   att_heads = []
   for i in range(tot_n_heads):
    att_heads.append(attention_probs[:, i] @ V_reshaped[:, : , i, :])

   output_dense = torch.cat(att_heads, 2) @ model.encoder.layer[layer_n].attention.output.dense.weight.T + \
                                            model.encoder.layer[layer_n].attention.output.dense.bias
   # normalization + residual connection
   output_layernorm = layer_norm(output_dense + out_layernorm, 
                                 model.encoder.layer[layer_n].attention.output.LayerNorm.weight, 
                                 model.encoder.layer[layer_n].attention.output.LayerNorm.bias)

   # linear layer + non linear gelu activation
   interm_dense = torch.nn.functional.gelu(output_layernorm @ model.encoder.layer[layer_n].intermediate.dense.weight.T + \
                                                              model.encoder.layer[layer_n].intermediate.dense.bias)
   # linear layer
   out_dense = interm_dense @ model.encoder.layer[layer_n].output.dense.weight.T + model.encoder.layer[layer_n].output.dense.bias
   # normalization + residual connection
   out_layernorm = layer_norm(out_dense + output_layernorm, 
                              model.encoder.layer[layer_n].output.LayerNorm.weight, 
                              model.encoder.layer[layer_n].output.LayerNorm.bias)

注意 out_layernorm – 每层的输出如何被馈送到下一层。
我们可以看到这与 out_view 中的结果相同


torch.allclose(out_view[-2][-1], out_layernorm, atol=1e-05) # True


Pooler
现在我们可以获取最后一个 BertLayer 的第一个令牌输出,即 [CLS],将其通过一个线性层并应用一个 Tanh 激活函数来获得池化输出。使用第一个标记进行分类的原因来自于模型是如何被训练为 Bert state 的作者的:
每个序列的第一个标记始终是一个特殊的分类标记 ([CLS])。与该标记对应的最终隐藏状态用作分类任务的聚合序列表示。


out_pooler = torch.nn.functional.tanh(out_layernorm[:, 0] @ model.pooler.dense.weight.T + model.pooler.dense.bias)


分类器
最后,我们创建一个简单的类,它将是一个简单的线性层,但您可以向它添加一个 dropout 和其他东西。我们在这里假设一个二元分类问题(output_dim=2),但它可以是任何维度的。

from torch import nn
class Classifier(nn.Module):
    
    def __init__(self, output_dim=2):
        super(Classifier, self).__init__()
        self.classifier = nn.Linear(model.config.hidden_size, output_dim, bias=True)
    
    def forward(self, x):
        return self.classifier(x)
classif = Classifier()
classif(out_pooler)
tensor([[-0.2918, -0.5782],
        [ 0.2494, -0.1955],
        [ 0.1814,  0.3971]], grad_fn=<AddmmBackward>)

引用:

 
https://arxiv.org/pdf/1606.08415v3.pdf
https://arxiv.org/pdf/1810.04805.pdf
https://jalammar.github.io/illustrated-transformer/
https://github.com/huggingface/transformers/

作者 east
数据库 3月 26,2022

NoSQL数据库面面观

NoSQL 数据库是否比遵循关系模型的数据库更好,反之亦然?这是一个不容易回答的问题。事实上,它可能根本没有答案。这取决于数据库将存储、组织和操作什么样的数据。一旦知道了这一点,选择就会变得更加清晰。 NoSQL,也被称为“不仅仅是 SQL”,近年来越来越流行。大数据时代已经来临,捕获大量非结构化数据的需求是许多组织非常感兴趣的话题。利用大量数据,将其归结为可理解的模式,并利用这些知识做出合理的业务决策,这是分析的核心。无论规模大小,组织都意识到这是一个如果他们希望成功竞争就不能忽视的领域。然而,处理这些庞大的数据集可能是一项艰巨的挑战,而这正是 NoSQL 最擅长的。 NoSQL 的开发是为了满足数据量和用户量的增长。在过去,几千个并发用户似乎过多。今天,一些在线应用程序可能会在很短的时间内拥有数十万甚至数百万的用户。从购物偏好到制造产出的微小细节,这些海量数据都被捕获、存储和分析。不幸的是,这些活动超出了传统关系数据库的能力。 NoSQL 数据库可以通过提供水平可扩展性、高性能处理和有效处理非结构化数据的能力来应对这种新的“大数据环境”。

NoSQL 的特点

NoSQL 数据库的存储和检索方法与传统的关系数据库管理系统 (RDBMS) 相比存在显着差异。 NoSQL 和关系模型之间最大的区别之一是,与 RDBMS 相比,许多 NoSQL 数据库没有严格的结构。这是有效处理非结构化数据的关键。

可扩展性

在处理大量数据的应用程序中,快速、弹性地扩展系统的需求变得势在必行。与关系型 SQL 相比,NoSQL 在可扩展性方面表现出色。过去,当数据库负载增加并且系统需要扩展时,RDBMS 的主要选择是扩展。这通常需要升级到更大、更昂贵的服务器。今天,NoSQL 允许您向外扩展。这涉及向集群添加额外的服务器,使其能够承担额外的数据库负载。可以使用更便宜的商品服务器,过程几乎是透明的,部署时间最短,如果做得好,应该不会出现应用程序停机。

模式

关系模型使用的刚性模式是由构成数据库的基础表之间的关系和约束定义的。这些是一组非常严格的规则,用于管理传统 RDBMS 的许多操作。然而,NoSQL 数据库在“无模式”模型上运行。它不受关系模型强制执行的严格规则的约束。这使得 NoSQL 数据库更加灵活,可以轻松处理结构化、半结构化和非结构化数据。

成本

平均 RDBMS 的硬件要求可能很昂贵。这种类型的数据库通常需要昂贵的专有服务器才能运行。对于许多公司而言,软件许可费用也可能过高。由于 NoSQL 旨在运行在廉价商品服务器集群上,因此其成本效益方面对组织非常有吸引力。另一个优势是相当多的 NoSQL 风格是开源的,有助于进一步降低成本。最后,许多商业 RDBMS 安装需要训练有素的数据库管理员。这些专业人士并不便宜。 NoSQL 数据库更简单的数据模型大大减少了管理需求。

性能特点和优势

除了 NoSQL 数据库可以快速轻松地捕获和处理大量数据之外,它的操作环境还有其他几个关键的性能优势。 NoSQL 数据库是在分布式架构上实现的。这意味着不存在单点故障。这些高可用性集群经过调整,以便如果集群中的一个节点出现故障,系统中内置了足够的冗余,使其能够连续运行。 NoSQL 数据库运行的分布式架构也使得实现容错和灾难恢复等功能成为可能。上面突出显示的 NoSQL 的特性是使其成为快速有效地处理大数据需求的好选择的原因。这些功能的设计考虑了大数据的三个 V:数量、速度和多样性。这三个词优雅地代表了组织的大量数据、非凡的速度和多样化的数据。

NoSQL 限制

考虑到它的实用性,NoSQL 数据库仍然存在一些不足。在数据冗余和准确性方面,它没有架构这一事实可能会导致问题。但是等一下。我们不是说在处理非结构化数据时需要一个无模式数据库吗?是的,但是在其他情况下,没有架构可能会产生不利影响。由于数据库没有像 RDBMS 那样对数据的收集、组织和存储执行严格的规则,因此它为丢失数据完整性敞开了大门。 NoSQL 供应商声称已经建立了机制来解决这个问题,但这些解决方案本质上是程序化的,而不是内置的。现代 RDBMS 是一个成熟的、经过时间考验的系统,背后有数十年的严格操作使用。 NoSQL 数据库仍然需要在这方面做一些追赶。

NoSQL 与关系型

正如我们所见,在某些情况下 NoSQL 数据库是必不可少的。但是,其他数据需求需要 RDBMS 的成熟度。这并不总是一个明确的情况,许多组织发现他们不能没有两个模型并存。

结论

关系数据库的消亡可能为时过早。 NoSQL 数据库已经在数据库世界中留下了自己的印记。然而,越来越明显的是,大多数组织都离不开这两种模式。例如,列式数据库在查询 TB 级数据时非常快,但即使在查询边缘数据集时,查询也需要几秒钟才能返回。在这种情况下,RDBMS 在速度和效率上是最好的。在处理商业智能分析的聚合数据时,使用 MySQL 或 PostgreSQL 进行交易、电子商务服务的组织也可能需要 NoSQL。 Amazon Redshift、Vertica 和 Hadoop 等解决方案和框架的普及和需求证实了这一点。无论您怎么看,具有 NoSQL 和关系模型的混合数据中心可能会在未来一段时间内出现。

作者 east

上一 1 … 51 52 53 … 93 下一个

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。回复”chatgpt”获取免注册可用chatgpt。回复“大数据”获取多本大数据电子书

标签

AIGC AI创作 bert chatgpt github GPT-3 gpt3 GTP-3 hive mysql O2O tensorflow UI控件 不含后台 交流 共享经济 出行 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 日历 机器学习 深度学习 物流 用户系统 电商 画图 画布(canvas) 社交 签到 联网 读书 资讯 阅读 预订

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • spark内存溢出怎样区分是软件还是代码原因
  • MQTT完全解析和实践
  • 解决运行Selenium报错:self.driver = webdriver.Chrome(service=service) TypeError: __init__() got an unexpected keyword argument ‘service’
  • python 3.6使用mysql-connector-python报错:SyntaxError: future feature annotations is not defined
  • 详解Python当中的pip常用命令
  • AUTOSAR如何在多个供应商交付的配置中避免ARXML不兼容?
  • C++thread pool(线程池)设计应关注哪些扩展性问题?
  • 各类MCAL(Microcontroller Abstraction Layer)如何与AUTOSAR工具链解耦?
  • 如何设计AUTOSAR中的“域控制器”以支持未来扩展?
  • C++ 中避免悬挂引用的企业策略有哪些?

文章归档

  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年1月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年7月
  • 2018年6月

分类目录

  • Android (73)
  • bug清单 (79)
  • C++ (34)
  • Fuchsia (15)
  • php (4)
  • python (45)
  • sklearn (1)
  • 云计算 (20)
  • 人工智能 (61)
    • chatgpt (21)
      • 提示词 (6)
    • Keras (1)
    • Tensorflow (3)
    • 大模型 (1)
    • 智能体 (4)
    • 深度学习 (14)
  • 储能 (44)
  • 前端 (4)
  • 大数据开发 (491)
    • CDH (6)
    • datax (4)
    • doris (31)
    • Elasticsearch (15)
    • Flink (78)
    • flume (7)
    • Hadoop (19)
    • Hbase (23)
    • Hive (41)
    • Impala (2)
    • Java (71)
    • Kafka (10)
    • neo4j (5)
    • shardingsphere (6)
    • solr (5)
    • Spark (100)
    • spring (11)
    • 数据仓库 (9)
    • 数据挖掘 (7)
    • 海豚调度器 (10)
    • 运维 (34)
      • Docker (3)
  • 小游戏代码 (1)
  • 小程序代码 (139)
    • O2O (16)
    • UI控件 (5)
    • 互联网类 (23)
    • 企业类 (6)
    • 地图定位 (9)
    • 多媒体 (6)
    • 工具类 (25)
    • 电商类 (22)
    • 社交 (7)
    • 行业软件 (7)
    • 资讯读书 (11)
  • 嵌入式 (71)
    • autosar (63)
    • RTOS (1)
    • 总线 (1)
  • 开发博客 (16)
    • Harmony (9)
  • 技术架构 (6)
  • 数据库 (32)
    • mongodb (1)
    • mysql (13)
    • pgsql (2)
    • redis (1)
    • tdengine (4)
  • 未分类 (7)
  • 程序员网赚 (20)
    • 广告联盟 (3)
    • 私域流量 (5)
    • 自媒体 (5)
  • 量化投资 (4)
  • 面试 (14)

功能

  • 登录
  • 文章RSS
  • 评论RSS
  • WordPress.org

All Rights Reserved by Gitweixin.本站收集网友上传代码, 如有侵犯版权,请发邮件联系yiyuyos@gmail.com删除.