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

标签归档机器学习

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

  • 首页   /  
  • 标签: "机器学习"
Keras 4月 15,2022

如何在 Keras 中使用词嵌入层进行深度学习

词嵌入提供了词及其相对含义的密集表示。

它们是对更简单的词袋模型表示中使用的稀疏表示的改进。

词嵌入可以从文本数据中学习并在项目之间重用。它们也可以作为在文本数据上拟合神经网络的一部分来学习。

在本教程中,您将了解如何使用 Keras 在 Python 中使用词嵌入进行深度学习。

完成本教程后,您将了解:

关于词嵌入以及 Keras 通过嵌入层支持词嵌入。
如何在拟合神经网络的同时学习词嵌入。
如何在神经网络中使用预训练的词嵌入。
从我的新书《自然语言处理的深度学习》开始您的项目,包括分步教程和所有示例的 Python 源代码文件。

让我们开始吧。

2018 年 2 月更新:修复了由于底层 API 更改而导致的错误。
2019 年 10 月更新:针对 Keras 2.3 和 TensorFlow 2.0 进行了更新。

教程概述
本教程分为 3 个部分; 他们是:

词嵌入
Keras 嵌入层
学习嵌入的例子
使用预训练手套嵌入的示例

1.词嵌入
词嵌入是一类使用密集向量表示来表示词和文档的方法。

这是对传统的词袋模型编码方案的改进,在传统的词袋模型编码方案中,使用大的稀疏向量来表示每个单词或对向量中的每个单词进行评分以表示整个词汇表。这些表示是稀疏的,因为词汇量很大,并且给定的单词或文档将由一个主要由零值组成的大向量表示。

相反,在嵌入中,单词由密集向量表示,其中向量表示单词在连续向量空间中的投影。

向量空间中单词的位置是从文本中学习的,并且基于使用该单词时围绕该单词的单词。

单词在学习向量空间中的位置称为它的嵌入。

从文本中学习词嵌入的两个流行示例包括:

Word2Vec。
GloVe。
除了这些精心设计的方法之外,还可以将词嵌入作为深度学习模型的一部分进行学习。这可能是一种较慢的方法,但会根据特定的训练数据集定制模型。

2、Keras嵌入层
Keras 提供了一个嵌入层,可用于文本数据上的神经网络。

它要求对输入数据进行整数编码,以便每个单词都由一个唯一的整数表示。这个数据准备步骤可以使用 Keras 提供的 Tokenizer API 来执行。

Embedding 层使用随机权重初始化,并将学习训练数据集中所有单词的嵌入。

它是一个灵活的层,可以以多种方式使用,例如:

它可以单独用来学习一个词嵌入,以后可以保存并在另一个模型中使用。
它可以用作深度学习模型的一部分,其中嵌入与模型本身一起学习。
它可用于加载预训练的词嵌入模型,一种迁移学习。
Embedding 层被定义为网络的第一个隐藏层。它必须指定 3 个参数:

它必须指定 3 个参数:

input_dim:这是文本数据中词汇的大小。例如,如果您的数据被整数编码为 0-10 之间的值,那么词汇表的大小将为 11 个单词。
output_dim:这是嵌入单词的向量空间的大小。它为每个单词定义了该层的输出向量的大小。例如,它可以是 32 或 100 甚至更大。为您的问题测试不同的值。
input_length:这是输入序列的长度,就像您为 Keras 模型的任何输入层定义的一样。例如,如果您的所有输入文档都包含 1000 个单词,那么这将是 1000。
例如,下面我们定义了一个包含 200 个词汇表的 Embedding 层(例如,从 0 到 199 的整数编码词,包括 0 到 199),一个 32 维的向量空间,其中将嵌入词,输入文档每个有 50 个词。


e = Embedding(200, 32, input_length=50)

Embedding 层具有学习的权重。 如果您将模型保存到文件中,这将包括嵌入层的权重。

Embedding 层的输出是一个 2D 向量,对于输入的单词序列(输入文档)中的每个单词都有一个嵌入。

如果您希望将 Dense 层直接连接到 Embedding 层,则必须首先使用 Flatten 层将 2D 输出矩阵展平为 1D 矢量。

现在,让我们看看如何在实践中使用嵌入层。

3、学习嵌入的例子
在本节中,我们将研究如何在将神经网络拟合到文本分类问题时学习词嵌入。

我们将定义一个小问题,我们有 10 个文本文档,每个文档都有一个关于学生提交的作品的评论。 每个文本文档被分类为正“1”或负“0”。 这是一个简单的情感分析问题。

首先,我们将定义文档及其类标签。

# define documents
docs = ['Well done!',
		'Good work',
		'Great effort',
		'nice work',
		'Excellent!',
		'Weak',
		'Poor effort!',
		'not good',
		'poor work',
		'Could have done better.']
# define class labels
labels = array([1,1,1,1,1,0,0,0,0,0])

接下来,我们可以对每个文档进行整数编码。 这意味着作为输入,嵌入层将具有整数序列。 我们可以尝试其他更复杂的词模型编码包,如计数或 TF-IDF。

Keras 提供了 one_hot() 函数,该函数将每个单词的散列创建为有效的整数编码。 我们将估计词汇量为 50,这比减少散列函数冲突概率所需的要大得多。

# integer encode the documents
vocab_size = 50
encoded_docs = [one_hot(d, vocab_size) for d in docs]
print(encoded_docs)

序列具有不同的长度,Keras 更喜欢对输入进行矢量化,并且所有输入都具有相同的长度。 我们将填充所有输入序列的长度为 4。同样,我们可以使用内置的 Keras 函数来完成此操作,在本例中为 pad_sequences() 函数。

# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)

我们现在准备将嵌入层定义为神经网络模型的一部分。

Embedding 的词汇量为 50,输入长度为 4。我们将选择一个 8 维的小嵌入空间。

该模型是一个简单的二元分类模型。 重要的是,嵌入层的输出将是 4 个 8 维向量,每个词一个。 我们将其展平为一个 32 元素的向量,以传递给 Dense 输出层。

# define the model
model = Sequential()
model.add(Embedding(vocab_size, 8, input_length=max_length))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# summarize the model
print(model.summary())

最后,我们可以拟合和评估分类模型。

# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))

下面提供了完整的代码清单。

from numpy import array
from keras.preprocessing.text import one_hot
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers.embeddings import Embedding
# define documents
docs = ['Well done!',
		'Good work',
		'Great effort',
		'nice work',
		'Excellent!',
		'Weak',
		'Poor effort!',
		'not good',
		'poor work',
		'Could have done better.']
# define class labels
labels = array([1,1,1,1,1,0,0,0,0,0])
# integer encode the documents
vocab_size = 50
encoded_docs = [one_hot(d, vocab_size) for d in docs]
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
# define the model
model = Sequential()
model.add(Embedding(vocab_size, 8, input_length=max_length))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# summarize the model
print(model.summary())
# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))

运行示例首先打印整数编码的文档。

 
[[6, 16], [42, 24], [2, 17], [42, 24], [18], [17], [22, 17], [27, 42], [22, 24], [49, 46, 16, 34]]

然后打印每个文档的填充版本,使它们都具有统一的长度。

 
[[ 6 16  0  0]
[42 24  0  0]
[ 2 17  0  0]
[42 24  0  0]
[18  0  0  0]
[17  0  0  0]
[22 17  0  0]
[27 42  0  0]
[22 24  0  0]
[49 46 16 34]]

定义网络后,将打印层的摘要。 我们可以看到,正如预期的那样,Embedding 层的输出是一个 4×8 矩阵,它被 Flatten 层压缩为一个 32 元素的向量。

 
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
embedding_1 (Embedding)      (None, 4, 8)              400
_________________________________________________________________
flatten_1 (Flatten)          (None, 32)                0
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 33
=================================================================
Total params: 433
Trainable params: 433
Non-trainable params: 0
_________________________________________________________________

注意:您的结果可能会因算法或评估过程的随机性或数值精度的差异而有所不同。考虑运行该示例几次并比较平均结果。

最后,打印出训练模型的准确率,表明它完美地学习了训练数据集(这并不奇怪)。

精度:100.000000


您可以将学习到的权重从嵌入层保存到文件中,以供以后在其他模型中使用。

您通常也可以使用此模型对测试数据集中具有相同类型词汇的其他文档进行分类。

接下来,让我们看看在 Keras 中加载预训练的词嵌入。

4、使用预训练手套嵌入的示例
Keras Embedding 层也可以使用在其他地方学习的词嵌入。

在自然语言处理领域,学习、保存和免费提供词嵌入是很常见的。

例如,GloVe 方法背后的研究人员在他们的网站上提供了一套预训练的词嵌入,并在公共领域许可下发布。看:

GloVe:单词表示的全局向量
嵌入的最小包为 822Mb,称为“glove.6B.zip”。它在 10 亿个标记(单词)的数据集上进行了训练,词汇量为 40 万个单词。有几种不同的嵌入向量大小,包括 50、100、200 和 300 维。

您可以下载此嵌入集合,我们可以使用来自训练数据集中单词的预训练嵌入的权重为 Keras 嵌入层播种。

这个例子的灵感来自 Keras 项目中的一个例子:pretrained_word_embeddings.py。

下载解压后会看到几个文件,其中一个是“glove.6B.100d.txt”,里面包含了一个100维版本的embedding。

如果您查看文件内部,您将在每行看到一个标记(单词),然后是权重(100 个数字)。例如,下面是嵌入 ASCII 文本文件的第一行,显示了“the”的嵌入。

 
the -0.038194 -0.24487 0.72812 -0.39961 0.083172 0.043953 -0.39141 0.3344 -0.57545 0.087459 0.28787 -0.06731 0.30906 -0.26384 -0.13231 -0.20757 0.33395 -0.33848 -0.31743 -0.48336 0.1464 -0.37304 0.34577 0.052041 0.44946 -0.46971 0.02628 -0.54155 -0.15518 -0.14107 -0.039722 0.28277 0.14393 0.23464 -0.31021 0.086173 0.20397 0.52624 0.17164 -0.082378 -0.71787 -0.41531 0.20335 -0.12763 0.41367 0.55187 0.57908 -0.33477 -0.36559 -0.54857 -0.062892 0.26584 0.30205 0.99775 -0.80481 -3.0243 0.01254 -0.36942 2.2167 0.72201 -0.24978 0.92136 0.034514 0.46745 1.1079 -0.19358 -0.074575 0.23353 -0.052062 -0.22044 0.057162 -0.15806 -0.30798 -0.41625 0.37972 0.15006 -0.53212 -0.2055 -1.2526 0.071624 0.70565 0.49744 -0.42063 0.26148 -1.538 -0.30223 -0.073438 -0.28312 0.37104 -0.25217 0.016215 -0.017099 -0.38984 0.87424 -0.72569 -0.51058 -0.52028 -0.1459 0.8278 0.27062

与上一节一样,第一步是定义示例,将它们编码为整数,然后将序列填充为相同的长度。

在这种情况下,我们需要能够将单词映射到整数以及将整数映射到单词。

Keras 提供了一个适合训练数据的 Tokenizer 类,可以通过调用 Tokenizer 类的 texts_to_sequences() 方法将文本一致地转换为序列,并提供对 word_index 属性中单词到整数的字典映射的访问。

# define documents
docs = ['Well done!',
		'Good work',
		'Great effort',
		'nice work',
		'Excellent!',
		'Weak',
		'Poor effort!',
		'not good',
		'poor work',
		'Could have done better.']
# define class labels
labels = array([1,1,1,1,1,0,0,0,0,0])
# prepare tokenizer
t = Tokenizer()
t.fit_on_texts(docs)
vocab_size = len(t.word_index) + 1
# integer encode the documents
encoded_docs = t.texts_to_sequences(docs)
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)

接下来,我们需要将整个 GloVe 词嵌入文件加载到内存中,作为词到嵌入数组的字典。

# load the whole embedding into memory
embeddings_index = dict()
f = open('glove.6B.100d.txt')
for line in f:
	values = line.split()
	word = values[0]
	coefs = asarray(values[1:], dtype='float32')
	embeddings_index[word] = coefs
f.close()
print('Loaded %s word vectors.' % len(embeddings_index))

这很慢。 过滤训练数据中唯一单词的嵌入可能会更好。

接下来,我们需要为训练数据集中的每个单词创建一个嵌入矩阵。 我们可以通过枚举 Tokenizer.word_index 中的所有唯一词并从加载的 GloVe 嵌入中定位嵌入权重向量来做到这一点。

结果是一个权重矩阵,仅适用于我们将在训练期间看到的单词。

# create a weight matrix for words in training docs
embedding_matrix = zeros((vocab_size, 100))
for word, i in t.word_index.items():
	embedding_vector = embeddings_index.get(word)
	if embedding_vector is not None:
		embedding_matrix[i] = embedding_vector

现在我们可以像以前一样定义、拟合和评估模型了。

关键区别在于嵌入层可以使用 GloVe 词嵌入权重作为种子。 我们选择了 100 维的版本,因此 Embedding 层必须定义 output_dim 设置为 100。最后,我们不想更新该模型中的学习词权重,因此我们将模型的 trainable 属性设置为 False .

e = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False)

下面列出了完整的代码示例。

from numpy import array
from numpy import asarray
from numpy import zeros
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers import Embedding
# define documents
docs = ['Well done!',
		'Good work',
		'Great effort',
		'nice work',
		'Excellent!',
		'Weak',
		'Poor effort!',
		'not good',
		'poor work',
		'Could have done better.']
# define class labels
labels = array([1,1,1,1,1,0,0,0,0,0])
# prepare tokenizer
t = Tokenizer()
t.fit_on_texts(docs)
vocab_size = len(t.word_index) + 1
# integer encode the documents
encoded_docs = t.texts_to_sequences(docs)
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
# load the whole embedding into memory
embeddings_index = dict()
f = open('../glove_data/glove.6B/glove.6B.100d.txt')
for line in f:
	values = line.split()
	word = values[0]
	coefs = asarray(values[1:], dtype='float32')
	embeddings_index[word] = coefs
f.close()
print('Loaded %s word vectors.' % len(embeddings_index))
# create a weight matrix for words in training docs
embedding_matrix = zeros((vocab_size, 100))
for word, i in t.word_index.items():
	embedding_vector = embeddings_index.get(word)
	if embedding_vector is not None:
		embedding_matrix[i] = embedding_vector
# define model
model = Sequential()
e = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False)
model.add(e)
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# summarize the model
print(model.summary())
# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))

注意:您的结果可能会因算法或评估过程的随机性或数值精度的差异而有所不同。 考虑运行该示例几次并比较平均结果。

运行该示例可能需要更长的时间,但随后证明它同样能够解决这个简单的问题。

[[6, 2], [3, 1], [7, 4], [8, 1], [9], [10], [5, 4], [11, 3], [5, 1], [12, 13, 2, 14]]
 
[[ 6  2  0  0]
 [ 3  1  0  0]
 [ 7  4  0  0]
 [ 8  1  0  0]
 [ 9  0  0  0]
 [10  0  0  0]
 [ 5  4  0  0]
 [11  3  0  0]
 [ 5  1  0  0]
 [12 13  2 14]]
 
Loaded 400000 word vectors.
 
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
embedding_1 (Embedding)      (None, 4, 100)            1500
_________________________________________________________________
flatten_1 (Flatten)          (None, 400)               0
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 401
=================================================================
Total params: 1,901
Trainable params: 401
Non-trainable params: 1,500
_________________________________________________________________
 
 
Accuracy: 100.000000

在实践中,我鼓励您尝试使用固定的预训练嵌入来学习词嵌入,并尝试在预训练嵌入之上执行学习。

看看什么最适合您的特定问题。

总结
在本教程中,您了解了如何通过 Keras 在 Python 中使用词嵌入进行深度学习。

具体来说,您了解到:

关于词嵌入以及 Keras 通过嵌入层支持词嵌入。
如何在拟合神经网络的同时学习词嵌入。
如何在神经网络中使用预训练的词嵌入。

作者 east
深度学习 4月 5,2022

Word Embedding的几种模型和示例

介绍

人类有能力理解单词并轻松地从中获取含义。然而,在当今世界,大多数任务都是由计算机执行的。例如,如果您想知道今天是晴天还是下雨天,则必须在 Google 中输入文本查询。现在的问题是,机器将如何频繁地理解和处理文本中呈现的如此大量的信息?答案是词嵌入。

Word Embeddings 基本上是向量(文本转换为数字),用于捕获单词的含义、各种上下文和语义关系。嵌入本质上是使用预定义字典将单词映射到其对应向量。

例如,

句子: It will rain heavily today.

字典:{“it”:[1,0,0,0,0],“will”:[0,1,0,0,0],“rain”:[0,0,1,0,0] , “ heavily ”: [0,0,0,1,0], “today”: [0,0,0,0,1]}

在这里,每个单词都被分配了一个唯一的向量(例如),以便区分所有单词。

Let the corpus comprise three sentences.

S1 = In monsoon, it will rain.

S2 = rain rain come again.

S3 = sun is visible in summer. In the monsoon, the sun is hidden by clouds.

Let N be the list of unique words = [‘monsoon’, ‘rain’, ‘come’, ‘again’, ‘sun’, ‘visible’, ‘summer’, ‘hidden’, ‘clouds’]

计数矩阵的维度将是 3X9,因为语料库中有 3 个文档和 9 个唯一词。
计数矩阵如下所示:

优点:由于只考虑单词的频率,因此计算成本较低。


缺点:由于计算只是基于计数并且没有考虑单词的上下文,因此该方法证明不太有用。
代码:

#Importing libraries
from sklearn.feature_extraction.text import CountVectorizer
import nltk 
from nltk.corpus import stopwords 
from nltk.tokenize import word_tokenize 

#Downloading stopwords and punkt packages
nltk.download('stopwords') 
nltk.download('punkt') 

#Initialising stopwords for english
set(stopwords.words('english')) 

#sample sentences
text = ["In monsoon, it will rain", "rain rain come again", "sun is visible in summer. In the monsoon, the sun is hidden by clouds"]

#set of stop words
stop_words = set(stopwords.words('english')) 
all_sentences = []

#Logic for removing stop words and obtaining filtered sentences from the list 

for i in range(len(text)):
  word_tokens[i] = word_tokenize(text[i]) 
  tokenized_sentence = []

  for j in word_tokens[i]: 
      if j not in stop_words: 
          tokenized_sentence.append(j) 
  all_sentences.append(" ".join(tokenized_sentence))

#Initialising the CountVectorizer
countvectorizer = CountVectorizer()

#Applying CountVectorizer to the list of sentences
X = countvectorizer.fit_transform(all_sentences)

#Converting output to array
result = X.toarray()

print("Sentences after removing stop words", all_sentences)
print("Count Vector:", result)

2.TF-IDF:

TF-IDF 代表词频-逆文档频率。 该方法是对 Count Vector 方法的即兴创作,因为特定单词的频率被考虑在整个语料库中,而不仅仅是单个文档。 主要思想是对某些文档非常具体的词给予更多的权重,而对更普遍且在大多数文档中出现的词给予较少的权重。

例如,诸如“is”、“the”、“and”之类的通用词会经常出现,而诸如“Donald Trump”或“Indira Gandhi”之类的词将特定于特定文档。

数学上,

词频 (TF) = 词条在文档中出现的次数 / 文档中词条的总数

逆文档频率 (IDF) = log(N/n) 其中 N 是文档总数,n 是一个术语出现的文档数。

考虑以下示例。
给出了两个文档——D1 和 D2。

TF(Today, Document 1) = 1/8

TF(Today, Document 2) = 1/8

TF(sunny, Document 1) = 4/8

IDF(Today) = log(2/2) = log(1) = 0

IDF(sunny) = log(2/1) = log(2) = 0.301

Therefore,

TF-IDF(Today, Document 1) = 1/8 * 0 = 0

TF-IDF(Today, Document 2) = 1/8 * 0 = 0

TF-IDF(sunny, Document 1) = 4/8 * 0.301 = 0.1505

从上面的计算可以看出,与文档 1 的上下文中的重要词“sunny”相比,常用词“Today”的权重较低。

优点:

它在计算上很容易。
文档中最重要的单词是通过基本计算提取的,不需要太多努力。

缺点:

它无法捕捉单词的语义,只能像词汇级别的特征一样工作。
代码:

from sklearn.feature_extraction.text import TfidfVectorizer 
import pandas as pd

#Declaring the list of sentences
documents = ['Today is sunny day', 'Today is rainy day']

#Initialising Tfidf Vectorizer
vectorizer = TfidfVectorizer()

#Fitting the Vectorizer to the list
X = vectorizer.fit_transform(documents)
print(X)

#Printing the feature names
print(vectorizer.get_feature_names()) 

matrix = X.todense()
tfidf_list = matrix.tolist()
tfidf_df = pd.DataFrame(tfidf_list, columns = vectorizer.get_feature_names())

print(tfidf_df)

3.Word2Vec:

Word2Vec 是一种基于预测的词嵌入方法。 与确定性方法不同,它是一个浅层的两层神经网络,能够预测单词之间的语义和相似性。 Word2Vec 是两种不同模型的组合——(i)CBOW(连续词袋)和(ii)Skip-gram。

模型概述 – CBOW(连续词袋)和 Skip-gram。

word_2_vec

3.1 CBOW(连续词袋):

该模型是一个浅层神经网络,可以在给定上下文的情况下预测单词的概率。 这里,上下文是指围绕要预测的单词的单词的输入。
CBOW模型的架构:

Architecture of CBOW model

作为第一步,输入是通过为给定文本形成一个词袋来创建的。
例如,

Sentence 1 = All work and no play make Jack a dull boy.

Sentence 2 = Jack and Jill went up the hill.

Bag of Words: {“All”:1, “work”:1, “no”:1, “play”:1, “makes”:1, “Jack”:2, “dull”:1, “boy”:1, “Jill”:1, “went”:1, “up”:1, “hill”:1} (after removing the stop words)

这个由单词及其出现频率组成的输入作为向量发送到输入层。对于 X 个单词,输入将是 X[1XV] 个向量,其中 V 是向量的最大长度。

接下来,输入隐藏层矩阵由维数 VXN 组成,其中 N 是表示单词的维数。输出隐藏层矩阵由维数 NXV 组成。在这里,这些值是通过将输入乘以隐藏输入权重来计算的。

在输出层,通过将隐藏输入乘以隐藏输出权重来计算输出。在隐藏层和输出层之间计算的权重给出了单词的表示。作为一个连续的中间步骤,通过对输出和目标值之间计算的误差使用反向传播来调整权重。
优点:

与确定性方法相比,概率性方法给出了更好的结果。
由于不需要计算巨大的矩阵,因此内存需求较少。
缺点:

优化非常重要,否则培训将需要很长时间才能完成。


3.2 Skip-gram :

Skip-gram 模型预测给定单词的上下文,与 CBOW 所做的正好相反。 Skip-gram 模型的架构:

Architecture of Skip-gram model:

输入层大小:[1XV],输入隐藏权重矩阵大小:[VXN],输出隐藏权重矩阵:[NXV],输出层大小:C[1XV]

模型的输入和直到隐藏层的进一步步骤将类似于 CBOW。 输出目标变量的数量取决于上下文窗口的大小。 例如,如果上下文窗口的大小为 2,那么将有四个目标变量,两个词在给定词之前,两个词在给定词之后。

将针对四个目标变量计算四个单独的误差,并通过执行元素相加获得最终向量。 然后反向传播这个最终向量以更新权重。 对于训练,输入和隐藏层之间的权重用于单词表示。

优点:

Skip-gram 模型可以捕获单词的不同上下文信息,因为每个上下文都有不同的向量表示。
对于不常用的术语更准确,并且适用于更大的数据库。
缺点:

它需要更多的 内存 进行处理。
代码:

要使用 genism 库中预训练的 Word2Vec 模型:

import gensim 
import gensim.downloader as api
from gensim.models.keyedvectors import KeyedVectors

#loading pretrained model
nlp_w2v = api.load("word2vec-google-news-300") 

#save the Word2Vec model
nlp_w2v.wv.save_word2vec_format('model.bin', binary=True)

#load the Word2Vec model 
model = KeyedVectors.load_word2vec_format('model.bin', binary=True)

#Printing the most similar words to New York from vocabulary of pretrained model
model.most_similar('New_York')

从头开始训练 Word2Vec 模型:

import gensim 
'''
Data for training Word2Vec
train: A data frame comprising of text samples
'''

#training data
corpus = train

#creates a list for a list of words for every training sample
w2v_corpus = []
for document in corpus:
   w2v_words = document.split()
   w2v_grams = [" ".join(w2v_words[i:i+1]) 
               for i in range(0, len(w2v_words), 1)]
   w2v_corpus.append(w2v_grams)

#initialising and training the custom Word2Vec model 
'''
size: dimensions of word embeddings 
window: context window for words 
min_count: words which appear less number of times than this count will be ignored 
sg: To choose skip-gram model 
iter: Number of epochs for training
'''

word2vec_model = gensim.models.word2vec.Word2Vec(w2v_corpus, size=300,   
            window=8, min_count=1, sg=1, iter=30)

#vector size of the model
print(word2vec_model.vector_size)

#vocabulary contained by the model
print(len(word2vec_model.wv.vocab))

4.GloVE:

GloVe 代表词表示的全局向量。 该算法是对 Word2Vec 方法的改进,因为它考虑全局统计而不是局部统计。 在这里,全局统计数据意味着从整个语料库中考虑的单词。 GloVe 基本上试图解释特定单词对在文档中出现的频率。 为此,构建了一个共现矩阵,该矩阵将表示特定单词相对于另一个单词的存在。

例如,

Corpus – It is rainy today, tomorrow it will be sunny and the day after will be windy.

上面的矩阵表示一个共现矩阵,其值表示在给定示例语料库中一起出现的每对单词的计数。

在计算给定“today”、p(rainy/today) 和给定“tomorrow”、p(rainy/tomorrow) 的单词“rainy”的出现概率后,结果是与“rainy”最相关的单词 与“明天”相比,“今天”是“今天”。

代码:

#Import statements
from numpy import array
from numpy import asarray
from numpy import zeros
from keras.preprocessing.text import Tokenizer 

#Download the pretrained GloVe data files
!wget http://nlp.stanford.edu/data/glove.6B.zip

#Unzipping the zipped folder
!unzip glove*.zip

#Initialising a tokenizer and fitting it on the training dataset
'''
train: a dataframe comprising of rows containing text data
'''
tokenizer = Tokenizer(num_words=5000)
tokenizer.fit_on_texts(train)

#Creating a dictionary to store the embeddings
embeddings_dictionary = dict()

#Opening GloVe file
glove_file = open('glove.6B.50d.txt', encoding="utf8")

#Filling the dictionary of embeddings by reading data from the GloVe file
for line in glove_file:
    records = line.split()
    word = records[0]
    vector_dimensions = asarray(records[1:], dtype='float32')
    embeddings_dictionary[word] = vector_dimensions
glove_file.close()

#Parsing through all the words in the input dataset and fetching their corresponding vectors from the dictionary and storing them in a matrix 
embedding_matrix = zeros((vocab_size, 50))
for word, index in tokenizer.word_index.items():
    embedding_vector = embeddings_dictionary.get(word)
    if embedding_vector is not None:
        embedding_matrix[index] = embedding_vector

#Displaying embedding matrix 
print(embedding_matrix) 

结论:

在这篇博客中,我们回顾了一些方法——Count Vector、TF-IDF、Word2Vec 和 GloVe,用于从原始文本数据创建词嵌入。 预处理文本然后发送预处理数据以创建词嵌入总是一个好习惯。 作为进一步的步骤,这些词嵌入可以发送到机器学习或深度学习模型,用于各种任务,例如文本分类或机器翻译。

作者 east
深度学习 4月 2,2022

Tensorflow:使用 GPU 进行 BERT 微调

训练数据的短缺是自然语言处理面临的最大挑战之一。 因为 NLP 是一个多元化的领域,在多语言数据中具有多种任务。 最特定于任务的数据集仅包含几千个训练数据,这不足以实现更好的准确性。

为了提高现代基于深度学习的 NLP 模型的性能,需要数百万或数十亿的训练数据。 研究人员已经开发出各种方法来使用网络上的大量未注释文本来训练通用语言表示模型。 这称为预训练。

这些预训练模型可用于为广泛的 NLP 任务(例如问答和测试分类)创建最先进的模型。 它被称为微调。 当我们没有足够数量的训练样本时,微调是有效的。

BERT

BERT 代表来自 Transformers 的双向编码器表示。 BERT 是由 Google AI 的研究人员推出的 NLP 框架。 它是一种新的预训练语言表示模型,可在各种自然语言处理 (NLP) 任务上获得最先进的结果。 只需添加单个输出层即可对预训练的 BERT 模型进行微调。 你可以在这里找到 BERT 的学术论文:https://arxiv.org/abs/1810.04805。

在本教程中,您将通过一个示例学习对 BERT 模型进行微调。 可以参考之前的 BERT 教程,里面已经解释了 BERT 模型的架构。

我们将使用 Kaggle 的 Quora Insincere Questions Classification 任务数据进行演示。

In [1]:
# Let's load the required packages
import pandas as pd
import numpy as np
import datetime
import zipfile
import sys
import os

下载预训练的 BERT 模型以及模型权重和配置文件

In [2]: !wget storage.googleapis.com/bert_models/2018_10_18/uncased_L-12_H-768_A-12.zip

提取下载的模型 zip 文件。

In [3]:
repo = 'model_repo'
if not os.path.exists(repo):
    print("Dir created!")
    os.mkdir(repo)
with zipfile.ZipFile("uncased_L-12_H-768_A-12.zip","r") as zip_ref:
    zip_ref.extractall(repo)
In [4]:
BERT_MODEL = 'uncased_L-12_H-768_A-12'
BERT_PRETRAINED_DIR = f'{repo}/uncased_L-12_H-768_A-12'

OUTPUT_DIR = f'{repo}/outputs'
if not os.path.exists(OUTPUT_DIR):
    os.makedirs(OUTPUT_DIR)

print(f'***** Model output directory: {OUTPUT_DIR} *****')
print(f'***** BERT pretrained directory: {BERT_PRETRAINED_DIR} *****') 

Out[4]:
***** Model output directory: model_repo/outputs *****
***** BERT pretrained directory: model_repo/uncased_L-12_H-768_A-12 *****

准备和导入 BERT 模块

以下 BERT 模块是从 GitHub 克隆源代码并导入模块。

In [5]:
# Download the BERT modules
!wget raw.githubusercontent.com/google-research/bert/master/modeling.py 
!wget raw.githubusercontent.com/google-research/bert/master/optimization.py 
!wget raw.githubusercontent.com/google-research/bert/master/run_classifier.py 
!wget raw.githubusercontent.com/google-research/bert/master/tokenization.py
!wget raw.githubusercontent.com/google-research/bert/master/run_classifier_with_tfhub.py
In [6]: # Import BERT modules 
import modeling 
import optimization 
import run_classifier 
import tokenization 
import tensorflow as tf 
import run_classifier_with_tfhub

准备训练数据

在这里,我们将在一小部分训练数据上训练 BERT 模型。

In [7]:
from sklearn.model_selection import train_test_split

train_df =  pd.read_csv('input/train.csv')
train_df = train_df.sample(2000)                 # Train on 2000 data

train, val = train_test_split(train_df, test_size = 0.1, random_state=42)

train_lines, train_labels = train.question_text.values, train.target.values
val_lines, val_labels = val.question_text.values, val.target.values

label_list = ['0', '1']
In [8]:
def create_examples(lines, set_type, labels=None):
    guid = f'{set_type}'
    examples = []
    if guid == 'train':
        for line, label in zip(lines, labels):
            text_a = line
            label = str(label)
            examples.append(
              run_classifier.InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
    else:
        for line in lines:
            text_a = line
            label = '0'
            examples.append(
              run_classifier.InputExample(guid=guid, text_a=text_a, text_b=None, label=label))
    return examples

指定 BERT 预训练模型。

这里使用的是 uncased_L-12_H-768_A-12 型号。 该模型由12层、768个隐藏、12个头、110M个参数组成。 它是一个 Uncased 模型,这意味着文本在标记化之前已被小写。

In [9]:
BERT_MODEL = 'uncased_L-12_H-768_A-12' 
BERT_MODEL_HUB = 'https://tfhub.dev/google/bert_' + BERT_MODEL + '/1'

初始化模型超参数。

In [10]:
TRAIN_BATCH_SIZE = 32
EVAL_BATCH_SIZE = 8
LEARNING_RATE = 2e-5
NUM_TRAIN_EPOCHS = 3.0
WARMUP_PROPORTION = 0.1
MAX_SEQ_LENGTH = 128

# Model Configuration
SAVE_CHECKPOINTS_STEPS = 1000 
ITERATIONS_PER_LOOP = 1000
NUM_TPU_CORES = 8

VOCAB_FILE = os.path.join(BERT_PRETRAINED_DIR, 'vocab.txt')
CONFIG_FILE = os.path.join(BERT_PRETRAINED_DIR, 'bert_config.json')
INIT_CHECKPOINT = os.path.join(BERT_PRETRAINED_DIR, 'bert_model.ckpt')
DO_LOWER_CASE = BERT_MODEL.startswith('uncased')

tpu_cluster_resolver = None   # Model trained on GPU, we won't need a cluster resolver

def get_run_config(output_dir):
    return tf.contrib.tpu.RunConfig(
    cluster=tpu_cluster_resolver,
    model_dir=output_dir,
    save_checkpoints_steps=SAVE_CHECKPOINTS_STEPS,
    tpu_config=tf.contrib.tpu.TPUConfig(
        iterations_per_loop=ITERATIONS_PER_LOOP,
        num_shards=NUM_TPU_CORES,
        per_host_input_for_training=tf.contrib.tpu.InputPipelineConfig.PER_HOST_V2))

加载分词器模块

注意:当您使用 Cased 模型时,传递 do_lower_case = False。

In [11]:
tokenizer = tokenization.FullTokenizer(vocab_file=VOCAB_FILE, do_lower_case=DO_LOWER_CASE)
train_examples = create_examples(train_lines, 'train', labels=train_labels)

# compute number of train and warmup steps from batch size
num_train_steps = int( len(train_examples) / TRAIN_BATCH_SIZE * NUM_TRAIN_EPOCHS)
num_warmup_steps = int(num_train_steps * WARMUP_PROPORTION)

微调来自 TF Hub 的预训练 BERT 模型

本节说明了来自 TensorFlow 集线器模块的微调预训练 BERT 模型。

In [12]:

model_fn = run_classifier_with_tfhub.model_fn_builder(
  num_labels=len(label_list),
  learning_rate=LEARNING_RATE,
  num_train_steps=num_train_steps,
  num_warmup_steps=num_warmup_steps,
  use_tpu=False,
  bert_hub_module_handle=BERT_MODEL_HUB
)

estimator_from_tfhub = tf.contrib.tpu.TPUEstimator(
  use_tpu=False,    #If False training will fall on CPU or GPU
  model_fn=model_fn,
  config=get_run_config(OUTPUT_DIR),
  train_batch_size=TRAIN_BATCH_SIZE,
  eval_batch_size=EVAL_BATCH_SIZE,
)
In [13]:
# Train the model
def model_train(estimator):
    print('Please wait...')
    train_features = run_classifier.convert_examples_to_features(
      train_examples, label_list, MAX_SEQ_LENGTH, tokenizer)
    print('***** Started training at {} *****'.format(datetime.datetime.now()))
    print('  Num examples = {}'.format(len(train_examples)))
    print('  Batch size = {}'.format(TRAIN_BATCH_SIZE))
    tf.logging.info("  Num steps = %d", num_train_steps)
    train_input_fn = run_classifier.input_fn_builder(
      features=train_features,
      seq_length=MAX_SEQ_LENGTH,
      is_training=True,
      drop_remainder=True)
    estimator.train(input_fn=train_input_fn, max_steps=num_train_steps)
    print('***** Finished training at {} *****'.format(datetime.datetime.now()))
In [14]: model_train(estimator_from_tfhub)
In [15]:
# Evaluate the model
def model_eval(estimator):
    
    eval_examples = create_examples(val_lines, 'test')
    
    eval_features = run_classifier.convert_examples_to_features(
        eval_examples, label_list, MAX_SEQ_LENGTH, tokenizer)
        
    print('***** Started evaluation at {} *****'.format(datetime.datetime.now()))
    print('  Num examples = {}'.format(len(eval_examples)))
    print('  Batch size = {}'.format(EVAL_BATCH_SIZE))
    
    eval_steps = int(len(eval_examples) / EVAL_BATCH_SIZE)
    
    eval_input_fn = run_classifier.input_fn_builder(
      features=eval_features,
      seq_length=MAX_SEQ_LENGTH,
      is_training=False,
      drop_remainder=True)
    
    result = estimator.evaluate(input_fn=eval_input_fn, steps=eval_steps)
    
    print('***** Finished evaluation at {} *****'.format(datetime.datetime.now()))
    
    print("***** Eval results *****")
    for key in sorted(result.keys()):
        print('  {} = {}'.format(key, str(result[key])))
In [16]: model_eval(estimator_from_tfhub)

从检查点微调预训练的 BERT 模型

您还可以从保存的检查点加载预训练的 BERT 模型。

In [17]:
CONFIG_FILE = os.path.join(BERT_PRETRAINED_DIR, 'bert_config.json')
INIT_CHECKPOINT = os.path.join(BERT_PRETRAINED_DIR, 'bert_model.ckpt')

OUTPUT_DIR = f'{repo}/outputs_checkpoints'
if not os.path.exists(OUTPUT_DIR):
    os.makedirs(OUTPUT_DIR)

model_fn = run_classifier.model_fn_builder(
    bert_config=modeling.BertConfig.from_json_file(CONFIG_FILE),
    num_labels=len(label_list),
    init_checkpoint=INIT_CHECKPOINT,
    learning_rate=LEARNING_RATE,
    num_train_steps=num_train_steps,
    num_warmup_steps=num_warmup_steps,
    use_tpu=False, #If False training will fall on CPU or GPU, 
    use_one_hot_embeddings=True)

estimator_from_checkpoints = tf.contrib.tpu.TPUEstimator(
    use_tpu=False,
    model_fn=model_fn,
    config=get_run_config(OUTPUT_DIR),
    train_batch_size=TRAIN_BATCH_SIZE,
    eval_batch_size=EVAL_BATCH_SIZE)
In [18]: 
# Train the Model
model_train(estimator_from_checkpoints)
# Evaluate the Model
In [19]: model_eval(estimator_from_checkpoints)
作者 east
深度学习 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

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

标签

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

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • 详解Python当中的pip常用命令
  • AUTOSAR如何在多个供应商交付的配置中避免ARXML不兼容?
  • C++thread pool(线程池)设计应关注哪些扩展性问题?
  • 各类MCAL(Microcontroller Abstraction Layer)如何与AUTOSAR工具链解耦?
  • 如何设计AUTOSAR中的“域控制器”以支持未来扩展?
  • C++ 中避免悬挂引用的企业策略有哪些?
  • 嵌入式电机:如何在低速和高负载状态下保持FOC(Field-Oriented Control)算法的电流控制稳定?
  • C++如何在插件式架构中使用反射实现模块隔离?
  • C++如何追踪内存泄漏(valgrind/ASan等)并定位到业务代码?
  • C++大型系统中如何组织头文件和依赖树?

文章归档

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

功能

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

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