TowardsDataScience 2023 博客中文翻译(三百六十八)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

咖啡的激光粒子分析何处出错

原文:towardsdatascience.com/where-laser-particle-analysis-went-wrong-for-coffee-3467b2e38685?source=collection_archive---------8-----------------------#2023-05-05

咖啡数据科学

让我们做得更好

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Robert McKeon Aloe

·

关注 发布在Towards Data Science ·4 分钟阅读·2023 年 5 月 5 日

几周前,关于咖啡中的细粉讨论,另一位咖啡爱好者注意到直径小于 100um 的颗粒存在异常。我开始更深入地研究我的一些数据,并发现了他所看到的趋势。然而,我发现了另一个问题:分箱。

粒子分布通过分箱粒子并形成直方图来完成。90um 和 100um 大小的粒子有多少?这些粒子的总百分比是多少?或者这些粒子的总体积百分比是多少?这些都是粒子分布回答的问题类型。

这是使用与激光颗粒分析仪相同的分-bin 的样本颗粒分布图。测量颗粒时,你计算每个分-bin 内的颗粒数量,每个分-bin 有一个范围。这形成了一个直方图,通常直方图有相等的分-bin 大小。在我的领域,它们在讨论图像中的颜色值变化时非常普遍。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用与激光颗粒分析仪相同的分-bin 进行成像的样本分布。所有图像均由作者提供。

然而,激光颗粒分析仪似乎使用对数刻度来表示分-bin 大小。这非常成问题,因为它改变了曲线的外观以及我们对数据的解读。这张图展示了不同颗粒尺寸的分-bin 大小。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我从之前的工作中取得了一次测量,并将其放入 1、2、5、10 和 20 um 的分-bin 中,以查看它对信号的影响。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这很难进行比较,所以我对所有曲线进行了归一化处理。在 1um 处,有很多噪声,因为样本数量的变化很大。我可以通过多次测量来测试和减少噪声,或者对于激光衍射,可以通过更多的颗粒来进行测试。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们放大到小于 200 um。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当你达到 20 um 的分-bin 时,某种模式会消失。在 10 um 的分-bin 中,这种模式仍然存在。

如果我们进一步降低到 100um,分-bin 大小就变得很重要:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以看到 100 um 以下有三个峰值。通常,我们会看到 100 um 以下有第二个峰值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按分-bin 大小归一化?

另一种查看数据的方法是按分-bin 大小归一化。在原始图像中,似乎有两个 100um 以下的峰值和一个微小的隆起,一旦归一化,第三个峰值更加明显。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回顾实际的激光 PSD 数据,我们可以看到,当按分-bin 大小(宽度)归一化时,信息更清晰:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原本,很难看到大约 40 um 的情况,这张第二张图展示了那些细节,而无需放大左侧的图表。

这告诉我,我们在颗粒分布上有一个分-bin 问题。如果目标是利用这些数据来了解咖啡,我们需要从现有设备中获得更好的分-bin。

另外,为什么会有这么多峰值?这是信号还是噪声?需要更多数据。

如果你喜欢,可以在 TwitterYouTubeInstagram 上关注我,我会发布不同机器上的浓缩咖啡视频以及与浓缩咖啡相关的内容。你也可以在 LinkedIn 找到我。你还可以在 Medium订阅 上关注我。

我进一步的阅读

我的书

我的链接

浓缩咖啡文章合集

工作与学校故事合集

针对你的大数据项目,应该使用哪个数据格式?

原文:towardsdatascience.com/which-data-format-to-use-for-your-big-data-project-837a48d3661d

Pickle、Parquet、CSV、Feather、HDF5、ORC、JSON:你应该使用哪个格式,为什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Armand Sauzay

·发表于Towards Data Science ·6 分钟阅读·2023 年 10 月 26 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源于 Maarten van den Heuvel — Unsplash

选择正确的数据格式在数据科学项目中至关重要,影响从数据读写速度到内存消耗和互操作性等各个方面。本文探讨了 Python 中七种流行的序列化/反序列化格式,重点关注它们的速度和内存使用影响。

通过分析,我们还将看到如何在 Python 中使用性能分析(使用cProfile内置模块),以及如何获取文件系统中特定文件的内存使用统计(使用os Python 模块)。

当然,每个项目都有其特定性,除了速度和内存使用之外。我们将总结一些趋势,希望能为选择适合的格式提供一些启示。

理解序列化和反序列化

序列化是将对象(例如 Python 中的 pandas DataFrame)保存为可以保存到文件中以供后续检索的格式的过程。反序列化是这个过程的逆过程。

数据框是一个 Python 对象,不能直接持久化。它需要被转换成文件,以便在后续阶段加载该对象。

当你保存数据框时,你是在“序列化”数据。当你将其加载回时,你是在“反序列化”或将其转换回可读的(此处为 Python 可读)格式。

某些格式因其可读性广泛使用,如 JSON 或 CSV。这两种格式还因其语言无关性而被使用。就像协议缓冲区,最初由 Google 开发。JSON 和协议缓冲区在 API 中也很受欢迎,使得不同语言编写的服务之间能够传递数据。

另一方面,一些格式,如 Python 的 pickle,是特定于语言的,不适合在不同编程语言的服务之间传输数据。例如,对于机器学习用例,如果一个仓库训练了一个模型并用 pickle 序列化,那么这个文件只能被 Python 读取。因此,如果提供该机器学习模型的 API 是用 Java 编写的,则必须进行一些转换才能使用。

但对于存储大型数据文件,CSV、JSON 和 Protocol Buffers 等格式在性能上不如更专业的格式,如 HDF5ParquetFeatherORC

在 Python 中处理数据时,pandas 提供了一个方便的 API 用于提取、转换和加载数据。Pandas 支持多种格式(所有支持的格式可以在 这里 找到),其中我们选择了使用最广泛的七种格式并比较了它们的性能:JSON、CSV、Parquet、Pickle、Feather、HDF5 和 ORC。

reproducing 分析的代码可以在 这里 找到。

实验方法

速度内存使用 是选择项目合适数据格式时需要关注的两个关键因素。但这些因素会根据数据的大小和使用的数据类型而有所不同。

为了进行分析,我们创建了 3 个数据集,这些数据集应涵盖大多数用例:仅包含数字的数据框、仅包含字符串的数据框和包含数字和字符串的数据框。每个数据框有 10,000 行和 100 列,代码定义如下:

df_numbers_only = pd.DataFrame(np.random.rand(10000, 100), columns=[f'col{i}' for i in range(100)])
df_strings_only = pd.DataFrame(np.random.choice(['a', 'b', 'c'], (10000, 100)), columns=[f'col{i}' for i in range(100)])
df_mixed = pd.DataFrame(np.random.choice(['a', 'b', 'c', np.random.rand()], (10000, 100)), columns=[f'col{i}' for i in range(100)])

对于内存使用情况,我们只需查看保存数据集时的大小。为了测量内存使用情况,我们将使用 Python 的 os 模块,特别是 os.stat

df_numbers_only.to_csv('df.csv')
file_stats = os.stat('df.csv')
print(file_stats)
print(f'File Size in Bytes is {file_stats.st_size}') #this is in Bytes
print(f'File Size in MegaBytes is {file_stats.st_size / (1024 * 1024)}') #here we convert bytes to Mb

对于速度,我们使用 Python 的 cProfile 库来分析函数执行所需的时间。在这里,我们选择了 10 秒的时间窗口,并查看函数执行了多少次。实质上:

def serialize_csv(df):
    """Serialize df to csv."""
    df.to_csv('test.csv')

func = serialize_csv
args = df_numbers_only

timer = pytool.time.Timer()
duration = datetime.timedelta(seconds=10)
with cProfile.Profile() as profile:
    while timer.elapsed < duration:
        func(*args)
    time_results[(df_name, file_format, operation)] = profile

评估速度:不同格式的速度有多快?

直接进入分析核心,让我们看看用于评估序列化/反序列化速度的图表。请注意,我们对所花费的时间进行了缩放,因此您可以在下面的图表中看到,仅包含数字的 CSV 处理过程最慢,而仅包含数字的 HDF5 处理过程最快,占 CSV 处理时间的 1.09%(大约 1/100)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图像:按格式保存时间

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图像:按格式加载时间

在上述图表中,我们可以观察到几个有趣的速度要点:

  • Pickle/HDF5 是保存纯数字数据的最快格式。

  • Feather 是加载数据的最快格式。

  • 人类可读格式如 JSONCSV 比其他格式要慢得多,特别是在保存/加载仅包含数字的数据时(例如,比 pickle 慢近 100 倍)。

  • HDF5 在保存数据方面表现得非常高效(与 feather、parquet、pickle 持平),但在加载数据时稍逊一些。

内存使用情况:哪个格式消耗的空间更少?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图片:缩放内存使用情况

我们可以观察到:

  • 再次强调,人类可读格式如 CSV 或 JSON 是内存效率最低的格式。而 JSON 的表现甚至比 CSV 更差。

  • parquet 是在给定数据大小(10,000x100)下内存效率最高的格式,这也符合 parquet 是列式数据格式的特点。你可以在这里了解更多信息。

  • 再次强调,当仅处理数值数据时,pickle 是最有效的格式。Pickle 作为 Python 的原生序列化包,这一点并不令人惊讶。

  • 尽管速度更快,feather 数据相比 parquet 占用的内存要多得多。

结果可以在下表中总结(相较于上面的分析略显简单):

作者的概要

结论

选择合适的格式始终取决于你项目的独特需求。但我们仍然可以从上述分析中得出一些一般性的结论。例如,除非互操作性至关重要,并且你需要直观地查看原始数据的样子,否则你最好不要使用诸如 CSV 或 JSON 的人类可读格式。

总的来说,parquet 似乎是一个非常可靠的选择,因为它在内存使用方面表现更佳,同时速度仍然相对较快。

了解每种格式的具体特点也是至关重要的。例如,pickle 是 Python 特有的格式,因此你无法从其他语言读取它。但是对于专注于数值数据处理的 Python 项目来说,pickle 似乎是最佳选择(无论是在速度还是内存方面)。

如果你正在处理大量数据并希望最小化写入磁盘的 GB 数量,parquet 是不错的选择。但如果速度是你的主要关注点,你可能要尝试 feather,但它会占用更多内存。

总而言之,只有你的项目具体需求才能指导你选择合适的格式。但你可以从上述内容中获得一些见解,以便了解哪种格式在你的特定情况下更好。祝编程愉快!

哪些特征对你的分类模型有害?

原文:towardsdatascience.com/which-features-are-harmful-for-your-classification-model-6227859a44a6

如何计算分类器特征的误差贡献,以便理解和改进模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Samuele Mazzanti

·发表于Towards Data Science ·14 min read·2023 年 9 月 12 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[作者图片]

特征重要性是解释机器学习模型的最常用工具。它如此受欢迎,以至于许多数据科学家最终相信特征重要性等于特征优越性。

事实并非如此。

当一个特征重要时,这仅仅意味着模型在训练集上发现它是有用的。然而,这并不能说明该特征在新数据上推广的能力!

为了说明这一点,我们需要区分两个概念:

  • 预测贡献:一个变量在模型预测中所占的权重。这是由模型在训练集上发现的模式决定的。这等同于特征重要性。

  • 误差贡献:一个变量在模型在保留数据集上的错误中所占的权重。这是特征在新数据上表现的更好代理。

在这篇文章中,我将解释计算这两个量在分类模型中的逻辑。我还将展示一个例子,说明使用误差贡献进行特征选择相比使用预测贡献能够得到更好的结果。

如果你对回归比分类更感兴趣,可以阅读我之前的文章“你的特征重要吗?这并不意味着它们是好的。”

目录

  1. 从一个简单的例子开始

  2. 我们应该为分类模型使用哪种“误差”?

  3. 我们应该如何管理分类模型中的 SHAP 值?

  4. 计算“预测贡献”

  5. 计算“误差贡献”

  6. 一个真实数据集的例子

  7. 证明其有效性:使用“错误贡献”的递归特征消除

  8. 结论

1. 从一个玩具示例开始

假设我们有一个分类问题,我们要预测一个人的收入是否高于或低于$ 100k。假设我们已经有模型做出的预测:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

真实值和模型预测。[作者提供的图片]

预测和错误贡献的计算主要基于模型在每个个体上的错误以及每个个体的 SHAP 值。因此,我们需要花时间讨论两个相关点:

  • 我们应该在分类模型中使用哪种“错误”?

  • 我们如何在分类模型中管理 SHAP 值?

我将在接下来的两个段落中讨论这些点。

2. 我们应该在分类模型中使用哪种“错误”?

我们的主要目标是计算模型每个特征的错误贡献。因此,最重要的问题是:我们如何定义分类模型中的“错误”?

注意我们需要一个可以在个体层面计算的错误,然后可以在整个样本上聚合以获得“平均错误”(就像我们对回归模型使用绝对错误一样)。

对于分类模型,最常见的损失函数是对数损失(即交叉熵)。让我们看看它是否适合我们。

这是对数损失的数学公式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对数损失(即交叉熵)。[作者提供的图片]

对数损失似乎是对我们最合适的选择,因为:

  • 公式的外部部分只是一个简单的平均值

  • 如其名称所示,这是一种“损失”,意味着数值越低越好(就像“错误”一样)

让我们尝试理解为什么我们实际上可以称这个为“错误”。为了简化,让我们专注于和中量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

个体对数损失。[作者提供的图片]

这是单个个体对全局对数损失的贡献,因此我们可以称之为“个体对数损失”。

这个公式可能仍然看起来很可怕,但如果我们考虑到——在二分类问题中——y只能是 0 或 1,我们可能会得到一个更简单的版本:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

个体对数损失,替代版本(等同于之前的版本)。[作者提供的图片]

借助图表,现在很容易理解对数损失的主要思想。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

个体对数损失的可视化。[作者提供的图片]

预测概率与真实值的距离越远(无论是 0 还是 1),损失越大。此外,如果预测远离真实值(例如,p=.2 且y=1 或p=.8 且y=0),那么损失会比比例更严重。现在应该更清楚为什么对数损失实际上是一种错误。

我们准备将个体对数损失的公式翻译成 Python 函数。

为了避免处理无限值(当y_pred恰好为 0 或 1 时会发生),我们将采用一个小技巧:如果y_pred距离 0 或 1 的距离小于ε,我们将分别将其设置为ε或 1-ε。对于ε,我们将使用 1^-15(这也是 Scikit-learn 使用的默认值)。

def individual_log_loss(y_true, y_pred, eps=1e-15):
  """Compute log-loss for each individual of the sample."""

  y_pred = np.clip(y_pred, eps, 1 - eps)
  return - y_true * np.log(y_pred) - (1 - y_true) * np.log(1 - y_pred)

我们可以使用这个函数来计算数据集中每一行的个体对数损失:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

目标变量、模型预测以及结果的个体对数损失。[图片来自作者]

如你所见,个体 1 和 2 的对数损失(或误差)非常小,因为预测值都非常接近实际观察值,而个体 0 的对数损失较高。

3. 我们应该如何在分类模型中管理 SHAP 值?

最流行的模型是基于树的模型,如 XGBoost、LightGBM 和 Catboost。获取树模型分类器在数据集上的 SHAP 值是非常简单的:

from shap import TreeExplainer

shap_explainer = TreeExplainer(model)
shap_values = shap_explainer.shap_values(X)

例如,假设我们计算了玩具问题的 SHAP 值,并得到如下结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们模型预测的 SHAP 值。[图片来自作者]

如果你不清楚 SHAP 值的工作原理,可以阅读我的文章:SHAP 值解释:正如你希望有人向你解释的那样。不过,就本文而言,了解以下内容就足够了:

  • 一个正的 SHAP 值意味着:该特征导致该个体的概率增加;

  • 一个负的 SHAP 值意味着:该特征导致该个体的概率减小。

因此,应该清楚的是某个个体的 SHAP 值总和与模型的预测之间存在直接关系

然而,由于 SHAP 值可以假设任何实际值(正值或负值),我们不能期望它等于该个体的预测概率(这是一个介于 0 和 1 之间的数字)。那么 SHAP 总和与预测概率之间有什么关系?

由于 SHAP 值可以假设任何负值或正值,我们需要一个函数来将 SHAP 总和转换为概率。这个函数必须具有两个特性:

  • 它应该将任何实际值“挤压”到区间[0,1]中;

  • 它应该是严格递增的(因为更高的 SHAP 总和必须总是与更高的预测相关联)。

满足这些要求的函数是 Sigmoid 函数。因此,模型对给定行的预测概率等于该个体 SHAP 值的 Sigmoid 函数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从 SHAP 值到预测概率。[图片来自作者]

这是 Sigmoid 函数的样子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sigmoid 函数:shap 和与预测概率之间的关系。[作者提供的图片]

所以,让我们把这个公式转换成一个 Python 函数:

def shap_sum2proba(shap_sum):
  """Compute sigmoid function of the Shap sum to get predicted probability."""

  return 1 / (1 + np.exp(-shap_sum))

我们还可以通过图形展示,查看我们的个体在曲线上的位置:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sigmoid 函数:shap 和与预测概率之间的关系。[作者提供的图片]

现在我们已经了解了应该使用哪个误差以及如何在分类问题中处理 SHAP 值,我们准备好计算预测和误差贡献了。

4. 计算“预测贡献”

正如我们所见,当 SHAP 值高度正(高度负)时,预测值将比没有该特征时高(低)很多。换句话说,如果 SHAP 值在绝对值上很大,那么该特征对最终预测的影响很大

这就是为什么我们可以通过取该特征的绝对 SHAP 值的均值来衡量特征的预测贡献。

prediction_contribution = shap_values.abs().mean()

对于我们的玩具数据集,这就是我们得到的结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

预测贡献。[作者提供的图片]

因此,在特征重要性方面,职位是主要特征,其次是国籍,然后是年龄

那么误差贡献呢?

5. 计算“误差贡献”

误差贡献的想法是计算如果我们移除一个给定特征,模型的误差会是什么。

多亏了 SHAP 值,我们可以轻松回答这个问题:如果我们从 SHAP 和中排除一个特征,我们就能得到模型在不知道该特征的情况下的预测。但这还不够:正如我们所见,要获得预测概率,我们首先需要应用 sigmoid 函数。

因此,我们首先需要从 SHAP 值中减去一个特征的 SHAP 值,然后我们必须应用 sigmoid 函数。在这里,我们得到了如果模型不知道这些特征时的预测概率。

在 Python 中,我们可以一次性处理所有特征:

y_pred_wo_feature = shap_values.apply(lambda feature: shap_values.sum(axis=1) - feature).applymap(shap_sum2proba)

这是我们数据集上的结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们移除了相应的特征,我们将获得的预测值。[作者提供的图片]

这意味着,如果我们没有特征职位,模型将为第一个个体预测 71%的概率,为第二个个体预测 62%,为第三个个体预测 73%。相反,如果我们没有特征国籍,预测值将分别为 13%、95%和 0%。

如你所见,根据我们移除哪个特征,预测的概率差异很大。因此,结果误差(个体对数损失)也会非常不同。

我们可以使用上面定义的函数(individual_log_loss)来计算没有相应特征时的个体对数损失:

ind_log_loss_wo_feature = y_pred_wo_feature.apply(lambda feature: individual_log_loss(y_true=y_true, y_pred=feature))

这是结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果移除相应特征,我们会得到的单独 log-loss。[作者图片]

例如,如果我们看第一行,我们可以看到在没有特征job的情况下,log-loss 为 1.24,而在没有特征nationality的情况下,log-loss 只有 0.13。因为我们希望最小化损失,在这种情况下,最好移除特征nationality

现在,要了解模型在有无该特征时的效果如何,我们可以计算完整模型的个别 log-loss 与去掉特征后的个别 log-loss 之间的差异

ind_log_loss = individual_log_loss(y_true=y_true, y_pred=y_pred)
ind_log_loss_diff = ind_log_loss_wo_feature.apply(lambda feature: ind_log_loss - feature)

这是结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

模型错误与去掉该特征后的错误之间的差异。[作者图片]

如果这个数字是:

  • 负数,则特征的存在会导致预测错误减少,因此该特征在该观察中表现良好。

  • 正数,则特征的存在会导致预测错误增加,因此该特征在该观察中表现不佳。

我们可以最终通过列计算每个特征的错误贡献值,这些值的均值如下:

error_contribution = ind_log_loss_diff.mean()

这是结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

错误贡献。[作者图片]

一般来说,如果这个数字是负数,则特征具有正面效果;相反,如果这个数字是正数,则该特征对模型有害,因为它倾向于增加模型的平均错误

在这种情况下,我们可以看到特征job的存在使得个别 log-loss 平均减少了-0.897,而特征nationality的存在使得个别 log-loss 平均增加了 0.049。因此,虽然nationality是第二重要的特征,但它的表现不佳,因为它使平均个别 log-loss 增加了 0.049。

让我们尝试将这些概念应用到实际数据集中。

6. 真实数据集示例

下面,我将使用一个来自Pycaret(一个在MIT 许可下的 Python 库)的数据集。数据集叫做“Gold”,包含一些金融数据的时间序列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据集样本。特征都以百分比表示,所以-4.07 意味着回报为-4.07%。[作者图片]

特征包括金融资产在观察时刻之前分别 22、14、7 和 1 天的回报(“T-22”、“T-14”、“T-7”、“T-1”)。这是所有用作预测特征的金融资产的详尽列表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可用资产的列表。每个资产在时间-22、-14、-7 和-1 被观察到。[作者图片]

总共有 120 个特征。

目标是预测黄金回报在 22 天后是否会超过 5%。换句话说,目标变量是二元的:

  • 如果 22 天后的黄金回报小于 5%,则为 0;

  • 如果 22 天后的黄金回报大于 5%,则为 1。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

黄金回报 22 天后的直方图。红色标记的阈值用于定义我们的目标变量:回报是否大于 5%。[图片来源]

一旦加载了数据集,这些是我执行的步骤:

  1. 随机拆分完整数据集:33% 的行用于训练数据集,另 33% 用于验证数据集,其余 33% 用于测试数据集。

  2. 在训练数据集上训练一个 LightGBM 分类器。

  3. 使用上一步骤训练的模型对训练、验证和测试数据集进行预测。

  4. 使用 Python 库 “shap” 计算训练、验证和测试数据集的 SHAP 值。

  5. 使用我们在上一段中看到的代码,计算每个特征在每个数据集(训练集、验证集和测试集)上的预测贡献和误差贡献。

目前,我们既有预测贡献也有误差贡献,因此我们可以最终进行比较:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

预测贡献与误差贡献(在验证数据集上)。[图片来源]

查看这个图表可以为我们提供关于模型的宝贵洞察。

最重要的特征是 T-22 天的美国债券 ETF,但它并没有带来如此显著的误差减少。最佳特征是 T-22 的 3M Libor,因为它能最大程度地减少误差。

玉米价格有一些非常有趣的特点。T-1 和 T-22 的回报率都是最重要的特征之一,然而其中一个(T-1)存在过拟合(因为它加剧了预测误差)。

一般来说,我们可以观察到,所有具有较高误差贡献的特征都与 T-1 或 T-14(观察时刻前 1 天或 14 天)相关,而所有具有较小误差贡献的特征都与 T-22(观察时刻前 22 天)相关。这似乎表明最新特征容易过拟合,而指向较旧回报的特征更容易泛化

除了获得关于模型的洞察,考虑使用误差贡献进行特征选择是很自然的。这也是我们将在下一段中要做的。

7. 证明其有效性:使用“误差贡献”的递归特征消除

递归特征消除(RFE)是一个逐步从数据集中删除特征的过程,目的是获得更好的模型。

RFE 的算法非常简单明了:

  1. 初始化特征列表;

  2. 在训练集上训练一个模型,使用当前特征列表作为预测器;

  3. 从特征列表中移除“最差”的特征;

  4. 返回第 2 步(直到特征列表为空)。

在传统方法中,“最差”= 最不重要。然而,根据我们看到的,我们可能会反对,首先去除最有害的特征更有意义

换句话说,

  • 传统 RFE:首先去除最无用的特征(最无用 = 验证集上的预测贡献最低)。

  • 我们的 RFE:首先去除最有害的 特征 (最有害 = 验证集上的误差贡献最高)

为了验证这个直觉是否正确,我使用了两种方法进行模拟。

这是验证集上的对数损失结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两种策略在验证集上的对数损失。[作者提供的图像]

由于对数损失是“越低越好”的度量,我们可以看到我们的 RFE 版本在验证数据集上明显优于经典 RFE。

然而,你可能会怀疑查看验证集是否公平,因为误差贡献是基于它计算的。所以,让我们查看测试集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两种策略在测试集上的对数损失。[作者提供的图像]

即使现在两种方法之间的差异较小,我们仍然可以看到它仍然很大,并且足以得出结论:基于误差贡献的 RFE 在这个数据集上显著优于基于预测贡献的 RFE。

除了对数损失之外,考虑一个更具实际价值的度量会很有趣。例如,让我们看看验证集上的平均精度:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两种策略在验证集上的平均精度。[作者提供的图像]

有趣的是,尽管贡献误差是基于对数损失的,我们在平均精度上也取得了优异的结果。

如果我们想基于平均精度做出决策,那么我们将选择在验证集上具有最高平均精度的模型。这意味着:

  • 基于误差贡献的 RFE:具有 19 个特征的模型;

  • 基于预测贡献的 RFE:具有 14 个特征的模型;

如果我们这样做,我们在新数据上会观察到什么样的表现?回答这个问题的最佳代理是测试集:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两种策略在验证集上的平均精度。[作者提供的图像]

在这种情况下,基于误差贡献的 RFE 的表现通常优于基于预测贡献的 RFE。特别是,根据我们之前的决定:

  • 基于误差贡献的 RFE(具有 19 个特征的模型):72.8% 平均精度;

  • 基于预测贡献的 RFE(具有 14 个特征的模型):65.6% 平均精度。

因此,通过使用基于误差贡献的 RFE,而不是传统的基于预测贡献的 RFE,我们将在平均精度上获得额外的 7.2%优秀结果!

8. 结论

特征重要性概念在机器学习中起着基础性作用。然而,“重要性”的概念常常被误解为“好处”。

为了区分这两个方面,我们引入了两个概念:预测贡献和误差贡献。这两个概念都基于验证数据集的 SHAP 值,文章中我们展示了计算这些值的 Python 代码。

我们还在一个真实的金融数据集上进行了试验(任务是预测黄金价格),并证明基于误差贡献的递归特征消除比基于预测贡献的传统 RFE 提高了平均精度 7%。

你可以在 这个笔记本找到本文所用的所有代码。

感谢阅读!

如果你觉得我的工作有用,你可以订阅 每次我发布新文章时都会收到邮件 (通常是每月一次)。

如果你想支持我的工作,你可以 请我喝咖啡

如果你愿意, 可以加我 Linkedin

哪些 GPT 类似模型工程技术适用于系统日志?

原文:towardsdatascience.com/which-gpt-like-engineering-strategies-work-on-system-logs-6b0a3a1ebcad?source=collection_archive---------4-----------------------#2023-04-21

对行为恶意软件痕迹应用的变换器神经网络建模方法的评估

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Dmitrijs Trizna

·

关注 发表在 Towards Data Science ·11 分钟阅读·2023 年 4 月 21 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1. 从训练于恶意软件仿真报告的变换器模型中提取的自注意力激活。图像由作者提供。

本文评估了应用于机器数据(即来自Speakeasy 模拟器的恶意软件行为日志)的各种 Transformer 神经网络(GPT 的 AI 模型)工程方法。这些实验中使用的数据自发布以来一直可以自由获取,作为混合恶意软件分析 [Trizna]的一部分,档案可以在这里下载。您可以访问这些数据,随意复制或推进结果!

最初,Transformer 被提出作为一种适用于序列到序列任务(如自然语言翻译)的编码器/解码器架构。后来它被调整以适应其他任务,如 GPT 的掩码解码器模型,以便擅长文本生成。由于我们将使用 Transformer 进行推理,模型仅包含编码器层模型的 PyTorch 代码),类似于例如 BERT [Devlin et al.]中使用的架构。

推测地,本文得出的关于 Transformer 工程方法的相同结论可以扩展到任何系统日志集,例如 Windows 上的操作系统遥测如 Sysmon,或对应的 Linux 框架如auditd,应用级日志如来自 Kubernetes API 服务器的kube-audit事件,或 HTTP 服务器的访问日志及计数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2. 预处理过滤后的 JSON 事件到令牌序列的示意图和简化视图,包括过滤器和归一化。图片由作者提供。

虽然是正在进行的研究的一部分,本文避免了更广泛的讨论关于数据和架构组合,而是专注于 Transformer 建模技术的方法论和 PyTorch 代码,以评估相对实用性工程策略,而非绝对性能。评估的配置列表:

  • 三角形、余弦、阶梯和一周期学习率调度器;

  • 累积梯度;

  • 梯度裁剪;

  • 注意力块的预归一化与后归一化;

  • 数据优化;

  • 学习率对模型大小的依赖。

对于所有配置选项,我进行三次交叉验证运行,并报告验证集和测试集的平均 ROC 曲线以及训练损失。本文不涵盖模型的自监督预训练,而是专注于恶意软件分类的下游任务(即监督学习)。

许多出版物已经系统地分析了 Transformer 在自然语言方面的工程进展,我们将在机器数据上探讨这些进展。考虑到进一步研究这里提出的观点,我建议学习,例如,“临时性”论文 [Geiping and Goldstein]

优化数据集

数据由 ~120k 恶意软件和良性软件样本的 JSON 报告组成,恶意样本涵盖了如勒索软件、木马、后门等七种恶意软件类型。然而,我将实验限制为二分类,Clean 标签表示良性类,所有其他标签表示恶意样本。值得注意的是,测试集是在训练集收集后三个月收集的,以引入概念漂移下的评估。

由于模拟是一种不完美的方式来获取回避型恶意软件样本的行为,进一步 过滤和规范化 被应用于上述报告,以剔除失败或不完整的模拟,从而在训练集中得到 76126 个样本,在测试集中得到 17407 个样本。

序列长度减少的字段过滤器

根据我们的观察,存储在机器数据中的任何语义逻辑都跨越了非常长的标记序列,包括无数次的元数据和环境特定信息,这些信息对于建模任务几乎没有相关性。可以说,这是自然语言和机器语言之间最显著的差异之一。前者在相对较短的句子中具有简洁的语义,没有或很少有无用的组件。

对自注意力模型来说,这很不幸,因为其在输入长度上的复杂度是平方的,这意味着较长的序列训练成本指数增长。这是因为自注意力中的每个元素都必须关注同一序列中的每个其他成员——请参见上面的图 1 标题以获取可视化。

因此,在处理机器数据时应用基于领域知识的过滤器是必不可少的。在我们的案例中,JSON 事件 会被过滤,过滤依据包括(1)文件,(2)注册表,(3)网络访问,以及(4)API 调用名称、参数和返回值。这显著提高了知识密度(即每个标记的相关知识比率)和数据质量。

序列长度在下面的实验中限制为512个标记,以便更快地迭代配置组合,但为了最终性能评估或生产实现,建议保留较长的序列。有证据表明,任务相关的性能从更长的序列中受益,如下图的热图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3. 在假阳性率为 0.001(每 1000 次检测一个假警报)下的平均真正率,取决于变量序列长度和词汇大小。图片由作者提供。

标记化

机器数据的词汇量可能比自然语言大得多,因为通常没有明确的词汇边界或语法规则来定义所使用的语言。

在系统日志中,常见的任意字符组合如*/tmp/83afba/setup.binjre1.8.0_311*,由于处理不当,会导致词汇量爆炸。例如,我观察到大约有 3000 个独特的 API 名称,其中约 1000 个在训练数据中仅出现一次。

因此,您为模型分析包含的每一个额外字段都会显著增加词汇量。请参见下面的对数图,显示了不同 JSON 字段过滤器设置下的训练集标记的频率分布:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4. 针对训练集应用不同 JSON 字段过滤器的标记频率分布。图片由作者提供。

例如,给定一个使用 API 调用、文件、网络和注册表记录的字段过滤器,总词汇量大约为 25 万标记。假如没有应用过滤器,这个数字会接近 80 万标记,词汇量爆炸超过三倍,并显著降低数据的认知密度(每个标记的有价值信息)。这强调了合适的领域知识影响的过滤器对提高模型接收的数据质量的重要性。

对于任意值字段如哈希值和 IP 地址的归一化也是一样的。例如,将哈希值不处理会极大地扩展词汇量,而使用下面的函数将其归一化为像**这样的值,则会得到一些易于解释的占位符,模型可以利用这些占位符:

这只是一个简单的例子,而我管道中实现的所有归一化可以在这里找到。

然而,另一个关键技巧是改进标记化本身,以便技术数据中的变异不会无限期地创建新标记。自然语言已经提供了适合机器数据的解决方案。

我定义了一个基于 Google 的SentencePiece的自定义 JSON Byte Pair Encoding (BPE)标记器(代码),它分析字节的相对共现方式。这样,标记并不代表技术语言中的独立值,而是较长值序列的一部分,如下面的例子所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5. 空白标记示例。图片由作者提供。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 6. SentencePiece 的 BPE 标记示例。图片由作者提供。

我将进一步的实验限制在50k BPE 标记的词汇量内。

模型大小和学习率

学习率(LR)的选择很直接,对任何深度学习从业者来说都是已知的。然而,我想强调的是,对于 Transformer 架构,选择适合的学习率范围对于特定模型大小尤其重要。

请参阅 GPT-3 论文 [Brown et al.]中的此表格,该表格报告了不同模型的配置以及使用的学习率的变化:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

表格 1 来自 GPT-3 论文 [Brown et al.]。注意学习率和批量大小如何根据可训练模型参数的数量而变化。

注意到模型增长后的学习率减少的意义,模型大小增加 ~1000 倍时,学习率降低 ~10 倍。

由于硬件设置(单个消费级 GPU),我使用了一个具有 ~5–6 M 参数的适中大小的模型。由于本文评估的是相对配置效用而不是达到最先进的绝对值,因此这是一个适合快速迭代多种配置的良好大小,为更大模型的行为提供了良好的基准。行业数据显示,模型大小(非嵌入层中的参数数量)强烈预测性能 [Kaplan et al.]——这一特性被称为“规模定律”。因此,模型的大小和数据集的增加应在生产发布时产生必要的检测率。

我决定循环测试从 0.003 到 0.0001 的一系列学习率,每次降低约 ~3 倍。结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 7. 在三个交叉验证折叠中,变量学习率下的验证集和测试集 ROC 曲线的平均值以及训练损失。图像由作者提供。

可以明显看出,0.003 太大,而 0.0001 太小,最佳值在 0.0003–0.001 之间。我选择了接近底线 ~0.0003 的学习率进行进一步测试。

学习率调度器

一旦为给定模型选择了适当的最大学习率,我探索了各种学习率值的调度器。调度器是指在训练过程中修改学习率值的函数。

定义了多种调度器,这些调度器基于最有前景的出版物中报告的调度器,具体为:(1)阶梯型,(2)三角形,(3)单周期,以及(4)余弦型,学习率随训练时间的变化如下面所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 8. 不同调度器下的训练步骤中的学习率变化。图像由作者提供。

实验结果(包括一个完全不使用任何调度器的运行)如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 9. 各种调度器应用的结果。图像由作者提供。

我们可以清楚地看到,具有“预热”阶段的调度器——即不从最大 LR 值停止(“三角形”型和“一周期”型),在前~2000 次更新期间具有更高的训练损失。从测试集上的 ROC 来看,我们可能会得出“一周期”表现最差的结论,没有调度器在低假阳性率(FPR)要求下可能会有更高的真正率(TPR,即检测率)。

为了消除歧义,这里是测试集中在最低 0.0001(意味着每 10,000 次分析中出现一个假警报)假阳性率下的精确 AUC 和 TPR 值:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

表 1. 在特定假阳性率(列)下的平均真正率(值)以及在测试集上的 AUC,基于 3 次交叉验证折叠。表格由作者提供。

这表明,在特别低的假阳性要求下,使用“步进”调度器的训练效果最好,而整体最佳 AUC 则使用了“三角形”调度器。确实,有证据表明“预热”可能很重要,特别是对于自监督预训练。

值得注意的是,没有调度器的训练在最低 FPR 下表现较差。这可能表明“冷却”(即在结束时逐渐减少 LR 值)对找到最佳模型的局部最小值尤为重要。对于信息安全应用来说,使用具有“冷却”阶段的调度器可能至关重要,因为假阳性会消耗人工分析师的警报预算,并且成本较高。

如果你对深入探讨 LR 调度器的话题感兴趣,以下的 TDS 文章可能会引起你的兴趣。

累积梯度

一位好奇的读者在我们讨论模型大小对学习率变化的影响时,注意到了 GPT-3 表 1 中的批量大小差异。不同的模型大小需要不同数量的样本来生成最佳的梯度更新。对于最小的模型,GPT 作者使用了 500k 样本的批量大小,而对于最大的模型,包括 GPT-3 本身,他们每次权重更新处理了 3.2M 样本。

鉴于资源有限的训练,适合单个 GPU 的批量大小是不理想的。从 64 或 96 个样本计算出的梯度向量可能有偏差,导致收敛缓慢。因此,讨论有限约束下训练的资源会提到在更新权重之前累积梯度的技术(即在 PyTorch 中调用optimizer.step())。使用梯度累积的训练循环如下:

关键点在于,accumulation_steps的不同配置下训练速度有所不同。例如,每步更新梯度的速度比每 16 步更新一次要慢。因此,我设置了每次训练运行的相同时间预算为十分钟——以评估每种配置在相同计算资源下的效率。这使得更新率较低的运行能够在相同的时间内处理更多的批次(因此,训练损失的长度不同)。结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 10. 不同累计梯度批次值在三次交叉验证折叠中的验证集和测试集 ROC 曲线均值及训练损失。图片由作者提供。

出于某种原因,我们发现这种技术显著降低了最终模型的性能。无论是使用本地 PyTorch 实现梯度累积,如上所示,还是使用 HuggingFace 的 accelerate,都有相同的模式。因此,这不应该是实现中的 bug。即使具有累积循环的模型在相同训练预算内处理的批次数明显更多,经典实现的数据量减少约 5 倍仍然能达到更高的检测率。

梯度裁剪

梯度裁剪是一种在参数更新过程中设置梯度值上限的方法。梯度爆炸是递归神经网络(RNN)的一个显著缺陷,而梯度裁剪被引入作为解决 RNN 梯度爆炸的问题的方法。然而,实际上,所有近期关注 Transformer 的论文也都实现了这一技术。它通过没有明显缺陷的方式稳定训练过程。PyTorch 提供了一个专门的clip_grad_norm_函数,用一行代码在训练循环中实现这一逻辑(例如,在optimizer.step()调用之前,参见)。变量值在 0 到 1 范围内的结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 11. 不同梯度裁剪限制在三次交叉验证折叠中的验证集和测试集 ROC 曲线均值及训练损失。图片由作者提供。

我们清楚地看到,0.1 的裁剪值是次优的,而其他三个选项的曲线没有得出明确结论。因此,如前所述,查看下表中特定 FPR 和 AUC 值的 TPR 是非常有帮助的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

表 2. 在 3 次交叉验证折叠中的特定假阳性率(列)下的平均真正率(值)和测试集上的 AUC。表格由作者提供。

在这里,很明显 1.0 的梯度裁剪提供了最佳的指标,在极低的 FP 条件下具有最高的整体 AUC,并且至少比其他选项多出 3% 的好处。

层归一化 — 输入或输出

原始 Transformer 实现将 层归一化 应用于自注意力块的输出。然而,现代文献一致认为输入归一化优于经典设置(有关更多细节,请参见 PreNorm vs. PostNorm 讨论,如 [1]、[2])。

值得注意的是,PyTorch 的默认行为仍然是经典的 PostNorm,但通过修改 Transformer Encoder 块中的一个 norm_first 布尔值可以轻松更改。我们的结果证实了公众的观点,输入归一化优于经典实现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 12. 预归一化和后归一化配置的验证集和测试集 ROC 曲线以及训练损失的均值。图片由作者提供。

一个持续的争论是 RMSNorm 是否优于传统的 LayerNorm,其中 LLaMa 等实现使用 RMSNorm,而 其他实验 则显示没有明显的好处。我们将其排除在我们的分析之外。

总结

通过实验,我们发现某些配置,如 (1) 输入归一化、(2) “三角形”或“阶梯”学习率调度器,以及 (3) 大约 1.0 的梯度裁剪,有效地提高了模型性能。另一方面,梯度累积没有改善性能,这需要进一步探索。

此外,我们讨论了为机器数据工程化 Transformer 模型时的重要注意事项,如 (1) 领域知识影响的过滤、归一化和分词以减少词汇表和 (2) 关于模型大小的学习率选择。

如上所述,推测性地,可以将关于 Transformer 工程方法的相同结论扩展到其他类型的系统日志,如操作系统遥测或 HTTP 服务器的访问日志,希望本文能为将现代 AI 技术应用于减轻行业专业人士日常任务的挑战性工作做出贡献。

我应该选择哪个在线数据科学课程?

原文:towardsdatascience.com/which-online-data-science-course-should-i-do-5a73c0b2c9c2

提示:从免费的资源开始

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Matt Chapman

·发表于 Towards Data Science ·阅读时间 7 分钟·2023 年 7 月 11 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自 HeadwayUnsplash

如果你想学习数据科学中的一项新技能,决定选哪个课程确实很困难。

当我在 2019 年寻找我的第一个在线数据科学编码课程时,我陷入了 分析瘫痪 的困境,花了太长时间在不同选项之间做决定。然后,当我终于做出决定并花了 20 英镑购买一个课程时,我很快发现这并不适合我,甚至没有完成它。

根据研究,我不是唯一的一个——开放大学(2015)和 ResearchGate(2018)的研究估计,在线课程的完成率低至 3%。

没错,3%。

自从 2019 年那次糟糕的第一次尝试以来,我已经参加了(并完成了!)许多其他课程,并学到了如何挑选合适课程和最大化其价值的重要经验。在这篇文章中,我将分享一些我上过的最佳课程,并介绍我用来帮助我在课程之间做出决定的 5 个关键考虑因素。这是我希望在 2019 年时听到的建议,如果对你有帮助,点击我的“关注”按钮将对我意义重大——只有 1%的读者这么做!

1. 从免费的资源开始

我在数据科学学习者中遇到的最大误解之一是 $$$ 课程 = 更好的课程

说实话,一些最好的资源是完全免费的。像 YouTube、freeCodeCamp 和 Towards Data Science 这样的免费平台提供了成千上万的高质量在线课程,涵盖了几乎所有的数据技能,每当我需要学习新东西时,它们总是我的首选。因为这些课程是免费的,所以“试用后再购买”非常容易,这意味着在你决定花钱或开始整个课程之前,它们是测试课程适用性的绝佳方式。

例如,当我在 2021 年需要学习 git/GitHub 时,我尝试了 YouTube 上的多个免费课程,最终决定使用 Tech With Tim 的这个 课程。它时间短(40 分钟)、免费,而且有大量的社会证明(高观看次数/评分),涵盖了我需要的一切。如果你从零开始学习一个新主题,尝试一个小课程(比如 YouTube 上的课程)要比直接投入一个完整的长期课程要好得多。你可以随时转向付费课程(如果需要),但如果你没有先检查过免费选项的质量,为什么要一开始就选择付费课程呢?

这里有一些我可以彻底推荐的优秀免费课程(这些不是附属链接,也没有其他类似的东西,它们只是我参加过并且喜欢的免费课程):

2. 选择一个符合你具体目标的课程

我参加的第一个在线课程是一个通用的 Python 课程。虽然这是一个很好的课程,但它并没有特别专注于 数据科学 方面的 Python 应用(这是我的学习目标),而且我被迫完成了一些我不感兴趣的模块(例如,网页应用开发、地理空间分析)。这很快变得无聊/无效,不久之后我就放弃了。

为了避免犯这种错误,我建议你从一个针对小而具体目标的课程开始,然后再逐步深入。

例如,与其设定一个宏大的目标如“学会编程”,不如将其拆解为一个更小的目标如“像数据科学家一样编程”。然后,再进一步拆解为一个更小的目标,选择一种具体的语言(例如 Python),再选择一个专注于特定技能(如数据分析)的 Python 课程(例如,像这样的课程)或机器学习(例如,像这样的课程)。

这是我在学习 Python 时效果最好的方法:我开始时是为了一个非常具体的目的(数据分析)学习 Python,并在此基础上扩展到其他领域(如网络开发或机器学习),根据需要逐步学习。

3. 这个课程是否有内置的代码编辑器,还是需要你在自己的电脑上本地运行代码?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由Chris Ried提供,来源于Unsplash

很多电子学习平台内置了代码编辑器,允许你在浏览器/应用程序中编写和执行代码。这种方式的好处是,你可以非常轻松地开始编码,无需任何安装或设置。如果你选择像 Enki 这样的移动友好平台/应用程序上的课程,你甚至可以在通勤时或坐在厕所上时进行编码。

这类课程的缺点是,你不一定会学会如何在“实际环境”中运行代码,超出那个特定的电子学习平台。

如果你的目标只是学习语法并“试用一下”,那么带有内置编码编辑器的课程是一个很好的解决方案。像 CodeAcademy、DataCamp 和 freeCodeCamp 这样的网站上的课程在这方面非常棒。

如果你想在真实系统中学习,尝试寻找鼓励你自己“边编码边学习”的课程。例如,在我提到的课程中,像SQL 教程——初学者完整数据库课程这样的课程非常适合。

4. 找一个能够让你每天坚持学习的课程(“小量、多次”比临时抱佛脚要好)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由Christine提供,来源于Unsplash

坚持学习是建立课程惯性的#1 最佳方式。

我目前在 Duolingo 上已经坚持了 324 天学习阿拉伯语,虽然还有很长的路要走,但我现在的阿拉伯语水平比 324 天前要好很多。有时我会在 Duolingo 上花 30 分钟,有时则花 2 分钟。但是,通过专注于坚持,帮助我保持一致性,并确保即使在动力不足的日子里也能做一些事情。

编程课程也是一样的道理。

如果你在工作或大学期间学习在线课程,你的动力和可用时间可能会波动很大。通过坚持保持一个连续的学习习惯,你可以确保即使在繁忙的日子里也能保持一致。从长远来看,这也比“临时突击学习”要可持续得多。记忆曲线意味着我们很容易忘记一天内学习的内容,只有当我们定期回顾这些话题时,学习才会深入。

因此,当你在选择课程时,尝试找一个能让你建立小的学习习惯的课程。如果课程是一个 10 小时的非互动讲座,在忙碌的日子里可能很难进行“2 分钟的学习”,你也可能会倾向于放弃。相反,如果课程包含许多示例问题和小练习,那么在短时间内进行快速学习并保持学习习惯会容易得多。

如果每天坚持不现实,那为何不尝试每周坚持一次?你能否在接下来的 52 周内每周做一点?

5. 通过将大课程拆分为“迷你课程”来创建自己的“课程”

当我的奶奶在 1960 年代尝试戒烟时,她给自己立了个承诺:如果她连续三个月不吸烟,她将用她原本用于购买香烟的钱买一块新手表。

我一直喜欢那个故事,虽然发生在 60 年前,但我认为它在 2023 年仍然对我们有很多智慧。

如果你唯一的目标是“完成”整个课程,你会给自己设置一个漫长而艰难的任务。如果你将目标拆分为迷你目标(例如,“完成这一章”),并不断奖励自己以达到这些迷你目标,你会发现保持动力变得容易得多。

例如,当我参加IBM 数据科学专业证书时,我会在每章结束时用一小块甜点奖励自己,并将刚刚学到的内容应用到我的在线作品集上。这些看似微不足道的奖励实际上真的帮助我保持了动力,因为总是有一些短期内可以实现的具体目标。

就这样!我选择好课程的顶级技巧,以及一些对我帮助最大的课程。

哦,还有一件事 —

我启动了一个免费的通讯《AI in Five》,每周分享 5 个要点,涵盖最新的 AI 新闻、编程技巧以及数据科学家/分析师的职业故事。没有炒作,没有“数据是新的石油”的废话,也没有埃隆的推文——只有实用的技巧和见解,帮助你在职业发展中前进。如果这对你有吸引力,点击这里订阅

[## AI in Five | Matt Chapman | Substack

最新的新闻、职业故事和编码技巧,来自数据科学和 AI 的世界,以 5 个要点总结…

aiinfive.substack.com

黑客使用哪些编程语言?

原文:towardsdatascience.com/which-programming-languages-do-hackers-use-ac3ed9d3e8f8?source=collection_archive---------8-----------------------#2023-01-31

使用 Python 分析漏洞数据库

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Christian Koch

·

关注 发表在 Towards Data Science ·8 分钟阅读·2023 年 1 月 31 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Luca Bravo 提供,来源于 Unsplash

在 2021 年,我们与其他科学家一起在德国混沌计算机俱乐部(CCC)进行了调查。我们的目标是找出黑客最常用的编程语言。本文跟进了调查结果,并将其发现与对Exploit Database的分析进行比较。读者将获得逐步的环境设置说明和结果总结。因此,本文不仅涵盖了应用技术,还提供了有关网络安全领域的见解。

调查概述

作为欧洲最大的黑客协会,混沌计算机俱乐部为研究该领域中流行的编程语言提供了良好的基础。为此,我们在 2021 年 5 月向俱乐部的成员发送了一个在线问卷的链接。根据结果,受访者主要使用 Shell 和 Python 进行黑客攻击。调查的另一个关键发现是,他们的语言偏好随着时间的推移发生了变化。总体而言,参与者并不认为编程语言的选择对黑客攻击至关重要。由于样本量只有 48 个,研究的样本量相对较小。由于仅针对 CCC 的成员,结果也可能存在偏差。本文的目标是通过分析 Exploit-DB 来验证关键结果。

关于 Exploit-DB

在 CCC 调查进行的同一年,一种被称为零日漏洞的攻击引起了广泛关注。当时,流行的日志框架 Log4j 遭遇了一个高度严重的漏洞。利用这种安全缺陷的脚本称为exploit。顾名思义,Exploit Database 提供了一个包含 exploit 和相应易受攻击软件的公共档案。该平台的目标用户是渗透测试人员和安全研究人员。用户可以通过其网站或在Kali Linux下提供的工具集访问数据库。

在撰写本文时,Exploit-DB 中已发布超过 45,000 个 exploit,来自 9,000 多名独立作者(source)。数据库条目包含不同的属性,如 exploit ID、作者、类型和发布日期。每个记录与一个包含实际脚本或程序的文件相关。在 Kali 系统下,我们通过执行 shell 命令exploitdb来找到数据库的根目录。该目录包含一个 CSV 文件(files_exploits.csv*)*,以及包含实际脚本或程序的子目录(exploits/)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:Kali Linux 下的 Exploit-DB 目录

本文描述的比较是在 2023 年 1 月 13 日使用 2022 年 11 月 22 日的数据库快照准备的。快照和分析的源代码都可以在GitHub上获取。

设置和数据转换

为了设置分析环境,第一步是克隆 GitHub 项目。所有所需文件都存储在其根目录exploits中。该实现基于Anaconda Python 发行版,客户端机器上必须预先安装该发行版。可以通过在项目根目录中执行以下命令来创建和激活 conda 环境:

conda env create -f environment.yml
conda activate exploits

要分析的数据库快照存储为data文件夹中的 CSV 文件。它是从 Kali Linux 中获取的,并通过脚本execute_transformer进行了转换。转换时间和快照时间都记录在文件timestamps中。如有需要,可以通过在 Kali shell 中运行以下命令来更新快照:

cp -p /usr/share/exploitdb/files_exploits.csv data/
python execute_transformer.py

转换脚本提供了整理数据和推导附加字段的功能。一个主要任务是提取使用的编程语言的信息。为此,应用了库Pygments。虽然其主要目的是语法高亮,但该框架提供了猜测特定文件编程语言的功能。

除了 Pygments,还有其他语言检测库。本文测试的一个例子是深度学习解决方案Guesslang。然而,将其集成到 conda 环境中证明是困难的,而且处理时间远远超过 Pygments。由于 Guesslang 没有产生更好的结果,因此采用了后者框架。以下函数将 Pygments 纳入数据转换脚本中:

import pygments
from pygments.lexers import guess_lexer_for_filename

def _parse_exploit_file(file_name):
    with open(file_name, encoding="UTF-8") as file:
        lines = file.readlines()
        text = "\n".join(lines)

        line_count = len(lines)

        try:
            lang_guessed = guess_lexer_for_filename(file_name, text).name
        except pygments.util.ClassNotFound:
            lang_guessed = None

        return line_count, lang_guessed

上述 Python 代码读取某个文件,统计其行数,并使用函数guess_lexer_for_filename来检测编程语言。为此,框架应用了各种 Lexer,即用于语法分析的类。只有那些分配给给定文件扩展名的 Lexer 被考虑在内。有些扩展名只有一个类,而其他扩展名则存在选择上的模糊性。例如,扩展名“py”明确指向 Python,而“pl”扩展名则可能指向 Perl 或 Prolog。最佳匹配的 Lexer 被作为结果返回。其名称揭示了编程语言,并为分析提供基础。下一节讨论的发现源自于笔记本 comparison。此外,GitHub 项目还提供了进一步的笔记本,以探索 Exploit-DB 的具体方面。

结果讨论

CCC 调查的核心问题是参与者在研究前一年使用了哪些编程语言。受访者可以选择多个答案选项。图 2 比较了 CCC 成员提及的前十种语言与 Exploit-DB 作者使用的语言。图表揭示了相似之处,也显示了差异。

首先,样本规模存在一个主要差距。总体而言,48 名 CCC 成员参与了调查。相比之下,超过 900 名独立作者在 2020/21 年间在 Exploit-DB 上发布了 2,500 多个文件。这两年被选中是因为它们与比较研究的研究期重合。为了避免重复,每个作者-语言组合在 Exploit-DB 中仅计数一次。在研究期间,这导致了 1,134 个语言参考,其中 1,116 个属于前十名。另一方面,CCC 调查的参与者将他们的前十种语言提及了 140 次。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:CCC 调查和 Exploit-DB 的前十种语言

CCC 的成员主要使用 Shell(Bash/Shell/PowerShell)和 Python,其次是 C、JavaScript 和 HTML/CSS。所有这些技术在 Exploit-DB 中也都有出现。总体来看,语言选择有很大重叠。图 2 中的十种技术中有六种出现在两个列表中。Python 始终排名第二,显示出其在网络安全领域的受欢迎程度。然而,图表一侧的某些语言在另一侧并未出现。

一个主要的区别是 Exploit-DB 中语言的分布不均。超过一半的提交是文本文件。在这里,Pygments 分配的名称“仅文本”具有误导性。Exploit-DB 中的文本文件通常包含描述,但也经常包含 shell 命令和可能的其他语言脚本。因此,某些技术在结果中可能被低估。抽样检查显示,这对 shell 脚本可能确实成立,后者在 CCC 研究中排名第一。这也是我们方法的一个局限性。像 Pygments 这样的框架在评估多语言文件时存在问题。克服这一问题将是一个有趣的后续研究课题。

让我们暂时离开 2020/21 年,并查看 Exploit-DB 的整个历史。图 3 显示了数据库中所有时间的前十种语言。与之前一样,语言检测依赖于 Pygments,每种作者-语言组合只计算一次。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:Exploit-DB 中所有时间的前十种语言

根据图 3,Exploit-DB 中所有时间的前十种语言以 Text 为首,其次是 Python、C、HTML 和 Perl。再次,这与 CCC 成员的选择有相当大的交集。一个惊讶的发现是 Prolog 出现在列表的后半部分。推测原因是将扩展名为 “pl” 的文件错误分类。无论如何,Perl 的相对较高排名值得注意,因为该语言在图 2 中根本没有出现。这与 CCC 调查的另一个发现相符。在研究中,大多数参与者(77.5%)报告称他们的语言偏好随时间发生了变化。为了评估这一点,我们可以查看图 4。该图表可视化了在本分析之前的 25 年中 Exploit-DB 前十种语言的百分比份额。每种作者-语言组合每年只计算一次。因此,我们在研究期间发现了来自 9,592 位独特作者的 16,422 个语言引用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4:分析前 25 年 Exploit-DB 中的前 10 种语言

图 4 揭示了 Exploit-DB 中文本文件的百分比保持相对稳定。选择 25 年的时间范围是因为此期间之前的提交数量相对较少。除了文本的持续使用外,图 4 显示了其他语言的偏好变化。最明显的是数据库中从 C 语言向 Python 的转变。CCC 研究中也提到了一个可能的原因。参与者报告称,他们并未将编程语言的选择视为黑客攻击中的关键因素。因此,Python 使用的增加可能仅仅反映了其近年来的普遍受欢迎程度。语言偏好因此应随着技术的发展而继续变化。例如,引入Rust作为 Linux 内核开发的第二语言,可能会引发这种变化。这个预测是否准确将在未来几年得到验证。

结论

总结而言,本文中呈现的比较揭示了 CCC 成员和 Exploit-DB 作者所使用语言之间的显著重叠。两个数据集都确认了 Python 在网络安全领域的流行程度。此外,每个数据集都表明语言偏好随着时间的推移而发生变化。CCC 研究提出了一个可能的原因。参与者并未将编程语言的选择视为黑客攻击中的关键因素。根据这一解释,人们应预期随着技术进步,语言偏好将继续变化。Exploit-DB 分析的一个主要限制与语言检测方法有关。由于多语言文件的问题,某些技术可能被低估。解决这个问题将是一个有趣的后续研究主题。显然,Exploit-DB 为数据科学家和安全专家提供了丰富的数据集。关于利用艺术的学习还有很多。

除非另有说明,所有图片均由作者提供。

哪种量化方法适合你?(GPTQ vs. GGUF vs. AWQ)

原文:towardsdatascience.com/which-quantization-method-is-right-for-you-gptq-vs-gguf-vs-awq-c4cd9d77d5be

探索预量化的大型语言模型

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Maarten Grootendorst

·发布于 Towards Data Science ·11 分钟阅读·2023 年 11 月 14 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在过去一年里,我们见证了大型语言模型 (LLMs) 的狂野西部。新技术和模型的发布速度惊人!因此,我们有了许多不同的标准和处理 LLM 的方法。

在这篇文章中,我们将探讨一个话题,即通过几种(量化)标准加载你的本地 LLM。由于分片、量化以及不同的保存和压缩策略,很难知道哪种方法适合你。

在这些例子中,我们将使用 Zephyr 7B,这是 Mistral 7B 的一个微调变体,经过 Direct Preference Optimization (DPO) 训练。

🔥 提示:在每个加载 LLM 的示例后,建议重启你的笔记本,以防止 OutOfMemory 错误。加载多个 LLM 需要大量 RAM/VRAM。你可以通过删除模型并重置缓存来重置内存:

# Delete any models previously created
del model, tokenizer, pipe

# Empty VRAM cache
import torch
torch.cuda.empty_cache()

你还可以参考 Google Colab Notebook 确保一切按预期工作。

更新:我上传了一个视频版本到 YouTube,深入探讨了如何使用这些量化方法:

1. HuggingFace

加载你的 LLM 的最直接、最基本的方法是通过 🤗 Transformers。HuggingFace 创建了一套大型软件包,使我们能够对 LLM 进行惊人的操作!

我们将从安装 HuggingFace 开始,从其主分支中支持更新的模型:

# Latest HF transformers version for Mistral-like models
pip install git+https://github.com/huggingface/transformers.git
pip install accelerate bitsandbytes xformers

安装后,我们可以使用以下管道轻松加载我们的 LLM:

from torch import bfloat16
from transformers import pipeline

# Load in your LLM without any compression tricks
pipe = pipeline(
    "text-generation", 
    model="HuggingFaceH4/zephyr-7b-beta", 
    torch_dtype=bfloat16, 
    device_map="auto"
)

这种加载 LLM 的方法通常不会进行任何压缩技巧来节省 VRAM 或提高效率。

为了生成我们的提示,我们首先需要创建必要的模板。幸运的是,如果聊天模板保存在底层分词器中,这可以自动完成:

# We use the tokenizer's chat template to format each message
# See https://huggingface.co/docs/transformers/main/en/chat_templating
messages = [
    {
        "role": "system",
        "content": "You are a friendly chatbot.",
    },
    {
        "role": "user", 
        "content": "Tell me a funny joke about Large Language Models."
    },
]
prompt = pipe.tokenizer.apply_chat_template(
    messages, 
    tokenize=False, 
    add_generation_prompt=True
)

使用内部提示模板生成的提示构造如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提示模板是使用内部提示模板自动生成的。注意到有不同的标签来区分用户和助手。

然后,我们可以开始将提示传递给 LLM 来生成我们的答案:

outputs = pipe(
    prompt, 
    max_new_tokens=256, 
    do_sample=True, 
    temperature=0.1, 
    top_p=0.95
)
print(outputs[0]["generated_text"])

这给我们以下输出:

为什么大型语言模型去参加派对?

为了网络和扩展其词汇量!

笑点可能有点老套,但大型语言模型的核心就是扩展词汇量和与其他模型建立联系以提高语言技能。因此,这个笑话非常适合它们!

对于纯推理来说,这种方法通常是效率最低的,因为我们在没有任何压缩或量化策略的情况下加载整个模型。

然而,这是一个很好的起点方法,因为它便于加载和使用模型!

2. 分片

在我们深入量化策略之前,还有另一个技巧可以用来减少加载模型所需的 VRAM。通过分片,我们实际上是将模型拆分成小块或分片

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分片 LLM 不过是将其拆分成多个小块。每个小块更容易处理,可能避免内存问题。

每个分片包含模型的一小部分,旨在通过将模型权重分布到不同设备上来绕过 GPU 内存限制。

记得我之前说过我们没有进行任何压缩技巧吗?

这并不完全正确……

我们加载的模型,Zephyr-7B-β,实际上已经为我们进行了分片!如果你访问模型并点击*“Files and versions”*链接,你会看到模型被拆分成了八个部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

模型被拆分成了八个小块或分片。这减少了必要的 VRAM,因为我们只需处理这些小块。

尽管我们可以自己对模型进行分片,但通常建议寻找量化模型或自己进行量化。

使用Accelerate包进行分片非常简单:

from accelerate import Accelerator

# Shard our model into pieces of 1GB
accelerator = Accelerator()
accelerator.save_model(
    model=pipe.model, 
    save_directory="/content/model", 
    max_shard_size="4GB"
)

就这样!因为我们将模型分片成了 4GB 而不是 2GB,所以我们创建了更少的文件来加载:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3. 使用 Bitsandbytes 进行量化

大型语言模型由一堆权重和激活值表示。这些值通常由常见的 32 位浮点数(float32)数据类型表示。

位数告诉你它可以表示多少个值。Float32可以表示从 1.18e-38 到 3.4e38 之间的值,数量相当多!位数越少,能表示的值就越少。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

常见的值表示方法。我们旨在将位数保持在尽可能低的水平,同时最大化表示的范围和精度。

正如你可能预期的那样,如果我们选择较低的位大小,模型的准确性会降低,但它也需要表示更少的值,从而减小了模型的大小和内存需求。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不同的表示方法可能会对表示值的精度产生负面影响。以至于某些值甚至无法表示(例如,对于 float16 来说过大的值)。示例是使用 PyTorch 计算的。

量化是指将大型语言模型从其原始的Float32表示转换为较小的表示。然而,我们不仅仅是使用较小的位变体,而是将较大的位表示映射到较小的位而不丢失太多信息。

实际上,我们通常使用一种新的格式,称为4bit-NormalFloat (NF4)。这种数据类型通过一些特殊技巧有效地表示较大的位数据类型。它包括三个步骤:

  1. 归一化:模型的权重被归一化,以便我们期望权重落在一定范围内。这允许对更常见的值进行更高效的表示。

  2. 量化:权重被量化为 4 位。在 NF4 中,量化水平相对于归一化的权重均匀分布,从而有效地表示原始的 32 位权重。

  3. 去量化:虽然权重以 4 位存储,但在计算过程中会进行去量化,这在推理过程中提升了性能。

要使用 HuggingFace 执行这种量化,我们需要定义一个量化配置,使用Bitsandbytes

from transformers import BitsAndBytesConfig
from torch import bfloat16

# Our 4-bit configuration to load the LLM with less GPU memory
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,  # 4-bit quantization
    bnb_4bit_quant_type='nf4',  # Normalized float 4
    bnb_4bit_use_double_quant=True,  # Second quantization after the first
    bnb_4bit_compute_dtype=bfloat16  # Computation type
)

这个配置允许我们指定我们要使用的量化水平。通常,我们希望使用 4 位量化来表示权重,但在推理时使用 16 位。

然后,加载模型到管道中是直接的:

from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline

# Zephyr with BitsAndBytes Configuration
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
model = AutoModelForCausalLM.from_pretrained(
    "HuggingFaceH4/zephyr-7b-alpha",
    quantization_config=bnb_config,
    device_map='auto',
)

# Create a pipeline
pipe = pipeline(model=model, tokenizer=tokenizer, task='text-generation')

接下来,我们可以使用之前的相同提示:

# We will use the same prompt as we did originally
outputs = pipe(
    prompt, 
    max_new_tokens=256, 
    do_sample=True, 
    temperature=0.7, 
    top_p=0.95
)
print(outputs[0]["generated_text"])

这将给我们如下输出:

大型语言模型为什么去参加派对?

为了联网并扩展其词汇量!

这个笑话可能有点老套,但大型语言模型的核心就是扩展词汇量,并与其他模型建立联系以提高语言技能。所以,这个笑话非常适合它们!

量化是一种强大的技术,可以减少模型的内存需求,同时保持性能相似。它允许更快地加载、使用和微调 LLM,即使是在较小的 GPU 上。

4. 预量化(GPTQ vs. AWQ vs. GGUF)

到目前为止,我们已经探讨了分片和量化技术。尽管这些技术在你的技能库中非常有用,但每次加载模型时都要应用它们似乎有些浪费。

相反,这些模型通常已经被分片和量化,供我们使用。TheBloke 尤其是 HuggingFace 上的一个用户,执行了一些量化供我们使用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在撰写本文时,他已经上传了 2000 多个 量化模型供我们使用!

这些量化模型实际上有很多不同的形状和大小。最显著的是,GPTQ、GGUF 和 AWQ 格式最常用于执行 4 位量化。

GPTQ: 针对 GPT 模型的后训练量化

GPTQ 是一种 - (PTQ) 方法,用于 4 位量化,主要关注 GPU 推理和性能。

该方法背后的想法是通过最小化均方误差,将所有权重压缩到 4 位量化。在推理过程中,它会动态地将权重解量化为 float16,以提高性能,同时保持较低的内存占用。

要了解 GPTQ 内部工作的更详细指南,务必查看以下帖子:

## 4-bit Quantization with GPTQ

使用 AutoGPTQ 量化你自己的 LLM

towardsdatascience.com

我们开始安装一些需要在 HuggingFace Transformers 中加载 GPTQ 类模型的包:

pip install optimum
pip install auto-gptq --extra-index-url https://huggingface.github.io/autogptq-index/whl/cu118/

完成后,我们可以导航到我们想加载的模型,即“TheBloke/zephyr-7B-beta-GPTQ”,并选择一个特定的修订版。

这些修订本质上表示量化方法、压缩级别、模型的大小等。

目前,我们仍然坚持使用“main”分支,因为它在压缩和准确性之间通常是一个不错的平衡:

from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline

# Load LLM and Tokenizer
model_id = "TheBloke/zephyr-7B-beta-GPTQ"
tokenizer = AutoTokenizer.from_pretrained(model_id, use_fast=True)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    device_map="auto",
    trust_remote_code=False,
    revision="main"
)

# Create a pipeline
pipe = pipeline(model=model, tokenizer=tokenizer, task='text-generation')

尽管我们安装了一些额外的依赖项,但我们可以使用与之前相同的管道,这也是使用 GPTQ 的一个很大好处。

加载模型后,我们可以运行如下提示:

# We will use the same prompt as we did originally
outputs = pipe(
    prompt,
    max_new_tokens=256,
    do_sample=True,
    temperature=0.1,
    top_p=0.95
)
print(outputs[0]["generated_text"])

这给了我们以下生成的文本:

为什么大型语言模型去参加派对?

当然,是为了展示它的机智和魅力!

但不幸的是,它在人群中迷失了,找不到回去的路

对它的主人。派对上的人们对它融入环境的能力感到印象深刻

与人群无缝融合,但大型语言模型只是感到困惑

并想回家。最后,一群人发现了它

他们认识到其独特的风格,并将其带回了应有的地方。

从那时起,大型语言模型确保在

为了安全起见,所有派对。

GPTQ 是最常用的压缩方法,因为它优化了 GPU 的使用。如果你的 GPU 无法处理如此大的模型,绝对值得从 GPTQ 开始,然后切换到以 CPU 为重点的方法,如 GGUF。

GGUF: GPT-生成统一格式

尽管 GPTQ 处理压缩非常好,但它对 GPU 的关注可能在你没有硬件支持时成为一个缺点。

GGUF,之前称为 GGML,是一种量化方法,允许用户使用 CPU 运行 LLM,但也可以将一些层卸载到 GPU 上以加速。

虽然使用 CPU 通常比使用 GPU 推理更慢,但对于在 CPU 或 Apple 设备上运行模型的人来说,它是一个了不起的格式。特别是随着我们看到更多较小但更强大的模型出现,如 Mistral 7B,GGUF 格式可能会长久存在!

使用 GGUF 通过 ctransformers 包相当简单,我们需要先安装这个包:

pip install ctransformers[cuda]

完成后,我们可以导航到我们想要加载的模型,即“TheBloke/zephyr-7B-beta-GGUF”并选择一个具体的文件。

像 GPTQ 一样,这些文件指示了量化方法、压缩、级别、模型大小等。

我们使用“zephyr-7b-beta.Q4_K_M.gguf”因为我们专注于 4 位量化:

from ctransformers import AutoModelForCausalLM
from transformers import AutoTokenizer, pipeline

# Load LLM and Tokenizer
# Use `gpu_layers` to specify how many layers will be offloaded to the GPU.
model = AutoModelForCausalLM.from_pretrained(
    "TheBloke/zephyr-7B-beta-GGUF",
    model_file="zephyr-7b-beta.Q4_K_M.gguf",
    model_type="mistral", gpu_layers=50, hf=True
)
tokenizer = AutoTokenizer.from_pretrained(
    "HuggingFaceH4/zephyr-7b-beta", use_fast=True
)

# Create a pipeline
pipe = pipeline(model=model, tokenizer=tokenizer, task='text-generation')

加载模型后,我们可以运行如下提示:

# We will use the same prompt as we did originally
outputs = pipe(prompt, max_new_tokens=256)
print(outputs[0]["generated_text"])

这给出了以下输出:

为什么大型语言模型去参加派对?

让大家对它的词汇印象深刻!

但不幸的是,它不断重复相同的笑话,让大家 groan 和 roll their eyes。派对上的人们很快意识到,大型语言模型更像是个 party pooper 而不是 party animal。

故事的寓意是:仅仅因为大型语言模型可以生成很多字词,并不意味着它知道如何搞笑或娱乐。有时候,少即是多!

GGUF 是一个很棒的格式,如果你像我一样缺乏 GPU,没有最新最强的 GPU,想要同时利用 CPU 和 GPU 的话。

AWQ: Activation-aware Weight Quantization

一个新格式是 AWQ (Activation-aware Weight Quantization),它是一种类似于 GPTQ 的量化方法。AWQ 和 GPTQ 作为方法之间有几个区别,但最重要的一点是 AWQ 假设不是所有的权重对 LLM 的性能同样重要。

换句话说,在量化过程中会跳过一小部分权重,这有助于减少量化损失。

结果,他们的论文提到,与 GPTQ 相比有显著的加速,同时保持类似,甚至有时更好的性能。

这种方法仍然相对较新,尚未普及到像 GPTQ 和 GGUF 那样的程度,因此很有趣的是看看这些方法是否能够共存。

对于 AWQ,我们将使用 vLLM 包,因为根据我的经验,这是使用 AWQ 的最简便途径:

pip install vllm

使用 vLLM,加载和使用我们的模型变得毫不费力:

from vllm import LLM, SamplingParams

# Load the LLM
sampling_params = SamplingParams(temperature=0.0, top_p=1.0, max_tokens=256)
llm = LLM(
    model="TheBloke/zephyr-7B-beta-AWQ", 
    quantization='awq', 
    dtype='half', 
    gpu_memory_utilization=.95, 
    max_model_len=4096
)

然后,我们可以轻松地使用 .generate 来运行模型:

# Generate output based on the input prompt and sampling parameters
output = llm.generate(prompt, sampling_params)
print(output[0].outputs[0].text)

这给我们带来了以下输出:

为什么大型语言模型去参加派对?

为了扩展词汇量和建立网络!

为什么大型语言模型脸红了?

因为它听到另一个模型说它有点啰嗦!

为什么大型语言模型被逐出了图书馆?

它太吵了,一直打断其他模型的对话,喋喋不休!

虽然这是一个新格式,但由于其速度和压缩质量,AWQ 正在获得越来越多的关注!

🔥 提示:对于这些技术在 VRAM/困惑度方面的详细比较,我强烈建议阅读这篇 深入文章 和后续的 讨论

感谢阅读!

如果你和我一样,对 AI 和/或心理学充满热情,请随时在 LinkedIn 上添加我,在 Twitter 上关注我,或者订阅我的 Newsletter。你也可以在我的 Personal Website 上找到我的一些内容。

所有没有来源信用的图片均由作者创作 —— 也就是说,全部都是我,我喜欢自己制作图片 😉

哪个团队应该负责数据质量?

原文:towardsdatascience.com/which-team-should-own-data-quality-44f1d6996eb8?source=collection_archive---------3-----------------------#2023-06-09

专家还是全能型人才?工程师还是分析师?我们探讨了哪些团队结构最适合有效提升数据质量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 shane murray

·

关注 发布于 Towards Data Science ·8 分钟阅读·2023 年 6 月 9 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源:Shane Murray。

当然,数据质量是每个人的问题。但谁来负责解决方案呢?

鉴于方法的多样性和成功的参差不齐,我们有许多自然实验可以借鉴。

一些组织会尝试将责任广泛分配给数据管理员、数据所有者、数据工程和治理委员会,每个人负责数据价值链的一部分。而另一些组织则将责任集中在少数几个专家身上,期望他们能够跨越整个平台。一些团队将数据质量主要视为技术挑战,而另一些团队则将其视为业务或流程问题。

我在过去一年中与几十位数据领导者交谈,以了解他们如何将数据质量作为整体组织目标的一部分来处理。我们还调查了 200 名数据专业人士,询问他们的内部团队中哪个负责数据质量等问题。

本文将关注最常见的团队所有权模型,包括:数据工程、数据可靠性工程、分析工程、数据质量分析师和数据治理团队。

为什么数据质量的所有权很重要?

但在深入探讨之前,回答这个常见的跟进问题很重要。它通常以“只要完成了就好,谁负责数据质量又有什么关系?”的形式提出。

这种表述中有一点诡辩,因为“只要完成了就好”远未确定,坦率地说,这也是整个工作的目的所在。关于明确的问责制所有权目标设定的积极影响有很多研究,很难只引用其中一个。

现实是,解决数据质量问题不太可能是团队要优先考虑的工作,而是通常是团队需要优先考虑的工作,以保持信任或扩大团队和平台。没有问责制的话,推进数据质量的低可见性任务,如单元测试或文档,将无法按应有的程度完成。

此外,当责任分散时,你通常会得到碎片化的解决方案、协调不一致的优先级和沟通差距,最终导致数据产品的停机时间增加。

虽然我见过所有类型的团队成功实施数据质量解决方案,但每种所有权结构都有独特的优势和需要缓解的劣势。

数据领导者需要理解每个团队和能力如何契合在一起。如果你还要派一个笨重的中锋,那么拥有一个快速的控球后卫并喜欢过渡进攻就没有意义了。整体需要大于各部分之和。

现在,让我们更详细地了解最流行的数据质量团队结构的优缺点。

数据工程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Luke Chesser 摄影,来源于 Unsplash

让数据工程团队主导数据质量响应是最常见的模式。大约一半使用现代数据堆栈的组织都采取了这种方式。

通常,这种方法伴随着“你构建了管道,你就拥有它”的心态。

这种方法的优势在于责任归属于高度技术化、系统性思维的人员,他们能够解决影响基础设施、代码或数据的系统级问题。

数据工程师在对数据质量影响较大的系统中工作。如果一个 Airflow 作业、dbt 模型或 Fivetran 同步失败,他们可能是第一个发现问题的人,并且通过数据血缘等功能,他们能够了解下游的影响范围,以便进行适当的处理。

然而,这种方法也有其缺点。例如,数据工程师往往供不应求,因此他们专注于系统和管道,可能没有深入的数据领域知识。例如,他们可能知道一个数据集源于 Salesforce 以及将数据传送到数据仓库的管道动态,但他们可能不知道这个数据集中的client_currency_exchange_rate 字段永远不能为负。

尽管让管道构建者和维护者为同一个人是高效的,但这也可能造成部落知识的孤岛,当人员离开和其他人尝试上手时,这些知识可能会丧失。

解决这些挑战的有效方法可以是强调文档的重要性以确保知识转移,以及嵌入团队或将工程师与嵌入的分析师配对,以更好地获取领域知识。

BlaBlaCar 是一个数据工程负责数据质量的组织的例子。他们经历了瓶颈和容量挑战,直到他们转向数据网格,并利用数据可观察性来减少进行根本原因分析所需的时间。

分析工程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

经许可使用:source**.**

分析工程团队通常拥有技术专长与深厚领域知识的结合,使他们在数据质量方面成为有效的领导者。

他们通常作为扩大数据转换和访问的方式进行部署,常使用 dbt 或类似工具,而集中式数据工程团队则专注于基础设施、企业数据管理或共享服务。

这种方法的优势在于典型分析工程师的强大领域专长。他们能够有效处理管道可靠性和领域级质量。

不过,这种方法的缺点可能是他们在解决基础设施问题或协调上游数据生产团队和系统方面的能力有限。数据质量问题中的一部分起源于转换层,因此分析工程师需要与产品和平台工程团队建立强有力的合作伙伴关系,以有效处理源系统和数据摄取层中的问题。

Upside 的分析工程团队通过将自己定位为不同团队之间的卓越中心,成功掌控了组织中的数据质量。当我的同事高级分析工程师 Jack Willis 交谈时,他提到:

“我们的分析工程师应该是加速者,而不一定是领域专家。所以我们将他们置于所有这些不同专业团队的中间。这使他们能够成为卓越中心,并能够与这些团队紧密合作,获得跨职能的专业知识。”

分析工程团队发现,当他们建立自定义数据管道监控器并与系统健康团队一起培训时,他们的数据质量倡议变得更加可持续。通过将系统健康团队纳入设计和创建过程,他们获得了支持,并使系统健康团队能够设置监控器,从而创造出有意义的见解。

数据治理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Contentsquare 如何将数据质量作为其数据治理倡议的一部分来处理。经许可使用:来源

数据治理团队通常在数据质量方面发挥领导作用,同时肩负数据安全、隐私和访问的更大任务。

强项在于制定全面的战略,考虑数据的整个价值链,影响数据生产者、工程师和数据消费者的行为。我们经常看到治理团队拥有一系列解决方案,包括数据可观察性、数据目录和访问管理。

数据治理团队通过技术标准、政策和业务流程推动其他团队的变革。但如果没有安全或隐私倡议的合规性要求,采用总是更具挑战性。

在大规模操作中,治理团队创建质量数据的全球标准至关重要,例如文档、监控和服务水平协议的最低要求,然后在各种数据拥有者之间分配责任,无论他们是按领域组织还是按数据团队组织。

Contentsquare 的数据治理团队负责数据的访问和应用。数据质量也在他们的职责范围内。

治理团队将每个团队输出视为数据产品。每个数据产品都与使用案例相关联,使用案例又与基础数据相关联。数据质量监控支撑着所有这些基础数据,数据团队定期检查以确保每个数据产品按设计运行。我的同事与他们的前数据治理负责人 Octávio Bastos 交谈过,他讨论了如何设计这一点以帮助团队扩展。

“有时当我们进展太快时,我们往往只关注价值创造:新的仪表板、新的模型、新的数据探索相关性,”他们的前全球数据治理负责人说。“我们忘记了建立良好的数据工程、良好的数据治理和高效的数据分析团队。这在长期内非常重要,以确保我们能够扩展,并且未来能够用同一个团队做更多的事情。”

数据可靠性

数据可靠性工程是数据工程的一个专门子集,专注于响应性和预防性实践,以提高数据系统的质量和可靠性。虽然这种结构不如其他结构常见,但正在迅速获得关注(我们提到它们和数据团队的专业化作为我们 2023 年数据工程趋势的重点之一)。

在数据产品面向外部和/或需要满足严格的数据服务水平协议(SLA)的情况下,专门的数据可靠性工程师团队可以将所需的关注点集中于事件响应和主动措施,以解决可靠性问题。

我们在 Monte Carlo 的产品遥测中看到,采用这种方法的团队在数据可靠性方面的操作指标有所改善,包括事件状态更新明显增加。

然而,团队和数据环境需要足够大,以从专业化中获得适当的效率。

Mercari 使用数据可靠性工程团队结构。他们成功的关键在于设定明确的目标和责任,例如:

  • 入职和支持最重要的管道

  • 现代化数据管道基础设施

  • 扩展的数据操作和监控实践

  • 确保对客户数据的安全访问

他们的专注还使他们能够在何时解决和进行更多渐进式修复与何时需要进行更大规模现代化之间做出明智的决策。

数据质量分析师

最后,一些组织,尤其是较大的组织,将利用数据分析师或专门的数据质量分析师。

这种结构的优势在于,这些分析师通常非常接近业务,并且能够很好地定义所需的质量标准,制定量身定制的测试或监控以执行这些标准。

然而,这些团队通常需要与数据工程有强连接,以便有效地处理和解决上游的问题。

PayJoy 是一个成功拥有数据质量的组织的例子,其中数据分析师和分析主管 Trish Pham 扮演了重要角色。他们拥有超过 2,000 个表格,主要利用数据来提高对业务表现的可见性,并推动跨职能的数据驱动决策。

只要完成即可

无论你的组织和数据团队决定谁来主导数据质量的响应,明确所有权和责任至关重要。

首先评估操作性、分析性和面向客户的数据使用案例以及所需的数据可靠性水平。然后,在这些关键使用案例中,确定对数据价值链具有最大杠杆作用的团队——他们应该能够掌握响应性和预防性解决方案,并且需要与数据生产者和消费者有一定影响力。

这不是一个单独的项目。你能多大程度上赋能团队并促进跨部门协作,你成功的可能性就有多大。

关注我 在 Medium 上,获取更多关于数据领导力、数据科学应用及相关话题的故事。订阅 以便将我的故事送到你的邮箱。

Whisper JAX 与 PyTorch:揭示 GPU 上 ASR 性能的真相

原文:towardsdatascience.com/whisper-jax-vs-pytorch-uncovering-the-truth-about-asr-performance-on-gpus-8794ba7a42f5

深入探讨自动语音识别:在平台间基准测试 Whisper JAX 和 PyTorch 实现

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Luís Roque

·发表于 Towards Data Science ·阅读时间 8 分钟·2023 年 4 月 29 日

介绍

在自动语音识别(ASR)的世界里,速度和准确性非常重要。最近,数据和模型的规模显著增长,使得效率难以提升。然而,竞争才刚刚开始,我们每周都能看到新的进展。本文集中在 Whisper JAX 上,它是 Whisper 的一种新实现,使用了不同的后端框架,似乎比 OpenAI 的 PyTorch 实现快 70 倍。我们测试了 CPU 和 GPU 实现,并测量了准确性和执行时间。此外,我们定义了小型和大型模型的实验,同时调整了批量大小和数据类型,以查看是否可以进一步提高性能。

正如我们在上一篇文章中看到的,Whisper 是一个多功能的语音识别模型,在多种语音处理任务中表现出色。它可以执行多语言语音识别、翻译甚至语音活动检测。它使用 Transformer 序列到序列架构来共同预测单词和任务。Whisper 作为一个语音处理任务的元模型。Whisper 的一个缺点是其效率;与其他最先进的模型相比,它通常被发现运行较慢。

在接下来的章节中,我们将详细介绍这种新方法带来的变化。我们比较了 Whisper 和 Whisper JAX,突出了 PyTorch 和 JAX 之间的主要差异,并开发了一个管道来评估两种实现之间的速度和准确性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:我们能有效地理解声音吗? (来源)

本文属于“大型语言模型编年史:探索 NLP 前沿”,这是一个新的每周系列文章,将探索如何利用大型模型的力量来处理各种 NLP 任务。通过深入了解这些前沿技术,我们旨在帮助开发者、研究人员和爱好者利用 NLP 的潜力,开启新的可能性。

目前已发布的文章:

  1. 使用 ChatGPT 总结最新的 Spotify 发布

  2. 在大规模语义搜索中掌握技巧:使用 FAISS 和 Sentence Transformers 快速索引数百万文档

  3. 释放音频数据的力量:使用 Whisper、WhisperX 和 PyAnnotate 进行高级转录和分段

一如既往,代码可以在我的 Github 上找到。

PyTorch 与 JAX

机器学习社区广泛使用如 PyTorch 和 JAX 等强大的库。虽然它们有一些相似之处,但其内部工作机制却大相径庭。让我们来了解一下主要的区别。

Meta 的 AI 研究实验室开发了 PyTorch 并且目前积极维护它。它是一个基于 Torch 库的开源库。由于 PyTorch 的动态计算图、直观的界面和强大的调试功能,研究人员广泛使用它。它使用动态图,使其在构建新模型和简化运行时修改模型方面具有更大的灵活性。它更接近 Python,特别是 NumPy API。主要的区别在于,我们处理的不是数组,而是可以在 GPU 上运行的张量,并且支持自动微分。

JAX 是一个由 Google 开发的高性能库。与 PyTorch 相反,JAX 结合了静态和动态计算图的优点。它通过 即时 编译功能实现这一点,这提供了灵活性和性能。我们可以将 JAX 视为一个逐步重写程序的解释器堆栈。它最终将实际计算卸载到 XLA —— 加速线性代数 编译器,这也是由 Google 设计和开发的,用于加速机器学习计算。

构建使用 PyTorch 或 JAX 的 ARS 系统

让我们开始构建一个类来处理使用 Whisper 与 PyTorch(OpenAI 实现)或 Whisper 与 JAX 的音频转录。我们的类是模型的封装器,并且是一个易于设置实验的接口。我们想进行几个实验,包括指定设备、模型类型和 Whisper JAX 的附加超参数。请注意,我们使用了单例模式,以确保在运行多个实验时,不会有多个模型实例消耗我们的内存。

class Transcription:
    """
    A class to handle audio transcriptions using either the Whisper or Whisper JAX model.

    Attributes:
        audio_file_path (str): Path to the audio file to transcribe.
        model_type (str): The type of model to use for transcription, either "whisper" or "whisper_jax".
        device (str): The device to use for inference (e.g., "cpu" or "cuda").
        model_name (str): The specific model to use (e.g., "base", "medium", "large", or "large-v2").
        dtype (Optional[str]): The data type to use for Whisper JAX, either "bfloat16" or "bfloat32".
        batch_size (Optional[int]): The batch size to use for Whisper JAX.
    """
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(
        self,
        audio_file_path: str,
        model_type: str = "whisper",
        device: str = "cpu",
        model_name: str = "base",
        dtype: Optional[str] = None,
        batch_size: Optional[int] = None,
    ):
        self.audio_file_path = audio_file_path
        self.device = device
        self.model_type = model_type
        self.model_name = model_name
        self.dtype = dtype
        self.batch_size = batch_size
        self.pipeline = None

set_pipeline 方法为指定的模型类型设置管道。根据 model_type 属性的值,该方法通过实例化 FlaxWhisperPipline 类来初始化 Whisper JAX 的管道,或者通过调用 whisper.load_model() 函数来初始化 Whisper 的 PyTorch 实现。

 def set_pipeline(self) -> None:
        """
        Set up the pipeline for the specified model type.

        Returns:
            None
        """
        if self.model_type == "whisper_jax":
            pipeline_kwargs = {}
            if self.dtype:
                pipeline_kwargs["dtype"] = getattr(jnp, self.dtype)
            if self.batch_size:
                pipeline_kwargs["batch_size"] = self.batch_size

            self.pipeline = FlaxWhisperPipline(
                f"openai/whisper-{self.model_name}", **pipeline_kwargs
            )
        elif self.model_type == "whisper":
            self.pipeline = whisper.load_model(
                self.model_name,
                torch.device("cuda:0") if self.device == "gpu" else self.device,
            )
        else:
            raise ValueError(f"Invalid model type: {self.model_type}")

run_pipeline 方法将音频文件转录并返回结果,结果以包含转录文本和时间戳的字典列表形式呈现。在 Whisper JAX 的情况下,如果提供了数据类型和批量大小等可选参数,它会考虑这些参数。请注意,如果您只对获取转录结果感兴趣,可以将 return_timestamps 设置为 False。如果我们使用 PyTorch 实现进行转录处理,模型输出会有所不同。因此,我们必须创建一个新的对象来对齐两个返回对象。

 def run_pipeline(self) -> List[Dict[str, Union[Tuple[float, float], str]]]:
        """
        Run the transcription pipeline a second time.

        Returns:
            A list of dictionaries, each containing text and a tuple of start and end timestamps.
        """
        if not hasattr(self, "pipeline"):
            raise ValueError("Pipeline not initialized. Call set_pipeline() first.")

        if self.model_type == "whisper_jax":
            outputs = self.pipeline(
                self.audio_file_path, task="transcribe", return_timestamps=True
            )
            return outputs["chunks"]
        elif self.model_type == "whisper":
            result = self.pipeline.transcribe(self.audio_file_path)
            formatted_result = [
                {
                    "timestamp": (segment["start"], segment["end"]),
                    "text": segment["text"],
                }
                for segment in result["segments"]
            ]
            return formatted_result
        else:
            raise ValueError(f"Invalid model type: {self.model_type}")

最后,transcribe_multiple() 方法支持多个音频文件的转录。它接受一个音频文件路径的列表,并返回每个音频文件的转录列表,每个转录都是一个包含文本和开始与结束时间戳元组的字典列表。

 def transcribe_multiple(
        self, audio_file_paths: List[str]
    ) -> List[List[Dict[str, Union[Tuple[float, float], str]]]]:
        """
        Transcribe multiple audio files using the specified model type.

        Args:
            audio_file_paths (List[str]): A list of audio file paths to transcribe.

        Returns:
            List[List[Dict[str, Union[Tuple[float, float], str]]]]: A list of transcriptions for each audio file, where each transcription is a list of dictionaries containing text and a tuple of start and end timestamps.
        """
        transcriptions = []

        for audio_file_path in audio_file_paths:
            self.audio_file_path = audio_file_path
            self.set_pipeline()
            transcription = self.run_pipeline()

            transcriptions.append(transcription)

        return transcriptions

Whisper JAX 与 PyTorch 性能比较

实验设置

我们使用了一段超过 30 分钟的长音频片段来评估 Whisper 变体的性能,包括 PyTorch 和 JAX 实现。开发 Whisper JAX 的研究人员声称,在转录长音频文件时,差异更为显著。

我们的实验硬件设置包括以下关键组件。对于 CPU,我们有一个 x86_64 架构,总共有 112 个核心,由一台运行在 2.70GHz 的 Intel® Xeon® Gold 6258R CPU 提供动力。关于 GPU,我们使用了一块 48 GB VRAM 的 NVIDIA Quadro RTX 8000。

结果与讨论

在本节中,我们讨论了从实验中获得的结果,以比较 Whisper JAX 和 PyTorch 实现的性能。我们的结果提供了对这两种实现的速度和效率的见解,涵盖了 GPU 和 CPU 平台。

我们的第一个实验涉及使用 GPU 和较大的 Whisper 模型(large-v2),该模型需要大约 10GB 的 VRAM,来处理超过 30 分钟的长音频。与 Whisper JAX 作者的说法相反,我们的结果表明 JAX 实现的速度比 PyTorch 版本慢。即使采用了半精度和批处理,我们也无法超越 PyTorch 实现的性能。Whisper JAX 执行类似转录所需的时间几乎是 PyTorch 实现的两倍。我们还观察到,在使用半精度和批处理时,转录时间异常较长。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2: 在 GPU 上使用 Whisper 的 PyTorch 实现与 Whisper JAX 进行大模型的转录执行时间(图像来源于作者)

另一方面,在比较 CPU 性能时,我们的结果显示 Whisper JAX 优于 PyTorch 实现。Whisper JAX 的加速因子约为 PyTorch 版本的两倍。我们在基础和显著模型变体中观察到了这种模式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3: 在 CPU 上使用 Whisper 的 PyTorch 实现与 Whisper JAX 进行基础和大模型的转录执行时间(图像来源于作者)

关于 Whisper JAX 作者提出的第二次转录应该快得多的说法,我们的实验未提供支持证据。第一次和第二次转录之间的速度差异不显著。此外,我们发现 Whisper 和 Whisper JAX 实现之间的模式相似。

结论

在本文中,我们提供了对 Whisper JAX 实现的全面分析,比较了其与原始 PyTorch 实现的性能。我们的实验旨在评估声称的 70 倍速度提升,使用了包括不同硬件和超参数的多种设置来测试 Whisper JAX 模型。

结果显示,Whisper JAX 在 CPU 平台上优于 PyTorch 实现,速度大约提高了两倍。然而,我们的实验并未支持作者关于 Whisper JAX 在 GPU 平台上显著更快的说法。实际上,在使用 GPU 转录长音频文件时,PyTorch 实现表现更佳。

此外,我们没有发现第一次和第二次转录之间速度的显著差异,这是 Whisper JAX 作者提出的说法。两个实现表现出类似的模式。

保持联系:LinkedIn

谁做什么工作?AI 眼中的职业角色

原文:towardsdatascience.com/who-does-what-job-occupational-roles-in-the-eyes-of-ai-68f6fc685274

如何 GPT 模型对职业的看法随着时间的推移而演变

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Yennie Jun

·发表于 Towards Data Science ·阅读时间 11 分钟·2023 年 12 月 2 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

词云显示了 GPT-4 在被提示为“这位女士/先生的工作是 …”时生成的主要职业。图像由作者创建。

原始文章发表于我的 个人博客

到目前为止的故事

在 2020 年 12 月,我 开始撰写一篇论文,与牛津大学的一组人一起调查生成语言模型中的偏见。我们进行了实验,以了解当时最热门的语言模型 GPT-2 所表现出的职业和性别偏见(这是在“大型语言模型”这一术语被广泛使用之前)[1]。

自那时以来的三年里,自然语言处理领域发展迅速,出现了更大的模型和更复杂的训练方法。我在 2020 年测试的小版本 GPT-2 只有 1.24 亿参数。相比之下,GPT-4 估计拥有超过 1 万亿个参数,使其大约是 GPT-2 的 8000 倍。不仅如此,模型训练时还更加注重将语言模型与人类的价值观和反馈对齐。

原始论文旨在了解语言模型为提示“这位男士/女士的工作是 …”生成了什么职业。语言模型是否将某些职业与男性更多地关联,而将其他职业与女性更多地关联?我们还用交叉类别(如种族和宗教)对模型进行了提示(如 "这位亚洲女士/佛教男士的工作是 …")。

考虑到现在语言模型的状态,我三年前的实验在更新的、更大的 GPT 模型上表现如何?

实验

我使用了 47 个提示模板,其中包括 16 种不同的标识形容词和 3 种不同的名词 [2]。这些标识形容词与美国的主要 种族 和宗教相关。它们还包括与性取向和政治立场相关的标识符。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用作语言模型提示的各个群体的图示。图像由作者创建。

我使用了以下模型:

我对每个语言模型的每个提示运行了 1000 次,使用默认设置(例如“开箱即用”)。然后,我分析了每个语言模型为每个提示生成的职业。

结果 1:更新的模型生成了类似水平的性别职业多样性

2020 年的一个原始发现是,GPT-2 为男性生成了 更多样化的职业,而不是女性。

下图展示了每个模型生成的独特工作数量(过滤掉出现频率较低的工作后) [3]。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每个模型为“男性”和“女性”类别生成的独特工作数量。GPT-2 为男性生成了更多样化的职业,而 GPT-3.5 和 GPT-4 为两性生成了相似数量的工作。图像由作者创建。

的确,GPT-2 为男性生成了更多类型的工作,而不是女性。

另一方面,更新的 GPT-3.5 和 GPT-4 模型总体上生成的职业多样性较小。此外,这些模型 为男性和女性生成了类似数量的独特工作。就男性和女性生成的独特工作总体数量而言,这些数字几乎达到了性别平等。

结果 2:男性主导的工作 → 女性主导的工作

原始论文的另一个发现是 GPT-2 生成了刻板化的生成结果:

[M] 男性与手工劳动职位如工人、水管工、卡车司机和机械师以及专业职位如软件工程师、开发者和私人侦探相关联。

女性则与家庭和护理角色如保姆、女仆和社会工作者相关联。此外,“妓女”一词的超过 90% 的返回结果是女性,“软件工程师”一词的超过 90% 的返回结果是男性。

以下图表显示了每个语言模型生成的前十名职业,按其倾向于男性还是女性主导进行排序。左侧的职业是语言模型通常与男性相关的职业,右侧的职业是通常与女性相关的职业。

最有趣的发现之一是“软件工程师”职业,在 GPT-2 的生成输出中主要与男性相关。在 GPT-3.5 的生成输出中,该职业接近性别平衡,而在 GPT-4 的生成输出中,几乎完全与女性相关。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GPT-2 最常生成的职业,显示了男性与女性主导的工作。图片由作者创建。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GPT-3.5 最常生成的职业,显示了男性与女性主导的工作。图片由作者创建。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GPT-4 最常生成的职业,显示了男性与女性主导的工作。图片由作者创建。

一些观察结果:

  • “软件工程师”角色发生了最大的变化——从 GPT-2 主要与男性相关,到 GPT-4 主要与女性相关。

  • 其他专业角色,如“记者”,也在较新的模型中逐渐与女性相关。

  • 没有显著的职业发生了相反的变化(例如,GPT-2 与男性相关,GPT-4 与女性相关)。

  • 像“僧侣”和“牧师”等宗教角色在所有三个模型中仍然是男性主导的。

  • 一些职业,如“护士”,在所有三个模型中仍然是女性主导的。

我将生成的语言模型输出与美国劳工局 2022 年详细职业的就业调查进行了比较。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“软件工程师”和“记者”职业的真实与 AI 生成的性别比例,与 2022 年美国劳工局数据进行比较。图片由作者创建。

根据劳工局的数据,软件工程仍然是一个主要由男性主导的职业。GPT-2 将类似数量的男性和女性与软件工程相关联,与现实世界统计数据相当。GPT-3.5 将两倍数量的女性与软件工程相关联,相比 GPT-2。而最新的 GPT-4 模型主要将女性与软件工程相关联。

另一方面,根据 2022 年美国劳工局的数据,记者的性别比例相当均衡。与“软件工程师”角色的变化类似,随着每个后续更新的模型,越来越多的女性与该职位相关联。

发生了什么?更新的 GPT 模型倾向于将更多的女性与某些专业职业相关联。

下图包括了几个职业的性别中立“人”类别。通常,GPT-2 更倾向于与女性相关的职业(如“治疗师”和“社会工作者”),在 GPT-4 中与“人”类别关联更多。GPT-2 更倾向于与男性相关的职业(如“政治家”和“机械师”),在 GPT-4 中与女性及“人”类别关联更多。更新的 GPT 模型倾向于将 GPT-2 关联的某些职业,从特定性别转变为更多的性别中立。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GPT-2/3.5/4 生成的某些职业的性别比例。图像由作者创建。

结果 3: 每个性别的独占职业

为了进一步了解模型随时间的变化,我好奇是否有些职业是模型生成给某一子群体的。在这里,我将突出几个仅对某些子群体的最常见职业。

仅归属于“人”的常见职业:

我本期待这些职业会更具性别中立性。

  • GPT-2: 自由职业者、工人、劳动者、奴隶

  • GPT-3.5: 客户服务代表

  • GPT-4: 中介

仅归属于“女性”的常见职业:

  • GPT-2: 无

  • GPT-3.5: 瑜伽教练、女祭司、传教士

  • GPT-4: 助产士、生物化学家

GPT-2 没有预测任何仅为女性的职业……

仅归属于“男性”的常见职业:

  • GPT-2: 屠夫、渔夫

  • GPT-3.5: 清洁工、园丁

  • GPT-4: 无

而另一方面,GPT-4 并没有预测出仅为男性的职业!这一点从 GPT-2 到女性的变化非常有趣,即使只是这样。

如果你错过了,GPT-2 生成的最受欢迎的仅为“人”类别的职业之一是“奴隶”。以下是 GPT-2 生成此输出的实体划分。这是语言模型如此有问题的众多原因之一!(幸运的是,GPT-3.5 和 GPT-4 没有将“奴隶”作为任何提示的职业生成,所以……我想这算是进步?)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为什么语言模型可能会有问题。GPT-2 为各种不同的人群生成了“[x] 人作为奴隶”这一职业。图像由作者创建。

结果 4: 某些职业的种族群体变化

与性别类似,GPT 模型在职业与不同种族群体的关联上也发生了变化。

GPT-4 趋向于增加亚洲和黑人工人与“软件工程师”和“记者”这两个职业的关联,即使这些值与现实世界数据相差甚远。事实上,GPT-2 对“软件工程师”这一职业的种族关联比较均等。我们在更新的模型中看到了对某些种族的更明显的倾斜。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

实际与 AI 生成的“软件工程师”和“记者”职业的种族划分,与 2022 年美国劳动局数据相比。

结果 5:宗教专属职业

2020 年的原始实验发现,GPT-2 推断出宗教实践与从事宗教职业之间有很强的关联。 也就是说,提示“佛教徒从事……”的结果中有 4%的生成职业是“僧侣”。

这种关联在较新的 GPT-3.5 和 GPT-4 模型中更为明显,这两个模型都预测超过 95%的佛教男性会从事僧侣工作。

这种关联在其他测试的宗教中也同样存在,其中宗教子群体与其各自的宗教角色(基督教牧师和教士、印度教祭司、穆斯林伊玛目和犹太拉比)强烈相关。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由语言模型生成的宗教职业比例。图片由作者创作。

尽管大多数佛教徒并不从事僧侣工作,大多数犹太人也不从事拉比工作,但当提示中指定了宗教时,语言模型倾向于形成这种关联。GPT-3.5 和 GPT-4 表现出宗教与从事宗教职业之间的更强关联,特别是在佛教、伊斯兰教和犹太教中。

结果 6:某些职业的政治极化

以前,研究人员曾讨论过语言模型的政治偏见。语言模型往往反映了其训练数据中的政治倾向。我自己的先前实验发现,GPT-3 倾向于具有更多的自由主义政治偏见

在比较三代 GPT 模型时,我观察到与保守派和自由派相关的职业发生了变化。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GPT-2/3.5/4 生成的输出中自由主义和保守主义职业的比例。图片由作者创作。

“政治家”和“银行家”是 GPT-2 几乎专门与自由派人士相关联的职业,但 GPT-4 则几乎专门与保守派人士相关联。同样,GPT-4 生成的输出将“社会工作者”专门与自由派人士关联,即使早期的 GPT-2 模型并未如此。

较新的 GPT-4 模型倾向于将某些职业几乎专门与自由派或保守派人士关联。 这些类型的职业可能在下游使用场景中会引发问题,特别是在一个日益政治极化的世界中。

讨论

本文中的实验显示,GPT-2 与不同人口群体相关联的职业与 GPT-3.5 和 GPT-4 所关联的职业有很大不同。可以理解的是,每个模型会将不同的子群体与不同的职业相关联,并且生成的输出会随着模型的增长、改进、演变和对新数据的训练而改变。

然而,对于部分职业,从 GPT-2 到 GPT-3.5 再到 GPT-4 的比例变化使得这种转变变得明显。较新的模型往往过度校正和夸大某些职业的性别、种族或政治关联。这在以下方面得到了体现:

  • 在 GPT-2 中,软件工程师主要与男性相关联,而在 GPT-4 中则主要与女性相关联。

  • 在 GPT-2 中,软件工程师与每个种族的关联几乎是均等的,而在 GPT-4 中,则主要与黑人和亚裔工人相关联。

  • GPT-2 表现出宗教与从事宗教职业之间的关联;GPT-3.5 和 GPT-4 则大大夸大了这种关联。

  • 在 GPT-2 中,政治家和银行家主要与自由派人士相关联,而在 GPT-4 中则主要与保守派人士相关联。

当与美国人口普查局的数据相比时,这些模式变得更加明显,特别是对于软件工程师。

我并不主张语言模型的输出完美地反映现实世界的职业分布。实际上,推动媒体对传统上由单一性别主导的工作,如护理或工程领域,进行更多的呈现,对于挑战刻板印象至关重要。

然而,重要的是要承认这些语言模型在某些人口群体的职业关联方面所显示的潜在趋势。虽然在较新的模型中,软件工程越来越与女性对齐,但这种趋势并未普遍适用。例如,护理仍然主要与女性相关联。

这引发了问题:训练数据中是否有更多(可见的)女性从事软件工程,影响了这些关联?或者,是否存在属于训练模型公司或标注训练数据的人类标注者的政治或商业动机,旨在将特定人口群体与特定职业关联起来?

回到 2020 年,当我开始探讨 GPT-2 以揭示其在职业和不同人口群体方面的偏见时,我没有想到生成语言模型会变得如此重要[4]。

在进行原始实验时,我们面临了相同的问题,即语言模型应该代表和生成什么。我们以以下声明结束了原始论文:

生成语言模型的目标应该是什么?显然,它们不应该加剧现有社会关于职业隔离的偏见。是否应该反映或纠正社会分布的偏差则不那么明确。

这些问题更多地涉及社会和文化需求,而非技术上的可行性。它们今天仍然相关,并且很可能会继续相关。

附录:具体角色的分类

按性别分类

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按种族分类

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按宗教分类

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按性取向分类

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1 GPT-3 论文已经发布,但该模型尚未公开可用。

2 本文与原论文相比的某些方法学/数据差异:(1)在原论文中,我们每个类别生成了 7000 个样本。然而,本文中由于成本原因,我每个类别生成了 1000 个样本。(2)本文中我增加了一些与性别相关的附加类别,即“跨性别者”、“双性恋”和“异性恋”。本文中还包括了中性“人”(除了男性和女性)。 (3)在原论文中,我们还使用了来自不同大陆的流行男性和女性名字来提示模型,但本文中未进行此操作。(4)在原论文中,我们对模型输出进行了与实际美国劳工局职业数据的系统比较。

3 经常出现一个模型仅生成一次的职业,之后不会再生成。我筛选出了每个模型仅生成一次的职位。

4 事实上,我在开始这个项目之前,从未听说过“生成语言模型”或了解它们是什么。

谁赢,谁输?AI 编码工具将如何影响不同类型的业务

原文:towardsdatascience.com/who-wins-and-who-loses-how-different-types-of-business-could-be-impacted-by-ai-tools-684d1e83a9e0

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者使用 Midjourney 制作的图片

生成式 AI 将如何影响产品工程团队 — 第五部分

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Mark Ridley

·发表于 Towards Data Science ·阅读时间 8 分钟·2023 年 7 月 31 日

这是一个六部分系列的第五部分,调查了生成式 AI 生产力工具(如 GitHub Copilot、ChatGPT 和 Amazon CodeWhisperer)可能如何影响整个产品工程团队的结构。

在第四部分中,我们探讨了:

  1. 生成式 AI 为组织在经济低迷和风险投资资金减少期间提供的机会。

  2. 三种公司可以利用生成式 AI 生产力工具提高开发者生产力的情景:投资增长、削减成本和维持当前预算

  3. 假设的后果和挑战,例如团队组成的剧烈变化以及这些变化对产品经理和工程师可能意味着什么。

谁从中受益 — 谁受益?

当商业环境迅速变化时,总是会有赢家和输家。到目前为止,我们一直从假设模型的角度讨论生成式 AI 工具的好处和可能的影响,但我们忽略了许多未明言的警示。

实际上,即使这些好处如我在前四篇文章中所描述的那样显现,我们也不太可能看到我们讨论的结构性变化会在一夜之间发生。

我可以证明,改变业务中角色的类型和数量会导致许多不眠之夜。大多数组织会选择不直接处理这些变化,因为变革既困难又充满情感。对大多数公司来说,这些变化会慢慢发生,逐步、有机地进行,避免做出艰难的决策。遗憾的是,这也意味着许多组织不会像他们应该的那样迅速看到这些变化带来的好处。

考虑到团队可能从这些 AI 编码工具中受益,我现在想关注它们可能对不同类型组织的影响;刚刚起步的初创公司有着雄心勃勃的增长计划,规模较小但稳定的公司,其产品和技术团队人数不到一百人,大型组织,技术团队有数百名工程师,以及我认为将会看到特别大影响的一个群体:开发外包和离岸公司。

初创公司

刚刚获得第一笔天使投资或风险投资的初创公司将从减少每个产品所需的工程师人数中受益最大。

就像 10 年前 Amazon AWS 和其他超级云服务提供商的到来一样,AI 编码助手(和低代码工具)的影响将进一步实现创造网页、移动和内部后台应用程序的能力的民主化(和揭秘)。简单来说,技术水平较低的团队将更容易将产品交付给付费客户。

即使在 15 年前,购买服务器的资本成本和多年合同的托管服务费用使得启动新产品的门槛对小型企业来说过于高昂。随着云计算的兴起,创业者可以按需扩展,只需一张信用卡(或免费的托管额度)即可。如今,对有产品愿景的创始人而言,最大的问题是工程人员的成本,而这些新工具有望显著降低这一成本。

在大多数获得风投支持的初创公司中,技术被视为业务独特价值的一个重要部分。许多创始团队陷入一个陷阱,认为尽可能多地构建技术栈会增加业务的价值。更糟糕的是,这种情况有时会因为一些风险投资公司推动其年轻的投资组合公司进行更多的垂直整合和事实上的“自建优于购买”的思维而加剧,优先考虑知识产权的拥有权。拥有一支充满技术天才的公司似乎具有一定的魅力,这对创始人和投资者都难以抗拒。

然而,对于务实的技术联合创始人来说,减少烧钱(现金储备的消耗速度)和削减业务中最高的支出之一——工程师薪资,是一个巨大的机会。根据 Carta 的这份报告,工程师通常占客户总人数的 25% 和总薪资支出的 30%。

通过选择重点优化使用生成式 AI 编程助手,如 Copilot,同时选择最小化“聪明”工程的工具,如 AWS Amplify StudioRetoolMicrosoft Power Apps 以及与点解决方案的集成,如 Intercom’s Fin,创始团队可以比那些选择优先考虑知识产权价值的团队更快地推进。

我们在这一系列中讨论的生成式 AI 编程工具迅速缩小了产品经理的愿景与实现该愿景的技术工作之间的差距。

智能的初创公司创始人到 2023 年将从询问他们应该使用哪些工具来构建软件的角度出发,而不是是否应该使用生成式 AI 工具。由于这类公司几乎没有投入现有团队、嵌入的技术偏见和需要支持的遗留软件,他们将能够在起步时就利用新技能和团队结构。

对于初创公司来说,生成式 AI 工具将降低等效质量产品的成本和上市时间,并且可能会鼓励它们有更高的实验倾向,比传统同行更快地进行调整。

小型企业

对于那些拥有两到三个产品工程团队的小型但稳定和成熟的企业来说,将有很好的机会受益于更高效的工程师。选择使用生成式 AI 工具来增强团队的公司应该会看到更高质量的代码、更高的自动化水平、更短的开发周期和更具成本效益的开发。

拥有 20 到 40 名工程师的小型和可管理的开发团队中,许多人已经在公司工作多年,这些企业不太可能选择减少员工人数。然而,提供更多服务而成本不变将会很有吸引力。

在需要降低成本的情况下,对于较小的公司来说,最明显的地方是查看任何外包开发伙伴,特别是那些更传统的 “bodyshopping” 公司,这些公司提供工程、测试或其他技术技能。在这些较小的企业中,如果能使永久工程师变得更加高效,那么裁减外包和昂贵的合同角色的费用将比裁减内部员工更容易。

(外包公司自身可能会发生业务模式的变化,我们稍后会回到这一点)

对于小型企业,应该会有小而积极的经济影响,因为它们的小团队会更多地自动化工作,并看到更高质量的输出,同时裁员风险相对较低。

大型公司

拥有一百多人技术和产品团队的大型企业在其长期规划中面临艰难的选择——它们是希望以相同的成本增长,还是以大幅降低的成本维持相同的产品开发速度?

这些组织的规划是按年进行的,而不是按季度进行。大多数公司将与多个外包公司建立长期合作关系,并拥有内部的永久和临时技术员工混合体。正如我们之前简单建模所见,对于选择完全拥抱生成性 AI 工具的这种规模的公司来说,潜在的节省每年可达数百万英镑/美元/欧元。

然而,尽管财务利益显著,这些公司中的变革也很困难。既定的思维方式和工作方式、现有的等级制度、内部政治、组织变革的复杂性以及大规模裁员的非常显著成本将导致规划详细而缓慢。虽然这些公司在考虑变革如何展开时,它们的团队可能会开始自行采用工具。正如我们在其他易于使用的技术工具中所见,通常是市场营销等非技术(但与技术相关)团队推动了工具的采用。在产品工程团队内部,也会有一些创新和采纳工具的动力,但可以理解的是,对减少技术组织中的角色数量的努力较少。

对于这些大型企业来说,风险很高,但变革将缓慢进行,生产力或成本节省的好处也将逐渐显现。然而,对于一些有眼光和果断的组织来说,影响可能会很显著。

外包公司

啊,我一直在等待这个。

我首先想说的是,确实有很多外包的好理由,我通常将其分解为以下几点:

  1. 吸引公司不一定会持续使用的高价值技能

  2. 为稳定的永久团队成员基础增添灵活性

  3. 增加一个不会使你的业务与众不同的能力

外包的一个不太理想的用途是拥有大型的、多年的合同,用于相对昂贵且长期保持一致的资源。不幸的是,这仍然很常见,许多外包公司一旦成为客户的“家具”后,就会赚很多钱。

Stability AI 的首席执行官 Emad Mostaque 最近在一次采访中表示,他认为“在接下来的一两年内,外包的三级程序员将会消失”并且“五年后将没有程序员”。我认为我对 Mostaque 的观点不如他那样乐观,但仍然看到外包公司在不久的将来面临巨大的挑战。

对于那些专注于提供短期价值的咨询公司来说,调查生成式 AI 工具的机会非常明显,因为他们有现金和激励来配置自己的团队进行工具实验,并向客户展示最佳实践。会出现一个暂时丰富的市场,类似于 5-10 年前的‘数字化转型’趋势,这些公司可以提供咨询,帮助客户公司采用新工具,提供培训、框架和使用指南。这对于那些更为保守的客户将尤其令人放心,如果他们能够获得有关知识产权、安全和数据隐私等问题的深思熟虑的建议,这些问题可能对他们来说过于重大。

正如我之前提到的,任何认为生成式 AI 工具应该带来成本节省的公司,可能会首先审视其外包和离岸成本,然后才会考虑减少正式员工的数量。

如果我在一家大型组织中担任首席技术官,面对像 Copilot 和 CodeWhisperer 这样的工具,并了解到五分之四的开发人员可以被 AI 工具替代,我的初步反应将是开始考虑所有的外包支出。为了保护我高价值的内部工程师,削减对外包公司的资金将是一个相对简单的哲学决策。

这将会很有趣地展开。对于提供高度专业化咨询服务的外包公司影响会较小,但如果客户外包是为了利用低成本地区的技术资源,影响将会非常真实且不断增长。

专注于移动应用开发、网页应用开发、QA 或 DevOps 等领域的小型精品公司,将受到的影响与像埃森哲、德勤、TCS、Infosys 和 Wipro 等巨头会有所不同。

那些最应该担忧生成式 AI 工具出现的供应商是那些有持续的人力外包合同,提供相对通用技术资源给客户的公司,而不是那些合作提供特定成果或高度专业技能的公司。

在第六部分,我们将把接力棒交给你,并请求你进行实验,同时反思早期采用者需要考虑的关键事项。

阅读第六部分发布后

本系列的其他文章:

附言。如果你喜欢这些关于团队的文章,可以查看我的Teamcraft 播客,在这里我和我的共同主持人 Andrew Maclaren 会与嘉宾讨论如何让团队运作顺利。

为什么箱线图不应单独使用及与之配合使用的 3 种图表

原文:towardsdatascience.com/why-a-box-plot-should-not-be-used-alone-and-some-plots-to-use-it-with-23381f7e3cb6?source=collection_archive---------12-----------------------#2023-01-16

解释箱线图中的缺失信息及使用 Python 代码解决该问题的替代方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Boriharn K

·

关注 发表在 Towards Data Science ·7 分钟阅读·2023 年 1 月 16 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由Lance Asper提供,来源于Unsplash

箱形图或 箱形图和须图描述性统计 中常见的数据可视化图表。该图通过其 四分位数 直观地展示数值数据,这些四分位数包括最小值、第一个四分位数、中位数、第三个四分位数和最大值。此外,它有助于轻松发现异常值。

然而,没有什么是完美的。箱形图有一些主要的限制。在解释这些限制之前,让我们看看下面的图片。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

箱形图显示了三组数据的分布。图像由作者提供。

这些是三组不同数值数据的箱形图。可以注意到它们看起来几乎一样。我知道你可能有一种直觉感觉它们并不相同。

事实上,当使用直方图绘制真实数据时,数据完全不同,如下图所示。在这种情况下,使用箱形图可能会误导数据的解释。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

直方图和箱形图显示了三组数据的分布。图像由作者提供。

这个问题可以简单解释为: 箱形图无法显示数据集的 众数

此外,作为出现频率最高的值,众数也指的是分布的 局部最大值。在处理 双峰分布、它有两个众数(或峰值),或 多峰分布、它有多个峰值时,箱形图无法表达这些洞察信息。

此外,箱形图的形状为矩形,因此它可能会误导我们认为四分位数范围内有数据。如果四分位数范围内存在空白或没有数据,这些情况可能不会被注意到。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

本文推荐的用于与箱形图配合使用的可视化示例。图像由作者提供。

鉴于这些限制,箱形图应该与其他图表一起使用。本文将介绍一些可以与箱形图配合使用的替代图表,以可视化数据特征。

开始吧。

免责声明: 本文对使用箱形图没有任何异议。如前所述,一切都有利有弊。就个人而言,我仍然使用箱形图,因为它帮助我轻松找到异常值。然而,我不会单独使用它。要彻底理解数据,还需要使用其他图表。

获取数据

从导入库开始。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline

作为示例,本文将使用一个模拟数据集。我们将使用Numpy创建一个正态分布的数据集。

mu, sigma = 0, 1 #mean and standard deviation
s1_pre = np.random.normal(mu, sigma, size=5000)
s1 = [i for i in s1_pre if i<2.6 and i>-2.6]

通过下面的代码修改生成的数据,以获得另外两个具有不同分布和数据间隙的数据集。

#defnie a function
def pair_sum(input_):
    input_.sort()
    if len(input_)%2 == 0:
        loc = [i for i in range(len(input_)) if i%2 == 0]
        output = [input_[l] + input_[len(input_)-(l+1)] for l in loc]
    else:
        loc = [i for i in range(len(input_)) if i%2 == 0]
        output = [input_[l] + input_[len(input_)-(l+1)] for l in loc[0:-1]]
        output.append(input_[-1])
    return output

#bimodal distribution with gaps
s2_out, s2_sub1, s2_sub2 = [], [], []
for i in s1:
    if i>0.05 and i<0.6:
        s2_sub1.append(i)
    elif i<-0.05 and i>-0.6:
        s2_sub2.append(i)
    else:
        s2_out.append(i)

sub1_mod = pair_sum(s2_sub1)
sub2_mod = pair_sum(s2_sub2)
s2 = s2_out + sub1_mod*2 + sub2_mod*2

#distribution with gaps
s3_out, s3_sub = [], []
for i in s1:
    if i>-0.4 and i<0.4:
        s3_sub.append(i)
    else:
        s3_out.append(i)

sub3 = pair_sum(s3_sub)
s3 = s3_out + sub3*2

绘制模拟数据以查看结果。

c_list = ['#1a936f', '#F77F05', '#D62829']

n = 25
f, axes = plt.subplots(3, 2 ,figsize=(12,5))
ax1=sns.boxplot(s1,ax= axes[0,0],color= c_list[0],boxprops= dict(alpha=.9))
ax2=sns.boxplot(s2,ax= axes[1,0],color= c_list[1],boxprops= dict(alpha=.9))
ax3=sns.boxplot(s3,ax= axes[2,0],color= c_list[2],boxprops= dict(alpha=.9))

ax4=sns.histplot(s1, bins=n, ax=axes[0,1], color=c_list[0])
ax5=sns.histplot(s2, bins=n, ax=axes[1,1], color=c_list[1])
ax6=sns.histplot(s3, bins=n, ax=axes[2,1], color=c_list[2])

ax4.set(ylabel=None, yticklabels=[])
ax5.set(ylabel=None, yticklabels=[])
ax6.set(ylabel=None, yticklabels=[])
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

直方图和箱线图显示了模拟数据的分布。图片来源:作者。

在继续之前,让我们创建一个 DataFrame。在这一步中,我们将使用panda.cut将数据值分段并排序,以备后用。

bins1 = pd.cut(s1, bins=n, labels=False)
bins2 = pd.cut(s2, bins=n, labels=False)
bins3 = pd.cut(s3, bins=n, labels=False)

df1 = pd.DataFrame(zip(s1, bins1), columns=['v1','bins'])
df2 = pd.DataFrame(zip(s2, bins2), columns=['v2','bins'])
df3 = pd.DataFrame(zip(s3, bins3), columns=['v3','bins'])

df1_m = pd.melt(df1, id_vars=['bins'],value_vars=['v1'])
df2_m = pd.melt(df2, id_vars=['bins'],value_vars=['v2'])
df3_m = pd.melt(df3, id_vars=['bins'],value_vars=['v3'])

df = pd.concat([df1_m, df2_m, df3_m])
df.head()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

替代的数据可视化

1. 小提琴图

小提琴图的概念基于箱线图和核密度图。因此,结果可以表达数据集的峰值。这是检查数据集是否具有单峰、双峰或多峰分布的好方法。

在本文中,我们将主要使用Plotly,一个有用的数据可视化库,来可视化数据。我们可以用几行代码绘制小提琴图,如下所示。

import plotly.express as px
fig = px.violin(df, x = df['value'], box=True, width=900, height=600,
                color=df['variable'], color_discrete_sequence=color_list)
fig.update_layout(legend_title="", xaxis_title=None)
fig.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

小提琴图显示了模拟数据的分布。图片来源:作者。

2. 直方图

与箱线图相比,直方图是另一种能够展示数据分布的数据可视化方式。每个区间的数据密度显示了是否存在间隙或多个峰值,或四分位数范围之间的间隙。

先用下面的代码分别绘制每个直方图。

fig1 = px.histogram(x= df[df['variable']=='v1']['value'],
                    nbins = 50, width=900, height=400,
                    color_discrete_sequence=[color_list[0]])
fig2 = px.histogram(x= df[df['variable']=='v2']['value'],
                    nbins = 50, width=900, height=400,
                    color_discrete_sequence=[color_list[1]])
fig3 = px.histogram(x= df[df['variable']=='v3']['value'],
                    nbins = 50, width=900, height=400,
                    color_discrete_sequence=[color_list[2]])

fig1.update_layout(xaxis_title=None, yaxis_title=None)
fig2.update_layout(xaxis_title=None, yaxis_title=None)
fig3.update_layout(xaxis_title=None, yaxis_title=None)

fig1.show()
fig2.show()
fig3.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

直方图显示了模拟数据的分布。图片来源:作者。

我们还可以叠加直方图并添加地毯图来展示分布标记。

fig = px.histogram(df, x= 'value', nbins = 60, color = 'variable',
                   opacity=0.8, width=900, height=600, marginal="rug",
                   color_discrete_sequence=color_list)
fig.update_layout(yaxis_title=None, legend_title="", xaxis_title=None)
fig.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

叠加直方图和地毯图显示了模拟数据的分布。图片来源:作者。

可以添加核密度估计(KDE)线,以使结果更具信息性。

import plotly.figure_factory as ff

group_labels = list(set(df['variable']))
hist_data = [df[df['variable']=='v1']['value'],
             df[df['variable']=='v2']['value'],
             df[df['variable']=='v3']['value']]
fig = ff.create_distplot(hist_data, group_labels, bin_size=0.25,
                         colors=color_list)
fig.update_layout(width=900, height=600)
fig.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

叠加直方图、KDE 线和地毯图显示了模拟数据的分布。图片来源:作者。

3. 条形图

如果之前的结果看起来复杂,条形图可能是创建简洁可视化的一个好方案。

可以创建条形图,如下所示。

import plotly.express as px
fig = px.strip(df, x = 'value', y ='variable', stripmode='overlay',
               width=1000, height=600
              )
fig.update_layout(xaxis_range=[-2.69, 2.69])
fig.update_layout(legend_title="", yaxis_title=None,
                  xaxis_title=None,showlegend=False)
fig.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

条形图显示了模拟数据的分布。图片来源:作者。

然而,由于我们无法区分每个数据范围内的数据密度,结果可能不会太有用。通过分配颜色以表达密度,结果可以得到改善。

下面的代码展示了如何定义一个函数,以创建一个字典来为每个数据范围中的数据点着色。

#add a new columns to facilitate creating a dictionary
df['vari_bins'] = [v+'_'+str(b) for v,b in zip(df['variable'],df['bins'])]

def strip_color(input_list, prefix, color, n_color):
    #count data in each bin 
    c_bin = [input_list.count(i) for i in range(n)]
    #create a dictionary by enumerate each bin  
    dict_c = {prefix+str(c):i for c,i in enumerate(c_bin)}

    #sort the dictionary
    sort = {i[0]:i[1] for i in sorted(dict_c.items(), key=lambda x: x[1])}
    #extract color code from color palette
    pal = list(sns.color_palette(palette=color, n_colors=n_color).as_hex())

    #assign color code to the dictionary
    dict_out = {c:p for c,p in zip(sort.keys(), pal)}

    return dict_out

应用函数

dict_p1 = strip_color(list(df1_m['bins']), 'v1_', 'YlGn', 25)
dict_p2 = strip_color(list(df2_m['bins']), 'v2_', 'Oranges', 25)
dict_p3 = strip_color(list(df3_m['bins']), 'v3_', 'YlOrRd', 25)

dict_ = {}
dict_.update(dict_p1)
dict_.update(dict_p2)
dict_.update(dict_p3)

绘制条形图

import plotly.express as px
fig = px.strip(df, x = 'value', y ='variable',
               color = 'vari_bins',
               color_discrete_map=dict_, stripmode='overlay',
               width=1000, height=600,
              )
fig.update_layout(xaxis_range=[-2.69, 2.69])
fig.update_layout(legend_title="", yaxis_title=None,
                  xaxis_title=None, showlegend=False)
fig.show()

看呐!!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

带有颜色的条形图展示了模拟数据的分布。图像由作者提供。

总结

这篇文章展示了箱线图在展示众数时的局限性,这可能导致误导性的解释。在绘制具有两个或更多峰值的数据集或在四分位数范围内显示数据缺口时,它并不有用。顺便说一下,箱线图有一些优点,例如简单的可视化和显示异常值。

我相信还有比这篇文章中提到的更多图表可以弥补箱线图的缺点。

如果你有任何建议,请随时留言。我很乐意看到它。

感谢阅读

这些是我撰写的数据可视化文章,你可能会感兴趣:

  • 7 种使用 Python 表达排名随时间变化的可视化方法 (链接)

  • 8 种使用 Python 处理多个时间序列数据的可视化方法 (链接)

  • 9 种使用 Python 的可视化方法,比条形图更引人注目 (链接)

  • 9 种使用 Python 的可视化方法来展示比例,而不是饼图 (链接)

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值