针对印度口音微调 Mozilla DeepSpeech
谷歌语音识别 API 的最佳开源替代品——现在是第二大英语国家!
让计算机识别语音的最初尝试之一是专注于识别数字!贝尔实验室在 1952 年设计了 奥黛丽系统 ,它可以识别单个语音说出的数字。从那以后,维基百科的这篇文章中详细记录了许多其他的实验。快进到今天,我们有最先进的自动语音识别引擎(ASR ),如苹果的 Siri、谷歌助手和亚马逊的 Alexa。
很长一段时间,谷歌的语音转文本 API (STT)是任何 ASR 任务事实上的选择。当像Mozilla deep speech这样的开源替代品在 2017 年末问世时,这种情况慢慢改变了。它基于百度的原始深度语音研究论文,并使用(大部分)美国英语数据集进行训练,导致对其他英语口音的泛化能力较差。
在最近的一次实习中,我不得不为一个视频会议平台集成一个 ASR 引擎,这个平台主要由印度人使用。我们更倾向于寻找开源替代方案,但是大多数通用方案在实时会议中表现不佳。就在那时,我看到了 DeepSpeech 和 IITM 的Indic TTS项目。
Indic 数据集包含超过 50 GB 的来自印度 13 个邦的说话者的语音样本。它由 10000 多个英语口语句子组成,既有男性也有女性母语者。这些文件可以在中找到。wav 格式连同相应的文本。
在本文中,我将向您展示使用 Indic 数据集对 DeepSpeech 进行微调的过程,但是您也可以轻松地对其他英语数据集进行微调。你可以在 IITM 网站上注册,向他们索取数据集。
先决条件:熟悉 ASR 引擎、语音处理,并对递归神经网络和张量流有基本的了解。
注意:我所有的训练和预处理都是在 Google Colab 上用 DeepSpeech 版本 0.7.4 完成的
预处理数据集
在你申请数据集后,IITM 会给你七天的时间访问他们的 Google Drive 链接。因为我长期需要这些数据,所以我把所有的 ZIP 文件都转移到了 Google Cloud Bucket 中。每个 ZIP 文件都会有一个包含的文件夹。wav 文件和对应的名为 txt.done.data 的元数据文件。
我们需要处理元数据文件,并为数据集生成培训/开发/测试分割。我们可以一次为一个州训练模型,或者将几个州分组,然后训练模型。下图显示了如何处理元数据。
作者图片
下面给出的 GitHub 要点包含了生成单个 CSV 文件的完整代码,我们稍后需要对其进行拆分。大部分代码都是不言自明的,有足够的注释。确保先安装好 Librosa 和 num2words 。
执行脚本时, wav 参数指向包含所有音频文件的文件夹,而 meta 参数指向包含 txt.done.data 文件的文件夹。这里,第一部分将数据从 Google Bucket 复制到 Colab。第二部分创建一个 CSV 文件,最后一个命令追加到这个 CSV 文件中,依此类推。如果您想单独训练每个 ZIP 文件,只运行一个命令并继续分割 CSV(尽管我不建议这样做)。如果附加到同一个文件,小心注释掉第 45 行。
$ gsutil cp gs://bucket-name/hindi_female_english.zip /content/hindi_female_english.zip
$ gsutil cp gs://bucket-name/hindi_male_english.zip /content/hindi_male_english.zip$ unzip hindi_female_english.zip -d /content/hindi_female_english
$ unzip hindi_male_english.zip -d /content/hindi_male_english--------------------------------------------------------------------$ python preProcess.py --wav /content/hindi_female_english/english/wav --meta /content/hindi_female_english/english$ python preProcess.py --wav /content/hindi_male_english/english/wav --meta /content/hindi_male_english/english
现在,我们有一个 CSV 文件,需要将它分成三个单独的文件。在左边的要点中,我们首先将主 CSV 文件分割成序列和中间,然后将中间分割成开发和测试。然后我们最终有了三个文件,对应于 DeepSpeech 训练所需的三个拆分。
微调深度演讲
这里给出了官方培训文档。它非常详细,但跳过了一些可能会让你沮丧很长时间的细节😩。我假设您已经将数据集传输到 Google Cloud bucket,并且有适当的互联网连接,因为如果您不快速重新连接,Colab 会终止您的实例。以下所有步骤均摘自 Colab 上的 培训笔记本 此处 。
- 授权 Colab 访问您的 Google Cloud Bucket: 下载您项目的 IAM 访问凭证文件并上传到 Colab。
import os
from google.colab import authauth.authenticate_user()os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "creds.json"#ensure the path is set correctly
!echo $GOOGLE_APPLICATION_CREDENTIALSproject_id = '<gcloud-project-id>'
bucket_name = 'gs://<bucket-name>'
!gcloud config set project {project_id}
2。从 GitHub: 克隆 DeepSpeech v0.7.4,下载相应的检查点。
!git clone --branch v0.7.4 [https://github.com/mozilla/DeepSpeech](https://github.com/mozilla/DeepSpeech)!wget [https://github.com/mozilla/DeepSpeech/releases/download/v0.7.4/deepspeech-0.7.4-checkpoint.tar.gz](https://github.com/mozilla/DeepSpeech/releases/download/v0.7.4/deepspeech-0.7.4-checkpoint.tar.gz)!tar -xvf deepspeech-0.7.4-checkpoint.tar.gz -C \
/content/model_checkpoints/
****3。安装 DeepSpeech 依赖项:每次训练模型时,我们都需要安装很多东西。详细步骤在笔记本这里给出。
****4。设置默认的 CUDA 版本:如果你第一次没有做好,这部分将会非常令人沮丧😤。出于某种原因,每当你试图在 Colab 中设置默认的 CUDA 版本为 10.0 (DeepSpeech 需要 CUDA 10.0 和 CuDNN v7.6),它总是试图恢复到 10.1🤷。我发现了一系列看似有效的步骤,但我不能保证每次都有效——你可能需要挖掘一点点,才能找到正确的方法。详细步骤在笔记本这里给出。如果你仍然不能让它工作,我会非常乐意帮助:)
5。安装 TensorFlow-GPU:
!pip3 uninstall tensorflow
!pip3 install 'tensorflow-gpu==1.15.2'
6。将数据从 Google Bucket 复制到 Colab:这里需要小心,将文件复制到您生成 CSV 文件时的位置,因为模型使用 CSV 文件中声明的音频文件的绝对路径。
%cd /content/!gsutil cp gs://bucket-name/hindi_female_english.zip /content/hindi_female_english.zip
!gsutil cp gs://bucket-name/hindi_male_english.zip /content/hindi_male_english.zip!unzip hindi_female_english.zip -d /content/hindi_female_english
!unzip hindi_male_english.zip -d /content/hindi_male_english
7。检查不在 alphabet.txt : 中的额外字符这个文件(存在于 /DeepSpeech/data 中)定义了 DeepSpeech 正在被训练的语言的字母表。因为我们的任务语言是一样的,我们不需要改变它。如果我们想用一种完全不同的语言训练一个新的模型,我们需要重新定义字母表并遵循这些步骤。将三个 CSV 文件上传到 /content/ 并对其运行 check_parameters.py 。
!python3 /content/DeepSpeech/training/deepspeech_training/util/check_characters.py -csv /content/train.csv -alpha!python3 /content/DeepSpeech/training/deepspeech_training/util/check_characters.py -csv /content/dev.csv -alpha!python3 /content/DeepSpeech/training/deepspeech_training/util/check_characters.py -csv /content/test.csv -alpha
****注意:您可能需要注释掉check_characters.py
中的一些行才能让它工作。在注释掉一些行之后,这个文件中的第 44 行应该是这样的
if not args.disable_unicode_variants:
unicode_transcript = unicodedata.normalize("NFKC", row[2])
#if row[2] != unicode_transcript:
#print("Your input file", in_file, "contains at least one transript with unicode chars on more than one code-point: '{}'. Consider using NFKC normalization: unicodedata.normalize('NFKC', str).".format(row[2]))
#sys.exit(-1)
all_text |= set(row[2])
8.训练模型(最后😌):这一步非常简单。尝试不同的超参数,并仔细检查路径。增强参数可以帮助您的模型更好地进行概化。
9.导出模型进行推理:训练过程完成后,a 。pb 模型文件被导出到 export_dir 。但是这个模型非常大(~700MB),并且对于批量预测不是非常有效。幸运的是,有一个选项可以将导出的模型转换成内存映射模型,之后我们会得到一个。pbmm 模型文件。**
%cd /content/DeepSpeech/!python3 util/taskcluster.py --source tensorflow --artifact convert_graphdef_memmapped_format --branch r1.15 --target .!./convert_graphdef_memmapped_format --in_graph=/content/models/ft_model.pb --out_graph=/content/models/ft_model.pbmm
这个。pbmm 文件相对较小(~180MB)且高效,可与相应的划线器文件一起使用,以改善推断结果。**
结论
唷!那篇文章很长😵。如果您已经到达这里,感谢您的坚持:)
在我使用 DeepSpeech 的过程中,我发现它是 ASR 最容易使用的库之一。我希望这篇文章能帮助任何自己尝试的人。
** [## 使用 Mozilla DeepSpeech 自动生成字幕
对于那些嘴里薯条的噪音让你无法看电影的时候:)
towardsdatascience.com](/generating-subtitles-automatically-using-mozilla-deepspeech-562c633936a7)**
用 Python 进行语音识别
图片来自俚语实验室
语音识别
比较 9 个最突出的选择。
语音识别技术在过去的几年里发展迅速,并且正在从科学领域过渡到工程领域。随着 Alexa、Siri 和 Google Assistant 等语音助手的日益流行,一些应用程序(例如, YouTube 、加纳王国、 Paytm Travel 、 My Jio )开始拥有语音控制的功能。在 Slang Labs,我们正在为程序员构建一个平台,让他们能够轻松地用语音体验来增强现有的应用程序。
自动语音识别(ASR)是处理语音的必要的第一步。在 ASR 中,对麦克风说出的音频文件或语音经过处理并转换为文本,因此也称为语音到文本(STT)。然后,该文本被馈送到自然语言处理/理解(NLP/NLU)以理解和提取关键信息(例如意图、情感),然后采取适当的行动。ASR 也有独立的应用,例如记录口述,或为视频制作实时字幕。
我们对 ASR 和 NLU 感兴趣,尤其是它们在应用程序中语音到动作循环的功效。我们的 Android 和 Web SDK提供了从应用程序员的角度来看合适的简单 API,而俚语平台则处理将 ASR、NLU 和文本到语音(TTS)缝合在一起的复杂性负担。但是,很自然地,我们对 ASR、NLU 和 TTS 的技术状态感到好奇,尽管我们没有将我们技术堆栈的这些部分作为单独的 SaaS 产品来展示。对现有 ASR 解决方案的探索就是这种好奇心的结果。
服务与软件
有两种可能性:在云上调用语音转文本 SaaS,或者在应用程序中托管一个 ASR 软件包。
服务是最容易开始的方式。你必须报名参加 SaaS 并获得钥匙/证书。然后,您就可以在代码中使用它了,或者通过 HTTP 端点,或者通过您选择的编程语言中的库。然而,对于合理的大量使用,它通常花费更多的钱。
软件软件包在您托管它时为您提供完全的控制,还可以为您的应用创建更小的模型,并将其部署在设备/边缘上,而无需网络连接。但训练和部署模型需要专业知识和前期努力。
使用语音云服务与自托管 ASR 软件包的权衡
这是一个可逆的选择。例如,您可以从云服务开始,如果需要,迁移到您自己的软件包部署;反之亦然。您可以设计您的代码来限制这种反转的爆炸半径,以及在您迁移到另一个 SaaS 或软件包的情况下。
批处理与流式
您需要确定您的应用程序需要批处理 ASR 还是流式 ASR。
**批处理:**如果你有需要离线转录的录音,那么批处理就足够了,而且更经济。在 batch API 中,音频文件作为参数传递,语音到文本的转换一次性完成。
**流媒体:**如果你需要实时处理语音(比如声控应用,视频字幕),你就需要一个流媒体 API。在流式 API 的情况下,使用音频缓冲区的可用块重复调用它。它可能会发送临时结果,但最终结果在最后才可用。
所有的服务和软件包都有批处理 API,但是目前有些缺少流式 API。因此,如果你有一个流媒体应用程序,这消除了一些选择。
Python 的选择
大多数语音服务提供流行编程语言的库。在最坏的情况下,您总是可以使用 HTTP 端点。对于语音包来说也是如此,这些包带有各种编程语言的绑定。在最坏的情况下,您可以自己创建绑定。所以使用 Python 没有任何约束。
我为本文选择 Python,因为大多数语音云服务和 ASR 软件包都有 Python 库。此外,你可以在浏览器中使用它的同伴 Colab notebook 运行文章的代码片段,而不需要在你的计算机上安装任何东西。
一个常见的用例是从麦克风收集音频,并将缓冲区(批处理或流)传递给语音识别 API。不变的是,在这样的转录器中,麦克风是通过 PyAudio 访问的,这是通过 PortAudio 实现的。但是由于麦克风在 Colab 上不可用,我们将其简化。我们将使用一个完整的音频文件来检查批处理 API。对于流式 API,我们将把一个音频文件分成块并模拟流。
如何最好地利用文章的其余部分
涵盖以下服务和软件包。
服务:
- 谷歌语音转文本
- 微软 Azure 语音
- IBM Watson 语音测试
- 亚马逊转录
- 细微差别
软件:
- CMU 狮身人面像
- Mozilla DeepSpeech
- 卡尔迪
- 脸书 wav2 字母
由于某些特性或限制(在各自的章节中列出),没有为 Amazon Transcribe、Nuance、Kaldi 和脸书 wav2letter 提供代码示例。相反,给出了代码示例和资源的链接。
下一节有常见的实用函数和测试用例。最后一节介绍了 Python SpeechRecognition
包,它提供了对几个服务和软件包的批处理 API 的抽象。
如果你想对所有的服务和软件包有一个总体的了解,那么请打开 Colab ,在你阅读这篇文章的时候执行代码。如果您只对特定的服务或套餐感兴趣,请直接跳到该部分。但是不管是哪种情况,都要使用 Colab 中的代码来更好地探索它。
让我们深入研究代码。
通用设置
下载我们将用于测试语音识别服务和软件包的音频文件:
$ curl -LO https://github.com/mozilla/DeepSpeech/releases/download/v0.6.0/audio-0.6.0.tar.gz
$ tar -xvzf audio-0.6.0.tar.gz
$ ls -l ./audio/
它有三个音频文件。用需要的元数据定义测试用例:
TESTCASES **=** [
{
'filename': 'audio/2830-3980-0043.wav',
'text': 'experience proves this',
'encoding': 'LINEAR16',
'lang': 'en-US'
},
{
'filename': 'audio/4507-16021-0012.wav',
'text': 'why should one halt on the way',
'encoding': 'LINEAR16',
'lang': 'en-US'
},
{
'filename': 'audio/8455-210777-0068.wav',
'text': 'your power is sufficient i said',
'encoding': 'LINEAR16',
'lang': 'en-US'
}
]
另外,写一些实用函数。read_wav_file()
获取音频文件的路径,并返回缓冲字节和采样率:
**def** **read_wav_file**(filename) **->** Tuple[bytes, int]:
**with** wave**.**open(filename, 'rb') **as** w:
rate **=** w**.**getframerate()
frames **=** w**.**getnframes()
buffer **=** w**.**readframes(frames)
**return** buffer, rate
simulate_stream()
对于模拟 steam 来尝试流式 API 很有用。通常,会有一个类似麦克风的音频源。每隔一段时间,麦克风将生成一个语音块,该语音块必须传递给流 API。simulate_stream()
函数有助于避免所有的复杂性,并专注于 API。它需要一个音频缓冲区和批处理大小,生成该大小的块。请注意下面的yield buf
语句:
def simulate_stream(buffer: bytes, batch_size: int = 4096):
buffer_len = len(buffer)
offset = 0
while offset < buffer_len:
end_offset = offset + batch_size
buf = buffer[offset:end_offset]
yield buf
offset = end_offset
谷歌语音转文本
谷歌将语音转文本作为谷歌云服务之一。它有 C#、Go、Java、JavaScript、PHP、Python 和 Ruby 的库。它支持批处理和流模式。
设置
你将需要你的谷歌云证书。您需要设置指向 cred 文件的环境变量GOOGLE_APPLICATION_CREDENTIALS
:
$ export GOOGLE_APPLICATION_CREDENTIALS**=**'/path/to/google/cloud/cred/file/gc-creds.json'
$ ls -l $GOOGLE_APPLICATION_CREDENTIALS
批处理 API
使用批量语音转文本 API 很简单。您需要创建一个SpeechClient
,创建一个带有音频元数据的config
,并调用语音客户端的recognize()
方法。
**from** google.cloud **import** speech_v1
**from** google.cloud.speech_v1 **import** enums
**def** **google_batch_stt**(filename: str, lang: str, encoding: str) **->** str:
buffer, rate **=** read_wav_file(filename)
client **=** speech_v1**.**SpeechClient()
config **=** {
'language_code': lang,
'sample_rate_hertz': rate,
'encoding': enums**.**RecognitionConfig**.**AudioEncoding[encoding]
}
audio **=** {
'content': buffer
}
response **=** client**.**recognize(config, audio)
*# For bigger audio file, replace previous line with following:
* *# operation = client.long_running_recognize(config, audio)
* *# response = operation.result()*
**for** result **in** response**.**results:
*# First alternative is the most probable result
* alternative **=** result**.**alternatives[0]
**return** alternative**.**transcript
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('google-cloud-batch-stt: "{}"'**.**format(
google_batch_stt(t['filename'], t['lang'], t['encoding'])
))
当您运行它时,您将在输出中看到每个音频测试文件的文本:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
google-cloud-batch-stt: "experience proves this"
audio file="audio/4507-16021-0012.wav" expected text="why should one halt on the way"
google-cloud-batch-stt: "why should one halt on the way"
audio file="audio/8455-210777-0068.wav" expected text="your power is sufficient i said"
google-cloud-batch-stt: "your power is sufficient I said"
流式 API
谷歌的流媒体 API 也相当简单。为了处理音频流,您可以使用可用的音频块重复调用流 API,它将返回临时结果:
**from** google.cloud **import** speech
**from** google.cloud.speech **import** enums
**from** google.cloud.speech **import** types
**def** **response_stream_processor**(responses):
**print**('interim results: ')
transcript **=** ''
num_chars_printed **=** 0
**for** response **in** responses:
**if** **not** response**.**results:
**continue**
result **=** response**.**results[0]
**if** **not** result**.**alternatives:
**continue**
transcript **=** result**.**alternatives[0]**.**transcript
**print**('{0}final: {1}'**.**format(
'' **if** result**.**is_final **else** 'not ',
transcript
))
**return** transcript
**def** **google_streaming_stt**(filename: str, lang: str, encoding: str) **->** str:
buffer, rate **=** read_wav_file(filename)
client **=** speech**.**SpeechClient()
config **=** types**.**RecognitionConfig(
encoding**=**enums**.**RecognitionConfig**.**AudioEncoding[encoding],
sample_rate_hertz**=**rate,
language_code**=**lang
)
streaming_config **=** types**.**StreamingRecognitionConfig(
config**=**config,
interim_results**=**True
)
audio_generator **=** simulate_stream(buffer) *# chunk generator
* requests **=** (
types**.**StreamingRecognizeRequest(audio_content**=**chunk)
**for** chunk **in** audio_generator
)
responses **=** client**.**streaming_recognize(
streaming_config, requests
)
*# Now, put the transcription responses to use.
* **return** response_stream_processor(responses)
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('google-cloud-streaming-stt: "{}"'**.**format(
google_streaming_stt(
t['filename'], t['lang'], t['encoding']
)
))
在输出中,您可以看到随着输入更多音频,效果会有所改善:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
interim results:
not final: next
not final: iSpy
not final: Aspira
not final: Xperia
not final: Experian
not final: experience
not final: experience proved
not final: experience proves
not final: experience proves the
not final: experience proves that
not final: experience
final: experience proves this
google-cloud-streaming-stt: "experience proves this"
微软 Azure 语音
微软 Azure 认知服务是一个 AI 服务和认知 API 的家族。语音服务包括语音转文本,文本转语音,语音翻译服务。
设置
安装 Azure 语音包:
$ pip3 install azure-cognitiveservices-speech
您可以在 Microsoft Azure portal 上启用语音服务并查找您帐户的凭据。你可以在这里开一个免费账户。服务凭据:
AZURE_SPEECH_KEY **=** 'YOUR AZURE SPEECH KEY'
AZURE_SERVICE_REGION **=** 'YOUR AZURE SERVICE REGION'
批处理 API
Azure 的批处理 API 也很简单。它接受一个配置和音频输入,并返回文本:
**import** azure.cognitiveservices.speech **as** speechsdk
**def** **azure_batch_stt**(filename: str, lang: str, encoding: str) **->** str:
speech_config **=** speechsdk**.**SpeechConfig(
subscription**=**AZURE_SPEECH_KEY,
region**=**AZURE_SERVICE_REGION
)
audio_input **=** speechsdk**.**AudioConfig(filename**=**filename)
speech_recognizer **=** speechsdk**.**SpeechRecognizer(
speech_config**=**speech_config,
audio_config**=**audio_input
)
result **=** speech_recognizer**.**recognize_once()
**return** result**.**text **if** result**.**reason **==** speechsdk**.**ResultReason**.**RecognizedSpeech **else** None
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('azure-batch-stt: "{}"'**.**format(
azure_batch_stt(t['filename'], t['lang'], t['encoding'])
))
输出将如下所示:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
azure-batch-stt: "Experience proves this."
audio file="audio/4507-16021-0012.wav" expected text="why should one halt on the way"
azure-batch-stt: "Whi should one halt on the way."
audio file="audio/8455-210777-0068.wav" expected text="your power is sufficient i said"
azure-batch-stt: "Your power is sufficient I said."
流式 API
Azure 有几种流 API。通过创建不同类型的音频源,人们可以推送音频块,或者向 Azure 传递回调来拉取音频块。它触发几种类型的语音识别事件来连接回调。以下是如何将推送音频流与音频流发生器连接起来:
**import** time
**import** azure.cognitiveservices.speech **as** speechsdk
**def** **azure_streaming_stt**(filename: str, lang: str, encoding: str) **->** str:
speech_config **=** speechsdk**.**SpeechConfig(
subscription**=**AZURE_SPEECH_KEY,
region**=**AZURE_SERVICE_REGION
)
stream **=** speechsdk**.**audio**.**PushAudioInputStream()
audio_config **=** speechsdk**.**audio**.**AudioConfig(stream**=**stream)
speech_recognizer **=** speechsdk**.**SpeechRecognizer(
speech_config**=**speech_config,
audio_config**=**audio_config
)
*# Connect callbacks to the events fired by the speech recognizer
* speech_recognizer**.**recognizing**.**connect(
**lambda** evt: **print**('interim text: "{}"'**.**format(
evt**.**result**.**text
))
)
speech_recognizer**.**recognized**.**connect(
**lambda** evt: **print**('azure-streaming-stt: "{}"'**.**format(
evt**.**result**.**text
))
)
*# start continuous speech recognition
* speech_recognizer**.**start_continuous_recognition()
*# push buffer chunks to stream
* buffer, rate **=** read_wav_file(filename)
audio_generator **=** simulate_stream(buffer)
**for** chunk **in** audio_generator:
stream**.**write(chunk)
time**.**sleep(0.1) *# to give callback a chance against fast loop*
*# stop continuous speech recognition
* stream**.**close()
time**.**sleep(0.5) *# give chance to VAD to kick in
* speech_recognizer**.**stop_continuous_recognition()
time**.**sleep(0.5) *# Let all callback run*
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
azure_streaming_stt(t['filename'], t['lang'], t['encoding'])
第一个测试用例的输出如下所示:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
interim text: "experience"
interim text: "experienced"
interim text: "experience"
interim text: "experience proves"
interim text: "experience proves this"
azure-streaming-stt: "Experience proves this."
IBM Watson 语音转文本
IBM Watson 语音转文本是一项 ASR 服务。NET,Go,JavaScript, Python ,Ruby,Swift,Unity API 库,还有 HTTP 端点。它有丰富的文档。
设置
您需要注册/登录,获取 API 密钥凭证和服务 URL,并填写在下面。
批处理 API
可以预见,批处理 API 非常简单:
**import** os
**from** ibm_watson **import** SpeechToTextV1
**from** ibm_cloud_sdk_core.authenticators **import** IAMAuthenticator
**def** **watson_batch_stt**(filename: str, lang: str, encoding: str) **->** str:
authenticator **=** IAMAuthenticator(WATSON_API_KEY)
speech_to_text **=** SpeechToTextV1(authenticator**=**authenticator)
speech_to_text**.**set_service_url(WATSON_STT_URL)
**with** open(filename, 'rb') **as** audio_file:
response **=** speech_to_text**.**recognize(
audio**=**audio_file,
content_type**=**'audio/{}'**.**format(
os**.**path**.**splitext(filename)[1][1:]
),
model**=**lang **+** '_BroadbandModel',
max_alternatives**=**3,
)**.**get_result()
**return** response['results'][0]['alternatives'][0]['transcript']
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('watson-batch-stt: "{}"'**.**format(
watson_batch_stt(t['filename'], t['lang'], t['encoding'])
))
以下是输出:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
watson-batch-stt: "experience proves this "
audio file="audio/4507-16021-0012.wav" expected text="why should one halt on the way"
watson-batch-stt: "why should one hold on the way "
audio file="audio/8455-210777-0068.wav" expected text="your power is sufficient i said"
watson-batch-stt: "your power is sufficient I set "
流式 API
Watson 的流媒体 API 在 WebSocket 上工作,只需要一点点工作就可以设置好。它具有以下步骤:
- 创建一个用于接收语音识别通知和结果的
RecognizeCallback
对象。 - 创建缓冲队列。麦克风(或流模拟器)产生的音频块应该写入该队列,Watson 读取并使用这些块。
- 启动一个执行语音识别(以及 WebSocket 通信)的线程。
- 启动麦克风或语音模拟器,开始产生音频块
- 完成后,加入语音识别线程(即,等待它完成)。
**import** json
**import** logging
**import** os
**from** queue **import** Queue
**from** threading **import** Thread
**import** time
**from** ibm_watson **import** SpeechToTextV1
**from** ibm_watson.websocket **import** RecognizeCallback, AudioSource
**from** ibm_cloud_sdk_core.authenticators **import** IAMAuthenticator
*# Watson websocket prints justs too many debug logs, so disable it* logging**.**disable(logging**.**CRITICAL)
*# Chunk and buffer size* CHUNK_SIZE **=** 4096
BUFFER_MAX_ELEMENT **=** 10
*# A callback class to process various streaming STT events* **class** **MyRecognizeCallback**(RecognizeCallback):
**def** **__init__**(self):
RecognizeCallback**.**__init__(self)
self**.**transcript **=** None
**def** **on_transcription**(self, transcript):
*# print('transcript: {}'.format(transcript))
* **pass**
**def** **on_connected**(self):
*# print('Connection was successful')
* **pass**
**def** **on_error**(self, error):
*# print('Error received: {}'.format(error))
* **pass**
**def** **on_inactivity_timeout**(self, error):
*# print('Inactivity timeout: {}'.format(error))
* **pass**
**def** **on_listening**(self):
*# print('Service is listening')
* **pass**
**def** **on_hypothesis**(self, hypothesis):
*# print('hypothesis: {}'.format(hypothesis))
* **pass**
**def** **on_data**(self, data):
self**.**transcript **=** data['results'][0]['alternatives'][0]['transcript']
**print**('{0}final: {1}'**.**format(
'' **if** data['results'][0]['final'] **else** 'not ',
self**.**transcript
))
**def** **on_close**(self):
*# print("Connection closed")
* **pass**
**def** **watson_streaming_stt**(filename: str, lang: str, encoding: str) **->** str:
authenticator **=** IAMAuthenticator(WATSON_API_KEY)
speech_to_text **=** SpeechToTextV1(authenticator**=**authenticator)
speech_to_text**.**set_service_url(WATSON_STT_URL)
*# Make watson audio source fed by a buffer queue
* buffer_queue **=** Queue(maxsize**=**BUFFER_MAX_ELEMENT)
audio_source **=** AudioSource(buffer_queue, True, True)
*# Callback object
* mycallback **=** MyRecognizeCallback()
*# Read the file
* buffer, rate **=** read_wav_file(filename)
*# Start Speech-to-Text recognition thread
* stt_stream_thread **=** Thread(
target**=**speech_to_text**.**recognize_using_websocket,
kwargs**=**{
'audio': audio_source,
'content_type': 'audio/l16; rate={}'**.**format(rate),
'recognize_callback': mycallback,
'interim_results': True
}
)
stt_stream_thread**.**start()
*# Simulation audio stream by breaking file into chunks and filling buffer queue
* audio_generator **=** simulate_stream(buffer, CHUNK_SIZE)
**for** chunk **in** audio_generator:
buffer_queue**.**put(chunk)
time**.**sleep(0.5) *# give a chance to callback*
*# Close the audio feed and wait for STTT thread to complete
* audio_source**.**completed_recording()
stt_stream_thread**.**join()
*# send final result
* **return** mycallback**.**transcript
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('watson-cloud-streaming-stt: "{}"'**.**format(
watson_streaming_stt(t['filename'], t['lang'], t['encoding'])
))
产出:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
not final: X.
not final: experts
not final: experience
not final: experienced
not final: experience prove
not final: experience proves
not final: experience proves that
not final: experience proves this
final: experience proves this
watson-cloud-streaming-stt: "experience proves this "
亚马逊转录
Amazon transcript是一个语音转文本 AWS 云服务,拥有 C#、Go、Java、JavaScript、PHP、Python 和 Ruby 的库。它有一个批处理语音转文本 API(也可以作为命令行使用),但是它要求音频文件要么在 S3 桶中,要么可以通过 HTTP 获得。它在 WebSocket 和 HTTP/2 上也有一个流媒体 API。这里有一个使用 AWS Java SDK 的示例,但是没有 Python 绑定(当然可以使用 Python 套接字库,但是需要进入低级事件流编码)。
Amazon Transcribe Python APIs 目前不支持本文中涉及的用例,因此这里不包括代码示例。
细微差别
Nuance 很可能是最古老的商业语音识别产品,甚至是为各种领域和行业定制的。他们确实有语音识别服务的 Python 绑定。这里是他们 GitHub repo 中的一个代码样本。
我想不出创建开发者账户的方法。我希望有一种方法可以获得类似于其他产品的有限期限的免费试用信用,并获得访问服务所需的凭据。
CMU 狮身人面像
CMUSphinx 已经存在了相当一段时间,并且一直在适应 ASR 技术的进步。 PocketSphinx 是一个语音转文本解码器 Python 包。
设置
首先安装 swig 。在 macOS 上,您可以使用brew
进行安装:
$ brew install swig
$ swig -version
在 Linux 上,可以使用apt-get
:
$ apt-get install -y swig libpulse-dev
$ swig -version
然后使用 pip 安装pocketsphinx
:
$ pip3 install pocketsphinx
$ pip3 list | grep pocketsphinx
创建解码器对象
无论您使用批处理还是流式 API,您都需要一个解码器对象:
**import** pocketsphinx
**import** os
MODELDIR **=** os**.**path**.**join(os**.**path**.**dirname(pocketsphinx**.**__file__), 'model')
config **=** pocketsphinx**.**Decoder**.**default_config()
config**.**set_string('-hmm', os**.**path**.**join(MODELDIR, 'en-us'))
config**.**set_string('-lm', os**.**path**.**join(MODELDIR, 'en-us.lm.bin'))
config**.**set_string('-dict', os**.**path**.**join(MODELDIR, 'cmudict-en-us.dict'))
decoder **=** pocketsphinx**.**Decoder(config)
批处理 API
批处理 API 非常简单,只有几行代码:
**def** **sphinx_batch_stt**(filename: str, lang: str, encoding: str) **->** str:
buffer, rate **=** read_wav_file(filename)
decoder**.**start_utt()
decoder**.**process_raw(buffer, False, False)
decoder**.**end_utt()
hypothesis **=** decoder**.**hyp()
**return** hypothesis**.**hypstr
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text'])
)
**print**('sphinx-batch-stt: "{}"'**.**format(
sphinx_batch_stt(t['filename'], t['lang'], t['encoding'])
))
您将看到现在熟悉的输出:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
sphinx-batch-stt: "experience proves this"
audio file="audio/4507-16021-0012.wav" expected text="why should one halt on the way"
sphinx-batch-stt: "why should one hold on the way"
audio file="audio/8455-210777-0068.wav" expected text="your power is sufficient i said"
sphinx-batch-stt: "your paris sufficient i said"
注意抄写中的错误。随着更多的训练数据,它通常会改善。
流式 API
流式 API 也非常简单,但是没有挂钩来获得中间结果:
**def** **sphinx_streaming_stt**(filename: str, lang: str, encoding: str) **->** str:
buffer, rate **=** read_wav_file(filename)
audio_generator **=** simulate_stream(buffer)
decoder**.**start_utt()
**for** chunk **in** audio_generator:
decoder**.**process_raw(chunk, False, False)
decoder**.**end_utt()
hypothesis **=** decoder**.**hyp()
**return** hypothesis**.**hypstr
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('sphinx-streaming-stt: "{}"'**.**format(
sphinx_streaming_stt(t['filename'], t['lang'], t['encoding'])
))
Mozilla DeepSpeech
Mozilla 在 2019 年 12 月发布了 DeepSpeech 0.6 软件包,用 C、Java、.NET、 Python 和 JavaScript,包括支持在 edge 设备上使用 TensorFlow Lite 模型。
设置
您可以使用 pip 安装 DeepSpeech(如果您想在 Colab 运行时或您的机器上使用 GPU,请使用它deepspeech-gpu==0.6.0
):
$ pip install deepspeech**==**0.6.0
下载并解压缩模型(这需要一段时间):
$ curl -LO https://github.com/mozilla/DeepSpeech/releases/download/v0.6.0/deepspeech-0.6.0-models.tar.gz
$ tar -xvzf deepspeech-0.6.0-models.tar.gz
$ ls -l ./deepspeech-0.6.0-models/
测试它是否一切正常。检查最后三个命令的输出,您将分别看到结果*【经验证明少】【为什么要中途停顿】【我说你的动力够用了】*。你都准备好了。
$ deepspeech --model deepspeech-0.6.0-models/output_graph.pb --lm deepspeech-0.6.0-models/lm.binary --trie ./deepspeech-0.6.0-models/trie --audio ./audio/2830-3980-0043.wav
$ deepspeech --model deepspeech-0.6.0-models/output_graph.pb --lm deepspeech-0.6.0-models/lm.binary --trie ./deepspeech-0.6.0-models/trie --audio ./audio/4507-16021-0012.wav
$ deepspeech --model deepspeech-0.6.0-models/output_graph.pb --lm deepspeech-0.6.0-models/lm.binary --trie ./deepspeech-0.6.0-models/trie --audio ./audio/8455-210777-0068.wav
创建模型对象
第一步是读取模型文件并创建一个 DeepSpeech 模型对象。
**import** deepspeech
model_file_path **=** 'deepspeech-0.6.0-models/output_graph.pbmm'
beam_width **=** 500
model **=** deepspeech**.**Model(model_file_path, beam_width)
*# Add language model for better accuracy* lm_file_path **=** 'deepspeech-0.6.0-models/lm.binary'
trie_file_path **=** 'deepspeech-0.6.0-models/trie'
lm_alpha **=** 0.75
lm_beta **=** 1.85
model**.**enableDecoderWithLM(lm_file_path, trie_file_path, lm_alpha, lm_beta)
批处理 API
批量语音转文本只需要几行代码:
**import** numpy **as** np
**def** **deepspeech_batch_stt**(filename: str, lang: str, encoding: str) **->** str:
buffer, rate **=** read_wav_file(filename)
data16 **=** np**.**frombuffer(buffer, dtype**=**np**.**int16)
**return** model**.**stt(data16)
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('deepspeech-batch-stt: "{}"'**.**format(
deepspeech_batch_stt(t['filename'], t['lang'], t['encoding'])
))
输出:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
deepspeech-batch-stt: "experience proof less"
audio file="audio/4507-16021-0012.wav" expected text="why should one halt on the way"
deepspeech-batch-stt: "why should one halt on the way"
audio file="audio/8455-210777-0068.wav" expected text="your power is sufficient i said"
deepspeech-batch-stt: "your power is sufficient i said"
流式 API
DeepSpeech streaming API 需要创建一个流上下文,并重复使用它来提供音频块:
**def** **deepspeech_streaming_stt**(filename: str, lang: str, encoding: str) **->** str:
buffer, rate **=** read_wav_file(filename)
audio_generator **=** simulate_stream(buffer)
*# Create stream
* context **=** model**.**createStream()
text **=** ''
**for** chunk **in** audio_generator:
data16 **=** np**.**frombuffer(chunk, dtype**=**np**.**int16)
*# feed stream of chunks
* model**.**feedAudioContent(context, data16)
interim_text **=** model**.**intermediateDecode(context)
**if** interim_text **!=** text:
text **=** interim_text
**print**('inetrim text: {}'**.**format(text))
*# get final resut and close stream
* text **=** model**.**finishStream(context)
**return** text
*# Run tests* **for** t **in** TESTCASES:
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
t['filename'], t['text']
))
**print**('deepspeech-streaming-stt: "{}"'**.**format(
deepspeech_streaming_stt(t['filename'], t['lang'], t['encoding'])
))
DeepSpeech 返回中期结果:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
inetrim text: i
inetrim text: e
inetrim text: experi en
inetrim text: experience pro
inetrim text: experience proof les
deepspeech-streaming-stt: "experience proof less"
卡尔迪
卡尔迪是一个在研究社区中非常流行的语音识别工具包。它旨在试验不同的研究理念和可能性。它有各种可能的技术和备选方案的丰富集合。与代码实验室中讨论的其他替代方案相比,学习曲线更加陡峭。
PyKaldi 提供 Python 绑定。请务必看一下他们的 GitHub repo 的自述文件。
没有预构建的 PyPI 即用包,您必须从源代码或 Conda 构建它。这两种选择都不适合 Colab 环境。
脸书 wav2 字母
脸书于 2020 年 1 月发布了 wav2letter@anywhere 。它拥有一个完全卷积的(CNN)声学模型,而不是其他解决方案使用的递归神经网络(RNN)。它非常有前途,包括用于边缘设备。它为其推理框架提供了 Python 绑定。
和 Kaldi 一样,这也不提供 PyPI 包,需要从源进行构建和安装。
语音识别 Python 包
SpeechRecognition 包提供了几种解决方案的良好抽象。我们已经探索使用谷歌服务和 CMU Sphinxpackage。现在我们将通过 SpeechRecognition 包 API 来使用这些 API。可以使用 pip 进行安装:
批处理 API
SpeechRecognition 只有批处理 API。第一步是从文件或麦克风创建音频记录,第二步是调用recognize_<speech engine name>
函数。它目前有 CMU 狮身人面像、谷歌、微软、IBM、Houndify 和 Wit 的 API。让我们通过 SpeechRecognition 抽象使用一个云服务(Google)和一个软件包(Sphinx)来结帐。
**import** speech_recognition **as** sr
**from** enum **import** Enum, unique
**@**unique
**class** **ASREngine**(Enum):
sphinx **=** 0
google **=** 1
**def** **speech_to_text**(filename: str, engine: ASREngine, language: str, show_all: bool **=** False) **->** str:
r **=** sr**.**Recognizer()
**with** sr**.**AudioFile(filename) **as** source:
audio **=** r**.**record(source)
asr_functions **=** {
ASREngine**.**sphinx: r**.**recognize_sphinx,
ASREngine**.**google: r**.**recognize_google,
}
response **=** asr_functions[engine](audio, language**=**language, show_all**=**show_all)
**return** response
*# Run tests* **for** t **in** TESTCASES:
filename **=** t['filename']
text **=** t['text']
lang **=** t['lang']
**print**('\naudio file="{0}" expected text="{1}"'**.**format(
filename, text
))
**for** asr_engine **in** ASREngine:
**try**:
response **=** speech_to_text(filename, asr_engine, language**=**lang)
**print**('{0}: "{1}"'**.**format(asr_engine**.**name, response))
**except** sr**.**UnknownValueError:
**print**('{0} could not understand audio'**.**format(
asr_engine**.**name
))
**except** sr**.**RequestError **as** e:
**print**('{0} error: {0}'**.**format(asr_engine**.**name, e))
输出:
audio file="audio/2830-3980-0043.wav" expected text="experience proves this"
sphinx: "experience proves that"
google: "experience proves this"
audio file="audio/4507-16021-0012.wav" expected text="why should one halt on the way"
sphinx: "why should one hold on the way"
google: "why should one halt on the way"
audio file="audio/8455-210777-0068.wav" expected text="your power is sufficient i said"
sphinx: "your paris official said"
google: "your power is sufficient I said"
其他提供商的 API
对于其他语音识别提供商,您将需要创建 API 凭证,您必须将这些凭证传递给recognize_<speech engine name>
函数,您可以查看这个示例。
它还有一个很好的麦克风抽象,通过 PyAudio/PortAudio 实现。在批次中检查示例以捕捉来自麦克风的输入,并在背景中持续进行。
想写一个把麦克风输入转换成文本的 Python 转录器?看看这个: 如何使用 Mozilla deep speech构建 Python 转录器。
如果您喜欢,请:
通过 Google 云和 Sheets 自动刷新 Tableau 数据
通过 Python、Google Sheets 和 Google Cloud 的 Tableau 公共数据管道自动化教程
这篇文章介绍了通过 python、Google Sheets 和 Google Cloud 为 Tableau Public 构建自动数据刷新管道所需的步骤。在之前的帖子自动刷新 Tableau Public 中,我解释了如何将 Tableau Public 工作簿连接到 Google Sheets,以利用 Tableau Public-Google Sheet 的每日刷新。我描述了如何在本地安排一个启动守护进程来更新 Google Sheet 中包含的数据,从而刷新 connected Tableau 公共工作簿中的数据。虽然这种设置适用于相对不频繁的刷新周期,但不适用于需要每天(或更频繁)更新的数据。下面详细介绍的设置解决了这个问题,以创建一个真正自动化的数据刷新程序。
为什么您应该自动化您的更新渠道?
虽然我对每周更新英超联赛表的原始数据更新方法非常满意,但我后来构建了需要更频繁更新的 Tableau 仪表盘。对于我的 MLB 击球率预测工具,我需要每天刷新数据以使其具有相关性。在 MLB 赛季的每一天都打开我的个人电脑不是一个好的选择,所以我开始寻找一种可靠的任务调度方法。我最终选定了下面的工作流程:
- 使用 Google Cloud Scheduler 安排一个实例运行
- 在实例中启动一个 cron 作业,运行我的代码来获取更新的数据并将其加载到 Google Sheets
- 使用 Google Cloud Scheduler 安排实例停止运行(为了省钱,因为它每天只需要运行 5 分钟)
我考虑过使用 Google Cloud Scheduler 直接执行脚本,而不是在实例中使用 cron,但是我喜欢通过 ssh 连接到实例,并且我已经熟悉了使用虚拟实例,所以这是阻力最小的途径。我也考虑过使用我在工作中使用的 Airflow,但是它需要一个类似的调度设置和一个额外的 web 服务器部署层。然而,我正在将这一过程转换为 Airflow,因此我可以更容易地安排未来的新工作,并在完成后更新后续帖子。
谷歌云入门
如果你是第一次安装谷歌云,我建议你遵循这个指南。首次使用 Google Cloud 的用户第一年可以获得 300 美元的积分,不过你必须启用计费并填写信用卡信息才能使用。你也可以使用谷歌云的免费层,它有使用限制。空闲层限制了您的可用内存和处理能力,但是您应该有足够的空间来执行基本操作。我对这个脚本使用了第二小的层实例大小,但是它非常便宜,因为我每天只运行 5 分钟。
创建实例
我每次都使用同一个实例,这样我就可以存储代码供重复使用。可能有更好的方法,但对我来说这是最直接的方法。为了在本地机器和实例之间移动代码,我使用 GitHub。显然,GitHub 使版本控制变得更容易,但这也是一种比每次我需要更新脚本时从我的本地机器向实例移动代码更简单的方法。
创建项目
首先,您需要创建一个新项目,因为 Google Cloud 将所有东西都组织在项目中。要创建新项目,请进入项目页面,点击“创建项目”。您可以随意命名它,但是要确保它易于输入,以防您最终从命令行引用它。设置好项目后,您可能需要启用计算引擎 API。进入你项目的控制台(你项目的主页——点击左上角的 Google Cloud Platform)并点击 API。在下一个屏幕的顶部,单击“启用 API 和服务”,然后搜索并添加计算引擎 API。
启动实例
启用 API 后,您可以导航回控制台并单击“转到计算引擎”链接(如果没有出现,请单击左上角的侧栏图标,向下滚动并单击计算引擎)。当您进入计算引擎时,您可以选择创建一个实例。单击“创建”创建您的实例。您可以为您的实例取一个名称(同样,最好是一个容易键入的名称),然后选择一个区域和可用性区域。这些是谷歌云服务器的位置,你可以在那里托管你的虚拟机。典型的指导是选择一个离你近的地区,但我认为这没那么重要。你的区域选择也不是特别重要。然而,当你去启动你的实例时,它将在那个区域启动,区域组合默认为。如果您的默认区域关闭(偶尔会发生),您可以跨区域移动它,但是我从来不需要这个选项。
选择您的地区和区域后,您将选择您的实例类型。我用的是 N1 系列,机型 g1-small。根据您的计算需求,有一大堆选项。g1-small 在这方面和其他方面都为我提供了很好的服务,所以我一直保留着它!
在那里,您需要点击“访问范围”下的“允许完全访问云 API”。这将确保您的实例可以计划启动和停止。最后,您将希望允许 HTTP 和 HTTPS 流量。你需要他们运行一个脚本,从某个地方获取数据,然后存储在 Google Sheets 中。您可以在以后更改这些选项,但是从一开始就设置它们会更容易。一旦您的实例设置好了,您就可以通过点击实例,然后点击 start 来启动它!
设置您的实例
要连接到您的实例,您可以在新窗口中打开连接,按照其他选项之一在浏览器中打开它,使用另一个 ssh 客户端,或者通过 g Cloud(Google Cloud 命令行界面)连接。
我混合使用控制台和 gcloud 来使用 Google Cloud,但是你可以轻松地使用其中任何一种。然而,当连接到实例时,我更喜欢 gcloud,这样我可以更自然地与它们交互。要安装 gcloud,请按照这里的说明进行操作。要通过 gcloud 连接到您新创建的实例,您可以在本地终端中键入命令,或者从下拉列表中复制命令并粘贴到本地终端中。如果你不确定它是否有效,如果你看到你的终端把你的位置列为<你的 google 用户名> @ <你的实例名> (对我来说就是 irarickman@instance-1),你就会知道你在你的实例中。恭喜你,你现在在你的虚拟机里了!
安装软件包和工具
对于我的特定用例,我需要设置一些东西来准备运行我的 MLB 数据刷新脚本。根据您的需求,您自己的设置可能会有所不同,但是我需要以下内容
Python 包 —你的虚拟机应该附带 Python。如果没有,请执行第二步
- 运行须藤 apt 更新
- (如果你没有 python) 运行 sudo 来安装 python3
- 运行 sudo 来安装 python3-pip 来安装最新的 pip
- 通过 pip3 安装您需要的任何软件包。对我来说,这主要是 pybaseball,pygsheets,和一些较小的。
安装 Git 并克隆您的代码仓库——如果您还没有安装 Git,请遵循以下步骤。这里假设你想从 Github 或 Gitlab 中提取代码。如果没有,跳过这一步!
- 运行 sudo 来安装 git
- 像往常一样克隆您的回购协议!我用的是 https auth,可能会提示你输入用户名和密码。如果您使用 SSH,您需要完成正常的 ssh keygen 设置。
创建一个 Google Sheets API 应用程序并连接到它——为了避免重复创建另一个教程,我推荐遵循 Erik Rood 的优秀 Google Sheets API 设置。设置好凭据后,您需要将它们安全地复制到实例中以供使用。要保护拷贝,请打开一个新的终端标签,这样您就可以回到本地目录并运行
gcloud compute scp <file_path>/client_secret.json <googleusername>@<instance-name>:<~/file path>.
第一次使用 scp 时,系统会要求您创建一个密码短语。如果你只是按两次回车键,它不会创建一个。**如果您输入了密码,您需要在每次 scp 时输入。如果您从现在起几个月后再次尝试 scp,并且不记得您的密码,跳过密码非常有用。**如果您在连接实例时遇到任何错误,您可能需要指定项目和区域(记住它也需要运行)!要获得更多指导,我建议查看 GCP 文档。
加载您的凭据后,您可以对您的应用进行身份验证。这是一次性认证。您的浏览器可能会试图警告您该应用程序不安全。您可以点击高级并继续操作。要设置身份验证,您可以尝试运行您的脚本(并确保您适当地设置了您的授权文件位置),或者在您移动凭证的位置从命令行运行 python 并键入:
import pygsheets
gc = pygsheets.authorize()
您将被引导通过将 url 复制到浏览器中来完成认证流程。按照随后的指示,将密钥粘贴到命令行中,您应该已经准备好了!你可以在这里看到我的代码是如何使用 Google Sheets 的。
计划您的实例
这是允许您定期启动和停止实例的部分。要设置完整的工作流,您需要创建以下各项
- Pub/Sub topic —将携带通知开始事件的消息。
- 云函数 —实际执行一个事件的函数。
- 云调度任务 —启动工作流的预定命令。
设置发布/订阅主题
首先,导航至发布/订阅并点击“创建主题”。您将希望给它一个易于跟踪的名称,例如“start-instance”。
设置云功能
接下来,跳到你的云函数上,点击“创建函数”,然后按照以下步骤操作:
- 给你的函数起一个名字,可能是“startInstance”。
- 选择您的地区(同样,可能希望保持在同一个地区)。
- 选择发布/订阅作为触发器。这将启动你的功能。发布/订阅主题实际上只是向您的函数传递一条消息,让它知道它需要启动。在这种情况下,它还将区域和实例交付给 start。
- 在下拉列表中选择“启动实例”发布/订阅。您可以选择是否“失败时重试”。根据您的任务和结构的频率,您可能需要也可能不需要重试。我不为我的。
- 点击“下一步”进入代码编辑器。
- 在“入口点”输入字段中,输入函数的名称(例如,startInstance)。
- 在 index.js 编辑器中,擦除编辑器中已有的代码,输入下面的代码。确保将你的函数名替换为“导出”。<在第 33 行和第 77 行输入函数名,例如 start instance>。这段代码也可以在谷歌的教程 repo 中找到,不过 我在第 38–39 行、82–83 行和 120–122行做了一些小改动。Google 提供的脚本要求在调度任务中传递一个标签。我不标记我的谷歌云资源,所以我从搜索中删除了标签组件。下面的版本可以粘贴到 index.js 编辑器中,启动和停止函数都可以,只需要记住更改停止函数名。明确地说,您不需要在相应的开始和停止函数中包含开始和停止代码,但是为了方便起见,您可以在下面找到所有代码。
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the “License”);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an “AS IS” BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.// [START functions_start_instance_pubsub]
// [START functions_stop_instance_pubsub]
const Compute = require(‘[@google](http://twitter.com/google)-cloud/compute’);
const compute = new Compute();
// [END functions_stop_instance_pubsub]/**
* Starts Compute Engine instances.
*
* Expects a PubSub message with JSON-formatted event data containing the
* following attributes:
* zone — the GCP zone the instances are located in.
* label — the label of instances to start.
*
* [@param](http://twitter.com/param) {!object} event Cloud Function PubSub message event.
* [@param](http://twitter.com/param) {!object} callback Cloud Function PubSub callback indicating
* completion.
*/
exports.**<enter start function name>** = async (event, context, callback) => {
try {
const payload = _validatePayload(
JSON.parse(Buffer.from(event.data, ‘base64’).toString())
);
//const options = {filter: `labels.${payload.label}`};
const [vms] = await compute.getVMs();
await Promise.all(
vms.map(async (instance) => {
if (payload.zone === instance.zone.id) {
const [operation] = await compute
.zone(payload.zone)
.vm(instance.name)
.start();// Operation pending
return operation.promise();
}
})
);// Operation complete. Instance successfully started.
const message = `Successfully started instance(s)`;
console.log(message);
callback(null, message);
} catch (err) {
console.log(err);
callback(err);
}
};
// [END functions_start_instance_pubsub]
// [START functions_stop_instance_pubsub]/**
* Stops Compute Engine instances.
*
* Expects a PubSub message with JSON-formatted event data containing the
* following attributes:
* zone — the GCP zone the instances are located in.
* label — the label of instances to stop.
*
* [@param](http://twitter.com/param) {!object} event Cloud Function PubSub message event.
* [@param](http://twitter.com/param) {!object} callback Cloud Function PubSub callback indicating completion.
*/
exports.**<enter stop function name>** = async (event, context, callback) => {
try {
const payload = _validatePayload(
JSON.parse(Buffer.from(event.data, ‘base64’).toString())
);
//const options = {filter: `labels.${payload.label}`};
const [vms] = await compute.getVMs();
await Promise.all(
vms.map(async (instance) => {
if (payload.zone === instance.zone.id) {
const [operation] = await compute
.zone(payload.zone)
.vm(instance.name)
.stop();// Operation pending
return operation.promise();
} else {
return Promise.resolve();
}
})
);// Operation complete. Instance successfully stopped.
const message = `Successfully stopped instance(s)`;
console.log(message);
callback(null, message);
} catch (err) {
console.log(err);
callback(err);
}
};
// [START functions_start_instance_pubsub]/**
* Validates that a request payload contains the expected fields.
*
* [@param](http://twitter.com/param) {!object} payload the request payload to validate.
* [@return](http://twitter.com/return) {!object} the payload object.
*/
const _validatePayload = (payload) => {
if (!payload.zone) {
throw new Error(`Attribute ‘zone’ missing from payload`);
} //else if (!payload.label) {
//throw new Error(`Attribute ‘label’ missing from payload`);
//}
return payload;
};
// [END functions_start_instance_pubsub]
// [END functions_stop_instance_pubsub]
在 package.json 编辑器中,删除编辑器中的现有代码并输入以下内容:
{
“name”: “cloud-functions-schedule-instance”,
“version”: “0.1.0”,
“private”: true,
“license”: “Apache-2.0”,
“author”: “Google Inc.”,
“repository”: {
“type”: “git”,
“url”: “[https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git](https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git)"
},
“engines”: {
“node”: “>=10.0.0”
},
“scripts”: {
“test”: “mocha test/\*.test.js — timeout=20000”
},
“devDependencies”: {
“mocha”: “⁸.0.0”,
“proxyquire”: “².0.0”,
“sinon”: “⁹.0.0”
},
“dependencies”: {
“[@google](http://twitter.com/google)-cloud/compute”: “².0.0”
}
}
单击 Deploy,您的功能就应该设置好了!请注意,在下面的步骤中,我们将从调度程序传递区域和实例名称,这些名称将通过发布/订阅传递给函数,这样它就知道要开始什么了!
设置您的云计划任务
最后,转到云调度器,点击“创建”,然后按照以下步骤操作:
- 为您的作业选择一个区域(可能与您的实例相同)。
- 在下一页,给你的工作起一个名字和描述。我使用“启动实例”来启动它,使用“停止实例”来停止它!
- 指定时间表。下面的标题提供了更多信息,但是您需要使用 unix-cron 格式来安排。cron 调度的好处在于它足够灵活,可以每 5 分钟或每月第三天的午夜调度一次。欲了解更多信息,请查看此帮助页面。
- 选择您的时区。这样做时要小心。稍后我们将讨论在您的实例中设置 cron 作业。这些默认为 UTC,所以如果您决定不更改您的 cron 时区,您需要确保这些时间表是一致的。我喜欢使用 UTC,因为它不受夏令时的影响。
- 选择您的目标作为发布/订阅。
- 输入您的主题名称—它应该是您在上面的发布/订阅步骤中使用的名称。
- 在 payload 部分,您将告诉您的任务从哪个区域和实例开始。粘贴并编辑下面的代码:
{“zone”:”<zone>”,”instance”:”<instance-name>”}
设置停止实例工作流
上面的工作流程对于启动您的实例来说很棒,但是这个过程的全部要点是启动,然后停止实例。要设置停止工作流,遵循相同的步骤,只需将名称更改为 stop,并仔细检查是否在云函数脚本中填写了停止函数名称。请记住适当地设置启动和停止之间的时间间隔,以便在脚本启动后停止它(反之亦然)。
计划您的 python 脚本
一旦您将实例设置为启动和停止,您将希望在实例中设置脚本通过 crontab 运行。幸运的是,这个过程要简单得多。启动您的实例并在。在实例中,输入 crontab -e 。您将被要求选择您的编辑器,(我更喜欢 nano),然后您将被带到 crontab 文件。要阅读关于这个文件的更多信息,请查看 crontab.guru 。在那里你还可以找到一个有用的编辑器来测试 crontab 计时。
在您的 crontab 文件中,您可以安排您的脚本。再次提醒,要注意时间和时区!目标是在实例运行的同时调度 crontab 运行。默认情况下,您的 crontab 将在 UTC 上运行。因此,您需要考虑适当的 UTC 时间,以便与实例的开始/停止时间保持一致。找到合适的时间后,输入类似下面的命令来安排您的脚本:
0 10 * * * python3 /home/<google username>/projections_code/update_batting_avg-gcp.py
如果您有多个 python 安装(例如 python 2.7、anaconda 等)。)您将需要准确地指定要使用哪个 python 可执行文件。同样,您可能希望根据文件所在的位置来调整路径。
最后,我建议测试您的调度器和 cron 时间,以确保它们是一致的。我测试了我的脚本,将时间表设置为几分钟后运行,然后在我知道可以运行时调整实际脚本。虽然这是一个很好的前期工作,但它确实节省了我一些时间,并使一个有趣的画面仪表板。我希望本指南对您有所帮助——请随时提供反馈!
自动文本摘要
用 TextRank 凝聚客户投诉
动机
这项工作来自我使用美国消费者投诉数据集完成的 NLP 分类任务。任务是仅使用文本叙述来预测客户抱怨的金融产品。这是一个相当简单的监督问题,因为训练数据有标签,简单的逻辑回归分类器可以给出 0.80 的精度。当我浏览被错误分类的投诉时,我被它们的冗长所震惊。以下是对一种抵押贷款产品投诉的开始:
Hello, we have big problem again, there is a foreclosure sale scheduled for our home on XX/XX/XXXX and we are out of options and we have exhausted ourselves with this horrible company. We have had many attempts to receive an affordable monthly payment but no resolution and no affordable monthly payment offer has been given. We have sent in a request for mortgage assistance form along with bank statements taxes paystubs and other documents necessary for a loan modification review. We recently sent Mr. Cooper all documents but Mr. Cooper ahs the sale still scheduled. As part of this bailout, on XX/XX/XXXX, the United States Government took over XXXX XXXX and pumped billions, which in XX/XX/XXXX, then Treasury Secretary XXXX XXXX said as much as {$XXXX} XXXX would be pumped into XXXX XXXX and XXXX XXXX, each, which was separate from the {$700.00} in TARP funds given out to other lenders. 1\. The guidelines issued by the United States Treasury set forth a detailed process whereby a participating servicer, either action or not acting through its subsidiary, must : a. identify loans that are subject to modification under the HAMP program, both through its own review and in response to requests for modification from individual homeowners ; b. collect financial and other personal information from the homeowners to evaluate whether the homeowner is eligible for a loan modification under HAMP...
整份诉状约 2000 字长,引用了美国财政部、联邦和州政府的政策,还掺杂了该公司和特定涉案人员的行为。看到这一点,我对机器学习算法有了真正的了解,这种算法无需人工干预就能对投诉进行分类。对于这个任务,单词“mortgage”的频繁出现会向人暗示我们正在处理一个抵押贷款产品。但是,如果我们想深入到问题的层面,了解投诉的内容,那么我们需要阅读这篇文章——这不是大多数人会喜欢的任务。
幸运的是,我们可以使用机器学习来减少理解文本的努力,通过自动文本摘要。
自动文本摘要
自动文本摘要的一个很好的定义是“产生一个简洁流畅的摘要,同时保留关键信息内容和整体含义的任务”。有两种不同的方法,提取总结和抽象总结。
摘录摘要
- 从原文中找出最重要的句子或短语
- 仅从原文中提取句子
- 摘录的句子将是我们的总结
- 大多是无监督学习
抽象概括
- 从原文中产生新的句子
- 生成的句子可能不会出现在原文中
- 更困难的任务,包括语言理解
- 使用深度学习方法
提取与抽象摘要
在这里,我们将只关注提取总结算法。我们要看的这个叫做 TextRank。
TextRank 算法
TextRank 算法是一种提取的无监督文本摘要算法。这是一个相当古老的方法,于 2004 年首次提出。顾名思义,它与著名的 PageRank 算法有相似之处,page rank 算法用于按重要性对网站进行排序。
应用程序中的文本等级
TextRank 与 PageRank 的比较
- 代替网页的句子
- 任意两个句子之间的相似度相当于网页转移概率
- 相似性得分存储在一个正方形矩阵中,类似于 PageRank 中使用的矩阵 M
首先,将文本拆分成句子。我们计算每对句子之间的相似度。这建立了一个完整的加权图,即每个顶点(句子)连接到所有其他顶点,每个边是它连接的两个顶点之间的相似性得分。边的值基本上类似于为另一个顶点“投票”——投票越多,顶点(句子)的重要性就越高。然而,正如在 PageRank 中,谁投票也很重要:重要的句子在投票时的贡献更高。在过去,他们使用重叠来计算句子之间的相似度,但现在我们可以只使用句子嵌入来计算余弦相似度。
下面是分成句子的示例段落和句子嵌入之间的相似性矩阵。
0: ‘I have reached out to the credit bureaus about these debts they have put on my credit file.'
1: ‘This has been a long road.’
2: ‘When ever I apply for anything I am never approved because for some reason I believe me and someone has the same social.’
3: ‘Its extremely frustrating.’
4: ‘I just would like all this inaccurate information removed’
我们使用这个矩阵运行 PageRank 算法(PageRank 在 networkx 中作为方法可用),取前五个句子作为文本摘要。
结果
在用于进行实验的语料库中,单词的中位数是 51,最大值是 2643 个单词。总结之后,字数的中位数略微下降到 40 个,但是我们基本上消除了长尾效应,现在投诉的最大字数为 482 个。
你可以去我的 Github repo 查看一些文本摘要的例子,这里有一个简单的例子。这是一份在“讨债”下提交的投诉,具体问题是“关于债务的书面通知”。
原文:
'It was recently reported on my account that I had a derogatory account with Eastern Connecticut Account. I have never received anything regarding a missing payment to my New York address. This is regarding an XXXX XXXX payment for XXXX dollars. This was a charge from XX/XX/XXXX, I had XXXX XXXX XXXX XXXX XXXX at the time as I was under my father’s insurance. \tI received a few phone calls in XX/XX/XXXX from *XXXX Fraud Alert #*, I obviously did not answer. I had a voicemail saying to please call and confirm a social security number. I XXXX Eastern Connecticut and saw extremely negative reviews. My concern regarding giving them my personal information only began to grow. When I called back I instructed the representative that they showed up on my phone as fraud. Then the representative began to instruct me on an XXXX XXXX debt. I asked from when was this from, they said XX/XX/XXXX. I asked her if XXXX XXXX put my insurance in. XXXX XXXX XXXX XXXX XXXX in and out of state number. I know that my insurance would have went through, as I had XXXX XXXX XXXX and had numerous bills that were all covered. I instructed her to reach out to the XXXX XXXX and try to submit the claim or call me back if there were any issues. I didn’t feel comfortable just making a payment to this organization, especially after the reviews and the type of infection I had during that time. When the organization never called me back, I assumed that the XXXX XXXX had taken care of it.\tAfter I got an update from my XXXX app on a negative report to my score, I saw it was Eastern Connecticut. I immediately called Eastern Connecticut, and left numerous Voice Mail Messages. I had one representative hang up on me multiple times, when I was trying to explain I don’t live in Connecticut. After finally getting through to one representative, I finally paid the XXXX dollars. I asked if they could send a report to your company saying they didn’t have my address and the person laughed at me over the phone. He said, “Why would I help your credit score”. He said, having a phone number is sufficient enough to report someone as a derogatory account. \tThis organization is taking advantage of people and I don’t want my credit report to be negatively reflected by this. XXXX even reported their entity as fraud. I did pay this organization, however extremely reluctantly. I have attached a copy of the receipt. Please, if your organization can update my credit score and remove this derogatory account information. I have never missed a payment on any of my accounts. I have a number of student loans that I’m trying to pay off, and this negative credit score will hurt my future in receiving a lower interest rate.'
总结文本:
'He said, having a phone number is sufficient enough to report someone as a derogatory account. This organization is taking advantage of people and I don’t want my credit report to be negatively reflected by this. I asked if they could send a report to your company saying they didn’t have my address and the person laughed at me over the phone. I have never received anything regarding a missing payment to my New York address. I have a number of student loans that I’m trying to pay off, and this negative credit score will hurt my future in receiving a lower interest rate.'
这个总结看起来很有意义,但它并不完美,因为句子来自原文,而且没有试图确保连贯性或语法。
回到分类
从投诉中删除了这么多单词后,我想检查分类任务现在将如何执行。使用与全文相同的方法——标记化、tf-idf 矢量化,然后应用线性 SVC 分类器,我们获得了 0.80 的精度,这与我使用全文获得的结果相同!召回矩阵如下:
结论
在为消费者投诉构建产品分类器时,我注意到长时间的投诉使得人工验证结果成为一项特别艰巨的任务,于是我研究了在不丢失关键信息的情况下总结文本的方法。我们使用了一种叫做 TextRank 的无监督方法,可以快速运行。它产生合理的摘要,并且当使用摘要文本而不是原始全文作为分类的输入时,我们发现该算法在性能上没有损失。当然,该方法的缺点是摘要中的所有文本都来自原始文本。
参考
- https://www.aclweb.org/anthology/W04-3252
- 手套:【http://www.aclweb.org/anthology/D14-1162】T2
自动检测新冠肺炎错误信息
图片来源:Unsplash
NLP,机器学习,新冠肺炎
普通市民识别假新闻不容易。而假冠状病毒新闻也不例外。
作为打击关于冠状病毒的错误信息的努力的一部分,我尝试并收集了训练数据,并训练了一个 ML 模型来检测冠状病毒的假新闻。
我的训练数据并不完美,但我希望它可以帮助我们了解假新闻在风格和语言使用上是否与真实新闻有系统的区别。所以,让我们来看看。
数据
正如在上一篇文章中提到的,我从各种新的来源收集了超过 1100 篇关于新冠肺炎的新闻文章和社交网络帖子,然后给它们贴上标签。数据集可以在这里找到。
fake_covid.py
我决定基于新闻标题和新闻文章主体创建几十个新功能。我来一一解释一下。
标题中大写字母
- 计算每个标题中大写字母的数量。
- 计算每篇文章正文中大写字母的百分比,而不是简单地计算数字,因为文章的长度差异很大。
title _ 大写. py
图 1
boxplot_cap.py
图 2
平均来说,假新闻标题中出现大写字母的单词要多得多。这让我想到假新闻针对的是容易被标题影响的受众。
停止标题中的单词
- 统计每个标题中停用词的数量。
- 计算每篇文章正文中停用词的百分比,而不是简单地计算数量,因为文章的长度差异很大。
stop _ words.py
图 3
boxplot_stop_words.py
图 4
假新闻标题比真实新闻标题的停用词少。
标题中的专有名词
- 计算每个标题中专有名词(NNP)的数量。
图 5
boxplot_proper_noun.py
图 6
假新闻标题专有名词比较多。显然,标题中专有名词的使用对于区分真假非常重要。
从文章标题分析中抽离
总的来说,这些结果表明,假新闻的作者试图通过在标题中使用所有大写单词来吸引注意力,并通过跳过停用词和增加专有名词来尽可能多地向标题中挤压内容。我们将很快发现这些是否也适用于文章正文。
这里有一个假新闻标题与真实新闻标题的例子。
假新闻标题:“《烟枪》重磅采访全文:FRANCES BOYLE 教授揭露新冠肺炎冠状病毒的生物武器来源”
真实新闻标题:“冠状病毒这样的疫情为何呈指数级传播,如何‘拉平曲线’”
特征
为了研究虚假和真实的新闻文章,我们在文章主体上计算许多基于内容的特征。它们是:
- 使用词性标注器,记录每个标注在文章中出现的次数。
pos_tag.py
- 文章正文中否定和疑问句的数量。
否定. py
textstat.py
- [类型-标记比率](https://carla.umn.edu/learnerlanguage/spn/comp/activity4.html#:~:text=A%20type%2Dtoken%20ratio%20(TTR,a%20given%20segment%20of%20language.) (TTR),是给定语言片段中独特单词(类型)的总数除以单词(标记)的总数。使用 Python 库—lexical richity。
ttr.py
- 文章正文中动力词、休闲词、试探词、情感词的数量。
power_words.py
探索
文章正文中的大写字母
大写 _text.py
图 7
平均而言,假新闻在文章正文中出现大写字母的单词比真实新闻多。
文章正文中的停用词
text_stop_words.py
图 8
假新闻和真实新闻中停用词的比例似乎没有显著差异。
文章正文中的 NNP(专有名词,单数)
专有名词文本
图 9
与标题类似,假新闻在文章正文中也包含更多专有名词。
文章正文中的否定词
否定. py
图 10
平均来说,假新闻的否定词比真新闻多一点。
支架
括号. py
出于某种原因,在我的数据中,假新闻在文章正文中使用了更多的括号。
类型-令牌比(TTR)
ttr.py
图 11
就 TTR 而言,假新闻和真实新闻之间似乎没有显著的区别。
我没有探究所有的数字特性,你可以自己做。然而,从我的探索中,我发现假新闻文章在标题上比在正文上有更多的不同。
哈佛健康出版社诉自然新闻
记住,自然新闻是极右的阴谋论和假新闻网站。我从那里收集的新闻文章都被贴上假新闻的标签。
哈佛 _natural.py
图 12
在预期范围内,自然新闻文章使用的停用词比哈佛健康出版社少得多。
哈佛 _ 自然 _ttr.py
图 13
[TTR](https://carla.umn.edu/learnerlanguage/spn/comp/activity4.html#:~:text=A%20type%2Dtoken%20ratio%20(TTR,a%20given%20segment%20of%20language.) 意在捕捉文档中词汇的词汇多样性。低的 [TTR](http://carla.umn.edu/learnerlanguage/spn/comp/activity4.html#:~:text=A%20type%2Dtoken%20ratio%20(TTR,a%20given%20segment%20of%20language.) 意味着文档有更多的单词冗余,高的 [TTR](http://carla.umn.edu/learnerlanguage/spn/comp/activity4.html#:~:text=A%20type%2Dtoken%20ratio%20(TTR,a%20given%20segment%20of%20language.) 意味着文档有更多的单词多样性。很明显,在 TTR 方面,《哈佛健康杂志》和《自然新闻》有很大的不同。
分类模型
由于我的数据收集有偏差,我们不会使用“来源”作为特征,例如,我只从脸书和推特上收集假帖子。而事实上,脸书或推特上的大多数帖子都是真实的。
我相信你已经注意到我们已经创建了大量的数字特征。对于第一次尝试,我决定使用它们来拟合一个支持向量机(SVM)模型,该模型具有线性核和 10 重交叉验证,以防止过度拟合。
linearSVC_fake.py
print(scores.mean())
当 10 重交叉验证完成时,我们可以在每次迭代中看到 10 个不同的分数,然后我们计算平均分数。
取 C 参数 的所有值,检查精度得分。
c_accuracy1.py
图 14
从上面的图中我们可以看到,对于 C=1,精度接近 84.2%,然后下降到 83.8%左右,并保持不变。
我们将更详细地了解为我们提供良好准确度分数的参数的确切值。
c_accuracy2.py
图 15
上图显示,对于 C=0.7,准确度得分最高。
未来的工作
记得为了学习和探索,我创建了几十个新的数字特征,并使用它们来拟合分类模型。我建议您使用假设检验方法来选择前 8 或前 10 个特征,然后运行线性 SVM 模型和 10 重交叉验证。
假设检验不能对数据中的预测类说什么,但是,这些检验可以说明哪些特征比其他特征更重要。
Jupyter 笔记本可以在 Github 上找到。周末愉快!
*参考:【https://arxiv.org/pdf/1703.09398.pdf *
从文件中自动推断关系结构
一种使用 pandas 和 NetworkX 自动推断和显示类似 CSV 数据的底层关系结构的方法
从数据文件的集合到对业务有意义的信息空间地图。(原始图像,在 DataSmith 中生成的图形)
背景
他们叫你来是因为他们需要洞察力。也许是对未来的计划,或者是对现在的批判性评估——无论哪种方式,你的愿景都需要有严肃具体的证据支持。为了实现这一点,你需要获取一些原始数据,并将这些数据快速转化为知识*。*
实际上,放在你办公桌上的很可能是一捆 CSV 文件,由业务分析师匆忙汇编而成,或者是在地下室布满灰尘的服务器上发现的。
我们需要知道这些文件意味着什么,但我们不能为此目的轻易采用标准的 ML 算法,因为我们可能要查看的业务数据是高度分类的——名词将是法律实体、员工、销售、产品和客户,而不是数字观察。
在本文中,我们将看看如何使用 Python、 pandas 和 N etworkX 快速洞察这些 CSV 文件的底层结构。本文中讨论的功能的后端代码(不是特别简洁)可以根据需要获得。
(本文所有图片均为原创。我自己的图形可视化工具 DataSmith 生成的图形图像。)
用例示例
为了便于讨论,让我们以这个描述销售的真实(并且真实地枯燥……)的 CSV 文件为例。
图 1:自然环境中的示例 CSV 文件。
显然,这些列中的一些彼此之间具有特定的关系。给定的“国家”可能总是在同一个“地区”。“Region”和“RegID”似乎大致是一回事。目前还不清楚“货币”是否总是与“国家”或“城市”匹配,或者“ProdGrp”是否与其他任何东西有任何关系。“SaleID”看起来很适合作为主键。
我们想要的是一种工具,它能产生类似于我的纸笔分析的东西:
图 2:两分钟的 CSV 文件铅笔和纸分析
只是我们希望它是即时的、正确的、像样的。本文的其余部分描述了解决这个问题的方法。
我们可以使用许多技术来推断数据结构的近似值,但是大体上我们需要一些基本的构建块:
- 衡量一列对另一列的依赖程度的方法
- 一种基于该度量值构建列关系图的方法
- 一种简化和表示图形方法
事实上,以上三个步骤是许多(如果不是全部)关系信息可视化挑战的特征。现在,我们将依次查看如何定义一个度量、构建一个图表,以及从图表中呈现有用的结论。
措施
本节考虑了测量列之间相关性的方法,并提出了一种自定义的测量方法,即“码头系数”。为了推断关系结构,我们主要想回答以下问题:
- “A 列可能是 B、C 和 D 列的关键字吗?”
- ’ A 列是 B 列可能是其属性或子维度的维度吗?’
相关性,卡方和他们的朋友
我们需要一个度量来告诉我们列之间是否相关,以及相关程度如何。我们的 ML 本能可能会告诉我们寻找列之间的相关性。不过,这并不是很有效,因为纯粹的相关性并不真正适用于分类变量之间。
所以,我们寻找一个相关的分类版本。常见的卡方测度就是这样;它为我们提供了两个分类变量独立性的数值度量。
图 3:卡方公式
在实践中,卡方是一个可怕的相关性度量,因为它没有缩放,并且很难知道我们应该如何对更大或更小的卡方值做出不同的反应。为了找到列之间相关度的度量,我们可以使用一个叫做 Cramer V 的度量;这种测量是一种缩放的卡方:
图 4:克莱姆的 V——一个缩放的卡方检验
维基百科建议对克莱姆的 V 这里的进行额外的缩放步骤,这可能是分类字段的“最正确”的类似相关性的度量。然而,在实践中,它对当前的任务并不那么有用。
这些方法的问题在于它们是相互关联的度量。为了回答我们的问题,我们想要一个方向性的度量;我们正在寻找不对称的关系,其中 A 列暗示 B 列,但不是(通常)反之亦然。
贝叶斯定理的
为了测量 A 列隐含 B 列的程度,我们可以使用贝叶斯逻辑。这有两大好处:
- 它产生了一个“信心水平”,这是我们正在寻找的;我们想知道给定 A 列的值,我们对 B 列的值有多大的把握。
- 这是一种单向关系,很容易表达 A 暗示 B 的情况,但反之则不然。
在实践中,贝叶斯逻辑对我们的问题是有用的,但它有一些缺点。特别是,贝叶斯模型的大多数可用实现对于分类输入都不太适用。例如,为了在 sklearn 中使用非常有用的 Bernoullian Bayes 实现,我们必须使用所谓的‘one hot’编码来将输入列表示为一组布尔值:
图 5:一键编码;决定“语言”是否依赖于“城市”
这是将分类数据转换成适合普通 ML 算法的状态的一般问题的一个特例,这本身就是一个有趣的问题(参见这篇关于数据科学的文章中的介绍)。
虽然贝叶斯方法当然不应该被拒绝用于结构推断——事实上,它们可能非常有用——但这里的目标是构建一个快速、简单的工具。特别是,要推断整个文件的结构,这可能很大,我们需要将每一列与几乎每一列进行比较,而这需要使用贝叶斯方法。此外,当一列几乎暗示另一列的值时,贝叶斯置信水平产生一个难以解释的数字。
码头系数
出于这些原因,对于手头的任务,值得建议一个新的衡量标准,即“码头系数”(之所以这么叫,是因为它在金丝雀码头很有用,金丝雀码头是伦敦的一部分,那里有大量的 CSV 文件)。这是一个回答问题的简单方法:
如果我用 A 列的值来猜测 B 列的值,那么我的正确率是多少?
码头系数计算如下:
图 6:码头系数
…其中 a 是我们的目标列的可能值, b 是我们的从属列的可能值,N ba 是在两列中具有特定值对的记录数。换句话说,它是每个可能的 a 值的最频繁 b 值的总和。
当然,当 A 列暗示 B 列时,码头系数为 1。如果码头系数略低于 1,则表明除了特定数量的数据错误外,A 列暗示 B 列。如果该值较低,则建议在列之间进行一些关联,并且需要进行一些调整,以便很好地猜测是否存在实际的关系。
码头系数的一个优点是,它可以表示为熊猫(奇怪的心理图像,那里)的单个快速运行线,这对于我们的用例来说是理想的。
*w = (df.groupby([cb,ca])[ca].count().max(level=0)).sum()/df.shape[0]*
另一个优点是,它表达了一个对商业有意义的事实:“如果你假设 A 列暗示了 B 列,那么你会得到完全错误的答案(1-w) 100%”。*
构建图表
选择了一个列对另一个列的依赖性的度量之后,我们继续构建一个推断的底层数据结构的图。我们需要图表,因为为了从蕴涵矩阵中提取知识,我们将使用图表技术来简化图表以便显示。
构建蕴涵矩阵
我们通过测量每对列之间的蕴涵度来构建一个蕴涵矩阵。在我们枯燥的销售数据示例中,隐含矩阵恰好是:
图 7:示例数据的隐含矩阵。我们看到“City”几乎意味着“Store ”,但不完全是。
阈值
我们可以在这里决定一段关系有多脆弱才值得考虑。我们可以通过定义一个阈值来做到这一点,低于该阈值的两列之间的关系将被忽略。假设我们使用码头系数,以下阈值是一个很好的起点:
- 1 —如果我们正在寻找完全的关系完整性,并且我们假设数据没有损坏,则使用此选项。
- 0.98 —如果我们正在寻找完全的关系完整性,但我们预计底层关系结构可能会因数据质量问题而略微模糊,请使用此值。
- 0.85 —使用此值,我们将寻找不一定等于实际外键约束的强关系
列移除
在构建矩阵之前,应该从数据集中删除某些类型的输入列。例如:
- 基数非常低的列可能没有用。基数为 1 的列是没有意义的,因为每隔一列就意味着它们。
- 看起来像数字度量的列,例如浮点数,可能不构成关系结构的一部分。
- 基数很高但很大的列可能是不构成关系结构一部分的文本值。
在现实生活中,这一步几乎总是需要的。在我们的示例数据中,为了简洁起见,已经删除了这样的列。
清洗
可能需要填充 nan,纠正 Excel 中引入的空白问题,并进行其他清理。幸运的是,Python/pandas 是完成这类任务的强大工具。
从矩阵中构建图形
我们的“蕴涵矩阵”有表示列之间单向关系强度的单元。这恰好意味着它也是一个图邻接矩阵(其中关系强度是列权重)。
因此,构建关系的图形表示很容易;我们挥动 python 魔棒,非常有用的 NetworkX 库一步就为我们构建了一个图形:
*g = nx.from_numpy_matrix(mat,create_using=nx.DiGraph)*
在现实生活中,我们必须在这里完成一些簿记任务——特别是,原始的 DataFrame 列名需要变成 NetworkX 图中的节点名。
现在,我们可以使用一系列技术(有些在 Python 中已经可用,有些没有)从图中提取决策输入,即知识。
图表的分析和展示
在这一节中,我们考虑从我们的列关系图中呈现快速、可读的输出的步骤。
主键
我们可以很容易地识别主键候选;它们是暗示其他列的列。
出于几个目的,我们想要删除主键,这样它们就不会因为它们的许多关系而使图形变得混乱。
同义词
我们也可以很容易地识别同义词列组;如果两列互相暗示,则它们是同义词。这在现实生活中经常发生,因为如此多的文件包含像‘汽车序列号’、‘汽车牌照号’、‘汽车 ID’等我们期望一起变化的字段。虽然查找成对的同义词列很容易,但是识别大组同义词需要一点图论知识,而 NetworkX 可以很容易地为我们完成:
*filter(lambda x:len(x)>1, nx.strongly_connected_components(g))*
我们在这里做的是识别“强连接组件”,这是图中所有节点都具有双向关系的子图。如果它们有双向关系,它们就是同义词,所以每个结果子图都是一组同义词。然后我们过滤掉只有一个节点的子图。
我们简化图形的下一步是将所有同义词压缩在一起。为此,我们可以使用各种方法,但“最正确的”可能是使用极其强大的 PowerGraph 方法。这种方法将具有相似关系的节点压缩成单个节点。下图给出了一个想法:
图 8:用于简化包含同义词的图的 PowerGraph 方法
对 PowerGraph 的全面讨论,以及超图的迷人世界,超出了本文的范围。 cola 项目包含一个相当容易实现的 PowerGraph。在本文附带的我自己的代码中,我使用了一种更线性的方法;可惜 NetworkX 这次没有给我们一个预打包的算法。
属性
找到键和压缩同义词后,我们现在可以寻找维度。事实上,剩下的每一个不是键的列都是一个维度(因为我们之前已经清除了所有的度量),但是仅仅知道这一点并没有太大的用处。现实生活中,有趣的维度是有结构的;例如,在我们的例子中,我们期望“城市”有一个属性“国家”,可能还有一个属性“语言”和/或“货币”,即使我们不太确定它们是如何连接在一起的。
我们使用更方便的 NetworkX 算法来发现这些属性。
*dimensions = list(nx.weakly_connected_components(r))*
弱连通分量是由单向关系连接的子图;这正是我们所期望的每个维度,因为维度中的属性通过单向“是属性”关系连接。
当我们执行这一步时,我们发现了另一个简化的机会。我们的维度会以过多的关系结束。例如,如果真正的基础结构是“城市意味着国家,意味着地区”,那么隐含矩阵也将显示城市意味着地区,即使这对人类读者来说不是有用的信息。我们需要去除这些多余的关系,如下所示。
图 9:通过寻找生成树从维度中移除多余的关系
为此,我们可以使用另一种 NetworkX 算法来找到表示维度的子图的“最小生成树”。这是用尽可能少的边来表示图形,并删除不必要的关系。
布局
最常见的可视化表示图形的方式是古老而重要的 d3 项目称之为“力定向布局”。如果您使用 NetworkX 和 matplotlib,这就是您将得到的结果(尽管 NetworkX 称之为“spring layout”)。这通常不是一种非常有用的方式来呈现对业务有意义的项目的小图表(我认为,这甚至也不是一种有用的方式来呈现一般的大多数图表)。默认情况下,NetworkX 和 matplotlib 为我们的示例图形生成了以下可视化效果:
图 10:未简化图形的简单力导向布局的严酷结果
这对于检查代码是否工作以及我们是否有一个图表来说是不够的,但是对于演示或决策来说是没有用的。
在这种情况下,适当的布局选择应该是利用这样一个事实,即我们知道在中间有零个或多个主键,并且有零个或多个分支维度连接到它们。像 GraphViz twopi 这样的放射状布局会更好,但仍然会引入视觉噪音——定位的变化看起来有意义,但却是布局逻辑而不是图形的产物。我实现了一个特定于任务的布局,将维度约束为从主键辐射出来的一条直线(带有分支)。
结果
我们的最终输出如下所示:
图 11:在 DataSmith 中生成的最终结果,显示了输入文件的维度结构
这与我们的预期相差不远,但对于所花的几秒钟来说,结果还不错(在 7000 行的输入文件上)。三个维度是可见的,我们可以看到,虽然货币是每个国家,语言是每个城市,这是我们可能不会采取其他方式。几个同义词已经确定并压缩在一起。该工具使用了适合显示维度信息的布局,并添加了一些微妙的颜色来帮助我们直观地对列进行分组。
进一步的步骤
我在这里只讨论了基础知识。进一步的工作可能沿着以下路线进行:
- 跨多个输入文件关联数据。这涉及到在文件间寻找关联 id,这是一项重要的任务,但适用于许多用例。
- 更好地使用贝叶斯逻辑。我认为码头系数对于基本上相关的数据是理想的,但是对于仅统计相关的数据,以及对于使测量而不是维度有意义的数据,将贝叶斯逻辑融入其中将是有趣的。
- 数据质量用例。这里描述的技术可以构成数据质量链中非常有用的一部分,特别是对于取代基于数据透视表的操作。
如果你有兴趣讨论这样的问题,请联系我们。如上所述,本文中显示的函数的后端代码可以根据请求获得(不保证)!这是一个为应用分析和可视化的最新进展提供巨大机会的领域,可以降低成本,让生活更轻松。
使用人脸通过计算机视觉自动锁定和解锁 Ubuntu!!!
我用 OpenCV 和人脸识别库实现了一个自动人脸解锁技术。
Ubuntu Face
在玩代码之前,让我们看看你的 Ubuntu 机器上需要安装的库。
要求
- python 3.7
- OpenCV 4.1.0
- NumPy
- 人脸识别
- sudo apt-get 安装 gnome 屏保
- sudo apt-get 安装 xdotool
下面是三个 python 文件,刚好可以实现这一点!!!
1.face_generate.py
2.face_train.py
3.face_unlock.py
演示视频
1.face_generate.py
生成面
作为第一步,我们必须生成训练图像来训练模型。我已经创建了一个 python 文件来生成我们的面部图像。当你执行这个文件时,它会在命令行中询问你的名字,然后系统会用给定的名字创建一个文件夹。
number=0;
frame_count=0
detector = dlib.get_frontal_face_detector()
print("enter the person name")
name = input()
folder_name="dataset/"+nameif os.path.exists(folder_name):
print ("Folder exist")
else:
os.mkdir(folder_name)
之后,我们需要使用 OpenCV 库通过网络摄像头读取我们的脸,并将其存储在相应的文件夹中,在保存到该文件夹之前,我们应该调整我们的图像大小。
image = imutils.resize(image, width=500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# detect faces in the grayscale image
rects = detector(gray, 1)
# loop over the face detections
for (i, rect) in enumerate(rects):
# determine the facial landmarks for the face region, then
(x, y, w, h) = face_utils.rect_to_bb(rect)
#print rect.dtype
cro=image[y: y + h, x: x + w]out_image = cv2.resize(cro,(108,108))
fram= os.path.join(folder_name+"/",str(number)+ "." + "jpg")
number+=1
cv2.imwrite(fram,out_image)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
frame_count+=1
这将需要 50 张人脸图像来训练模型,你可以根据自己的需要改变图像的数量。
2.face_train.py
该文件将读取由 face_genrate.py 文件生成的每个人脸图像。完成后,我们需要将它们传递给 load_image_file 方法,以获取图像的面部位置。
face = face_recognition.load_image_file("dataset/" + person + "/" + person_img)
# location is in css order - top, right, bottom, left
height, width, _ = face.shape
face_location = (0, width, height, 0)
在训练我们的人脸模型之前,我们应该对我们的图像进行编码,所以我使用了 face_encoding 方法。此外,我们应该将我们的名字存储在一个数组中,以便用 k-最近邻算法进行训练。
face_enc = face_recognition.face_encodings(face, known_face_locations=[face_location])face_enc = np.array(face_enc)
face_enc = face_enc.flatten()
# Add face encoding for current image with corresponding label (name) to the training data
encodings.append(face_enc)
names.append(person)
Sci-kit 学习库是机器学习算法的流行库。我们使用了 sci-kit 学习库提供的 KNeighborsClassifier 算法。
knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')
knn_clf.fit(encodings,names)
最后,我们应该使用 pickle 库保存我们的模型文件。
# Save the trained KNN classifier
if model_save_path is not None:
with open(model_save_path, 'wb') as f:
pickle.dump(knn_clf, f)return knn_clf
3.face_unlock.py
这个 python 文件将根据训练好的图像锁定和解锁 ubuntu 系统。让我们首先使用 OpenCV 库通过网络摄像头捕捉我们的脸。使用 read 方法后,我们可以将人脸图像作为帧来读取。
camera = cv2.VideoCapture(0)
(grabbed, image1) = camera.read()
我们必须从图像中检测人脸的位置,因此我使用了 face_location 方法。得到人脸位置后,我们应该传递给 face_encodings 方法对人脸图像进行编码,以便进行下一步处理。
image = image1[:, :, ::-1]X_face_locations = face_recognition.face_locations(image)# If no faces are found in the image, return an empty result.
if len(X_face_locations) != 0:
# Find encodings for faces in the test iamge
faces_encodings = face_recognition.face_encodings(image, known_face_locations=X_face_locations)
在预测之前,应该使用 knn 模型来找到给定人脸的最佳匹配。下面是验证脸的预测方法。它将返回名称和顶部、左侧、右侧和底部变量。
closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=1)are_matches = [closest_distances[0][i][0] <= 0.4 for i in range(len(X_face_locations))]predictions = [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec in zip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)]
使用 gnome shell 命令锁定和解锁 ubuntu 系统。
if name not in "unknown":
os.popen('gnome-screensaver-command -d && xdotool key Return')
else
os.popen('gnome-screensaver-command -a')
如果用户的面部未知或未被检测到,系统将保持锁定状态。
结论
就这样,在上面列出的三个 python 文件的帮助下,我们已经使用人脸成功测试了 ubuntu 的自动锁定和解锁技术。你可以在这里得到完整的源代码
自动将您的项目从 DVC≤ 0.94 迁移到 DVC 1.x
将您的项目从 DVC ≤ 0.94 迁移到 DVC 1.x 可能是一个非常复杂的过程。这里有一个简单的方法。
DVC 1.0 已经发布了!
DVC 1.0 已经发布,并带来了一整套期待已久的功能。如果你对新功能的完整列表感兴趣,你应该看看 DVC 官方发布的。其中一个主要的变化是一个单独的dvc.yaml
文件,它存储了描述管道的所有必要信息。这在充当 git 存储库中缓存文件占位符的.dvc
文件和调用dvc repro
时要运行的管道的描述之间创建了一个清晰的分离。
这次升级的一个注意事项是,将包含大量.dvc
文件的存储库迁移到新的格式是一个相当复杂的过程。在这篇文章中,我将带你完成从 DVC ≤ 0.94 到 DVC 1 的迁移过程。x 使用一个单一自动化脚本,然后演示一种方法来检查您的迁移是否成功。
迁移一个装满。dvc 文件到新 DVC 1。X YAML 格式
设置
- 首先,在终端中打开您的存储库目录。
cd path/to/your/repository
2.我强烈建议创建一个新的分支,专门用于这个迁移,这对于以后比较新旧配置也很有用
git checkout -b dvc-1-migration
3.升级至最新的 DVC 1。x 版本(现在是时候了)。
**# Homebrew (Mac)** brew upgrade dvc**# Chocolatery (Windows)** choco upgrade dvc**# Conda** conda update -c conda-forge dvc**# pip** pip install dvc -U
运行迁移脚本
捷径——不要告诉我细节!
我建议您继续阅读,看看脚本在做什么,但是如果您只是想运行脚本,您可以在您的目录中执行以下操作:
curl 'https://raw.githubusercontent.com/DAGsHub/Dvc1Migration/master/migrator.py' | python -
漫漫长路——我想明白!
在 DVC ≤ 0.94 阶段以包含其细节的文件命名— Dvcfile
或<name>.dvc
。从 DVC 1 开始,您定义了阶段的名称,而不是包含它的文件的名称。
由 DVC 的合作者之一提供的这个 python 脚本正在将一个单阶段文件转换成dvc.yaml
和dvc.lock
中的一个阶段。它将原始的.dvc
文件(或Dvcfile
)和应该出现在新管道中的 stage 的名称作为参数。这意味着你必须手动运行python migrator.py <file.dvc> <stage_name>
无数次。当涉及到具有许多阶段的管道时,这可能会变得很麻烦。此外,一些.dvc
文件并不代表管道中的阶段,而只是跟踪文件缓存信息。这意味着它们是由 DVC 在运行命令dvc add
或dvc import
时创建的。这些不应该作为阶段出现在您的dvc.yaml
文件中。
我冒昧地修改了脚本,这样它就可以移植一个包含我想要的任意多的.dvc
文件的整个项目。简而言之,它将搜索带有“cmd”键的.dvc
文件,并将它们的内容添加为新格式的 stage。例如,如果您当前有一个名为train.dvc
的阶段文件,脚本将假设您想要调用阶段train
。您可以根据自己的喜好随意改变这种行为!
你可以这样下载:
curl 'https://raw.githubusercontent.com/DAGsHub/Dvc1Migration/master/migrator.py' -O
所有原始的.dvc
文件将被备份为<old_file>.dvc.bak
,并且在您的工作目录的根目录下将创建两个新文件
要运行命令,请执行以下操作:
python migrator.py
输出应该如下所示:
Creating 'dvc.yaml'
Adding stage 'featurization' in 'dvc.yaml'
Generating lock file 'dvc.lock'
Adding stage 'training' in 'dvc.yaml'
Updating lock file 'dvc.lock'
Adding stage 'Dvcfile' in 'dvc.yaml'
Updating lock file 'dvc.lock'
...
如果你不认识这种模式,请在下面的评论中描述你的问题,我会尽我所能来看看。
否则,通过运行以下命令开始跟踪新生成的文件:
git stage -u .
git add dvc.yaml dvc.lock
git commit -m "migration to dvc 1"
git push -u origin dvc-1-migration
这将:
- 在 git 中将旧的
.dvc
文件标记为已删除,同时保持工作目录中的备份文件不被跟踪 - 将新的
dvc.yaml
和dvc.lock
添加到 git 树中 - 将分支
dvc-1-migration
提交并推送到您的origin
遥控器
差不多完成了
就这样,您现在已经将您的项目迁移到 DVC 1 号了!
没那么快!您希望确保您的管道也这样做,并且您的所有数据文件都被正确地跟踪。
比较您的管道
检查 YAML 文件 一个选项是手动检查创建的文件,并验证所有阶段、部门、输出和指标都存在,并且运行正确的命令。或者,您可以…
直观地比较管道图 理想情况下,您会希望轻松地查看新旧管道,直观地描述两个版本的差异。 DAGsHub 是一个致力于数据科学社区的平台,可以为您做到这一点,它支持 DVC 1 和更老的版本(也有其他很酷的功能)。欢迎你使用任何你喜欢的其他工具来可视化这些差异,但实际上我是有偏见的;-)
通过将您现有的存储库连接到 DAGsHub,您可以通过切换分支将您以前的管道与您在分支dvc-1-migration
中创建的管道进行比较。
注意
计算 DVC 1 管道图时,DAGsHub 执行的计算与原始计算略有不同。dvc 文件。这可能会导致节点以不同的顺序出现。除此之外,节点和边应该还是一样的。
谢谢大家!
感谢你阅读了这一点,我希望你觉得有用。如果您有任何建议或反馈,请在下面留下评论,或加入 DAGsHub discord channel 。
在 Python 中自动更新数据源
数据科学基本 Python 指南
以新冠肺炎数据集为例的分步指南
由 Chaeyun Kim 更新数据集 Python 插图
在 Data Sciences 中,很多时候,您会从开源网站或 git 存储库中为您的 Python 项目获得一个外部数据源,比如一个 csv 表。其中一些数据集可能会定期更新。然后,您可能会在运行 Python 脚本以获得最新结果之前,打开 web 浏览器下载数据集。本文将向您展示一个基本指南,告诉您如何自动化这个过程,以一种简单的方式保持您的数据是最新的。
从网站(URL)更新数据集
可以从 URL 中检索几个开源数据集。您可以使用urllib
模块直接在 Python 中打开并读取 URL 。它是大多数 Python 版本中预装的模块。所以你可以导入这个模块,使用下面的代码从任何 URL 下载数据。
**import urllib.request****url = '***<Your URL Here>***'
output = '***<Your output filename/location>***'
urllib.request.urlretrieve(url, output)**#.. Continue data analysis with updated output file
例如,下面的示例脚本显示了从罗伯特·科赫研究所(RKI,德国疾病控制和预防研究机构)更新德国新冠肺炎数据的示例。该数据为 csv 格式,可通过此 URL 获取。在实际操作中,一些URL可能会随着时间的推移而改变或贬值,这使得 Python 脚本运行出错,因此我们可以包含try/except
来检查 URL 是否仍然有效。假设你想保存下载文件的所有版本,你可以使用datetime
模块给输出文件名添加一个时间戳。
从 URL 下载文件的 Python 脚本示例(示例:来自 RKI 的新冠肺炎案例,使用 Python3.8)
*请注意,如果使用 macOS,应该先安装 Python 证书,然后才能使用urllib
库。你可以通过运行 Macintosh HD>Applications>python 3 . x 文件夹中的install certificates.command
文件轻松做到这一点。
从 Git 存储库更新数据集
如果您的 python 项目依赖于来自 git 存储库的数据。在您克隆存储库并将数据集获取到您的本地机器之后,您可能需要定期执行 git fetch 或 pull 来保持您的数据集是最新的。在这种情况下,您可以使用GitPython
模块自动更新您的项目数据集。要使用这个模块,你必须先安装它,你可以很容易地使用pip
这样做。
**pip install gitpython**
如果遇到错误,您可以查看完整的 GitPython 文档来检查您的操作系统环境可能没有的需求。安装完模块后,您可以轻松地按照这些代码在每次运行代码时自动执行 git pull。
**import git****repo = git.Repo('<your repository folder location>')
repo.remotes.origin.pull()**#... Continue with your Code.
例如,JHU·CSSEGithub 仓库提供了csv
格式的新冠肺炎时间序列数据集,这些数据集每天都在更新。将存储库克隆到您的机器上之后,您可以将上述代码添加到 Python 脚本的开头,以便每次都自动获取最新版本。这样,您可以确保您的结果是最新的。
一些提示
对于 git 认证,如果您使用ssh
,这将非常简单。如果您使用HTTPs
,将您的用户名和密码保存到您的环境中会更方便。在 Mac 和 Windows 中,首次输入后会自动存储鉴定信息。在 Linux 中,您可以通过更改凭证超时来强制机器记住您的凭证。例如,您可以使用以下命令让您的计算机记住您的凭据一年。(31536000 秒)
$ **git config --global credential.helper 'cache --timeout=31536000'**
作者单词
本文展示了在 Python 脚本的开头直接从任何 URL 或 git 存储库更新数据集的分步指南。这样,您可以确保基于最新的数据集运行脚本。
我希望你喜欢这篇文章,并发现它对你的日常工作或项目有用。如果您有任何问题或意见,请随时给我留言。
关于我&查看我所有的博客内容:链接
安全健康健康吗!💪
感谢您的阅读。📚
自动化类比:通过人工智能识别跨领域的意义
通过揭示类比联系促进科学发现
介绍
在最近的《自然》杂志文章中,研究人员使用单词嵌入来发现材料科学的候选化合物。其中一名作者 Vahe Tshitoyan 也发表了一篇关于介质的综述。具体来说,他们表明新的热电材料可以通过挖掘科学期刊来发现。
我认为这是著名的单词嵌入技术的一个有趣的应用。使用单词嵌入,我们希望为文档中的重要单词创建矢量表示。一旦矢量化,这些单词就可以用于线性代数中常见的向量运算。因此,我们可以通过加和减单词来找到符合我们直觉的结果。常见的例子是“king” minus “queen” approximately equals “man” minus “woman”
。
矢量化的单词还允许我们匹配在某种潜在意义上与相似的单词。例如,父亲和母亲会比鸡和钱彼此更亲近。这意味着单词向量可以用来捕获复杂的概念*,而无需显式编码这些概念*。
我认为这将是一个很好的应用。一个人们可以用来搜索与他们的研究相关的术语的工具。该工具将返回最近在各种领域发表的文章,这些文章包含与用户搜索词相似的词。
重要的是,相似性是“类比驱动”的,因为这种联系不是偶然观察就能明显看出的。这个词在其他文章中找不到,相反,其他文章只是在类似的背景下讨论一些事情。在上面提到的《自然》杂志的文章中,新的热电材料可能会被发现,因为其他论文正在以类似于人们讨论热电材料的方式讨论一些事情;但是其他文章里没有提到热电这个词。
为了理解单词嵌入在这个应用中做了什么,我们必须掌握它们如何与类比的概念相关联。我写过关于类比的力量的文章,before⁵,我强烈推荐 Douglas Hofstadter 的作品。
对于单词向量,我们看到线性行为,例如“woman is to queen as man is to king”
。这些已经被证明是类比 phenomenon⁴.的基础
在参考文献 4 中,他们表明逐点互信息 (PMI)矩阵的因式分解导致嵌入中的线性相似结构。从概率的角度来看,当词集在所谓的上下文词上引起等价分布时,它们会相互释义。作者通过表明“释义”对应于通过单词转换的类比,将这一点扩展到类比。
深入研究数学细节超出了本文的范围。请问我是否想更详细地讨论类比背后的数学。我鼓励在 Twitter 上进行这些对话,这样其他人也能受益。
“语境”是影响其含义的语句前后的词语。当我们在两个不同的领域之间进行类比时,我们认识到了一些潜在的相似性。
“从一个人和什么样的人交往,你就可以知道他是什么样的人”——弗斯
这就是一直以来的发现。人类通过意识到看似不同的领域之间的潜在联系,将它们联系起来。只有通过阅读其他作者的作品才能建立这种联系。
但是研究人员阅读自己领域之外的论文的可能性有多大呢?在阅读自己领域的论文、教学和撰写资助之间,不太可能。
研究人员多长时间审查一次他们领域之外的论文?
这意味着研究者的工作和其他出版物之间潜在联系的财富在很大程度上还没有被开发。如果人工智能可以提供一种方法来自动发现各种领域之间的类比联系,这将非常有用。将这种能力转化为产品可以帮助学术和独立研究人员做出他们可能会错过的发现。
以此为动机,让我们拼凑一个产品,帮助研究人员在他们的工作和许多不同的 STEM 领域之间建立联系。
注意:我并不声称本文中的应用程序是真正的发现。充其量,该应用程序可能会根据研究人员领域之外的上下文相似的领域,为他们指出一个有趣的方向。参见最后的错误叙述部分。
最终的应用程序如下所示:
我将介绍用于创建应用程序的高级方法。我使用 gensim 库提供的 Doc2Vec 和 Word2Vec。完整的应用程序可以在 Github 上获得。读者可以克隆项目来使用和/或修改。如果需要任何帮助,请联系我。
让我们开始吧。
应用
流程:第 1 部分
应用程序的后端使用 Node/Express web 服务来实现后端和前端之间的通信。图 1 显示了与后端处理相关的用户流。
图 1 前后端关系。Node 处理 arXiv 抓取,而 Python 处理所有其他与 Doc 和 Word 向量相关的函数。
用户首先从下拉框中选择 6 个域中的一个。这是 6 个常见的词干字段。一旦他们选择了他们的领域(和一个子领域),他们将被引导填写大量的搜索词。在参考文献 1 的例子中,这就是“热电”。
用户可以列出多个搜索词,用空格隔开。一旦他们列出了他们的术语,他们运行 DOC2VEC ,此时我们的后端检索所有 6 个域中最近发布的 arXiv 文章,为每篇文章创建文档向量,并根据与用户搜索术语的相关性返回前 5 篇文章。
此时,用户可以查看返回的文章,寻找有趣的对话。同样,这种想法是这些返回的文章可能在与用户的搜索词经常被讨论的相似的上下文中讨论工作(这些返回的文章中的词是“保持与用户的搜索词相同的公司”)。
让我们通过从 arXiv 获取主题来开始支持这个用户流。
获取主题
我们需要在arXiv.org获得所有主题。由于 arXiv 不太可能频繁添加新主题,我将在浏览器控制台中使用客户端 JavaScript,而不是设置后端抓取。
我们可以查看 arXiv 的分析页面并抓取那里的标题和命名代码。我写了下面的 JavaScript 来收集需要的内容:
我们在浏览器控制台中为 6 个域中的每一个运行这个。通过单击页面顶部的浅蓝色标题可以访问每个域:
为每个域这样做提供了 6 个 JSON 文件。下图显示了预期结构的一个片段:
我们可以使用这些来填充我们的下拉列表,并帮助我们抓取实际的文章。我将这些添加到应用程序中的数据文件夹:
├── **data** └── physics.json
└── mathematics.json
└── computer_science.json
└── quant_bio.json
└── quant_fin.json
└── stat.json
└── words.txt
我们可以通过过滤掉任何可能出现在 arXiv 论文中的非英语单词/符号来提高结果的质量。我将使用这个 50 个英语单词的列表:
http://www.mieliestronk.com/corncob_lowercase.txt
我会将这些文字复制并粘贴到一个名为 word.txt 的文件中,并将其放入数据文件夹。这些将在我们运行 Word2Vec 时使用。
刮擦 arXiv
当用户点击 RUN DOC2VEC 时,我们首先需要抓取 arXiv 上的文章。这意味着获取所选领域的每篇文章并创建文档向量。我们可以通过使用 Node.js 包 cheerio 得到每篇文章的链接。这个代码在scrape_arxiv.js
文件中。
我们以.list-identifier
类为目标,用href
来检索每个元素的 URL。这保存了一个名为 domain_1.json 的文件,其中保存了所有 25 个文档的所有单词,如图图 2 所示。
图 2 每个文档的(arXiv 文章)单词作为一个值保存在 domain_1.json 文件中。
这将由Doc2Vec
函数读取(并使用 words.txt 进行清理),以便创建文档向量并找到(推断出)与用户搜索词最匹配的文档。我们现在就写吧。
Doc2Vec
我们使用 gensim 的Doc2Vec
方法,该方法期望从我们读入的 JSON 中得到一个dict
对象作为 domain_1.json 。
您可以在 GitHub 上检查项目,看看我们的 API 如何将这些结果返回到前端。现在,用户已经返回了相关文档,我们可以支持用户流的第二部分。
流程:第 2 部分
在第 1 部分中,用户能够查看返回的文章。这使他们能够找到与自己的工作相关的潜在有用的讨论。然而,阅读整篇文章仍然很费时间,尤其是当所建立的“联系”可能在很大程度上是多余的时候。为了帮助确定这篇文章是否值得一读,我们可以尝试发现这篇文章中的哪些词与用户的搜索词最相似。如果这些返回的单词中有任何一个与用户相关,那么这篇文章可能值得进一步研究。
在第 2 部分中,我们抓取用户选择的文章(从返回的 5 篇文章中),使用 gensim 的 fastText (最初来自脸书)生成单词向量,并从第 1 部分中推断出与用户的搜索词最接近的单词。如图图 3 所示支持该流程。
图 3 用户可以运行 Word2Vec 来生成单词向量,并返回与搜索词最匹配的单词。这有助于用户决定所选文章是否值得进一步探索。
现在让我们创建 Word2Vec 函数。
Word2Vec
既然我们已经有了与用户搜索词最匹配的文档,我们想在一张纸上运行 Word2Vec。用户选择的任何论文都将通过 fastText 由 gensim 的 Word2Vec 方法进行处理,以找到最相关的单词。
与第 1 部分中返回的文档一样,您可以查看应用程序的代码库,看看这些结果是如何返回到前端的。
运行应用程序
让我们打开应用程序,运行几个实验,看看我们有什么发现。
从 GitHub 克隆应用程序:
git clone [https://github.com/sean-mcclure/word2vec_arxiv.git](https://github.com/sean-mcclure/word2vec_arxiv.git)
进入目录并启动 REST API :
node api/scrape_arxiv.js
从终端启动一个简单的 web 服务器:
python3 -m http.server
最后,将您的浏览器指向:
[**http://localhost:8000/app/**](http://localhost:8000/app/)
您应该会看到应用程序的启动状态:
结果
让我们做些试验。我们能从我们选择的一组搜索词中找到有趣的新研究思路吗?这个想法是为了看看单词嵌入是否与我们的直觉一致。
也许我想为我的分子动力学研究发现一种新的优化方法。我对量化金融或其子领域投资组合管理一无所知,但也许这一领域的人们正在尝试与我的工作类似的东西,尽管他们没有从事任何与物理或化学直接相关的工作。
让我们试试:
- 领域:量化金融>投资组合管理
- 搜索词:最优化、能源、量子、系统、动力学、绝热
我从量化金融下拉列表中选择投资组合管理,并填写我的 6 个搜索词。
用户可以列出任意数量的搜索词,甚至只有一个。
第篇论文 返回按相关程度排列:
- 带学习的鲁棒最优投资和再保险问题
- 具有路径依赖劳动收入的最优投资组合选择:无限地平线情形
- 半度量投资组合优化:一种减少同时资产冲击的新算法
- 使用自动编码器重建比率检测资产共同运动的变化
- 高维夏普比率:样本外最大值、约束最大值和最优投资组合选择的案例
我可以审核申请中显示的文件:
这些论文肯定是在谈论最优化,并且似乎提到了与动力学相关的东西。让我们在我们的顶级论文上运行 Word2Vec 来聚焦与我们的搜索词相关的具体讨论:
约简、顺序、策略和过滤这几个词或许值得一查。同样,这些是 Word2Vec 返回的单词,表明它们与我的搜索词相关的一些讨论有关联。让我们仔细检查一下这张纸,看看是否是这样。
简化一词是指论文使用了所谓的简化控制模型。这来自于控制理论,它是数学的一个子领域,研究影响动力系统的行为。动力系统与系统化学有联系,系统化学是研究相互作用分子网络及其涌现特性的科学。系统化学的一个主要目标是揭示复杂的反应网络,其中分子不断消耗能量来执行特定的功能。
经济模型处理多条业务线以及它们之间的依赖关系。他们试图通过创建一个通过优化学习到的参数模型来最大化财富的效用。这种优化是由汉密尔顿-雅可比-贝尔曼方程 (HJB)驱动的,其中导数由广义克拉克梯度代替。
HJB 方程已被用于研究“化学波”,即信息在整个反应扩散系统中快速传播,以同步和协调生物事件。
通过在网上做一些研究,我们已经能够在单词“ reduced ”和我们对分子动力学的兴趣之间建立联系。这是因为出现在我们最相关的文档中的单词 vector“reduced”与我们的搜索词“很接近”;优化、能量、量子、系统、动力学、绝热。深入研究后,我们很快意识到“减少”这个词确实是在优化的上下文中讨论的。这似乎是我们的词向量捕捉有用概念而没有显式编码这些概念的一个例子。
记住,我们最相关的文档也是通过使用嵌入发现的,通过文档向量。通过将 Doc2Vec 和 Word2Vec 放在一起,我们可以在不同的研究领域之间建立有趣和相关的联系。
这就是使用自动类比在我们可能永远不会想到的领域之间建立联系的力量。这是一个很好的例子,通过使用以类似方式运行的“智能”机器,增强了人们已经有的工作方式。
但是像一份经济学期刊的作者所使用的那样,探索使用与克拉克梯度相匹配的 HJB 方程来学习应用于复杂化学系统的优化参数,真的值得吗?也许吧。
或者也许我从一开始就知道(相信)这是不可行的。但是,在自动类比的鼓励下,沿着这种道路走下去不会有太大的害处。我只尝试了第一篇相关论文的第一个词,一个领域的第一个词,在我尝试的第一个词干领域。
至少这个应用程序让我重新考虑我目前的研究方法,看看其他人在做什么。这可能会引发新的见解,或者迫使我寻找不同的道路。它可能会让我想起我在另一本杂志上读过的东西,促使我重温某些概念。在领域之间建立松散的联系有助于我们远离短视的想法。
虚假叙述?
每当我们“发现”一些有趣的东西时,如果不提出一个困扰人类的基本问题,那将是我的失职。很容易看出我们想要什么,以为有联系,但实际上没有。我们必须小心,不要对看似有趣,但实际上不相关或不切实际的东西赋予太多的权重。
因此,当我们建立联系时,我们应该对任何相关的发现保持怀疑。科学的美妙之处在于(如果做得恰当的话),任何新的想法都必须经过严格的可证伪性检验,并证明它确实站得住脚。
愉快的探索。