基于标签的多领域文本分类
Labelur 允许你通过 REST API 对多领域文本进行分类。Labelur 使用现代零镜头学习技术进行多领域文本分类,无需训练定制模型。
什么是 Labelur?
Labelur 是一个执行多领域文本分类的在线服务。上手毫不费力!只需使用您选择的任何编程语言,如 Python、Java、Node 或 PHP(谁还在使用 PHP?)用您的文本数据向 Labelur 的 API 服务器发送 POST 请求。Labelur 将回复给定文本的标签。
Labelur 与其他文本分类有何不同
大多数文本分类服务只处理特定领域的数据,如情感分析、法律文档分类或通用主题的通用文本分类。如果你想为一个特定的领域做一个分类器,比如房地产,你需要有一个训练数据,创建一个分类器。传统上,如果没有数据来训练自定义模型,就无法产生好的文本分类器。
Labelur 使用 NLP 中的现代进步来分类大多数通用领域中的文本。它利用知识提炼和零炮学习对文本进行分类。如果您没有自己的数据或者不想训练和部署自己的 ML 模型,这是一个极好的起点。
让我们对一些文本进行分类!
我将用 Python 做一个演示,但是同样的,你可以使用任何你选择的语言。首先,创建一个帐户并获得您的 API 密钥。
API 密钥已被编辑
我将使用 Python 的请求库向 Labelur 的服务器发送 POST 请求。JSON 库将用于 JSON 化我们的文本负载,Matplot 将用于绘制最终结果。
在这里,我们必须遵循有效载荷模式。有效载荷需要有文本和 标签作为键。标签的值将由一列字符串组成,文本的值也将是一个字符串。在选择可能的标签类别时,我们必须选择一个尽可能描述该类别的词。
例如,在文本“了解美国的邮寄投票”中,我们提供的标签是“体育”、“政治”和“选举”。下面是 Labelur 返回的结果。
Labelur 的结果
总之
我们只用了 3 分钟就创建了一个帐户,并开始使用 Labelur 对文本进行分类。如果您没有数据来训练自己的模型,或者不想处理部署 ML 模型的麻烦,Labelur 可能是您的一个很好的解决方案。
注意:Labelur 目前处于测试版,API 仅通过邀请提供。
使用传单和 amCharts 在浏览器中进行多方面的数据探索
在浏览器中创建一个数据探索仪表板,从 Google Sheets 加载实时记录,并将地理空间信息与时间数据交叉。
演示:https://smarques.github.io/mufa-leaf/
(演示中的数据是随机的,真正的研究还没有发表。)
在这个充满挑战的 CoVid 时代,我被要求对我居住的意大利地区进行数据可视化。
这些数据由大约 20k 条记录组成,按照子行业、主题类型、数据来源和活动开始的年份进行地理参考和标记。
例如:
subsector =>sub C1,
subject =>subject 2,
year = > 1985,
position =>【45.375302,11.727905】
source =>gov . Census
我的目标是以不同的方式探索这些数据:
- 作为地图上的标记和聚类-
-作为可导航的树形图-
-通过过滤器和时间轴选择器
理想情况下,这种可视化应该应用于整个数据集或选定的数据子集,以便您可以应用过滤器,查看特定年份的分布情况,也可能仅针对给定省份的特定子行业。
想法是将数据作为 JSON 结构加载到浏览器中,并保存在内存中,根据用户与过滤器的交互加载子集,并将子集数据提供给每个可视化。
我在这里将会介绍一些流程,具体的实现请参考 GitHub repo:https://github.com/smarques/mufa-leaf
准备数据
由于数据仍在修改和重新分类中,我想从一个共享的谷歌表单中加载它。我还用谷歌工作表对地址进行地理编码,使用的是这个漂亮的谷歌工作表宏。
因为人们仍在使用 google sheet,所以我决定在将数据导入我的 JS 应用程序时直接进行数据检查和数据清理。
要从 Google 工作表中加载数据,我找到的最佳选项是 Papa Parse 。它可以让你把 CSV 解析成 JSON,从任何地方加载,处理大文件,所有的事情,而且它有一个有趣的名字。
让我们试一试。
首先,您需要在 Google 表单上执行两个操作:
- 发布到 web:文件->发布到 web,复制网址,会是这样的:https://docs.google.com/spreadsheets/d/e/<哈希>/pub html
- 分享:点击右上方的分享按钮,然后点击获取可分享链接。这将打开按链接共享,任何有链接的人都可以看到数据。
你需要提供给 Papa Parse 的 url(呀,这个名字真有趣)是 https://docs.google.com/spreadsheets/d/e/T4<哈希> /pub?输出= CSV
你也可以直接从 google sheets 导出 JSON 格式的数据,但是我们的朋友 Papa 给了我们更多的类型转换、数据清理等选项。
完成后,您只需通过以下方式导入数据:
https://gist . github . com/smarques/3d bfaaae 4 B3 D8 a 204 D2 AC 280 f 488528 e
processData 函数负责清理和提炼我们从 Google Sheets 收到的数据。有时你需要应用一些正则表达式,删除奇怪字符,修复输入错误。
创建聚类地图
现在的目标是让这些家伙在地图上,可能在三个不同的层和不同的标记颜色层。我们还希望标记有一个不同的主题类型的图标。因为我们有将近 30k 个标记,所以设置一些聚类可能是个好主意。
我选择的地图库是传单。它有很棒的代码和文档,非常灵活,有一个很好的插件生态系统。
我添加了几个插件,如:
传单全屏控制因为我只是喜欢让地图全屏
传单轻松打印:有几个打印插件,但这似乎对我最有效
传单提供者:要轻松混合和匹配不同来源的瓷砖,我必须提到雄蕊水彩瓷砖因为它们真的很赏心悦目。
传单牛逼标记让你在地图标记上使用牛逼字体图标
现在,如果您只需显示并最终过滤传单地图上的标记,通常的做法是将标记添加到相应的图层,然后调用地图上的函数来隐藏或显示整个图层或特定标记。我的想法有点不同,我想将所有数据保存在应用程序级别,这样我不仅可以将它用于地图,还可以用于其他图形和小部件。当我们应用过滤器时,我希望在应用程序级别过滤数据,随后重新绘制地图,以及应用程序中任何其他数据相关的小部件。
此时的问题是:地图和图形的重绘速度是否足够快,以提供良好的用户体验和数据探索?
让我们来了解一下。(剧透:yayyy 他们做)
因此,我们在应用程序中有一个名为 currentData 的变量,它保存当前显示的完整记录集的子集。每次用户改变选择过滤器时,我们从 App.data 开始创建一个新的数据选择,保存到 App.currentData 中,并触发每个小部件的重绘。
updateCurrentData(App.data);
即使我们只是在清理数据后初始化应用程序,我们也可以调用 update 函数来填充应用程序 currentData ,因为用户没有机会过滤记录集,函数将只选择每一条记录,我们就可以开始了。
现在让我们看看如何使用地图小部件。
没有聚类,地图会有点拥挤:不是很有用,而且在你的浏览器上也很沉重。
因此,让我们使用传单添加一个聚类级别。标记集群。
我根据标记所属的子部门来构造标记,这里只有 4 个可能的值,所以让每个子部门在不同的层上会使每个组的开关变得非常容易。此外,这将使每个子行业有可能有单独的集群,使显示更有趣,并为数据分布提供更好的线索。
MarkerCluster 允许您自定义显示聚类标记的功能(因此得名…)因此,根据集群的大小,我有稍微不同的标记。(例如,参见 9 对 325 红色星团)。
对于四个扇区中的每一个,我们实例化一个标记集群组,给出一个 iconCreateFunction,如前所述。我还在集群图标上添加了一个鼠标悬停功能,这样你就可以通过将鼠标悬停在一个层上来向上浮动(改变它的 z 索引)。
我还想强调这项研究涉及的领域。传单让你加载 GeoJSON 所以我所要做的就是在 GitHub 中搜索带有该区域形状的 GeoJSON,并将其加载到自己的图层上。(感谢斯特凡诺·库迪尼)
L.geoJson(venetoData).addTo(App.mainMap);
过滤器!
我希望所有的过滤器都集成到地图中,所以我在地图的右侧添加了一个侧面板,让您可以打开不同的过滤器控制面板。
我为整个子行业或某个行业内的单个主题创建了过滤器。然后过滤每个省
并且对于每个数据源
我不会深入讨论所有过滤器 gui 的实现细节,您可以在 GitHub repo 上查找,基本上是为了避免回调地狱每个 gui 元素都使用 bacon.js (一个反应函数库)连接到一个事件流。这样,任何过滤器中的任何更改都会导致调用相同的更新函数,传递完整的过滤器值集,以便我们可以将所有需要的条件应用到完整的数据集,并为每个要显示的小部件加载新的 currentData 子集。
更新功能
因为我希望将数据过滤保持在主应用程序级别,所以每次过滤器发生变化时,我都会调用一个更新函数来从整个集合中提取相关数据。
我使用一个名为 的 js 库 alasql 根据用户选择的过滤器处理 15k 记录数组。其中,alasql 允许您对任何对象数组运行 sql 查询。这使得处理您的数据变得非常容易,并且使您的代码可读,易于调试和维护。
我可以运行如下查询:
var res = alasql(`SELECT MIN(${App.field_names.year}) AS minYear, MAX(${App.field_names.year}) AS maxYear FROM ? WHERE ${App.field_names.year} > 1900`, [App.currentData]);
至此,我在 update 函数中所要做的就是构建一个条件数组来添加到我的 SELECT 语句中。
事实证明,如果您删除所有图层标记并重新添加它们,MarkerCluster 的更新速度非常快,所以当我有一个新的 currentData 对象时,我只需运行它并重新分配它。
时间轴选择器
接下来,我们希望能够根据年间隔选择记录。
传单控件只是 html 元素,所以我使用了 Ion。RangeSlider 并将其值添加到触发新查询和后续重绘的反应流中。
当我第一次从 Google Sheet 接收数据时,我只获得了 year 列的最小值和最大值,所以我可以用它来显示时间选择器的合理范围。
树形图
作为最后一个元素,我们添加了一个树形图,这样我们就可以可视化所选子集的结构。我包含了 amCharts 库,并在我的更新函数中设置了一个调用来重绘图表。我选择按省份开始分解。
然后,您可以点击树形图块,在可视化视图中向下钻取。
包装它
因此,现在我们有了一个主应用程序层,它负责加载完整的数据,根据不同的过滤器和用户行为进行子选择,然后触发不同图形和小部件的更新。这是一个很好的框架,可以让用户在浏览器中探索数据,并且很容易添加更多的可视化。关键是它们都引用相同的数据子集。
例如,当您更改 year 参数时,查看位置和数据结构如何变化非常有用。您可以添加一个播放按钮,并创建一个显示每年变化的动画。
另一个改进是通过 IndexedDb (alasql 支持它)同步本地存储上的数据,以便您有完整的离线体验。
如果你想添加元素或进行实验,请随意在 GitHub 上提出请求!
Pytorch 中的多 GPU 培训
数据和模型并行性
安娜·安彻的《收割机》。链接:维基百科。
这篇文章将概述 Pytorch 中的多 GPU 培训,包括:
- 在一个 GPU 上训练;
- 多 GPU 上的训练;
- 通过一次处理更多的例子,使用数据并行性来加速训练;
- 使用模型并行性来支持需要比一个 GPU 上可用的内存更多的内存的训练模型;
- 使用 num_workers > 0 的数据加载器来支持多进程数据加载;
- 仅在可用设备的子集上训练。
在一个 GPU 上训练
假设您有 3 个可用的 GPU,并且您想在其中一个上训练一个模型。您可以通过指定设备来告诉 Pytorch 使用哪个 GPU:
device = torch.device('cuda:0') for GPU 0device = torch.device('cuda:1') for GPU 1device = torch.device('cuda:2') for GPU 2
在多个 GPU 上训练
要允许 Pytorch“查看”所有可用的 GPU,请使用:
device = torch.device('cuda')
使用多个 GPU 有几种不同的方式,包括数据并行和模型并行。
数据并行度
数据并行是指使用多个 GPU 来增加同时处理的实例数量。例如,如果 256 的批处理大小适合一个 GPU,您可以通过使用两个 GPU 使用数据并行性将批处理大小增加到 512,Pytorch 会自动将大约 256 个示例分配给一个 GPU,将大约 256 个示例分配给另一个 GPU。
使用数据并行可以通过数据并行轻松实现。例如,假设您有一个名为“custom_net”的模型,该模型当前初始化如下:
import torch, torch.nn as nnmodel = custom_net(**custom_net_args).to(device)
现在,使用数据并行性所要做的就是将 custom_net 包装在 DataParallel 中:
model = nn.DataParallel(custom_net(**custom_net_args)).to(device)
您还需要增加批量大小,以最大限度地利用所有可用设备。
有关数据并行性的更多信息,请参见本文。
模型并行度
您可以使用模型并行性来训练需要比一个 GPU 上可用的内存更多的内存的模型。模型并行性允许您将模型的不同部分分布在不同的设备上。
使用模型并行有两个步骤。第一步是在模型定义中指定模型的哪些部分应该在哪个设备上运行。这里有一个来自 Pytorch 文档的例子:
**import** torch
**import** torch.nn **as** nn
**import** torch.optim **as** optim
**class** **ToyModel**(nn**.**Module):
**def** __init__(self):
super(ToyModel, self)**.**__init__()
self**.**net1 **=** torch**.**nn**.**Linear(10, 10)**.**to('cuda:0')
self**.**relu **=** torch**.**nn**.**ReLU()
self**.**net2 **=** torch**.**nn**.**Linear(10, 5)**.**to('cuda:1')
**def** **forward**(self, x):
x **=** self**.**relu(self**.**net1(x**.**to('cuda:0')))
**return** self**.**net2(x**.**to('cuda:1'))
第二步是确保在调用 loss 函数时,标签与模型的输出在同一个设备上。
例如,您可能希望从将标签移动到设备“cuda:1”并将数据移动到设备“cuda:0”开始。然后,您可以在“cuda:0”上用模型的一部分处理您的数据,然后将中间表示移动到“cuda:1”,并在“cuda:1”上生成最终预测。因为您的标签已经在“cuda:1”上,Pytorch 将能够计算损失并执行反向传播,而无需任何进一步的修改。
有关模型并行性的更多信息,请参见本文。
使用 Num_Workers 加快数据加载速度
Pytorch 的数据加载器提供了一种自动加载和批处理数据的有效方法。您可以将它用于任何数据集,不管它有多复杂。您需要做的就是首先定义您自己的数据集,该数据集继承自 Pytorch 的 Dataset 类:
from torch.utils.data import DataLoaderclass MyComplicatedCustomDataset(Dataset):
def __init__(self, some_arg, some_other_arg):
"""Documentation"""
self.some_arg = some_arg
self.some_other_arg = some_other_arg
# Pytorch Required Methods # — — — — — — — — — — — — — — —
def __len__(self):
"""Return an integer representing the total number of
examples in your data set"""
return len(self.my_list_of_examples)
def __getitem__(self, idx):
"""Return a single sample at index <idx>. The sample is any
kind of Python object you want. It could be a numpy array.
It could be a dictionary with strings for keys and
numpy arrays for values. It could be a list — really
whatever you want."""
return self._a_custom_method(self.my_list_of_examples[idx])
# Whatever Custom Stuff You Want # — — — — — — — — — — — -
def _a_custom_method(self, example_name):
#processing step 1
#processing step 2
#etc.
return processed_example
对数据集的唯一要求是它定义了 len 和 getitem 方法。
len 方法必须返回数据集中示例的总数。
getitem 方法必须返回基于整数索引的单个示例。
你实际上如何准备例子和例子是什么完全取决于你。
一旦创建了数据集,就需要将该数据集包装在 Pytorch 的数据加载器中,如下所示:
from torch.utils.data import Dataset, DataLoaderdataset_train = MyComplicatedCustomDataset(**dataset_args)train_dataloader = DataLoader(dataset_train, batch_size=256, shuffle=True, num_workers = 4)
为了获得批处理,您只需遍历数据加载器:
for batch_idx, batch in enumerate(train_dataloader): do stuff
如果希望加快数据加载,可以使用多个工作线程。请注意,在对 DataLoader 的调用中,您指定了一些工作线程:
train_dataloader = DataLoader(dataset_train, batch_size=256, shuffle=True, **num_workers = 4**)
默认情况下,num_workers 设置为 0。将 num_workers 设置为正整数将启用多进程数据加载,在这种情况下,将使用指定数量的加载器工作进程来加载数据。(注意,这并不是真正的多 GPU,因为这些加载器工作进程是 CPU 上的不同进程,但是因为它与加速模型训练有关,所以我决定将它放在同一篇文章中)。
请注意,工作进程越多并不总是越好。如果将 num_workers 设置得太高,实际上会降低数据加载速度。关于如何选择最佳工人数量,也没有很大的规则。网上有很多关于它的讨论(例如这里的),但没有结论性的答案。关于如何选择工作人员的数量,没有什么很好的规则,原因是最佳的工作人员数量取决于您正在使用的机器类型、您正在使用的数据集类型以及您的数据需要多少即时预处理。
选择工人数量的一个好方法是在数据集上运行一些小实验,在这些实验中,您计算使用不同数量的工人加载固定数量的示例需要多长时间。随着 num_workers 从 0 开始增加,您将首先看到数据加载速度的增加,随后当您遇到“太多 workers”时,数据加载速度将会降低
有关更多信息,请参见本页的中的“多进程数据加载”。
模型并行和数据并行同时进行
如果您想同时使用模型并行和数据并行,那么数据并行必须以稍微不同的方式实现,使用 DistributedDataParallel 而不是 DataParallel。更多信息,请参见“分布式数据并行入门”
对可用设备子集的培训
如果您想使用模型并行性或数据并行性,但不想占用单个模型的所有可用设备,该怎么办?在这种情况下,您可以限制 Pytorch 可以看到每个型号的哪些设备。在您的代码中,您将设置设备,好像您想要使用所有的 GPU(即使用 device = torch.device('cuda ')),但是当您运行代码时,您将限制哪些 GPU 可以被看到。
假设您有 6 个 GPU,您想在其中的 2 个上训练模型 A,在其中的 4 个上训练模型 B。您可以这样做:
CUDA_VISIBLE_DEVICES=0,1 python model_A.pyCUDA_VISIBLE_DEVICES=2,3,4,5 python model_B.py
或者,如果您有 3 个 GPU,并且希望在其中一个上训练模型 A,在其中两个上训练模型 B,您可以这样做:
CUDA_VISIBLE_DEVICES=1 python model_A.pyCUDA_VISIBLE_DEVICES=0,2 python model_B.py
多 GPU 训练快乐!
原载于 2020 年 3 月 4 日 http://glassboxmedicine.com**的 。
使用词袋和 TF-IDF 的多标签分类
该项目遵循传统技术,如单词袋和 tf-idf,以数字格式表示语料库中的单词,用于多标签分类。
Wordcloud 摘录自 Jigsaw 有毒评论。免责声明:该数据集包含被视为亵渎、粗俗或冒犯的文本。文章最后给出了构建这个词云的代码。
1.加载数据
在这项研究中,我们使用 Kaggle 数据进行有毒评论分类挑战。让我们加载并检查数据。这是一个多标签分类问题,其中注释按照毒性级别进行分类:toxic / severe_toxic / obscene / threat / insult / identity_hate
import pandas as pd
data = pd.read_csv('train.csv')
print('Shape of the data: ', data.shape)
data.head()
数据集的快照
y_cols = list(data.columns[2:])
is_multilabel = (data[y_cols].sum(axis=1) >1).count()
print('is_multilabel count: ', is_multilabel)
- 从上面的数据可以观察到,并不是所有的评论都有标签。
- 其次,它是多标签数据,意味着每个评论可以有一个或多个标签。
首先,让我们为没有标签的评论添加一个标签“无毒”。此外,探索如何平衡的类。
# Add a label, ‘non_toxic’ for comments with no label
data['non_toxic'] = 1-data[y_cols].max(axis=1)
y_cols += ['non_toxic']# Inspect the class balance
def get_class_weight(data):
class_weight = {}
for num,col in enumerate(y_cols):
if num not in class_weight:
class_weight[col] = round((data[data[col] == 1][col].sum())/data.shape[0]*100,2)
return class_weight
class_weight = get_class_weight(data)print('Total class weight: ', sum(class_weight.values()), '%\n\n', class_weight)
我们可以看到数据是高度不平衡的。不平衡数据指的是分类问题,例如,89%的评论被归类到新建的“无毒”标签下。
任何给定的线性模型如果使用平方损失进行二进制分类,将会非常糟糕地处理类别不平衡。在这个项目中,我们将不讨论解决不平衡问题的技术。如果你想了解更多关于处理不平衡数据的知识,请参考这篇博客。
让我们在使用 BoW(单词包)和 tf-idf(术语频率和逆文档频率)将文本数据转换为数字数据之前,重点关注预处理。
2.将数据集分为训练、验证和测试
from sklearn.model_selection import train_test_splitX, X_test, y, y_test = train_test_split(X_data, y_data, test_size=0.2, train_size=0.8)
X_train, X_val, y_train, y_val = train_test_split(X,y,test_size = 0.25,train_size =0.75)X_train[:1]
让我们仔细看看其中一条评论。请注意,由于数据集是随机分割的,因此文本会因您而异。如果你的目标是复制结果,请在分割中使用种子。
3.预处理文本
从上面的例子中,我们可以看到,文本需要预处理,即将其转换为相同的大小写(小写),在将文本转换为标记之前,删除符号、数字和停用词。为了预处理文本,您需要下载特定的库。
import re
import numpy as n
import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
nltk.download('punkt')
要点学分: Coursera
预处理文本
4.将文本转换为矢量
对于机器学习模型,文本数据必须转换为数字数据。这可以通过各种方式实现,如 BoW、tf-idf、单词嵌入等。在这个项目中,我们将关注 BoW 和 tf-idf。
词汇袋
在 BoW 模型中,一个文本(如一个句子或一个文档)被表示为其单词的包(多集合),不考虑语法甚至词序,但保持多样性。
-通过排名建立一个前 N 个流行词的字典。
BoW 表示两个评论,“hello world”和“How are you”
我们将把自己限制在 N 个流行词,以限制矩阵的大小。而且包含冷门词只会引入稀疏,不会增加太多信息。对于这个项目,让我们用 10000 个流行词。
# Lets take a look at top 10 popular words
POPULAR_WORDS[:10]
-建造船首
对于语料库中的每个评论,创建具有 N 维的零向量,并且对于在评论中找到的单词,将向量中的值增加 1,例如,如果一个单词出现两次,则向量中的索引将得到 2。
为了有效存储,我们将把这个向量转换成一个稀疏向量,一个利用稀疏性并且实际上只存储非零条目的向量。
from scipy import sparse as sp_sparse
TF-IDF
在信息检索中,TF–IDF或 TFIDF ,是词频-逆文档频率的简称,是一种数值统计,意在反映一个词对集合或语料库中的文档有多重要。
这种方法是单词袋的扩展,其中单词的总频率除以文档中的总单词数。这通过在整个文档中规范化过于频繁的单词来惩罚它们。
from sklearn.feature_extraction.text import TfidfVectorizer
5.多标签分类
我们使用两种不同的技术 BoW 和 tf-idf 准备了数据集。我们可以在两个数据集上运行分类器。由于这是一个多标签分类问题,我们将使用一个简单的 OneVsRestClassfier 逻辑回归。
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression
你可以尝试不同的正则化技术,L1 和 L2 与不同的系数(例如,C 等于 0.1,1,10,100),直到你满意的结果,这被称为超参数调整。这可以通过 cv 网格搜索、随机搜索和贝叶斯优化来实现。我们不打算在本文中讨论这个话题。如果你想了解更多这方面的信息,请参考这个帖子。
6.估价
我们将使用准确性分数和 f1 分数等指标进行评估。
- 准确度分数:在多标签分类中,该函数计算子集准确度:为样本预测的标签集必须与 y_true 中的相应标签集完全匹配。
- F1 分数:F1 分数可以解释为精确度和召回率的加权平均值,其中 F1 分数在 1 时达到其最佳值,在 0 时达到其最差分数。精确度和召回率对 F1 分数的相对贡献是相等的。F1 得分= 2 (精确度召回率)/(精确度+召回率)
'F1 score micro'
:通过计算总的真阳性、假阴性和假阳性来计算全局指标。
'F1 score macro'
:计算每个标签的指标,求其未加权平均值。这没有考虑标签不平衡。
'F1 score weighted'
:计算每个标签的度量,并根据支持度(每个标签真实实例的数量)计算它们的平均值。这改变了“宏”以解决标签不平衡;它会导致 F 值不在精确度和召回率之间。
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_auc_score
from sklearn.metrics import average_precision_score
from sklearn.metrics import recall_score
F1 分数加权和说明数据不平衡的宏看起来不错。让我们检查输出、预测标签和实际标签。我们需要用实际的标签替换一次性编码的标签来进行解释。接下来让我们对 tf-idf 模型进行预测。
test_predictions = classifier_tfidf.predict(X_test_tfidf)
for i in range(90,97):
print('\ny_label: ', test_labels[i], '\ny_pred: ', test_pred_labels[i])print('\ny_label: ', test_labels[i], '\ny_pred: ', test_pred_labels[i])
成绩不算太差,但还可以做得更好。请尝试使用超参数调整和不同的分类器来检查模型的性能。希望你喜欢阅读。
如果你感兴趣,我留下了构建单词云图像的代码。
带 Twitter 掩码的词云
comments_join = ' '.join(POPULAR_WORDS)from scipy.misc import imread
from wordcloud import WordCloud, STOPWORDStwitter_mask = imread('twitter.png', flatten=True)
wordcloud = WordCloud(
stopwords=STOPWORDS,
background_color='white',
width=1800,
height=1400,
mask=twitter_mask
).generate(comments_join)plt.figure(figsize = (12, 12), facecolor = None)
plt.imshow(wordcloud)
plt.axis("off")
plt.savefig('twitter_comments.png', dpi=300)
plt.show()
带代码的 jupyter 笔记本,请点击此处。
参考资料:
https://www.coursera.org/learn/language-processing/home
使用 Vowpal Wabbit 的多标签分类:从为什么到如何!
如何制定多标签分类任务并使用 Vowpal Wabbit 求解
什么是多标签分类?
想想你最近读的一篇文章/推文,如果你被要求标记它!
大概你会想出科技、政治、时尚等标签。考虑这条推文,自己尝试一下。
来源:https://twitter.com/orangebook_
它可以被标上自助,沉思,凌晨 3 点的想法!和许多其他人。不能说其中有一个是最好的。他们每个人都是对的,你只需要一个视角!
一个标签可能比其他的更合适,但是你不能只有一个标签。我们稍后将回到这个话题。
现在这样的问题在我们的生活中经常出现,更多的例子有:
- 根据图像的内容给图像加标签:(天空、房子、草地)
- 电影的类型分类:(动作、冒险、犯罪)
- 标记堆栈溢出中提出的问题。
那么多类和多标签分类有什么区别呢?
当有多个类别,但每个实例只分配了其中一个类别,或者类别是互斥的,这就是多类别分类。
当每个实例可以被分配多个类别或者类别彼此相关时,这就是多标签分类。
解决多标签分类问题的标准实践
Scikit-Learn 为多标签分类提供了单独的库 Scikit-Multilabel 。我不会深入本库提供的标准算法的细节,因为那样会分散我对博客目标的注意力。
您可以看看下面的文章来方便地使用这个库:
- https://www . analyticsvidhya . com/blog/2017/08/introduction-to-multi-label-class ification/
- http://scikit.ml/multilabeldnn.html基于 DL 的多标签分类
- https://towards data science . com/journey-to-the-center-of-multi-label-class ification-384 c 40229 BFF
什么是 Vowpal Wabbit,为什么我们需要它?
它是由微软研究院(之前由雅虎公司)开发的一个库,用于解决机器学习问题。
Vowpal Wabbit 提供了一种快速、灵活、在线和主动的学习解决方案,使您能够解决复杂的交互式机器学习问题。
从我的经历来看,这个图书馆与众不同的两点是速度和在线学习。
在计算机科学中,在线机器学习是一种机器学习方法,其中数据以连续的顺序变得可用,并用于在每一步更新我们对未来数据的最佳预测,这与批量学习技术相反,批量学习技术通过一次性学习整个训练数据集来生成最佳预测。
让我们深入研究我们的问题
为了更好地理解 Vowpal Wabbit 和多标签分类,让我们解决将标签分配给简短文本描述的问题。
我们将使用来自极限分类库的 Bibtex 数据集,该分类库为单个文本提供了 1836 个二进制特征和 159 个可能的标签。
使用 Vowpal Wabbit 的多标签分类代码
为了获得更广泛的视图,你可以前往 Github 链接。
正如你可能已经看到的,只要对每个例子迭代一次,也是以在线的方式和极快的速度,模型收敛到很好的精度。
让我们了解一下这里使用的算法(请在继续下一步之前阅读代码)。
成本敏感的多类分类
这里,不是只有一个正确的标签(而所有其他的都不正确),而是 K 个不同标签中的每一个都有不同的成本。对于每个例子,你也可以有不同的“允许”标签。与上述相同的成本敏感训练集是:
1\. 1:0 2:1 3:1 4:1 | a b c
2\. 1:1 2:1 3:0 4:1 | b c d
第一行意味着标签 1 的成本为零,标签 2、3 和 4 的成本都为一。“a、b、c”是与示例相关联的二元特征。你可以只陈述存在的特征,而忽略不存在的特征。
在内部, csoaa 做了一些与你想象不同的事情。这个问题归结为回归问题。如果有 K 个可能的标签,它将构建 K 个回归问题,其中输入是要素的(基于标签的)版本,输出是该标签的成本。
然后在测试时,选择回归量给出最低值(预测成本)的标签。
这篇博客的目的不是寻找提高准确率的方法,而是介绍这个不同的机器学习世界(多标签分类)以及如何有效地使用 Vowpal Wabbit 来解决这个问题。
在上述解决方案中有许多可能的修改/改进,例如:改变损失函数、通过数据的次数、优化策略、改变每个标签的成本等。
要了解更多信息,您可以点击下面的链接:
- http://users.umiacs.umd.edu/~hal/tmp/multiclassVW.html
- https://github . com/VowpalWabbit/vowpal _ wabbit/wiki/Cost-Sensitive-One-again-All-(csoaa)-multi-class-example
- http://manikvarma.org/downloads/XC/XMLRepository.html
- https://vail lab . blogspot . com/2014/06/mutlti-label-class ification-using . html
*如有任何疑问或建议,欢迎随时 ping 我*😃。还有,在Twitter和Linkedin上找我。再见!!
使用 BERT、Transformers 和 Keras 的多标签、多类别文本分类
在本文中,我将展示如何使用 Huggingface Transformers 库和 Tensorflow Keras API 完成多标签、多类别的文本分类任务。这样,您将了解如何使用 Transformer 中的 BERT 模型作为使用 Keras API 构建的 Tensorflow 模型中的一个层。
使用 BERT、Transformers 和 Keras 的多标签、多类别文本分类
互联网上充满了文本分类的文章,其中大多数是 BoW 模型与某种 ML 模型的结合,通常解决二进制文本分类问题。随着 NLP 的兴起,特别是 BERT(如果你不熟悉 BERT,请看这里的)和其他基于多语言转换器的模型,越来越多的文本分类问题现在可以得到解决。
然而,当涉及到使用 Huggingface Transformers 、 BERT 和 Tensorflow Keras 解决多标签、多类别文本分类问题时,文章的数量确实非常有限,就我个人而言,我还没有找到任何…还没有!
因此,在大量与 BERT、Keras 中的多标签分类或其他有用信息相关的博客帖子、教程和 GitHub 代码片段的帮助和启发下,我将向您展示如何构建一个工作模型,解决这个问题。
为什么使用拥抱脸变形金刚而不是谷歌自己的 BERT 解决方案?因为使用变压器很容易在不同型号之间切换,如伯特、阿尔伯特、XLnet、GPT-2 等。这意味着,您或多或少地“只是”在代码中用一个模型替换另一个模型。
从哪里开始
用数据。在寻找可以用于多标签多类别文本分类任务的文本数据时,我偶然发现了来自 data.gov 的“消费者投诉数据库】。看起来很管用,所以我们就用这个。
接下来是探索性数据分析。显然,这对于正确理解数据的样子、可能存在的缺陷、数据的质量等等至关重要。但是我现在跳过这一步,只是因为这篇文章的目的纯粹是如何建立一个模型。
如果你不喜欢四处搜索,可以看看这两篇关于这个主题的文章: NLP 第 3 部分|文本数据的探索性数据分析和一个完整的文本数据的探索性数据分析和可视化。
继续吧
我们有了数据,现在是编码部分。
首先,我们将加载所需的库。
#######################################
### -------- Load libraries ------- #### Load Huggingface transformers
from transformers import TFBertModel, BertConfig, BertTokenizerFast# Then what you need from tensorflow.keras
from tensorflow.keras.layers import Input, Dropout, Dense
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.initializers import TruncatedNormal
from tensorflow.keras.losses import CategoricalCrossentropy
from tensorflow.keras.metrics import CategoricalAccuracy
from tensorflow.keras.utils import to_categorical# And pandas for data import + sklearn because you allways need sklearn
import pandas as pd
from sklearn.model_selection import train_test_split
然后,我们将导入我们的数据,并围绕它展开讨论,使其符合我们的需求。没什么特别的。请注意,我们将仅使用数据集中的“消费者投诉叙述”、“产品”和“问题”列。“消费者投诉叙述”将作为我们模型的输入,“产品”和“问题”将作为我们的两个输出。
#######################################
### --------- Import data --------- #### Import data from csv
data = pd.read_csv('dev/Fun with BERT/complaints.csv')# Select required columns
data = data[['Consumer complaint narrative', 'Product', 'Issue']]# Remove a row if any of the three remaining columns are missing
data = data.dropna()# Remove rows, where the label is present only ones (can't be split)
data = data.groupby('Issue').filter(lambda x : len(x) > 1)
data = data.groupby('Product').filter(lambda x : len(x) > 1)# Set your model output as categorical and save in new label col
data['Issue_label'] = pd.Categorical(data['Issue'])
data['Product_label'] = pd.Categorical(data['Product'])# Transform your output to numeric
data['Issue'] = data['Issue_label'].cat.codes
data['Product'] = data['Product_label'].cat.codes# Split into train and test - stratify over Issue
data, data_test = train_test_split(data, test_size = 0.2, stratify = data[['Issue']])
接下来,我们将加载一些不同的变压器类。
#######################################
### --------- Setup BERT ---------- #### Name of the BERT model to use
model_name = 'bert-base-uncased'# Max length of tokens
max_length = 100# Load transformers config and set output_hidden_states to False
config = BertConfig.from_pretrained(model_name)
config.output_hidden_states = False# Load BERT tokenizer
tokenizer = BertTokenizerFast.from_pretrained(pretrained_model_name_or_path = model_name, config = config)# Load the Transformers BERT model
transformer_model = TFBertModel.from_pretrained(model_name, config = config)
在这里,我们首先加载一个控制模型、记号赋予器等的 BERT 配置对象。
然后,我们将在稍后的脚本中使用一个记号赋予器,将我们的文本输入转换成 BERT 记号,然后填充并截断到我们的最大长度。记号赋予器已经被很好地记录了,所以我不会在这里深入讨论。
最后,我们将加载 BERT 模型本身作为 BERT Transformers TF 2.0 Keras 模型(这里我们使用12 层 bert-base-uncased )。
现在是有趣的部分
我们准备好建立我们的模型。在变形金刚库中,有许多不同的 BERT 分类模型可以使用。所有模型的母亲是简单地称为“BertModel”(py torch)或“TFBertModel”(tensor flow)的模型,因此也是我们想要的模型。
Transformers 库还附带了一个预构建的用于序列分类的 BERT 模型,称为“TFBertForSequenceClassification”。如果你看一下这里的代码你会发现,他们从加载一个干净的 BERT 模型开始,然后简单地添加一个漏失层和一个密集层。因此,我们要做的只是简单地添加两个密集层,而不是只有一个。
这是我们模型的样子:
基于 BERT、Transformer 和 Keras 模型的多标签多类别文本分类
更详细的模型视图:
Model: "BERT_MultiLabel_MultiClass"
___________________________________________________________________
Layer (type) Output Shape Param # Connected to
===================================================================
input_ids [(None, 100)] 0
(InputLayer)
___________________________________________________________________
bert ( 109482240 input_ids[0][0]
(TFBertMainLayer) (None, 100, 768),
(None, 768)
)
___________________________________________________________________
pooled_output (None, 768) 0 bert[1][1]
(Dropout)
___________________________________________________________________
issue (None, 159) 122271 pooled_output[0][0]
(Dense)
___________________________________________________________________
product (None, 18) 13842 pooled_output[0][0]
(Dense)
===================================================================
Total params: 109,618,353
Trainable params: 109,618,353
Non-trainable params: 0
___________________________________________________________________
如果你想更多地了解 BERTs 建筑本身,看看这里。
现在我们有了模型架构,我们需要做的就是用代码编写它。
#######################################
### ------- Build the model ------- #### TF Keras documentation: [https://www.tensorflow.org/api_docs/python/tf/keras/Model](https://www.tensorflow.org/api_docs/python/tf/keras/Model)# Load the MainLayer
bert = transformer_model.layers[0]# Build your model input
input_ids = Input(shape=(max_length,), name='input_ids', dtype='int32')
inputs = {'input_ids': input_ids}# Load the Transformers BERT model as a layer in a Keras model
bert_model = bert(inputs)[1]
dropout = Dropout(config.hidden_dropout_prob, name='pooled_output')
pooled_output = dropout(bert_model, training=False)# Then build your model output
issue = Dense(units=len(data.Issue_label.value_counts()), kernel_initializer=TruncatedNormal(stddev=config.initializer_range), name='issue')(pooled_output)
product = Dense(units=len(data.Product_label.value_counts()), kernel_initializer=TruncatedNormal(stddev=config.initializer_range), name='product')(pooled_output)
outputs = {'issue': issue, 'product': product}# And combine it all in a model object
model = Model(inputs=inputs, outputs=outputs, name='BERT_MultiLabel_MultiClass')# Take a look at the model
model.summary()
让魔法开始吧
然后剩下要做的就是编译我们的新模型,并根据我们的数据进行拟合。
#######################################
### ------- Train the model ------- #### Set an optimizer
optimizer = Adam(
learning_rate=5e-05,
epsilon=1e-08,
decay=0.01,
clipnorm=1.0)# Set loss and metrics
loss = {'issue': CategoricalCrossentropy(from_logits = True), 'product': CategoricalCrossentropy(from_logits = True)}
metric = {'issue': CategoricalAccuracy('accuracy'), 'product': CategoricalAccuracy('accuracy')}# Compile the model
model.compile(
optimizer = optimizer,
loss = loss,
metrics = metric)# Ready output data for the model
y_issue = to_categorical(data['Issue'])
y_product = to_categorical(data['Product'])# Tokenize the input (takes some time)
x = tokenizer(
text=data['Consumer complaint narrative'].to_list(),
add_special_tokens=True,
max_length=max_length,
truncation=True,
padding=True,
return_tensors='tf',
return_token_type_ids = False,
return_attention_mask = False,
verbose = True)# Fit the model
history = model.fit(
x={'input_ids': x['input_ids']},
y={'issue': y_issue, 'product': y_product},
validation_split=0.2,
batch_size=64,
epochs=10)
一旦模型被拟合,我们就可以根据我们的测试数据对它进行评估,看看它的表现如何。
#######################################
### ----- Evaluate the model ------ #### Ready test data
test_y_issue = to_categorical(data_test['Issue'])
test_y_product = to_categorical(data_test['Product'])
test_x = tokenizer(
text=data_test['Consumer complaint narrative'].to_list(),
add_special_tokens=True,
max_length=max_length,
truncation=True,
padding=True,
return_tensors='tf',
return_token_type_ids = False,
return_attention_mask = False,
verbose = True)# Run evaluation
model_eval = model.evaluate(
x={'input_ids': test_x['input_ids']},
y={'issue': test_y_issue, 'product': test_y_product}
)
事实证明,我们的模型表现得相当好,具有相对较好的准确性。尤其是考虑到我们的输出“产品”由 18 个标签组成,而“问题”由 159 个不同的标签组成。
####################################################################
Classification metrics for Product precision recall f1-score support
Bank account or service 0.63 0.36 0.46 2977
Checking or savings account 0.60 0.75 0.67 4685
Consumer Loan 0.48 0.29 0.36 1876
Credit card 0.56 0.42 0.48 3765
Credit card or prepaid card 0.63 0.71 0.67 8123
Credit reporting 0.64 0.37 0.47 6318
Credit reporting, credit
repair services, or other
personal consumer reports 0.81 0.85 0.83 38529
Debt collection 0.80 0.85 0.82 23848
Money transfer, virtual
currency, or money service 0.59 0.65 0.62 1966
Money transfers 0.50 0.01 0.01 305
Mortgage 0.89 0.93 0.91 13502
Other financial service 0.00 0.00 0.00 60
Payday loan 0.57 0.01 0.02 355
Payday loan, title loan, or
personal loan 0.46 0.40 0.43 1523
Prepaid card 0.82 0.14 0.24 294
Student loan 0.83 0.87 0.85 5332
Vehicle loan or lease 0.49 0.51 0.50 1963
Virtual currency 0.00 0.00 0.00 3 accuracy 0.76 115424
macro avg 0.57 0.45 0.46 115424
weighted avg 0.75 0.76 0.75 115424####################################################################
Classification metrics for Issue (only showing summarized metrics)precision recall f1-score support
accuracy 0.41 115424
macro avg 0.09 0.08 0.06 115424
下一步做什么?
但是,您可以做很多事情来提高这个模型的性能。在这里,我尽量做到简单,但如果您希望获得更好的性能,请考虑以下几点:
- 摆弄优化器中设置的超参数,或者改变优化器本身
- 使用消费者投诉数据库数据训练一个语言模型——要么从头开始,要么通过微调现有的 BERT 模型(在这里看看)。然后加载该模型,而不是这里使用的“bert-base-uncased”。
- 使用多个输入。在我们当前的设置中,我们只使用令牌 id 作为输入。然而,如果我们在输入中加入注意力屏蔽,我们可能会获得一些性能提升。它非常简单,看起来像这样:
# Build your model inputinput_ids = Input(shape=(max_length,), name='input_ids', dtype='int32')attention_mask = Input(shape=(max_length,), name='attention_mask', dtype='int32')inputs = {'input_ids': input_ids, 'attention_mask': attention_mask}
(记得在拟合你的模型时添加 attention_mask,并在你的 tokenizer 中设置 return_attention_mask 为 True。更多关于注意力面具的信息, 看这里 。此外,我在下面的要点中添加了注意力面具,并将其注释掉,以供你的灵感*。)*
- 尝试另一个模型,如艾伯特、罗伯塔、XLM,甚至是自回归模型,如 GPT-2 或 XLNet——所有这些都可以通过 Transformers 库轻松导入到您的框架中。您可以在此处找到所有直接可用型号的概述。
就是这样——希望你喜欢这个如何用 BERT、Transformer 和 Keras 进行“多标签、多类文本分类”的小演示。如果你有任何反馈或问题,请在下面的评论中提出。
多目标车辆路径优化
遵循从完整的基础到先进的路线优化解决方案的学习路径。
作者图片
路线优化是运输规划中最重要的方面之一,因为它确保货物总是准时到达,并以尽可能低的成本和能耗执行。然而,对于现实生活中的场景,我们需要考虑很多变量。
来源:一个路线优化软件能提供什么?
在这个不幸的 COVID 期间,我们要处理来自分散在一个城市、一个国家甚至整个世界的各种客户的大量电子商务订单,然后出现了大量的变量,这些变量根本无法在实际时间内使用传统方法解决。随着人工智能、机器学习和云数据的最新发展,路线优化的整个游戏已经开始改变。人工智能不断检索数据,从中学习,并寻找改进的方法,以确保司机的最佳路线。
在这个系列中,我们将经历一个学习多目标路线优化的奇妙旅程,从线性方法到高级深度强化学习:
1.车辆路径问题及多目标优化
2.遗传算法
3.蚁群优化
4.迭代局部搜索
5.使用 CPLEX-python 的基于 MILP 的方法
6.深度强化学习
在这篇博客中,我们将深入探讨带有一些附加约束的车辆路径问题的详细描述、多目标优化的概念以及本系列将介绍的方法的简要概述。
介绍
V 车辆路径问题(VRP)可以定义为在满足一些约束条件的情况下,寻找从一个或几个仓库到多个客户的最优运送或收集路线的问题。这个问题可以推广到社会垃圾的收集、汽油运输车、货物和邮件的运送等,应用是无限的。
来源:为什么要进行路线优化?
车辆路径问题
在传统的 VRP 中,顾客和仓库的位置是预先知道的,这有助于我们在上述路线中确定路线。为了简化问题的定义,让我们考虑一个图 G=(V,A) ,其中 V={1……n} 是一组顶点(客户),仓库位于顶点 1,而 A 是一组弧线(路线)。除此之外,我们假设停车场有一定数量的可用车辆,并为每辆车分配初始成本。这些车辆通过以下方式覆盖客户之间的路线:
(I)每个城市只被一辆车访问一次
(ii)所有车辆路线的起点和终点都在停车场
来源:上述配方的图示
然而,平心而论,上述问题虽然包括几个变量和指令,但仍然缺乏直接应用于任何地方的现实感,因此我们转向一种更一般化形式的 VRP,称为车辆路线安排和调度问题或 VRPTW (带时间窗的车辆路线安排问题)。我们的目标是优化车队的使用,车队必须多次停车为一组客户提供服务,并指定每辆车应该为哪些客户提供服务以及以何种顺序提供服务,以使成本最小化,同时遵守车辆容量和服务时间限制。
因此,上述定义可以修改为有向图 G=(V,E) ,由一组 n 个客户+ 1 个仓库组成,每个客户只能在指定的时间间隔或时间窗口内到达,以及一组具有非负权重的弧 E 代表行程距离。每辆车的最大载客量为 Q,所有客户的请求服务规模为 qi
多目标方法
在确定问题之后,现在的任务是优化车辆行驶的路线,以获得最低的成本。然而,在我们开始之前,让我们先熟悉一下多目标优化的概念。这是一个多准则决策的领域,涉及数学优化问题,涉及一个以上的目标函数同时优化。它主要用于当我们的目标相互冲突,并且最优决策位于它们的折衷之间时。与单目标相比,多目标优化的另一个结果是我们获得一组最优解,而不是单个解,所有这些融合在一起,使多目标方法更适合现实世界的情况。
作者图片:多目标优化是必要的!
我们将在场景中考虑的目标是分配给任务的车辆数量和穿越路线所需的总成本。时间延迟将在成本函数中用额外的延迟成本来处理。上图将整个过程概括为两个部分,即初始随机解的生成,将这些随机解收敛以获得一组非支配解。重复这个过程,直到获得帕累托最优集合。
作者的图像:多目标解决方案的表示
各种方法概述
乍看之下,VRP 似乎并不难解决,因为人们总是可以通过确定所有可能的路线并选择最便宜的路线来遵循蛮力方法来解决问题。那么这种方法有什么问题呢?原来这个过程叫做枚举,只对非常小的问题可行。据报道,VRP 是一个 NP-hard 问题,这意味着求解时间随着规模的增加而呈天文数字增长。对于 VRP 来说,可能的解决方案有 n 个!,这种阶乘的增长是时间的巨大增长的原因。下表显示了每秒处理十亿次计算的计算机求解 VRP 的预计时间。
作者图片
大多数现实世界的问题涉及大量的客户,因此我们需要转向其他方法,比如元启发式方法来解决问题。这些都是从*‘启发式’和‘元’——一个更高层次或更高层次的意思中衍生出来的。*这些方法在生成随机化和局部搜索之间进行权衡。解决方案的质量在更短的时间内得到保证。此外,也不能保证这种方法会给我们提供一个最优解。元启发式算法的两个主要组成部分是探索和利用。前者处理不同解的生成,以在全局范围内探索搜索空间,而后者负责搜索局部区域,知道该区域中存在好的解。在这两者之间找到一个好的平衡会导致一个好的算法收敛,并给出最接近全局最优的解
作者图片:这里使用的元启发式方法
另一种可以解决这个 NP 难题的方法是强化学习。近来,这个领域有了巨大的发展,尤其是在 Deepmind 通过 AlphaZero 计划取得成功之后。一个通用的 RL 模型由三个主要部分组成,即:- 状态、主体和环境。该模型使用一系列的奖励和惩罚作为在特定环境中给定状态下主体所采取行动的积极或消极行为的信号。代理人的主要目标是最大化总的累积报酬。下图说明了 RL 模型的动作反馈回路:
来源:通用 RL 模型
资料组
整个教程是使用 Solomon 数据集进行的,它由三种不同的客户分布组成;
(一)随机化或 R 型
来源:红点代表单个车厂,其他为客户
客户随机分布在整个城市,车辆从仓库出发。这相当于在一个城市中的不同商店需要交付货物。
(二)集群或 C 型
来源:红点代表单个仓库,其他为客户
这是一个有趣的案例,其中特定的数据群随机分布在整个城市中,就像城市中有组织的地区和社会,用于送货上门或垃圾收集等基本服务。
(iii)随机和群集或 RC 类型。
来源:红点代表单个仓库,其他为客户
这种特殊类型是上述两种方法的组合,其中地理位置以聚类和随机的形式分布。
根据它们的时间窗口的长度,它们被进一步分成两个子类别:短调度和长调度
摘要
在详细描述了我们在 VRP 问题上所面临的问题,并简要概述了本系列将采用的方法之后,我们将进入本系列的下一部分,深入讨论我们的第一个元启发式方法:遗传算法。在这里,我们将详细阐述应用框架的细节,并详细解释选择、变异和交叉的各个步骤。
真诚感谢萨纳特·K、斯巴纳·拉纳和拉维·兰詹对这个项目的指导,特别感谢拉维·兰詹在这个系列中的灵感。
多视角神经网络——一种无监督的深度度量学习算法
一种学习生成嵌入的无监督深度度量学习算法。
链接: 演示视频 & Github 资源库
想象你是一个刚刚睁开眼睛看世界的婴儿。想象一下缺乏意识,想象一下什么都不知道。你连怎么看东西都不知道,更别说怎么识别东西了。现在,回到你的意识中来。你可以看到,你可以认出你周围的任何物体,这些物体甚至会让你想起你的记忆。
克里斯蒂安·鲍文在 Unsplash 上拍摄的照片
但是,你是如何获得这些技能的呢?这是多视角神经网络(MPNN)的起点。
在我之前的文章中,我已经谈到了一种无监督学习算法,它可以学习创建有意义的特征作为输出的过滤器。帖子链接:无监督学习的学习过滤器。这篇文章是上一篇文章的延续。在这篇文章中将有三个部分,如逻辑和哲学,代码,测试。
逻辑和哲学
由 sergio souza 在 Unsplash 上拍摄的照片
该算法基本上学会了将卷积层的输出彼此分解。当我们对图像应用卷积运算时,我们得到 NxRxC 矩阵,其中 N 是滤波器的数量,R 和 C 是行大小和列大小。在 MPNNs 中,卷积运算的输出中的 N 个层试图彼此分解。当最大相似性值低于预定阈值时,该级别的学习过程完成。之后,对下一级重复这一过程。最后,神经网络生成具有有意义特征的嵌入。
显示分解管道的图表(按作者)
我开始思考这次行动的哲学。我想到了与这个层分解操作相匹配的概念。我一直在寻找的概念是 视角。 人类试图学会用不同的视角看待事件、物体和其他一切,以便他们能够分析正在发生的事情。这不仅发生在高级抽象中,也发生在低级学习中。MPNN 试图做的是将这种视角生成应用于视觉中的低级学习过程。
密码
我在以前的帖子中分享了代码。但是,我已经做了一些改变,所以我想在这个帖子里再次分享。完整的代码仍然可以在的 GitHub 库中找到。
一个单独的卷积图层类。
class ConvLayer(torch.nn.Module):
def __init__(self, in_channels, out_channels, kernel_size, stride):
super(ConvLayer, self).__init__()
self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride)def forward(self, x):
out = self.conv2d(x)
return out
一个单一的卷积级类。级别是分解发生的地方。
class SSNet(torch.nn.Module):
def __init__(self,in_filters, out_filters):
super(SSNet, self).__init__()
self.conv1 = ConvLayer(in_filters, 64, kernel_size = 5, stride = 1)
self.conv2 = ConvLayer(64, out_filters, kernel_size = 1, stride = 1)
self.pool = nn.AvgPool2d(2, stride=2)
self.relu = torch.nn.ReLU()
def forward(self, x):
out = self.pool(self.conv2(self.relu(self.conv1(x))))
return out
包含几级 SSNet 类的 MPNN 类。
class SSNetMultiple(torch.nn.Module):
def __init__(self,levels = 5):
super(SSNetMultiple, self).__init__()
self.children = []
for cnt in range(levels):
if cnt == 0:
in_filters, out_filters = 3,16
elif cnt == levels-1:
in_filters, out_filters = 16,16
else:
in_filters, out_filters = 16,16
self.children.append(SSNet(in_filters, out_filters))
self.main = nn.Sequential(*self.children)
def forward(self, x, queue = 1):
outs = [x]
for cnt,child in enumerate(self.main):
if cnt<queue:
outs.append(child(outs[-1]))
return outs[-1]
规范化操作。如果我们想要获得相似性值 1 作为最大相似性,归一化是必要的。
def normalize(vector):
norm = vector.norm(p=2, dim=0, keepdim=True)
vector_normalized = vector.div(norm.expand_as(vector))
return vector_normalized
相似性函数用于提取和组合层的相似性,以便我们可以计算损失。
def sim_func(layers):
combinations = list(itertools.combinations(np.arange(0,layers.shape[1]), 2))
similarity_vector = torch.empty(len(combinations))
for cnt,comb in enumerate(combinations):
first = layers[0][comb[0]].flatten()
second = layers[0][comb[1]].flatten()
first_norm = normalize(first)
second_norm = normalize(second)
similarity_vector[cnt] = torch.matmul(first_norm,second_norm.T)
return similarity_vector
用分解层数定义 MPNN 实例。
model = SSNetMultiple(levels = 4)
对于数据集,我在上一篇文章中使用了 MNIST。这一次,我们将使用从 YouTube 下载的视频。
视频可在链接中找到:西班牙伊比沙岛的诱惑
为了从视频中捕捉帧,我使用了 OpenCV。我们需要捕捉帧,应用中心裁剪,调整大小,并转换到 PyTorch 张量。
def cam_to_tensor(cam):
if cam.isOpened():
ret, frame_ = cam.read()
else:
cam.release()
cam = cv2.VideoCapture(video_source)
ret, frame_ = cam.read()
frame = cv2.cvtColor(frame_, cv2.COLOR_BGR2RGB)
frame_pil = Image.fromarray(frame)
image = transform(frame_pil)
return image, frame_, camtransform=transforms.Compose([
transforms.CenterCrop((360,360)),
transforms.Resize((224,224)),
transforms.ToTensor()
])
现在,所有的训练脚本。对于评论行,请检查我在以前的职位解释。链接可以在这篇文章的顶部找到。
首先,我们从视频中捕捉一帧。然后,我们准备好要提供给模型的帧。之后,模型训练分解的第一级。当最大相似值低于 0.3 时,我们开始训练下一级,以此类推。别忘了,视频中捕捉到的画面是城市旅游的场景。
lr = 0.02
optimizer = optim.SGD(model.parameters(), lr=lr)
lossfunc = nn.MSELoss()video_source = "./videoplayback.mp4"
cam = cv2.VideoCapture(video_source)loss_obs = 0
epoch = 0while epoch<4:
# if epoch>0:
# for cc,param in enumerate(model.main[epoch-1].parameters()):
# print(epoch-1,"grad is deactivated")
# param.requires_grad = True
for cnt in range(0,120000):
image, _, cam = cam_to_tensor(cam)
optimizer.zero_grad()
out = model(image.unsqueeze(0), queue = epoch+1)
sim_vec = sim_func(out)
loss = lossfunc(sim_vec, torch.zeros(sim_vec.shape))
loss_obs_ = torch.max(torch.abs(sim_vec-torch.zeros(sim_vec.shape)))
loss_obs += loss_obs_
loss.backward()
optimizer.step()
print("Epoch: {}\tSample: {}\tLoss: {}\tLR: {}".format(epoch,cnt,loss_obs_,optimizer.param_groups[0]["lr"]))if cnt%20 == 0 and cnt!=0:
loss_obs = loss_obs/20
print("Epoch: {}\tSample: {}\tLoss: {}\tLR: {}".format(epoch,cnt,loss_obs,optimizer.param_groups[0]["lr"]))
if loss_obs<0.30:
epoch += 1
break
loss_obs = 0
试验
我们的模特学会了欣赏城市风景。我们如何观察它学到了什么?我们可以捕捉随机帧,并将这些帧与后面的帧进行比较。通过这样做,我们可以观察帧的相似性值,并看到帧中每个场景出现的效果。例如:如果有一个特定的对象,如人、窗户等。在锚定帧中,并且如果在随后的帧中存在该对象,即使场景已经改变,并且如果相似性值有点高,那么我们理解模型可以提取特征来帮助它识别场景中的该对象。
def generate_embedding(model,cam,queue = 3):
image, frame, _ = cam_to_tensor(cam)
embedding = model(image.unsqueeze(0), queue = queue).flatten()
return embedding, framedef compare_samples(e1,e2):
first_norm = normalize(e1.flatten())
second_norm = normalize(e2.flatten())
return torch.matmul(first_norm,second_norm.T).detach().numpy()embedding_list = []
def compare_continuous(model,cam,queue):
min_sim = 1
max_diff = 0
font = cv2.FONT_HERSHEY_SIMPLEX
bottomLeftCornerOfText = (10,100)
fontScale = 1
fontColor = (255,255,255)
lineType = 2
last_sim_list = []
cnt_f = 0
while True:
if cnt_f%300==0:
e1, f1 = generate_embedding(model,cam,queue = queue)
cv2.imshow('frame 1', f1)
e2, f2 = generate_embedding(model,cam,queue = queue)
embedding_list.append(e2.detach().numpy())
embedding_list_np = np.array(embedding_list)
std = np.std(embedding_list_np, axis=0)
pca_idx = std.argsort()[-64:][::-1]
e1_pca = e1[pca_idx.tolist()]
e2_pca = e2[pca_idx.tolist()]
sim = compare_samples(e1_pca,e2_pca)
print(sim)
cv2.putText(f2,'Similarity: {}'.format(sim),
bottomLeftCornerOfText,
font,
fontScale,
fontColor,
lineType)
cv2.imshow('frame 2', f2)
if cv2.waitKey(25) & 0xFF == ord('q'):
break
cnt_f += 1
还有播放按钮。
compare_continuous(model,cam,queue=5)
演示视频可以在链接中找到。
Keras 中的多样本丢失
加速训练和更好地推广你的神经网络
安布尔·沃尔夫在 Unsplash 上拍摄的照片
Dropout 是一种有效的正则化工具,用于避免深度神经网络的过拟合。它的工作非常简单,在训练过程中随机丢弃一部分神经元;结果,泛化发生了,因为以这种方式神经元不再相互依赖。Dropout 很容易适用于每一个神经网络结构,它也可以用于各种目的:例如,我在的前一篇文章中用它来估计神经网络的不确定性。
在这篇文章中,我试图重现在这篇文章中的结果;引入了一种叫做多样本丢失的技术。正如作者所声明的,其范围是:
- 加快培训,提高对原有辍学学生的概括能力;
- 降低计算成本,因为大部分计算时间消耗在下面的层中(通常是卷积的或递归的),并且共享顶部层中的权重;
- 实现更低的错误率和损失。
数据
我想在一个 NLP 问题中应用论文中介绍的程序。我在 Kaggle 上发现了一个有价值的数据集。提供了新闻标题数据集来进行句子中的讽刺检测。这个数据集中的文本是从网上收集的,带有讽刺或不讽刺的相关注释。
标签分发
模型
我选择 NLP 任务是因为它允许我们用一致的训练时间来尝试一个循环的模型结构。此外,在网络末端附近使用 dropout 和全连接层使得执行时间不显著。
基本想法很简单:创建多个漏失样本,而不是只有一个,如下图所示。对于每个漏失样本,重复漏失层和漏失之后的几个层。“dropout”、“fully connected”和“softmax + loss func”层被复制。不同的掩模用于漏失层中的每个漏失样本,使得不同的神经元子集用于每个漏失样本。相反,参数(即,连接权重)在复制的完全连接的层之间共享。使用相同的损失函数(例如交叉熵)为每个丢失样本计算损失,并且通过对所有丢失样本的损失值求平均来获得最终损失值。该最终损失值用作训练期间优化的目标函数。将最后一个完全连接的层的输出平均值中具有最高值的类标签作为预测。
原始漏失与多样本漏失(来源)
在 Keras 语言中,所有的概念都可以用简单的代码实现:
def get_model(num):inp = Input(shape=(max_len,))
emb = Embedding(len(tokenizer.word_index) + 1, 64)(inp)
x = SpatialDropout1D(0.2)(emb)
x = GRU(128, return_sequences=True, activation='relu')(x)
out = GRU(32, activation='relu')(x)
dense = []
FC = Dense(32, activation='relu')
for p in np.linspace(0.1,0.5, num):
x = Dropout(p)(out)
x = FC(x)
x = Dense(y_train.shape[1], activation='softmax')(x)
dense.append(x)
out = Average()(dense)
model = Model(inp, out)
model.compile(loss='categorical_crossentropy',
optimizer='adam', metrics=['accuracy'])
return model
作为一个循环块,在模型的底部,我使用了 GRU 层。当模型被初始化时,丢失样本的数量被定义为参数。顶部完全连接的层共享每个漏失样本的权重。我用不同的掩码和不同的概率(从 0.1 到 0.5,不总是 0.5)构建了每个辍学样本(这是我允许自己采用的一个小变化)。网络有多个输出层,其数量与丢弃样本一样多。我们的网络的最后一步是一个平均层,它将前面的全连接层输出组合成一个简单的平均值。通过这种方式,最终损耗值计算为我们的丢失样本输出的平均值。
在训练阶段结束时,我们能够在测试集上实现大约 0.85%的最终准确度。
摘要
在这篇文章中,我试图重现一种叫做多样本丢失的技术。这是传统辍学的升级。它可以简单地应用于每一个神经网络结构(也可以应用于深度神经网络结构),并提供一种低成本的方式来更好地概括和改进结果,尤其是在分类任务中。
保持联系: Linkedin
参考文献
加速训练和更好推广的多样本辍学:井上浩,IBM 研究,东京
多表刮!
当你想从多篇文章中获取信息时该怎么做
克林特·王茂林在 Unsplash 上拍摄的照片
在过去的几个星期里,我一直在写如何从维基百科页面上抓取不同的东西。三周前,我写了一篇关于如何从维基百科文章中抓取一张表格的文章。两周前,我写了关于如何使用一个脚本从维基百科的多个页面中抓取数据的文章。最后,上周我写了一篇关于 s 使用颜色而不是文本来显示数据的文章。本周,我将讨论如何从多个表中抓取数据。
正如我们过去三周所做的那样,我们将继续研究关于英国烘焙大赛第一季的文章。本周,我们的目标是了解面包师如何应对技术挑战。对于那些不熟悉节目形式的人来说,每一集面包师都要经历三个挑战,签名,技术和节目主持人。技术上的挑战是,所有的面包师根据其中一位评委写的食谱烘焙相同的东西,这些面包师被匿名评判,并从最差到最好排序。在文章中,技术挑战结果显示在一个表格中,如下所示:
从一个图表中获取信息非常容易,您可以回到我的第一篇文章来回顾一下它是如何工作的。但是,当你想获得所有剧集的技术挑战信息时,你会怎么做呢?这将在下面讨论
正如我们一直在做的,我们将从导入包和使用 BeautifulSoup 访问网站开始
import requests
from bs4 import BeautifulSoup
import pandas as pd
import re
import numpy as npurl='https://en.wikipedia.org/wiki/The_Great_British_Bake_Off_(series_1)'page = requests.get(url)soup = BeautifulSoup(page.content)
此外,为了获得我们的面包师名单,我们将首先隔离排除图(上周我们使用的那张)。
然后,我们将通过执行以下操作从图表中获取面包师的姓名:
我不会过多地讨论我是如何得到这个列表的,因为这不是本文的重点,但本质上,如果排除表中的一个项目具有属性“align”,那么该项目的文本就是一个参赛者姓名。此外,如果“align”在项目的样式部分,文本也是参赛者姓名。这些名字被添加到一个列表中,在名字被刮掉之后,它们都通过。rstrip()去掉任何换行符。这给我们留下了一个参赛者名单,如下所示:
['Edd', 'Ruth', 'Miranda', 'Jasminder', 'David', 'Jonathan', 'Annetha', 'Louise', 'Lea', 'Mark']
现在我们要做的就是拿到所有的烘焙技术结果。下面是我们将要浏览的完整代码:
下面是上面代码的最终输出:
{1: {'Edd': 0,
'Ruth': 0,
'Miranda': 0,
'Jasminder': 0,
'David': 0,
'Jonathan': 0,
'Annetha': 0,
'Louise': 0,
'Lea': 0,
'Mark': 0},
2: {'Annetha': 2.0,
'David': 3.0,
'Edd': 1.0,
'Jasminder': 5.5,
'Jonathan': 9.0,
'Lea': 10.0,
'Louise': 5.5,
'Mark': 5.5,
'Miranda': 8.0,
'Ruth': 5.5},
3: {'Annetha': 7.0,
'David': 8.0,
'Edd': 6.0,
'Jasminder': 2.0,
'Jonathan': 1.0,
'Louise': 4.0,
'Miranda': 3.0,
'Ruth': 5.0},
4: {'David': 4.0,
'Edd': 1.0,
'Jasminder': 5.0,
'Jonathan': 6.0,
'Miranda': 3.0,
'Ruth': 2.0},
5: {'David': 5.0, 'Edd': 3.0, 'Jasminder': 2.0, 'Miranda': 1.0, 'Ruth': 4.0},
6: {'Edd': 2.0, 'Jasminder': 4.0, 'Miranda': 1.0, 'Ruth': 3.0}}
现在让我们进入上面的代码。前三行表示三个变量,“ep_counter”、“tech_results_list”和“ep_tech”,分别是零、空列表和字典。字典以键 1 开始,值是一个字典,其中键是参赛者的名字,值都是零。这样做是因为如果你使用这些数据来创建一个预测模型,你想从最近的前一集得到技术排名,而不是你正在分析的当前一集。显然,在第一集里,选手们没有进行技术烘焙,也没有被排名,因此他们都被分配了零分。
从这里,我们开始刮。前两行(5-6)查找所有包含“情节”的标题。然后我们创建两个空列表,名字和地点。名字将有来自一个给定的事件的选手名字,并且地点将有在所说的事件中选手如何被放置在技术烘焙中。在这里,我们执行以下操作:
本质上,我们正在做的是找到具有技术烘焙的剧集(上面的第 2 行),然后我们获取整个表并将其命名为“result_tables ”,并向剧集计数器添加 1。最后,我们创建“ep_list”,这是一个从 2 开始到最后一集结束的数字列表(本例中为 6)。然后我们深入研究结果表:
我们首先找到包含参赛者姓名的列,我们这样做,“如果一个条目的文本中的一个单词与参赛者姓名列表中的一个条目匹配,则将该条目的文本添加到姓名列表中。”然后我们再看两栏,看看他们在技术上的排名。但是,您可能已经在文章中注意到了一个小问题:
在第一集中,只有前三名和后三名获得排名,所以我们不知道谁获得了第 4,第 5,第 6 和第 7 名。因此,当我将一个条目的文本追加到位置列表中时,我告诉 regex split 要么获取数字(可能有一个或两个数字),要么获取“N/A”
考虑到这一点,我们如何处理像上面这样的缺失值呢?我选择的方法是取上述值的平均值,并将该平均值赋给缺失值,我使用下面的代码做到了这一点:
在这一点上,我将处理一个完整的位置列表,所以我首先说如果在位置列表中有一个“N/A ”,那么执行以下操作。然后我创建一个数字列表(num_list ),隔离列表中的所有数字,并使它们都是整数。然后,我取该列表的平均值(ave ),并用该平均值替换 place 列表中的所有“N/A”值。
现在我们有了一个名称列表,并且所有这些名称都有与之对应的位置编号,我们可以使用以下方法将它们放在一起:
place = [float(x) for x in place]episode_placement = dict(zip(names,place))tech_results_list.append(episode_placement)
首先,我们使位置列表中的所有项成为浮点型,因为它们以前是字符串,除非它们是代替“N/A”的平均值。然后,我们创建我们的字典(episode_placement ),其中键是参赛者的名字,值是它们在技术中的位置。然后,我们将该词典添加到我们一开始创建的技术结果列表中。
最后,我们能够更新我们开始时使用的 ep_tech 字典。如果您还记得,该字典以一个键和一个包含所有参赛者姓名的字典值 0 开始。现在我们有了以下剧集的所有信息,我们可以做以下事情:
ep_tech.update(dict(zip(ep_list,tech_results_list)))
通过这样做,我们获得了 ep_list,它计算了所有具有技术挑战的剧集,并使列表中的项目成为键,而值则是每集的名称和位置的字典。这导致了上面显示的输出:
{1: {'Edd': 0,
'Ruth': 0,
'Miranda': 0,
'Jasminder': 0,
'David': 0,
'Jonathan': 0,
'Annetha': 0,
'Louise': 0,
'Lea': 0,
'Mark': 0},
2: {'Annetha': 2.0,
'David': 3.0,
'Edd': 1.0,
'Jasminder': 5.5,
'Jonathan': 9.0,
'Lea': 10.0,
'Louise': 5.5,
'Mark': 5.5,
'Miranda': 8.0,
'Ruth': 5.5},
3: {'Annetha': 7.0,
'David': 8.0,
'Edd': 6.0,
'Jasminder': 2.0,
'Jonathan': 1.0,
'Louise': 4.0,
'Miranda': 3.0,
'Ruth': 5.0},
4: {'David': 4.0,
'Edd': 1.0,
'Jasminder': 5.0,
'Jonathan': 6.0,
'Miranda': 3.0,
'Ruth': 2.0},
5: {'David': 5.0, 'Edd': 3.0, 'Jasminder': 2.0, 'Miranda': 1.0, 'Ruth': 4.0},
6: {'Edd': 2.0, 'Jasminder': 4.0, 'Miranda': 1.0, 'Ruth': 3.0}}
现在,假设您有一个预先存在的数据帧,其中有关于这一集的其他数据,例如参赛者的年龄和家乡信息,以及他们在之前几集的表现。我之前创建了这个数据帧,下面是它的快照:
下面是我如何用那本字典创建一个技术安置专栏:
浏览代码时,我首先创建了一个字典,其中的关键字是带有名称和剧集的元组,值是参赛者如何放置该剧集(第 1-4 行)。然后我创建一个空列表 placement_list,它将成为技术栏。然后,我创建了一个元组列表,其中每个元组都是上面所示数据帧(第 6–7 行)中每行的参赛者姓名和剧集编号。从那里,我说对于元组列表中的每一项,在 tech_tuple 字典中查找它的值,并将该值添加到位置列表中。现在我已经有了一个完整的技术职位列表,我只需创建一个新的列“technical”并将其分配给职位列表。这就是我们如何得到以下结果的:
在本文中,我展示了如何查看页面的许多不同区域,而不仅仅是页面的一个图表或部分。维基百科页面的格式一般来说是可读的,并且便于用户理解,但这也意味着你可能正在寻找的数据需要被格式化和压缩。通过这样做,您可以获取可读信息并使其可处理。
使用 Pytorch 和 FastAI 进行多任务学习
使用相同的模型预测年龄、性别和种族。
阿纳斯塔西娅·舒拉耶娃在像素上拍摄的照片
根据我在名为的帖子中提出的概念,你应该使用 FastAI 吗?,我想在这里展示如何使用混合 Pytorch-FastAI 方法来训练多任务深度学习模型。Pytorch-FastAI 方法的基本思想是使用 Pytorch 代码定义数据集和模型,然后使用 FastAI 来拟合您的模型。这种方法为您提供了构建复杂数据集和模型的灵活性,但仍然能够使用高级 FastAI 功能。
多任务学习(MTL)模型是一种能够完成多项任务的模型。就这么简单。一般来说,一旦你发现自己在优化不止一个损失函数,你就有效地在做 MTL。
在这次演示中,我将使用 UTKFace 数据集。该数据集由超过 30k 张带有年龄、性别和种族标签的图像组成。
年龄:61 岁,性别:女性,民族:印度人
如果你想跳过所有的谈话,直接跳到代码,这里有链接。
1.为什么要多任务学习?
当你看着某人的照片并试图预测年龄、性别和种族时,你没有使用完全不同的大脑区域,对吗?我想说的是,你不要试图用 3 种不同的方式去理解这幅图像,每一种方式都是针对每一项任务的。你所做的是利用大脑对图像的单一理解,然后试图将这种理解解码成年龄、性别和种族。除此之外,来自性别估计的知识可能有助于年龄估计,来自种族估计的知识可能有助于性别估计等等。
那么,为什么是 MTL?我们相信,训练一个模型来完成我们感兴趣的所有任务,会比训练一个模型来完成每项任务产生更好的结果。里奇·卡鲁阿纳很好地总结了 MTL 的目标:“MTL 通过利用相关任务的训练信号中包含的特定领域信息来提高概括能力”。
由于这是一个训练 MTL 模型的实用教程,我不会深入理论和直觉,但如果你想阅读更多,请查看 Sebastian Ruder 的这篇惊人的帖子。
2.创建数据集、数据加载器和数据绑定
编辑:有些人报告了代码中的一个错误,看起来像是一个图像正在破坏它。好像删除图片“61_3_20170109150557335.jpg”就解决问题了。(谢谢 Stonelive !)
当你在处理深度学习问题时,通常首先要关心的是如何向你的模型提供数据,以便它能够学习。对于这个特定的 MTL 问题,Pytorch 数据集的定义非常简单。
数据集类定义
你可能会问,为什么我取年龄的对数,然后除以 4.75。取对数意味着预测高年龄和低年龄的误差将同样影响结果。稍后我会解释为什么除以 4.75。另外要提的是,我这里用的是 FastAI 的数据增强(我觉得比 torchvision.transforms 的要好)。
一旦定义了 dataset 类,创建 dataloaders 和 databunch 就非常容易了。
创建数据集、数据加载器和数据绑定。
3.创建模型
请记住,我们的目标是根据给定的图像,预测年龄、性别和种族。回想一下,预测年龄是单输出的回归问题,预测性别是双输出的分类问题,种族是 5 输出的分类问题(在这个特定的数据集中)。考虑到这一点,我们可以创建我们的 MTL 模型。
您可以看到该模型只使用了一个编码器(一个特征提取器),并将编码(特征)提供给特定于任务的头部。每个头有适当数量的输出,以便它可以学习它的任务。
为什么我要对来自 ages head 的结果应用一个 sigmoid?这与我之前提到的除以 4.75 有关,我会在下节课讲。
4.损失函数呢?
损失函数是指导训练的,对吗?如果你的损失函数不好,你的模型也不会好。在 MTL 问题中,通常你要做的是将每项任务的损失结合起来。例如,在我们的问题中,损失可能是预测年龄的均方误差和预测性别和种族的交叉熵。对于 MTL 问题,有一些组合任务特定损失的常用方法。我就说其中的三个。
第一步是计算每项任务的损失,然后将它们加在一起,或者取平均值。尽管我在一些论坛上读到过这种方法很有效,但这并不是我从实验中得出的结论。由于损失可能有不同的大小,其中一个损失可以控制训练,你不会得到好的结果。
第二步是试着用手称量损失,然后将它们相加/平均。事实证明,这种方法相当复杂,需要太多时间,我也无法让它工作。
另一方面,第三次拍摄给我带来了不错的结果。它包括让模型学习如何衡量特定任务的损失。在论文多任务学习使用不确定性来衡量场景几何和语义的损失中,作者提出了这样的损失函数。下面是我对论文中针对这个具体问题的建议的实现。
我们提出了一种多任务深度学习的原则性方法,该方法通过考虑每个任务的同方差不确定性来权衡多个损失函数。这允许我们在分类和回归设置中同时学习不同单位或标度的各种量。
现在我应该解释一下为什么我选择将年龄的对数除以 4.75(在 dataset 类的 getitem 方法上)以及为什么我将 sigmoid 应用于年龄头部的输出(在模型定义上)。
理论上,损失函数应该能够学习权重并衡量每个任务的损失。但事实上,在我的实验中,我得出结论,保持特定任务的损失在相同的范围内对拟合过程有很大帮助。所以我用年龄的对数除以 4.75,因为这是对数(年龄)的最大值。所以 log(age)/4.75 的结果应该是 0 到 1 之间的一个数,这样 MSE 损失就不会比其他损失大很多。我在年龄的头部后应用了一个 sigmoid,这样我可以强制我的模型总是输出一个在可接受范围内的预测。
5.创造学习者和培训
通过数据分组,模型和损失函数定义了创建学习器的时间。我将添加一些指标来帮助我跟踪模型在验证集上的性能。
定义了学习者之后,现在我们可以使用 FastAI 功能来训练我们的模型。我们可以使用学习率查找器、fit_one_cycle 方法、判别学习率训练等。
由于我使用的是在 Imagenet 上预训练的 resnet34 编码器,首先我将只训练编码器上的头部和批次规范层。经过 15 个纪元的训练,我得到了年龄预测的 0.087 RMSE,性别预测的 89.84% 准确率和种族预测的 84.15% 准确率。
之后,我解冻编码器,并用 100 个时期的判别学习率训练整个模型,这使我得到了年龄预测的 0.058 RMSE,性别预测的 99.42% 准确度和种族预测的 99.19% 准确度。
6.结论
在这篇文章中,我介绍了使用 Pytorch/FastAI 混合方法训练 MTL 模型所需的基础知识。我想我再次展示了 FastAI 的高级功能非常有用,让我的生活变得更加轻松。如此轻松地使用高级深度学习功能作为区分性学习速率和一个周期调度,在我看来是 FastAI 的大拇指。
值得一提的是,在本教程中,我的重点是帮助你解决一个 MTL 问题。UTKFace 数据集非常偏向于白人和年龄在 20 到 40 岁之间的人,所以你应该记住这一点。在我的最终实现中,我对损失函数做了一些小的调整,使得模型的性能偏差更小。
如果你喜欢这篇文章,请给它一些掌声。你可以通过访问我的 github 查看更多关于我正在做的事情,并通过 LinkedIn 取得联系。
感谢您的阅读!
Google Cloud AI 平台上的 Tensorflow 多工培训
理解大数据
图片由作者在 CC BY-NC 4.0 下
几乎在每个深度学习项目中,都有一个决定性的时刻,海量的训练数据或缺乏处理能力成为在适当的时间完成训练的限制因素。因此,应用适当的缩放是不可避免的。虽然纵向扩展,即升级到更强大的硬件,可能会提供暂时的补救措施,但它很少提供正确的可扩展性,因为纵向扩展会很快达到其物理极限。因此,我们没有其他选择,只能扩大模型训练,即使用额外的机器。幸运的是,在云时代,横向扩展不再是一个障碍。
谈到向外扩展神经网络训练,有两种主要方法。有一种叫做模型并行的策略,在这种策略中,神经网络本身被分割到多个设备上。这种类型的分布主要用于模型由大量参数组成并且不适合特定设备的情况,或者输入样本的大小甚至会妨碍计算激活的情况。对于那些对 Tensorflow 的模型并行感兴趣的人,有一个官方的解决方案叫做 Mesh 。
另一种分布策略称为数据并行,其中模型在每个节点上复制。然后,数据以这样的方式分布,每个副本看到它的不同部分。这种分布策略对于具有大量训练数据的情况特别有用。
由于每个副本在每一步都接收到不同的训练数据片段,因此工作人员必须有序地传达梯度更新。有两种沟通方式。有异步训练、**、**工人独立训练自己的复制品。异步训练通常使用离散参数服务器来报告梯度更新。
另一种是同步训练,在每一个训练步骤之后,工人们分享参数更新。同步训练经常实现全归约算法,这意味着所有副本存储归约(更新)的参数,而不是将它们传递到中央位置。
异步训练的主要好处体现在避免最慢的工人空闲,以及稍微好一点的机器容错能力。主要缺点是参数服务器需要大量的网络带宽来与工作人员进行有效的通信。运行多个参数服务器可能会解决这个问题,但也会增加培训成本。
同步训练的权衡正好相反。不需要使用额外的机器来存储更新的模型参数。另一方面,等待最慢的工人肯定会拖延进程。选择业绩相似的员工可能会减少闲置时间。采用高效的网络拓扑来共享梯度更新同样至关重要。工人之间多余的交流会抵消同步培训的好处。
多工人分布式张量流
Tensorflow 通过tf.distribute.Strategy
API 在他们的标准库中实现数据并行策略。它们支持同步和异步多工人培训,尽管后者支持有限。截至撰写本文时,异步的ParameterServerStrategy
只支持原始的tf.estimator.Estimator
API。然而,从 2.4 版本开始,人们开始努力使异步培训变得更加可用。
自从 Tensorflow 2.0 发布以来,tf.keras.Model
API 已经成为构建神经网络的主要方式,尤其是那些不需要定制训练循环的神经网络。新开发的分布式培训策略同样主要集中在 Keras 模型上。尽管已经为 Keras 模型实现了几种分布式培训策略,但是在撰写本文时,当前可用的多工人培训仅仅是同步的MultiWorkerMirroredStrategy
。
这个策略为我们增加了很多负担。它会根据所用的硬件和网络拓扑来优化选择合适的 all-reduce 实现。目前,可用的选项有 ring all-reduce 和 NVidia 的 NCLL 。在训练 Keras 模型的情况下,该策略还自动在工人中分发训练数据集。通过文件或数据对数据集进行分片,可以进行分发。按文件分片是首选,因为每个副本只加载分配的文件。例如,它可用于 TFRecord 数据集。在其中存储训练样本是高效处理大型数据集的最有效方式。另一方面,如果没有办法按文件进行分片,那么所有的工作人员都会读取所有可用的数据,但是他们只处理分配给他们的分片。例如,在直接从 BigQuery 中读取数据的情况下,或者文件数量少于 workers 的情况下,可能会发生日期分片。验证和测试数据集也是如此。
该策略还可以通过名为BackupAndRestore
的 Keras 回调提供容错。该回调在每个时期结束时备份模型。如果发生工人中断,所有其他工人也将重新开始,并且训练从最后完成的训练时期继续。模型训练成功后,存储的检查点将被删除。
多工人配置
在 Tensorflow 中配置多工人培训最简单的方法是通过名为TF_CONFIG
的环境变量。它是一个 JSON 字符串,包含两个键,cluster
和task
。前者描述拓扑结构,包括节点的地址。它的值在所有节点上都是相同的。后者对于每个节点都是唯一的,并定义了它们在集群中各自的角色。一旦 Tensorflow 解析了环境变量,它就会根据配置启动 gRPC 服务器。
以下示例描述了一个包含两个节点的集群,一个主节点和一个工作节点。
TF_CONIFG
在这个集群中有一个指定的节点具有额外的职责,称为主节点。它可以满足诸如保存训练检查点、为 TensorBoard 编写摘要以及序列化训练模型等任务的需要。如果在配置中没有明确指定负责人,则索引为 0 的工作人员将担任该角色。当然,主节点也执行相同的代码。
多工人模型
将MultiWorkerMirroredStrategy
与 Keras 模型集成很简单。只有几个要求。首先,模型的构建和编译必须在分销策略的范围内进行。其次,批量大小必须反映节点的数量。通常,批量大小通过乘以节点数来调整。保持原来的批量大小也是可行的。但是,在这种情况下,工人收到的批次较少。这些方法分别被称为弱缩放和强缩放。
多员工战略范围
与常规 Keras 训练相反的另一个区别是需要指定steps_per_epoch
参数,否则这是可选的。每个时期的步骤数很容易计算,并且是训练实例数除以调整后的全局批量的比率。函数create_model
包含了定义一个包含模型编译的模型的常用方法。
创建模型助手方法
保存一个多工人模型有点复杂。所有节点都必须保存模型,尽管保存到不同的位置。最后,除了主节点之外的所有节点都必须删除它们保存的版本。采取这些步骤的原因是所有-减少通信仍然可能发生。
多工人模型保存
人工智能平台上的多人培训
Google Cloud 和 Tensorflow 和谐地协同工作。Tensorflow 在 AI 平台中一直享有突出的地位。此外,谷歌云也一直在努力开发 Tensorflow 的新产品。例如,他们最近推出了带有补充支持和托管服务的 Tensorflow Enterprise 。
正如我们所见,正确设置TF_CONFIG
是 Tensorflow 多员工培训的重要组成部分。对于 Tensorflow 来说,在运行模型训练之前,环境变量必须存在。幸运的是,AI 平台会根据给定的培训作业配置来负责设置。
有两种方式提供作业配置。功能是设置提交命令的各个选项。但是,对于不常改变的属性,将它们存储在 YAML 配置文件中更方便。对于成功的多人培训,需要的选项有runtimVersion
、pythonVersion
、scaleTier
、masterType
、worketType
、workerCount
。
培训配置
上面的配置文件将创建一个由三个节点组成的集群,包括一个首领和两个工人。机器的类型可以不同,但最好是在整个培训集群中保持相同。也有预定义的机器层级,但是它们都带有参数服务器。因此,将 scale-tier 设置为 custom 是当前的当务之急。
配置还指定了 Tensorflow 版本,它等于runtimeVersion
属性。运行时会定期更新,但支持更高版本的 Tensorflow 需要一些时间。需要注意的是,2.1 版之前的运行时没有正确设置主节点。因此,AI 平台上的多工人培训仅适用于运行时 2.1 和更高版本。
另一方面,在某些情况下,能够使用尚不支持的 Tensorflow 版本是至关重要的。例如,有相关的新特性,或者它们需要在投入生产之前进行适当的测试。对于这种情况,Google AI 平台提供了使用自定义容器进行训练的选项。提交定制容器进行培训与使用所提供的运行时非常相似。不过,还有一些小细节需要考虑。为了拥有正确的TF_CONFIG
,容器化张量流模型需要将选项useChiefInTfConfig
设置为true
。此外,培训配置必须为主管和工人指定图像 URIs。当然,两种情况下的容器是相同的。
自定义容器配置
在官方运行时和自定义容器中,AI 平台训练都自动使用云 ML 服务代理凭证。
本地测试
在向 AI 平台提交作业之前,在本地测试培训配置的正确性是可行的,因为失败的作业也会被计费。幸运的是,官方运行时在本地运行、执行
gcloud ai-platform local train --distributed --worker-count $N ...
命令为我们设置了一个正确的TF_CONFIG
。唉,它还在配置中添加了一个参数服务器。Tensorflow 会发出警告,但拥有参数服务器不会妨碍训练。
对于容器,设置一个正确的TF_CONFIG
并运行容器稍微复杂一点,但并非不可行。实现本地测试的最简单的方法是使用 docker-compose 来运行主容器和工作容器以及设置环境变量。
docker-编写用于本地测试的配置
COMMAND
变量是一个字符串,包含训练任务的所有参数。一旦 docker-compose 配置完成,只需点击
docker-compose up
在这两种情况下,如果培训需要访问其他 Google 云服务,例如云存储,那么必须在运行本地培训之前定义指向正确的服务帐户密钥 JSON 文件的GOOGLE_APPLICATION_CREDENTIALS
。
后续步骤
构建神经网络本身并不是一项简单的任务。在此基础上处理分布式计算最终会严重阻碍这一过程。幸运的是,现代深度学习框架是在考虑可扩展性的情况下构建的,因此能够实现更快的开发。此外,由于 Tensorflow 和 Google Cloud 之间的顺利兼容,开发这种可扩展性从未像现在这样容易。
简单的例子
事实上,这种平稳性乍看起来可能并非如此。为此,我在 Github 上创建了一个简单的工作示例。查看实际细节。记住,最好的学习方法是实践。
在 Google Cloud AI 平台上设置和运行 Tensorflow 多工人培训模型的简单示例。这个…
github.com](https://github.com/kalosisz/tf-gcp-multi-worker-example)
资源
RoboCup 救援模拟器的多智能体强化学习
RoboCup 救援模拟器
多智能体,强化学习,RoboCup 救援模拟器。标题中已经使用了相当多的术语。但是不用担心。读完这篇文章,你会明白其中的每一点。我将首先构建一些关于机器学习的背景,机器学习技术的类型,然后深入研究强化学习领域。这是事情开始变得稍微技术性的地方,但我会尽量保持简单,并尽可能提供例子。然后,我将解释我如何应用强化学习来训练一群消防队,以找到着火的建筑并扑灭这些建筑中的火。全靠自己!所以,为这次激动人心的旅程做好准备吧。
什么是机器学习?
我们正处于这样一个时代,我们可以教机器如何学习,一些机器甚至可以自己学习。这种神奇的现象叫做机器学习。但是机器是怎么学习的呢?他们通过在相似的数据中寻找模式来学习。把数据想象成你从世界上获得的信息。给机器的数据越多,它就越“聪明”。
机器学习算法的类型
机器学习算法有哪些类型?
从广义上讲,有三种类型:监督学习、非监督学习和强化学习。
1.监督学习
机器从标记的数据中学习。标记数据由未标记数据组成,带有数据中特征的描述、标签或名称。例如,在标记的图像数据集中,图像被标记为它是猫的照片并且它是狗的照片。
2.无监督学习
机器从未标记的数据中学习。未标记数据由取自自然或人类创造的数据组成,以探索其背后的科学模式。未标记数据的一些例子可能包括照片、录音、视频、新闻文章、推文、x 光片等。主要概念是数据中的特征没有解释、标签、标记、类或名称。
3.强化学习
它是一种机器学习技术,使代理能够在交互式环境中使用来自其自身行为和经验的反馈,通过反复试验来学习。
虽然监督学习和强化学习都使用输入和输出之间的映射,但与监督学习不同,监督学习向代理提供的反馈是执行任务的一组正确的动作,强化学习使用奖励和惩罚作为积极和消极行为的信号。
与无监督学习相比,强化学习在目标方面是不同的。虽然无监督学习的目标是找到数据点之间的相似性和差异,但在强化学习的情况下,目标是找到一个合适的动作模型,使代理的总累积报酬最大化。下图说明了通用 RL 模型的行动-奖励反馈回路。
强化学习模型的抽象描述
如何公式化一个基本的强化学习问题?
描述 RL 问题基本要素的一些关键术语是:
- 环境— 代理运行的物理世界
- 状态— 代理的当前状态
- 奖励— 环境的反馈
- 策略— 将代理的状态映射到动作的方法
- 价值— 代理在特定状态下采取行动将获得的未来回报
一个 RL 的问题可以通过游戏得到最好的解释。就拿 吃豆人 这个游戏来说,代理人(吃豆人)的目标是吃掉格子里的食物,同时避开途中的幽灵。在这种情况下,网格世界对于代理来说是一个交互环境。代理人会因为吃了食物而得到奖励,如果被鬼魂杀死(输掉游戏)则会受到惩罚。状态是代理在网格世界中的位置,总的累积奖励是代理赢得游戏。
强化学习应用于 PacMan 的例子
为了建立一个最优策略,代理人面临着探索新状态,同时最大化其整体报酬的困境。这叫做勘探与开发权衡。为了平衡这两者,最好的整体策略可能需要短期的牺牲。因此,代理应该收集足够的信息,以便在未来做出最佳的整体决策。
马尔可夫决策过程**【MDPs】**是描述 RL 中环境的数学框架,几乎所有的 RL 问题都可以用 MDPs 来表述。一个 MDP 由一组有限的环境状态 S,一组在每个状态下的可能动作 A(s),一个实值报酬函数 R(s)和一个转移模型 P(s ',s | a)组成。然而,真实世界的环境更有可能缺乏任何环境动力学的先验知识。在这种情况下,无模型 RL 方法就派上了用场。
Q-learning是一种常用的无模型方法,可用于构建自玩 PacMan 代理。它围绕着更新 Q 值的概念,Q 值表示在状态 s 中执行动作 a 的值。下面的值更新规则是 Q 学习算法的核心。
q 学习算法
策略梯度 是另一种流行的无模型 RL 方法,但它不计算 Q 值,而是使用策略。政策学习从每个状态到行动的映射,它的目标是发现哪些行动导致更高的回报并增加它们的概率。政策梯度观察环境并在其中采取行动,并根据其获得的回报不断更新其政策。经过多次迭代后,策略收敛到最大值。策略梯度方法的缺点可能是,它有时会陷入局部最大值,而无法达到全局最大值。
最常用的强化学习算法有哪些?
在有大的状态和动作空间的情况下,学习每个状态和动作对的 Q 值或策略是不可行的。这是使用深度强化学习(DRL)** 的时候,其中利用神经网络对 RL 的组件进行建模。**
深度强化学习架构
我们考虑两种基于 DRL 模型的算法:深度 Q 学习和 ProximalPolicy 优化,主要是因为 DQN 在 Atari 游戏上表现出了很好的结果,并帮助团队实现了人类水平的表现,而使用 PPO,OpenAI 的 DOTA 2 团队能够在公开比赛中击败 99.4%的玩家。
深度 Q 网(DQN)
DQN 是 Q 学习和深度神经网络的结合。DQN 通过使用两种观点解决了使用非线性逼近器来表示 Q 值所导致的不稳定性:经验重放和目标网络。
体验回放:例如,我们将最后一百万个转场(或视频帧)放入一个缓冲区,并从该缓冲区中抽取一个 32 大小的小批量样本来训练深度网络。这就形成了一个足够稳定的输入数据集用于训练。当我们从重放缓冲区随机取样时,数据更加相互独立,更接近于同分异址。
**目标网络:我们创建两个深度网络 θ- 和 θ。我们使用第一个来检索 Q 值,而第二个包括训练中的所有更新。比如说 100,000 次更新之后,我们将 θ- 与 θ 同步。目的是暂时固定 Q 值目标,这样我们就没有一个移动的目标可以追逐。此外,参数变化不会立即影响 θ- ,因此即使输入可能不是 100% i.i.d .,也不会错误地放大其效果,如之前的所述。
有了经验重放和目标网络,我们有了更稳定的输入和输出来训练网络,并且表现得更像监督训练。要了解更多关于 DQN 是如何运作的,请阅读乔纳森·许的这篇令人惊叹的文章。
近似策略优化(PPO)
PPO 是一种政策梯度方法,其表现相当于或优于最先进的方法,但实施和调整要简单得多。为了用策略梯度算法获得好的结果,需要仔细调整步长。此外,大多数策略梯度方法对每个采样轨迹执行一次梯度更新,并且具有高样本复杂度。PPO 算法解决了这两个问题。它使用了一个替代目标,该目标被最大化,同时惩罚对策略的大的改变。他们定义了一个可能性比率
PPO 然后优化目标:
其中 A_t 是广义优势估计,clip (l_t(θ),1ε,1+ε)在区间[1-ε,1+ε]内 clips l_t(θ)。该算法在从策略中采样多个轨迹和在采样的数据集上执行 SGD 的几个时期之间交替,以优化该替代目标。由于状态值函数也被同时近似,所以值函数近似的误差也被添加到替代目标以计算完整的目标函数。要了解更多关于 PPO 如何工作的信息,请阅读 Jonathan Hui 的这篇令人惊叹的文章。
RoboCup 救援模拟器
现在理论到位了,让我们把重点放在一些应用上。1995 年 1 月 17 日,日本港口城市神户发生里氏 6.8 级地震,造成大规模破坏,约 7000 人丧生。1999 年 4 月 30 日,RoboCup 救援联盟成立,旨在促进国际研究,开发更好的救援能力。多年来,许多团队都参加了一年一度的机器人世界杯救援联盟,该联盟包括三个竞赛:机器人竞赛、虚拟机器人竞赛和模拟代理人竞赛。我们将重点关注被称为机器人世界杯救援模拟(RCRS)的模拟智能体竞赛,这是多智能体系统的一个完美例子。我们将把强化学习应用到 RCRS,以训练这些代理完成他们各自的任务。
RoboCup 救援模拟环境
以下是分配给代理的任务:
- 消防队:灭火
- 警察:清除碎片
- 救护车:运送平民到安全避难所
在这篇文章中,我们将关注消防队,并训练他们学会如何在城市中灭火。
RoboCup 救援模拟器(RCRS)的强化学习
正如我们上面所讨论的,为了制定任何 RL 模型,我们需要定义状态空间、动作空间和奖励函数。让我们讨论一下 RCRS 的这些属性。
状态空间 :状态空间有三部分。第一部分是建筑物信息,包括温度和热度。注意,火热度是衡量程度的一个参数。一栋大楼着火了。第二部分是代理信息,它给出了每个时间步的位置((X,Y)坐标)、消防水箱中的水和消防队的健康点。第三部分是忙/闲信息,它是一个二进制变量。消防队在每个时间点都会收到一个建筑物 id 作为他们的目标位置。但是有时它们需要一个以上的时间间隔才能到达建筑物。与此同时,动作不断被发送。因此,消防队必须忽略这些动作,直到他们访问在先前时间步中被告知要访问的建筑物。该信息作为状态信息被传递,这对于我们的算法更好地执行是非常有价值的。每当由算法发送的动作在模拟器中被使用时(忙),1 作为状态信息被发送回来,否则 0 被发送(空闲)。
状态空间参数范围
动作空间: 我们的代理唯一可用的动作是移动到着火的建筑物,因此动作空间由建筑物的 ID 组成。请注意,灭火和补水是我们的代理的默认特征,即,每当我们的代理靠近着火的建筑物时,它将尝试灭火,每当它离开水时,它将移动到避难所来给水箱补水。因此,这些动作不包括在动作空间中。
奖励功能 :由于消防队的最终目标是尽可能快地灭火,我们创建了一个奖励功能,对将火势控制在最低限度的特工给予更高的奖励,如果火势增大则对他们进行惩罚。火热度是衡量建筑物燃烧程度的一个参数,因此将整体火热度值保持在最低会导致更高的累积奖励。
奖励计算
根据火热程度值的火热程度
模型架构
我们使用 DQN 和 PPO 架构,做了一些修改。我们没有卷积层的集合,因为神经网络的输入不是图像。网络的输入是状态表示,每个可能的动作有一个单独的输出单元。稳定基线可以选择使用不同的架构,我们可以改变隐藏层的数量,使用 LSTM,使用 CNN 或结合 CNN 和 LSTM。我们在训练模型时尝试了不同的架构。作为我们尝试的一种架构的示例,请参考下图。
模型架构
超参数搜索
该表显示了我尝试训练模型的不同超参数。
PPO 超参数
DQN 超参数
结果
理论太多!让我们言归正传。结果如何?
以下是训练有素的特工对 DQN 和 PPO 的一些模拟。这些视频是在特定的时间间隔拍摄的,即在 5 集、150 集和 250 集之后。每集 100 个时间步长。
这里红色的移动点代表消防队,右下角是避难所,消防队正在那里重新装满他们的水箱。
不同的颜色阴影代表了这些建筑的火灾强度:
- 淡黄色:建筑物起火
- 橙色:楼内火势加剧
- 红色:建筑燃烧严重
- 黑色:建筑被烧毁
- **蓝色:消防队将大楼内的火扑灭
- 灰色:建筑未燃烧
这里是一个可视化的模拟器在未经训练时的样子,以及它如何开始学习最终扑灭城市中的所有火灾。
学习曲线
两种算法的学习曲线
从上面的曲线和 gif 可以看出,这两种算法都在这个模拟器上成功地学习,并且能够成功地完成它们的任务。从学习曲线中,我们还可以看到,DQN 在这种情况下比 PPO 表现得更好,并且能够快速学习。尽管如此,结果并不比贪婪算法更好(在贪婪算法中,所有的代理将熄灭温度最高的建筑)。目前,我正在一张有更多建筑的地图上训练这些代理,并将很快分享结果。
我要感谢我的导师皮特·斯通、加勒特·沃内尔和子超,他们给了我参与这个项目的机会。
这是我的 GitHub 回购协议的链接。
学习强化学习的要领!
towardsdatascience.com](/reinforcement-learning-101-e24b50e1d292) [## 机器学习初学者指南
我应该现在学…还是以后学?学习是一种普遍的技能/特性,是任何生物在这方面获得的…
medium.com](https://medium.com/@randylaosat/a-beginners-guide-to-machine-learning-dfadc19f6caf) [## 多智能体强化学习
在目前人工智能(AI)研究的各个领域中,有一个领域已经…
medium.com](https://medium.com/@RemiStudios/multi-agent-reinforcement-learning-3f00b561f5f0) [## 我在深度学习方面的文章列表
包括物体检测、自动驾驶汽车、元学习等
medium.com](https://medium.com/@jonathan_hui/index-page-for-my-articles-in-deep-learning-19821810a14)**
Python 中从头开始使用逻辑回归的多类分类:分步指南
Tj·霍洛韦丘克在 Unsplash 上拍摄的照片
逻辑回归的两种方法:梯度下降法和优化函数
逻辑回归是一种非常流行的机器学习技术。当因变量是分类变量时,我们使用逻辑回归。本文将集中讨论多类分类问题的逻辑回归的实现。我假设您已经知道如何用逻辑回归实现二元分类。
如果你还没有用逻辑回归研究过二元分类,我建议你在深入研究这篇文章之前先浏览一下这篇文章。
因为多类分类是建立在二类分类之上的。
在本文中,您将学习二进制分类的概念、公式和工作示例:
发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法…
towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0)
多类分类
多类分类的实现遵循与二类分类相同的思想。如你所知,在二元分类中,我们解决一个是或否的问题。与上述文章中的示例一样,输出回答了一个人是否患有心脏病的问题。我们只有两节课:心脏病和非心脏病。
如果输出为 1,则此人患有心脏病,如果输出为 0,则此人没有心脏病。
在多类分类中,我们有两个以上的类。这里有一个例子。比方说,我们将汽车、卡车、自行车和船只的不同功能和特征作为输入功能。我们的工作是预测标签(汽车、卡车、自行车或船)。
这怎么解决?
我们将把每一个类当作一个二元分类问题,就像我们解决一个心脏病或没有心脏病的问题一样。
这种方法被称为一对一方法
在 one vs all 方法中,当我们处理一个类时,这个类用 1 表示,其余的类变成 0。
例如,如果我们有四类:汽车、卡车、自行车和船。当我们处理汽车时,我们将汽车作为 1,其余的类作为 0。同样,当我们在卡车上工作时,卡车的元素将是 1,其余的类将是 0。
等你落实了就更好理解了。我建议你在阅读的时候继续编码和运行代码。
在这里,我将用两种不同的方式实现这个算法:
- 梯度下降法。
2.优化函数方法。
重要方程式及其工作原理:
逻辑回归使用 sigmoid 函数来预测输出。sigmoid 函数返回一个从 0 到 1 的值。一般我们取一个阈值,比如 0.5。如果 sigmoid 函数返回大于等于 0.5 的值,我们将其视为 1,如果 sigmoid 函数返回小于 0.5 的值,我们将其视为 0。
z 是输入特征乘以表示为θ的随机初始值。
这里,X 是输入特征。在大多数情况下,有几个输入特征。所以,这个公式变大了:
X1、X2 和 X3 是输入要素,将为每个输入要素随机初始化一个θ。开始时的θ0 是偏置项。
该算法的目标是在每次迭代中更新该θ,以便能够建立输入要素和输出标注之间的关系。
成本函数和梯度下降
成本函数给出了我们的预测与原始输出有多远的想法。这是它的公式:
这里,
m 是训练样本的数量或训练数据的数量,
y 是原始输出标签,
h 是假设或预测输出。
这是梯度下降的方程式。使用这个公式,我们将在每次迭代中更新θ值:
用梯度下降法实现
先决条件:
a.您需要能够舒适地读写 python 代码。
b.基本数字图书馆和熊猫图书馆。
在这里,我将一步一步地展示实现过程。
- 导入必要的包和数据集。我从 Coursera 的吴恩达的机器学习课程中获取了数据集。这是一个手写识别数据集。有从 1 到 10 的数字。
从像素数据集中,我们需要识别数字。在该数据集中,输入变量和输出变量被组织在 Excel 文件的不同表格中。请随意从本页末尾的链接下载数据集。
如果你正在阅读这篇文章来学习这个算法,请运行每一段代码。
让我们导入必要的包和数据集,
import pandas as pd
import numpy as np
xl = pd.ExcelFile('ex3d1.xlsx')
df = pd.read_excel(xl, 'X', header=None)
2.导入 y,这是输出变量
y = pd.read_excel(xl, 'y', header = None)
3.定义采用输入变量和θ的假设。它返回计算出的输出变量。
def hypothesis(theta, X):
return 1 / (1 + np.exp(-(np.dot(theta, X.T)))) - 0.0000001
4.构建采用输入变量、输出变量和θ的成本函数。它返回假设的成本。这意味着它给出了预测与原始输出之间的距离。
def cost(X, y, theta):
y1 = hypothesis(X, theta)
return -(1/len(X)) * np.sum(y*np.log(y1) + (1-y)*np.log(1-y1))
5.现在,是数据预处理的时候了。
数据是干净的。不需要太多的预处理。我们需要在输入变量中添加一个偏差列。请检查 df 和 y 的长度。如果长度不同,模型将不起作用。
print(len(df))
print(len(y))
X = pd.concat([pd.Series(1, index=df.index, name='00'), df], axis=1)
6.y 列有从 1 到 10 的数字。这意味着我们有 10 节课。
y 是一个不必要的数据帧。我将只把列作为包含值的序列。
y = y.iloc[:, 0]
我们将为每个类创建一个长度与 y 相同的列。当类为 5 时,为包含 5 和 0 的行创建一个包含 1 的列,否则为 0。
看看,我们有多少节课,
y.unique()
输出:
array([10, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64)
所以,我们有 10 节课。启动一个有 10 列和 df.shape[0]行的 DataFrame。
y1 = np.zeros([df.shape[0], len(y.unique())])
y1 = pd.DataFrame(y1)
我们将用一些简单的代码以编程的方式实现它:
for i in range(0, len(y.unique())):
for j in range(0, len(y1)):
if y[j] == y.unique()[i]:
y1.iloc[j, i] = 1
else:
y1.iloc[j, i] = 0
y1.head()
7.现在定义函数‘gradient _ descent’。该函数将输入变量、输出变量、theta、alpha 和历元数作为参数。这里,α是学习率。
你应该根据你的要求来选择它。学习率太小或太大都会使你的算法变慢。我喜欢针对不同的学习速率运行算法,并获得正确学习速率的想法。可能需要几次迭代来选择正确的学习速率。
对于 y1 中的每一列,我们将实现一个二元分类。
例如,当我考虑数字 2 时,它应该为数字 2 返回 1,为其余的数字返回 0。因此,由于我们有 10 个类,我们已经运行了每个时期(迭代)10 次。这里有一个嵌套的 for 循环。
def gradient_descent(X, y, theta, alpha, epochs):
m = len(X)
for i in range(0, epochs):
for j in range(0, 10):
theta = pd.DataFrame(theta)
h = hypothesis(theta.iloc[:,j], X)
for k in range(0, theta.shape[0]):
theta.iloc[k, j] -= (alpha/m) * np.sum((h-y.iloc[:, j])*X.iloc[:, k])
theta = pd.DataFrame(theta)
return theta, cost
7.初始化θ。记住,我们将为每个类实现逻辑回归。每堂课也会有一系列的θ。
我已经运行了 1500 个纪元了。我相信随着时代的增加,准确率会更高。
theta = np.zeros([df.shape[1]+1, y1.shape[1]])
theta = gradient_descent(X, y1, theta, 0.02, 1500)
8.使用更新后的θ,计算输出变量。
output = []
for i in range(0, 10):
theta1 = pd.DataFrame(theta)
h = hypothesis(theta1.iloc[:,i], X)
output.append(h)
output=pd.DataFrame(output)
9.将计算的输出与原始输出变量进行比较,以计算模型的准确性。
accuracy = 0
for col in range(0, 10):
for row in range(len(y1)):
if y1.iloc[row, col] == 1 and output.iloc[col, row] >= 0.5:
accuracy += 1
accuracy = accuracy/len(X)
准确率为 72%。我确信,更多时代的准确性会更好。因为花了太多时间,我没有重新运行算法。
如果你正在运行这个,请随意尝试更多的纪元,并在评论部分让我知道,你有多少准确性。
除了梯度下降法,你还可以使用内置的优化函数。
在这种方法中,使用优化函数来优化算法的θ。这是一个更快的方法。
用优化函数实现
1.我们将使用与之前相同的数据集。如果使用相同的笔记本,请使用不同的名称导入数据集:
xls = pd.ExcelFile('ex3d1.xlsx')
df = pd.read_excel(xls, 'X', header=None)
2.我们仍然需要为 df 中的偏差项添加一列全 1。
X = np.c_[np.ones((df.shape[0], 1)), df]
3.导入“y”的数据。
y = pd.read_excel(xls, 'y', header=None)
由于这是一个数据帧,只需将列 0 作为一个系列,并使其二维,以匹配 x 的维度。
y = y[0]
y = y[:, np.newaxis]
这里,“y”只有一列。10 节课 10 栏。每个专栏将处理一个类。例如,当我们将处理类 10 时,我们将把 10 保留在它的位置,并用零替换其余的值。下面是函数 y_change,它将接受 y 本身和一个类(比如 3)。然后,它会用 1 替换 3,用所有其他类替换 0。在后面的步骤中很快就会用到这个函数。
def y_change(y, cl):
y_pr=[]
for i in range(0, len(y)):
if y[i] == cl:
y_pr.append(1)
else:
y_pr.append(0)
return y_pr
数据准备完成。现在开发模型:
4.定义假设函数。这与前面的方法相同。
def hypothesis(X, theta):
z = np.dot(X, theta)
return 1/(1+np.exp(-(z)))
5.开发成本函数。这一个也和前面的方法一样:
def cost_function(theta, X, y):
m = X.shape[0]
y1 = hypothesis(X, theta)
return -(1/len(X)) * np.sum(y*np.log(y1) + (1-y)*np.log(1-y1))
6.定义渐变。这个不一样。该函数定义了如何更新θ。
def gradient(theta, X, y):
m = X.shape[0]
y1 = hypothesis(X, theta)
return (1/m) * np.dot(X.T, y1 - y)
7.现在,导入优化函数并初始化θ。我取零作为初始θ值。任何其他值应该也可以。
from scipy.optimize import minimize, fmin_tnc
theta = np.zeros((X.shape[1], 1))
8.让我们创建一个拟合函数,它将 X,y 和θ作为输入。它将使用一个优化函数并为我们输出优化后的θ。
它需要这三个参数:
I .需要最小化的功能,
二。待优化的参数,
三。用于优化的参数。
在本例中,成本函数应最小化,θ需要为此进行优化。输入和输出变量 X 和 y 是要使用的参数。
这个优化函数采用另一个参数,即梯度。但这是可选的。这里,我们有一个关于梯度的公式或函数。所以我们正在通过它。
def fit(X, y, theta):
opt_weigths = fmin_tnc(func=cost_function, x0=theta,
fprime=gradient, args=(X, y.flatten()))
return opt_weigths[0]
9.使用这种拟合方法找到优化的θ。我们必须分别优化每个类的θ。让我们开发一个函数,其中对于每个类,将使用步骤 3 中的 y_change 方法相应地修改“y”。
def find_param(X, y, theta):
y_uniq = list(set(y.flatten()))
theta_list = []
for i in y_uniq:
y_tr = pd.Series(y_change(y, i))
y_tr = y_tr[:, np.newaxis]
theta1 = fit(X, y, theta)
theta_list.append(theta1)
return theta_list
用这种方法找到最终的θ
theta_list = find_param(X, y, theta)
10.是时候预测产量了。我们还必须单独预测各个类别。
def predict(theta_list, x, y):
y_uniq = list(set(y.flatten()))
y_hat = [0]*len(y)
for i in range(0, len(y_uniq)):
y_tr = y_change(y, y_uniq[i])
y1 = hypothesis(X, theta_list[i])
for k in range(0, len(y)):
if y_tr[k] == 1 and y1[k] >= 0.5:
y_hat[k] = y_uniq[i]
return y_hat
使用上述预测方法,计算预测输出 y_hat:
y_hat = predict(theta_list, X, y)
11.计算准确度
accuracy=0
for i in range(0, len(y)):
if y_hat[i] == y.flatten()[i]:
accuracy += 1
print(accuracy/len(df)*100)
**这个过程给出了 100%的准确率。**现在。你可以自己决定,你想在你的项目中使用哪种逻辑回归方法。
在本文中,使用神经网络解决了同样的问题,展示了如何从头开始开发神经网络:
神经网络的详细说明和逐步实现
medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6)
如果你有任何问题,请在评论区问我。查看 GitHub 页面获取数据集:
[## rashida 048/用 Python 进行机器学习
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/rashida048/Machine-Learning-With-Python/blob/master/ex3d1.xlsx)
这是梯度下降法代码的链接
[## rashida 048/用 Python 进行机器学习
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/rashida048/Machine-Learning-With-Python/blob/master/multicall_classification_with_logistic_regression.ipynb)
下面是优化函数方法 Github 链接的链接:
[## rashida 048/用 Python 进行机器学习
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/rashida048/Machine-Learning-With-Python/blob/master/multiclass_classification_with_fmin_tnc.ipynb)
推荐阅读:
学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法
towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8) [## Python 中多元线性回归的逐步实现
学习用 Python 从头开始开发任意数量变量的多元线性回归。
towardsdatascience.com](/multivariate-linear-regression-in-python-step-by-step-128c2b127171) [## Python 中从头开始的多项式回归
学习用一些简单的 python 代码从头开始实现多项式回归
towardsdatascience.com](/polynomial-regression-from-scratch-in-python-1f34a3a5f373) [## Python 中从头开始的完整异常检测算法:分步指南
基于概率的异常检测算法
towardsdatascience.com](/a-complete-anomaly-detection-algorithm-from-scratch-in-python-step-by-step-guide-e1daf870336e) [## 置信区间的完整指南,以及 Python 中的示例
对统计学中一个非常流行的参数——置信区间及其计算的深入理解
towardsdatascience.com](/a-complete-guide-to-confidence-interval-and-examples-in-python-ff417c5cb593)
多类分类和信息瓶颈——以 Keras 为例
使用 Keras 对路透社数据集中的新闻进行分类,看看神经网络如何杀死你的数据。
多类 分类 是对两类以上样本的分类。将样本精确地分为两类,通俗地称为二元分类。
这篇文章将设计一个神经网络,使用 Python 库 Keras 将路透社 1986 年发布的路透社数据集中的新闻影片分类为 46 个互斥类。这个问题是一个典型的单标签、多类分类问题。
由absolute vision在 Unsplash 上拍摄的照片
信息瓶颈
神经网络由许多层组成。每一层都对数据执行某种转换,将输入映射到网络的输出。但是,需要注意的是,这些层不会生成任何额外的数据,它们只处理从前面的层接收到的数据。
比方说,如果一个层丢失了一些相关数据,那么所有后续层都无法访问这些信息。这些信息将永久丢失,并且无法恢复。丢弃该信息的层现在充当了瓶颈,抑制了模型的准确性和性能的提高,从而充当了信息瓶颈。
稍后我们将看到这一点。
路透社的数据集
路透社数据集是一组简短的新闻报道,分为 46 个互斥的话题。路透社在 1986 年发表了它。这个数据集被广泛用于文本分类。共有 46 个主题,其中一些主题比其他主题出现得多。但是,在训练集中,每个主题至少包含十个示例。
路透社数据集预装了 Keras,包含 8982 个训练样本和 2246 个测试样本。
加载数据
从 Keras 中预先打包的模块加载数据。我们将把数据限制在 10,000 个最频繁出现的单词。为此,我们将num_words=10000
参数传递给load_data
函数。
代码由 rakshitraj 托管在 GitHub 上
一些探索性数据分析
我们将在数据集上执行一些老式的 EDA。这样做可以让我们对数据的广度和范围有一个大致的了解。
代码由 rakshitraj 托管在 GitHub 上
解读一个故事
让我们继续解码一个故事。解码帮助我们获得数据的组织和编码的要点。
代码由 rakshitraj 托管在 GitHub 上
准备数据
我们不能向神经网络输入整数序列;因此,我们将对每个序列进行矢量化,并将其转换为张量。我们通过对每个序列进行一键编码来做到这一点。
我们的训练和测试数据中有 10,000 个独特的元素。对我们的输入数据进行矢量化将产生两个 2D 张量;形状的训练输入张量(8982,10000)和形状的测试输入张量(2246,10000)。
由 rakshitraj 托管在 GitHub 上的代码
这个问题的标签包括 46 个不同的类。标签用 1 到 46 范围内的整数表示。为了对标签进行矢量化,我们可以,
- 将标签转换为整数张量
- 对标签数据进行一次性编码
我们将对标签数据进行一键编码。这将给我们张量,它的第二轴有 46 维。这可以使用 Keras 中的to_categorical
函数轻松完成。
为了更加清晰,我们将手动执行。
代码由 rakshitraj 托管在 GitHub 上
执行标签的一次性分类编码的另一种方法是使用内置函数,如上面的要点所示。为了清楚起见,这里又是:
from keras.utils.np_utils import to_categorical
Y_train = to_categorical(train_labels)
Y_test = to_categorical(test_labels)
构建神经网络
主题分类的问题(单标签多类分类 _)类似于文本字段的 _ 二元分类。这两个问题都遵循类似的数据处理和预处理方法。实现神经网络的教学方法保持不变。然而,有一个新的限制:类的数量从 2 个增加到 46 个。输出空间的维度要高得多。
因此,每一层都必须处理更多的数据,这就出现了真正的信息瓶颈。
信息瓶颈
给定一个多类分类问题,与二进制分类问题相比,我们需要对数据执行的处理量显著增加。
在密集层的堆栈中,就像我们所使用的,每一层只能访问前一层输出中的信息。如果一个层丢弃了相关信息,该信息对于所有后续层都是永久不可访问的。信息一旦丢失,就永远不能被后面的层恢复。在像多类分类这样的情况下,数据是有限且关键的,每一层都可能成为信息瓶颈。
如果一个层丢失了相关的信息,这可能是一个信息瓶颈。
这些层很容易成为我们网络性能的瓶颈。为了确保关键数据不会被丢弃,我们将使用具有更多隐藏单元的层,即更大的层。为了比较,我们在 IMDB 评论的情感分析的两类分类示例中,使用具有 16 个隐藏单元 *Dense(16)*
的层。在这种情况下,输出维度是 46,我们将使用 64 个隐藏单元的层,Dense(64)
。
模型定义
我们将用两个全连接的 ReLU 激活层来定义我们的网络,每个层有 64 个隐藏单元。第三和最后一层将是尺寸为 46 的致密层。该层将使用一个 softmax 激活,并将输出一个 46 维矢量。每一维都是属于该类的输入的概率。
代码由 rakshitraj 托管在 GitHub 上
编译模型
对于我们的网络,我们将使用优化器 rmsprop
、loss function、categorical_crossentropy
,并将监控模型的accuracy
(metrics)。
代码由 rakshitraj 托管在 GitHub 上
设置验证集
由 rakshitraj 托管在 GitHub 上的代码
训练我们的模型
最初,我们将在 512 个样本的小批量中为 20 个时期训练我们的模型。我们还将把我们的验证集传递给fit
方法。
由 rakshitraj 托管在 GitHub 上的代码
调用fit
方法返回一个History
对象。这个对象包含一个成员history
,它存储了关于训练过程的所有数据,包括随着时间的推移可观察到的或监控到的量的值。我们将保存该对象,因为它包含的信息将帮助我们确定更好地应用于训练步骤的微调。
在训练结束时,我们达到了 95%的训练准确率和 80.9%的验证准确率
既然我们已经训练了我们的网络,我们将观察存储在History
对象中的性能指标。
调用fit
方法返回一个History
对象。这个对象有一个属性history
,它是一个包含四个条目的字典:每个被监控的指标一个条目。
由 rakshitraj 托管在 GitHub 上的代码
history_dict
包含以下值
- 培训损失
- 训练准确性
- 验证损失
- 验证准确性
在每个时期结束时。
让我们使用 Matplotlib 并排绘制训练和验证损失以及训练和验证准确性。
培训和验证损失
损失与时代
代码由 rakshitraj 托管在 GitHub 上
培训和验证准确性
模型与时代的准确性
代码由 rakshitraj 托管在 GitHub 上
过度拟合:损失和精度数据的趋势
我们观察到最小验证损失和最大验证准确度在大约 9-10 个时期达到。之后,我们观察到两个趋势:
- 验证损失增加,培训损失减少
- 验证准确性降低,培训准确性提高
这意味着该模型在对训练数据的情绪进行分类方面越来越好,但当它遇到新的、以前从未见过的数据时,会做出持续更差的预测,这是过度拟合的标志。在第 10 个时期之后,模型开始过于接近训练数据。
为了解决过度拟合的问题,我们将把历元的数量减少到 9。这些结果可能会因您的机器以及不同型号的随机重量分配的本质而异。
在我们的情况下,我们将在九个纪元后停止训练。
从头开始重新训练我们的模型
既然我们知道过多的时期导致我们的模型过度拟合,我们将限制时期的数量并从头重新训练我们的模型。
代码由 rakshitraj 托管在 GitHub 上
预测结果和评估
代码由 rakshitraj 托管在 GitHub 上
我们的方法产生了大约 80%的效率
如果这是一个平衡的数据集,使用简单的概率,标签的随机属性将导致 50%的准确性。但是由于这个数据集是不平衡的,随机分类器的准确性可能会更低。
随机分类器随机给样本分配标签。客观地说,你当地动物园的黑猩猩会用随机分类器来分类这些新闻短片。
让我们确定这个随机基线:
代码由 rakshitraj 托管在 GitHub 上
考虑到随机基线约为 19%,我们的模型以约 80%的准确度表现得相当好。
一个信息瓶颈模型
这次我们在模型中引入了一个信息瓶颈。我们的一个图层将会丢失数据,我们将会看到它对模型性能的影响,即其准确性的下降。
由 rakshitraj 托管在 GitHub 上的代码
存在瓶颈时,测试精度会下降 10%
结论
至此,您已经成功地将路透社数据集中的新闻短片按照各自的主题进行了分类。您还将看到隐藏单元数量不足的层如何通过杀死宝贵的数据来破坏模型的性能。
信息瓶颈的影响是显而易见的,因为预测准确性大大降低。
我建议你配合这篇文章。您可以使用类似的策略解决大多数多类分类问题。如果你解决了这个问题,试着修改网络及其层的设计和参数。这样做将帮助您更好地理解您所选择的模型的属性和架构。
我在每篇文章中都详细讨论了一个话题。在这一篇中,我们探索了信息瓶颈。对任何特定主题的详尽解释从来不在我的写作范围之内;然而,你会发现大量的快速旁白。
我假设读者不是机器学习领域的完全新手。我在这篇文章之前和之前的更多工作链接如下;
使用 Keras 根据情感对评论进行分类。
towardsdatascience.com](/binary-classification-of-imdb-movie-reviews-648342bc70dd) [## 解决 MNIST 图像分类问题
“你好,世界!”深度学习和 Keras
towardsdatascience.com](/solve-the-mnist-image-classification-problem-9a2865bcf52a)
想了解更多,请查看我发誓的书——Francois Chollet 的《用 Python 进行深度学习》。
感谢阅读!