如何训练 _ 测试 _ 拆分:KFold vs StratifiedKFold
举例说明
伊丽莎白躺在 Unsplash 上
监督学习任务中使用的数据包含一组观察值的特征和标签。这些算法试图对特征(自变量)和标签(因变量)之间的关系进行建模。我们首先通过为一些观察结果提供特征和标签来训练模型。然后通过仅提供特征并期望它预测标签来测试模型。因此,我们需要将数据分成训练和测试子集。我们让模型在训练集上学习,然后在测试集上测量它的性能。
Scikit-learn 库提供了许多工具来将数据分成训练集和测试集。最基本的一个是 train_test_split ,它只是按照指定的划分比例将数据分成两部分。例如,**train _ test _ split(test _ size = 0.2)**将留出 20%的数据用于测试,80%用于训练。让我们看一个例子。我们将创建一个带有一个要素和一个标签的示例数据帧:
import pandas as pd
import numpy as nptarget = np.ones(25)
target[-5:] = 0df = pd.DataFrame({'col_a':np.random.random(25),
'target':target})df
然后我们应用 train_test_split 函数:
from sklearn.model_selection import train_test_splitX = df.col_a
y = df.targetX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)print("TRAIN:", X_train.index, "TEST:", X_test.index)
前 80%是训练,后 20%是测试集。如果我们将 shuffle 参数设置为真,数据将被随机分割:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True)print("TRAIN:", X_train.index, "TEST:", X_test.index)
shuffle 的默认值为 True,因此如果我们不指定 shuffle 参数,数据将被随机拆分。如果我们希望分割是可再现的,我们还需要将一个整数传递给 random_state 参数。否则,每次我们运行 train_test_split 时,不同的索引将被拆分成训练集和测试集。请注意,输出中看到的数字是数据点的索引,而不是实际值。
数据是宝贵的资产,我们希望充分利用它。如果我们使用 train_test_split 来拆分数据,我们只能使用为培训而留出的部分来培训模型。随着训练数据量的增加,模型变得更好。克服这个问题的一个解决方案是**交叉验证。**通过交叉验证,数据集被分成 n 份。N-1 分割用于训练,剩余的分割用于测试。该模型遍历整个数据集 n 次,每次都使用不同的分割进行测试。因此,我们使用所有的数据点进行训练和测试。交叉验证也有助于更准确地衡量模型的性能,尤其是在新的、以前看不到的数据点上。
交叉验证中有不同的数据分割方法。常用的有折叠和分层折叠。
KFold
顾名思义,KFold 将数据集分成 k 个折叠。如果 shuffle 设置为 False,连续折叠将是前一个折叠的移位版本:
X = df.col_a
y = df.targetkf = KFold(n_splits=4)for train_index, test_index in kf.split(X):
print("TRAIN:", train_index, "TEST:", test_index)
在第一次迭代中,测试集是前四个索引。然后 KFold 不断移动测试集 k 次。如果 shuffle 设置为 True,那么拆分将是随机的。
kf = KFold(n_splits=4, shuffle=True, random_state=1)for train_index, test_index in kf.split(X):
print("TRAIN:", train_index, "TEST:", test_index)
分层折叠
StratifiedKFold 将交叉验证向前推进了一步。数据集中的类分布保留在训练和测试拆分中。让我们来看看我们的示例数据框架:
有 16 个数据点。其中 12 人属于 1 级,其余 4 人属于 0 级,因此这是一个不平衡的等级分布。KFold 没有考虑到这一点。因此,在类别分布不平衡的分类任务中,我们应该优先选择 StratifiedKFold 而不是 KFold。
0 类和 1 类的比例是 1/3。如果我们设置 k=4,那么测试集包括来自类 1 的三个数据点和来自类 0 的一个数据点。因此,训练集包括来自类 0 的三个数据点和来自类 1 的九个数据点。
skf = StratifiedKFold(n_splits=4)for train_index, test_index in skf.split(X, y):
print("TRAIN:", train_index, "TEST:", test_index)
等级 0 的指数是 12、13、14 和 15。正如我们所看到的,数据集的类分布保留在分割中。我们也可以对 StratifiedKFold 使用洗牌:
skf = StratifiedKFold(n_splits=4, shuffle=True, random_state=1)for train_index, test_index in skf.split(X, y):
print("TRAIN:", train_index, "TEST:", test_index)
另一种用于分割的方法被称为“留一个出来”,该方法仅使用一个数据点进行测试,剩余的数据点用于训练。Scikit learn 有 LeaveOneOut 类来执行这种类型的分区。
最后,我想提一下 scikit 提供的另一个重要工具——learn,即 cross_val_score。
Cross_val_score 获取数据集并应用交叉验证来拆分数据。然后,使用指定的估计器(如逻辑回归、决策树等)训练模型,并测量模型的性能(评分参数)。
感谢您的阅读。如果您有任何反馈,请告诉我。
如何用简单的变形金刚训练你的聊天机器人
创造一个令人惊叹的对话式人工智能并不一定很难,当然也不需要花几个月的时间!迁移学习是方法。
Bewakoof.com 官方在 Unsplash 上的照片
介绍
曾经主要出现在科幻小说中的聊天机器人和虚拟助手正变得越来越普遍。今天的谷歌助手和 Siri 还有很长的路要走,才能达到钢铁侠的 J.A.R.V.I.S .等,但旅程已经开始。虽然目前的对话式人工智能远非完美,但它们也远非像伊莱扎(ELIZA)这样的简单程序那样卑微。
远离典型的基于规则的聊天机器人,拥抱脸想出了一种基于转换器的方法来构建聊天机器人,让我们利用伯特和开放 GPT 等模型的最先进的语言建模能力。使用这种方法,我们可以快速构建强大而令人印象深刻的对话式人工智能,它可以超越大多数基于规则的聊天机器人。它还消除了构建良好的基于规则的聊天机器人所需的繁琐的规则构建和脚本编写。
简单变形金刚提供了一种快速、高效、简单地构建这些对话式人工智能模型的方法。简单的变形金刚实现建立在拥抱脸实现的基础上,这里给出了和。
设置
设置环境相当简单。
- 从这里安装 Anaconda 或 Miniconda 包管理器
- 创建新的虚拟环境并安装软件包。
conda create -n transformers python
conda activate transformers
如果使用 Cuda:
conda install pytorch cudatoolkit=10.1 -c pytorch
其他:
conda install pytorch cpuonly -c pytorch
- 如果您使用 fp16 培训,请安装 Apex。请遵循此处的说明。(从 pip 安装 Apex 给一些人带来了问题。)
- 安装简单变压器。
pip install simpletransformers
资料组
我们将使用人物聊天数据集。请注意,您不需要手动下载数据集,因为如果在训练模型时没有指定数据集,简单转换器将自动下载数据集的格式化 JSON 版本(由 Hugging Face 提供)。
对话式人工智能模型
是在简单变形金刚中使用的类,用来做所有与对话式人工智能模型相关的事情。这包括培训、评估和与模型的交互。
目前,你可以通过ConvAIModel
使用任何一款 OpenAI GPT 或 GPT-2 型号。然而,拥抱脸提供的预训练模型开箱即用性能良好,在创建自己的聊天机器人时可能需要较少的微调。您可以从这里的下载模型,并解压文档以跟随教程(假设您已经下载了模型并解压到gpt_personachat_cache
)。
上面的代码片段创建了一个ConvAIModel
,并用预先训练好的权重加载转换器。
ConvAIModel
配有多种配置选项,可在文档中找到,此处为。您还可以在简单的 Transformers 库中找到全局可用的配置选项列表。
培养
您可以通过简单地调用train_model()
方法来进一步微调角色聊天训练数据的模型。
这将下载数据集(如果尚未下载)并开始训练。
要根据您自己的数据训练模型,您必须创建一个具有以下结构的 JSON 文件。
该结构遵循下面解释的角色聊天数据集中使用的结构。(文档此处)
Persona-Chat 中的每个条目都是一个字典,有两个键personality
和utterances
,数据集是一个条目列表。
personality
: 包含代理人个性的字符串列表utterances
: 字典列表,每个字典有两个键,分别是字符串列表。candidates
:【下一个 _ 话语 _ 候选人 _1…下一个候选是在会话数据中观察到的基本事实响应history
:【dialog _ turn _ 0,…dialog_turn N],其中 N 是奇数,因为其他用户开始每个对话。
预处理:
- 句末句号前的空格
- 全部小写
假设您已经创建了一个具有给定结构的 JSON 文件,并将其保存在data/train.json
中,您可以通过执行下面的行来训练模型。
model.train_model("data/minimal_train.json")
估价
通过调用eval_model()
方法,可以对角色聊天数据集进行评估,就像训练一样简单。
与培训一样,您可以提供不同的评估数据集,只要它遵循正确的结构。
互动
虽然你可以通过计算评估数据集的指标来获得数字分数,但了解对话式人工智能有多好的最好方法是与它进行实际对话。
要与您刚刚训练的模型对话,只需调用model.interact()
。这将从数据集中选择一个随机的个性,并让你从终端与之对话。
model.interact()
或者,您可以通过给interact()
方法一个字符串列表来创建一个动态的角色!
包扎
提示:要加载一个经过训练的模型,您需要在创建ConvAIModel
对象时提供包含模型文件的目录的路径。
model = ConvAIModel("gpt", "outputs")
就是这样!我希望这篇教程能帮助你创建自己的聊天机器人!
如何训练回归而不失去真实感
培训和分析中的常见陷阱
詹姆斯·霍姆通过皮克斯贝拍摄的照片(CC0)
在无所不包的人工智能时代,如果我们有足够的数据,很容易陷入机器学习(ML)可以最终解决任何问题的想法。在这里,以一个大的带标签的数据集为例,我们发现当大量的数据不够时,没有领域专业知识的 ML 的直接应用是如何误导的,以及我们有什么工具来避免错觉。
大纲
-材料科学中的数据科学
-特征化
-用神经网络回归
-范畴分类
-随机森林能表现得更好吗?
-混淆矩阵
-数据扩充&分析
我们想要解决的一个问题存在于组合学、概率和材料科学中。为了在技术上取得进步,我们需要发现新的更高效的材料:磁铁、压电材料、你刚刚在屏幕上触摸向下滚动的透明导电氧化物,或者其他许多材料。大多数现代材料是多组分的,由三种或三种以上的原子元素组成。随着集合中元素数量的增加,组合搜索很快变得难以处理。为了进一步测试研究人员的士气,不是所有的原子组合都能产生稳定的成分,更不用说功能性的了。
图二。原子元素周期表。一组随机的原子会形成一种新材料吗?
经过几十年的研究和实验,我们已经收集了超过 200,000 种材料的数据库[1],其中几千种材料由不同的原子组成,这将构成我们的训练数据集。我们的目标是预测一组新的原子是否可能富含新的稳定物质。
特色化
为了尽可能多地编码关于一组元素的信息,可以使用元素描述符:原子序数、质量、价电子数等来产生候选集合的多维向量。我们可以从参考文献中选择 40 种不同的原子描述符。2,构成 4 个元素的候选集合的 160 个特征。
高度相关的特征增加了复杂性,同时没有提供额外的描述。一个好的做法是确保描述符是正交的和可缩放的。
来自实验数据库的目标是由一组特定元素组成的大量实验验证的稳定材料——对于一些组,它小到 1,对于另一些组,大到 162。
# An example of featurisation
import numpy as np
def symbols2numbers(data, symbols, tables):
''' Featurisation of atomic sets into a n-dim vectors
data are atomic sets of interests
symbols are atomic symbols
tables are tabulated elemental descriptors, i.e.
atomic numbers, masses, etc.''' transit = [ {} for i in range(len(tables))]
for i, table in enumerate(tables):
transit[i] = {sym: num for sym, num in zip(symbols, table)}
vectors = []
for set in data:
for atom in set:
numbers = [t[atom] for t in transit]
vectors.append(numbers)
return np.asarray(vectors)
回归
我们将尝试训练一个深度神经网络(NN)来识别一组元素的 160 个特征的函数形式,从而产生许多[一组的稳定成分]。我们从实验神经网络架构开始——向层中添加节点并将层堆叠起来。我们的度量是回归损失函数。我们也可以试验它的形式,但是具有均方误差(mse)的稳定解决方案应该足以看到损失很大,更糟糕的是,它不会随着训练的进行而减少。
在选择验证集时,必须小心谨慎。具有多个时期和自适应学习率的大型 NN 可以减少训练期间的损失——事实上,如果验证损失仍然很大,这可能只是过度拟合的迹象。
将自适应 momenta optimizer (Adam)更改为随机梯度下降,并将内斯特罗夫 momenta 更新作为最后手段,说服我们回到我们应该开始的地方——分析用于训练的可用数据。
# Implementation of a NN with one hidden layerfrom keras.model import Sequential
from keras.layers import Dense, Dropout
from keras.callbacks import ReduceLROnPlateau
from sklearn.preprocessing import StandardScalerx_train = symbols2numbers(data, symbols, tables)
x_train = StandardScaler().fit_transform(x_train)
original_dim = x_train.shape[1]model = Sequential()
model.add(Dense(
original_dim,
activation='relu',
input_shape=(original_dim,),
activity_regularizer=l2(0.1)))
model.add(Dropout(0.2))
model.add(Dense(
original_dim,
activation='relu',
input_shape=(original_dim,),
activity_regularizer=l2(0.1)))
model.add(Dropout(0.2))
model.add(Dense(1))
model.compile(loss='mse',optimizer='adam')rlr = ReduceLROnPlateau(
monitor='val_loss',
factor=0.2, patience=10, min_lr=1e-8)
model.fit(x_train, y_train,
batch_size=30,
shuffle=True,
validation_split=0.1,
epochs=100,
callbacks=[rlr])
checkback = model.predict(x_train)
分类
我们的数据严重不平衡:超过 50%的 4 原子组只有 1 个稳定的组成。为了改善平衡,我们可以通过增加稳定成分的数量来将数据分成标记组。
回归依赖于数据平衡。如果数据删减或增加是不可能的,将数据分成不同的类别可能会实现分类。
因此,我们将损失函数改为分类交叉熵,将“softmax”激活添加到输出层,并重新训练 NN 进行分类。这减少了几次交互后的验证损失函数,但是模型仍然不足:它将所有原子集作为最有可能的集合归入第一组。
我们可以进一步简化任务,将数据分成两半:一个和多个稳定成分——现在两组平衡,第一组(一个稳定成分)的目标为 0,第二组(多个稳定成分)的目标为 1。损失函数:二元交叉熵。再培训。不合身。所有人的概率相等:55%对 45%。
随机森林能表现更好吗?
这是一个流行的问题。诚实的回答是,视情况而定。众所周知,具有大型决策树集合的随机森林(RF)分类器可以防止过拟合,并适于特征工程,例如处理缺失值。此外,RF 还可以用于多项选择分类和回归,这使得该模型在各种应用中具有通用性[3]。
from sklearn.model_selection import cross_val_score as cvs
from sklearn.model_selection import RepeatedStratifiedKFold as RSKF
from sklearn.ensemble import RandomForestClassifier as RF
from sklearn.preprocessing import StandardScaler, LabelEncoderdef evaluate(model, x, y)
''' Model evaluation in cross-validation '''
cv = RSKF(n_splits=5, n_repeats=3, random_state=1)
scores = cvs(model, x, y, scoring='accuracy', cv=cv, n_jobs=4)
return scoresx_train = symbols2numbers(data, symbols, tables)
x_train = StandardScaler().fit_transform(x_train)model = RF(n_estimators=1000)
scores = evaluate(x_train, y_train, RF(n_estimators=1000))
model.fit(x_train,y_train)
checkback = model.predict(x_train)
使用默认的超参数,在交叉验证中对模型的评估证明了 70%的准确性。对保留的 1000 个标记数据条目(在训练期间没有暴露给模型)的预测产生以下混淆矩阵,
从中我们计算出相关的度量:
精度= TP/(TP+FP)= 100%
NPV = TN/(TN+FN)= 35%
召回= TP/(TP+FN)= 4%
TNR = TN/(TN+FP)= 100%
准确率= (TP + TN) /总计= 37%
当与其他指标分开考虑时,定量指标(如准确度或精确度)可能会产生误导,因为它们并不总是您模型的最佳指标。
F1 =精度*召回率/ 2(精度+召回率)= 22%
平衡精度= (TPR + TNR) /2 = 52 %
在我们的模型中,精度很高,因为零假阴性。然而,我们对预测尽可能多的真阳性感兴趣,因为这些是产生多种稳定成分的原子集合。但是召回的车型太少了。
所以一节问题的答案是
在特定的问题设置中,RF 可以胜过 NN。通过在 scikit-learn 中作为黑盒模型的简单实现,RF 可以是建立基本线的分类器的首选。
数据扩充、分析和结论
有许多数据扩充技术可以通过增强机器学习和促进优化来击败欠拟合。一些技术,例如图像反射,也有助于评估模型,因为您可能会对反射图像有相同的预测。
数据扩充可以通过改进优化来帮助克服欠拟合。一些增强方法,例如图像反射,也有助于评估。
在我们的问题中,我们可以通过原子集的排列来增加数据流形,因为你选择原子形成新材料的顺序不应该影响结果。观察具有排列不变性的真阳性,我们发现它们的数量甚至更少,最终丢弃该模型。
总之,在上述假设的基础上,仅仅通过观察组成原子集合来预测丰富物质相的 ML 的雄心勃勃的目标是无法实现的。这里的一个薄弱环节不是我们拥有的数据量,而是数据不完整的事实:我们的标签(报告的情况)很可能是错误的,因为我们并不真正知道自然实际上允许给定原子集有多少稳定的组成。这并不奇怪,毕竟,大多数原子集合只被报道一次,因为实验者倾向于竞相发现新的相位场。
在科学传统中,有一个确实是最积极的,那就是不报告失败。这对于数据有偏差效应(没有负面影响),并且不利于进步的速度,因为我们不可避免地会沿着错误的路线前进,这些错误的路线可能已经被发现了多次,但是被保密了。我希望,上面描述的常见陷阱和问题设置列表将有助于在一个面向数据的时代减轻积极传统的影响。
参考
[1] 无机晶体结构数据库
【2】A Seko,A Togo,I Tanaka,材料数据机器学习的描述符,纳米信息学。新加坡斯普林格。
【3】Saimadhu pola muri,随机森林在机器学习中如何工作。
PyTorch【基础】—张量和亲笔签名
如何训练你的神经网络[图片[0]]
如何训练你的神经网络
这篇博文将带您了解一些最常用的张量运算,并演示 PyTorch 中的自动签名功能。
随着 PyTorch 的大肆宣传,我决定冒险在 2019 年底学习它。开始有点困难,因为没有太多适合初学者的教程(在我看来)。有一些博客文章只是浏览了一个模型实现,其中到处都有一些深度学习理论,或者有一个巨大的 Github repo,其中有几个 python 脚本,实现了一个具有多个依赖关系的超级复杂的模型。
在这两种情况下,你都会想——“呃……什么?”
安德烈·卡帕西为 PyTorch 发的推文[图片[1]]
在使用 PyTorch 一段时间后,我发现它是最好的深度学习框架。因此,在 2020 年,我决定每两周(希望是:P)发表一篇博文,介绍我在 PyTorch 1.0+ 中在时间序列预测、NLP 和计算机视觉领域实现的一些东西。
这 4 大类是——py torch[基础]、py torch[表格]、PyTorch[NLP]和 py torch[远景]。
在这篇博文中,我们将实现一些最常用的张量运算,并谈一谈 PyTorch 中的自动签名功能。
导入库
import numpy as np
import torch
from torch.autograd import grad
张量运算
创建一个单位化张量
长张量。
x = torch.LongTensor(3, 4)
print(x) ################## OUTPUT ##################tensor([[140124855070912, 140124855070984, 140124855071056, 140124855071128],
[140124855071200, 140124855071272, 140124855068720, 140125080614480],
[140125080521392, 140124855066736, 140124855066800, 140124855066864]])
浮点张量。
x = torch.FloatTensor(3, 4)
print(x) ################## OUTPUT ##################tensor([[1.7288e+25, 4.5717e-41, 1.7288e+25, 4.5717e-41],
[0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00],
[0.0000e+00, 2.7523e+23, 1.8788e+31, 1.7220e+22]])
手动创建张量
x1 = torch.tensor([[1., 2., 3.], [4., 5., 6.]])
x1 ################## OUTPUT ##################tensor([[1., 2., 3.],
[4., 5., 6.]])
从列表中创建张量
py_list = [[1, 2, 3], [4, 5, 6]]
print('List: \n', py_list, '\n')print('Tensor:')
print(torch.tensor(py_list)) ################## OUTPUT ##################List:
[[1, 2, 3], [4, 5, 6]] Tensor:
tensor([[1, 2, 3],
[4, 5, 6]])
从 numpy 数组创建张量
numpy_array = np.random.random((3, 4)).astype(float)
print('Float numpy array: \n', numpy_array, '\n')print('Float Tensor:')
print(torch.FloatTensor(numpy_array)) ################## OUTPUT ##################Float numpy array:
[[0.03161911 0.52214984 0.06134578 0.03143846]
[0.72253513 0.1396692 0.14399402 0.02879052]
[0.01618331 0.41498778 0.60040201 0.95173069]] Float Tensor:
tensor([[0.0316, 0.5221, 0.0613, 0.0314],
[0.7225, 0.1397, 0.1440, 0.0288],
[0.0162, 0.4150, 0.6004, 0.9517]])
将张量转换为 numpy 数组
print('Tensor:')
print(x1)print('\nNumpy array:')
print(x1.numpy()) ################## OUTPUT ##################Tensor:
tensor([[1., 2., 3.],
[4., 5., 6.]])Numpy array:
[[1\. 2\. 3.]
[4\. 5\. 6.]]
在一个范围内创建张量
长型张量。
# Create tensor from 0 to 10.
torch.arange(10, dtype=torch.long) ################## OUTPUT ##################tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
浮点型张量。
torch.arange(10, dtype=torch.float) ################## OUTPUT ##################tensor([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
用随机值创建张量
torch.randn(3, 4) ################## OUTPUT ##################tensor([[ 0.6797, 1.3238, -0.5602, -0.6977],
[ 1.1281, -0.8198, -0.2968, -0.1166],
[ 0.8521, -1.0367, 0.5664, -0.7052]])
只有正数。
torch.rand(3, 4) ################## OUTPUT ##################tensor([[0.8505, 0.8817, 0.2612, 0.8152],
[0.6652, 0.3061, 0.0246, 0.4880],
[0.7158, 0.6929, 0.4464, 0.0923]])
创建张量作为单位矩阵
torch.eye(3, 3) ################## OUTPUT ##################tensor([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
创建全零张量
torch.zeros(3, 4) ################## OUTPUT ##################tensor([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
创建全 1 张量
torch.ones(3, 4) ################## OUTPUT ##################tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
索引张量
print(x1, '\n')
print(f"Tensor at x1[0,0] = {x1[0, 0]}")
print(f"Tensor at x1[1,2] = {x1[1, 2]}")
print(f"0th column of x1 = {x1[:, 0]}")
print(f"1st row of x1 = {x1[1, :]}") ################## OUTPUT ##################tensor([[1., 2., 3.],
[4., 5., 6.]]) Tensor at x1[0,0] = 1.0
Tensor at x1[1,2] = 6.0
0th column of x1 = tensor([1., 4.])
1st row of x1 = tensor([4., 5., 6.])
张量的形状
print(x1, '\n')
print(x1.shape) ################## OUTPUT ##################tensor([[1., 2., 3.],
[4., 5., 6.]]) torch.Size([2, 3])
重塑张量
创建一个张量。
x2 = torch.arange(10, dtype=torch.float)
x2 ################## OUTPUT ##################tensor([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
使用.view
重塑张量。
x2.view(2, 5) ################## OUTPUT ##################tensor([[0., 1., 2., 3., 4.],
[5., 6., 7., 8., 9.]])
-1
根据张量的大小自动识别维度。
x2.view(5, -1) ################## OUTPUT ##################tensor([[0., 1.],
[2., 3.],
[4., 5.],
[6., 7.],
[8., 9.]])
使用.reshape
整形。
x2.reshape(5, -1) ################## OUTPUT ##################tensor([[0., 1.],
[2., 3.],
[4., 5.],
[6., 7.],
[8., 9.]])
改变张量轴
view
和permute
略有不同。view
改变张量的顺序,而permute
仅改变轴。
print("x1: \n", x1)
print("\nx1.shape: \n", x1.shape)
print("\nx1.view(3, -1): \n", x1.view(3, -1))
print("\nx1.permute(1, 0): \n", x1.permute(1, 0)) ################## OUTPUT ##################x1:
tensor([[1., 2., 3.],
[4., 5., 6.]])x1.shape:
torch.Size([2, 3])x1.view(3, -1):
tensor([[1., 2.],
[3., 4.],
[5., 6.]])x1.permute(1, 0):
tensor([[1., 4.],
[2., 5.],
[3., 6.]])
获取张量的内容
print(x2)
print(x2[3])
print(x2[3].item()) ################## OUTPUT ##################tensor([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
tensor(3.)
3.0
得到张量的平均值
print(x1)
torch.mean(x1) ################## OUTPUT ##################tensor([[1., 2., 3.],
[4., 5., 6.]])tensor(3.5000)
获取张量中值的和
print(x1)
torch.sum(x1) ################## OUTPUT ##################tensor([[1., 2., 3.],
[4., 5., 6.]])tensor(21.)
获取张量的 e^x 值
print(x1)
torch.exp(x1) ################## OUTPUT ##################tensor([[1., 2., 3.],
[4., 5., 6.]])tensor([[ 2.7183, 7.3891, 20.0855],
[ 54.5981, 148.4132, 403.4288]])
张量算术运算
x3 = torch.randn(5, 2)
x4 = torch.randn(5, 2)print(f"x3 + x4 = \n{x3 + x4}\n")
print(f"x3 - x4 = \n{x3 - x4}\n")
print(f"x3 * x4 (element wise)= \n{x3 * x4}\n")
# You can also do [x3 @ x4.t()] for matrix multiplication.
print(f"x3 @ x4 (matrix mul)= \n{torch.matmul(x3, x4.t())}\n") ################## OUTPUT ##################x3 + x4 =
tensor([[-0.1989, 1.9295],
[-0.1405, -0.8919],
[-0.6190, -3.6546],
[-1.4263, -0.1889],
[ 0.7664, -0.6130]])x3 - x4 =
tensor([[ 1.5613, -1.8650],
[-2.2483, -1.9581],
[ 0.4915, 0.6334],
[ 2.0189, -2.8248],
[-2.5310, -4.7337]])x3 * x4 (element wise)=
tensor([[-0.5995, 0.0612],
[-1.2588, -0.7597],
[ 0.0354, 3.2387],
[-0.5104, -1.9860],
[-1.4547, -5.5080]])x3 @ x4 (matrix mul)=
tensor([[-0.5384, 0.7351, -0.4474, -1.1310, 1.1895],
[-1.6525, -2.0185, 3.7184, 0.1793, -4.9052],
[-2.8099, -0.8725, 3.2741, -1.8812, -3.2174],
[-3.1196, -0.4
连接张量
连接行。
x5, x6 = torch.randn(4, 7), torch.randn(3, 7)
print('X5:', x5.shape)
print(x5)
print('\nX6:', x6.shape)
print(x6)print('\nConcatenated tensor', torch.cat((x5, x6)).shape)
print(torch.cat((x5, x6))) ################## OUTPUT ##################X5: torch.Size([4, 7])
tensor([[ 0.9009, -0.7907, 0.2602, -1.4544, 1.0479, -1.1085, 0.9261],
[ 0.2041, -1.2046, -0.8984, 1.6531, 0.2567, -0.0466, 0.1195],
[-0.7890, -0.0156, 0.2190, -1.5073, -0.2212, 0.4541, 0.7874],
[ 0.7968, -0.1711, -1.0618, -0.1209, -0.4825, -0.7380, -2.1153]])X6: torch.Size([3, 7])
tensor([[-1.1890, 0.1310, 1.7379, 1.8666, 1.4759, 1.9887, 1.1943],
[ 0.1609, -0.3116, 0.5274, 1.3037, -1.2190, -1.6068, 0.5382],
[ 1.0021, 0.5119, 1.7237, -0.3709, -0.1801, -0.3868, -1.0468]])Concatenated tensor torch.Size([7, 7])
tensor([[ 0.9009, -0.7907, 0.2602, -1.4544, 1.0479, -1.1085, 0.9261],
[ 0.2041, -1.2046, -0.8984, 1.6531, 0.2567, -0.0466, 0.1195],
[-0.7890, -0.0156, 0.2190, -1.5073, -0.2212, 0.4541, 0.7874],
[ 0.7968, -0.1711, -1.0618, -0.1209, -0.4825, -0.7380, -2.1153],
[-1.1890, 0.1310, 1.7379, 1.8666, 1.4759, 1.9887, 1.1943],
[ 0.1609, -0.3116, 0.5274, 1.3037, -1.2190, -1.6068, 0.5382],
[ 1.0021, 0.5119, 1.7237, -0.3709, -0.1801, -0.3868, -1.0468]])
串联列。
x7, x8 = torch.randn(3, 3), torch.randn(3, 5)
print('X7:', x7.shape)
print(x7)
print('\nX8:', x8.shape)
print(x8)print('\nConcatenated tensor', torch.cat((x7, x8), 1).shape)
print(torch.cat((x7, x7), 1)) ################## OUTPUT ##################X7: torch.Size([3, 3])
tensor([[-1.1606, 1.5264, 1.4718],
[ 0.9691, -0.1215, -0.1852],
[-0.5792, -1.2848, -0.8485]])X8: torch.Size([3, 5])
tensor([[ 0.3518, -0.2296, 0.5546, 1.5093, 1.6241],
[ 0.8275, -1.1022, -0.1441, -0.3518, 0.4338],
[-0.1501, -1.1083, 0.3815, -0.5076, 0.5819]])Concatenated tensor torch.Size([3, 8])
tensor([[-1.1606, 1.5264, 1.4718, -1.1606, 1.5264, 1.4718],
[ 0.9691, -0.1215, -0.1852, 0.9691, -0.1215, -0.1852],
[-0.5792, -1.2848, -0.8485, -0.5792, -1.2848, -0.8485]])
查找张量中的最小值/最大值
print('Tensor x1:')
print(x1)print('\nMax value in the tensor:')
print(torch.max(x1))print('\nIndex of the max value in the tensor')
print(torch.argmax(x1))print('\nMin value in the tensor:')
print(torch.min(x1))print('\nIndex of the min value in the tensor')
print(torch.argmin(x1)) ################## OUTPUT ##################Tensor x1:
tensor([[1., 2., 3.],
[4., 5., 6.]]) Max value in the tensor:
tensor(6.) Index of the max value in the tensor
tensor(5) Min value in the tensor:
tensor(1.) Index of the min value in the tensor
tensor(0)
从张量中删除维度
torch.squeeze()
从张量中删除所有一维部分。
x9 = torch.zeros(2, 1, 3, 1, 5)
print('Tensor:')
print(x9)print('\nTensor shape:')
print(x9.shape)print('\nTensor after torch.squeeze():')
print(x9.squeeze())print('\nTensor shape after torch.squeeze():')
print(x9.squeeze().shape) ################## OUTPUT ##################Tensor:
tensor([[[[[0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.]]]], [[[[0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.]]]]])Tensor shape:
torch.Size([2, 1, 3, 1, 5])Tensor after torch.squeeze():
tensor([[[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]], [[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]])Tensor shape after torch.squeeze():
torch.Size([2, 3, 5])
另一个例子来阐明它是如何工作的。
x10 = torch.zeros(3, 1)
print('Tensor:')
print(x10)print('\nTensor shape:')
print(x10.shape)print('\nTensor shape after torch.squeeze(0):')
print(x10.squeeze(0).shape)print('\nTensor shape after torch.squeeze(1):')
print(x10.squeeze(1).shape) ################## OUTPUT ##################Tensor:
tensor([[0.],
[0.],
[0.]])Tensor shape:
torch.Size([3, 1])Tensor shape after torch.squeeze(0):
torch.Size([3, 1])Tensor shape after torch.squeeze(1):
torch.Size([3])
使用自动签名的反向传播
如果requires_grad=True
,张量对象保持跟踪它是如何被创建的。
x = torch.tensor([1., 2., 3.], requires_grad = True)
print('x: ', x)y = torch.tensor([10., 20., 30.], requires_grad = True)
print('y: ', y)z = x + y
print('\nz = x + y')
print('z:', z) ################## OUTPUT ##################x: tensor([1., 2., 3.], requires_grad=True)
y: tensor([10., 20., 30.], requires_grad=True)z = x + y
z: tensor([11., 22., 33.], grad_fn=<AddBackward0>)
既然,requires_grad=True
,z
知道它是由两个张量z = x + y
相加而产生的。
s = z.sum()
print(s) ################## OUTPUT ##################tensor(66., grad_fn=<SumBackward0>)
s
知道它是由它的数字之和创造出来的。当我们在s
上调用.backward()
时,backprop 从s
开始运行。然后我们可以计算梯度。
s.backward()
print('x.grad: ', x.grad)
print('y.grad: ', y.grad) ################## OUTPUT ##################x.grad: tensor([1., 1., 1.])
y.grad: tensor([1., 1., 1.])
亲笔签名示例
我在这里引用了一些很好的资源来研究 PyTorch 上的亲笔签名
x1 = torch.tensor(2, dtype = torch.float32, requires_grad = True)
x2 = torch.tensor(3, dtype = torch.float32, requires_grad = True)
x3 = torch.tensor(1, dtype = torch.float32, requires_grad = True)
x4 = torch.tensor(4, dtype = torch.float32, requires_grad = True)z1 = x1 * x2
z2 = x3 * x4
f = z1 + z2gradients = grad(outputs=f, inputs = [x1, x2, x3, x4, z1, z2])
gradients ################## OUTPUT ##################(tensor(3.), tensor(2.), tensor(4.), tensor(1.), tensor(1.), tensor(1.))
让我们打印出所有的梯度。
print(f"Gradient of x1 = {gradients[0]}")
print(f"Gradient of x2 = {gradients[1]}")
print(f"Gradient of x3 = {gradients[2]}")
print(f"Gradient of x4 = {gradients[3]}")
print(f"Gradient of z1 = {gradients[4]}")
print(f"Gradient of z2 = {gradients[5]}") ################## OUTPUT ##################Gradient of x1 = 3.0
Gradient of x2 = 2.0
Gradient of x3 = 4.0
Gradient of x4 = 1.0
Gradient of z1 = 1.0
Gradient of z2 = 1.0
叶张量是直接创建的张量,不是任何算术运算的结果。
在上面的例子中, x1,x2,x3,x4 是叶张量,而 z1 和 z2 不是。
我们可以使用tensor.backward()
自动计算所有的梯度,而不是使用grad(outputs=f, inputs = [x1, x2, x3, x4, z1, z2])
指定所有的输入来计算梯度。
x1 = torch.tensor(2, dtype = torch.float32, requires_grad = True)
x2 = torch.tensor(3, dtype = torch.float32, requires_grad = True)
x3 = torch.tensor(1, dtype = torch.float32, requires_grad = True)
x4 = torch.tensor(4, dtype = torch.float32, requires_grad = True)z1 = x1 * x2
z2 = x3 * x4
f = z1 + z2f.backward()print(f"Gradient of x1 = {x1.grad}")
print(f"Gradient of x2 = {x2.grad}")
print(f"Gradient of x3 = {x3.grad}")
print(f"Gradient of x4 = {x4.grad}")
print(f"Gradient of z1 = {z1.grad}")
print(f"Gradient of z2 = {z2.grad}") ################## OUTPUT ##################Gradient of x1 = 3.0
Gradient of x2 = 2.0
Gradient of x3 = 4.0
Gradient of x4 = 1.0
Gradient of z1 = None
Gradient of z2 = None
我们可以使用x.grad.zero_
使渐变为 0。
print(x1.grad.zero_())################## OUTPUT ##################tensor(0.)
感谢您的阅读。欢迎提出建议和建设性的批评。:)你可以在 LinkedIn 和 Twitter 找到我。
你也可以在这里查看我的其他博客文章。
开始数据科学之旅的五个数据集
以及一些分析思路
W 借助一点想象力,数据科学家可以被视为“数据的全栈开发者”。就像全栈开发人员拥有从后端到前端的横向知识一样,数据科学家需要了解数据工程和业务领域之间的一切。这样的专业人员需要精通几个领域,如数据工程、数据可视化、机器学习、统计学。此外,他/她需要是一个主题专家。
我相信,一个人在这个世界上开始他/她的旅程可能会面临两个主要挑战:
- 挑战 1:如何学习和训练所有需要的技能— 当谈到“如何做”我不清楚时*:我不认为有单一的学习方法或单一的改进方法,然而有多种方法对每个人都有不同的作用:最好的办法是找到适合我们自己的完美组合。*
- 挑战 2:如何获得面试成功的经验 —这很难,尤其是如果一个人试图从另一个领域(例如软件开发)过渡到数据科学。
我对学习的完美组合包括理论学习和实践经验,但比例肯定倾向于后者,因为我是一个边做边学的人。我还认为“做事”在找工作时会有帮助(尤其是对那些初次经历的人);您希望在以下两者之间给出什么答案:
- “我有一个数据科学学位,这将是我的第一份工作经历”。
- “我有一个数据科学学位,这将是我的第一份工作经历;在申请工作时,我参与了一个模拟 Hadoop 日志消息流的项目;这些被摄取到一个 Spark 数据管道中,该管道提取一些基本信息(例如错误、时间属性等。),把一切都写在储存在 HDFS 的拼花文件里。在这些信息的基础上,我创建了一个 Tableau dashboard ,旨在识别 Java 异常中的模式(例如,当它们发生时,最常见的错误,等等)。).如果你想看看代码,这里有 Tableau 公共链接和 GitHub。
学位和课程是绝对必要的你应该尽可能多的学习,但是你可能会同意一些展示你技能的实际例子会有所帮助!
那又怎样?
我在本文中分享的是五个数据集,我认为它们对学习和实践都非常有帮助。这一选择背后的想法是让数据来自不同的领域,易于使用,但并非没有挑战。让我们深入其中吧!
有史以来最好的艺术品
一个很不错的数据集是用户 Icaro ( 下载 )上传的 Kaggle 有史以来最好的艺术品。如描述中所述,该数据集包含三个文件:
- artists . CSV*:每个艺人的信息数据集*
- images . zip*:图片集合(全尺寸),分文件夹,顺序编号*
如果这些数据被输入到人工智能模型中(大多数神经网络需要非常小的图像),调整大小的图片可以方便地加速预处理。注意“数据是 2019 年 2 月底期间从art challenge . ru”1【刮出来的。
关于如何使用这个数据集的一个想法可能是用 ConvNets** 做实验来建立一个分类器,给定一张图像,它可以识别作者;另一个应用可以是使用艺术品来实现一个 神经风格转移 GAN 。图像也是构建良好数据可视化的基础**:为什么不实现一个根据某种逻辑连接艺术品的图形呢?几年前,我用一个类似的数据集玩得很开心,分析波洛克的画 。****
为了展示在几个小时内可以完成什么,在下面的例子中,我使用了在 ImageNet 上训练的 ResNet50 来从每幅作品中提取特征。这是通过去除神经网络的最后一层并收集顶层之前的神经元的输出来完成的;该输出将是我们的“特征向量”(我们将为每幅图像准备一个向量)。
在特征提取之后,我使用了 PCA 和 tSNE 的组合来将高维向量投影到二维空间上。最后,我运行了 DBSCAN 来识别一些集群;正如你从下面的 GIF 中看到的,即使我没有进行微调,该算法也能够理解输入图像(褪色的缩略图是那些被 DBSCAN 标记为噪声的缩略图)。
如果你想下载完整的结果, 这是 的链接。
伦敦警察厅——武力的使用
我认为这个数据集很有趣,因为它有相当多的维度。它包含了伦敦警察厅关于使用武力的统计数据。每一行集合代表一名军官在一个主题上使用武力。 此行设置的不是一个计数事件 。如果不止一名官员对同一主题使用武力,这将显示在单独的数据行 [ 2 ]中。
这些数据可以驱动到非常引人注目的仪表板上,并且,稍加努力,还可以驱动到 ML 模型上(例如,预测涉及使用武力的警察干预的结果)。还要注意,时间维度是进行时间序列分析的必备工具。
意大利 2011 年人口普查
我想在这个列表中加入一些人口普查数据。*人口普查是系统地获取和记录给定人口成员信息的过程,大多数国家都有某种统计机构,定期收集整个人口的数据。我这里建议的是意大利 2011 年人口普查数据集 ( 下载 )。*****
我想包含这类数据有两个主要原因:
- 它允许玩 GIS (地理信息系统)——我上面链接的下载页面,也包含了 2011 年所有人口普查部分的shape file,它代表了意大利领土的一个相当精细的划分。Shapefile 是一种数字矢量存储格式,用于存储几何位置和相关属性信息[4。这些可以用来表示地图上的指标:传单 或者OpenStreetMaps都是处理这类数据的很好的 JavaScript 库。****
- 在许多现实生活的应用中,您希望在分析中包含人口数据。大多数人口普查彼此之间都非常相似,所以我认为习惯它们是个好主意!
要开始使用数据库,请访问我提供的链接并下载下面的文件:
zip 存档包含 20 个意大利地区的每个地区的一个文件,名称模板是R<n>_indicatori_2011_sezioni.csv
,其中R<n>
是地区号。列被描述在一个名为 **tracciato_2011_sezioni.csv**
的文件中。
不幸的是,该数据集似乎没有英文版本,所以你可以选择利用谷歌来翻译栏目名称,或者使用另一个国家的人口普查:)
拼图毒性评论分类挑战
第四个数据集来自一个老 Kaggle 比赛( 下载 )。主持人提供了大量维基百科评论,这些评论已经被人类评分员标记为有毒行为。毒性的类型有:
***toxic
severe_toxic
obscene
threat
insult
identity_hate***
目的是创建一个模型来预测每条评论的每种毒性的概率[5]。
如果你想深入研究 NLP 和递归神经网络深度学习,我相信这是一个很好的起点。为了使建模更有趣,您可以尝试不同的预处理技术、网络拓扑和数据丰富*(为什么不使用 Google APIs 将维基百科的评论翻译成另一种语言,然后重新翻译回英语以获得更多的训练数据呢?).*****
这个数据集的另一个好处是,你将从 Kaggle 社区获得大量的材料。
下面的仪表板与深度学习无关,它只是对数据集的简单探索(仪表板后面的脚本是我用来从原始评论中提取信息的)。
Loghub
如果你想挑战自己的一些数据工程和特征提取,以及大容量的数据,我建议你从 Logpai ( 下载 )的 Loghub 数据集。****
Loghub 维护着一系列系统日志,这些日志可以出于研究目的自由访问。一些日志是从以前的研究中发布的生产数据,而另一些是从我们实验室环境中的真实系统中收集的。尽可能不对日志进行任何形式的清理、匿名或修改。所有这些日志总计超过 77 GB。因此,对于每个数据集[6】,我们在 Github 上只托管一个小样本(2k 行)。
从他们在 Github 页面上提供的描述中可以看出,我们谈论的是大约 77 GB 的数据。尽管这些在集群上不是问题,如果在本地运行代码,它们可能会很有挑战性:我认为**这对于学习来说是一个优势!**
拿走
- ****当我开始从事数据科学时,我希望得到的一个建议是用几个项目构建一个存储库。这对学习和“个人品牌”都非常有帮助。
- 当选择一个数据集时,选择一些具有挑战性的东西,例如从数据建模或性能角度,除非你想非常具体地专注于一些已经具有挑战性而没有其他复杂性的特定技术。
- 不要害怕尝试不同的工具和编程语言。
我希望你喜欢!我很乐意在推特上联系!让我知道你的想法,如果你愿意,也可以看看这些文章。
***** [## Jupyter 笔记本上的 JavaScript 图表
用漂亮的 JavaScript 可视化将 Jupyter 推向新的高度
towardsdatascience.com](/javascript-charts-on-jupyter-notebooks-dd25f794cf6a) [## 六个星火练习来统治他们
一些具有挑战性的 Spark SQL 问题,易于在许多现实世界的问题上提升和转移(带解决方案)
towardsdatascience.com](/six-spark-exercises-to-rule-them-all-242445b24565)*****
如何将 2D 图像转换成三维空间?
使用 python 从头开始转换图像,并使用用户友好的滑块界面来可视化转换矩阵
变换图像
变换矩阵
变换矩阵用于修改和将点从一帧重新定位到另一帧。它们被广泛用于视频游戏和计算机视觉。无法列举它们的所有用途,但它们也用于在深度学习的训练中增强图像。
目前我们不知道什么是矩阵 M 和它的系数对应。实际上,系数不是直接找到的。不如说有更好的方法分解这个矩阵。事实上,一个变换矩阵可以分解成 4 个矩阵,所有矩阵都在空间坐标变换中起作用。
我们注意到平移矩阵、旋转矩阵、缩放矩阵和剪切(或倾斜)矩阵。
我已经按照上面的顺序分解了矩阵。订单有它的重要性。在这种情况下,它将首先应用平移,然后旋转,等等。然而,为了应用 3D 透视,我们必须移动到齐次坐标,因此引入两个新矩阵。
齐次坐标
我们将要看到的两个矩阵允许我们从笛卡尔坐标系到投影坐标系,反之亦然,分别是 H 和H’。注意 H’ 不是 H 的逆矩阵。
为了解释什么是投影坐标,为了简单起见,我将在 2D 进行类比。想象一个尺寸为 X , Y 的屏幕,相当容易表现。然后我们有 (X,Y,W) 其中 W 是屏幕-投影仪距离。所以我们在射影(或齐次)坐标下的 2D 空间中。
现在我们在这个投影空间中,我们可以将投影仪从屏幕向前或向后移动距离δW。如果我们将它向后移动,那么投影图像将会超出它。相反,通过使投影仪更靠近屏幕,屏幕上图像的显示尺寸减小。
不可能(或者很难)想象这个射影空间与 3D 笛卡尔空间相关联,但是原理是相同的。我们会有 (X,Y,Z,W) 。
在接下来的脚本中,我们将通过考虑以度 ( 0 到 360 )为单位的角度和以像素为单位的度量来应用这些变换矩阵。
目前我们还没有定义转换矩阵。我们将在后面定义它们。我们将用身份矩阵来代替它们。这个矩阵并不修改图像,它就像一个数字乘以 1 。
让我们回到从笛卡尔坐标到射影坐标的转换的矩阵,反之亦然。目前,矩阵 M 是单位矩阵。
这里, h 和 w 为待处理图像的高度和宽度尺寸。
如果 h 和 w 出现在我们的等式中,则会将标记置于图像中心。的确,在一幅图像中,标记的原点在图像的左上角(坐标 (0,0) )。
同样,我们可以在之前看到的图表中看到与我们投影仪的焦距相对应的变量f的外观。
让我们写剧本吧
这样我们就可以为我们的图像变换函数打基础了。从恢复所有轴上的所有变换值开始,然后定义齐次通道的矩阵。
翻译
让我们转到翻译矩阵。顾名思义,这允许我们在不同的轴上进行平移。
你会注意到 Z 轴的平移必须被更新。事实上,我们的转换(以像素为单位)没有考虑“到投影仪的距离”。
你会明白我们不得不也为标尺更新 Z 轴。
旋转
旋转矩阵可以分解成不同轴上的旋转矩阵的乘积。在 3D 空间中,我们有 3 个旋转矩阵。
刻度
简单地说,缩放矩阵允许模拟缩放。换句话说,如果我们再次以我们的图像为例,在 X 或 Y 上放大两倍可以通过在这些轴上扩展图像来理解(同时从相同的距离观看图像)。
而对于 Z 轴,我们可以将二倍缩放解释为在 X 和 Y 上的二倍缩放的组合。(或焦距比率的变化)
注意,可以通过传递一个值 -1 在轴上建立对称性。
剪
剪切矩阵使得在不同的轴上拉伸(剪切)成为可能。
因此,在 3D 中,我们有一个剪切矩阵,它在 3 个轴上被分解成变形矩阵。
奖金部分
创建一些滑块
然后我们有了所有必要的矩阵来转换我们的图像。能够在我们选择的图像上实时可视化它们的效果会很有趣。让我们创建一个滑块**。**
滑块只是一个静态图像,还不能做任何事情。让我们为这些滑块创建一个堆栈,这样我们就可以用鼠标实时控制它们。
跑吧!
知识就是分享。
支持我,一键获取 中我所有文章的访问**。**
来源
所有的图片都是自制的,可以免费使用。
如何将机器学习成果转化为商业影响
向高管解释模型结果
马库斯·斯皮斯克在 Unsplash 上的照片
我以前写过数据科学是一个模糊的概念,人们不太理解。为了说明这一点,我想告诉你我曾经和一位副总裁的对话,内容是这样的:
我:“我可以建立一个机器学习模型来选择最有可能购买的顶级用户。”
VP :“你是说像回归模型?”
我:“是啊……差不多吧。”(忍住做掌脸的冲动)
如果您所有的建模工作都被视为可以在 Excel 中完成的回归,那么作为一名数据科学家,您如何让人们了解您所提供的价值?
今天,我将分享一些我将机器学习成果转化为商业影响的方法,以便高管和你的利益相关者能够理解。
1.显示相对于公司 KPI 的改进
高管需要说明该模型如何改善他们关心的公司关键绩效指标,即转化率、用户参与度和续订率。
例如,您构建了一个模型,发现顶级功能可以提高用户参与度。通过让产品团队在用户入职体验期间强调这些功能,您帮助提高了团队的用户参与度 KPI。
这向产品副总裁展示了您构建的模型的价值,否则产品团队将会花费大量时间来寻找。
2.显示增量收入影响
如果没有非常适合您构建的模型的 KPI,或者您想要显示相对 KPI 改进的大小,请计算对业务的增量收入影响。
例如,你建立了一个模型,将转化率从 1%提高到了 2%。1%的差异听起来并不多,但如果你也说 1%的转化率增加转化为 100 万美元的额外收入呢?
哇,现在你真正展示了你的价值,因为这比你的年薪还多(如果你赚了 100 多万,我想知道你的秘密)。
3.显示成本降低或花费的时间
如果您的模型与公司 KPI 无关,或者您无法关联收入金额,那么尝试通过降低成本或员工时间来显示价值。
例如,我开发了一个模型来选择最有可能转化为团队许可的单个用户。现在,他们可以选择最有可能购买的用户,并在更短的时间内增加转化的机会,而不是让两名销售代表花费一天时间在数据库中查看数百万用户,以找到最佳销售线索。
我不知道该模型可以提高的确切转化率,但这足以说服销售团队使用它,因为它有明显的价值,可以减少销售代表手动查看数据库所花费的时间。
作为数据科学家,重点是模型的准确性,但有时你必须后退一步,看看大局,以展示机器学习模型对业务的价值。
感谢阅读!如果您有兴趣在未来听到更多关于特定数据分析主题的信息,请留下您的评论。
你可能也会喜欢…
将数据科学与数据分析相结合
medium.com](https://medium.com/swlh/how-i-used-a-machine-learning-model-to-generate-actionable-insights-3aa1dfe2ddfd) [## 我作为数据科学家和数据分析师的经历
我希望从一开始就知道的成功秘诀
towardsdatascience.com](/my-experience-as-a-data-scientist-vs-a-data-analyst-91a41d1b4ab1)
如何用 Python 翻译 PDF(Google vs AWS Translate)——第 1 部分:提取和翻译文本
实践教程
如何使用谷歌翻译 API 和 AWS 翻译 API 阅读和翻译 PDF 文件的逐步指南。
我需要将一个包含英文文本的 PDF 文件翻译成拉脱维亚文。事实证明,这比我最初想象的稍微更具挑战性,所以我决定写一篇教程来分享我学到的东西,希望能为你节省一些时间。我把我的项目分成两部分。
这篇文章是第一部分,重点是如何阅读你的 PDF 文件,提取文本,并翻译它。它着眼于两种翻译文本的方法——使用谷歌翻译和 AWS 翻译。
第 2 部分将着眼于如何从获得的翻译创建、格式化和保存一个新的 PDF 文件。你可以在 GitHub 中找到我的项目的链接,并在本文末尾找到完整的代码。
这篇文章涵盖了什么?
- 如何使用 Python
PyPDF2
库读取 PDF 文件并从 PDF 中提取文本 - 2 种翻译文本的方法:python
googletrans
库和AWS Translate.
使用 Python 读取 PDF 文件
要以编程方式读取 PDF 文件,您可以使用各种第三方库,本文使用 PyPDF2 库。
PyPDF2 可以使用 pip 软件包管理器安装:
pip install PyPDF2
要读取该文件,我们首先要以二进制读取模式打开该文件,并创建一个 PdfFileReader。
file = open("example.pdf", 'rb')
reader = PdfFileReader(file)
从 PDF 中提取文本
现在,您可以一次一页地阅读 PDF 文件。您可以通过调用 reader 对象上的一个numPages
属性来获得文档的页数。然后逐一遍历所有页面,提取文本。要获取页面内容,使用reader.getPage(<page number>
,要从页面内容中提取文本,使用extractText
方法。
num_pages = reader.numPagesfor p in range(num_pages):
page = reader.getPage(p)
text = page.extractText()
翻译文本
一旦文本被提取出来,它就可以被翻译。我很好奇将使用谷歌翻译的 python 库与 AWS 翻译器进行比较。googletrans
库是开源的,使用它没有额外的费用。AWS Translate 使用神经机器学习算法进行翻译,并在翻译时考虑上下文。要使用 AWS 翻译,您需要有一个 AWS 帐户。他们提供前 12 个月的免费等级,在此期间你可以翻译 200 万个字符。之后,采用现收现付的定价方式,每百万字符的费用为 15 美元。请注意,免费层是在您首次使用服务时激活的。
使用谷歌翻译 API 翻译文本
您可以使用 pip 安装该库:
pip install googletrans
在幕后,这个库使用 Google Translate Ajax API 调用 Translate 方法。您也可以指定 Google 服务域 URL。在下面的例子中,我声明了两个不同服务域的列表:translate.google.com
和translate.google.lv.
您需要创建一个翻译器客户端实例,然后调用translate
方法来翻译文本。默认的目标语言是英语。可以通过在translate
方法中指定dest
参数来改变。默认的源语言是自动检测的,但是您可以使用src
参数专门定义源语言。在下面复制的例子中,它自动检测源语言并翻译成拉脱维亚语。
from googletrans import TranslatorURL_COM = 'translate.google.com'
URL_LV = 'translate.google.lv'
LANG = "lv"translator = Translator(service_urls=[URL_COM, URL_LV])
translation = translator.translate(text, dest=LANG)
使用亚马逊 AWS 翻译工具翻译文本
您需要有一个 AWS 帐户才能使用 AWS 翻译。请注意,如果您使用 python 以编程方式使用 AWS 服务,那么最简单的方法就是使用由 AWS 提供的名为boto3
的 python SDK。AWS 的工作方式是,它向您选择的区域中的 AWS 翻译端点发送一个 HTTP API 调用。使用您的访问密钥和秘密访问密钥以及当前时间戳对该请求进行加密签名。您确实需要配置您的aws_access_key_id
和aws_secret_access_key.
,它使用一种叫做 AWS Signature Version 4 的协议来签署您的请求。您笔记本电脑上的时钟必须正确,因为该协议考虑了当前时间。它会在签署您的请求时包含时间戳,并且您发送给 AWS 的请求仅在 15 分钟内有效。如果在 15 分钟后收到,那么出于安全原因,AWS 将拒绝该请求。
要安装 AWS Python boto3
SDK:
pip install boto3
如上所述,AWS 提供了一个免费的 AWS 翻译试用层,为期 12 个月,给你 200 万字免费翻译。之后是每 100 万字 15 美元。请注意,AWS 也将空格算作字符。
为了翻译,我们首先为translate
服务创建一个客户端,并指定区域。然后在客户端对象上调用translate_text
方法,提供Text
参数,这是您想要翻译的文本。SourceLanguageCode
允许指定源语言。如果使用值auto
,那么将自动检测源语言。TargetLanguageCode
允许指定目标语言。一旦从 AWS 收到结果,还有一个额外的步骤来获取翻译后的文本,那就是调用result.get(‘TranslatedText’).
import boto3LANG = "lv"
AWS_REGION = 'eu-west-1'translate = boto3.client(service_name='translate',
region_name=AWS_REGION,
use_ssl=True)result = translate.translate_text(Text=page.extractText(),
SourceLanguageCode="auto",
TargetLanguageCode=LANG)
translation = result.get('TranslatedText')
结论
感谢您抽出时间阅读。我希望这篇文章对你有用。您学习了如何使用 python 阅读 PDF 文件,以及如何从 PDF 文件中提取文本。然后,您看了如何自动翻译这段文本的两种不同方式。
请关注第 2 部分,它将介绍如何使用 python 库reportlab
将翻译后的文本保存到一个新的 PDF 文件中。它还将格式化和保存新创建的文件。
在 GitHub 中查看该项目的完整代码:https://github.com/akapne01/translator
如何免费试用 UCP 码头工人?
使用码头游乐场
每个人都在转向微服务和对接单片应用。想熟悉 docker 的 Docker 新手可以使用 Docker 游乐场。它是免费的!
我总是建议我的学生使用谷歌浏览器。通常,它不会要求输入您的 Docker Hub ID 和密码。它将向您显示 START 按钮,如图 1 所示。点击它。
图 1:在谷歌浏览器中启动 Docker 游乐场
Docker 企业套件由三个组件组成:
1。Docker 企业引擎
2。UCP(通用控制平面)
3。DTR (Docker 可信注册中心)
注意有两个 Docker 引擎:Docker 社区版(CE)和 Docker 企业版(EE)。
- Docker CE 仅用于开发和测试,绝不用于生产。然而,这是免费的。
- Docker EE 是您用于生产的版本,您可以在其中初始化 Swarm 或 Kubernetes。这不是免费的。不过,你可以免费试用一个月。
Docker Playground 帮助您免费安装和试用 UCP。然而,这个播放实验室被限制在小于 3 GB 的内存中,大约 4 小时后过期。
现在,按照步骤在 Docker 操场上安装 UCP。
第一步:
通过单击左侧的“Add New Instance”创建一个节点,如图 2 所示。
图 2:在 Docker Playground 上创建一台新机器
第二步:
使用 docker swarm init 命令初始化 Docker Swarm。从节点名称或页面顶部获取节点的 IP 地址。
docker swarm init —-advertise-addr <Node IP>
如果您想要将工作节点添加到您的集群,Docker 引擎将生成一个长令牌。
第三步:
从 docker/ucp: 镜像创建一个容器来安装 ucp。该命令如下所示:
docker container run --rm -it --name ucp -v /var/run/docker.sock:/var/run/docker.sock docker/ucp:2.2.9 install --host-address <node IP> --swarm-port 2400 --interactive --force-insecure-tcp
在这里,我们正在根据docker/ucp:2.2.9
图像制作一个容器。
客房服务的--rm
。我们告诉 docker 当它停止时自动删除这个容器。
-it
做一个交互终端。
将这个容器命名为ucp
的--name
,而不是 docker 默认生成的形容词 _ 名词的名称。
-v
在主机和该容器之间共享卷。
install
是安装 UCP 的命令。
--host-adress
设置群首的主机/节点地址。
将--swarm-port
端口设置为 2400。
使容器交互的--interactive
标志。
--force-insecure-tcp
的最后一个标志是为了避免以下错误:
该节点上的 Docker 端口可从外部访问,接受端口 2375 上的连接。该节点不安全。
docker/ucp
图像的其他一些标签不使用--force-insecure-tcp
。相反,你可以使用--ucp-insecure-tls
。
它将停止等待您输入您的管理员用户名和密码。同样,它将再次暂停以输入额外的别名。只需按 enter 键,docker 就可以继续安装,因为集群中没有任何其他节点。
安装完成后,节点 IP 地址旁边会显示一些链接。
第四步:
您可以从 443 端口访问 UCP。但是,如果你点击它,它会在本地下载一个文件。要解决这个问题,右键单击 443 端口链接,然后单击复制链接地址。打开一个新的浏览器标签,粘贴链接。将 http://更改为 https://,然后单击 enter。
假设你没有链接到 443 端口,没问题。复制 SSH 地址。
打开新的浏览器选项卡。用 https://替换 ssh。将地址中的@替换为。点击回车。
我会给你一个错误。单击底部的高级,将显示一个链接以继续。点击链接。
第五步:
将显示 UCP 登录。输入您的管理员用户名和密码。
第六步:
它会要求您上传许可证。您可以从 Docker Hub 的帐户获得一个月的试用许可证:
https://hub.docker.com/editions/enterprise/docker-ee-trial
此外,你可以跳过以后。UCP 将如下所示:
您可以稍后从左侧菜单中,单击管理→管理设置→许可证来上传。
享受你的审判!
如何调整 Pytorch 闪电超参数
想知道如何用 30 行代码优化 Pytorch Lightning 超参数?
Pytorch Lightning 是 2020 年最热门的人工智能库之一,它使人工智能研究可扩展并快速迭代。但是如果你使用 Pytorch Lightning,你需要做超参数调整。
正确的超参数调整可以决定训练的成功与否。每个人都知道,通过良好的调优方法,可以极大地提高模型的准确性!
在这篇博文中,我们将演示如何使用 PyTorch Lightning 使用 Ray Tune,这是一种超参数调整的行业标准。 Ray Tune 是 Ray 的一部分,是一个用于缩放 Python 的库。
它以 PyPI 包的形式提供,可以这样安装:
pip install "ray[tune]"
要使用 PyTorch Lightning 的 Ray Tune ,我们只需要添加几行代码!!
雷调+ PTL 入门!
要运行这篇博文中的代码,请确保首先运行:
pip install "ray[tune]"
pip install "pytorch-lightning>=1.0"
pip install "pytorch-lightning-bolts>=0.2.5"
下面的例子是在 ray1.0.1,pytorch-lightning1.0.2,pytorch-lightning-bolts==0.2.5 上测试的。 参见此处完整示例。
先从一些进口说起:
导入之后,有三个简单的步骤。
- 创建您的
LightningModule
- 创建一个用调优回调函数调用
Trainer.fit
的函数 - 使用
tune.run
执行您的超参数搜索。
步骤 1:创建你的照明模块
第一步,创建你的照明模块。你的LightningModule
应该把一个配置字典作为初始化的参数。然后,这个字典应该设置您想要调整的模型参数。您的模块可能如下所示:
第 2 步:创建一个函数,用 Tune 回调函数调用Trainer.fit
我们将使用回调来与射线调进行通信。回调非常简单:
from ray.tune.integration.pytorch_lightning import TuneReportCallback...
metrics = {"loss": "ptl/val_loss", "acc": "ptl/val_accuracy"}
callbacks = [TuneReportCallback(metrics, on="validation_end")]
trainer = pl.Trainer(... callbacks=callbacks)
这个回调确保了在每个验证时期之后,我们向光线调节报告损失度量。val_loss
和val_accuracy
键对应于validation_epoch_end
方法的返回值。
此外,射线调节将开始许多不同的训练运行。为了创建多个训练运行(用于超参数搜索),我们需要将训练器调用包装在一个函数中:
train_mnist()
函数需要一个config
字典,然后传递给LightningModule
。该配置字典将包含一次评估的超参数值。
第三步:使用tune.run
执行你的超参数搜索。
最后,我们需要调用ray.tune
来优化我们的参数。这里,我们的第一步是告诉光线调节哪些值是参数的有效选择。这叫做 搜索空间 ,我们可以这样定义:
# Defining a search space!config = {
**"layer_1_size"**: tune.choice([32, 64, 128]),
**"layer_2_size"**: tune.choice([64, 128, 256]),
**"lr"**: tune.loguniform(1e-4, 1e-1),
**"batch_size"**: tune.choice([32, 64, 128])
}
让我们快速浏览一下搜索空间。对于第一层和第二层的大小,我们让射线调整在三个不同的固定值之间选择。学习率在0.0001
和0.1
之间采样。对于批量大小,也给出了三个固定值的选择。当然,还有许多其他的(甚至是定制的)方法可以用来定义搜索空间。
射线调节现在将随机对十个不同的参数组合进行采样,训练它们,然后比较它们的性能。
我们将train_mnist
函数包装在tune.with_parameters
中,以传递常数,如训练每个模型的最大历元数和每次试验可用的 GPU 数量。 Ray Tune 支持分数 GPU,所以只要模型仍然适合 GPU 内存,类似gpus=0.25
的东西完全有效。
# Execute the hyperparameter search
analysis = tune.run(
tune.with_parameters(train_mnist_tune, epochs=10, gpus=0),
config=config,
num_samples=10)
对tune.run
的最终调用如下所示:
最后,优化结果可能如下所示:
在这个简单的例子中,一些配置达到了很好的精度。我们观察到的最好结果是在批量大小为 32,层大小为 128 和 64,学习率为 0.001 左右的情况下,验证精度为 0.978105 。我们还可以看到,学习率似乎是影响性能的主要因素——如果学习率太大,运行将无法达到良好的准确性。
您可以通过使用tune.run
的返回值来检索最佳分数:
analysis = tune.run(...)best_trial = analysis.best_trial # Get best trial
best_config = analysis.best_config # Get best trial's hyperparameters
best_logdir = analysis.best_logdir # Get best trial's logdir
best_checkpoint = analysis.best_checkpoint # Get best trial's best checkpoint
best_result = analysis.best_result # Get best trial's last results
您还可以轻松利用 Ray Tune 的一些更强大的优化功能。例如, Ray Tune 的搜索算法可以让你轻松优化超参数组合的景观。Ray Tune 的调度程序还可以尽早停止性能不佳的试验,以节省资源。
在张量板上检查结果
Ray Tune 自动将度量标准导出到 TensorBoard,中,还可以轻松支持 W & B。
就是这样!
要用 射线调 启用简单的超参数调,我们只需要添加一个回调,包装好 train 函数,然后开始调。
当然,这是一个非常简单的例子,没有利用许多 Ray Tune 的搜索功能,如早期停止表现不佳的试验或基于人群的培训。如果你想看完整的例子,请看看我们的完整 PyTorch 闪电教程。
如果你已经成功地使用 py torch Lightning withRay Tune,或者如果你需要任何帮助,请通过加入我们的 Slack 或者通过我们的 Github 来联系我们——我们希望收到你的来信!
如果你喜欢这篇博文,一定要看看:
- 我们的权重和偏差报告针对变压器的超参数优化
- 从零开始为你的 NLP 模型服务的最简单的方法
恐龙和圆圈的数据集可以有相同的统计数据吗?
它们具有相同的均值和标准差,但它们是两个明显不同的数据集!
动机
数据可视化不仅仅是展示漂亮的图表。它还有助于您更深入地了解您的数据。
恐龙来转圈
上面的 gif 捕捉了不同数据集的统计和可视化。如果我们只查看右侧的统计数据,而不可视化数据集,我们会假设这些数据集几乎相同,因为它们具有相同的均值、标准差和相关性
但是当我们看左边的可视化时,我们意识到这两个数据集是不同的,因为一个描绘的是恐龙而一个描绘的是圆圈!
这个输出证明我们不应该只相信统计数据,而应该在做出结论之前进一步可视化数据集。
在本文中,我将向您展示如何创建具有相同统计数据但看起来彼此不同的数据集。
使用模拟退火创建相同的统计数据和不同的图表
来自 Autodesk Research 的贾斯汀·马特伊卡和乔治·菲兹莫里斯找到了创建这种数据集的方法。受安斯科姆的四重奏的启发,他们试图找出如何创建具有这些特殊属性的数据集。
从维基百科检索到的安斯康姆四重奏
他们的方法智能地保持统计数据不变,同时控制结果输出的图形外观。那么这个方法是怎么运作的呢?
从头开始创建具有这些属性的数据集是极其困难的。但是,如果我们从一个特定的数据集开始,在每次迭代中只对它进行轻微的修改,同时保持统计数据不变,直到我们创建出具有我们想要的形状的数据集,那会怎么样呢?
这是该方法的伪代码。
从贾斯汀·马特伊卡和乔治·菲兹莫里斯的论文中检索到的代码
上述代码的解释:
Inital_ds
:初始化我们想要维护统计值的数据集- 在每次迭代中调用
Perturb function
,通过在随机方向上少量移动一个或多个点来修改数据集的最新版本current_ds
。该功能确保至少 95%的移动不会改变整个数据集的统计属性 Fit function
检查扰动点是否已经增加了数据集的整体适合度。由于我们希望将数据集强制转换成特定的形状,因此增加适应度意味着最小化目标形状上所有点到最近点的平均距离**。**- 当有更多的全局最优解(更好的解)可用时,为了避免陷入局部最优解(一个好的但不是最好的解),该方法采用模拟退火到来增加选择的随机性。这意味着我们总是接受具有改进的适应度的解决方案,但是即使解决方案没有改进,如果当前温度大于 0 和 1 之间的一个随机数,我们仍然接受解决方案。
现在让我们试着用这个方法把一只恐龙变成靶心。
把恐龙变成靶心
为了方便你使用上面的方法,我创建了一个名为same-stats-different-graphs的包。这是 Autodesk 提供的代码的修改版本。
这个包允许你把一个形状变成另一个形状,并在命令行上为这个转换创建 gif。
要安装软件包,请键入:
pip install same-stats
现在我们准备把一个恐龙数据集变成靶心!在您的终端上,键入:
python -m same_stats --shape_start=dino --shape_end=bullseye
并且像下面这样的 GIF 会以dino_bullseye.gif
的名字保存到gifs
目录中:
恐龙对牛眼
其他参数选项:
--shape_start
:形状开始。选项:dino
、rando
、slant
、big_slant
--shape_end
:目标形状。选项:x
、h_lines
、v_lines
、wide_lines
、high_lines
、slant_up
、slant_down
、center
、star
、down_parab
、circle
、bullseye
、dots
--iters
:迭代次数--decimals
:小数位数--frames
:帧数
结论
恭喜你!您刚刚发现了如何使用相同的统计值创建完全不同的数据集!我们方法的输出可用于展示可视化数据的重要性。你可以在 Autodesk 研究网站上了解更多关于这种方法的信息。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 T21 Twitter 上与我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
[## 如何使用 HyperDash 远程监控和记录您的机器学习实验
培训需要很长时间才能完成,但你需要去洗手间休息一下…
towardsdatascience.com](/how-to-monitor-and-log-your-machine-learning-experiment-remotely-with-hyperdash-aa7106b15509) [## 如何找到和 Python 很好的搭配
给定个人偏好,如何匹配使得总偏好最大化?
towardsdatascience.com](/how-to-match-two-people-with-python-7583b51ff3f9) [## 如何用 Faker 创建假数据
您可以收集数据或创建自己的数据
towardsdatascience.com](/how-to-create-fake-data-with-faker-a835e5b7a9d9) [## 如何用图论可视化社交网络
找出《权力的游戏》中的影响者
towardsdatascience.com](/how-to-visualize-social-network-with-graph-theory-4b2dc0c8a99f) [## 如何用 Altair 创建交互式剧情
在 5 行简单的 Python 代码中利用您的数据分析
towardsdatascience.com](/how-to-create-interactive-and-elegant-plot-with-altair-8dd87a890f2a) [## cy thon——Python 函数的加速工具
当调整你的算法得到小的改进时,你可能想用 Cython 获得额外的速度,一个…
towardsdatascience.co](/cython-a-speed-up-tool-for-your-python-function-9bab64364bfd)
如何将文本转化为特征
入门
使用 NLP 进行机器学习的综合指南
简单问题:如何把文字变成特征?作者图片
假设你被分配了一项任务,为你的公司产品评论建立一个情感分析工具。作为一名经验丰富的数据科学家,您构建了许多关于未来销售预测的见解,甚至能够根据客户的购买行为对他们进行分类。
但是现在,你很感兴趣:你有一堆文本条目,必须将它们转化为机器学习模型的特征。如何做到这一点?当数据科学家第一次遇到文本时,这是一个常见的问题。
对于有经验的 NLP 数据科学家来说,将文本转换成特征可能看起来很简单,但对于该领域的新手来说,这并不容易。这篇文章的目的是提供一个将文本转化为特征的指南,作为我在过去几个月中构建的 NLP 系列的继续(我知道,距离上一篇文章已经有一段时间了)。
之前,我已经讨论了 NLP 预处理管道中的几个步骤。现在,这是预处理管道的最后一步,当你精心策划的文本最终变成机器学习模型的可用特征时(如果这是你的目的——没有机器学习也可以有 NLP,这是另一个话题)。
像往常一样,除了解释如何做之外,我还将介绍三种最常用的建模技术:单词袋模型、基于 TF-IDF 算法的模型和 Word2Vec 模型。让我们开始讨论吧。
特色?
对于那些不习惯这个词的人,让我稍微离题一下。特征是给予选择或处理的数据的名称,准备用作算法(通常是机器学习算法)的输入。特征可以是房子的价格、像素的 RGB 值,或者在我们的例子中是单词的表示。
来自谷歌开发者机器学习速成班的漂亮图片描述了什么是特性。
甚至有一种叫做“特征工程”的很酷的技能,数据科学家研究数据,从数据中获得特征。这些特征甚至可能在数据中不明显,但可以通过修改现有数据或添加新数据使其更完整来获得,从而有助于实现更稳健的决策。
因此,最终,我们的目标是获得原始数据(文本)并转化为特征(计算机算法可以处理的东西)。
文本矢量化
用于将文本转换成特征的技术可以被称为“文本矢量化技术,因为它们都旨在一个目的:将文本转换成向量(或者数组,如果你想更简单的话;或者张量,如果你想要更复杂的话),然后可以以经典的方式输入到机器学习模型中。
文本矢量化旨在将文本转换为整数(或布尔或浮点数)向量。图片作者。
把我们的预期结果想成一个向量是一个很好的起点,来想象我们如何把文本变成特征。让我们对此进行更多的思考。考虑下面的短语:
我想把我的文本转换成数据。
用简单的计算术语来说,向量是具有 n 个位置的列表。考虑如何将文本转换为向量的一种自然方法是创建一个所有单词的有序列表,如下所示:
图片作者。
但是,如果条目更短或更大,会发生什么情况呢?此外,你的机器学习算法(基本上是一系列矩阵和向量计算)如何比较两个单词——这些由人类发明的具有特殊含义的符号?
既然你很聪明,你已经想到了:让我做一个字典或者一些类似的结构(一般来说,一个词汇图),用单词索引代替单词!
一个假设的解决方案是为每个单词创建一个映射……作者的图片。
然后用单词索引对向量进行编码。图片作者。
你在正确的道路上,但是让我们考虑这里的一些问题:单词“我的”比“想要的”更重要吗?对于机器学习算法来说,这就是你的数据“告诉”的。机器学习算法不关心数字是否是一个索引,只关心它是一个要计算的值(当然,你可以有一个分类特征,但我们会在下面看到)。
不要吼,言语不是价值观!图片来自海绵宝宝电视节目,由作者编辑。
“正常化,正常化,正常化!!!",可以认为。但是,记住:这些都不是价值观!它们是指数。
如果你玩数据科学和机器学习已经够久了,你可能会想到 one 解决方案:使用 One Hot Encoding 。
一个热编码是对分类特征进行编码的过程,其中该特征的每个可能值被映射到一个新的“列”,如果存在,则该列被设置为 1,否则为 0。
让我们使用前面提到的词汇表“map”和建议的短语来考虑这一点(在这种情况下,词汇表与短语的单词相同)。我们得到这个:
“我想把我的文本转换成数据”的一键编码。图片作者。
现在,如果我们想编码:“我想要我的数据”,我们会得到:
“我要我的数据”的一键编码。图片作者。
太好了,我们找到了一种将我们的数据编码成机器学习方式的方法!但是这里有很多问题需要解决:让我们考虑第一个问题——词频——这就是词汇袋模型的用武之地!
单词袋(蝴蝶结)模型
一种热编码只将值视为“存在”和“不存在”。这不适合发短信。在许多文本应用中,词频起着重要的作用。考虑以下两段:
狗是犬科的家养食肉动物。它是像狼一样的犬科动物的一部分,是最广泛丰富的陆地食肉动物。狗和大灰狼是姐妹分类群,因为现代狼与最初被驯化的狼没有密切关系,这意味着狗的直接祖先已经灭绝。狗是第一个被驯化的物种,几千年来因为各种行为、感觉能力和身体特征而被选择性繁殖。
今天我带着我的狗出去,我在公园里发现了 100 美元。想到这些钱可能是某个可怜的老太太一周的午餐钱,我很难过。
第一个是维基百科关于狗的文章的第一段,第二个是我为了证明这个问题而写的一个伪博客。问题:你会向一个用“狗”这个词搜索假想引擎的用户推荐哪个网页?
一个热编码将在两个条目中为“dog”给出相同的值,所以这不好。
进入词汇袋模式!
一袋单词😜。图片作者。
这个模型建议,使用一个词频矢量,而不是一个布尔值矢量。在上面的示例中,单词“dog”的列在第一个文本中将接收值“4 ”,而在第二个文本中仅接收值“1”。现在,规范化这些值是可以的,但不是必须的(只是为了更快的处理)。
一个乱七八糟的包!图片由 Pinterest 上的 Cocoon Innovations 提供。
这种模型被称为“包”,因为它不保持单词“秩序”(就像我们妈妈在 90 年代的包总是乱七八糟)。
但是在讨论单词袋模型的缺点之前,我们先来看看如何使用 Python 和 Numpy 实现它。
这很简单,但是让我们一步一步来看。我决定让它成为一个类,这样我就可以在一个模型中实例化多个 BoW。这是类构造函数:
基本上,我们有一组所有单词和几个字典来存储单词索引。
接下来,我们通过拟合来准备我们的单词包(一次添加所有的文档,所以它可以‘学习’我们可以使用的单词)。
最后,我们可以转换新的输入,返回整个词汇表大小的数组,并计算该单词出现的次数。为此,我使用 numpy,这是一个数学和代数库,专门研究向量/矩阵代数。这是 python 目前针对这类任务的默认库(并被用作大多数机器学习库的输入格式)。
这是一个用法和输出示例:
现在我们已经看到了它是如何完成的,我们可以讨论模型中的问题了:
第一个:完全无视语序。您可以通过查看下图来理解这一点:
图片作者。
第二:趋于非常高维度。根据牛津英语语料库,如果你的语料库只包含 90%最常见的英语单词至少一次,那将产生至少 7000 维的向量(其中大部分为零,但仍然是很多维)!
但是弓很简单,能为简单的问题带来快速的结果。如果在构建 NLP 解决方案时,您不确定从哪里开始,请尝试最基本的方法:使用 BoW 模型。它是一个很好的基线估计器。
仅指出一点,有一个变体在大数据案例中是有用的,特别是在您必须在字符库中比较文本的情况下(不考虑语义)。该方法使用文本瓦片区(收缩)。在这种情况下,不要将句子拆分成单词,而是在每 k 个字符或每个停用词处进行拆分。点击此处阅读更多内容:
下一篇:参考资料和进一步阅读:网络搜索基础知识上一篇:索引大小和估计内容索引一…
nlp.stanford.edu](https://nlp.stanford.edu/IR-book/html/htmledition/near-duplicates-and-shingling-1.html)
TF-IDF 模型
这个实际上并不是一个模型,而是对计算单词相对于文档的“相关性”的改进。为简单起见,我称之为模型。
在 TF-IDF 模型中,我们不是存储单词的频率,而是存储对输入数据执行 tf-idf 算法的结果。 TF 代表词频, IDF 代表逆文档频率。
简而言之,TF-IDF 计算一个词在特定文档中的权重,同时考虑词的总体分布。结果的呈现方式与单词包相同:一个稀疏的向量(0 表示没有出现的单词,否则有些单词会浮动)。
例如,在情感分析任务中,与单词袋相比,TF-IDF 模型可以返回更好的结果。
为了更好地理解,让我们把这个算法分成两部分:计算全局逆文档频率,然后计算单独的 TF-IDF 分数。
逆文档频率
第一部分是计算每个单词的全局 IDF 值。这个值表示每个单词在所有文档中的权重(在整个语料库中)。这意味着非常常见的单词将具有较小的总权重,而罕见的单词将具有较大的权重(这甚至消除了去除停用词的需要,因为它们非常常见,所以权重较小)。
有许多不同的方法来计算 TF 和 IDF(例如,看看算法维基百科页面)。我选择使用对数标度的 IDF,其计算公式如下:
其中:
- D =文件总数
- freq =出现该术语的文档数。
首先,我们定义一个助手方法:
1)将句子转换成单词和频率的字典的简单方法(可以使用 Python 集合“Counter”来获得最佳性能,但为了简单起见,我将使用旧的字典方法):
然后我们初始化 IDF 类,类似于 BoW 类:
对于拟合,我们根据上面提到的公式计算全局词频率,然后是每个词的 idf。
太好了,我们的文档有了全球 IDF。现在,通过找到每个句子中每个术语的术语频率分数并乘以全局术语 IDF,为每个句子计算 TF-IDF。
计算词频
简而言之,我们通过以下方式获得一个句子的 TF-IDF 得分:
- 统计句子中术语的出现频率。
- 将每个术语的术语频率乘以逆文档频率。
下面是代码(注意,我添加了一些条件和私有方法来说明批量转换):
就这样,我们的 TF-IDF 特征化完成了!
现在,对于每一个句子,我们得到一个数组,它的大小相当于整个词汇表的大小,包含每个单词与该句子的相关性(如果缺少,则为 0)。
下面是一个输出示例:
或者更“可读”一点:
{‘of’: 0.0, ‘list’: 0.0, ‘sentence’: 0.08664339756999316, ‘a’: 0.07192051811294521, ‘second’: 0.0, ‘sentences’: 0.0, ‘in’: 0.0, ‘complexity’: 0.0, ‘is’: 0.08664339756999316, ‘this’: 0.08664339756999316, ‘word’: 0.08664339756999316, ‘for’: 0.0}
你可以在这里找到用于生成上述‘解释’的代码。
这是到目前为止实现的提交,请注意代码中会有一些不同,因为我也将使用我的工具集中内置的一些结构。:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/Sirsirious/NLPTools/tree/b48910b1db6e0de463b1713fcb65521df98e58e6)
关于 BoW 和 TF-IDF 的一些讨论:
正如我们所看到的,BoW 和 TF-IDF 方法为一个句子生成一个向量,其大小相当于整个词汇表。这不考虑词序或位置,使得这些技术不适合连续性敏感的应用程序(大多数 NLP 应用程序都是如此)。
一种可能的解决方法是对每个单词使用 BoW/TFIDF 数组,将它们堆叠起来并作为特征传递,如下图所示(以人工神经网络的输入层为例):
图片作者。
对于上面的图像,你有一个 10000*4 的稀疏矩阵,用于一个 4 个单词的句子(即使每个布尔使用一个位,你会得到大约 1kb 每个单词每个句子!想象一个大型语料库?).用于训练简单情感分析模型的计算时间和存储将使其过于昂贵或不可行(事实上,几年前,由于缺乏足够的内存和处理能力,当问题是机器学习时,文本几乎是一个未触及的话题)。
然而,这种方法允许我们保持单词顺序。如果我们能降低这个向量的维数呢?
输入单词嵌入!
单词嵌入
我不会深入解释单词嵌入,因为有几种计算它们的方法,并且大多数涉及深度神经网络,这本身需要时间来解释(这不是本文的重点)。
但我不会克制自己给你关于它的基本和最重要的信息。
让我们这样陈述:
单词嵌入是从上下文训练中学习到的单词的向量表示。它不是每个单词的分数,相反,它更像是单词的“坐标”。
因此,当训练一个模型而不是词汇大小的一次性编码时,您需要输入一个表示输入的单词嵌入数组。这个数组有一个预定义的 d 维深度,它通常比词汇表的大小小得多。
最著名的生成单词嵌入的技术之一是 Word2Vec,它是该方法的创始人。Word2Vec 本身可以使用两种不同的技术来计算,但是细节在这里并不重要。
相反,您最好知道训练/使用嵌入的方式有多种变化。这里总结了用于创建嵌入的技术:
- Word2vec (Google) - 2 技术:连续词包(CBoW)和 Skip-Gram;
- 全局向量或手套(斯坦福);
- 快速文本(脸书)——有趣的事实:解释了词汇之外的单词。
如果你想了解更多,我推荐这个来自 DeepLearning 的神奇课程。艾出席 Coursera:【https://www.coursera.org/learn/probabilistic-models-in-nlp】T2
生成单词嵌入的方式通常通过训练过程,允许单词根据其上下文进行编码。这导致了嵌入也能够表示单词语义(在一定程度上)的有趣效果。
因为单词是用坐标表示的,所以要进行比较(比较相似性)。如果使用诸如主成分分析(PCA)之类的技术来适当地降低维度,则可以绘制单词,并且绘制通常会将具有相似含义的单词更紧密地显示在一起,如下图所示,摘自 IBM 研究博客:
单词嵌入能够在一定程度上捕捉单词语义。句子甚至可以用嵌入来比较。图片由 IBM Research 的编辑人员提供。
坐标通常以大量的维度给出,通常在 8 到 1024 之间。这样,我们就有了一个 8 到 1024 维的非稀疏数组,而不是一堆 10000 维的填充 0 的数组。这更适合计算机使用。
这是另一个很酷的例子,摘自大卫·罗扎多在《公共科学图书馆综合》杂志上的一篇文章:
大卫·罗扎多拍摄。
当考虑人们如何使用嵌入时,重要的是指出单词嵌入可以通过两种不同的方式产生:
- 通过与正在进行的过程(如情感分析任务)一起接受训练,并根据该特定任务捕捉单词之间的关系。这就是当您使用诸如 Keras 、 Pytorch 或 Trax 等库来定义嵌入层时会发生的情况。这些层将单词索引映射到嵌入值。
- 通过在一个巨大的语料库上进行预处理来捕捉语言中最常见的关系。然后,可以将这些经过预训练的嵌入加载到模型中,以帮助加快学习过程或获得更好的结果。这就是 fastText、Word2vec 或 GloVe 的用武之地。诸如spaCy等库提供了这种嵌入用法。
我不会在这里讨论如何预训练一个嵌入,但是我准备了一个专门的帖子来解释这个实践。我建议你订阅我的帐户,以便在文章发表时得到通知,或者留意这一段,因为当它准备好时,我会在它下面发表一个链接。
关于这个主题再补充一点,当把文本转换成特征时,也可以进行特征工程。换句话说,数据科学家可以应用自己的规则(通常通过预处理)来定义在将文本转换成数字数组之前应该提取什么。
正如我们所看到的,将文本转换成功能看起来可能是一件简单而琐碎的事情,但是需要考虑很多事情。
在被输入编码器之前,单词索引被映射到它们各自的嵌入,这是在训练过程中使用的真实值。图片取自py torch seq seq 车型教程。
目前,NLP 中的大多数现有技术仅使用单词嵌入,因为它们更健壮并且能够以顺序方式使用。
当然,每个算法和问题都需要对输入文本进行特定的操作。例如,Seq2Seq 模型通常有一个固定的序列
长度。为了加强这一长度,使用了填充或压缩。但最后,填充和文字都转换成了嵌入。
既然我们已经完成了 NLP 预处理中最基本的主题,我们可以开始讨论应用程序和技术了。别忘了订阅敬请关注,收到下一个话题的通知!
此外,请经常查看我的存储库中的新代码。根据当前的许可,随意重用和贡献代码。如果你需要帮助,可以通过 Linkedin 联系我,只要查看我的个人资料就可以了!下一篇文章再见。
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/Sirsirious/NLPTools)**
创建数据科学家工具带。
如何将 Python 程序从 IDE 中取出并放入命令行
TL;所有必要的步骤都在底部的代码片段中。
作为一名学生,我看到我的许多同学创造了令人印象深刻的工具,我想把它们整合到我的工作流程中。但是这些功能要么归入 Jupyter 笔记本,要么归入 Slack 上共享的代码片段集合。
这篇文章的目标是给你一个实用的知识,如何在你的 mac 上的任何地方创建一个可执行的脚本。本教程将涉及许多不同的主题。为了简短起见,我将不详细介绍任何步骤。我将为那些好奇的人提供进一步阅读的链接。
另外,我用的是 z-shell 和一台 mac。如果你使用 z-shell 或者 bash (将 **zshrc**
替换为 **bashrc**
) ,所有这些步骤都可以工作。
教程大纲:
1)检查您是否有 python3,并且它是最新的
2)创建一个简单的示例程序来打印到 stdout
3)学习如何使你的脚本可执行
4)将脚本添加到新的源路径,以便在任何目录下都可以调用
1)检查您是否有 python3,并且它是最新的
如果你像我一样是计算机科学的新手,你可能不知道你在哪里安装了 Python3,或者你是否安装了它。让我们确保您将它放在正确的目录中。这篇文章概述了如果你犹豫不决,我们将要做的事情。
以下所有步骤都将发生在您的终端内部。
打开你的终端,让我们开始编码吧!
让我们检查一下你是否安装了 python3。为此,我们将调用which
函数。which
将在你的路径变量中搜索 python3 的位置。
which python3
如果你看到类似于:
something/something/python3
你可以跳过这一步,继续制作你的第一个命令行工具。
但是,如果您看到python3 not found
,您需要遵循这里概述的步骤。我推荐做一个brew install python3
,但是如果你不太习惯自制软件,你也可以在这里下载安装程序。
安装 python3 后,重复上述步骤,python3 应该已经安装,PATH 变量现在将指向正确的目录。
让我们继续吧。
2)创建一个简单的程序来打印到标准输出
使用您喜欢的文本编辑器或 IDE (我将使用 VIM) 创建一个简单的“script.py”。对我们美国人来说,2020 年的情况尤其糟糕。为了振作起来,我将编写一个简单的命令行程序来鼓励用户!让我们称它为鼓励。py。它将 1 个参数,用户的名字和打印出一个个性化的笔记。
vim encourage.py
sys.argv 允许您为 CLI 提供命令行参数。
目前,这是一个 Python 脚本,我们只能使用函数 python3 来运行它。
python3 encourage.py tim
You're doing great, Tim!
您可能已经知道了 shell 中的别名,我们可以通过将 alias 命令附加到 shell 资源文件(zshrc)中来实现。注意,如果你没有 ~/。zshrc 文件,这将为您创建一个:
echo "alias py='python3'" >> ~/.zshrc
很好,现在我们可以简单地调用:
py encourage.py tim
You're doing great, Tim!
但是,这不是我们想要的。我们可以做得更好,并删除”。我们文件里的 py。的”。py”只对文本编辑器或 IDE 中的语法突出显示很重要。它不需要文件扩展名,因为您给函数 Python3 的是纯文本文件。这个你可以自己测试!
# rename your function
mv encourage.py encourage
py encourage tim
You're doing great, Tim!
太好了!现在我们要完全放弃“Python3”函数,制作一个完整的命令行程序。
3)让你的脚本可执行
在上一节中,我们了解到当我们调用 Python3 函数时,脚本的名称充当命令行参数。函数 Python3 不关心你的脚本是否有. py,因为它会接受你给它的任何纯文本文件。然而,如果我们想完全放弃调用 Python,那么我们必须在脚本的顶部插入 shebang 命令 #!/usr/bin/env python3
:
这告诉您的 shell 在读取该文件时将它解释为 Python 代码。默认情况下,您的 shell 不允许您执行文件,因此您必须为设置一个权限标志。在您的 shell 中运行这个命令,它将更改文件的权限,以便它是可执行的。
chmod +x encourage
在运行 chmod +x 鼓励我们的文件现在应该预览如下
现在我们可以运行我们的程序,只需:
./encourage tim
You're doing great, Tim!
有多简单?
4)将脚本添加到我们的 PATH 变量中,这样它在任何目录中都是可调用的
cp、touch、ls 和 mkdir 的目录都存储在 PATH 变量中
你会注意到,为了调用它,你必须和函数在同一个目录中,但是我们希望能够从任何地方调用我们的函数。为了实现这一点,我们必须更新我们的 路径变量。PATH 变量加载到你的 shell 中,告诉 shell 在哪里寻找命令行函数。git、cd、ls 和 mkdir 目录的位置都存储在 PATH 变量中。我们有一个全新的功能鼓励我们需要添加到路径中。让我们首先在我们的用户目录中创建一个名为 bin 的新目录,并将我们程序的副本放在那里:
mkdir ~/.local/bin
cp encourage ~/.local/bin/encourage
然后,我们需要在 shell 资源文件中添加一个命令来更新我们的路径变量:
echo “PATH=$PATH:~/.local/bin/” >> ~/.zshrc
现在要么重启你的终端,要么运行source ~/.zshrc
您已经准备好测试您的程序了!切换到除您一直工作的目录之外的任何目录,并运行您的代码:
encourage tim
You're doing great, Tim!
恭喜你!你完了。所有代码都在一个地方:
# Remove old version of python and do a fresh brew installsudo rm -rf /Library/Frameworks/Python.framework/Versions/3.6
sudo rm -rf “/Applications/Python 3.7”
brew install python3# Shebang command to add to the top of your script (include the "#")#!/usr/bin/env python3# Make the script executable by running this in your terminalchmod +x script# Create a local bin and add it to your shell PATH variablemkdir ~/.local/bin
echo "PATH=$PATH:~/.local/bin/" >> ~/zshrc# move a copy of your script to the ./local/bin
cp script ~/.local/bin/script# Restart your terminal or shell
source ~/.zshrc
如何将您的网络摄像头变成运动检测控制器
如何使用 JavaScript 实现运动检测的完整指南,构建一个虚拟鼓,你只需在空中挥舞双手就可以演奏。
你玩过带运动传感器的 Xbox 游戏吗?在电子游戏中,只要挥动手臂去打网球就感觉很酷。运动检测是让这一奇迹发生的技术,它可以检测到物体相对于其周围环境的位置变化。
在这篇文章中,让我们来找点乐子。我打算建一个虚拟的鼓乐场,让你只需在空中挥舞双手就能敲鼓。它不需要任何运动传感器,只需要打开电脑或手机上的摄像头。
这是虚拟鼓游乐场的演示。正如你所看到的,当鼓和钹在那个区域探测到显著的运动时,它就会演奏。
点击下面的链接亲自尝试一下:
[## 运动检测-使用网络摄像头播放鼓声- Benson 技术
你玩过带运动传感器的 Xbox 游戏吗?挥动手臂击球的感觉真酷…
bensonruan.com](https://bensonruan.com/motion-detection-play-drums-with-webcam/)
履行
你玩得开心,像摇滚明星一样一直打鼓吗?你好奇这种神奇是怎么发生的吗?我首先受到了这个木琴版本的启发,然后建立了我的上面的鼓版本。下面跟随我实现这个虚拟鼓游乐场的旅程。
#步骤 1:将网络摄像头传输到浏览器
为了让你的网络摄像头进入浏览器,我使用了 JavaScript 库navigator.mediaDevices.getUserMedia
。要了解更多细节,请参考我之前的博客:
[## 如何使用 JavaScript 访问网络摄像头并拍照
介绍网络摄像头-简易 npm 模块
medium.com](https://medium.com/swlh/how-to-access-webcam-and-take-picture-with-javascript-b9116a983d78)
#步骤 2:标记每个滚筒区域
用鼓和钹的图像覆盖网络摄像头。这是为了在网络摄像头中设置目标区域,以便每当在这些区域检测到重大运动时,它就会触发播放齿轮的效果。
HTML
JavaScript
通过齿轮的(x,y,宽度,高度)来存储齿轮的位置,请注意,宽度和高度需要通过全屏相机大小和混合画布大小之间的比率来计算。
#步骤 3:加载声音音频
为了演奏鼓和钹,我们需要加载这些乐器的音频声道文件。
#步骤 4:通过混合模式差异进行运动检测
这是进行运动检测的最重要的部分。它使用了一种叫做Blend Mode Difference
的技术。
首先,我来解释一下混合模式差异的概念。想象你拍了一张照片,半秒钟后又拍了一张,如果在那半秒钟内没有任何东西移动,那两张照片会完全一样。当你减去这两张图片的像素值时,它将全是 0,混合图像将完全是黑色的。如果在某些区域有移动,混合图像将突出显示差异。
有关更多详细信息,请参考下面的文章:
了解如何使用 HTML5、JavaScript 和 jQuery 来检测网络摄像头流的移动,并对用户做出实时反应…
www.adobe.com](https://www.adobe.com/devnet/archive/html5/articles/javascript-motion-detection.html)
#第五步:播放效果和声音
我们为网络摄像头视频的每一帧反复调用以下函数进行运动检测。
**function****update()** {
drawVideo();
blend();
checkAreas();
**window.requestAnimationFrame(update);**
}
在鼓和钹的区域内,如果它检测到帧之间的显著差异,则表明该区域有运动。然后我们播放相应档位的效果和声音。
while (i < (blendedData.data.length * 0.25)) {
**average += (blendedData.data[i*4] + blendedData.data[i*4+1] + blendedData.data[i*4+2]) / 3;**
++i;
}
average = Math.round(average / (blendedData.data.length * 0.25));
**if (average > 20)** { //over a threshold, means significant movement
playHover(drum);
}
代码就这么多了。让我们享受和玩一些疯狂的鼓!
GitHub 知识库
您可以通过下面的链接下载上述演示的完整代码:
从网络摄像头检测动作,通过在空中挥舞双手来玩虚拟鼓。
github.com](https://github.com/bensonruan/Motion-Detection-Virtual-Drums)
结论
如今,运动检测已经应用于许多领域,例如安全警报、自动门……有些与传感器一起工作,有些可能基于计算机视觉目标检测。毕竟,我希望你觉得这个虚拟鼓游乐场有趣,并激起你对最新技术的兴趣。
感谢您的阅读。如果你喜欢这篇文章,请在 LinkedIn 或 Twitter 上分享。如果你有任何问题,请在评论中告诉我。在 GitHub 和 Linkedin 上关注我。
如何学习数据科学
加速您的数据科学学习之旅
我刚刚读完斯科特·扬的 Ultralearning ,我认为这本书里的概念可以帮助许多想学习数据科学的人。Scott 用这种方法在一年内(通常需要四年)学习完了麻省理工学院本科生的计算机科学课程,并通过了所有的考试。
一、什么是超学习?
**超学习:**一种获取技能和知识的策略,这种策略是自我导向的和强烈的。
斯科特有 9 条超级学习原则。在本文中,我将重点介绍一些与您的数据科学研究最相关的因素(元学习、专注、直接、反馈和实验)。如果你想了解其余的(操练、提取、记忆和直觉),我强烈推荐你读这本书。这篇文章与我的数据科学学习阶段文章(链接)非常吻合,所以如果你喜欢这篇文章,你可能想在之后阅读那篇文章。
元学习
书中的第一个原则叫做元学习。这为你的学习之旅奠定了基础。你应该花时间对这个领域有一个广泛的了解,并创建一个学习路线图。Scott 建议你应该在这一步上花费你总学习时间的 10%。
首先,你应该想想你到底想达到什么目的。要不要用数据科学搭建一个特定的 app?你想学足够的数据科学来找工作吗?在这里,你越具体越好。
接下来,你应该开始规划一条通往这个目的地的学习路径。我认为这非常类似于为自学课程建立你自己的课程。
从根本上说,数据科学只是编程和数学的结合。我做了几个视频,帮助你从哪里以及如何学习这些概念:如何学习数据科学的数学 & 如何学习数据科学的编程。
我还建议在网上寻找数据科学课程。大多数大学都在网上发布这些,你可以看到这些学校推荐学生上什么课或学什么概念。由此,你可以弄清楚你需要学习哪些概念,才能达到你特定的学习目标。
在你有了一个学习路径之后,你需要找到一个坐下来真正做工作的方法。
焦点
这不是数据科学特有的,但专注是一项值得学习的技能。没错,专注是一种习得的技能而不是与生俱来的。有两个主要组成部分,建立你集中注意力的能力和限制分心。
为了集中注意力,你应该专心工作,不要分心。这是卡尔·纽波特在他的《T2 深度工作》一书中谈到的一个概念。当你安排工作时间并坚持执行时,你就是在训练你的大脑。杨还推荐番茄工作法,即工作 25 分钟,休息 5 分钟。安排你的休息时间对我来说是一个巨大的突破。
为了减少分心,我建议控制你的环境。拥有一个专用的工作空间是很好的第一步。你的手机可能是你最大的干扰,所以把它放在不同的房间里,关闭电脑上的通知功能,会对你的注意力产生神奇的效果。
直接
这是我迄今为止最喜欢的原则。它建议你应该一头扎进去,开始做你努力学习的实际活动。当您接触到真实世界的数据科学项目时,您几乎会立即意识到自己的不足。我不断地推荐项目,我认为它们是学习数据科学最有效的方式。
当开始一个新项目时,我通常会工作到被某样东西卡住为止。一旦我这样做了,我打开几个谷歌标签,了解我正在努力的领域,并找出如何将它应用到我的项目中。这种方法保证了你正在学习完成手头项目所需要的东西。有时,我们陷入困境,因为我们试图学习太多来解决我们的问题。缩小范围和直接可以帮助我们提高学习效率。
直率可能会非常令人生畏。你会为你不知道的事情而挣扎和沮丧。这是完全正常的,也是作为一名数据科学家的一部分。这种感觉不会消失,即使你已经在这个领域取得了很大进展。
反馈
这可能令人害怕和不舒服,但却极其重要。数据科学很好,因为有许多清晰的反馈来源。在编程中,大多数时候你做错了事就会出错。您应该仔细阅读这些错误,因为它们通常会提示您哪里出错了。我也推荐使用 Google 和 Stack Overflow 调试代码。你通常只需将你的错误信息复制粘贴到浏览器中,就可以发现其他人是如何解决你所面临的同样问题的。
另一种获得有价值反馈的方法是通过社交平台来寻求反馈。Kaggle 和 Reddit 在这方面都很棒。有许多数据科学初学者论坛,对于构建促进建设性反馈的社区来说非常棒。
通常最好的反馈来自专家。你可以向网络中的数据科学家、教授或其他做过类似项目的人寻求反馈。我发现这种类型的帮助是最难得到的,但能帮助你提高最多。
实验
实验可以让你的数据科学工作从优秀走向卓越。当我们学习这个领域时,我们通常只用一种方法来解决每个问题。事实上,有许多不同的方法来分析每个项目。你做实验的时候,从不同的角度看同一个问题。这有助于您找出哪种方法最适合手头的任务。
当你做实验时,你经常不得不忘记一些你以前知道的事情。如果你只有一把锤子,一切都是钉子。如果你失去了你的锤子,你将需要找到独特的方法来建造。其中一些不同的方法可以节省您的时间/计算资源,并且实际上可以产生更好的结果。
实验有助于拓展你对概念的理解,并接近更高的学习水平。
最后的想法
希望这些原则能帮助你以新的眼光看待你的数据科学学习之旅。我希望我可以带着这些想法开始我自己的学习过程。同样,如果你想更深入地探索所有这些原则,我推荐你阅读这本书。
*顶部的超级学习链接是亚马逊联盟链接。通过链接购买的每件商品,我都可以免费获得几分钱。如果你想表示你对我或我的文章的支持,请随时通过它购买这本书!
如何取消删除您的 Jupyter 笔记本
用 SQL 和命令行破解 Jupyter 笔记本的元数据科学
谁不爱 Jupyter 笔记本?它们是互动的,给你即时反馈的即时满足感。它们是可扩展的——你甚至可以把它们作为网站来部署。对于数据科学家和机器学习工程师来说,最重要的是,它们具有表现力——它们跨越了操纵数据的科学家和工程师与消费并希望理解数据所代表的信息的普通观众之间的空间。
但是 Jupyter 笔记本也有缺点。它们是大型 JSON 文件,存储您运行的每个单元的代码、降价、输入、输出和元数据。为了理解我的意思,我写了一个简短的笔记本来定义和测试 sigmoid 函数。
朱庇特笔记本。
以下是当 IPython 不渲染它时(的一部分)看起来的样子(除了第一个实际的输入单元格,我已经省略了所有的单元格,因为即使对于一个短笔记本来说,它也是又长又丑的):
{
"nbformat": 4,
"nbformat_minor": 2,
"metadata": {
"language_info": {
"name": "python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"version": "3.6.8-final"
},
"orig_nbformat": 2,
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"npconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": 3,
"kernelspec": {
"name": "python36864bitvenvscivenv55fc700d3ea9447888c06400e9b2b088",
"display_name": "Python 3.6.8 64-bit ('venv-sci': venv)"
}
},
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import random"
]
},
...
}
因此很难对它们进行版本控制。这也意味着有很多你通常不太关心保存的垃圾数据,比如单元执行计数和输出。
下次你想知道为什么你的 Jupyter 笔记本运行如此缓慢时,在纯文本编辑器中打开它,看看你的笔记本元数据中有多少海量数据帧。
不过,在适当的情况下,所有这些垃圾看起来都像珍贵的宝石。这些情况通常包括:
- 意外关闭笔记本而未保存它
- 点击错误的快捷键,删除重要的单元格
- 在多个浏览器窗口中打开同一笔记本并覆盖您自己的工作
任何误入在 IPython 笔记本上进行开发的危险领域的人都至少做过一次这些事情,可能是在同一时间。
如果这是你,你在这里是因为你谷歌了恢复删除 jupyter 笔记本刷新浏览器窗口,不要惊慌。首先我要告诉你如何修理它。*然后我要告诉你如何防止它再次发生。
*是的,你能修好它。(大概吧。)
我为你做的一本指南,在笔记本上,关于笔记本
要求:
- 安装了 Jupyter、IPython(带有 nbformat 和 nbconvert)和 jupytext 的 Python 虚拟环境(最好是一个新的 venv,这样您可以测试一下)
- sqlite3 的工作安装(可选但推荐:像 SQLiteStudio 这样的数据库浏览器)
- 希望和决心
场景:您意外删除了活动笔记本中的几个单元格
(不科学)估计恢复概率:90%
相对难度:更容易
在最坏的情况下,您点击了不想删除的单元格上的x
,现在您想取回它的代码或数据。
方法一:进出
当您使用笔记本时,IPython 内核会运行您的代码。IPython 内核是一个独立于 Python 解释器的进程。(这也是为什么您需要将新的内核链接到新的虚拟环境。这两者不是自动连接的。)它使用 JSON 发送和接收消息,就像您的代码单元一样。
当您运行一个单元或点击“保存”时,笔记本服务器会将您的代码作为 JSON 发送到您计算机上的一个笔记本中,该笔记本存储您的输入和输出。所以你手机旁边的小单词In
和Out
不仅仅是单词,它们是容器——特别是你会话历史的列表。你可以打印出来并编入索引。
[]容器中的 IPython
方法二:IPython 魔术
使用%history
line magic 打印您的输入历史(后进先出)。这个强大的命令允许您通过绝对或相对数字访问当前和过去的会话。
如果当前的 IPython 进程仍然处于连接状态,并且您已经在您的虚拟环境中安装了nbformat
,那么在单元格中执行以下代码来恢复您的笔记本:
>>> %notebook your_notebook_filename_backup.ipynb
这种魔法将整个当前会话历史呈现为一个新的 Jupyter 笔记本。
嗯,还不算太糟。
这并不总是有效,您可能需要花费一些精力从输出中剔除无关的单元格。
你可以用历史魔法做更多的事情。这里有几个我觉得有用的食谱:
%history -l [LIMIT]
获取最后的 n 个输入%history -g -f FILENAME
:将您的整个保存的历史记录写入一个文件%history -n -g [PATTERN]
:使用 glob 模式搜索您的历史,并打印会话和行号%history -u
:仅从当前会话中获取唯一的历史。%history [RANGE] -t
:获取本机历史,也就是 IPython 生成的源代码(有利于调试)%history [SESSION]/[RANGE] -p -o
:使用>>>
提示符打印输入和输出(适合阅读和文档)
如果你已经在一个真正的大数据科学笔记本上工作了很长时间,那么%notebook
魔法策略可能会产生很多你不想要的噪音。使用其他参数削减%history -g
的输出,然后使用 jupytext(解释如下)转换结果。
场景:你关闭了一个未保存的笔记本
(不科学的)估计恢复概率:70–85%
相对难度:更难
还记得我们说过笔记本的版本控制很难吗?一个内核可以同时连接到多个前端。这意味着打开同一笔记本的两个浏览器选项卡可以访问相同的变量。这就是你最初重写代码的方式。
IPython 将您的会话历史存储在数据库中。默认情况下,您可以在您的主目录下的一个名为.ipython/profile_default
的文件夹中找到它。
$ ls ~/.ipython/profile_defaultdb history.sqlite log pid security startup
备份history.sqlite
到副本。
$ cp history.sqlite history-bak.sqlite
在数据库浏览器中或通过 sqlite3 命令行界面打开备份。它有三个表:历史、输出历史和会话。根据您想要恢复的内容,您可能需要将这三者结合在一起,所以请放弃您的 SQL。
IPython 历史的 SQLiteStudio 视图
盯着它
如果您可以从数据库浏览器 GUI 中判断出history
表中的哪个会话号有您的代码,那么您的生活就简单多了。
历史表的 SQLiteStudio 视图
在浏览器中或命令行上执行 SQL 命令:
sqlite3 ~/.ipython/profile_default/history-bak.sqlite \
"select source || char(10) from history where session = 1;" > recovered.py
这只是指定会话号和要写入的文件名(在给出的例子中是1
和recovered.py
),并从数据库中选择源代码,用换行符(在 ASCII 中是 10)分隔每个代码块。
如果您想选择行号作为 Python 注释,可以使用如下查询:
"select '# Line:' || line || char(10) || source || char(10) from history where session = 1;"
一旦你有了一个 Python 可执行文件,你就可以松一口气了。但是你可以用 jupytext 把它变回笔记本,这是一个神奇的工具,可以把明文格式转换成 Jupyter 笔记本。
jupytext --to notebook recovered.py
不太可怕!
场景:你在多个标签页中打开你的笔记本,重新加载一个旧版本,删除你所有的工作,并杀死你的内核
(不科学的)估计恢复概率:50–75%
相对难度:最难
以上都不起作用,但你还不准备放弃。
硬模
回到你正在使用的任何工具来浏览你的history-bak.sqlite
数据库。您编写的查询将需要创造性的搜索技术来充分利用您拥有的信息:
- 会话开始的时间戳(总是非空)
- 会话结束的时间戳(有时以有用的方式为空)
- 输出历史
- 每个会话执行的命令数
- 您的输入(代码和降价)
- IPython 的渲染源代码
例如,您可以通过以下查询找到您今年编写的与 pytest 相关的所有内容:
**select** line, source**from** history**join** sessions**on** sessions.session = history.session**where** sessions.start > '2020-01-01 00:00:00.000000'**and** history.source like '%pytest%';
一旦您将视图调整为您想要的行,您可以像以前一样将其导出到可执行的.py
文件,并使用 jupytext 将其转换回.ipynb
。
如何避免需要这篇文章
当你品味不必从头重写笔记本的解脱时,花点时间思考一些措施来防止未来的探索进入history.sqlite
:
- 不要将相同的前端连接到同一个内核。换句话说,不要在多个浏览器标签中打开同一个笔记本。使用 Visual Studio 代码作为您的 Jupyter IDE 很大程度上消除了这种风险。
- 定期备份您的 IPython 历史数据库文件,以防万一。
- 尽可能将您的笔记本转换为明文,至少为了备份。Jupytext 让这变得几乎微不足道。
- 使用 IPython 的
%store
魔法在 IPython 数据库中存储变量、宏和别名。你所需要做的就是在profile_default
中找到你的ipython_config.py
文件(或者如果你没有的话运行ipython profile create
,添加这一行:c.StoreMagics.autorestore = True
。如果你愿意,你可以存储、别名和访问从环境变量到小型机器学习模型的任何东西。这是完整的文档。
Jupyter 笔记本给你带来的最大挑战是什么?对你想在以后的帖子中讨论的话题发表评论。