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

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

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

  • 首页   /  
  • 作者: east
  • ( 页面53 )
深度学习 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
人工智能 3月 25,2022

google BERT开源网站介绍中文翻译

BERT
2020 年 3 月 11 日新:更小的 BERT 模型

这是在 Well-Read Students Learn Better: On the Importance of Pre-training Compact Models 中引用的 24 个较小的 BERT 模型(仅英文,不加大小写,使用 WordPiece 掩码训练)的版本。

我们已经证明,标准 BERT 配方(包括模型架构和训练目标)在各种模型大小上都有效,除了 BERT-Base 和 BERT-Large。较小的 BERT 模型适用于计算资源受限的环境。它们可以以与原始 BERT 模型相同的方式进行微调。然而,它们在知识提炼的背景下最为有效,其中微调标签由更大、更准确的教师生成。

我们的目标是在计算资源较少的机构中进行研究,并鼓励社区寻求创新方向来替代增加模型容量。

您可以从此处下载所有 24 个,也可以从下表中单独下载:

请注意,包含此版本中的 BERT-Base 模型只是为了完整性; 它在与原始模型相同的机制下进行了重新训练。

以下是测试集上对应的 GLUE 分数:

对于每个任务,我们从下面的列表中选择了最好的微调超参数,并训练了 4 个 epoch:

批量大小:8、16、32、64、128
学习率:3e-4、1e-4、5e-5、3e-5
如果您使用这些模型,请引用以下论文:

@article{turc2019,
标题={阅读良好的学生学得更好:关于预训练紧凑模型的重要性},
作者={Turc, Iulia and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina},
journal={arXiv 预印本 arXiv:1908.08962v2 },
年={2019}
}
2019 年 5 月 31 日新:全词掩蔽模型

这是几个新模型的发布,这些模型是改进预处理代码的结果。

在原始的预处理代码中,我们随机选择 WordPiece 标记进行掩码。例如:

输入文本:这个人跳起来,把他的篮子放在 phil ##am ##mon 的头上 原始蒙面输入:[MASK] man [MASK] up , put his [MASK] on phil [MASK] ##mon ‘s头

这项新技术被称为全字掩码。在这种情况下,我们总是同时屏蔽与一个单词对应的所有标记。总体掩蔽率保持不变。

Whole Word Masked Input: man [MASK] up , put his basket on [MASK] [MASK] [MASK]’s head

训练是相同的——我们仍然独立地预测每个掩码的 WordPiece 标记。改进来自这样一个事实,即原始预测任务对于已拆分为多个 WordPieces 的单词来说太“容易”了。

这可以在数据生成期间通过将标志 –do_whole_word_mask=True 传递给 create_pretraining_data.py 来启用。

带有全字掩码的预训练模型链接如下。数据和训练在其他方面是相同的,并且模型具有与原始模型相同的结构和词汇。我们只包括 BERT-Large 模型。使用这些模型时,请在论文中明确说明您使用的是 BERT-Large 的 Whole Word Masking 变体。

  • BERT-Large, Uncased (Whole Word Masking): 24-layer, 1024-hidden, 16-heads, 340M parameters
  • BERT-Large, Cased (Whole Word Masking): 24-layer, 1024-hidden, 16-heads, 340M parameters

2019 年 2 月 7 日新功能:TfHub 模块

BERT 已上传到 TensorFlow Hub。有关如何使用 TF Hub 模块的示例,请参阅 run_classifier_with_tfhub.py,或在 Colab 上的浏览​​器中运行示例。

2018 年 11 月 23 日新增:非标准化多语言模型 + 泰语 + 蒙古语

我们上传了一个新的多语言模型,它不对输入执行任何规范化(没有小写、重音剥离或 Unicode 规范化),还包括泰语和蒙古语。

建议使用此版本开发多语言模型,尤其是非拉丁字母的语言。

这不需要任何代码更改,可以在这里下载:

BERT-Base, Multilingual Cased:104 种语言,12 层,768 隐藏,12 头,110M 参数
2018 年 11 月 15 日新:SOTA SQuAD 2.0 系统

我们发布了代码更改以重现我们 83% 的 F1 SQuAD 2.0 系统,该系统目前以 3% 的优势在排行榜上排名第一。有关详细信息,请参阅 README 的 SQuAD 2.0 部分。

2018 年 11 月 5 日新:提供第三方 PyTorch 和 Chainer 版本的 BERT

HuggingFace 的 NLP 研究人员提供了一个 PyTorch 版本的 BERT,它与我们预训练的检查点兼容,并且能够重现我们的结果。 Sosuke Kobayashi 还提供了 BERT 的 Chainer 版本(谢谢!)我们没有参与 PyTorch 实现的创建或维护,因此请向该存储库的作者提出任何问题。

2018 年 11 月 3 日新功能:提供多语言和中文模式

我们提供了两种新的 BERT 模型:

BERT-Base, Multilingual(不推荐,使用 Multilingual Cased 代替):102 种语言,12 层,768 隐藏,12 头,110M 参数
BERT-Base,中文:中文简繁体,12层,768隐藏,12头,110M参数
我们对中文使用基于字符的标记化,对所有其他语言使用 WordPiece 标记化。两种模型都应该开箱即用,无需更改任何代码。我们确实在 tokenization.py 中更新了 BasicTokenizer 的实现以支持汉字标记化,所以如果你分叉了它,请更新。但是,我们没有更改标记化 API。

有关更多信息,请参阅多语言自述文件。

结束新信息

简介
BERT,或 Transformers 的双向编码器表示,是一种预训练语言表示的新方法,它在各种自然语言处理 (NLP) 任务中获得最先进的结果。

我们的学术论文详细描述了 BERT,并提供了多项任务的完整结果,可以在这里找到:https://arxiv.org/abs/1810.04805。

举几个数字,以下是 SQuAD v1.1 问答任务的结果:

加上许多其他任务。

此外,这些结果都是在几乎没有特定任务的神经网络架构设计的情况下获得的。

如果您已经知道 BERT 是什么并且只想开始,您可以下载预训练模型并在几分钟内运行最先进的微调。

什么是 BERT?
BERT 是一种预训练语言表示的方法,这意味着我们在大型文本语料库(如维基百科)上训练一个通用的“语言理解”模型,然后将该模型用于我们关心的下游 NLP 任务(如问题回答)。 BERT 优于以前的方法,因为它是第一个用于预训练 NLP 的无监督、深度双向系统。

无监督意味着 BERT 仅使用纯文本语料库进行训练,这很重要,因为大量纯文本数据在网络上以多种语言公开可用。

预训练的表示也可以是无上下文的或上下文的,上下文表示还可以是单向的或双向的。 word2vec 或 GloVe 等上下文无关模型为词汇表中的每个单词生成单个“词嵌入”表示,因此 bank 在银行存款和河岸中具有相同的表示。相反,上下文模型会根据句子中的其他单词生成每个单词的表示。

BERT 建立在最近在预训练上下文表示方面的工作之上——包括半监督序列学习、生成预训练、ELMo 和 ULMFit——但至关重要的是,这些模型都是单向或浅双向的。这意味着每个单词仅使用其左侧(或右侧)的单词进行上下文化。例如,在句子 I made a bank deposit 中,bank 的单向表示仅基于 I made a but not deposit。以前的一些工作确实结合了来自单独的左上下文和右上下文模型的表示,但只是以“浅”的方式。 BERT 使用其左右上下文来表示“银行”——我做了一笔存款——从深度神经网络的最底层开始,因此它是深度双向的。

BERT 为此使用了一种简单的方法:我们屏蔽掉输入中 15% 的单词,通过深度双向 Transformer 编码器运行整个序列,然后仅预测被屏蔽的单词。例如:

Input: the man went to the [MASK1] . he bought a [MASK2] of milk.
Labels: [MASK1] = store; [MASK2] = gallon

为了学习句子之间的关系,我们还训练了一个可以从任何单语语料库生成的简单任务:给定两个句子 A 和 B,B 是 A 之后的实际下一个句子,还是只是语料库中的一个随机句子 ?

Sentence A: the man went to the store .
Sentence B: he bought a gallon of milk .
Label: IsNextSentence

Sentence A: the man went to the store .
Sentence B: penguins are flightless .
Label: NotNextSentence

然后我们在大型语料库(Wikipedia + BookCorpus)上长时间(1M 更新步骤)训练一个大型模型(12 层到 24 层 Transformer),这就是 BERT。

使用 BERT 有两个阶段:预训练和微调。

预训练相当昂贵(在 4 到 16 个 Cloud TPU 上需要 4 天),但对于每种语言都是一次性的(当前模型仅支持英语,但多语言模型将在不久的将来发布)。我们正在从论文中发布一些在 Google 进行预训练的预训练模型。大多数 NLP 研究人员永远不需要从头开始预训练他们自己的模型。

微调成本低。从完全相同的预训练模型开始,论文中的所有结果最多可以在单个 Cloud TPU 上复制 1 小时,或者在 GPU 上复制几个小时。例如,可以在单个 Cloud TPU 上对 SQuAD 进行大约 30 分钟的训练,以达到 91.0% 的 Dev F1 分数,这是最先进的单个系统。

BERT 的另一个重要方面是它可以很容易地适应多种类型的 NLP 任务。在本文中,我们展示了句子级别(例如,SST-2)、句子对级别(例如,MultiNLI)、单词级别(例如,NER)和跨度级别的最新结果(例如,SQuAD)任务,几乎没有针对特定任务的修改。

此存储库中发布了什么?
我们正在发布以下内容:

BERT 模型架构(主要是标准的 Transformer 架构)的 TensorFlow 代码。
论文中 BERT-Base 和 BERT-Large 的小写和大写版本的预训练检查点。
TensorFlow 代码用于一键复制论文中最重要的微调实验,包括 SQuAD、MultiNLI 和 MRPC。
此存储库中的所有代码都可与 CPU、GPU 和 Cloud TPU 一起使用。

预训练模型
我们正在发布论文中的 BERT-Base 和 BERT-Large 模型。 Uncased 表示文本在 WordPiece 标记化之前已小写,例如,John Smith 变为 john smith。 Uncased 模型还去掉了任何重音标记。大小写意味着保留真实的大小写和重音标记。通常,除非您知道案例信息对您的任务很重要(例如,命名实体识别或词性标记),否则 Uncased 模型会更好。

这些模型都是在与源代码 (Apache 2.0) 相同的许可下发布的。

有关多语言和中文模型的信息,请参阅多语言自述文件。

使用案例模型时,请确保将 –do_lower=False 传递给训练脚本。 (或者如果您使用自己的脚本,则直接将 do_lower_case=False 传递给 FullTokenizer。)

模型的链接在这里(右键单击名称上的“将链接另存为…”):

  • BERT-Large, Uncased (Whole Word Masking): 24-layer, 1024-hidden, 16-heads, 340M parameters
  • BERT-Large, Cased (Whole Word Masking): 24-layer, 1024-hidden, 16-heads, 340M parameters
  • BERT-Base, Uncased: 12-layer, 768-hidden, 12-heads, 110M parameters
  • BERT-Large, Uncased: 24-layer, 1024-hidden, 16-heads, 340M parameters
  • BERT-Base, Cased: 12-layer, 768-hidden, 12-heads , 110M parameters
  • BERT-Large, Cased: 24-layer, 1024-hidden, 16-heads, 340M parameters
  • BERT-Base, Multilingual Cased (New, recommended): 104 languages, 12-layer, 768-hidden, 12-heads, 110M parameters
  • BERT-Base, Multilingual Uncased (Orig, not recommended) (Not recommended, use Multilingual Casedinstead): 102 languages, 12-layer, 768-hidden, 12-heads, 110M parameters
  • BERT-Base, Chinese: Chinese Simplified and Traditional, 12-layer, 768-hidden, 12-heads, 110M parameters

每个 .zip 文件包含三个项目:

包含预训练权重(实际上是 3 个文件)的 TensorFlow 检查点 (bert_model.ckpt)。
用于将 WordPiece 映射到单词 id 的词汇文件 (vocab.txt)。
一个配置文件 (bert_config.json),它指定模型的超参数。
使用 BERT 进行微调
重要提示:本文中的所有结果均在具有 64GB RAM 的单个 Cloud TPU 上进行了微调。目前无法使用具有 12GB – 16GB RAM 的 GPU 在纸上重新生成大部分 BERT-Large 结果,因为内存中可以容纳的最大批大小太小。我们正在努力将代码添加到此存储库,以允许在 GPU 上实现更大的有效批量大小。有关更多详细信息,请参阅有关内存不足问题的部分。

此代码已使用 TensorFlow 1.11.0 进行了测试。它使用 Python2 和 Python3 进行了测试(但更彻底地使用了 Python2,因为这是 Google 内部使用的)。

使用 BERT-Base 的微调示例应该能够使用给定的超参数在具有至少 12GB RAM 的 GPU 上运行。

使用 Cloud TPU 进行微调
下面的大多数示例都假设您将使用 Titan X 或 GTX 1080 等 GPU 在本地机器上运行训练/评估。

但是,如果您有权访问要训练的 Cloud TPU,只需将以下标志添加到 run_classifier.py 或 run_squad.py:

  --use_tpu=True \
  --tpu_name=$TPU_NAME


请参阅 Google Cloud TPU 教程,了解如何使用 Cloud TPU。或者,您可以使用 Google Colab 笔记本“BERT FineTuning with Cloud TPUs”。

在 Cloud TPU 上,预训练模型和输出目录需要位于 Google Cloud Storage 上。例如,如果您有一个名为 some_bucket 的存储桶,则可以改用以下标志:

–output_dir=gs://some_bucket/my_output_dir/
解压后的预训练模型文件也可以在 Google Cloud Storage 文件夹 gs://bert_models/2018_10_18 中找到。例如:

导出 BERT_BASE_DIR=gs://bert_models/2018_10_18/uncased_L-12_H-768_A-12
句子(和句子对)分类任务
在运行此示例之前,您必须通过运行此脚本下载 GLUE 数据并将其解压缩到某个目录 $GLUE_DIR。接下来,下载 BERT-Base 检查点并将其解压缩到某个目录 $BERT_BASE_DIR。

此示例代码在 Microsoft Research Paraphrase Corpus (MRPC) 语料库上对 BERT-Base 进行微调,该语料库仅包含 3,600 个示例,并且可以在大多数 GPU 上在几分钟内进行微调。

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
export GLUE_DIR=/path/to/glue

python run_classifier.py \
  --task_name=MRPC \
  --do_train=true \
  --do_eval=true \
  --data_dir=$GLUE_DIR/MRPC \
  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
  --max_seq_length=128 \
  --train_batch_size=32 \
  --learning_rate=2e-5 \
  --num_train_epochs=3.0 \
  --output_dir=/tmp/mrpc_output/

你应该看到这样的输出:

***** Eval results *****
  eval_accuracy = 0.845588
  eval_loss = 0.505248
  global_step = 343
  loss = 0.505248

这意味着开发集准确率为 84.55%。即使从相同的预训练检查点开始,像 MRPC 这样的小集在 Dev 集的准确性上也有很大的差异。如果您重新运行多次(确保指向不同的 output_dir),您应该会看到 84% 到 88% 之间的结果。

其他一些预训练模型在 run_classifier.py 中现成实现,因此按照这些示例将 BERT 用于任何单句或句子对分类任务应该很简单。

注意:您可能会看到一条消息正在 CPU 上运行火车。这实际上只是意味着它运行在包含 GPU 的 Cloud TPU 以外的其他东西上。

分类器的预测
训练好分类器后,您可以使用 –do_predict=true 命令在推理模式下使用它。您需要在输入文件夹中有一个名为 test.tsv 的文件。输出将在输出文件夹中名为 test_results.tsv 的文件中创建。每行将包含每个样本的输出,列是类概率。

export BERT_BASE_DIR=/path/to/bert/uncased_L-12_H-768_A-12
export GLUE_DIR=/path/to/glue
export TRAINED_CLASSIFIER=/path/to/fine/tuned/classifier

python run_classifier.py \
  --task_name=MRPC \
  --do_predict=true \
  --data_dir=$GLUE_DIR/MRPC \
  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$TRAINED_CLASSIFIER \
  --max_seq_length=128 \
  --output_dir=/tmp/mrpc_output/

SQuAD 1.1

斯坦福问答数据集 (SQuAD) 是一个流行的问答基准数据集。 BERT(在发布时)在 SQuAD 上获得了最先进的结果,几乎没有针对特定任务的网络架构修改或数据增强。 然而,它确实需要半复杂的数据预处理和后处理来处理(a)SQuAD 上下文段落的可变长度性质,以及(b)用于 SQuAD 训练的字符级答案注释。 此处理在 run_squad.py 中实现和记录。

要在 SQuAD 上运行,您首先需要下载数据集。 SQuAD 网站似乎不再链接到 v1.1 数据集,但可以在此处找到必要的文件:

  • train-v1.1.json
  • dev-v1.1.json
  • evaluate-v1.1.py

将这些下载到某个目录 $SQUAD_DIR。

由于内存限制,论文中最先进的 SQuAD 结果目前无法在 12GB-16GB GPU 上重现(事实上,即使批量大小 1 似乎也不适合使用 BERT-Large 的 12GB GPU)。 但是,可以使用以下超参数在 GPU 上训练一个相当强大的 BERT-Base 模型:

python run_squad.py \
  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
  --do_train=True \
  --train_file=$SQUAD_DIR/train-v1.1.json \
  --do_predict=True \
  --predict_file=$SQUAD_DIR/dev-v1.1.json \
  --train_batch_size=12 \
  --learning_rate=3e-5 \
  --num_train_epochs=2.0 \
  --max_seq_length=384 \
  --doc_stride=128 \
  --output_dir=/tmp/squad_base/

开发集预测将保存到 output_dir 中名为 predictions.json 的文件中:

python $SQUAD_DIR/evaluate-v1.1.py $SQUAD_DIR/dev-v1.1.json ./squad/predictions.json
{"f1": 88.41249612335034, "exact_match": 81.2488174077578}

您应该会看到类似于论文中报告的 BERT-Base 的 88.5% 的结果。

如果您可以访问 Cloud TPU,则可以使用 BERT-Large 进行训练。 这是一组超参数(与论文略有不同),它们始终获得大约 90.5%-91.0% 仅在 SQuAD 上训练的 F1 单系统:

python run_squad.py \
  --vocab_file=$BERT_LARGE_DIR/vocab.txt \
  --bert_config_file=$BERT_LARGE_DIR/bert_config.json \
  --init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \
  --do_train=True \
  --train_file=$SQUAD_DIR/train-v1.1.json \
  --do_predict=True \
  --predict_file=$SQUAD_DIR/dev-v1.1.json \
  --train_batch_size=24 \
  --learning_rate=3e-5 \
  --num_train_epochs=2.0 \
  --max_seq_length=384 \
  --doc_stride=128 \
  --output_dir=gs://some_bucket/squad_large/ \
  --use_tpu=True \
  --tpu_name=$TPU_NAME

例如,使用这些参数进行一次随机运行会产生以下 Dev 分数:

{"f1": 90.87081895814865, "exact_match": 84.38978240302744}

如果您在此之前在 TriviaQA 上微调一个 epoch,结果会更好,但您需要将 TriviaQA 转换为 SQuAD json 格式。

SQuAD 2.0
该模型也在 run_squad.py 中实现和记录。

要在 SQuAD 2.0 上运行,您首先需要下载数据集。 必要的文件可以在这里找到:

  • train-v2.0.json
  • dev-v2.0.json
  • evaluate-v2.0.py

将这些下载到某个目录 $SQUAD_DIR。

在 Cloud TPU 上,您可以使用 BERT-Large 运行,如下所示:

python run_squad.py \
  --vocab_file=$BERT_LARGE_DIR/vocab.txt \
  --bert_config_file=$BERT_LARGE_DIR/bert_config.json \
  --init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \
  --do_train=True \
  --train_file=$SQUAD_DIR/train-v2.0.json \
  --do_predict=True \
  --predict_file=$SQUAD_DIR/dev-v2.0.json \
  --train_batch_size=24 \
  --learning_rate=3e-5 \
  --num_train_epochs=2.0 \
  --max_seq_length=384 \
  --doc_stride=128 \
  --output_dir=gs://some_bucket/squad_large/ \
  --use_tpu=True \
  --tpu_name=$TPU_NAME \
  --version_2_with_negative=True

我们假设您已将从输出目录复制到名为的本地目录。/ squad/。 初始DEV SET预测将在./squad/predictions.json和每个问题的最佳答案(“”)和最佳非空答案之间的差异将在文件中。/ squad/null_odds.json

运行此脚本以调整预测NULL与非空答案的阈值:

python $ squad_dir / evaluate-v2.0.py $ squad_dir / dev-v2.0.json ./squad/predictions.json – prob-file ./squad/null_odds.json

假设脚本输出“best_f1_thresh”阈值。 (典型值在-1.0和-5.0之间)。 您现在可以重新运行模型以使用派生阈值生成预测,或者您可以从。/squad/nbest_predictions.json提取适当的答案。

python run_squad.py \
  --vocab_file=$BERT_LARGE_DIR/vocab.txt \
  --bert_config_file=$BERT_LARGE_DIR/bert_config.json \
  --init_checkpoint=$BERT_LARGE_DIR/bert_model.ckpt \
  --do_train=False \
  --train_file=$SQUAD_DIR/train-v2.0.json \
  --do_predict=True \
  --predict_file=$SQUAD_DIR/dev-v2.0.json \
  --train_batch_size=24 \
  --learning_rate=3e-5 \
  --num_train_epochs=2.0 \
  --max_seq_length=384 \
  --doc_stride=128 \
  --output_dir=gs://some_bucket/squad_large/ \
  --use_tpu=True \
  --tpu_name=$TPU_NAME \
  --version_2_with_negative=True \
  --null_score_diff_threshold=$THRESH

内存溢出的问题
本文中的所有实验都在云TPU上进行微调,具有64GB的设备RAM。因此,使用带12GB – 16GB的RAM的GPU时,如果使用纸纸中描述的相同的超参数,则可能会遇到内存中的问题。

影响内存使用的因素是:

max_seq_length:发布的模型培训,序列长度高达512,但您可以使用较短的最大序列长度进行微调,以节省大量内存。这由我们的示例代码中的max_seq_length标志控制。

TRAIN_BATCH_SIZE:内存使用率也与批处理大小成比例。

模型类型,BERT-BASE与BERT-LIGHT:BERT-MAT​​RIC型号比BERT基本要显着更多的内存。

优化器:BERT的默认优化器是ADAM,这需要大量额外的内存来存储M和V向量。切换到更多内存高效的优化器可以减少内存使用情况,但也可以影响结果。我们没有尝试使用其他优化器进行微调。

使用默认的培训脚本(run_classifier.py和run_squad.py),我们通过Tensorflow 1.11.0基准于 Titan X GPU (12GB RAM)上的最大批量大小:

不幸的是,BERT-Large 的这些最大批量大小非常小,以至于无论使用何种学习率,它们实际上都会损害模型的准确性。我们正在努力向这个存储库添加代码,这将允许在 GPU 上使用更大的有效批量大小。该代码将基于以下一种(或两种)技术:

梯度累积:小批量中的样本通常独立于梯度计算(不包括批量归一化,此处未使用)。这意味着可以在执行权重更新之前累积多个较小 minibatch 的梯度,这将完全等同于单个较大的更新。

梯度检查点:在 DNN 训练期间 GPU/TPU 内存的主要用途是缓存正向传递中的中间激活,这是反向传递中高效计算所必需的。 “梯度检查点”通过以智能方式重新计算激活来用内存换取计算时间。

但是,这在当前版本中没有实现。

使用 BERT 提取固定特征向量(如 ELMo)
在某些情况下,与其对整个预训练模型进行端到端微调,不如获得预训练的上下文嵌入,这是从预训练的隐藏层生成的每个输入标记的固定上下文表示。 – 训练模型。这也应该可以缓解大多数内存不足的问题。

例如,我们包含脚本 extract_features.py 可以像这样使用:

# Sentence A and Sentence B are separated by the ||| delimiter for sentence
# pair tasks like question answering and entailment.
# For single sentence inputs, put one sentence per line and DON'T use the
# delimiter.
echo 'Who was Jim Henson ? ||| Jim Henson was a puppeteer' > /tmp/input.txt

python extract_features.py \
  --input_file=/tmp/input.txt \
  --output_file=/tmp/output.jsonl \
  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
  --layers=-1,-2,-3,-4 \
  --max_seq_length=128 \
  --batch_size=8

这将创建一个 JSON 文件(每行输入一行),其中包含来自层指定的每个 Transformer 层的 BERT 激活(-1 是 Transformer 的最终隐藏层等)

请注意,此脚本将生成非常大的输出文件(默认情况下,每个输入标记大约 15kb)。

如果您需要保持原始单词和标记化单词之间的对齐(用于投影训练标签),请参阅下面的标记化部分。

注意:您可能会看到一条消息,例如在 model_dir: /tmp/tmpuB5g5c 中找不到训练好的模型,正在运行初始化以进行预测。此消息是预期的,它只是意味着我们使用的是 init_from_checkpoint() API,而不是保存的模型 API。如果您没有指定检查点或指定无效的检查点,此脚本会报错。

代币化
对于句子级任务(或句子对)任务,标记化非常简单。只需按照 run_classifier.py 和 extract_features.py 中的示例代码进行操作即可。句子级任务的基本过程是:

实例化 tokenizer = tokenization.FullTokenizer 的实例

使用 tokens = tokenizer.tokenize(raw_text) 对原始文本进行标记。

截断到最大序列长度。 (您最多可以使用 512,但出于内存和速度原因,您可能希望使用更短的时间。)

在正确的位置添加 [CLS] 和 [SEP] 令牌。

单词级别和跨度级别的任务(例如,SQuAD 和 NER)更复杂,因为您需要保持输入文本和输出文本之间的对齐,以便您可以投射训练标签。 SQuAD 是一个特别复杂的示例,因为输入标签是基于字符的,并且 SQuAD 段落通常比我们的最大序列长度长。请参阅 run_squad.py 中的代码以显示我们如何处理此问题。

在我们描述处理单词级任务的一般方法之前,了解我们的分词器到底在做什么是很重要的。它有三个主要步骤:

文本规范化:将所有空白字符转换为空格,并且(对于 Uncased 模型)小写输入并去除重音标记。例如,约翰·约翰逊的,→ 约翰·约翰逊的,。

标点拆分:拆分两边的所有标点字符(即在所有标点字符周围添加空格)。标点字符被定义为 (a) 任何具有 P* Unicode 类的字符,(b) 任何非字母/数字/空格的 ASCII 字符(例如,像 $ 这样的字符在技术上不是标点符号)。例如,john johanson’s, → john johanson’s ,

WordPiece 标记化:将空白标记化应用于上述过程的输出,并将 WordPiece 标记化分别应用于每个标记。 (我们的实现直接基于来自 tensor2tensor 的实现,它是链接的)。例如,john johanson’s , → john johan ##son’s ,

这种方案的优点是它与大多数现有的英语分词器“兼容”。例如,假设您有一个词性标注任务,如下所示:

输入: John Johanson 's house
标签: NNP NNP POS NN
标记化的输出将如下所示:

代币:john johan ##son 的房子
至关重要的是,这将与原始文本是 John Johanson 的房子的输出相同(在 ‘s 之前没有空格)。

如果您有一个带有单词级别注释的预标记表示,您可以简单地独立标记每个输入单词,并确定性地保持原始到标记的对齐方式:

### Input
orig_tokens = ["John", "Johanson", "'s",  "house"]
labels      = ["NNP",  "NNP",      "POS", "NN"]

### Output
bert_tokens = []

# Token map will be an int -> int mapping between the `orig_tokens` index and
# the `bert_tokens` index.
orig_to_tok_map = []

tokenizer = tokenization.FullTokenizer(
    vocab_file=vocab_file, do_lower_case=True)

bert_tokens.append("[CLS]")
for orig_token in orig_tokens:
  orig_to_tok_map.append(len(bert_tokens))
  bert_tokens.extend(tokenizer.tokenize(orig_token))
bert_tokens.append("[SEP]")

# bert_tokens == ["[CLS]", "john", "johan", "##son", "'", "s", "house", "[SEP]"]
# orig_to_tok_map == [1, 2, 4, 6]

现在 orig_to_tok_map 可用于将标签投影到标记化表示。

有一些常见的英语标记化方案会导致 BERT 的预训练方式略有不匹配。例如,如果您的输入标记化拆分了类似 do n’t 的缩略词,这将导致不匹配。如果可以这样做,您应该预处理您的数据以将它们转换回看起来很原始的文本,但如果不可能,这种不匹配可能不是什么大问题。

使用 BERT 进行预训练
我们正在发布代码来对任意文本语料库进行“蒙面 LM”和“下一句预测”。请注意,这不是论文中使用的确切代码(原始代码是用 C++ 编写的,并且有一些额外的复杂性),但该代码确实会生成论文中描述的预训练数据。

以下是如何运行数据生成。输入是一个纯文本文件,每行一个句子。 (重要的是这些是“下一句预测”任务的实际句子)。文档由空行分隔。输出是一组序列化为 TFRecord 文件格式的 tf.train.Examples。

您可以使用现成的 NLP 工具包(例如 spaCy)执行句子分割。 create_pretraining_data.py 脚本将连接段,直到它们达到最大序列长度,以最大限度地减少填充造成的计算浪费(有关更多详细信息,请参阅脚本)。但是,您可能希望有意在输入数据中添加少量噪声(例如,随机截断 2% 的输入段),以使其在微调期间对非句子输入更加稳健。

该脚本将整个输入文件的所有示例存储在内存中,因此对于大型数据文件,您应该对输入文件进行分片并多次调用该脚本。 (您可以将文件 glob 传递给 run_pretraining.py,例如 tf_examples.tf_record*。)

max_predictions_per_seq 是每个序列的掩码 LM 预测的最大数量。您应该将其设置为大约 max_seq_length * masked_lm_prob (脚本不会自动执行此操作,因为需要将确切的值传递给两个脚本)。

python create_pretraining_data.py \
  --input_file=./sample_text.txt \
  --output_file=/tmp/tf_examples.tfrecord \
  --vocab_file=$BERT_BASE_DIR/vocab.txt \
  --do_lower_case=True \
  --max_seq_length=128 \
  --max_predictions_per_seq=20 \
  --masked_lm_prob=0.15 \
  --random_seed=12345 \
  --dupe_factor=5

以下是如何进行预训练。 如果您是从头开始预训练,请不要包含 init_checkpoint。 模型配置(包括词汇大小)在 bert_config_file 中指定。 此演示代码仅对少量步骤 (20) 进行预训练,但实际上您可能希望将 num_train_steps 设置为 10000 步或更多。 传递给 run_pretraining.py 的 max_seq_length 和 max_predictions_per_seq 参数必须与 create_pretraining_data.py 相同。

python run_pretraining.py \
  --input_file=/tmp/tf_examples.tfrecord \
  --output_dir=/tmp/pretraining_output \
  --do_train=True \
  --do_eval=True \
  --bert_config_file=$BERT_BASE_DIR/bert_config.json \
  --init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
  --train_batch_size=32 \
  --max_seq_length=128 \
  --max_predictions_per_seq=20 \
  --num_train_steps=20 \
  --num_warmup_steps=10 \
  --learning_rate=2e-5

这将产生如下输出:

***** Eval results *****
  global_step = 20
  loss = 0.0979674
  masked_lm_accuracy = 0.985479
  masked_lm_loss = 0.0979328
  next_sentence_accuracy = 1.0
  next_sentence_loss = 3.45724e-05

请注意,由于我们的 sample_text.txt 文件非常小,因此此示例训练将在几个步骤中过度拟合该数据并产生不切实际的高精度数字。

预训练提示和注意事项
如果使用您自己的词汇表,请确保更改 bert_config.json 中的 vocab_size。如果你使用更大的词汇量而不改变这一点,那么在 GPU 或 TPU 上训练时,由于未经检查的越界访问,你可能会得到 NaN。
如果您的任务有大量特定领域的语料库可用(例如,“电影评论”或“科学论文”),那么从 BERT 检查点开始对您的语料库进行额外的预训练步骤可能会有所帮助。
我们在论文中使用的学习率为 1e-4。但是,如果您从现有的 BERT 检查点开始执行额外的预训练步骤,则应使用较小的学习率(例如 2e-5)。
当前的 BERT 模型仅支持英语,但我们确实计划在不久的将来(希望在 2018 年 11 月末)发布一个已在多种语言上进行预训练的多语言模型。
较长的序列成本不成比例,因为注意力与序列长度成二次方。换句话说,一批 64 个长度为 512 的序列比一批 256 个长度为 128 的序列要昂贵得多。全连接/卷积成本相同,但 512 长度序列的注意力成本要高得多.因此,一个好的方法是预先训练 90,000 步,序列长度为 128,然后再进行 10,000 步,序列长度为 512。学习位置嵌入通常需要非常长的序列,这可以学得还算快。请注意,这确实需要使用不同的 max_seq_length 值生成两次数据。
如果您是从头开始进行预训练,请准备好预训练的计算成本很高,尤其是在 GPU 上。如果您是从头开始进行预训练,我们推荐的方法是在单个可抢占 Cloud TPU v2 上预训练 BERT-Base,这需要大约 2 周时间,成本约为 500 美元(基于 2018 年 10 月的定价) .与论文中使用的相比,仅在单个 Cloud TPU 上进行训练时,您将不得不缩小批量大小。建议使用适合 TPU 内存的最大批量大小。
预训练数据
我们将无法发布论文中使用的预处理数据集。对于 Wikipedia,推荐的预处理是下载最新的转储,使用 WikiExtractor.py 提取文本,然后应用任何必要的清理将其转换为纯文本。

不幸的是,收集 BookCorpus 的研究人员不再提供公开下载。 Project Guttenberg 数据集是一个较小的(2 亿字)公共领域的旧书集合。

Common Crawl 是另一个非常大的文本集合,但您可能需要进行大量的预处理和清理以提取可用的语料库以用于预训练 BERT。

学习一个新的 WordPiece 词汇
此存储库不包含用于学习新 WordPiece 词汇的代码。原因是论文中使用的代码是用 C++ 实现的,依赖于 Google 的内部库。对于英语,从我们的词汇和预训练模型开始几乎总是更好。对于学习其他语言的词汇,有许多可用的开源选项。但是,请记住,这些与我们的 tokenization.py 库不兼容:

  • Google’s SentencePiece library
  • tensor2tensor’s WordPiece generation script
  • Rico Sennrich’s Byte Pair Encoding library

在 Colab 中使用 BERT
如果您想将 BERT 与 Colab 一起使用,您可以从笔记本“BERT FineTuning with Cloud TPUs”开始。在撰写本文时(2018 年 10 月 31 日),Colab 用户可以完全免费访问 Cloud TPU。注意:每位用户一个,可用性有限,需要一个带有存储空间的 Google Cloud Platform 帐户(尽管注册 GCP 时可以使用免费信用购买存储空间),并且此功能将来可能不再可用。单击刚刚链接的 BERT Colab 以获取更多信息。

常问问题
此代码与 Cloud TPU 兼容吗? GPU 呢?
是的,这个存储库中的所有代码都可以与 CPU、GPU 和 Cloud TPU 一起使用。但是,GPU 训练仅限于单 GPU。

我收到内存不足错误,怎么了?
有关更多信息,请参阅有关内存不足问题的部分。

有可用的 PyTorch 版本吗?
没有官方的 PyTorch 实现。然而,来自 HuggingFace 的 NLP 研究人员提供了一个 PyTorch 版本的 BERT,它与我们预训练的检查点兼容,并且能够重现我们的结果。我们没有参与 PyTorch 实现的创建或维护,因此请向该存储库的作者提出任何问题。

是否有可用的 Chainer 版本?
没有官方的 Chainer 实现。然而,Sosuke Kobayashi 提供了 BERT 的 Chainer 版本,它与我们预先训练的检查点兼容,并且能够重现我们的结果。我们没有参与 Chainer 实现的创建或维护,因此请向该存储库的作者提出任何问题。

是否会发布其他语言的模型?
是的,我们计划在不久的将来发布多语言 BERT 模型。我们无法就将包含哪些语言做出确切承诺,但它可能是一个单一模型,其中包含大多数拥有庞大维基百科的语言。

是否会发布比 BERT-Large 更大的模型?
到目前为止,我们还没有尝试训练任何比 BERT-Large 更大的东西。如果我们能够获得重大改进,我们可能会发布更大的模型。

这个库是在什么许可证下发布的?
所有代码和模型均在 Apache 2.0 许可下发布。有关详细信息,请参阅许可证文件。

我如何引用 BERT?
现在,引用 the Arxiv paper:

@article{devlin2018bert,
  title={BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding},
  author={Devlin, Jacob and Chang, Ming-Wei and Lee, Kenton and Toutanova, Kristina},
  journal={arXiv preprint arXiv:1810.04805},
  year={2018}
}

如果我们将论文提交给会议或期刊,我们将更新 BibTeX。

免责声明
这不是 Google 的官方产品。

联系信息
有关使用 BERT 的帮助或问题,请提交 GitHub 问题。

有关 BERT 的个人交流,请联系 Jacob Devlin (jacobdevlin@google.com)、Ming-Wei Chang (mingweichang@google.com) 或 Kenton Lee (kentonl@google.com)。

作者 east
数据仓库, 数据库 3月 25,2022

数据工程最糟糕的部分是什么

在数据工程团队中,列表很长,取决于您的个人角色。但我的一般选择是“最终数据科学家和数据分析师糟糕的 SQL 语句”。

可能不是一个明显的答案,所以让我解释一下。

如果您正在使用数据仓库,让我们从数据工程团队的三个主要工作领域的角度来看这个问题:

构建 ETL 管道 → 将数据导入您的仓库

构建转换→加入/转换不同的数据集

公开数据以供下游使用 → 报告、分析、ML/AI

数据工程师还需要对元数据进行分类和组织,并定义从仓库写入和读取数据的流程。在某种程度上,他们是数据仓库的图书馆员。

然后目标是尽可能抽象和自动化。通过自动化,数据工程师可以将他们稀缺的时间用于构建与维护/修复。

您还通过向您提供的数据添加 SLA 来向业务做出承诺。 “报告将在太平洋标准时间早上 6 点之前完成”或“我们的分析环境仅比我们的生产环境晚 15 分钟”。

瞧,您已经完成了以上所有工作,将其投入生产,稍作调整,一切正常。你可以继续做别的事情。嗯,不。

变革的驱动力

事情不是一成不变的。如果您正在为一家不断发展的企业工作,那么您将不得不应对三个挑战:

数据量在 5 年内增长约 10 倍,同时出现了越来越多的新型数据源

模型的数量正在增长。随着您将更多数据引入您的仓库,您可以以无限新的方式组合这些数据。你会听到术语“DAG”(有向无环图)。

用户和工具的数量正在增长。随着业务的增长,需要/想要访问数据的人数也在增加。他们将希望使用他们选择的工具访问这些数据。

数据工程的挑战

现在你是负责这个堆栈的数据工程师。您的公司将雇用更多的数据工程师来保持运转。例如,Netflix 每个数据源都有一名数据工程师,他们的全部工作就是保持该数据源的盘子旋转。

但并非每家公司都有 Netflix 的预算。人数有上限。但是,贵公司招聘的数据科学家和分析师的数量似乎没有限制。更多的关注数据是“数据驱动的”。

因此,“数据构建者”(数据工程师)和“数据消费者”(数据分析师、科学家、机器学习应用程序等)之间的比例猛增。

我看到(数据构建者)与(数据消费者)的比率介于 1:20 到 1:40 之间。一名数据工程师必须支持 20-40 个下游用户。

这就是问题开始的地方。回到最初的三个工作领域,将会发生以下情况:

ETL 管道运行很长时间并产生错误和问题。不过,您可能只能在运行后发现,现在您必须弄清楚是什么损坏了。这是一个巨大的干扰。

现有的模型可能无法提供企业想要的答案。分析师想要快速行动,因此他们绕过您并开始添加新模型,甚至直接在您的仓库中查询原始数据。如果基础表发生变化,这会导致模型膨胀和损坏。

您的最终用户可能正在使用为他们生成 SQL 的工具。或者他们编写自己的 SQL 语句。这两种方法都可能导致糟糕的 SQL 语法使整个仓库紧张,每个人的查询速度都很慢。

然后用户向数据工程师提交支持票(“我的查询很慢”,或者“我的查询没有完成或完成”)。你会被支持请求淹没。

我们当然是在戏剧化,但从方向上讲,这是工作中最糟糕的三个部分。让我们称之为“保持盘子旋转”。

数据工程中最糟糕的部分

我书中最糟糕的一点是最后一点——处理糟糕的 SQL。

那是因为管道和模型是您可以控制的。约定、工具、监控、警报、访问权限等——有一种方法可以在事物周围设置护栏。

但是控制最终用户和他们的 SQL 是不可能的。例如,我见过没有 WHERE 子句的“SELECT *”查询,它连接两个表,每个表有 20 亿行。输出量如此之大,以至于它会填满并取下仓库。 “谁写了那个查询??”。

不太引人注目的结果包括编写查询,例如10 分钟的执行时间,一个小的更改可能会导致 1 分钟的执行时间。这听起来可能没什么大不了的(“我会同时去喝杯咖啡”),但这是生产力的巨大损失。对于数据科学,快速迭代和测试模型就是一切。

是的,您可以设置规则来终止查询,但所做的只是增加分析师文件的支持票数,因为查询没有完成。

对于数据工程师来说,这些查询是谁编写的也不是很明显。分析师使用的工具掩盖了他们背后的用户。 Tableau、Looker 或 Mode Analytics 等仪表板工具在您的仓库中显示为一个用户。

但在他们身后,他们可能有 100-200 人在编写查询。因此,您使用“Looker”作为用户,但您不知道是“Jack”、“Anne”还是“Joe”编写了查询。因此,要找出发生了什么以及谁编写了哪个查询,需要进行大量的挖掘工作。

概括

所以你去,上面是长版本。答案的简短版本是“最终用户的 SQL 语句不佳”。

这是一个问题,原因有以下三个:

您无法控制分析师编写的 SQL 语法。您可能只有在查询运行并造成损坏后才能发现。

分析师用来编写查询的工具掩盖了他们背后的用户。在拥有数百名用户的情况下,找到编写查询的用户就像大海捞针一样。

您不能只是关闭分析师或终止他们的查询——这将导致支持票证的增加以及数据工程和数据消费者之间的摩擦。

随着数据生产者与数据消费者的比例越来越大,问题只会越来越大。您必须支持的最终用户越多,您必须处理的投诉和罚单就越多,这是一个巨大的挫败感和时间浪费。

当然,这个问题的答案是让分析师能够编写更好的 SQL,并帮助数据工程师在这方面与分析师协作。

作者 east
数据库 3月 25,2022

SQL对比NoSQL 5 关键不同点

在选择现代数据库时,最大的决定之一是选择关系 (SQL) 或非关系 (NoSQL) 数据结构。 虽然两者都是可行的选择,但用户在做出决定时必须牢记两者之间的关键区别。

在这里,我们分解最重要的区别并讨论可用的最佳 SQL 和 NoSQL 数据库系统。

SQL 与 NoSQL 之间的五个关键区别是:

1、SQL 数据库是关系型的,NoSQL 数据库是非关系型的。

2、SQL 数据库使用结构化查询语言并具有预定义的模式。 NoSQL 数据库具有用于非结构化数据的动态模式。

3、SQL 数据库是垂直可扩展的,而 NoSQL 数据库是水平可扩展的。

4、SQL 数据库是基于表的,而 NoSQL 数据库是文档、键值、图形或宽列存储。

5、SQL 数据库更适合多行事务,而 NoSQL 更适合文档或 JSON 等非结构化数据。

数据库架构

在最基本的层面上,这两种技术最大的区别在于 SQL 数据库是关系型的,而 NoSQL 数据库是非关系型的。

数据库模式和查询语言

SQL 数据库使用结构化查询语言并具有用于定义和操作数据的预定义模式。 SQL 是可用的最通用和广泛使用的查询语言之一,使其成为许多用例的安全选择。它非常适合复杂的查询。但是,SQL 可能过于严格。您必须使用预定义的模式来确定您的数据结构,然后才能使用它。您的所有数据都必须遵循相同的结构。这个过程需要大量的前期准备。如果你想改变你的数据结构,这对你的整个系统来说将是困难和破坏性的。

NoSQL 数据库具有用于非结构化数据的动态模式,并且数据以多种方式存储。您可以对数据使用面向列、面向文档、基于图形或 KeyValue 存储。这种灵活性意味着:

您可以创建文档而无需先定义其结构

每个文档都可以有自己独特的结构

语法可能因数据库而异

您可以随时添加字段

数据库扩展

SQL 数据库在大多数情况下是垂直可扩展的。您可以通过添加更多 CPU、RAM 或 SSD 容量来增加单个服务器的负载。 NoSQL 数据库是水平可扩展的。您可以通过分片来处理更高的流量,从而为您的 NoSQL 数据库添加更多服务器。水平扩展比垂直扩展具有更大的整体容量,使 NoSQL 数据库成为大型且频繁变化的数据集的首选。

数据结构

SQL 数据库是基于表的,而 NoSQL 数据库是文档、键值、图形或宽列存储。

SQL 数据库的一些示例包括 MySQL、Oracle、PostgreSQL 和 Microsoft SQL Server。 NoSQL 数据库示例包括 MongoDB、BigTable、Redis、RavenDB Cassandra、HBase、Neo4j 和 CouchDB。

各自理想使用场合

SQL 数据库更适合多行事务,而 NoSQL 更适合文档或 JSON 等非结构化数据。 SQL 数据库也常用于围绕关系结构构建的遗留系统。

SQL 数据库系统

现在您已了解 SQL 和 NoSQL 数据库之间的主要区别,是时候探索适用于您的工作负载的不同选项了。

MySQL

免费和开源

极其成熟的数据库,拥有庞大的社区、广泛的测试和高度的稳定性

适用于所有主要平台

复制和分片可用

涵盖广泛的应用领域

Oracle

商业数据库,更新频繁,管理专业,客户支持优秀

Procedural Language/SQL 或 PL/SQL 是使用的 SQL 方言

适用于大型数据库

简单升级

事务控制

兼容所有操作系统

适用于工作负载要求高的企业和组织

微软 SQL 服务器

由微软开发和管理的商业数据库

Transact SQL 或 T-SQL 是使用的 SQL 方言

仅适用于 Windows 和 Linux

方便使用的

发现错误时难以中途调整

优秀的文档

非常适合需要商业数据库解决方案而无需 Oracle 成本的中小型组织

PostgreSQL

面向对象的数据库管理系统,这意味着它是一个混合 SQL/NoSQL 数据库解决方案

免费和开源

与广泛的操作系统兼容

活跃的社区和许多第三方服务提供商

使用纯 SQL

NoSQL 数据库系统

MongoDB 是非常受欢迎的 NoSQL 数据库,这是有充分理由的。它的特点和好处包括:

免费使用

动态模式

水平可扩展

简单查询的出色性能

在不影响现有行或应用程序性能的情况下添加新列和字段

MongoDB 最适合正在经历快速增长阶段或拥有大量非结构化数据的公司。这个 NoSQL 数据库的鲜为人知的替代品是可用的,例如:

Apache Cassandra

Google Cloud BigTable

Apache HBase

作者 east
Hbase, Hive 3月 24,2022

生产环境选型考虑:Hive全方位对比HBase

Apache Hive 和 Apache HBase 是用于大数据的令人难以置信的工具。虽然它们的功能有一些相同之处,但 Apache Hive 和 Apache HBase 都具有独特的作用,使它们更适合特定的场景。一些主要区别包括:

Apache Hive 是建立在 Hadoop 之上的数据仓库系统,而 Apache HBase 是在 HDFS 或 Alluxio 之上的 NoSQL 键/值。

Hive 为 Spark/Hadoop 数据提供 SQL 功能,HBase 实时存储和处理 Hadoop 数据。

HBase 用于实时查询或大数据,而 Hive 不适合实时查询。

Hive 最适合用于数据的分析查询,而 HBase 主要用于将非结构化 Hadoop 数据作为湖存储或处理。

归根结底,将 Apache Hive 与 Apache HBase 进行比较就像将苹果与橘子,或 Google 与 Facebook 进行比较。虽然这两个实体相似,但它们不为用户提供相同的功能。然而,尽管存在差异,Apache Hive 和 Apache HBase 都是处理大数据时使用的绝佳工具。继续阅读以了解有关 Apache Hive、Apache HBase 的更多信息,以及它们的各种功能如何在处理大数据时改善您的业务。

什么是 Apache Hive?

让我们从 Apache Hive 开始“Hive 与 Hbase”的考试。 Apache Hive 是一个构建在 Hadoop 之上的数据仓库系统。它为大型 Hadoop 非结构化数据池提供数据汇总、分析和查询。您可以查询存储在 Apache HDFS 中的数据,甚至可以查询存储在 Apache HBase 中的数据。 MapReduce、Spark 或 Tez 执行该数据。

Apache Hive 使用一种称为 HiveQL(或 HQL)的类似 SQL 的语言来查询批量 MapReduce 作业。 Hive 还支持 ACID 事务,例如 INSERT/DELETE/UPDATE/MERGE 语句。从更新 3.0 开始,Hive 通过减少表模式约束和提供对矢量化查询的访问权限为此添加了一些额外的功能。

简而言之,Apache Hive 为 Spark/Hadoop 数据提供了 SQL 特性(MapReduce 的 Java API 不太容易使用),它既是一个数据仓库系统,也是一个具有丰富集成和大量用户友好的 ETL 工具特征。与许多类似的产品(例如 Apache Pig)一样,Hive 在技术上可以处理许多不同的功能。例如,Hive 允许您使用 SQL,而不是为 MapReduce 作业编写冗长的 Java。您在堆栈中使用 Hive 的原因将因您的需求而异。

Hive 的核心功能

Hive 可以帮助精通 SQL 查询与 Hadoop 集成的各种数据存储中的数据。由于它符合 JDBC,它还与现有的基于 SQL 的工具集成。运行 Hive 查询可能需要一段时间,因为默认情况下它们会遍历表中的所有数据。尽管如此,Hive 的分区功能限制了数据量。分区允许对存储在单独文件夹中的数据运行过滤查询,并且只读取与查询匹配的数据。例如,如果文件将日期格式作为其名称的一部分,它可以用于仅处理在特定日期之间创建的文件。

以下是 Hive 的一些功能:

它使用 SQL。

出色的 Apache Spark 和 Tez 集成。

您可以使用用户定义函数 (UDF)。

它有很棒的带有 Hive 3+ 的 ACID 表。

您可以查询庞大的 Hadoop 数据集。

大量集成(例如,BI 工具、Pig、Spark、HBase 等)。

其他基于 Hive 的功能(例如 HiveMall)可以提供一些额外的独特功能。

什么是 Apache HBase?

Apache HBase 是运行在 HDFS 或 Alluxio 之上的 NoSQL 键/值存储。与 Hive 不同,HBase 操作在其数据库而不是 MapReduce 作业上实时运行。所以,你有随机访问能力——这是 HDFS 所缺少的。由于 HDFS 不是为处理具有随机读/写操作的实时分析而构建的,因此 HBase 为 HDFS 带来了大量功能。您可以将其设置为通过 Hadoop 处理的实时数据的数据存储。您可以将它与 MapReduce 集成。更好的是,您可以将它与 Hive 和 MapReduce 集成以获得 SQL 功能。

HBase 包含表,并且表被拆分为列族。列族(在架构中声明)将一组特定的列组合在一起(列不需要架构定义)。例如,“message”列族可以包括以下列:“to”、“from”、“date”、“subject”和“body”。 HBase 中的每个键/值对都定义为一个单元格,每个键由 row-key、c​​olumn family、column 和 time-stamp 组成。 HBase 中的一行是由行键标识的一组键/值映射。 HBase 享有 Hadoop 的基础设施并横向扩展。

简而言之,HBase 可以存储或处理具有近乎实时读/写需求的 Hadoop 数据。这包括结构化和非结构化数据,尽管 HBase 擅长后者。 HBase 具有低延迟,可通过 shell 命令、Java API、Thrift 或 REST 访问。 HBase 通常是 Hadoop 集群中的存储层,Adobe 等大型品牌利用 HBase 来满足其所有 Hadoop 存储需求。

HBase的核心特性

HBase 通过将数据存储为模仿 Google 的 Bigtable 的键/值来工作。它支持四种主要操作:添加或更新行、扫描以检索一系列单元格、返回指定行的单元格以及删除以从表中删除行、列或列版本。版本控制是可用的,因此它可以获取数据的先前值(历史记录不时删除以通过 HBase 压缩清理空间)。尽管 HBase 包含表,但仅表和列族需要模式,列不需要模式,并且它包括增量/计数器功能。

以下是 HBase 的一些功能:

它支持键值

它是一个支持随机读/写操作的 NoSQL 数据库

中型对象 (MOB) 支持

HBase 支持协处理器。这对于计算海量数据非常有用,并且操作类似于 MapReduce 作业,并具有一些额外的好处。

允许您利用 Apache Phoenix

您可以执行扫描操作

Hive 和 HBase 的局限性是什么?

每个工具都有自己的优缺点。因此,Hive 和 HBase 总是存在某些限制。阅读下面的这些限制。

Hive限制

首先,Hive 具有非常基本的 ACID 功能。他们到达了 Hive 0.14,但没有 MYSQL 等产品的成熟度。也就是说,仍然有 ACID 支持,并且每个补丁都会变得更好。

Hive 查询通常也具有高延迟。由于它在 Hadoop 上运行批处理,因此可能需要几分钟甚至几小时才能获得查询结果。此外,更新数据可能既复杂又耗时。

Hive 在小数据查询(尤其是大容量数据)方面并不是最好的,大多数用户倾向于依靠传统的 RDBMS 来处理这些数据集。

HBase 限制

HBase 查询采用自定义语言,需要经过培训才能学习。类似 SQL 的功能可以通过 Apache Phoenix 实现,尽管它是以维护模式为代价的。此外,HBase 并不完全符合 ACID,尽管它确实支持某些属性。最后但同样重要的是——为了运行 HBase,你需要 ZooKeeper——一个用于分布式协调的服务器,例如配置、维护和命名。

HBase 可以通过协同处理来处理小数据,但它仍然不如 RDBMS 有用。

实践中的 Hive 和 HBase

正如 Hive 和 HBase 在某些场景中有其局限性一样,它们也有它们蓬勃发展的特定场景。在下面的实践中阅读 Hive 和 HBase。

Hive使用场景

Hive 应该用于对一段时间内收集的数据进行分析查询——例如,计算趋势或网站日志。

我们通常会看到两个 Hive 用例:

HDFS 的 SQL 查询引擎 – Hive 可以成为 SQL 查询的重要来源。您可以利用 Hive 处理 Hadoop 数据湖并将它们连接到您的 BI 工具(如 Tableau)以实现可见性。

具有 HBase、Pig、Spark 或 Tez 的表存储层。大量 HDFS 工具使用 Hive 作为表存储层。从技术上讲,这可能是其最大的全球用例。

Hive 使用的真实例子

目前有超过 4,330 家公司品牌使用 Hive。这比使用 HBase 少,但仍然有很多品牌——尤其是因为大多数公司仍在运行 SQL 堆栈。

Scribd 将 Hive 典型的数据科学用例与 Hadoop 结合使用。这包括机器学习、数据挖掘和 BI 工具的临时查询。确实,Scribd 使用 Hive 作为其整体 Hadoop 堆栈的一部分——这是它最适合的地方。您可以将 Hive 和 HBase 放在同一个集群上进行存储、处理和即席查询。

MedHelp 将 Hive 用于其 Find a Doctor 功能。他们每天在 Hadoop 堆栈上处理数百万个查询,而 Hive 像专业人士一样处理它。

Last.fm 还使用 Hive 进行临时查询。再次,这就是 Hive 的亮点。如果您需要在 Hadoop 上进行临时查询,请使用 Hive。

HubSpot、hi5、eHarmony 和 CNET 也使用 Hive 进行查询。

HBase 使用场景

HBase 非常适合实时查询大数据(例如 Facebook 曾经将其用于消息传递)。 Hive 不应该用于实时查询,因为结果需要一段时间。

HBase 主要用于将非结构化 Hadoop 数据作为湖存储和处理。您也可以使用 HBase 作为所有 Hadoop 数据的仓库,但我们主要看到它用于写入繁重的操作。

HBase 使用的真实使用场景

几乎所有这些案例都将使用 HBase 作为 Hadoop 的存储和处理工具——这是它自然适合的地方。

Adobe 自推出以来一直在运行 HBase。他们的第一个节点早在 2008 年就启动了,他们目前将 HBase 用于他们的 30 个 HDFS 节点。他们将其用于内部结构化数据和非结构化外部数据。

Flurry 使用 HBase 运行 50 个 HDFS 节点,它使用 HBase 处理数百亿行。

HubSpot 主要使用 HBase 进行客户数据存储。作为 HDFS 堆栈的一部分,他们还使用 Hive 对该 HBase 数据运行查询。

Twitter 也在他们的 Hadoop 堆栈中使用 HBase。它用于用户搜索的内部数据。

Streamy 从 SQL 切换到带有 HBase 的 Hadoop 堆栈。他们声称能够比以往更快地处理。

Sematext(为 HBase 创建 SMP)使用 HBase 和 MapReduce 堆栈。同样,这两者可以很好地协同工作(通常通过 Hive 加以利用),因为它们完美地互补了彼此的优缺点。 超过 10,000 家企业使用 HBase。而且大部分都很大。在当前的技术生态系统中,大品牌倾向于更频繁地利用 Hadoop,因此 HBase 往往处于一些大堆栈中(例如,TCS、Marin Software、Taboola、KEYW Corp 等)

作者 east
Spark 3月 24,2022

生产环境选型考虑:5款大数据流处理平台

实时分析可以让您及时了解当前正在发生的事情,例如目前有多少人正在阅读您的新博客文章,以及是否有人喜欢您最新的 Facebook 状态。对于大多数平台分析来说,实时是一个不错的功能,它不会提供任何额外的功能。然而,有时实时处理是必须的。

假设您经营一家大型广告公司。实时分析可以让您随时了解最新的在线广告活动(您的客户花费大量资金购买)是否真的有效,如果没有,您可以在预算进一步花费之前立即进行更改。另一个用例是为您自己的应用程序提供实时分析——它看起来不错,您的用户可能需要它。

实时分析可以让您及时了解当前正在发生的事情,例如目前有多少人正在阅读您的新博客文章,以及是否有人喜欢您最新的 Facebook 状态。对于大多数用例来说,实时是一个不错的功能,它不会提供任何重要的见解。然而,有时实时是必须的。

假设您经营一家大型广告公司。实时分析可以让您随时了解您的最新在线广告活动(您的客户支付了大量资金)是否真的有效。如果不是,您可以在预算进一步花费之前立即进行更改。另一个用例是为您自己的应用程序提供实时分析。毕竟,这样做看起来不错,您的用户甚至可能需要它。

那里有很多实时平台。他们中的很多人都是新人,他们之间的区别并不是每个人都清楚。我们至少可以提供所有选项供您选择,因此这里有五个可用于大数据的实时流媒体平台。

1. Apache Flink

Apache Flink 是一个开源流媒体平台,在复杂流处理方面速度极快。事实上,它能够在几毫秒内处理实时流,因为它可以被编程为仅在实时通过大数据行时处理新的、更改的数据。通过这种方式,Flink 可以轻松实现大规模的批处理和流处理,以提供实时洞察,因此这个平台以提供低延迟和高性能着称也就不足为奇了

Flink 著名的另一个特性是容错,这意味着系统故障不会影响整个集群。它还设计为在完成计算的同时在任何集群环境中运行,使其成为一种可靠、快速的解决方案,恰好可以根据需要轻松扩展。精确一次语义的添加和预定义运算符的存在有助于在该平台上进行实时处理。

请注意,Flink 可以将事件流处理为有界或无界数据集。使用无界流,没有定义的结束并且可以始终如一地处理。另一方面,有界的事件流将作为批处理进行处理,并具有定义的开始和结束。这提供了一定的灵活性,因为程序可以用多种语言编写,例如 Python、Scala、SQL 和 Java。最后,Flink 以其易用性和易于与其他开源大数据处理工具(如 Kafka 和 Hadoop)集成而闻名。

2.Spark

另一个以速度和易用性着称的开源数据处理框架是 Spark。该平台在集群的 RAM 上运行在内存中,并且不依赖于 Hadoop 的 MapReduce 两阶段范式,这在大数据处理方面增加了其闪电般的快速性能。

它不仅可以轻松完成大型数据集的处理任务,还可以将它们分布在多台计算机上。此外,它还可以创建数据管道、处理数据流和图表等等。这就是为什么它是领先的实时流媒体平台之一,从批处理和机器学习到大规模 SQL 和流式大数据。事实上,英特尔、雅虎、Groupon、趋势科技和百度等公司已经在依赖 Apache Stream。

Spark 可以在独立集群模式或 Hadoop YARN 之上运行,它可以直接从 HDFS 读取数据。它还可以在 EC2、Mesos、Kubernetes、云等上运行。此外,Spark 用户可以使用 Python、SQL、R、Scala 或 Java 轻松编写应用程序,使其用途广泛且易于使用。这些功能是 Spark 成为当今顶级实时流媒体平台之一的原因。

3. Storm

Storm 是一个免费的分布式实时计算系统,它致力于实现 Hadoop 为批处理所做的工作。换句话说,它是一种用于处理无限大数据流的简单解决方案。使用 Storm 的一些大品牌包括 Spotify、Yelp 和 WebMD。

Storm 的一大好处是它被设计用于任何编程语言,为用户提供了很大的灵活性。此外,还有几个用例,包括实时分析、机器学习、ETL、连续计算等。与当今许多最好的实时流媒体平台一样,它速度很快,可确保在几毫秒内处理大数据。

关于 Storm 的其他一些需要了解的事实是,它具有容错性、可扩展性,并且易于与您可能已经在使用的技术集成。特别是,它运行在 Hadoop YARN 之上,可以与 Flume 一起使用,将数据存储在 HDFS 上。因此,在使用 Storm 时,无论您喜欢哪种编程语言,您都可以在一个易于设置和使用的平台上快速处理您的数据。

4. Apache Samza

Samza 是一个开源分布式流处理框架,允许用户构建可以实时处理来自多个来源的大数据的应用程序。它基于 Apache Kafka 和 YARN,但也可以作为独立库运行。 LinkedIn 最初开发了 Samza,但从那时起,其他大品牌也开始使用它,例如 eBay、Slack、Redfin、Optimizely 和 TripAdvisor。

Samza 提供了一个简单的基于回调的 API,类似于 MapReduce,它包括快照管理。它还以持久和可扩展的方式提供容错,以及有状态的处理和隔离。它与其他批处理系统(例如 Spark 或 Hadoop)真正区别开来的一个特性是它提供了连续的计算和输出,使其响应时间非常快。

总体而言,Samza 以为超快速数据分析提供非常高的吞吐量和低延迟而闻名。这使其成为为处理大数据而构建的众多平台中的流行选择。

5.Amazon Kinesis

Kinesis 是 Amazon 用于在云上实时处理流数据的服务。这种分析解决方案能够避免像 Hadoop 这样的工具所存在的批处理问题。正因为如此,Kinesis 在大数据处理方面能够更好地提供实时精度,因为它每小时可以处理多达数百 TB 的数据。

该服务的功能使您可以开发需要实时数据的应用程序。毕竟,借助 Kinesis,您可以使用此服务立即摄取、缓冲和处理您的数据,无论是视频、音频、网站点击流还是其他媒体。您不必等待首先收集所有数据,因为它可以在到达时进行处理。这使您可以在几分钟内获得人工智能、机器学习等的分析。 Kinesis 也是可扩展的,因为它可以以低延迟处理来自众多来源的大量流数据。

此外,Kinesis 通过连接器与其他 Amazon 服务集成,包括 Redshift、S3、DynamoDB,以形成完整的大数据架构。该工具还包括 Kinesis Client Library (KCL),它允许您构建应用程序并将流数据用于仪表板、警报甚至动态定价。

作者 east
Hadoop, Spark 3月 23,2022

企业生产环境考虑:Spark 全方位对比 Hadoop MapReduce

Apache Spark 与 Hadoop MapReduce 的五个主要区别:
1、Apache Spark 可能比 Hadoop MapReduce 快 100 倍。
2、Apache Spark 使用 内存,并且不依赖于 Hadoop 的两阶段范式。
3、Apache Spark 适用于可以全部放入服务器 内存 的较小数据集。
4、Hadoop 处理海量数据集更具成本效益。
5、Apache Spark 现在比 Hadoop MapReduce 更受欢迎。
多年来,Hadoop 一直是大数据无可争议的首选——直到 Spark 出现。自 2014 年首次发布以来,Apache Spark 一直在点燃大数据世界。凭借 Spark 便捷的 API 和承诺的速度比 Hadoop MapReduce 快 100 倍,一些分析人士认为,Spark 标志着大数据新时代的到来。

Spark 是一个开源数据处理框架,如何能够如此快速地处理所有这些信息?秘诀在于 Spark 在集群上运行在内存中,它不依赖于 Hadoop 的 MapReduce 两阶段范式。这使得重复访问相同数据的速度更快。 Spark 可以作为独立应用程序运行,也可以在 Hadoop YARN 之上运行,它可以直接从 HDFS 读取数据。雅虎、英特尔、百度、Yelp 和 Zillow 等数十家主要科技公司已经将 Spark 作为其技术堆栈的一部分。

虽然 Spark 似乎注定要取代 Hadoop MapReduce,但您现在还不应该指望 MapReduce。在这篇文章中,我们将比较这两个平台,看看 Spark 是否真的非常有优势。

什么是 Apache Spark?
Apache Spark 是“用于大规模数据处理的统一分析引擎”。 Spark 由非营利性的 Apache Software Foundation 维护,该基金会已经发布了数百个开源软件项目。自项目启动以来,已有 1200 多名开发人员为 Spark 做出了贡献。

Spark 最初是在加州大学伯克利分校的 AMPLab 开发的,于 2010 年首次作为开源项目发布。Spark 使用 Hadoop MapReduce 分布式计算框架作为其基础。 Spark 旨在改进 MapReduce 项目的几个方面,例如性能和易用性,同时保留 MapReduce 的许多优点。

Spark 包括一个核心数据处理引擎,以及用于 SQL、机器学习和流处理的库。凭借适用于 Java、Scala、Python 和 R 的 API,Spark 在开发人员中享有广泛的吸引力——为其赢得了大数据处理领域“瑞士军刀”的美誉。

什么是 Hadoop MapReduce?
Hadoop MapReduce 将自己描述为“一个用于轻松编写应用程序的软件框架,该应用程序以可靠、容错的方式在大型商用硬件集群(数千个节点)上并行处理大量数据(多 TB 数据集)。”

MapReduce 范式由两个顺序任务组成:Map 和 Reduce(因此得名)。 Map 过滤和排序数据,同时将其转换为键值对。然后,Reduce 接受此输入并通过对数据集执行某种汇总操作来减小其大小。

MapReduce 可以通过分解大型数据集并并行处理它们来极大地加速大数据任务。 MapReduce 范式由 Google 员工 Jeff Dean 和 Sanjay Ghemawat 于 2004 年首次提出;后来它被整合到 Apache 的 Hadoop 框架中以进行分布式处理。

Spark 和 MapReduce 的区别
Apache Spark 和 Hadoop MapReduce 之间的主要区别是:

>性能
>易于使用
>数据处理
>安全
然而,Spark 和 MapReduce 之间也有一些相似之处——这并不奇怪,因为 Spark 使用 MapReduce 作为其基础。 Spark 和 MapReduce 的相似点包括:

>成本
>兼容性
>容错
下面,我们将在每个部分详细介绍 Spark 和 MapReduce 之间的差异(以及相似之处)。

Spark VS MapReduce:性能
Apache Spark 在随机存取存储器 (RAM) 中处理数据,而 Hadoop MapReduce 在执行映射或归约操作后将数据持久化回磁盘。那么理论上,Spark 的性能应该优于 Hadoop MapReduce。尽管如此,Spark 需要大量内存。与标准数据库非常相似,Spark 将进程加载到内存中并保留在那里,直到进一步通知以进行缓存。如果您在 Hadoop YARN 上运行 Spark 和其他需要资源的服务,或者如果数据太大而无法完全放入内存,那么 Spark 可能会遭受严重的性能下降。

MapReduce 会在作业完成后立即终止其进程,因此它可以轻松地与性能差异很小的其他服务一起运行。

对于需要多次传递相同数据的迭代计算,Spark 具有优势。但是,当涉及到类似 ETL 的一次性作业时——例如,数据转换或数据集成——这正是 MapReduce 的设计目的。

小结:当所有数据都适合内存时,Spark 性能更好,尤其是在专用集群上。 Hadoop MapReduce 专为无法放入内存的数据而设计,并且可以与其他服务一起很好地运行。

Spark VS Hadoop MapReduce:易用性
Spark 为 Java、Scala 和 Python 提供了预构建的 API,还包括用于 SQL 的 Spark SQL(以前称为 Shark)。由于 Spark 的简单构建块,编写用户定义的函数很容易。 Spark 甚至包括用于运行命令并立即反馈的交互模式。

MapReduce 是用 Java 编写的,并且非常难以编程。 Apache Pig 让它变得更容易(尽管它需要一些时间来学习语法),而 Apache Hive 则增加了 SQL 兼容性。一些 Hadoop 工具也可以在没有任何编程的情况下运行 MapReduce 作业。

此外,虽然 Hive 包含命令行界面,但 MapReduce 没有交互模式。 Apache Impala 和 Apache Tez 等项目希望将完整的交互式查询引入 Hadoop。

在安装和维护方面,Spark 不受 Hadoop 的约束。 Spark 和 Hadoop MapReduce 都包含在 Hortonworks (HDP 3.1) 和 Cloudera (CDH 5.13) 的发行版中。

小结:Spark 更易于编程,并且包含交互模式。 Hadoop MapReduce 更难编程,但有几个工具可以使它更容易。

Spark VS Hadoop MapReduce:成本
Spark 和 MapReduce 是开源解决方案,但您仍然需要在机器和人员上花钱。 Spark 和 MapReduce 都可以使用商品服务器并在云上运行。此外,这两种工具都有相似的硬件要求:


Spark 集群中的内存至少应该与您需要处理的数据量一样大,因为数据必须适合内存才能获得最佳性能。如果您需要处理大量数据,Hadoop 肯定是更便宜的选择,因为硬盘空间比内存空间便宜得多。

另一方面,考虑到 Spark 和 MapReduce 的性能,Spark 应该更划算。 Spark 需要更少的硬件来更快地执行相同的任务,尤其是在计算能力按使用付费的云服务器上。

人员配备问题呢?尽管 Hadoop 自 2005 年就已经存在,但市场上仍然缺乏 MapReduce 专家。根据 Gartner 的一份研究报告,57% 的使用 Hadoop 的组织表示“获得必要的技能和能力”是他们最大的 Hadoop 挑战。

那么这对于自 2010 年才出现的 Spark 来说意味着什么呢?虽然它可能有更快的学习曲线,但 Spark 也缺乏合格的专家。好消息是,有大量 Hadoop 即服务产品和基于 Hadoop 的服务(如 Integrate.io 自己的数据集成服务),这有助于缓解这些硬件和人员配备要求。同时,Spark 即服务选项可通过 Amazon Web Services 等提供商获得。

小结:根据基准,Spark 更具成本效益,但人员配备成本可能更高。 Hadoop MapReduce 可能会更便宜,因为可用的人员更多,而且对于海量数据量来说可能更便宜。

Spark VS Hadoop MapReduce:兼容性
Apache Spark 可以作为独立应用程序在 Hadoop YARN 或 Apache Mesos 内部部署或云中运行。 Spark 支持实现 Hadoop 输入格式的数据源,因此它可以与 Hadoop 支持的所有相同数据源和文件格式集成。

Spark 还通过 JDBC 和 ODBC 与商业智能工具一起工作。

底线:Spark 对各种数据类型和数据源的兼容性与 Hadoop MapReduce 相同。

Spark vs Hadoop MapReduce:数据处理
Spark 可以做的不仅仅是简单的数据处理:它还可以处理图形,它包括 MLlib 机器学习库。由于其高性能,Spark 可以进行实时处理和批处理。 Spark 提供了一个“一刀切”的平台供您使用,而不是在不同的平台上拆分任务,这会增加您的 IT 复杂性。

Hadoop MapReduce 非常适合批处理。如果你想要一个实时选项,你需要使用另一个平台,比如 Impala 或 Apache Storm,而对于图形处理,你可以使用 Apache Giraph。 MapReduce 曾经有 Apache Mahout 用于机器学习,但后来被 Spark 和 H2O 抛弃了。

小结:Spark 是数据处理的瑞士军刀,而 Hadoop MapReduce 是批处理的突击刀。

Spark vs Hadoop MapReduce:容错
Spark 具有每个任务的重试和推测执行,就像 MapReduce 一样。尽管如此,MapReduce 在这里有一点优势,因为它依赖于硬盘驱动器,而不是 RAM。如果 MapReduce 进程在执行过程中崩溃,它可以从中断的地方继续,而 Spark 必须从头开始处理。

小结:Spark 和 Hadoop MapReduce 都具有良好的容错性,但 Hadoop MapReduce 的容错性稍强一些。

Spark VS Hadoop MapReduce:安全性
在安全性方面,与 MapReduce 相比,Spark 没有那么先进。事实上,Spark 中的安全性默认设置为“关闭”,这会使您容易受到攻击。 RPC 通道支持通过共享密钥在 Spark 中进行身份验证。 Spark 将事件日志记录作为一项功能,并且可以通过 javax servlet 过滤器保护 Web UI。此外,由于 Spark 可以运行在 YARN 上并使用 HDFS,因此还可以享受 Kerberos 身份验证、HDFS 文件权限以及节点之间的加密。

Hadoop MapReduce 可以享受所有 Hadoop 安全优势并与 Hadoop 安全项目集成,例如 Knox Gateway 和 Apache Sentry。旨在提高 Hadoop 安全性的 Project Rhino 仅在添加 Sentry 支持方面提到了 Spark。否则,Spark 开发人员将不得不自己提高 Spark 的安全性。

小结:与具有更多安全功能和项目的 MapReduce 相比,Spark 安全性仍然欠发达。

Spark 的常用场景
虽然两者都是大规模数据处理的强大选项,但某些情况下,其中一种比另一种更理想。

流数据处理
随着公司走向数字化转型,他们正在寻找实时分析数据的方法。 Spark 的内存数据处理使其成为处理流数据的理想选择。 Spark Streaming 是 Spark 的一个变体,它使这个用例成为可能。那么,公司可以通过哪些方式利用 Spark Streaming?

流式 ETL – 在传统的 ETL 过程中,数据被读取、转换为兼容格式并保存到目标数据存储中。使用 Streaming ETL 的过程效率更高,因为数据在保存到目标数据存储之前会在内存中不断清理和聚合。

数据丰富——公司在尝试适应和提供更增强的客户体验时处于不断变化的状态。通过将实时数据与静态数据相结合,公司可以构建更可靠的客户画像,从而为他们提供个性化体验。

触发事件检测——实时响应事件的能力是一项重要的业务能力,有助于提高敏捷性和适应变化的能力。借助 Spark Streaming,公司可以实时分析数据,以识别需要立即关注的异常活动。

机器学习
在预测分析方面,Spark 的机器学习库 (MLib) 提供了一套强大的工具,可以轻松完成它。当用户对一组数据进行重复查询时,他们本质上是在构建类似于机器学习的算法。例如,机器学习可以帮助公司出于营销目的进行客户细分。它还可以帮助执行情绪分析。

交互式查询
想象一下能够对实时数据执行交互式查询。从本质上讲,您可以分析大型数据集,而无需依赖外部数据存储来处理信息。使用 Spark Streaming,您可以查询数据流,而无需将其持久化到外部数据库。

MapReduce 的常用场景
当处理对于内存中操作来说太大的数据时,MapReduce 是要走的路。因此,MapReduce 最适合处理大型数据集。

处理大型数据集(PB或TB)
考虑到实施和维护所需的时间和费用,千兆字节大小不足以证明 MapReduce 的合理性。希望管理PB或TB数据的组织是 MapReduce 的理想选择。

以不同格式存储数据
公司可以使用 MapReduce 处理多种文件类型,例如文本、图像、纯文本等。由于这些文件对于内存中的处理来说太大了,使用 MapReduce 进行批处理更经济。

数据处理
MapReduce 具有对大型数据集执行基本和复杂分析的强大功能。通过使用基于磁盘的存储而不是内存中的处理,对大型数据集进行汇总、过滤和连接等任务的效率要高得多。

Spark 与 Hadoop MapReduce 趋势

随着公司寻找在拥挤的市场中保持竞争力的新方法,他们将需要适应即将到来的数据管理趋势。这些趋势包括:

XOps – 使用 DevOps 的最佳实践,XOps 的目标是在数据管理过程中实现可靠性、可重用性和可重复性。

Data Fabric – 作为一个架构框架,Data Fabric 的目标是在一个无缝的数据管理平台中结合多种类型的数据存储、分析、处理和安全性

数据分析作为核心业务功能 – 传统上,数据管理由一个单独的团队处理,该团队分析数据并将其提供给关键业务领导者。然而,一种新方法将这些数据直接交到组织领导者手中,这样他们就可以立即访问这些信息以进行决策。

结论
Apache Spark 可能比 Hadoop MapReduce 快 100 倍。
Apache Spark 使用 RAM,并且不依赖于 Hadoop 的两阶段范式。
Apache Spark 适用于可以全部放入服务器 RAM 的较小数据集。
Hadoop 处理海量数据集更具成本效益。
Apache Spark 现在比 Hadoop MapReduce 更受欢迎。
Apache Spark 是大数据平台上闪亮的新玩具,但仍有使用 Hadoop MapReduce 的用例。无论您选择 Apache Spark 还是 Hadoop MapReduce,

Spark具有出色的性能,并且具有很高的成本效益,这得益于其内存数据处理。它与 Hadoop 的所有数据源和文件格式兼容,并且学习曲线更快,并具有可用于多种编程语言的友好 API。 Spark 甚至包括图形处理和机器学习功能。

Hadoop MapReduce 是一个更成熟的平台,它是专门为批处理而构建的。对于无法放入内存的超大数据,MapReduce 比 Spark 更具成本效益,而且可能更容易找到具有 MapReduce 经验的员工。此外,由于许多支持项目、工具和云服务,MapReduce 生态系统目前更大。

但即使你认为 Spark 看起来像这里的赢家,你也很可能不会单独使用它。您仍然需要 HDFS 来存储数据,并且您可能想要使用 HBase、Hive、Pig、Impala 或其他 Hadoop 项目。这意味着您仍然需要与 Spark 一起运行 Hadoop 和 MapReduce 以获得完整的大数据包。

作者 east
Elasticsearch, spring 3月 22,2022

Spring Boot直接输出到Logstash

Spring Boot应用程序可以直接远程输出到Logstash。这里以Logback日志为例,新建项目,在项目中加入Logstash依赖。

1、 要使用logback一个插件来将数据转成json,引入maven配置

dependency>

      <groupId>net.logstash.logback</groupId>

      <artifactId>logstash-logback-encoder</artifactId>

     <version>5.3</version>

</dependency>



2、配置 logback-spring.xml

接下来,在src/resources目录下创建logback-spring.xml配置文件,在配置文件中将对日志进行格式化,并且输出到控制台和Logstash。需要注意的是,在destination属性中配置的地址和端口要与Logstash输入源的地址和端口一致,比如这里使用的是127.0.0.1:4560,则在Logstash输入源中要与这个配置一致。其中logback-spring.xml内容如

<xml version="1.0" encoding="UTF-8"?>

    <configuration scan="true" scanPeriod="60 seconds" debug="true">

         <contextName>logstash-test</contextName>

   <!-- 这个是控制台日志输出格式 方便调试对比--->

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">

      <encoder>

          <pattern>%d{yyyy-MM-dd HH:mm:ss} %contextName %-5level %logger{50} -%msg%n</pattern>

   </encoder>

</appender>

<appender name="stash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">

  <destination>127.0.0.1:4560</destination> 这是是logstash服务器地址 端口

  <encoder class="net.logstash.logback.encoder.LogstashEncoder" /> 输出的格式,推荐使用这个

</appender>

<root level="info">

   <appender-ref ref="console"/>

   <appender-ref ref="stash"/>

</root>

启动项目,就会请求127.0.0.1:4560,如果有监听,就会自动发送日志。

3、logstash配置

input {

             tcp {

                        host => "localhost" #这个一定要是logstash本机ip,不然logstash 无法启动,也可以去除

                        port => 4560

                       codec => json_lines

                       mode => "server"

                  }

}

filter {

                 grok {

               match => {

"message" => "%{URIPATH:request} %{IP:clientip} %{NUMBER:response:int} \"%{WORD:sources}\" (?:%{URI:referrer}|-) \[%{GREEDYDATA:agent}\] \{%{GREEDYDATA:params}\}"

     }

}


output {

       stdout { codec => rubydebug } #标准输出,在命令行中输出方便调试

elasticsearch { hosts => [ "localhost:9200" ]

index => "pybbs"

document_type => "weblog"

    }

}

如果数据特别多,上述方案就会为Elasticsearch带来很大的压力。为了缓解Elasticsearch的压力,可以将Logstash收集的内容不直接输出到Elasticsearch中,而是输出到缓冲层,比如Redis或者Kafka,然后使用一个Logstash从缓冲层输出到Elasticsearch。当然,还有很多种方案进行日志收集,比如使用Filebeat替换Logstash等。笔者在生产环节搭建过ELK配置,这里提几点建议:

(1)根据日志量判断Elasticsearch的集群选择,不要盲目追求高可用,实际应用需要根据实际场景的预算等因素使用。

(2)缓冲层选择,一般来说选择Kafka和Redis。虽然Kafka作为日志消息很适合,具备高吞吐量等,但是如果需求不是很大,并且环境中不存在Kafka,就没有必要使用Kafka作为消息缓存层,使用现有的Redis也未尝不可。

(3)内存分配,ELK三者部署都是占有一定内存的,并且官网建议的配置都很大。建议结合场景来修改配置,毕竟预算是很重要的一环。

作者 east

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

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

标签

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

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • 解决gitlab配置Webhooks,提示 Invalid url given的问题
  • 如何在Chrome中设置启动时自动打开多个默认网页
  • 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工具链解耦?

文章归档

  • 2025年10月
  • 2025年8月
  • 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)
  • 前端 (5)
  • 大数据开发 (494)
    • CDH (6)
    • datax (4)
    • doris (31)
    • Elasticsearch (15)
    • Flink (79)
    • 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)
    • 运维 (36)
      • 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)
  • 未分类 (8)
  • 程序员网赚 (20)
    • 广告联盟 (3)
    • 私域流量 (5)
    • 自媒体 (5)
  • 量化投资 (4)
  • 面试 (14)

功能

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

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