零起点学习字母字符
能否识别训练中未提供的字母字符?
在这篇文章中,我想解释并实际演示一个被称为零射击学习的机器学习领域,我发现这真的很有趣。让我们先简单描述一下它到底是什么:
零射击学习是一种识别类别的方法,这种方法在训练中没有观察到。
与传统的监督学习方法相比,传统的监督学习方法依赖于每个类别的大量示例,零射击学习的主要思想是基于从观察到的类别到新看到的类别的语义转移。
想象一下,你这辈子都没见过字母“H”。如果我告诉你它是由两条垂直线和中间的一条水平线连接而成的呢?你能认出它吗?
15 个手动设计功能中的 10 个。图片作者。
这种语义转换的关键是将类别编码为语义空间中的向量。这对于培训和测试类别都是需要的,并且可以以监督或非监督的方式来完成。
监督方式将通过提出一些特征*来手动注释类别,例如,狗=有尾巴、有皮毛、有四条腿等。*并将它们编码成类别向量。这些特征也可以取自给定领域中已经存在的分类法。
一种不受监督的方式是对类别名称使用单词嵌入。这是因为单词嵌入已经根据类别名称出现在文本中的上下文(例如,在维基百科语料库中)捕获了类别的语义。
实验
我决定使用监督的方式,自己创建类别向量,这样我就可以更深入地了解最终的模型。因此,我开始寻找一个具有合理数量类别的任务,对于它来说,提出有意义的特性是可行的。正如你已经知道的,我用字母字符结束,使用 A-Z 手写字母数据集。
下一步是为所有 26 个类别(字母表中的字符)设计功能。这些特征必须足够通用,因此它们总是涵盖一个以上的类别,然而,每个类别都必须由一组独特的特征来描述,以便以后能够区分。总之,我想出了满足这些限制的 15 个特征(第一幅图中显示了其中的 10 个)。
之后,我必须划分数据集,决定哪些字符将被用作零拍类别。为此,我选择了五个特征相对不同的字符(“J”、“D”、“H”、“R”、“Z”),并将它们的所有数据放在一边。具有剩余 21 个类别的的数据集的剩余部分在训练集和测试集之间分割,用于拟合和测试模型。
有几种方法可以创建零起点学习的模型。我想尝试最简单的方法,它简单地预测任何给定输入的特性。该模型的输入是角色的图像,目标是其编码的类别向量(每个特征为 0 或 1)。这个任务可以被视为一个多标签分类,为此我在 Keras 中使用了以下两个卷积层的设置。
为了评估和实际使用经过训练的模型,我必须以某种方式将预测的类别向量映射回它们对应的类别。这是使用具有欧几里德距离的最近邻匹配完成的。首先,我使用测试集在观察到的类别上评估模型,达到了 96.53% 的准确率。
当我知道该模型能够正确概括时,我可以开始在看不见的零射击类别上评估它。基于这篇论文,我发现实际上有两种方法可以评估零炮模型。
第一个是某种限制性的设置,在预测的时候,我们知道这个实例是来自可见的还是不可见的类别。零触发学习为此受到了批评,因为在现实世界的应用中,我们通常没有这些可用的信息。我们的模型在被搁置的数据上这样评估,达到了 68.36% 的准确率。
第二种设置考虑了预测时所有可能的类别。处理这个问题的领域叫做广义零射击学习。以这种方式评估的结果通常低得多,因为观察到的类在搜索空间中充当干扰物。我们的情况也是如此,基于相同数据评估的模型仅达到了 10.83% 的准确度。对字符“R”的预测几乎总是更接近“P”,对“J”的预测更接近“U”,等等。解决这个问题的一种方法可以在本文中找到。
结论
这个实验让我第一次很好地了解了零起点学习的领域,以及从中可以期待什么。我希望它对你也一样。我必须承认,我期待一个更好的表现,主要是在广义的设置。然而,我使用的模型非常简单,当然可以使用更复杂的模型。一种看起来很有前途的方法,也是我想在未来尝试的方法,是使用双线性模型。该模型使用图像和类别向量作为输入,并预测该向量是否属于图像的实际类别。
感谢您的阅读。所有的代码都可以在这个 kaggle 笔记本中找到,所以你可以随意试验和训练你自己的模型。我将留给你一个卷积层的可视化,因为我很好奇它是否看起来有点类似于我设计的功能。
第一卷积层的特征图。图片作者。
有没有想过是否有比盲目猜测超参数或…更系统的方法来调整您的模型
towardsdatascience.com](/systematically-tuning-your-model-by-looking-at-bias-and-variance-4986662315b2) [## 主动学习能节省多少时间?
在 NLP 数据集上的动手实验。
towardsdatascience.com](/how-much-time-can-you-save-with-active-learning-b4886f5da462)
零镜头文本分类和评估
最近,零镜头文本分类由于其简单性引起了人们极大的兴趣。在这篇文章中,我们将看到如何使用零镜头文本分类和任何标签,并解释背景模型。然后,我们将在情感分析、新闻分类和情感分类中使用人工标注数据集来评估它的性能。
零镜头文本分类
在零镜头文本分类中,该模型可以在没有任何先验数据的情况下对给定标签之间的任何文本进行分类。
白板(图片由维基百科提供)
使用零触发文本分类,可以执行:
- 情感分析
- 新闻分类
- 情感分析
背景
实际上,零镜头文本分类的最新实现源于一个非常简单但非常棒的想法。自然语言处理中有一个领域叫做自然语言推理(NLI)。这个领域研究一个假设对于一个给定的前提是真的(蕴涵),假的(矛盾),还是不确定的(中性)。
监督 NLI 系统
现在,让我们假设我们的文本是*“我爱这部电影。”我们想要预测候选标签正和负*之间的文本的情感。我们将这两个假设-前提对给已经训练好的 NLI 模型,并检验结果。
*前提:*我爱这部电影。
假设-1: 本例为正。*前提:*我爱这部电影。
*假设——2:*这个例子是否定。
基本上,它为每个类别创建“此示例是…”的假设模板,以预测前提的类别。如果推论是蕴涵,就意味着前提属于那个类。在这种情况下,它是积极的。
代码
得益于 HuggingFace,可以通过管道模块轻松使用。
#!pip install transformers datasets
from transformers import pipelineclassifier = pipeline("zero-shot-classification", device=0) #GPUcandidate_labels = ["positive", "negative"]
text = "I don't know why I like this movie so well, but I never get tired of watching it."
classifier(text, candidate_labels)> {'labels': ['positive', 'negative'],
> 'scores': [0.8987422585487366, 0.10125774145126343],
> 'sequence': "I don't know why I like this movie so well, but I
never get tired of watching it."}
在第一个示例中,我们从 transformers 管道中初始化分类器,然后从 IMDB 数据集中给出一个示例。您可以看到分类器为每个标签生成了分数。在第一个例子中,它正确地预测文本的情感是积极的。
candidate_labels = ["world", "sports", "business", "sci/tech"]
text = "Quality Gets Swept Away Quality Distribution is hammered after reporting a large loss for the second quarter."
classifier(text, candidate_labels)> {'labels': ['business', 'world', 'sci/tech', 'sports'],
> 'scores': [0.8066419363021851, 0.16538377106189728, 0.018306914716959, 0.009667363949120045],
> 'sequence': 'Quality Gets Swept Away Quality Distribution is hammered after reporting a large loss for the second quarter.'}
我们的第二个例子是来自 AG 新闻数据集的新闻分类。它能正确预测商业类新闻。
candidate_labels = ["anger", "fear", "joy", "love", "sadness", "surprise"]
text = "i didnt feel humiliated"
classifier(text, candidate_labels)> {'labels': ['surprise', 'joy', 'love', 'sadness', 'fear', 'anger'],
> 'scores': [0.66361004114151, 0.1976112276315689, 0.04634414240717888, 0.03801531344652176, 0.03516925126314163, 0.01925000175833702],
> 'sequence': 'i didnt feel humiliated'}
在我们的上一个例子中,我们研究了来自情感数据集的一个例子。零镜头分类模型预测句子“我不觉得丢脸”的情感为惊喜,然而金标是悲伤。
评估
在这些例子中,零射击分类看起来很有希望。然而,它的性能应该通过使用已经标记的例子用正确的测量来评估。
摘樱桃???Andriyko Podilnyk 在 Unsplash 上拍摄的照片
通过使用 HuggingFace 最新的数据集库,我们可以很容易地在几个数据集上评估它的性能。
- IMDB 数据集:情感分析
类:正,负 - AG-News 数据集:新闻分类
类:世界,体育,商业,科技 - 情感数据集:情感分类
类:愤怒,恐惧,喜悦,爱情,悲伤,惊喜
让我们将我们的零镜头文本分类模型与最先进的模型和微平均 F1 中的随机选取进行比较。
不同数据集中的微观平均 F1
有关初始化零射击分类管道和评估代码的更多详细信息,请查看这篇精心准备的 Colab 笔记本:
详细的讲解和评价!
colab.research.google.com](https://colab.research.google.com/drive/14NuJFnW3hsKNYvy0t37S0x3YYRhrxJ47?usp=sharing)
结论
我们可以看到零镜头文本分类在情感分析和新闻分类中取得了显著的效果。在具有 6 类的情感分类中的表现相当差。我相信这可能是由于类之间的相似性。在没有任何先验数据的情况下,很难区分快乐、爱和惊喜类。
如预期的那样,对于每个任务,零镜头分类的性能低于监督模型。即便如此,如果你没有任何具体分类问题的数据,还是值得尝试的*!*
最初发表于【https://akoksal.com】。
在 Twitter 上关注我:https://twitter.com/alkksl
拥抱人脸的零镜头文本分类
这篇文章是关于以无监督的方式检测文本情感,使用拥抱脸零镜头文本分类模型。
几周前,我在实现 POC,其中一个要求是能够以无监督的方式检测文本情感(不需要事先有训练数据和建立模型)。更具体地说,这是关于数据提取。基于一些预定义的主题,我的任务是从文本数据中自动提取信息。在研究和寻找解决这个问题的最佳方法时,我发现拥抱脸 NLP 支持零镜头文本分类。
什么是零拍文本分类?查看这个帖子— 现代 NLP 中的零投学习。拥抱脸团队有一个现场演示和一个样品笔记本。简而言之,零射击模型允许我们对数据进行分类,而这些数据不是用来建立模型的。我在这里的意思是,这个模型是由别人建立的,我们用它来运行我们的数据。
我认为这将是一个有用的例子,我获取 Twitter 消息并运行分类来将消息分组到主题中。这可以作为更复杂用例的起点。
我使用 GetOldTweets3 库来删除 Twitter 消息。用变形金刚进行零镜头分类很简单,我是按照拥抱脸提供的 Colab 例子来做的。
进口清单:
import GetOldTweets3 as got
import pandas as pd
from tqdm import tqdm
import matplotlib.pyplot as plt
import seaborn as sns
from transformers import pipeline
从变压器管道获取分类器:
classifier = pipeline(**"zero-shot-classification"**)
我从 Twitter 上搜集了 500 条最新消息,基于一个预定义的查询——“气候斗争”。我们将把与气候变化斗争相关的信息提取到熊猫数据框架中,然后尝试使用零镜头分类将它们分成不同的主题:
txt = **'climate fight'** max_recs = 500
tweets_df = text_query_to_df(txt, max_recs)
在零触发分类中,您可以定义自己的标签,然后运行分类器为每个标签分配一个概率。有一个选项来做多类分类,在这种情况下,分数将是独立的,每个将落在 0 和 1 之间。我将使用默认选项,当管道假设只有一个候选标签为真时,返回每个标签的分数列表,加起来为 1。
主题的候选标签——这将让我们了解人们实际上在谈论什么气候变化斗争。有些信息是简单的广告,我们想忽略它们。零镜头分类能够很好地检测广告,这有助于清理数据:
candidate_labels = [**"renewable"**, **"politics"**, **"emission"**, **"temperature"**, **"emergency"**, **"advertisment"**]
我将进入循环并对每条消息进行分类:
res = classifier(sent, candidate_labels)
然后我在检查分类结果。检查第一个标签就足够了,因为当 pipeline 假设只有一个候选标签为真时,我使用默认选项。如果分类分数大于 0.5,我会记录下来,以便进一步处理:
if res[**'labels'**][0] == **'renewable'** and res[**'scores'**][0] > 0.5:
candidate_results[0] = candidate_results[0] + 1
从结果中,我们可以看到,政治话题主导了气候变化的讨论,也许正如所料。与排放和紧急情况相关的话题通过流行度彼此接近。大约有 20 个案例的广告来自废弃的 500 条信息:
作者:安德烈·巴拉诺夫斯基
让我们看看每个主题的一些例子。
- 可更新
Eco-friendly Hydrogen: The clean fuel of the future Germany is promoting the use of #eco-friendly hydrogen in the fight against climate change. Hydrogen can replace fossil fuels in virtually every situation, in an engine or fuel cell!
- 政治
This is so crazy and wrong. It’s as if the ACA isn’t better than what we had before, that the fight for voting rights doesn’t matter, or equal pay for women, or marriage equality, or the Paris climate agreement. Just because Biden isn’t what we want doesn’t mean Dems = GOP
- 发射
A simpler, more useful way to tax carbon to fight climate change - Vox
- 温度
I've noticed any time someone tries to tell me global warming is not a big deal and how climate change has happened before, my body goes into fight or flight.
- 紧急情况
(+ the next few years are CRUCIAL in the fight against climate change. if we don't address it, we'll pass the point of IRREVERSIBLE damage. biden supports the green new deal. trump... well, ya know.)
- 广告
What is your favorite party game? Have a look on @ClumsyRush https://www.nintendo.com/games/detail/clumsy-rush-switch/ #party #game #NintendoSwitch
分类结果非常好,我认为抱脸零拍模型做得非常好。上面的例句没有直接提到主题标签,但是它们被正确地分类了。
结论
使用零镜头模型的无监督文本分类允许我们在没有训练数据来训练模型时解决文本情感检测任务。相反,你依赖于一个来自变形金刚的大型训练模型。对于特定的用例,当文本基于特定的单词或术语时,最好使用基于训练集的监督分类模型。但是对于一般的主题,零射击模型非常有效。
源代码
- GitHub 回购
- 在笔记本上自己运行
TensorFlow 2 计算机视觉从零到英雄—第一部分
使用 TensorFlow 开始使用神经网络的基本实现指南。
免责声明!
本系列不解释算法的底层数学,而只关注逻辑实现和使用带有特定参数集的特定算法的推理。学习神经网络和底层数学基础的资源包含在我的博客中,我是如何通过 TensorFlow 开发人员证书考试的。
计算机视觉导论
最近,计算机终于能够执行看似琐碎的任务,检测图像中的物体/有机体,甚至识别口语。
更重要的问题是,为什么这些任务对人类来说如此微不足道?
简而言之,我们的意识缺乏理解这种感知的能力,这种感知利用了大脑中专门的视觉、听觉和其他感官模块。它是如此之快,以至于当感官信息到达我们的意识时,图像、视频或音频的高级特征已经被放大了。
卷积神经网络(CNN)已经从我们大脑视觉皮层的研究中出现,它们是一种深度学习模型,普遍用于计算机视觉应用。
但是在我们深入开发 CNN 之前,让我们先研究一下深度神经网络的构建模块。
这篇博客文章通过两个例子的帮助涵盖了开发深度学习模型:
- 用单神经元神经网络预测房价。
- 使用密集神经网络从图像中对时尚服装进行分类。
让我们从第一个非常简单的神经网络的实现开始。
构建最简单的神经网络
为了对神经网络如何工作有一个基本的了解,我选择了这个非常简单的房价预测的例子。我们将根据房子里卧室的数量来预测房价。
数据遵循简单的线性函数*y = mx + c*
。
这些数据仅仅是经过组织的:对于每间卧室,我们增加了 50K 美元的成本,等式中的 y 轴截距(当 x = 0 时)是 50K
我们不需要深度学习来解决这样的琐碎问题,这只是为了了解神经网络——它们是如何定义、编译、训练的,以及它们是如何进行预测的。
导入库
因此,第一步是导入所需的库,这里是 TensorFlow 和 NumPy:
##importing the main deep learningimport tensorflow as tf
from tensorflow import keras
import numpy as npprint("Tensorflow Version: ", tf.__version__)
print("Keras Version: ", keras.__version__)##output:
Tensorflow Version: 2.3.0
Keras Version: 2.4.0
确保你用的是 TensorFlow 2.x,我们已经单独导入了 Keras,可以直接使用。
数据
接下来,我们按照上面解释的公式定义数据:
bedrooms = np.array([2,3,4,5,6,7])
house_prices = np.array([150, 200, 250, 300, 350, 400])
模型定义
这将是你建立的最简单的神经网络模型。我们只需要一层,并且那层中只有一个神经元。输入形状也是[1]
,因为我们有一维数据。
我们将使用 Keras’ Sequential
API 来创建一系列相连的层:
model = tf.keras.Sequential([
tf.keras.layers.Dense(units = 1, input_shape=[1])
])
units
—层中神经元的数量。
Dense
—构建密集的神经网络。虽然这个只有一层。
input_shape
-告诉模型输入数据的维度。
模型汇编和培训
如果你一直想知道数学在机器学习中的作用,这是你应该更多探索的部分。虽然,我们有令人惊讶的定义函数,很好地封装了数学。
# model compilation
model.compile(optimizer='sgd', loss='mean_squared_error')#model training
model.fit(bedrooms, house_prices, epochs=100)
我们知道我们的数据遵循一个简单的数学函数,卧室(x)和房价(y)之间的关系是
y=50x+50。
当机器试图学习那个函数时,它会进行猜测…可能是 y=5x+10。然后,loss
函数根据实际答案评估这个猜测的答案,以测量模型预测的误差。
optimizer
函数试图通过另一种猜测来改善这种损失。随着每一次预测,它会尽量减少损失。经过多次迭代(历元),可能会达到一个接近 y=45x+45 的函数,这个函数仍然不正确,但更接近实际函数。
我们使用mean_squared_error
作为优化器的损失函数和随机梯度下降(sgd
)。
如何为特定场景找出合适的损失和优化函数是一项需要时间和实践来培养的技能。
模型预测法
print(model.predict([10]))
上图显示了一个 10 间卧室的房子的训练结果和图像末尾的预测值,该值应为 550,但模型预测值为 579.13。也许多训练几个时期的模型可以改进预测。你为什么不试试呢?
构建密集神经网络,从图像中对时尚服装进行分类
既然我们对 TensorFlow 制作的序列模型的各个组件有了相当好的理解,那么我们解决复杂的问题就会容易得多,例如图像分类,其中包括基于手头数据的一些预处理,在模型中添加密集层,以及更改输入和输出神经元。
资料组
我们使用的是时尚 MNIST 数据集,它是著名的 MNIST 数据集的替代品。它有 70,000 张 28x28 像素的灰度图像,但这些图像代表了时尚单品。因此,每一个阶层都更加多样化,问题也比 MNIST 更具挑战性。
让我们使用 Keras 实用函数加载数据集,以获取和加载常见的数据集,包括 MNIST 和时尚 MNIST,以及其他许多数据集。
##loading fashion MNIST dataset from tensorflow data API
fashion_mnist = keras.datasets.fashion_mnist
(X_train, y_train), (X_test, y_test) = fashion_mnist.load_data()
load_data
方法将我们的图像分成训练和测试集。
让我们检查一下训练集的形状:
X_train.shape##output:
(60000, 28, 28)
我们的数据集中有 60,000 张图片,每张都是 28x28 像素。
类似地,我们在测试集中有 10,000 张图像。
让我们看看打印出来的图像是什么样的:
X_train[0]#output:
我们在一个 2D 阵列中有 28×28 个强度。所有这些强度都在 0-255 之间。
从训练集创建验证集
由于我们在这里没有验证数据,我们将进一步分割我们的训练数据以创建验证集,如下所示:
- 为验证集保留前 5000 行图像。
- 因为我们将使用梯度下降来训练神经网络,所以我们必须缩放输入特征,也就是说,我们将通过将强度除以 255.0 来将强度缩小到 0–1 范围
X_valid, X_train = X_train[:5000] / 255.0, X_train[5000:] / 255.0
y_valid, y_train = y_train[:5000], y_train[5000:]
X_test = X_test / 255.0
此外,根据数据集描述,我们在数据集中有 10 种时尚服装,它们的编码都是从 0 到 9,我们将创建这些商品的列表:
class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat","Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]class_names[y_train[1]]#output:
'T-shirt/Top'
可视化数据集
import matplotlib.pyplot as plt
%matplotlib inlineplt.imshow(X_train[0], cmap='binary')
plt.axis('off')
plt.show()
看看前 40 件衣服,
n_rows = 4
n_cols = 10
plt.figure(figsize=(n_cols * 1.2, n_rows * 1.2))
for row in range(n_rows):
for col in range(n_cols):
index = n_cols * row + col
plt.subplot(n_rows, n_cols, index + 1)
plt.imshow(X_train[index], cmap="binary", interpolation="nearest")
plt.axis('off')
plt.title(class_names[y_train[index]], fontsize=12)
plt.subplots_adjust(wspace=0.2, hspace=0.5)
plt.show()
模型定义
下一步是定义模型:
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]), # input flatten layer
keras.layers.Dense(300, activation='relu'),
keras.layers.Dense(100, activation='relu'),
keras.layers.Dense(10, activation='softmax') # output layer
])
让我们来分解一下这个模型:
- 我们已经为密集神经网络创建了一个
Sequential
Keras 模型,该神经网络由顺序连接的单个层堆栈组成。 - 接下来,我们构建第一层,这是一个
Flatten
层,它将每个输入图像转换成一个 1D 数组:如果它接收到输入数据X
,它将计算X.reshape(-1, 28*28)
。它是密集层之前的一个简单的预处理层。由于它是模型中的第一层,我们指定了input_shape
,它只包括实例的形状。 - 随后,我们添加一个有 300 个神经元的
Dense
隐藏层。它还使用 ReLU 激活功能。 - 接下来,我们添加第二个有 100 个神经元的
Dense
隐藏层,同样使用 ReLU 激活函数。 - 最后,我们添加一个有 10 个神经元的
Dense
输出层(每个类一个),使用 softmax 激活函数(因为类是排他的)。
每个Dense
层管理自己的权重矩阵,包含神经元及其输入之间的所有连接权重。它还管理一个偏差项向量(每个神经元一个)。
我们可以访问这些层、它们的初始化权重和偏差:
模型摘要:
权重和偏差:
编译和训练模型
model.compile(loss="sparse_categorical_crossentropy",
optimizer="sgd",
metrics=["accuracy"])
- 损失:我们使用“稀疏 _ 分类 _ 交叉熵”损失,因为我们有稀疏标签(即,对于每个实例,只有一个目标类索引,在这种情况下从 0 到 9),并且类是唯一的。
- 优化器:“SGD”表示我们将使用简单的随机梯度下降来训练模型。基本上,Keras 将执行所讨论的反向传播算法。
- Metrics :由于这是一个分类问题,测量模型的准确性会很有用。
训练:
history = model.fit(X_train, y_train, epochs=30,
validation_data=(X_valid, y_valid))
在历史对象中捕获模型训练历史,我们将使用它来绘制模型的损失和准确性。
模型评估
我们可以通过传递测试实例和实际标签来评估模型的性能。
model.evaluate(X_test, y_test)# output:
313/313 [==============================] - 0s 533us/step - loss: 0.3326 - accuracy: 0.8823
[0.3326309025287628, 0.8823000192642212]
该模型在这一点上具有 88%的准确性。您可以使用不同的参数来调整模型,以查看效果。
绘制模型历史
history = pd.DataFrame(history.history)
history.plot(figsize = (12,8))plt.grid(True)
您可以看到,历史记录有助于我们将模型训练准确性和损失与验证准确性和验证损失进行比较,即模型对未知数据的性能。
与其在训练数据上的性能相比,模型的性能总是略低。如果模型在训练和测试数据上的准确度较低,那么我们会遇到欠拟合的情况,但是如果模型在训练和数据上表现准确,而在验证数据上表现不太准确,那么我们会遇到过拟合的情况。
对样本测试图像进行随机预测
在测试数据集样本上运行它:
# extracting first 5 sample images
X_sample = X_test[:5]
y_proba = model.predict(X_sample)
y_proba.round(2)y_pred = model.predict_classes(X_sample)
y_pred#output:
array([9, 2, 1, 1, 6])
我们可以使用上面创建的列表获得这些服装的名称:
np.array(class_names)[y_pred]
实际标签:
您可以使用 Google Colab 笔记本试用这些模型并测试其他功能和参数:
编辑描述
colab.research.google.com](https://colab.research.google.com/github/dswh/tf-end-to-end-image-classification/blob/master/Introduction.ipynb)
注意:这将是一系列博客(可能有 3 个),我们将在其中讨论基本的计算机视觉问题,用卷积对真实世界的图像进行分类&汇集并使用预先训练的模型来解决复杂的问题。
以下是这篇博客的视频版本:
数据科学与 Harshit
通过这个渠道,我计划推出几个覆盖整个数据科学领域的系列。以下是你应该订阅频道的原因:
- 这些系列将涵盖每个主题和子主题的所有必需/要求的高质量教程,如数据科学的 Python 基础。
- 解释了为什么我们在 ML 和深度学习中这样做的数学和推导。
- 与谷歌、微软、亚马逊等公司的数据科学家和工程师以及大数据驱动型公司的首席执行官的播客。
- 项目和说明实施到目前为止所学的主题。了解新的认证、训练营以及破解这些认证的资源,例如 Google 举办的 TensorFlow 开发者证书考试。
ZetaBrot,无限分形生成器——超越 Mandelbrot 和 Zeta 函数的变体
轰炸—z →( tanh(arcsinh((e(sinh((log(arccosh((z))))c 上的无限迭代))))))*c
除了我对数据科学的热情,数学,尤其是混沌理论,一直是我探索的主题。更准确地说,我贪婪地阅读了关于混沌系统、奇怪的吸引子和分形的数学好奇心。我觉得它们在某种意义上是令人欣慰的,看似混乱的环境中的秩序,在某种意义上是鼓舞人心的希望。Mandelbrot 集合是最著名的分形结构之一,在互联网上有数百万的参考文献。 Github 统计了超过 9 种编程语言的 6000 个知识库。它已经成为开发者的游乐场,但也是网络上一些最具 T4 催眠效果的视频的来源。Mandelbrot 的美丽还来自于生成它的函数的简单性:z → z +c 的迭代。仅仅通过这个简单的公式,就可以生成一个无限的世界,其中有环路、螺旋、山谷和丰富的惊人结构。分形几何的发现对自然环境产生了巨大的影响,在自然环境中,这些图案在生物和物理世界中随处可见而且还应用于手机天线的小型化和信号处理中的图案识别,从而彻底改变了通信。
在数学的另一个分支——数论上,黎曼泽塔函数被誉为数学家的圣杯。证明黎曼假设的天才将获得100 万美元的奖励,由于其简单公式中隐藏的秘密,它也是激烈调查的主题。ζ函数可以简单地写成所有 1/(n^s 值的无穷和,其中 s 是一个复数。但是莱昂哈德·欧拉在 200 多年前证明了这个无穷级数等于 1/(1-p^(-s 的无穷乘积,其中 p 代表后来的素数。所以基本上,齐塔函数知道一些关于质数的事情,这是一件大事。因为质数是现代密码学的基石,也是全世界数百名数学家爱好者和研究论文的热情主题。
在我复制这两个数学对象的可视化的卑微尝试中,我尝试了一些小的变化。其中一个经典的方法是进一步提升 Mandelbrot 集合的能力,但是这个方法又重复了很多次。然后,我试着加入一些更标准的功能,但并不总是考虑合理性,只是为了创造出视觉上的美感。因此,我的第一个变化是将齐塔函数封装在 sin 中。由此产生的视觉效果是惊人的,见下文。
z → z + sin(1/(n+0.5)^c 迭代的第一个变量)(x:-10/+10,y:-10/+10)
但随后开始了一个乏味的试错过程,在原始配方和新模式的基础上结合了几种功能。见下面第一个 Zeta 和 Mandelbrot 函数与 sin 分量的组合。
与 z → sin 的迭代的组合((z +c)/n^c) (x:-5/+5,y:-5/+5)
这是一项艰巨的工作,因为许多小的变化导致不收敛的系列。虽然经过一些调整和复制来自同行爱好者的变体(这里和那里),如燃烧的船分形,垂直曼德尔布罗,我特别受到 Jeffrey Ventrella 的倡议的启发,使用遗传算法进化曼德尔布罗集合。这促使我通过创建一种算法来试验不同函数组合的自动化,该算法通过循环和随机迭代过程混合 Numpy 库中所有可用的函数,通过精心制作的适应度标准仅保留具有收敛结果的变化。目标不是找到最好的(我该如何定义它?)而是简单地生成可以聚合并导致有趣的可视化的变化。本文简介中的图片是这套的一部分。以下是一些最有希望的结果,它们的名字是由它们的形状启发而来的。有些公式也是由算法自动生成的,但是很难掌握…
藻类:z → z + 1/(n^zc) (x:-5/+5,y:-5/+5)
花园:z → e^(z + sin(1/n^c)) (x:-5/+5,y:-5/+5)
分形蝙蝠:z→ArcTan((ArcTan((Abs(1/(conj(ArcSinH(z)))))+c)(x:-5/+5,y:-5/+5)
蒙德里安:z→tan((angle(sin(sqrt(cosh(c^(cosh(abs(tan((angle(tan(z))))))))))))))(x:-5/+5,y:-5/+5)
冲击波:z→arctanh(sqrt(((c(sqrt(arcsinh(tan(log(((arcsin(c(tan(((conj((z)+c))+c )n))))(arcsin(c^(tan(((conj((z)+c))+c )n)))))n))))))^c)+c))(x:-5/+5,y:-5/+5)
你说对了,公式变得更加复杂,设计也变得更加复杂。但是,算法如何知道哪些组合是有效的,哪些是无效的呢?
zeta brot——无限分形生成器
该算法本身分 4 步工作:
1-定义复杂性的“深度”,例如 z →z +c 的复杂性深度为 2:首先是 z 的平方,然后加上 c。对于 Zeta 函数,它将是 3:首先将 n 提高到 c 的幂,然后对其求逆,最后将其加到 z 上。
我将深度限制为 20,但这是任意的。
2-对于每个复杂程度,从 34 个可用函数中选择一个(从 sin 到 square,下至 atan,甚至 re 或 Im 代表复数)。并按照步骤 1 中随机选择的复杂性级别的底部进行操作。
3.对于复杂计划的每个点,迭代结果(类似于 Mandelbrot) n 次,n 也是任意设置的,但会影响可视化(特别是对于负的 n 次方值)
4.评估结果值的平均值和标准偏差。任何射向无穷大或具有无穷小标准偏差的都被丢弃。一个简单的条件检查和阈值有助于关注最有意义的结果
它的妙处在于一个非常复杂的公式,比如:
z→im(tan(c^(arccos(arcsinh((cosh(conj(arccos(cosh( arccos(z))))))^n)))))
可以通过算法中的主要公式组件进行总结:
【23,26,23,6,26,9,28,23,13,2,20,2】分别对应 ArcCos,CosH,conj…在我的手工参照中。
按照这种逻辑,Mandelbrot 可以表示为[7,15],Riemann Zeta 函数可以表示为[34,10,5,17]。
由于一些伟大的数学思想家受到现有问题的新颖可视化的启发,也许一些宝石隐藏在这些模式中,可能对尚未发现的新定理感兴趣,并帮助我们在混沌中找到新的模式。
我的下一个努力将是尝试几种规模,但也增加了新的公式的变化。保持联系。
下面是我最喜欢的一个例子来总结这次探索之旅:
混乱与秩序的世界:z→((arcsinh(tan(sinh(e((arcsinh(c(arctanh(arccosh(arcsinh(e^(((z)+c)+c )))))))^c)))))+c
鸣谢:感谢 Python 可视化库 Matplotlib 对 Mandelbrot set 的惊人视觉效果的渲染的详细代码分解。我仍然需要探索更多由图卢兹数学大学发布的精细着色功能。
ZFNet:用代码解释论文
揭开神经网络如何看待我们的世界的秘密!
丹尼尔·库切列夫在 Unsplash 上拍摄的照片
在 2013 年的 ImageNet 大规模视觉识别挑战赛(ILSVRC)中,ZFNet 受到了关注,与 AlexNet 相比有了显著的改进。本文是黄金宝典,为您提供了许多概念的起点,如深度特征可视化、特征不变性、特征进化、和特征重要性。
体系结构
https://arxiv.org/pdf/1311.2901.pdf
- 我们的输入是 224x224x3 的图像。
- 接下来,以 2 的步距执行 7x7 的 96 个卷积,随后是 ReLU 激活、以 2 步距的 3×3 最大汇集和局部对比度归一化。
- 接下来是 256 个 3×3 的滤波器**,每个滤波器然后再次被局部对比度归一化和汇集。**
- 第三层和第四层与 384 个内核相同,每个3 个。
- 第五层具有 3x3 的 256 个过滤器,接着是具有步幅 2 的 3x3 最大池和局部对比度归一化。
- 第六层和第七层分别容纳 4096 个密集的单元。
- 最后,我们输入 1000 个神经元的密集层,即 ImageNet 中的类的数量。
如果您不熟悉术语“局部对比度标准化”:
局部对比度归一化是一种执行局部减法和除法归一化的归一化,在特征图中的相邻特征之间以及不同特征图中相同空间位置的特征之间实施一种局部竞争。
来源:https://cedar . buffalo . edu/~ Sri Hari/CSE 676/12.2% 20 computer % 20 vision . pdf
特征的可视化
https://arxiv.org/pdf/1311.2901.pdf
对于特征的可视化,作者使用了去进化网络 (deconvnet)。可以把 deconvnet 看作是自动编码器的解码器部分。它与普通的卷积网络相反,它使用非 pooling 和过滤器从特征中恢复像素。
这个网络中唯一令人困惑的部分是它是如何撤销池的,因为当任何池完成时,给定使用 NxN 过滤器,N 个值中只有一个值剩余。整个数据不能被恢复,但是最大值仍然在那里,但是如果我们不知道它在卷积层的输出中的位置,它是没有用的。这就是为什么当进行汇集时存储最大值的位置以便以后使用。这些位置在文中被称为开关。
【https://ieeexplore.ieee.org/document/6126474
使用开关,最大值被放置在图层上正确的空间位置,从而允许将要素正确映射到像素。
此外,还有一点需要注意,卷积滤波器是在应用非线性之后应用的,这与卷积然后激活的正常流程相反。
https://arxiv.org/pdf/1311.2901.pdf
然后作者提取了特征图中前 9 个激活的特征并展示出来。
第一层去掉了最简单的特征,图像中的各种频率。把它当成学习图像中的线条。
第二层是建模各种角落和边缘/颜色组合。把它想象成学习图像中的曲线。曲线是由小线条构成的。
第三层学习网格等更复杂的图案。把它想象成学习那些曲线的组合,即网格。曲线聚集在一起创建网格(想想篮子)。
第四层学习特定类别的特征,例如狗脸。把它想象成把篮子做成不同的形状并涂上不同的颜色。网格可以被转换成类似于面和各种复杂的对象。
第五层学习具有一些姿势变化(侧面、正面和其他)的整个对象。把它想象成把所有这些篮子排列成相似的不同物体。可以将类似较大物体的较小人工制品的网格排列在一起,以形成整个形状。
从特征的可视化中,作者还获得了在 AlexNet 的第一层中减少过滤器大小和步幅的想法。
https://arxiv.org/pdf/1311.2901.pdf
在(b)中,我们有 AlexNet 的第 1 层功能,在©中,我们有 ZFNet 的第 1 层功能。在(b)的情况下,我们可以看到一些灰色方块,这些是没有激活值的死亡神经元。这是一件坏事。另一个问题是在(a)中可以看到颜色/强度的低值和高值,但是不能看到颜色/强度的中间范围。
第三个问题是图像特征中的锯齿状视觉特征或混叠。当采样率不够高时,就会发生混叠(想象一下图像中有正方形)。在这种情况下,采样率是将要发生的卷积数。如果滤波器尺寸较大,则采样率较低。如果滤波器尺寸较小,则采样率将会较高。大步流星也会发生同样的事情。
这就是为什么这些问题的解决方案是减小滤波器尺寸和步幅,这两者都导致采样速率增加,并且由于现在步幅很小,颜色/强度的中间范围出现。
特征不变性
卷积神经网络具有平移、缩放和旋转(给定对象具有旋转对称性)不变性。这是直观的证据:
https://arxiv.org/pdf/1311.2901.pdf
第一行是为了显示翻译不会影响训练有素的 CNN 的表现。在第一行的第二列中,您可以看到图像属于其真实类别的概率。除了在极端情况下,曲线在大多数情况下都是稳定的,主要是因为在图像中不能看到有问题的物体。
第二行是为了显示缩放不影响经过训练的 CNN 的性能。在第二行的第二列中,您可以看到图像属于其真实类别的概率。除了娱乐中心之外,大多数对象的曲线都是稳定的,娱乐中心实际上一直类似于电视,因此是这样的行为。但是,总的来说,CNN 看起来对缩放相当稳健。
第三行是为了显示旋转确实会搞乱 CNN。一个例外是,如果物体具有某种旋转对称性,那么 CNN 仍然保留其对该物体图像的预测能力。从第三行的第二列,你可以看到所有的曲线都乱了套,只有可爱的狮子狗和危险的非洲鳄鱼是稳定的,它们的图像看起来都是旋转对称的。CNN 对于具有旋转对称性的物体的旋转是鲁棒的,因此,你应该记住这一点。
因此,今天你就有了视觉证据,证明为什么 CNN 在图像任务上如此出色。
特征的演变
照片由 Alexas_Fotos 拍摄
这篇论文给了我们关于神经网络在引擎盖下做什么的视觉直觉。没有人知道如何处理和如何调整这个引擎的黑盒神经网络已经不再是谜了。下图显示了网络中图层的影像要素。
https://arxiv.org/pdf/1311.2901.pdf
这就是图像特征如何在层上演变,但用简单的自然语言来说,这就是它是如何发生的。
来源:作者
对这一观点的更多支持是,在第一层,你有线,我们可以把它联系起来,因为这两个方程看起来像:
来源:作者
正常神经元的方程式看起来像一条线。所以,第一层模拟图像中的线条。随着层数的增加,上面的 x 会越积越多。并且网络对越来越多的扭曲线及其组合进行建模。耶,我们得到了最好的算法来创建我们的模型。对于以上解释的更复杂的形式,请查阅通用逼近定理(UAT)和柯尔莫哥洛夫定理。
特征重要性
https://arxiv.org/pdf/1311.2901.pdf
精彩的部分还不止于此。本文还包含有关各图层特征预测能力的有用信息。正如我们所见,最后一层功能是最强大的。因此,在堆叠或迁移学习时,这些都可以使用。
密码
这里是上面广泛讨论的 awesome 网络的代码。
结论
ZFNet 第一次让世人看到了神经网络的内心世界。由于人类是视觉学习者,这为计算机视觉领域打开了新的大门和途径。它向我们展示了神经网络的中心思想以及它们是如何形成的。
通过 Lambda 函数在 EMR 中压缩和提交 PySpark 作业
端到端的项目结构和部署
Denys Nevozhai 在 Unsplash 上拍摄的照片
语境
我假设你已经熟悉 AWS 云平台,尤其是 Lambda 和 EMR 服务。我假设您已经运行了一个 EMR 集群,并且知道如何设置 lambda 函数。本文涵盖了创建 PySpark 项目并提交给 EMR 的端到端主题。最后,本文产生了一个名为 pyspark-seed 的 PySpark 项目,它已经准备好被克隆并在它的基础上进一步开发。
重要的事情先来
我的 Python 项目的 go to IDE 是 PyCharm 。Jupyter 笔记本总是在那里快速检查。为了构建 Python 虚拟环境,我将使用 venv 。Venv 很简单,并且预装了 Python 解释器。对于 Python,我会选择 3.7 版本;对于 PySpark,我会选择 2.4.5 版本。提供了一个持续集成配置文件,可以通过 GitLab Runner 执行。由于社区更大,我也在 GitHub 中托管这个 pyspark-seed 项目的源代码。
部署模式
在创建项目之前,让我们讨论一下部署!是的,部署发生在最后,但是它的重要性应该在项目开始时讨论。为什么?因为大多数时候,你部署项目的方式会影响项目结构和代码组织。
在 PySpark 项目中,您可以部署独立脚本或者部署打包/压缩的项目。如果你有几个简单的工作,但彼此之间不共享功能,就部署独立脚本。当您有多个彼此共享功能的作业时,部署一个打包/压缩的项目。
当打包用 Java 或 Scala 编写的 spark 作业时,您会创建一个单独的 jar 文件。如果打包正确,在 EMR 中提交这个 jar 文件将会成功地运行作业。要在 EMR 中提交 PySpark 项目,您需要具备以下两点:
- 您的项目的一个 zip 文件。
- 这个 zip 文件之外的一个 main.py 文件,它将这个 zip 文件作为一个模块导入。您不必指定*。导入模块时压缩*。
构建项目
我创建了一个名为 pyspark-seed 的 Python 项目。该项目的结构如下:
pyspark-seed 项目结构
- 模块 _ 种子:包含作业、服务、实用程序和测试的模块。这可以被认为是一个独立的模块,内部有一个 run.py 文件。该文件被导入到 main.py. 中
- 作业:我存储所有作业的包。
- 服务:自定义编写的函数,在作业内部调用,处理数据。这些函数抽象了作业中使用的共享功能。例子可能是:模式服务、日期服务等。
- utils : 一个包,我在里面存放了像 s3_utils、spark_utils、log_utils 等助手。(是的 utils 的意思和 helpers 一样)。
- 测试:存储单元和集成测试的包。
- 。gitignore :通常由 gitignore.io 生成。
- main.py: 这是主函数,在部署时,它将被保存在 zip 文件之外。该文件从模块种子包中导入 run.py 并运行它。
- setup.py: 安装这个项目。
虚拟环境
我使用 venv 来创建隔离的 Python 环境。这个环境中的 Python 二进制文件与您用来创建这个环境的 Python 中的二进制文件是相同的。安装在这个虚拟环境中的模块独立于安装在本地/系统 Python 中的模块。要创建 Python 环境,请在项目根目录(即/pyspark-seed)。
python3 -m venv venv. ./venv/bin/activate pip install -e .
第一个命令创建一个 Python 环境。这将在你的项目结构中创建一个名为 venv 的目录。第二个命令将激活创建的 Python 环境。最后一个命令将运行 setup.py 并安装/设置项目。
安装文件
该文件的职责是正确设置您的 Python 项目。您可以指定项目的名称、版本*、提供项目的描述*、作者名称、包等等。一个简单的 setup.py 如下:
在 version 变量中指定项目版本,允许您在 CI 期间访问它,并使用它来生成一个路径,在那里您将在 s3 中存储工件(即 seed_module 和 main.py )。访问这个变量非常简单:
python setup.py --version
CI-管道
PySpark 项目的 CI 管道通常有三个基本阶段:构建、测试、和部署。
pyspark-seed 项目的线性 CI 渠道
Python 3.7-stretch 用作基础图像。如果您想在测试阶段安装 PySpark 并运行 PySpark 测试,那么这个版本是必需的。这条管道是线性的。每个阶段在前一个阶段成功完成后运行。阶段构建和测试自动运行,而部署应该手动触发以进行部署。AWS 凭证作为环境变量存储在 GitLab 中。当在 s3 中存储工件时,我们总是用最新的变更覆盖最新的路径内容。
s3 中部署的工件
乔布斯
每个作业都应该写在单独的 Python 文件中。为了简单起见,每个作业都应该有一个名为 process 的函数,它至少接收 spark_session 、 input_path 和 output_path 作为参数。这些参数,即我们想要运行的作业名和其他参数,在下一节讨论的 lambda 函数中指定。下面显示了一个简单的作业模板。
通过 Lambda 向 EMR 提交作业
AWS Lambda 是一种无服务器服务。您可以通过 AWS CloudWatch 安排 lambda 代码运行,触发代码运行作为对事件的响应,甚至通过 API 调用按需触发 lambda 函数。下面展示了一个向 EMR 提交作业的 lambda 函数。这个 lambda 函数在 Python 3.7 中运行。
我已经定义了 main_path 和 modules_path ,它们默认指向产品的最新版本。特定于您的 main 函数的参数在 *main_path 之后的 spark-submit 中传递。*我更喜欢在字典中设置所有参数,将字典转换为字符串,并将整个字符串作为单个参数传递给 *main。*当收到这个字符串字典时,我使用 ast 模块,从中提取字典。
然后,该参数字典被传递给 run.py 函数,该函数使用提供的配置建立 spark 会话,并运行参数中规定的作业。
场景工作流
考虑一个用例,其中每 20 分钟将一个数据文件(大小约 3GB)转储到 s3 原始数据桶中。考虑一个事件侦听器被设置到这个桶属性。该事件监听器监听所有 对象创建事件。如果在这个桶中上传了一个对象,侦听器就会捕获它并触发目标 lambda 函数。这个 lambda 函数从事件消息中获取对象路径,提供作业参数,并在 EMR 中提交作业。下图显示了此工作流程的开始和结束。
通过 lambda 函数在 EMR 中提交 PySpark 作业的简单场景
最后的话
在本文中,我描述了启动 PySpark 项目、创建 CI 配置文件、在 S3 部署工件以及通过 Lambda 函数在 EMR 中提交作业的过程。提供的大部分建议都直接来自我在生产和研究中使用 PySpark 的个人经验。我在 Github 中托管了这个 pyspark-seed 项目的源代码。通过亲自探索这个知识库,可以了解许多其他细节。随意克隆它,让它变得更好。
当然,这个项目许多方面可以用不同的方式来完成。我打算提供这个种子项目作为一个起点,可以进一步发展。欢迎所有问题、反馈和批评。我相信在这个世界上,批评推动变化。
[## dardanxhymshiti/pyspark-seed
在 GitHub 上创建一个帐户,为 dardanxhymshiti/pyspark-seed 的发展做出贡献。
github.com](https://github.com/dardanxhymshiti/pyspark-seed)
用 Python 实现 4 步分区统计算法
如何汇总面区域的栅格数据
通常需要汇总不规则形状区域内网格化数据集的信息。虽然乍一看这似乎很简单,但调和栅格(格网)和矢量(面)数据类型之间的差异可能会很快变得复杂。本文展示了如何通过 4 个步骤用 Python 实现区域统计算法。
- 加载栅格数据和矢量多边形
- 栅格化面要素
- 将输入数据掩膜到面范围
- 计算面范围的分区统计数据
1.加载栅格数据和矢量多边形
首先导入必要的 Python 模块。
现在设置光栅和矢量数据的文件路径,并使用gdal
和ogr
分别加载光栅和矢量数据。从已加载的矢量数据源访问包含面数据的图层。然后获取地理变换信息(定位网格化栅格数据并指定像元大小),而不获取栅格数据的数据值。
我们还要用gdal
和ogr
做一些设置,为确定栅格和矢量多边形之间的重叠做准备。让gdal
和ogr
驱动程序在内存中创建临时光栅和矢量图层,并为临时 shapefile 设置名称。
2.栅格化面要素
加载栅格和矢量数据后,就该确定它们重叠的地方了。这将是算法中最复杂和最密集的部分。首先,从矢量图层读取第一个面要素。然后开始一个while
循环,只要矢量层中还有另一个特征,循环就会继续。下面是设置循环的基本方法。随着我们的继续,这个循环将被修改。
我们需要创建一些函数来帮助我们创建一个新的栅格来存储栅格化的面要素。当我们用实际数据调用这些函数时,它们会更有意义。现在,在脚本的顶部添加函数定义。首先,我们需要将包含面要素的边界框的坐标转换为与输入栅格相对应的像元坐标或偏移量(行号和列号)。面的边界框是包含整个面要素的矩形,它由最小和最大 X 和 Y 坐标组成。
接下来编写一个函数,用上面函数中计算的像元偏移量创建一个新的 GeoTransform。这两个函数将允许我们创建一个新的更小的栅格,该栅格仅覆盖由面要素重叠的区域。
现在是算法中最复杂的部分:在内存中创建新的空栅格,并将面要素转换为栅格。按照下面代码片段中的注释来理解每一行代码的作用。你可能还会发现查看 GDAL 和 OGR 文档很有用。
3.将输入数据掩膜到面区域
此时我们有两个并发的(重叠的)numpy
数组:tr_array
和r_array
。tr_array
值为 1,表示多边形已栅格化的位置。r_array
包含我们要用来计算每个面的分区统计数据的值。
首先,确保输入栅格存在。接下来创建一个遮罩数组。我们希望从r_array
获取数据,其中不包含无数据值,并且tr_array
中的相应值等于 1(或True
)。
现在我们将使用maskarray
来计算每个面要素的区域统计数据。
4.计算每个面范围的分区统计数据
再编写一个函数,它接受一些值作为输入,并创建一个值的字典。将此函数与其他函数一起放在区域统计脚本的顶部。
现在,计算来自maskarray
的值,并将它们传递给setFeatureStats
函数。仅当阵列存在时才这样做(is not None
)。否则,传递 no data 值来设置统计信息。
结论
恭喜你!您已经创建了可应用于许多不同应用程序的 Python 区域统计脚本。以下是完整的脚本。使用自定义的区域统计算法可以让您在使用结果时更加灵活。从这一点来看,很容易将字典列表转换为 pandas 数据帧进行分析,导出到 csv,或者在原始 shapefile 中创建新字段并将统计数据直接添加到原始数据中。这可以加快、简化和定制您的工作流程。
原载于 2020 年 11 月 10 日 https://opensourceoptions.com。
总统竞选中服用维柯丁:用马尔可夫链制造假头条
在讽刺和现实之间游走
来源:查尔斯·泰勒,via Adobe Stock
在这篇文章中,我们编写 Python 代码来生成假新闻标题,使用马尔可夫链模型,该模型是在过去一年中来自*《纽约时报》*的真实标题语料库上训练的。
一些假标题:
我曾经牵过手?
我们在下降,下降,下降
我们都在这张照片里吗?| 2019 年 9 月 18 日
在总统竞选中嗑了维柯丁
迈克·彭斯明确表示有一部新宪法
谁知道如何清除你孩子的 DNA 信息?
人工智能了解到自由主义者也会吃掉他们自己的律师
纽约人多么想要便宜的葡萄酒和许多真人大小的洋娃娃。
卡罗尔·巴斯金的丈夫唐·路易斯身上发生的一件事?
在帮助下,她找到了卡森·麦卡勒斯的情书。他们教她如何统治直到 2036 年
尽管这些标题很明显是假的,而且从未被《纽约时报》发表过,但在当前事件的背景下,它们却有着不可思议的真实性。
假设您有一个想要模拟的文本语料库,您可以扩展本文中的代码来生成任何想要的文本。
内容:
- 马尔可夫链是如何工作的
- 野外的马尔可夫链文本生成器
- 创建我们自己的马尔可夫链文本生成器
- 制造假标题
- 改进我们模型的方法
- 更多头条!
1.马尔可夫链是如何工作的
你可能没有意识到,但是你每天都在使用马尔可夫链。这些数学系统决定了哪些页面会出现在谷歌搜索的顶部。它们帮助你的手机预测你下一步要输入什么。它们还为各种 Twitter 和 Reddit 机器人以及其他模仿发生器提供动力。
从根本上说,所有这些应用程序中的马尔可夫链都是以同样的方式工作的。马尔可夫链描述了一系列可能的状态,其中每个状态的概率取决于紧接在其之前的状态。
马尔可夫链上有很多好的资源,比如这个可视化的,所以这篇文章只描述它们如何在 Python 包markovify**,**中工作,这是一个方便的小包,可以让我们自己委托编写模型的工作。
当给定像我们的标题这样的语料库时, markovify 使用重叠滑动窗口将每个句子(或者在我们的情况下,标题)分解成用户指定大小的 n 元语法状态。例如,如果我们告诉它,我们希望我们的语料库用二元模型状态的马尔可夫链来建模,这个标题来自 2020 年 4 月 30 日
谁应该在飞机上戴口罩?更多的航空公司说每个人
被分解成这个二元模型状态列表:
('___BEGIN__', '___BEGIN__')
('___BEGIN__', 'Who')
('Who', 'Should')
('Should', 'Wear')
('Wear', 'Masks')
('Masks', 'on')
('on', 'Planes?')
('Planes?', 'More')
('More', 'Airlines')
('Airlines', 'Say')
('Say', 'Everyone')
当它把这个标题分解成 n 个字母时, markovify 也在字典中记录了遵循特定二元模型的所有单词的频率。这本字典构成了马尔可夫链。
到目前为止,我们的马尔可夫链是这样的:
{('___BEGIN__', '___BEGIN__'): {'Who': 1},
('___BEGIN__', 'Who'): {'Should': 1},
('Who', 'Should'): {'Wear': 1},
('Should', 'Wear'): {'Masks': 1},
('Wear', 'Masks'): {'on': 1},
('Masks', 'on'): {'Planes?': 1},
('on', 'Planes?'): {'More': 1},
('Planes?', 'More'): {'Airlines': 1},
('More', 'Airlines'): {'Say': 1},
('Airlines', 'Say'): {'Everyone': 1},
('Say', 'Everyone'): {'___END__': 1}}
再来看另一个标题。
应该先救谁?专家提供伦理指导
在 markovify 分解这个标题并更新链之后,我们的链看起来是这样的(更新以粗体显示):
{('___BEGIN__', '___BEGIN__'): **{'Who': 2}**,
('___BEGIN__', 'Who'): **{'Should': 2}**,
('Who', 'Should'): {'Wear': 1, **'Be': 1**},
('Should', 'Wear'): {'Masks': 1},
('Wear', 'Masks'): {'on': 1},
('Masks', 'on'): {'Planes?': 1},
('on', 'Planes?'): {'More': 1},
('Planes?', 'More'): {'Airlines': 1},
('More', 'Airlines'): {'Say': 1},
('Airlines', 'Say'): {'Everyone': 1},
('Say', 'Everyone'): {'___END__': 1},
**('Should', 'Be'): {'Saved': 1}**
**('Be', 'Saved'): {'First?': 1},
('Saved', 'First?'): {'Experts': 1},
('First?', 'Experts'): {'Offer': 1},
('Experts', 'Offer'): {'Ethical': 1},
('Offer', 'Ethical'): {'Guidance': 1},
('Ethical', 'Guidance'): {'___END__': 1}**}
我们可以看到模型知道单词“Who”在标题中作为第一个单词出现了两次。该模型还知道“谁应该”后面可能会有两个不同的词,以及标题可以在“说每个人”或“道德指导”后面结束。
最终[和大]链的一瞥:
这是我们马尔可夫链的一部分,它从我们的纽约时报标题语料库中捕获了 233,477 个二元模型。
当生成一个句子时, markovify 以开始状态('___BEGIN__', '___BEGIN__')
或用户提供的开始状态开始,可能是('More', 'Airlines')
或其他 233,476 个二元模型中的任何一个。
Markovify 然后从这个开始状态开始链接,随机添加一个单词,假设它跟随前面的二元模型。当链遇到结束状态时,它停止。现在我们有了假标题。
使用马尔可夫链生成文本时会出现一些常见的问题,但是 markovify 在幕后处理了这些问题。这些问题与生成句子片段而不是完整的句子有关。如果我们从一个随机的单词开始,去掉标点符号,或者试图在一定数量的单词后任意结束句子,就会发生这种情况。 Markovify 通过记录所有可能的首字、保留所有标点符号、记录所有结束状态来处理这些问题。Markovify 还确保我们不会生成语料库中已经存在的句子。
2.野外的马尔可夫链文本生成器
虽然马尔可夫链文本生成器可以进行微调或与其他模型结合,以创建强大的应用程序,如谷歌搜索或手机上的预测文本,但它们也只是一种使用非常简单的快捷方式模仿智能的有趣方式。
马尔可夫链文本生成器的一些例子:
- 链发明精神错乱,一个反人类的卡片答题卡生成器。
- /u/user_simulator ,一个基于用户评论历史生成评论的 Reddit 机器人。
- Insta-Trump!,特朗普演讲生成器。
- Tay ,这是一款微软聊天机器人,它被设计成基于与 Twitter 上的人的互动来做出回复。然而,它在不到 24 小时内变成了一个热爱希特勒的性爱机器人,这要感谢巨魔给它提供了煽动性和攻击性的推文,并立即被拿下。
- shartificialintelligence.com,“世界上第一家完全由机器人文案组成的创意广告公司。”
3。创建我们自己的马尔可夫链文本生成器
为了创建我们自己的马尔可夫链文本生成器来生成模仿纽约时报的假标题,我们首先需要获得真实标题的语料库,然后我们使用马尔可夫链在这些标题上训练我们的模型。
从《纽约时报》下载真正的头条新闻
我们将使用去年《纽约时报》和《T21》的所有标题。我在这里描述如何得到它们。
Python 中的简单指南
towardsdatascience.com](/collecting-data-from-the-new-york-times-over-any-period-of-time-3e365504004)
或者,您也可以对任何其他文本语料库执行此操作。文本越多越好。你只需要遵循由 markovify 包指定的格式规则就可以把它变成一个可用的语料库。
在我们开始之前,加载依赖项。
import pandas as pd
import markovify
import random
加载独特的标题。
headlines = pd.read_csv('NYT.csv', parse_dates=['date']).drop_duplicates(subset='headline').reset_index(drop=True)['headline']
《纽约时报》过去一年的独特标题。
我们有 46,135 个标题输入到我们的模型中。
使用 markovify 训练我们的模型
为了训练我们的模型,我们给 markovify 我们的标题语料库和我们想要的 n 元语法的大小。
model = markovify.NewlineText(headlines, state_size=2)
我测试了一元模型、二元模型、三元模型,发现二元模型在这种情况下给出了最好的概率一致性,所以这就是我们选择state_size=2
的原因。
4.制造假标题
告诉模型生成一个假标题也很简单。
model.make_sentence()
我们还可以生成谈论特定话题的标题,比如当前的疫情。由于没有内置的方法来做到这一点,我不断地一个接一个地生成标题,如果它们包含至少一个与主题相关的预先指定的单词列表中的单词,就保留它们,直到我达到我想要的标题数量。
关于疫情的假标题:
冠状病毒已经赢了
总统赦免冠状病毒本身
你的访客应该知道冠状病毒
谋杀率惊人。病毒是冲着你来的?
冠状病毒成了圣人。但是首先,他的身体必须被释放
在充满枪支的漫画世界中半心半意的千禧年冠状病毒准备
当冠状病毒衰退时,堕胎是“合适的”
波兰和匈牙利利用冠状病毒在美国人中间挑拨离间?
冠状病毒导致 N.C.A.A .停止销售假冒的抗冠状病毒牙膏
爱泼斯坦原告敦促安德鲁·阿尔伯特·克里斯琴对性玩偶“全盘招供”,玛丽·雪莱创造了“弗兰肯斯坦”,然后是病毒
为了好玩,让我们尝试一个不同的话题——猫!
topic = ['cat', 'cats', 'kitty', 'kitten', 'kittens']
在变焦会议上为一只猫大吵大闹
掌握放牧数码猫的艺术
我们在衰退?永远养你的猫
他 22 磅重的猫太大了,无法保持安全
有小狗和小猫的房地产年
这些地方可能会没有爆炸的小猫
两只猫是美国第一批测试其安全团队的宠物
在奥地利,这是一个关于鬼魂、黑魔法和谋杀猫的俗气故事
一只黑猫为地球上令人不安的警告承担了一些责任
他在变焦会议上扔了一只猫后,他们的浪漫开始了
猫凯伦正要去和《纽约时报》的经理谈一谈。
我们可以将任何单词作为主题*、的一部分,因为纽约时报*至少在一个标题中使用过它。这个词出现得越频繁,我们的模型就越有创意。
感谢,jsvine ,让这个过程变得如此简单!
5.改进我们模型的方法
这篇文章中的所有标题都是人工策划的。虽然我们的马尔可夫链文本生成器对于这样一个简单的算法表现得非常好,但它只是做了它被告知的事情。我们没有告诉它如何变得有趣。我们没有告诉它英语是如何工作的。我们的模型无法知道它是否有趣,甚至语法是否正确。我们得帮点忙。
正常输出:
这些标题有些有道理,但有些没有。
这是机器人社区内部的一场辩论——对于生成自然语言的机器人,我们应该允许多少人为干预?
听说过 @horse_ebooks 吗?这是一个非常受欢迎的 Twitter 机器人,因为人们在他们认为是概率的东西中看到了的高雅艺术。但是当发现只是有人假装概率时,推特被激怒了。
这是个难题。一篇关于名为@ headlinetron的 Twitter 机器人的文章很好地描述了这一点:
“如果纯粹是机器人,那就不好笑了。但如果太人性化,就没意思了。没有人希望看到一个纯粹的马尔可夫链生成器生成的随机混杂的单词沙拉,但也没有人希望看到某个家伙假装成机器人,”埃尔南德斯说。
通常答案是生成大量的句子,然后在最少的人工干预下挑选出最好的句子。除了手工策划,我们还可以做其他事情来改进我们的模型(直到它变得太好而不好笑):
- 增加语料库的大小。
- 与其他模型结合以创建集合模型。
- 使用其他算法,例如神经网络(尽管我进行了初步测试,将 markovify 与 textgrnn 进行对比,结果 markovify 胜出)。
6。更多头条!
寻找一个棘手的情况
中国审查人员的工作日记
医生来拯救 2020 年夏天
我们从纽约时报学到了什么
内衣广告失去了如履薄冰的艺术
脸书是如何试图将“玉米卷星期二”注册为商标的
发微博抱怨我偏执的女房东的难以形容的代价
对于一些恐怖小说作家来说,没有什么比学生贷款更可怕的了
百老汇关闭了,但它的“施虐者”钢琴家仍然接受请求
每周健康问答:我们都在了解你妻子的垃圾
zoomers vs . Boomers——使用 Transformers 对 Twitter 用户进行世代分类,并进行世代分析
作者:胡安·帕埃斯人、布伦特·鲍斯格、大卫·戴、萨米·坎德克、悉达多·谢特卡尔和伊迪·周
这个项目的目标是创建一个模型,根据给定 Twitter 用户的个人资料和推文的内容对他们进行分类。年龄分类的应用可以包括有针对性的数字体验,以及年龄验证和分析各年龄组的流行趋势。发表在《PLOS 一号》上的研究也启发了这个项目(【https://doi.org/10.1371/journal.pone.0183537】T2)。PLOS 小组使用元数据和推文将推特用户分为三个年龄组。在此基础上,来自 Twitter 的用户信息和他们的推文被收集起来,并按年龄分为四代——Z 世代(18-25 岁)、千禧一代(26-40 岁)、X 世代(41-55 岁)和婴儿潮一代(56-76 岁)。我们试图利用基于从个人资料中收集的元数据和他们过去十条推文的内容的模型对他们进行分类。
我们能够从大约 2300 个分布在四代人之间的 Twitter 个人资料中收集信息。由一个说英语的人运营的 18 岁以上的 Twitter 个人资料被搜集用于 tweets 和元数据来创建我们的数据集。使用这个数据集,基于元数据及其推文的统计细微差别设计了新功能。接下来,我们应用了一种基于迁移学习的方法,对 Google 开发的变压器双向编码器表示(BERT)模型进行了微调。该模型为 tweet 生成嵌入,以捕获上下文信息,并生成逻辑,显示模型的原始预测,即一组给定的 tweet 属于一个类别。
生成的逻辑和嵌入与元数据要素一起用于创建集合模型。测试了各种模型,但 CatBoost 梯度增强是表现最好的,总体精度约为 60%。该模型在 Z 代上存在相对超额表现的问题,因为它以大约 80%的准确度对该组进行了分类。此外,该模型是在来自老一代的较少样本上训练的。我们的模型可以用更多的数据进行改进,包括每个配置文件的 tweets 数和获得的配置文件数,但由于时间限制、GPU 限制和 API 访问,这是不可能的。尽管有这些问题,我们的年龄预测模型比基线随机预测模型提供了巨大的提升。
数据采集和预处理
我们曾试图获得官方 Twitter API 密钥,但 Twitter 没有及时回应。因此,一个名为 GetOldTweets3 的非官方 Twitter API 被用来收集数据。这个库允许我们查询符合一般搜索标准的推文,如文本内容、推文位置和推文时间戳。
搜索标准是为不超过一周的推文设置的,包含短语“生日快乐”,括号中有数字年龄及其正确的后缀(例如,“18 日”、“19 日”、“20 日”、“21 日”等)。)从 18 岁到 90 岁。这个短语很重要,因为包含它的推文通常包括生日的个人的 twitter 句柄。例如,“21 岁生日快乐**@人**”暗示**@人**年满 21 岁。因此,使用以下代码为每个年龄组收集了 2000 条符合搜索标准的推文:
数据抓取
然后,符合所需格式的 2000 条推文中的每一条(每个年龄的 2000 条推文中不到 25%符合这种格式)都被抓取到紧接在生日短语之前或之后的 twitter 句柄,以识别庆祝他们生日的用户。从每个用户那里收集了 10 条推文作为样本,每个样本包括生日祝福者的用户名、推文 ID、永久链接、文本内容、发布日期、转发次数和收藏次数、提及次数、标签、推文回复者用户名(如果适用)以及推文的地理位置(如果适用)。然后,对每条抓取的推文进行人工审查,删除使用外语的用户、年龄明显不正确的用户(例如,布兰妮·斯皮尔斯被错误地识别为 70 岁)或其账户属于公司或组织而非个人的用户(例如,Old Spice、BBC 等)发出的推文。)
在查看推文数据集后,来自单个用户的 10 条推文被合并成一个样本,该样本包括用户的所有连接推文的字符串,以及调整后的元数据,如最小、最大和平均转发数和收藏夹数。这样做是为了将每个样本与单个用户相关联,从而将数据集从大约 23,000 个样本减少到大约 2,300 个。此外,个人年龄被重新划分为四个不同的类别。18-25 岁的用户归类为 0 类(“Z 世代”),26-40 岁的用户归类为 1 类(“千禧一代”),41-55 岁的用户归类为 2 类(“X 世代”),56-76 岁的用户归类为 3 类(“婴儿潮一代”)。年龄超过 77 岁的用户被丢弃,尽管此操作并没有显著减小数据集的大小。在为每个用户收集了推文和推文元数据之后,网络搜集库 BeautifulSoup 用于搜集每个用户的关注者和追随者数量,因为这些数量无法通过 GetOldTweets3 获得。
一旦我们的整个数据集被管理,它被分成 80/20 的训练集和测试集。这种在所有团队成员之间共享的静态划分的目的是确保每个团队成员单独测试的模型的分数之间更大的一致性和更准确的可比性。在特征工程之前,生成的数据集包含约 2,300 个样本,每个样本包含 17 个特征。
特征工程
收集数据后,基于元数据和自然语言处理(NLP)对推文内容的洞察,生成了附加特征。使用了几个 python 库来生成这些特性:BeautifulSoup 用于抓取元数据,nltk 用于情感分析,better_profanity 用于脏话检测,enchant 用于有效英语检测。下表列出了一些附加功能及其用途说明。
- 追随者/追随比率:知名人士拥有更高的追随者/追随比率。对于那些有更多时间获得声望的老年人来说,这可能是一个指标。
- 收藏夹的平均/最小/最大数量:有很多收藏夹的推文表明用户有一群忠实的追随者。高参与度的用户通常是年轻人和名人。
- 平均/最小/最大转发次数:就像喜欢的次数一样,一条推文的转发次数可以表明用户关注度的高低。这种特征在年轻人和名人中很常见。
- 每条推文的平均标签数:标签被用来关注当前最受年轻用户欢迎的 twitter 趋势。因此,每条推文的大量标签表明用户更年轻。
- 每条推文的平均提及次数:在推文中频繁提及其他用户可能是与其他简档高度互动的指标,这可能表明用户的年龄组。
- 推特频率:我们预计年轻人会比老年人更频繁地发推特。
- 平均字数:我们预计年轻人可能会自发或冲动地发微博,与老年人相比,他们的微博会更短,而老年人可能会发更长、更深思熟虑的微博。
- 情感得分(积极、消极、中立):情感可能表明 twitter 用户的态度,这可能与年龄组相关。
- 标点符号用法:代表标点符号用法的特征可以表明用户在发微博时有多细致或小心,这可以表明年龄组。
- 大写/小写百分比:与标点符号用法类似,不成比例地使用大写或小写可能代表粗心或情绪,这可能表明年龄组。
- 包含脏话、俚语计数、有效单词百分比:这些功能旨在揭示脏话、网络俚语(如 omg、lol、tbh)和正确拼写单词的代际用法差异。我们使用外部库来确定单词是否拼写正确或包含亵渎。
探索性数据分析
下图显示了细化数据集中按年龄组划分的推文分布:
按年龄组分列的概况样本分布
由此得出的按年龄组划分的抓取推文分布显示,年轻用户比年长用户有更强的代表性。这在意料之中,因为 Twitter 是最受年轻人欢迎的社交媒体平台。当人工审查个人资料时,许多针对老一辈的“生日快乐”推文实际上是针对公司或组织的,这减少了老年群体的样本量。受此影响最大的是“婴儿潮”一代。
使用以下包含所有特征和目标变量“年龄组”的相关性热图,对不同年龄组的特征分布进行了探究:
特征关联热图
相关矩阵显示,目标变量“年龄组”有几个预测因素,如中性推文情绪、平均字数、每条推文的标签数、每条推文的平均提及数和关注者与关注者的比率。此外,收藏的平均数量和转发的平均数量之间有很强的相关性。平均字数和周期数之间也有轻微的相关性。这些高相关系数意味着这些对中的一个特征可能在训练期间被丢弃,因为两个特征对目标变量具有相似的影响。
接下来,绘制箱线图,以了解特征如何分布在几个年龄组中,从而进一步研究与“年龄组”高度相关的核心特征例如,下面包含的箱线图用于检查四个不同年龄组的 10 个 tweet 样本的平均字数分布。
字数统计框图
这个箱线图清楚地显示了最小 IQR、最大 IQR 和平均字数在老年人群中是如何增加的。这一信息进一步证实了平均字数可以作为可靠的年龄预测指标。
另一个有趣的特征是关注者数量按年龄组的分布。scraper 捕获了所有年龄组的名人账户和非名人账户,但名人在年龄组中的分布可能有所不同。下图显示了按年龄组划分的关注者数量分布情况:
按年龄组分列的追随者分布
这个箱线图表明,被归类为“千禧一代”和“婴儿潮”的名人比被归类为“Z 世代”和“X 世代”的名人更扭曲这些分布。此外,“Z 世代”的追随者数量分布更加紧密,这表明相比之下,名人在其他年龄组中的比例可能过高。或者,这可能是因为与老一代名人相比,来自“Z 世代”的名人相对默默无闻,因此追随者较少。
最后,单词云被生成来可视化不同年龄组在他们的推文中如何使用单词:
年龄组的词云
虽然像“谢谢”和“爱”这样的词在所有年龄组中都很常见,但也有一些词是某些群体所独有的。例如,从 Instagram 上照片和账户的链接中砍掉了“igshid”令牌。这让我们考虑在我们的模型中加入 n-gram 分析。
模型
我们希望设计一个模型,利用文本推文风格和元数据趋势(如推文频率或字数)的代际差异。此外,最近在自然语言处理方面的突破性发展使用了深度学习模型,称为变形金刚(https://arxiv.org/abs/1706.03762)被用来将序列表示为嵌入,或包含关于它们所代表的单词和句子的上下文信息的向量。出于这些原因,我们的分类器针对我们的分类任务微调了谷歌著名的双向编码器表示(BERT)模型的预训练版本,并将其结果与我们的元数据和生成的特征进行了集成。我们的模型可以分为如下两个阶段:
- 在第一阶段,来自 Python huggingface transformer 库的预训练 BERT 模型加载有用于分类的附加线性图层。该模型被调整以优化分类准确性,并且产生的类逻辑和序列嵌入被用作下一阶段的特征。
- 在第二阶段,元数据特征与由调整的 BERT 模型产生的嵌入和逻辑一起使用,以训练经典的机器学习模型,如随机森林和梯度增强分类器。
模型
阶段 1:从 BERT 生成逻辑和嵌入
Python 中的 huggingface 库提供了对预训练的 BERT 模型的访问,这些模型针对特定任务的应用程序进行了优化,这些应用程序是在数十亿个文档上训练的。特别是,BertForSequenceClassification提供了一个 PyTorch 模块,该模块由 BERT 编码器组成,并在分类任务的合并输出上添加了一个全连接线性层。因此,我们只需加载模型,训练它以最大限度地提高 Twitter 文本数据的分类准确性,并最终提取其预测逻辑(分类器最后一层的向量代表非规范化预测)和嵌入(来自逻辑之前一层的向量代表每个令牌的上下文信息)。四个提取的 logits 代表了模型对十个 tweet 样本属于四个类别中的每一个的置信度,嵌入是向量,粗略地代表了简档的 tweet 作为一个整体。在嵌入空间中彼此更接近的向量代表上下文相似性。
我们为训练集生成了逻辑和嵌入,方法是将它分成八个块,并一次在七个块上微调一个新模型。八个模型中的每一个都用于为维持块生成嵌入和逻辑。这样做是为了避免信息泄漏,因为模型已经看到了它被训练的数据的标签,并且如果它们也被用于训练,则可能产生过度自信的逻辑或过度具体的嵌入。在对七个训练块进行调优之后,针对维持块对每个模型进行评估。最后一个输出图层的结果包含维持配置文件的 logits,上一个图层的结果包含每个令牌的唯一嵌入。一个新序列的开始由第一个[CLS]分类标记来标记,并且它产生一个代表整个序列的嵌入(【https://arxiv.org/pdf/1810.04805.pdf】)。这是被提取出来用作我们的集合模型的特征的嵌入。
首先,定义以下函数来调整 BERT PyTorch 模块,并从模块的输出中提取嵌入和逻辑:
使用 PyTorch 训练和评估配置文件的函数
接下来,在导入必要的库并将我们的训练集分割成 8 个组块之后,BERT 一次调整 7 个训练组块,将简档的链接 tweets 截断或填充到 512 个令牌(BERT 允许的最大值),从而为 8 个组块中的每一个生成如下特征:
为训练集提取逻辑和嵌入
一旦为训练集的所有八个组块生成了逻辑和嵌入,就在整个训练集上训练一个最终调整的 BERT 分类器,并用于为整个测试集生成逻辑和嵌入。测试集的特征是通过对整个训练集进行训练而生成的,并对分类器进行如下评估:
为测试集提取逻辑和嵌入
这个深度学习分类器本身在测试集上实现了 50%的准确率,但通过在模型的第二阶段将提取的特征与我们的元数据和其他工程特征进行集成,这个分数得到了提高。
我们使用 t-SNE 维数约简可视化了我们的 tweet 嵌入的可分性。如下所示,减少到二维的微调 BERT 嵌入已经开始显示出一种模式。特别是,Z 世代嵌入和婴儿潮嵌入之间有很多可分性,而来自 X 世代和千禧一代用户的推文产生了类似的嵌入。
微调 BERT 嵌入上的 t-SNE
这一信息得到了测试集上 BERT 分类器的混淆矩阵的支持,如下所示。Z 世代的分类准确率最高,千禧一代和 x 一代之间的困惑最多
阶段 2:分类器集成
在这一点上,每个 Twitter 个人资料样本都标有元数据特征以及来自 BERT 分类器的 4 个 logits 和 768 个嵌入元素。这种组合的数据被用作经典机器学习分类算法的输入,我们试图用它来实现比纯文本模型更好的准确性。经过一些超参数调整后,几种不同的模型达到了 50 年代中期的精度,包括逻辑回归、随机森林和梯度增强。
然后,我们使用梯度增强和随机森林模型的特征重要性来消除无用的嵌入特征。在所有的嵌入特征中,只有一小部分被认为是最重要的特征被保留下来。这样做的好处是双重的——它大大减少了我们的模型训练时间,同时也提高了性能。
我们的最终模型是一个基于 CatBoost 库的相当简单的梯度提升分类器,对于这个特定的数据集,它的性能优于 XGBoost 和 LightGBM。交叉验证用于深度调整,迭代次数增加,而学习率降低,以优化我们的准确性。这是结果集合模型,其产生 59.76%的准确度:
简单集合分类器
考虑了其他涉及使用 n 元语法的基于 NLP 的方法,这些方法使用 tweet 样本中出现的前 1000 个最常见的一到四个字符标记来创建特征。这种方法不是很成功,因为 BERT 的逻辑和嵌入比每个 n-gram 特征都要好。这可能是由于稀疏的 n-gram 集,可以通过从不同用户收集更多的 tweet 样本来改善;然而,这也凸显了变形金刚作为 NLP 工具的强大,因为 BERT 能够在同一组 tweets 上产生可分离的特征。
分析
最终模型混淆矩阵
总的来说,我们的最佳模型具有 59.76%的总体准确度,这明显优于产生 25%准确度的随机预测器。然而,对混淆矩阵的进一步检查表明,该模型在区分 Z 世代人和其他代人方面明显更好,准确率为 80%。尽管其他几代人 50%的准确率还不错,但这些结果表明,Z 世代人在 twitter 上表现出了与其他几代人明显不同的特征。即使在仅基于文本的模型中,Z 世代的分类准确率也比其他任何一代都高。
回顾我们的最佳模型的特征重要性揭示了一些有趣的结论。根据特征重要性,我们微调的 BERT 模型的输出逻辑和所选嵌入排名靠前,这表明不同代人在网上表达自己的方式存在明显差异。然而,脏话计数和俚语计数功能的排名出奇地低。这表明每一代用户使用脏话和俚语的方式相似,这与互联网上年轻人随意使用脏话和俚语的刻板印象相矛盾。然而,俚语和粗话随着时间的推移会发生快速变化,可以采取措施根据某些单词和短语在几代人之间的流行程度对粗话和俚语进行分类。
此外,以收藏和转发形式出现的用户参与似乎不是非常可靠的年龄预测指标。这表明,不同代人制作的内容质量没有差别。然而,这可能只是群体思维的一个迹象,因为个人倾向于追随与他们观点相同的其他人,这可能会导致一些推文在这些回音室中得到更积极的接收,而不是整个推特群体都接触到它们。
相反,跟随者、跟随者以及跟随者与跟随者的比率是决定世代的非常重要的特征,这回避了模型是名人分类器还是世代分类器的问题。
按年龄组划分的用户关注者热图
按年龄组列出的用户关注率热图
关注者数量和关注者/关注比率的相关热图显示,87%的 Z 世代人的关注者少于 10,000 人,88%的人的关注者/关注比率少于 10,这是用于确定个人推特用户名人地位的软基准。这些数字可能是 Twitter 上非名人和名人之间的百分比。然而,其他三代用户的分布则大不相同,有更多的用户拥有超过 10,000 名追随者,追随者与追随者的比率高于 10。这可以解释 Z 世代和其他几代人之间出现在原始混淆矩阵中的准确性差异的部分原因,这表明 Z 世代类可能被解释为伪非名人类,而其他几代人是伪名人类。
无论如何,Z 世代的优异表现并不能解释所有的差异,因为我们的模型仍然能够区分千禧一代、X 世代和婴儿潮世代,每一代的准确率接近 50%。此外,在通过完全删除关于关注者、转发和收藏的信息来“隐藏”可能创建伪名人类别的信息后,梯度增强分类器仍然能够达到 55%左右的准确率。这是对纯文本模型的一个重大改进,即使在隐藏信息以避免利用我们数据的名人分布之后。
结论
我们的模型展示了任何人都可以使用最先进的 NLP 工具来利用来自网络社交媒体的公共信息来创建新的有意义的信息。除了时间限制,最大的困难最终证明是我们缺乏干净、平衡的数据。虽然每个类别的用户数量相似,但大多数老一辈的生日愿望都是针对名人和机构的,这扭曲了我们基于元数据的模型的预测。此外,很难对接近年龄组临界值的个体进行分类,我们的标签程序虽然经过人工审查,但并不完善。也就是说,嵌入在推文和趋势中的信息仍然被有效地利用来创建一个良好的分类器,提供有趣的代际洞察。
例如,千禧一代被证明与婴儿潮一代和 X 一代有着非常相似的特征,尽管他们被老一代人排斥。事实上,仅仅根据推特内容来区分他们和老一代人是非常困难的。另一方面,Z 世代是最容易被推文内容和元数据分开的。这说明了 Z 世代在数字世界中成长的影响,他们在 Twitter 上的可分离性表明,他们对采用新技术的适应使他们能够在如何进行数字互动和交流中发展自己的集体身份。网络俚语和脏话的代际使用差异很小,这表明所有代人都能够适应快速变化的文化规范,从而对流行观点提出了挑战。
展望未来,这些方法不仅限于提取关于社交媒体使用的有趣事实,实际上可以用来对世界产生真正的影响。这项技术可能被证明在年龄分类起着重要作用的应用中是有用的,例如个性化数字体验或广告。此外,我们将基于迁移学习的模型与经典机器学习模型相结合的方法可以应用于利用最先进的 NLP 工具来完成其他重要的分类任务,如自杀预防和捕食者检测。自然,这些应用程序在数据可用性方面都会面临类似的挑战。但随着社会继续拥抱技术,从每天每秒共享的大量新数据中产生知识的新方法将继续出现。