TowardsDataScience 博客中文翻译 2021(五百九十一)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用 Pytorch 对预调整变压器进行情感分析

原文:https://towardsdatascience.com/sentiment-analysis-with-pretrained-transformers-using-pytorch-420bbc1a48cd?source=collection_archive---------17-----------------------

使用 Huggingface Transformers 中最简单的 API 预测积极或消极的情绪

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

卓成友Unsplash 上拍照

介绍

情感分析【NLP】问世以来,一直是一项非常热门的任务。它属于文本分类的子任务或应用,其中从不同文本中提取和识别情感或主观信息。如今,世界各地的许多企业都使用情感分析,通过分析不同目标群体的情感来更深入地了解他们的顾客和客户。它还广泛应用于不同的信息来源,包括产品评论、在线社交媒体、调查反馈等。

在本文中,我们将向您展示如何通过 Huggingface 使用 变形金刚库 **快速有效地实现情感分析。**我们将使用预调整的变压器,而不是微调我们自己的变压器,所以需要很低的安装成本。

所以,让我们直接进入教程吧!

教程概述

  • 步骤 1:安装库
  • 步骤 2:导入库
  • 步骤 3:建立情感分析管道
  • 步骤 4:输入文本
  • 步骤 5:执行语义分析

步骤 1:安装库

我们需要安装的库是 Huggingface 变形金刚库。要安装变压器,您只需运行:

pip install transformers

注意:Huggingface Transformers 需要安装py torchtensor flow中的一个,因为它依赖其中一个作为后端,因此在安装 Transformers 之前请确保有一个工作版本。

步骤 2:导入库

在您成功地将 Transformers 安装到本地环境之后,您可以创建一个新的 Python 脚本并导入 Transformers 库。我们没有导入整个库,而是在库中引入了[pipeline](https://huggingface.co/transformers/main_classes/pipelines.html)模块,它提供了一个简单的 API 来执行各种 NLP 任务,并将所有代码复杂性隐藏在其抽象层之后。要导入pipeline模块,我们可以简单地做:

from transformers import pipeline

步骤 3:建立情感分析管道

现在,在您导入pipeline模块后,我们可以开始使用该模块构建情感分析模型和分词器。为了建造它,我们可以做:

sentiment_analysis = pipeline(“sentiment-analysis”)

这将创建一个适合情感分析任务的管道。等等,你可能会问,这里用的是什么模型和记号化器。默认情况下,变形金刚库使用一个 DistilBERT 模型,该模型在来自 GLUE 数据集斯坦福情感树库 v2 (SST2) 任务上进行了微调。

如果您想使用另一个模型或标记器,您可以在实例化管道时将它们作为modeltokenizer参数传递。

步骤 4:输入文本

我们已经建立了管道,现在是时候输入我们想要测试其情感的文本了。让我们为两个句子声明两个变量,一个肯定,一个否定:

pos_text = “I enjoy studying computational algorithms.”
neg_text = “I dislike sleeping late everyday.”

第五步:进行情感分析

最后,是时候对我们输入文本的情绪(积极或消极)进行分类了。要执行情感分析,我们可以运行以下程序:

result = sentiment_analysis(pos_text)[0]
print("Label:", result['label'])
print("Confidence Score:", result['score'])
print()result = sentiment_analysis(neg_text)[0]
print("Label:", result['label'])
print("Confidence Score:", result['score'])

输出:

标签:阳性
置信度得分:0.9000136363686

标签:负的
信心分数:0.901038636866

瞧,瞧!我们现在可以看到,该模型正确地将两个文本预测到它们的情感中,具有高的置信度得分。

结论

这个帖子到此为止!在这篇短文中,我们回顾了如何使用 Transformers 库提供的简单 API 进行情感分析。如果你想要的话,我在这里附上了这篇文章的 Jupyter 代码:

如果你想知道如何对你自己的自定义数据集进行文本分类而不是情感分析,你可以参考我以前关于 BERT 文本分类的帖子。在那里,您将找到一个文本分类示例的深入演练和解释:

如果你喜欢,请随意看看我的其他帖子,下次见!

参考

[1] 变形金刚 Github ,拥抱脸

[2] 变形金刚官方文档,拥抱脸

[3] Pytorch 官网,艾研究

[4] Tensorflow 官网,谷歌大脑

[5] Sanh,Victor,et al. “蒸馏伯特,伯特的蒸馏版:更小,更快,更便宜,更轻。” arXiv 预印本 arXiv:1910.01108 (2019)。

[6] 斯坦福情感树库 v2 (SST2) ,Kaggle

[7] 通用语言理解评测(GLUE)基准,NYU,UW NLP,DeepMind

使用变形模型和心理扭曲进行情感分析

原文:https://towardsdatascience.com/sentiment-analysis-with-transformer-models-with-a-twist-of-psychology-fe19fe5383ae?source=collection_archive---------24-----------------------

入门

为什么情感分析需要先理解我们的思维方式,然后才能告诉我们我们的感受

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

Samule 孙Unsplash 上的照片

所以,你已经投入了大量的时间来开发热门的营销内容或撰写下一篇大文章(有点像这篇文章),并希望向你的观众传达某种情感。你想知道你的内容是否会引起你的观众的共鸣,并得出一种特定的感觉,无论是喜悦、愤怒、悲伤,以了解不同的人对你的内容的反应。

文本分析,更具体地说是情感分析,无论如何都不是一个新概念,然而它也经历了几次模型的迭代,随着时间的推移变得越来越好。首先,我们从单词袋方法开始,来理解某些单词是否会传达某种情感。然后我们转到 RNN/lstm,它使用更复杂的模型来帮助我们理解情绪,尽管需要大量的训练,但缺乏并行性,这使得它非常慢,而且需要大量资源。2017 年,谷歌的研究人员提出了变压器模型的概念(图 1),这比它的前辈们效率高得多。首先,输入嵌入是多维的,它可以处理完整的句子,而不是一个接一个的一系列单词。其次,它有一个强大的多头注意力机制,使句子能够保持上下文和句子中单词之间的关系。它对每个单词进行多次注意力分析,以确保足够的采样。最后,它使用前馈神经网络来归一化结果,并提供情绪(或极性)预测。要了解更多关于 transformer 架构的信息,请访问 huggingface 网站

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

图一。变压器模型架构[1]

现在我们已经理解了 transformer 模型,让我们双击这篇文章的要点,即对一个文档而不一定是一个句子进行情感分析。转换器模型使用的输入嵌入是句子嵌入,而不是整个段落或文档。为了分析一个文档,我们需要把句子分解成句子。为此,我使用 spacy 并定义了一个函数来获取一些原始文本并将其分解成更小的句子。

以下面的句子为例。我们会把这个句子放入一个空间模型,这个模型会分析文本,并把它分解成一个语法句子列表。这里有一个函数来帮助我们完成这个任务和输出

class Sentiment:# Constructor with raw text passed to the init function
    def __init__(self, raw_text):
        self.raw_text=raw_text.lower()

def breakSentence(self, text_content):
     self.text_content=text_content
     nlp = English()
     nlp.add_pipe(nlp.create_pipe(‘sentencizer’)) 
     doc = nlp(self.text_content)
     sentences = [sent.string.strip() for sent in doc.sents]
     return sentences

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

图 2: Spacy 句子列表[图片由作者提供]

一旦你有了一个句子列表,我们将通过 transformer 模型循环它,以帮助我们预测每个句子是积极的还是消极的,以及得分是多少。您最终会得到类似下面的结果(图 3)

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

图 3:带有情感极性和得分的句子突破[图片由作者提供]

现在,一旦我们有了这些句子,我们可以假设你只是平均出你的正面和负面,并得出一个最终的极性分数。这种假设存在一些挑战。首先,我们假设每个句子都具有相同的权重,但这并不总是如此(稍后会详细介绍),其次,我们包括模型识别为负面的置信度相对较低的句子(60%负面,40%正面)。在我的研究中,我想过滤掉任何没有至少 90%得分的句子,无论是正面还是负面的。这是我为此开发的一些代码和结果。在这段代码中,我还定义了一个 before 和 after 结果,它可以帮助我理解我从多少个句子开始,又过滤掉了多少个句子。最后,它返回适当的句子和一个矩阵,每个过滤后的句子是如何分类的,1 表示肯定,1 表示否定。

def findRawTextPolarity(self):
    confidence_level=0.9
    nlpSA = pipeline("sentiment-analysis")
    sentences=self.breakSentence(self.raw_text)
    print('Before: ', len(sentences))
    result = [{'sentence' : sentences[i],'label':nlpSA(sentences[i])[0]['label']} for i in range(len(sentences)) if nlpSA(sentences[i])[0]['score']>confidence_level]
    print('After: ', len(result))
    sentences= [result[i]['sentence'].lower() for i in range(len(result))]
    labels= [result[i]['label'] for i in range(len(result))] 
    map_polarity={'NEGATIVE': -1, 'POSITIVE': 1}
    matrix_result=[map_polarity[k] for k in labels]
    return sentences, matrix_result

好了,到这一点,我们应该有一个过滤句子的列表,至少有 90%的预测和一个极性矩阵。现在是阅读心理学有趣的部分。

当读者阅读文件时,他们倾向于在接近文件结尾时记住更多的内容,而在接近开始时记住较少的内容。第二,读者倾向于记住文档的顶峰或高潮。作者希望读者记住什么?如果你考虑峰端法则,这些陈述是正确的。峰值结束规则声明*“该理论声明总体评级由体验的峰值强度和体验的结束来确定。它不关心整个体验的平均值"*

因此,理解 peak end rule 的含义并将其与我们的用例联系起来,确实,当我们给模型一个大的文本语料库时,我们会努力理解文章的峰值并赋予它稍微更多的权重,以及确定一种机制来为文档中后面的句子提供更多的权重。我们该怎么做?

为了识别文章的高潮,我的假设是,我们需要理解机器如何对高潮进行分类,其中一种方法是使用文本摘要。文本摘要从文档中提取关键概念来帮助提取关键点,因为这将提供对作者希望你记住的内容的最佳理解。第二,我们需要定义一个衰减因子,这样当你在文档中往下移动时,前面的每一句都会减轻一些重量。好了,让我们来定义完成这些任务的函数。

首先,让我们获取一个文本语料库,并使用 transformer 预训练模型来执行文本摘要。这个函数返回到峰值句子。

def findPeak(self):
    summarizer = pipeline("summarization")
    peak = (summarizer(self.raw_text))[0]['summary_text']
    peak_sentences=self.breakSentence(peak)
    return peak_sentences

接下来,我们将在本文前面定义的句子列表中找到这些峰值句子的位置。如果一个句子是峰值的一部分,我们将保留值 1,但如果它不是峰值句子,我们将删除它。我用过 0.9,但是你可以测试一些适合你的用例的东西。下面的函数可以完成这项任务。

def getPeakposition(self):
    peak_weight_red=0.9
    peak=self.findPeak()
    sentences = self.findRawTextPolarity()[0]
    matches=[[1 if operator.contains(s.replace(' .', ''),p.replace(' .', '')) else 0 for s in sentences] for p in peak]
    match_filter=[m for m in matches if sum(m)>0]
    sum_matrix=np.sum(np.array(match_filter),0)
    map_polarity={1: 1, 0: 1* peak_weight_red}
    matrix_result=[map_polarity[k] for k in sum_matrix]
    return matrix_result

好了,现在我们需要创建一个机制来引入一个衰减因子,当一个句子在一篇文章中对人脑来说变老时,这个衰减因子会移除一定程度的权重。我已经创建了一个函数,使用线性衰减因子来降低它,但我也使用了工作良好的指数衰减。

def textWeights(self):
    decay=0.01
    matrix=self.findRawTextPolarity()
    matrix_size=len(matrix[1])
    decay_matrix=[1-(decay*i) for i in range(matrix_size)]
    return decay_matrix

好了,我们现在应该有三个矩阵了

  1. 提供衰减权重因子
  2. 为高峰句子提供权重
  3. 过滤句子的极性

现在变得容易了。我们将三者相乘,这将给出文档中每个句子的加权结果。既然这些都是加权的,我们就可以对整个文档的最终得分进行加权平均。我已经定义了我自己的分类尺度,但是你可以定义任何对你自己的用例有意义的东西。

这里得到的最终分数是我开发的代码,后面是我得到的结果。

def getFinalScore(self):
    peakposition=self.getPeakposition()
    decay=self.textWeightsexp()
    sent_polarity=self.findRawTextPolarity()[1]
    fin_score = [a*b*c for a,b,c in zip(peakposition,decay, sent_polarity)]
    fin_sent_fct = lambda x: 'POSITIVE' if x>0.5 else ('NEUTRAL' if 0.49>x>-0.5 else 'NEGATIVE')
    fin_sent=fin_sent_fct(np.mean(fin_score))
    print('This document is categorized as {} with a final score of {}'.format(fin_sent, np.mean(fin_score)))

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

图 4:最终情绪得分[图片由作者提供]

这就是结局吗?不。情绪分析实际上是一个非常棘手的问题,需要适当的考虑。首先,情绪可能是主观的,不同的人有不同的解释。例如,我可能喜欢某篇文章的巅峰,而其他人可能会将不同的句子视为巅峰,因此引入了很多主观性。第二,我们利用了一个预先训练好的模型,但该模型应该用您自己的数据和特定用例来训练。您可以利用各种模型,其中一个很流行的模型是 BERT,但是您可以根据您的用例再次使用其他几个模型。如果做得好,情感分析也是一种分析文本的好方法,可以释放大量的洞察力,帮助你更好地做出数据驱动的决策。

要观看视频示例,请访问 youtube 上的以下链接

[https://youtu.be/sZOV5pD4ELg](https://youtu.be/sZOV5pD4ELg)

来源:

  1. Google 的 Attention is all you need 一文中提出的变压器架构

根据您的闲置数据进行情绪和参与度分析

原文:https://towardsdatascience.com/sentiment-engagement-analysis-from-your-slack-data-11f7ff995b62?source=collection_archive---------17-----------------------

一瞥你松弛空间的情绪

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

图片由 Pankaj Patel 从Unplash.com拍摄

有没有想过你发布的内容有多吸引人?它是清晰的还是令人困惑的?或者在全公司会议上人们误解了你的意思?

远程环境让教师和领导者很少有机会获得反馈并优化他们的内容以取得更好的绩效。

因为我职业生涯的相当一部分已经是远程完成的了(实际上是在 covid 时代之前!),我发现这些问题在我渴望创造性解决方案的大脑中闪烁着兴奋和喜悦。我有数据,我所要做的就是起草我想回答的问题,然后去做。

这也是我训练营的最后一个 e2e 项目,我身边有主题专家作为利益相关者(我的首席老师和我的项目导师)指导我开发一个价值驱动的产品。

数据源

我的数据集包括从第一天到最后一天由 Slack 管理员提供的 Ironhack 训练营的公开对话。也可以通过 Slack API 来完成,但是这超出了我的项目范围。

为了保持这篇博文的简洁,请注意,我重点强调了代码中令人兴奋的部分,而不是它给出的见解。

如果您正在寻找:

  • 视觉效果(在画面中完成)看看我的演示
  • 详细代码,浏览我的 GitHub repo 这里

数据清理和争论

为了表示我在 JSON 文件数量方面遇到的挑战,这里是通用频道的文件夹,其中包含按天细分的所有对话,如下所示:

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

所以我首先将每个通道的 JSON 文件加载到一个数据帧中。

*# defining file path*
path_to_json = '../raw_data/general/' 

*# get all json files from there*
json_pattern = os.path.join(path_to_json,'*.json')
file_list = glob.glob(json_pattern)

*# an empty list to store the data frames*
dfs = []
**for** file **in** file_list:
    *# read data frame from json file*
    data = pd.read_json(file)
    *# append the data frame to the list*
    dfs.append(data)

*# concatenate all the data frames in the list*
channel_gen = pd.concat(dfs, ignore_index=**True**)
*# test*
channel_gen.tail(100)

然后为了方便起见,将每个通道的独立数据帧合并成一个数据帧。

*#frames = [channel_gen, channel_books, channel_dmemes, channel_dresource, channel_dbootcamp, channel_funcommittee, channel_dvizbeauties, channel_frustrations, channel_finalproject, channel_frustrations, channel_funcommittee, channel_katas, channel_labhelp, channel_music, channel_random, channel_vanilla]*

df = pd.concat([channel_gen, channel_books,
                    channel_dmemes, channel_dresource, 
                    channel_dbootcamp, channel_funcommittee,
                    channel_dvizbeauties, channel_frustrations, 
                    channel_finalproject, channel_frustrations, 
                    channel_funcommittee, channel_katas, 
                    channel_labhelp, channel_music, 
                    channel_random, channel_vanilla], ignore_index=**True**, join="outer")

到目前为止,我的 dataframe 有 5263 行和 13 列,其中有一堆与我的项目无关的数据。清洁是艰难的。

清洗柱子&抬杠:

- subtype: filter out it's values from df, remove the original column\
- ts: changing it to datetime, remove miliseconds, get days of the week, months of the year, type of the day, parts of the day\
- user_profile: extract real_name in new column, remove the original\
- attachments: extract title, text, link in new columns\
- files: extract url_private and who shared\
- attachments: extract title, text, link in new columns\
- reactions: extract user, count, name of the emoji\

因为几乎所有的数据都嵌套在 JSON 库中,所以我项目的大部分时间都花在了迭代特性工程任务上,以获得可以用来训练模型的变量。同时,提取数据是我最喜欢的。下面你可以看到几个函数的例子,这些函数被创建来从数据帧中获得洞察力。

谁发送的回复最多:

*#* user_profile column: extract real_namedef getrealnamefromprofile(x):
    """this function is applied to column user_profile
    """

    if x != x:
        return 'noname'
    else:
        return x['real_name']df_clean['real_name'] = df_clean['user_profile'].apply(getrealnamefromprofile)df_clean

群组中使用最多的表情符号是什么:

*# reactions column:  extract frequency*

**def** getcountfromreactions(x):
    *"""this function is applied to column reactions*
 *"""*

    **if** x != x:
        **return** 0
    **else**:
        **return** x[0]['count']

df_clean['reactions_count'] = df_clean['reactions'].apply(getcountfromreactions)

df_clean

人们在频道上分享了哪些链接:

*# files column: extract link*

**def** geturlfromfile(x):
    *"""this function is applied to column files*
 *"""*

    **if** x != x:
        **return** 'nofile'
    **else**:
        **try**:
            **return** x[0]['url_private']
        **except** **KeyError**:
            **return** 'nolink_infiles'

df_clean['link_of_file'] = df_clean['files'].apply(geturlfromfile)

df_clean

为了帮助我找到交流的来源,我创建了另一个函数来区分首席教师和助教与学生。

*# create a new column with teaching and students*
**def** applyFunc(s):
    **if** s == 'siand the LT (she/her)':
        **return** 'teacher'
    **if** s ==  'Florian Titze':
        **return** 'teacher'
    **if** s ==  'Kosta':
        **return** 'teacher'
    **else**:
        **return** 'student'
    **return** ''

df_clean['participant'] = df_clean['real_name'].apply(applyFunc)
df_clean['participant'].value_counts()

最后,在准备模型之前,我花了一点时间带着感激的心情检查了一下我清理过的数据框:

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

自然语言处理

在学习这一部分的时候,我意识到这是我想专攻的。文本分析,听起来很酷,对吧?想象一下,当机器可以在几毫秒内完成时,人们花在阅读繁琐的文本并试图用充满偏见的大脑分析它的时间有多长。让我颤抖。

我的范围最初还包括文本特征提取(因为这是你可以从书面交流中获得的最有价值的东西),这是我现在正在做的事情,但是,在那 5 天里我没有时间做这件事,这个主题也超出了训练营的范围。

相反,我专注于获得每条评论的情感分数,并从最常用的单词中生成一个令人敬畏的 worldcloud,作为给我同事的礼物。❤️

密码

**def** clean_links(df):
*#replace URL of a text*
    df_sent['text'] = df_sent['text'].str.replace('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', ' ')

clean_links(df_sent)
df_sent['text']*# load VADER*
sid = SentimentIntensityAnalyzer()# add VADER metrics to dataframedf_sent['scores'] = df_sent['text'].apply(lambda text: sid.polarity_scores(text))df_sent['compound']  = df_sent['scores'].apply(lambda score_dict: score_dict['compound'])df_sent['comp_score'] = df_sent['compound'].apply(lambda c: 'pos' if c >=0 else 'neg')#test 
df_sent.head()

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

这很容易。现在,到了具有挑战性的预处理部分,创建一个没有链接、数字、标点、停用词的世界云:

*# set of stopwords to be removed from text*
stop = set(stopwords.words('english'))

*# update stopwords to have punctuation too*
stop.update(list(string.punctuation))

**def** clean_text(text_list):

    *# Remove unwanted html characters*
    re1 = re.compile(r'  +')
    x1 = text_list.lower().replace('#39;', "'").replace('amp;', '&').replace('#146;', "'").replace(
    'nbsp;', ' ').replace('#36;', '$').replace('**\\**n', "**\n**").replace('quot;', "'").replace(
    '<br />', "**\n**").replace('**\\**"', '"').replace('<unk>', 'u_n').replace(' @.@ ', '.').replace(
    ' @-@ ', '-').replace('**\\**', ' **\\** ')
    text = re1.sub(' ', html.unescape(x1))

    *# remove non-ascii characters*
    text = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore').decode('utf-8', 'ignore')

    *# strip html*
    soup = BeautifulSoup(text, 'html.parser')
    text = soup.get_text()

    *# remove between square brackets*
    text = re.sub('\[[^]]*\]', '', text)

    *# remove URLs*
    text = re.sub(r'http\S+', '', text)

    *# remove twitter tags*
    text = text.replace("@", "")

    *# remove hashtags*
    text = text.replace("#", "")

    *# remove all non-alphabetic characters*
    text = re.sub(r'[^a-zA-Z ]', '', text)

    *# remove stopwords from text*
    final_text = []
    **for** word **in** text.split():
        **if** word.strip().lower() **not** **in** stop:
            final_text.append(word.strip().lower())

    text = " ".join(final_text)

    *# lemmatize words*
    lemmatizer = WordNetLemmatizer()    
    text = " ".join([lemmatizer.lemmatize(word) **for** word **in** text.split()])
    text = " ".join([lemmatizer.lemmatize(word, pos = 'v') **for** word **in** text.split()])

    *# replace all numbers with "num"*
    text = re.sub("\d", "num", text)

    **return** text.lower()*# apply cleaning function*
df_train['prep_text'] = df_train['text'].apply(clean_text)
df_train['prep_text'].head(5)*# apply wordcloud function*
make_wordcloud(df_train['prep_text'])

结果呢:(ta-daa)

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

机器学习模型

为了在这里强调一些很酷的东西,我采用了随机森林分类模型来查看您需要哪些特征来获得回复(在这种情况下,从群组中获得帮助),准确度分数为 0.86:

*# feature importance*
feat_importances = pd.Series(importances, index=X.columns)
plt.figure(figsize=(10,10))
feat_importances.nlargest(15).plot(kind='barh', color='#FF9B48', width= 0.7)
plt.xlabel('Level of importance', fontsize=16)
plt.ylabel('Features', fontsize=16)
plt.yticks([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14], ['length_of_text', 'neutral_tone', 'positive_tone',
                                                   'amount_of_reactions', 'negative_tone',
                                                   'may', 'morning','march', 'files_attached', 
                                                   'teacher_posted', 'evening', 'early_morning',
                                                   'labhelp_channel', 'general_channel', 'got_reaction'])

plt.title("Top 15 Important Features", fontsize=20)
plt.show()

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

看起来你有更好的机会得到回复,如果你:用中性或积极的语气写一封长信,收到很多回复,早上发送也有帮助,或者你有一个附件。

结论

通过这个项目,我学到了一些东西:

  • 在你投资的事情上工作是一个游戏改变者
  • 利益相关者在你身边是无价的
  • 迭代是关键
  • 从长远来看,函数可以节省您的时间

接下来,我将利用这个数据集,运用我从 Udemy 的 NLP 课程中获得的知识,从评论中提取一些很酷的东西。

拉丁语的零距离情感分类(借助其后代)

原文:https://towardsdatascience.com/sentiments-of-rome-80eb617b5980?source=collection_archive---------42-----------------------

一种用于死(和/或低资源)语言的 NLP 方法

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

Unsplash 上由 L A L A S Z A 拍摄的照片

介绍

拉丁语可以被认为是“旧世界的英语”。我把它与英语进行了比较,以强调这样一个事实,就像英语是当今世界上最流行的语言一样,拉丁语在古代西方世界占据主导地位。这不仅仅是因为受欢迎,而是因为罗马扩张的影响,尤其是在西欧和地中海地区。然而,拉丁语直接塑造了许多现代语言(罗曼语),也对其他语言产生了一些影响(比如英语)。我想看看拉丁语在现代自然语言处理(NLP)环境中是如何工作的(使用基于 transformer 的预训练模型),我在这篇短文中提到了这一点。

古典拉丁语现在被认为是一种死亡的语言,这使得它在 NLP 领域也是一种低资源语言。拉丁语的近亲被认为是撒丁语和意大利语。然而,它们大多是从“粗俗拉丁语”演变而来,这是一种在平民中流行的非文学拉丁语。我假设涉及拉丁语的 NLP 任务(情感分类任务)将由这些语言中的一种来帮助,尽管预训练模型在其预训练或微调阶段没有见过拉丁语。这也被称为零起点学习,我们可以将相关语言的知识转移到拉丁语中,而无需在拉丁语语料库中进行微调。

方法

作为一种资源匮乏的语言,要获得一个庞大的带注释的拉丁语语料库并不容易。我在互联网上使用了一个可访问的数据集【4】【5】,它由 45 个拉丁句子组成,分为 3 个情感类别(积极、消极、中性、混合),并从贺拉斯的颂歌中提取(数据集的创建者有一篇即将发表的论文使用了相同的数据集,请检查参考文献)。为了简单起见,我去掉了混合句和中性句。我使用了基于 transformer 的微调单语模型(用于情感分类),可用于意大利语 (Bert)、英语 (Roberta)、西班牙语 (Bert)、德语 (Bert)、以及印尼语 (Roberta)上的 Huggingface 。撒丁语也是一种资源匮乏的语言(或者至少网上没有足够的资源),因此它被抛弃了。拉丁语数据集由如下句子组成,

“这是一个很好的例子”——否定的
“非自我的酒神是我的朋友”——肯定的

对于 Huggingface 模型,剩下的工作很容易,每个模型都遵循通常的步骤(在 Huggingface 中也提到过)。结果是通过将标记化的拉丁句子直接输入到微调模型中获得的。

import torch
import numpy as np
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import pandas#Read the corpuslat=pandas.read_csv('latin.tsv',sep='\t')lat=lat[lat['Value']!='mixed']
lat=lat[lat['Value']!='neutral']sentences=lat.loc[:,'Text']labels=lat.loc[:,'Value']
true_val=map(lambda x:1 if x=='positive' else 0,labels)# Load model and tokenizertokenizer = AutoTokenizer.from_pretrained(“MilaNLProc/feel-it-italian-sentiment”)model = utoModelForSequenceClassification.from_pretrained(“MilaNLProc/feel-it-italian-sentiment”)#tokenize the sentencesinputs = tokenizer(list(sentences),padding=True, return_tensors="pt")#first 4 lines can slightly change with the model, e.g.- for spanish model, outputs = model(**inputs),logits = outputs.logitsproba = torch.nn.functional.softmax(logits, dim=0)labels = torch.tensor([0]*len(list(sentences)).unsqueeze(0)
outputs = model(**inputs, labels=labels)
loss, logits = outputs[:2]
logits = logits.squeeze(0)prob = torch.nn.functional.softmax(logits, dim=0)result=[]for i in prob:
result.append(list(i.detach().numpy()).index(np.max(i.detach().numpy       ())))from sklearn.metrics import accuracy_score
accuracy_score(list(true_val),result)#for some models, their output further needs to be processed in order to have numerical valueresult=[]for i in sentences:
     result.append(1 if sentiment_analysis(i)[0]['label']=='POSITIVE' else 0)

对于包括任务流水线的模型,

from transformers import pipeline#Here the pytorch models are not created explicitly like in the previous snippet. Yet, the models gives an output similar to previoussentiment_analysis = pipeline(“sentiment-analysis”,model=”siebert/sentiment-roberta-large-english”)result=[]for i in sentences:
     result.append(1 if sentiment_analysis(i)[0]['label']=='POSITIVE' else 0)accuracy_score(list(true_val),result)

结果

遗传相似度是语言学中用来衡量一对语言之间的相似性或关联性的一种尺度。它的值越高,这一对语言之间的距离就越大!。我使用了一个在线工具来测量拉丁语和上面提到的其他语言之间的相似性。它显示了如下关系。

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

按作者

像意大利语和西班牙语这样的罗曼语最接近拉丁语,而像英语和德语这样的日耳曼语则稍远一些。印尼语和拉丁语没有关系,但是印尼语在其拼写中采用了拉丁语。让我们来看看所选语言的每个模型如何执行零镜头分类。对于具有 3 个类别输出(德语)的模型,将少数中性/混合预测分别改为阴性和阳性,并考虑其中的最高准确度得分。

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

按作者

令人惊讶的是,语言之间的关系模式在这里没有出现。每个实例(除了印度尼西亚语)的准确度都大于 0.5,西班牙语显示了罗曼语的最高准确度分数。英语表现的最好,同时也是最接近拉丁语的语言;意大利语在后面。尽管一种语言与拉丁语相差甚远,但这并不总是意味着性能下降。

这种结果的一个可能原因是模型的能力(这取决于模型中的参数数量、预训练目标和用于预训练模型的语料库)。另一个主要原因是每个语言模型中使用的预训练/微调数据集的大小。意大利模型[1]使用由 2k 条推文组成的情感数据集进行了微调,而英国模型[2]也在属于不同领域的多个数据集(推文、评论等)上进行了微调。).西班牙模型[3]利用了大约 5k 的 tweets 进行微调。

有人可能会认为,无论源语言是什么,用于模型的训练语料库的质量/规模都会直接影响其零炮性能。此外,该模型可能能够学习句子情感的底层表示,而不管语言如何,并且所学习的知识可以在目标语言的零射击任务期间使用。你怎么想呢?在评论里提!!!这不是一套广泛/完整的实验和分析,因此无法对导致这一结果的因素做出明确的结论。甚至其他可用的和未经测试的模型也可能揭示一个新的结果。然而,据观察,语言相关度并不是唯一决定拉丁语情感分类零命中率的因素。我相信这是一个有趣的研究领域。

感谢您的阅读!

参考

[1]——“感受:意大利语的情感和情绪分类,比安奇等人”,https://aclanthology.org/2021.wassa-1.8/

[2]——“不止是一种感觉:情感分析准确性的基准,海特曼等,【https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3489963】T4

[3]—https://github.com/finiteautomata/pysentimiento/

[4]——https://github.com/CIRCSE/Latin_Sentiment_Analysis

[5]——“拉丁诗歌的情感分析:贺拉斯颂歌的第一次实验。,曼布里尼等人,“CLiC-it,202,https://clic2021.disco.unimib.it/

九月版:概率编程

原文:https://towardsdatascience.com/september-edition-probabilistic-programming-11a6699e2fac?source=collection_archive---------24-----------------------

月刊

模拟我们周围高度复杂的世界

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

照片由来自佩克斯麦克·穆林斯拍摄

我们是一个不可思议的物种:我们对周围的世界非常好奇,喜欢学习,并经常找到新的方法和工具来做这件事。过去几十年中的一个进步就是计算。通过改进计算引擎的架构,我们在模拟复杂动态、列举大量潜在结果以及对大量可能性进行快速计算方面做得更好了。所有这些事件都推动了我们对周围世界的理解。特别是机器学习(ML)为我们提供了一套高度灵活和强大的工具来预测、理解和推理未来。虽然目前最先进的方法在第一个目标上表现出色,但在后两个目标上进展缓慢。其中一个原因是视角。世界本来就很复杂。

此外,事件或结果通常是众多因素之间非线性相互作用的结果。通常,我们并不掌握影响因素的完整列表的信息,也不知道它们如何相互作用以产生观察到的结果。这些属性使得预测现实世界的事件变得极其困难。ML 社区已经使用两种根本不同的模型构建范例来应对这一挑战。它们是:

  1. 区别的
  2. 生殖的

我们在学校学到的和在新闻中听到的大多数模特都属于歧视型。这个框架的主要焦点是预测的准确性。观察到的数据引导关系发现过程,而不是对因素如何相互作用强加严格的假设。在这种范式下训练的深度神经网络已经在各种各样的任务上取代了人类水平的表现,主要是因为强调预测的准确性。虽然这非常令人印象深刻,但这些模型有其局限性。特别是,高度精确的网络非常复杂,需要大量的训练数据才能达到人类水平的性能。通常,这些模型用可解释性来换取卓越的性能。这个方面有好有坏。

一方面,我们希望对未来有非常准确的预测。精确使我们在面对不确定的结果时能够做好计划并茁壮成长。然而,难以解释的模型招致了很多怀疑,并疏远了人们。这种信任的缺乏缩小了这些强大算法的使用范围。复杂性也让我们很难对未来进行推理。如果我选择路径 A 而不是路径 B 会发生什么?路径 B 比路径 A 短吗?统计学家已经开发了一个广泛的工具包来回答这些问题。在辨别范式下这样做是很棘手的,因为这种思维模式并不试图明确地模拟内在的不确定性。

生成范式正好解决了这一困境。这一学派主张对世界做出假设,而不是回避它。任何上过统计学入门课的人都知道,统计模型允许我们给不确定性一个函数形式。这些模型让我们对自己的预测充满信心。他们让我们假设潜在的结果。诸如此类的活动使我们能够思考未来,并根据新信息做出决策。每个 stats 101 的学生也知道,所有这些模型经常做出严格的假设。有时这些假设被违反,有时它们就是完全错误的。

更糟糕的是,这些模型中的一些并不能很好地近似真实世界的现象。这一缺点主要是由于这些模型不能适应可能影响感兴趣的结果的多个潜在变量。虽然你,读者,现在可能想认输,但我劝你不要。生成模型师也对构建糟糕的世界近似持谨慎态度。然而,与他们的歧视性同行不同,他们融合了计算机科学、统计学和软件工程的概念来解决上述问题。其结果是一类被称为概率图形模型(PGM)的模型。

这些图表允许我们使用尽可能多的变量来模拟我们周围高度复杂的世界。它们让我们将一些、许多或所有这些变量相互联系起来。它们还为我们提供了确定信息如何在网络中流动的灵活性。信息应该从节点 A 传到节点 B 还是从节点 B 传到节点 A?也许我们没有具体说明,因为我们对信号应该如何通过我们的近似世界流动没有强烈的信念。PGM 的强假设允许他们建立稀疏模型。这些假设也使这些网络能够用比判别模型少得多的数据点进行学习。这些特征类似于人类形成一个世界如何运转的心理图像,并对其进行查询以确定如何在不熟悉的环境中行为。

除了建立精确的模型,另一个阻碍 PGMs 广泛应用的挑战是计算。存储大量随机变量的分布并更新它们的分布在计算上是禁止的。这些限制往往是 PGM 如何使用当前的编程语言和数据结构编码的产物。因此,从业者开发了一种新的编程范式,称为概率编程,以规避这些问题。这些语言将随机变量和概率分布视为一等公民。由于这些发展和该领域中一系列相关的发展(例如变分贝叶斯),越来越复杂的 PGM 变得更容易构建。这些创新还减少了查询这些模型和推理潜在行动过程的时间。

近来,生成模型还没有像判别模型那样受到关注。我希望这篇介绍能鼓励你们所有人看看这种不同的思维框架。如果你想更深入地了解这个话题,我强烈建议你去看看一些关于这个话题的精彩文章。

Abdullah FaroukTDS 的志愿编辑助理

概率图形模型介绍

有向图形模型和无向图形模型

布拉尼斯拉夫·霍兰德 — 11 分钟

让你的神经网络说“我不知道”——使用 Pyro 和 PyTorch 的贝叶斯神经网络

当一个人不确定的时候,很大一部分智慧是不行动的

Paras Chopra — 17 分钟

生成性与鉴别性概率图形模型

朴素贝叶斯和逻辑回归的比较

四维引起维克 — 5 分钟

变分贝叶斯:变分自动编码器(VAEs)背后的直觉

了解推动最先进模型的强大理念

安维斯·马尔韦德 — 7 分钟

概率编程简介

使用张量流概率(TFP)的用例

法比亚娜·克莱门特 — 6 分钟

概率推理的基本问题

如果你是机器学习从业者,为什么要关心采样?

作者:Marin Vlastelica pogan ii—6 分钟

我们也感谢最近加入我们的所有伟大的新作家:奥辛·杜塔雷纳托·菲林尼奇奥姆里·卡杜里陈莉莉本·威廉姆斯伊恩·加贝尔乔纳森·拉塞尔森、博士乔安娜·伦丘克恰冲胡曼·阿布·阿尔拉贾 佩德罗·布里托丹尼斯·冯周扬戴夫·德卡里欧阿奇特·亚达夫贾·一禅阿尔帕纳·梅塔拉胡尔·桑戈莱阿南亚·巴塔查里亚罗汉·苏库马兰https://medium.com/u/4e9f21318991?source=post_page-----11a6699e2fac-------------------------------- 杰克·米切尔z·玛利亚·王博士丹尼斯南阮琪·市川林赛·蒙塔纳里戴维斯·特雷比格瓦妮莎·王普亚·阿米尼我们邀请你看看他们的简介,看看他们的工作。

PyTorch 中带深度估计的序列做梦

原文:https://towardsdatascience.com/sequence-dreaming-with-depth-estimation-in-pytorch-d754cba14d30?source=collection_archive---------23-----------------------

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

梦境类:图腾柱+减噪。作者图片

人工艺术合成

虽然“沉睡”仍然是 reddit 上的大炒作,但我决定在连续帧(即视频)的深度做梦背景下,再看看开放性问题。受之前工作的启发,例如这个 Caffe 实现,除了将所有东西集成到最新的 PyTorch 框架中,我还想包含更多关于单类做梦(见我之前的帖子)和深度估计的最新见解。

三轮车系列梦。

你可以在这里找到我的回购(っ◔◡◔)っ♥https://github.com/Beinabih/Pytorch-HeadTrip

与我以前使用的一些类似的代码相比,我的实现大大改善了梦模式的闪烁。这个问题的发生通常是因为光流算法计算的矢量场在变化很小的区域接近于零,这导致了后续帧之间相应的梦内容的较大差异。这可能导致模式以高达每秒帧数的频率变化。我通过将前一个梦的模式扭曲到下一帧,并用流矢量场来参数化更新的强度,来解决这个问题。这种方法可以跟踪场景中运动的物体,还可以平稳地梦到新出现的物体和背景。目前,场景切换仍然必须手动处理,否则结果通常会显示不同场景之间梦境内容的不自然重叠。这个问题将来会得到解决。

在每一步中,使用 Farneback 方法(由 opencv2 提供)或可选的空间金字塔网络 (SPyNet)计算矢量场。为了获得更高的流量预测精度,应该使用 SPyNet。

我的代码可以用 PyTorch 1.8 运行。实现了以下附加功能:

  • 单一阶层做梦
  • 用 Pytorch MiDas 进行深度估计
  • 各种分类模型(resnet、vgg19、inception……)
  • 带 SPyNet 或 Farneback 的光流(opencv2)

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

睡袋海洋与深度估计。作者图片

设置

config 文件夹中提供了一个基本配置文件。它包含了做梦所需的所有参数。

视觉表现

输入图像被二次抽样到更小的分辨率,以便在许多不同的尺度上生成梦的结构。在较高分辨率下做梦会给在较低分辨率下产生的粗糙结构增加细节。参数 num_octavesoctave_scale 表征图像金字塔。 num_iterations 表示网络处理输入的次数。以下是将 num_iterations 或学习率( lr )设置为非常大的值时获得的示例结果:

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

涉及到一些后期处理步骤,如改变颜色和锐化。作者图片

我们可以观察到大量的细节,然而,图像的原始内容已经完全消失了。通过将 random 设置为 True,可以使上述参数随机化。

梦的内容

如果你想对你一直看到的狗的典型眼睛和脸之外的梦的特征有更多的控制,你可以将引导的参数设置为以启用特定类的梦。这是我在之前的帖子中提到过的一个话题。通过将相应的索引添加到 channel_list 中,您可以从该列表中选择并混合任意数量的 ImageNet 类。在下面的示例视频中,我使用了三个类:蘑菇、天鹅绒和雨伞。**

在蘑菇、天鹅绒和雨伞上做梦

相反,如果您希望算法动态选择模型分配最高概率的类别,请将 max_output 设置为 True 。一个实验特性是金字塔 _ 最大值参数,当设置为真时,在每个八度音阶中独立选择最可能的类别。

深度估计

还可以将梦的内容与感知的图像深度联系起来。首先,使用 PyTorch MiDas 模块计算图像的相对逆深度。深度图随后被归一化到区间[0,1]中,用于放大或抑制做梦。通过将使用深度设置为可以激活深度估计。您还可以通过设置 depth_str 为遮罩指定一个倍增强度因子。**

use_threshold 设置为真会将低于阈值 th_val 的所有内容归零。通过更改此参数,可以根据预测深度动态指定排除距离。如果你想排除前景,设置反转深度**

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

前景(左)和背景(右)做梦。作者图片

太棒了。

对于非常大的输入,通过利用兼容硬件上的 Nvidia Apex 模块提供的混合精度算法,还可以减少所需的内存并加快推理速度。好在已经在 PyTorch 中实现了,所以只需要设置 fp16True 即可。

现在发挥创意,制作一些很酷的图片和视频吧!

用递归神经网络进行序列间标记

原文:https://towardsdatascience.com/sequence-to-sequence-labeling-with-recurrent-neural-networks-5405716a2ffa?source=collection_archive---------22-----------------------

编码器-解码器模型

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

莱昂纳多·大久保俊郎在 Unsplash 上的照片

序列到序列的标记问题是通过算法将一个字母表上的序列映射到另一个字母表上的“好”序列。这两个字母可能不同。序列的长度也是如此。这个定义隐含的意思是,有一些方法可以区分好的和坏的映射。

我们来看一些值得注意的例子。

机器翻译:将单词序列从一种自然语言翻译成另一种自然语言。(比如从英语到法语。每种语言的词汇构成了它的字母表。

对话机器人:人类输入一句话或一个问题,机器人会给出合适的回答。在此设置中,输入和输出字母是相同的。人类和机器人“说着同一种语言”。

摘要:输入一个长句、段落或更长的文本,并对其内容进行摘要。

词性标注:输入一种语言(比如英语)的单词序列,输出单词(名词、动词、形容词等)的词性标签序列。

语音识别:输入一系列音素(口语),输出它们所代表的文本序列。

这个标记问题是一个机器学习问题,因为它涉及到预测给定输入序列的输出序列。这是监督学习的一种形式。也就是说,输入和输出都是序列

这个问题难在哪里?

下面我们重点介绍机器翻译。

词汇是巨大的:以英语和法语为例。英语有很多单词。法语也是。哪些英语单词对应哪些法语单词?也就是说,对于那些可绘制地图的人来说。

词汇可能不可映射:两种语言可能如此不同,以至于它们的词汇甚至可能不可映射。也就是说,在一种语言中用一个词就能简明表达的东西,在另一种语言中可能需要用好几个词。

不仅仅是单词:想想短语数据挖掘。它有一个非常具体的含义,来自于两个词数据采矿的接近。(在 NLP 中,这种现象被称为搭配。)显然,我们需要以某种方式捕捉这个意思,这样它就不会在翻译过程中丢失。

这只是冰山一角。更微妙的概念需要更复杂的词语序列来表达。为了让他们不在翻译过程中迷失,我们需要设法抓住他们的本质。

作为监督机器学习

序列到序列标记问题可以被框架化为学习预测给定输入序列的输出序列。虽然这种提法在原则上听起来很吸引人,但还是有一些关键的考虑因素。

其中最重要的是,我们是否有足够丰富和多样化的标记训练集可用。这种训练集采取(输入序列输出序列对)的形式。

“足够富裕”的富裕程度取决于我们试图解决的问题的复杂程度。学习一个通用的英语到法语的翻译可能需要比学习回答一个受限领域的问题更广泛的训练集,比如一个机器人来回答关于一个特定产品的问题。

接下来,我们应该考虑哪些机器学习算法?嗯,这不是监督学习吗?所以就不能随便用什么学习算法吗?不。输入和输出是序列。长短不一。经常在巨大的字母表上。因此,输入和输出空间的宇宙是巨大的。

幸运的是,我们有递归神经网络(RNNs),它是为这类问题设计的。(尽管是受约束的版本;见下文。)它们输入一个序列,输出另一个序列。它们从(输入序列,输出序列)对的训练集中学习。

约束是什么?输入和输出序列的长度必须相同。当输入序列中的第 I 个输入出现时,必须产生输出序列中的第 I 个输出。我们可以说输入和输出序列是对齐的。

词性标注用例遵守这一约束。输入序列中的每个单词在输出序列中都有一个与之相关联的词性标签。一个单词的 POS 标签可能依赖于序列中的一些其他单词以及它们出现的顺序,这就是为什么我们将此建模为序列到序列的标注问题。

机器翻译用例通常不会。根据语言和源序列中的具体内容,源序列和目标序列的长度可能会有所不同。用源语言表达某件事可能比用目标语言要用更多(或更少)的单词。

文本摘要用例肯定不会。

递归神经网络和神经语言模型

让我们从比对序列的简单例子开始。有两个原因。首先,如前所述,递归神经网络精确地模拟了这种情况。其次,这种简单情况的解决方案将作为更高级情况的构建模块,在这种情况下,输入和输出序列具有不同的长度。

有一篇中篇文章非常详细地介绍了这种(更简单的)情况[1]。这里我们只总结关键概念。

语言模型:在 NLP 中,这是记号字母表上序列的概率分布。语言建模的一个中心问题是从例子中学习语言模型。(例如来自句子训练集的英语句子模型。)学习的模型然后可以用于预测给定记号序列的下一个记号。正如[1]中所讨论的,语言模型有许多用途。

递归神经网络:这是一个神经网络,输入一个向量序列 x (1),…, x (T),输出一个相应的输出向量序列 y (1),…, y (T)。为了输出 y ( t ),在任何时候 t ,RNN 使用它能够从序列 x (1)、…、 x ( t )中学习和捕捉到的任何东西。正是这种能力让它变得如此强大——也相当复杂。与前馈神经网络形成对比,前馈神经网络仅从 x ( t )产生 y ( t )。

那么我们如何从向量x(1)…, x ( t )的序列中预测 y ( t )?很自然的一件事就是把 x (1)、…、 x ( t )中的信息汇总成一个定长向量,称之为 h ( t ),然后从 h ( t )预测 y ( t )。

可以,但是我们如何从 x (1),…, x ( t )中获得 h ( t )?这就是循环出现的原因。假设我们要从x(1)…, x ( t +1)预测 y ( t +1),就在我们从x(1)…, x ( t 预测完 y ( t )之后。在后面的预测中,我们使用了 h ( t )。首先我们从 h (t)和 x ( t +1)计算 h ( t +1)。于是,h( t +1)总结了 x (1)、…、 x ( t +1)中的相关信息。接下来,我们像之前一样从 h ( t +1)计算 y ( t +1)。

语言模型的 RNN:这里 x ( t )是语言字母表中某个符号的矢量编码。这代表语言中相应序列中位置 t 处的符号。我们的兴趣是从 x (1),…, x (T)预测 x (T+1)。对于这个预测任务,将目标 y ( t )定义为 x ( t +1)是有意义的。

现在让我们详细说明“语言字母表中某个符号的矢量编码”。主要有两条路可走:一热编码和分布式编码。在一键编码中,字母表中的每个符号都有一个维度。符号由一个向量表示,该向量在符号维度中的值为 1,在其余维度中的值为 0。在分布式编码(也称为嵌入)中,符号被投影到一个低得多的维度空间中,使得出现在相似上下文中的符号在该空间中彼此靠近。当字母表是一种语言的词典,即它的单词集时,这一点得到了最好的说明。人们会认为同义词的嵌入是相互靠近的。

在语言模型的 RNN 中,输出通常是独热编码。这是因为我们的主要兴趣是从 x (1),…, x (T)预测 x (T+1),这自然表示为

arg max _ s P(x(T+1)=编码(s) | x (1),…, x (T))

其中 s 表示字母表中的符号。因此,我们需要一种方法,能够为字母表中的每个符号分配成为序列中下一个符号的概率。

相比之下,输入原则上可以是一次性编码或分布式编码。由于输入维数很高,一键编码将使 RNN 在大字母表上具有更高的容量。(这可能是好的或坏的,取决于问题和训练集。)分布式编码在某种程度上增加了学习问题的难度。另一方面,人们可以利用来自预训练模型的嵌入来解决某些问题(例如对英语的语言建模),这可以产生改进的泛化。

学习

我们在这篇文章中涉及这个主题,因为它将为我们提供一种训练编码器-解码器模型的编码器组件的方法:作为源语言的语言模型。

RNN 的状态变化和状态到输出的行为都可以从一组(输入序列输出序列)对的训练集中自动学习。

我们将在这里描述高层次的学习。如需更深入的了解,请参见[1]。那些已经知道如何在 RNN 学习的人可以跳过这一步。

考虑当 RNN 在时间 t 接收输入向量 x ( t )时会发生什么。首先,从该输入和 h ( t -1)导出新的状态向量 h ( t )。接下来,从 h ( t )导出 RNN 的输出向量 yhat ( t )。

现在到了学习的部分。我们首先将输出向量与目标向量进行比较,即 yhat ( t )到 y ( t )。任何差异都会推动学习。首先,我们尝试修改状态到输出函数的可学习参数,以尝试使输出向量更接近目标向量。接下来,我们尝试修改状态转移函数的参数,以尝试将状态向量移动到更接近一个状态,从该状态产生的输出向量更接近目标向量。通常,对状态输出函数的参数和状态转移函数的参数的修改是独立完成的。就好像我们保持其中一个不变,而改变另一个,以使输出更接近目标。

事实上,还有更多。它与嵌入在状态转移函数中的递归有关。在这一点上,引入一些正式的概念和符号将有助于阐述。这将有助于我们涵盖“更多”的部分,也使前一段的讨论更加具体。

h(t)=f(h(t-1), x ( t ))。这里的 f 是输入当前状态向量 h ( t -1)和下一个输入向量 x ( t )产生下一个状态向量 h ( t )的状态转移函数。

y(t)=g(h(t))。这里 g 是将当前状态向量 h ( t )映射到输出向量 y ( t )的输出函数。

为了有个感觉,考虑在时间 T 产生目标向量 y (T),作为输入向量序列 x (1)、 x (2)、…、 x (T)的函数。任何一个输入向量 x ( t ),1 < = t < = T,都可能影响 y (T)。为了能够了解这种影响,首先,让我们及时展开 RNN 中的计算。从接收 x (1)一直到产生输出向量 yhat ( t )。

我们得到了

**h**(1) = **f**(**h**(0), **x**(1))
**h**(2) = **f**(**h**(1), **x**(2))
…
**h**(T) = **f**(**h**(T-1),**x**(T))
**yhat**(T) = **g**(**h**(T))

好的,那么让我们开始讨论从零开始的学习。首先,我们尝试修改 g 以便将 yhat (T)移近 y (T)。注意改变 g 可以改变 yhat (T)。接下来,我们尝试修改 f ,使yhat(T)=g(f(h(T-1), x (T))向 y (T)靠拢。注意,当考虑改变 f 时,我们保持 gh (T-1)和 x (T)不变。接下来,我们尝试修改 f ,使yhat(T)=g(f(f(h(T-2),x(T-1)), x (T))向 y (T)靠拢。我们用斜体显示了对 f 的调用,我们试图修改其行为。

诸如此类,将学习延伸到更早的时间…

例子:这将更具体地说明学习。(尽管这是一个玩具,基本上没什么用。)

假设我们希望 y(T)等于 x(1) + x(2) + … + x(T)。也就是说,我们只是试图让 RNN 学会如何维持一个运行总和。输入和输出都是一维的。

假设我们的 RNN 结构如下:

*f*(*h*,x) = *ah* + *bx*
*g*(*h*)   = *ch*

f 是具有可学习参数 ab 的状态转移函数。 g 是带有可学习参数 c 的输出函数。

比方说对于a=b=c= 2 我们给出输入序列( x 1=1, x 2=2, x 3=3)想学习 y 3=1+2+3=6。假设我们开始处理输入,0 = 0。

*h*1 = 2*h*0 + 2*x*1 = 2*0 + 2*1 = 2
*h*2 = 2*h*1 + 2*x*2 = 2*2 + 2*2 = 8
*h*3 = 2*h*2 + 2*x*3 = 2*8 + 2*3 = 22
*yhat*3 = 2*22 = 44

y 3 是 6,远小于 yhat 3。我们当然可以将 c 减少到 yhat 等于 6。具体来说,我们可以将 c 设置为 3/22。一般来说,这不是一件好事。我们正在对一个单一的可学习参数进行彻底的改变,使它产生我们想要的结果。这种剧烈的变化倾向于追逐最新的例子,可能会抹去以前的学习。

更好的做法是循序渐进。到底有多缓慢?这很难量化。尽管如此,引入一个参数来控制学习速度还是有意义的。其实这个参数就是所谓的学习率

好了,回到完成我们的例子。我们只是学得慢一点。我们先把 c 降低一点,比如说 1.5。这给了我们重新想象的 yhat 3 是 33。我们向 y 轴 3 靠近。

接下来我们来看看 h 3,等于 22。如果我们能够降低 h 3,我们将从当前值 44 降低 yhat 3。(之所以是 44,是因为我们在计算 h 3 对 yhat 3 的影响时,还在使用旧值 c 。)那么我们如何降低 h 3 呢?通过减少 a 或减少 b 。我们会双管齐下——将它们分别从降低到 1.5。好吧,我们现在有什么。

*h*3 = 1.5*8 + 1.5*3 = 16.5
*yhat*3 = 2*16.5 = 33

很好,这也让 yhat 3 更靠近 y 3。

同样,我们可以更进一步回到过去。尝试降低 h 2。在这一点上,中间计算变得更加复杂,对我们的符号进行一些改进将会有所帮助。让我们将 h 的计算表示为

*h*(*i*) = *a*(i)**h*(*i*-1) + *b*(*i*)**x*(*i*)

这将让我们跟踪当我们改变 a ( i )和 b ( i )时 h ( i )发生了什么。在一次学习迭代结束时,我们必须以某种方式确保所有的 a ( i )和所有的 b ( i )都具有相同的最终值。稍后会详细介绍。

由于其当前值 h 2 = 8, yhat 3 为 44。假设我们将 a 2 和 b 2 也降低到各 1.5。我们得到了

*h*2    = 1.5*2+1.5*2=6
*h*3    = 2*h*2 + 2*x*3 = 2*6 + 2*3 = 18
*yhat*3 = 2*18 = 36

yhat 3 再次靠近 y 3。

等等,我们继续回到过去…

好了,现在我们有了新的值new(I)和 bnew (i)用于各种 i 的。但实际上,我们只有两个参数 ab 。所以我们必须以某种方式有意义地将所有的 ( i )聚合成一个单一的 a ,并将所有的b 新 ( i )聚合成一个单一的 b 。一个自然的选择是将 ab 分别设置为所有new(I)和所有 bnew ( i )的平均值。

推论

训练有素的 RNN 能做出什么样的推论?涉及到什么?我们来说明一下语言建模设置中的思路。我们在这里讨论这个主题,因为它将在编码器-解码器模型的解码阶段发挥作用。

我们可以通过训练有素的 RNN 运行一系列单词 w 1、 w2 、…、 wn -1,并生成下一个可能单词的概率分布。有时候我们想要的不止这些。我们想要下一个 k 最有可能的单词。也就是说,我们想要

*wn*, *wn*+1, …, *wn*+*k*-1` = argmax *wn*, *wn*+1, …, *wn*+*k*-1` *P*(*wn*, *wn*+1, …, *wn*+*k*-1 | *w*1, *w2*, …, *wn*-1)

这个推理问题叫做解码问题。一般来说比较棘手,所以我们寻求启发式的解决方案。

贪婪解码:寻找下一个单词的最佳候选,将该单词追加到序列中,并继续下去,直到追加了 k 个单词。不能保证找到长度 k 的最佳扩展,因为它会在整个过程中做出局部最优决策。随后的决定取决于这些。

波束搜索:在贪婪解码中,任何时候,只有一个序列被扩展。波束搜索通过跟踪到目前为止的最佳扩展对其进行了改进,其中 m 是一个自由参数。(在贪婪解码中 m 为 1。)

更准确地说,波束搜索保留了 m 个最佳前缀序列。在每一次迭代中,它考虑这些 m 前缀的所有可能的 1 步扩展,计算它们的概率,并形成迄今为止的 m 最佳前缀序列的新列表。它一直持续下去,直到 m 延长部分达到所需长度。然后,它取出这些 m 扩展中得分最高的作为最终答案。

这里有一个例子来说明进行波束搜索的价值。考虑一个重复的组织名称列表。我们试图找到最受欢迎的组织名称。假设由于某种原因,我们不能(或选择不)保持每个组织名称在列表中出现的次数。(可能是截然不同的名字太多了。)

贪婪的方法可以从列表中最常出现的单词开始,并尝试扩展它。它选择银行作为起点似乎是合理的,因为有很多银行。现在想象一下,某个非银行组织比任何特定的银行都受欢迎。想到了谷歌。贪婪的方法永远找不到它,因为它被委托给银行。Beam search 有机会找到 Google,因为它为可能的扩展保留了多个候选项。

编解码器型号

考虑机器翻译。我们希望将特定源语言(比如英语)中的一系列单词翻译成特定目标语言(比如法语)。输入和输出序列可以具有不同的长度。如前所述,在这种情况下,不清楚如何使用 RNNs。

考虑一个两阶段的过程。在第一阶段,称为编码器,输入序列(英语句子)被转换成固定长度的数字向量。在第二阶段,称为解码器,向量被转换成合适的输出序列(法语翻译)。

我们可以把这个两阶段过程看作首先从英语句子中提取合适的特征,然后把得到的特征向量转换成输出序列。这不仅规避了对准约束;直觉上,它似乎更丰富。原则上,研究一个包含丰富特征的空间比研究一个单词序列要好。

解码(即翻译)过程直到源序列被完全编码后才开始。

在有限范围的机器翻译实例中,我们可能会从使用人工设计的功能中获益。这当然不是一个通用的解决方案,而且可能无法(在翻译质量上)有效地翻译源语言中任何看似合理的句子。

所以我们想从训练数据中学习编码器。一旦我们描述了端到端系统,即解码器,我们将深入学习。

解码器

这是另一个 RNN,就像编码器一样。那么翻译序列是如何从源序列的编码中生成的呢?我们将解码器的初始状态设置为编码器的最终状态,即源序列的编码状态。然后,我们使用这个 RNN 作为生成器,迭代地生成翻译序列中的下一个标记。下一个令牌可能是使用贪婪解码或波束解码生成的,这是我们之前讨论过的主题。

可以把解码器 RNN 看作是以源序列编码为条件的目标语言的语言模型。源序列的良好翻译具有高概率;可怜的低。

注意,“好的翻译”的一个方面是合理地安排翻译的顺序。作为一个想象的例子,假设我们想把猫很小翻译成法语。我们可以想象编码以某种方式捕获了关键方面:对象= ,属性= 。翻译可能会被解释为用法语表达成一个结构良好的句子。le chat est petit 是个不错的翻译。(有趣的是,作为旁注,当我们在中输入 est petit le chat 时,谷歌将翻译成法语并要求其翻译成英语,我们得到的是猫很小。)也就是 Google translate 对翻译后的序列进行了合理的排序。

更多这种类型的例子见[2]。

培训概述

在本节中,我们将对培训进行概述。我们首先讨论一种将训练分解成两部分的方法:训练编码器和训练解码器。这种方法有其局限性。然而,它也有一些潜在的好处。这也有助于教学目的。这有助于我们轻松进入联合培训讨论。

训练编码器

这里我们考虑将编码器作为源语言上的语言模型来训练。潜在的缺点是,整个系统没有进行端到端的训练,因此不会捕获源序列和其目标序列之间的相互作用。潜在的好处是简化了编码器培训。很容易得到一组丰富的源序列。第二个潜在的好处是,原则上可以使用同一个经过训练的编码器将源语言翻译成任何目标语言。

那么我们如何在源语言的一组序列上训练编码器呢?由于编码器是一个 RNN,训练它的自然方法是教它预测序列中的每个符号,来自它前面的序列前缀的符号。我们在学习一节中详细讨论了这一点。

训练解码器

解码器可以被类似地训练,因为它也实现语言模型。也就是说,语言模型取决于源编码。让我们来描述一下这是如何发挥作用的。

考虑一对( ST )。 S 是源序列。 T 是与之配对的目标序列。我们假设编码器已经被训练过。我们通过编码器运行 S 得到它的编码 E ( S )。我们将解码器 RNN 的状态初始化为这种编码。然后,我们教解码器为 S 中的每个符号预测其左侧子序列中的符号。

联合训练

这从一组( ST )对中联合训练编码器和解码器。从直观的角度来看,工作原理如下。我们将 S 呈现给编码器。编码器输出 E ( S )。这可能是 S 的一个好的编码,也可能不是,这取决于编码器训练的当前状态。

使用该编码作为输入,解码器产生预测的目标序列*。**即*的质量取决于解码器在其当前状态下的有效性,以及编码器(在其当前状态下)产生的编码 E ( S )的质量。因此,和 T 之间的差异驱动解码器和编码器的学习。

可以把这想象成误差从解码器的输出一直反向传播到编码器的输入,就像一个长长的多层网络。因此,解码器和编码器的参数都可能改变。

为了简单起见。我们已经把在一个实例上的学习( ST )描述为一次性过程。也就是说,首先 S 被完全输入,其编码被产生,该编码被完全解码,然后预测的目标序列和解码之间的差异驱动学习。

原则上,我们也可以考虑这种一次性过程的顺序变体。这可以看作是对( SiTi )的训练,其中 SiTi 分别表示 STi th 前缀。

这可能有助于将编码器-解码器组合视为单个 RNN,它在 S + T 上学习语言模型,其中+表示连接。在这个 RNN 中,使用编码器的参数预测 S 中的下一个符号,使用解码器的参数预测 T 中的下一个符号。以这种方式思考,我们还可以看到,当下一个符号仍在 S 内时,训练仅在编码器的参数上发生,其行为就好像编码器正在学习源语言的语言模型。也就是说,这种训练与调整编码器和解码器的参数的训练混合在一起。当要预测的下一个符号在 T 中时会发生这种情况。

反向编码器

在[4]中,发现颠倒源序列(但不是目标序列)产生更准确的翻译。这背后的直觉适用于翻译问题,其中源语言和目标语言中的句子具有相同的词序,例如从左到右。反转过程使源序列中的开始符号更接近它们在目标序列中的翻译。这似乎简化了这些部分的学习,这可能也有雪球效应。

参考文献

  1. 神经语言模型|作者 Arun Jagota
  2. CS 224d:NLP 的深度学习
  3. https://arxiv.org/pdf/1406.1078.pdf
  4. https://arxiv.org/abs/1409.3215用神经网络进行序列对序列学习 — Stutskever 等。

Python 和 R 语言的数据科学和数据分析系列项目

原文:https://towardsdatascience.com/series-of-projects-on-data-science-and-data-analytics-in-both-python-and-r-76db3fea9b7e?source=collection_archive---------13-----------------------

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

Fab LentzUnsplash 上拍摄的照片

探索性数据分析、机器学习、自然语言处理和计算机视觉项目

最好的学习方法就是做项目。特别是对于自学者来说,他们学习了一些编程和数据科学工具,并想知道接下来会发生什么。我建议,开始做一些自己的项目。那是最好的学习方法。

此外,对于一个没有行业经验的初学者来说,一些实践项目可以制作一个很好的投资组合。但是对于一个初学者来说,可能很难想到一个好的项目想法。在那种情况下,这篇文章可能会有帮助。在这里,我正在编译一些不同类型的项目,从探索性数据分析、机器学习和深度学习开始。你会发现一些使用 scikit-learn、stats model 或 Tensorflow 库的机器学习项目,以及一些从头开发的机器学习项目。

所有这些文章都是很好的学习资源!大部分都是对某个话题非常详细的讨论。您会发现 Python 和 r 中的项目。

随着时间的推移,我不得不为我的课程、我自己的实践和博客做相当多的项目。我把其中一些放在这里。我唯一的建议是,请带着数据集或想法,想出自己的项目。因为那会帮助你成长。

我将从简单的探索性数据分析项目开始,然后转向一些更深入的领域。让我们开始:

该项目利用 python 的 Pandas、Matplotlib 和 Seaborn 库进行数据分析和可视化,并利用 scikit-learn 库中的模型进行预测。

这是一个使用 scikit-learn 库的简单 KNN 分类器。因为它是一个教程,所以可能有点过于描述和冗长。但它使用了 Kaggle 的大型数据集,并开发了分类器。

一个简单的探索性数据分析,适合初学者:

这是 r 中的一个探索性数据分析项目。

特征选择是机器学习最重要的部分之一。本文用 python 实现了 4 种不同的特征选择方法。

R 用户的另一个项目。这一篇着重于线性回归及其在 r 中的详细分析。

本文详细讨论了 logistic 回归,并用 r。

https://medium.com/codex/complete-details-of-simple-logistic-regression-model-and-inference-in-r-eedb1c84b65f

本文使用了一个真实的数据集,并对其进行了方差分析和协方差分析,同时给出了详细的解释。所以,如果这个话题对你来说是新的,这可能是一个很好的学习资源。

https://pub.towardsai.net/dissecting-1-way-anova-and-ancova-with-examples-in-r-a3a7da83d742

这个项目又是关于 python 中的逻辑回归。但是它使用 statsmodel 库。您可以使用简单的代码获得变量之间的相关性、p 值、z 值、置信区间的详细信息。

这也是一个逻辑回归项目。但它是在 R 编程语言中。这个项目非常详细,在一篇文章中涵盖了很多主题,你可以从下面的标题和副标题中看到。

上面关于逻辑回归的项目使用了一个库来完成这个项目。但是在这个项目中,逻辑回归是从零开始发展的。

这是另一个从零开始开发的逻辑回归教程和项目。因为逻辑回归是最流行和最简单的分类器之一,所以学好它并不是一个坏主意。这是一个多类分类器,与从零开始开发的简单逻辑回归略有不同。如果你是初学者,这看起来可能有点复杂。

NLP 项目

这个项目使用非常流行和易于使用的库,如 sklearn,来进行情感分析。

另一个简单的 NLP 项目,查找文本之间的相似性并返回相似的文本。

https://pub.towardsai.net/similar-texts-search-in-python-with-a-few-lines-of-code-an-nlp-project-9ace2861d261

这个项目侧重于文本数据的分析和可视化,以及使用文本数据的情感分析。

[## 文本数据的探索性数据分析,包括可视化和情感分析

towardsdatascience.com](/exploratory-data-analysis-of-text-data-including-visualization-and-sentiment-analysis-e46dda3dd260)

这个项目是关于一个分类文本文件的分类器。

这是另一个使用 Keras 和 Tensorflow 的情感分析项目。

计算机视觉

几个简单的图像分类问题?

这不是一个直接的计算机视觉问题。但是这个 K 表示从零开始开发的聚类算法,并显示了在图像修改中使用的示例。

又是逻辑回归。但这一次,逻辑回归将表现得像一种深度学习算法。它将在逻辑回归中从头开始执行图像分类。

另一个图像分类问题使用从零开始开发的神经网络。

结论

外面有很多资源。但我试图编译所有这些项目,不仅包括代码,还提供详细的解释。我认为,对于那些试图同时学习或建立简历的人来说,这是一个很好的资源。我可能会在未来添加更多的项目到这个页面。希望这有所帮助!

欢迎在推特上关注我,喜欢我的 T2 脸书页面。

如何用例子处理大数据:MapReduce

原文:https://towardsdatascience.com/series-on-distributed-computing-1-mapreduce-fcc3cc2dfb5?source=collection_archive---------34-----------------------

理解大数据

简单解释如何运行并行工作负载来处理大数据

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

我决定写一个关于分布式计算的系列,一个关于我们在哪里成功地正确处理大数据的历史回顾,以及它是如何演变的。处理大文件的挑战是,我们在分布式机器上运行的计算必须在合理的时间内完成,这带来了一些问题:我们如何进行令人尴尬的并行计算,如何 分发数据 ,以及我们如何处理故障。2004 年,谷歌共享了 MapReduce 框架,在平均运行 10 万个 MapReduce 任务 4 年后,每天处理大约 2004 的数据。

他们实现的是将流程与 Map 任务解耦,在 Map 任务中他们可以并行处理输入,并减少任务,在 master 中他们可以对分类和分组的数据进行聚合,master 跟踪工人的健康状况,任务的完成和在故障机器上重新执行任务允许 容错

通过一个简单的伪代码,该映射获取一个键/值输入对,并独立于原始输入计算另一个键/值对。reduce 使用键,将所有值从 map 函数中分离出来,进行排序/分组,以便对其运行聚合功能。输出通常是一个输出值。

地图(k1,v1) →列表(k2,v2)

减少(k2,列表(v2)) →列表(v2)

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

初始执行

让我们考虑一个简单的用例“单词计数”,我们试图找出每个单词出现的次数。在这个场景中,用户程序将输入文件分成 M 对。如果输入是一个语料库,则每个拆分将是一个文档,如果输入是一个文档,则每个拆分将是一行,依此类推……此外,它还会旋转多个 workers,其中一个是主节点。

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

主选择地图/减少任务

主节点负责分配工作人员来映射和减少任务,并检查健康检查(通过 ping)。如果任何工人在该时间范围内没有响应,master 会将他们标记为失败,并重新安排这些工人正在进行的任务,并且所有 map 任务作为机器上的输出数据都会丢失。

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

地图工作者处理的分割输入文件

分配给 map 函数的工人读取拆分对,并将中间的键/值对保存到其磁盘(首先向缓冲区和分区函数写入磁盘,但是为了不被分散注意力,我们跳过)。这在当时是开创性的,因为地图工作者在 中令人尴尬的做了这些 并行 导致了大型商用电脑集群的高性能。

MapReduce 提供 局部优化, 因为它使用 GFS,master 向 GFS 请求输入文件块的位置,并在同一台机器或同一机架上调度映射任务,这允许数千台机器以本地磁盘速度读取输入,并且没有交换机机架,受读取速率的限制

问题是我们负责编写 map 和 reduce 函数,所以让我们看看如果我们用 Python 编写的话会做些什么。最初的文章/实现是在 C++上,我将使用 Python 来保持简单。如果您想了解更多信息,我在参考资料部分分享了许多实现方法:

现在,所有的中间键/值对都被保存了,分区函数将它们放到磁盘上,reduce 任务的一部分是对单词进行排序和分组。 Reduce 函数将采用唯一键和分组值列表,通过为全局输出追加每个输出来计算计数的总和。如果要求我们找出给定城市列表的最高温度,我们将对 Reduce 函数进行最大聚合。

如果 reduce 工作线程失败,主线程不会请求重新执行,因为输出是全局共享的。

我们完整的功能(在 mrjob 模块的帮助下)如下所示。Mrjob 模块几乎可以运行任何本地和云 Hadoop 集群。(PS:如果你更喜欢用 go, gossamr repo 可能有用)

如果我们检查我们的完整示例,我们将获得每个单词的出现次数,并将其保存在一个全局可访问的位置。谷歌的论文基于 2000 台工作机、5000 个分区和 200,000 个分割,其中他们选择每个分割大约 16MB 到 64MB。

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

聚合的 reduce worker 导致唯一关键字的值

输入文件或键/值对不同于中介以及输出键/值对,我们无法预测何时处理数 Pb 的数据。

后续步骤

它是第一个能够利用本地文件系统执行并行任务的抽象。接下来,受 MapReduce 编程模型的启发,2006 年的 Hadoop 由雅虎推出,云提供商也不吝推广 Hadoop-on-cloud 工具,即 Google 实现为 Dataproc ,AWS 实现为 EMR (弹性 MapReduce),Azure 实现为 HDInsights

号令:

所以,我们来反思一下 bak。问题是,对于这个简单的问题,你会如何改进谷歌找到的解决方案?如果您想处理重复执行,您将如何处理在 map 阶段结束时拆分的文件?你如何让软件开发人员更容易以更抽象的方式编写 map/reduce 函数?

直到下一个,保重!

参考文献:

*https://research.google/pubs/pub62/ https://learning.oreilly.com/videos/taming-big-data/9781787125568/9781787125568-video1_2

迈克尔·诺尔的博客文章*

使用 Jupyter 笔记本进行严肃的软件开发

原文:https://towardsdatascience.com/serious-software-development-using-jupyter-notebooks-95f84f4d8ef8?source=collection_archive---------24-----------------------

使用 nbdev 通过 Jupyter 笔记本构建 Python 包

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

肖恩·林在 Unsplash 上的照片

介绍

下图来自一个名为 fastcore 的库的文档页面。

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

它有源代码超链接,所以你可以很容易地检查实现,它有一个小的 pargraph 解释什么功能,它有测试,所以你可以验证函数的行为。

与常规的 Github 存储库相比,它只有部分文档或者没有文档,没有可供跳转的超链接,测试存在于单独的文件夹中,您已经可以看出哪种方法更好。

是的,你可以有变通办法,但没有什么比得上我将要向你展示的。

文化编程

早在 1983 年,Donald Knuth 就设想了一种叫做文化编程的编程风格。在这种编程风格中,你不再按照计算机强加的方式和顺序编写计算机程序,而是使程序员能够按照他们思维的逻辑和流程所要求的顺序开发程序。

来源:https://en.wikipedia.org/wiki/Literate_programming

捕捉这种编程风格的最佳环境是 Jupyter 笔记本。你可以处理一些代码,拼出你的想法,当你满意时,把它们放在一起。它们非常适合迭代的、实验性的编程风格。

然而,直到最近,Jupyter 笔记本还缺乏许多构建软件的附加功能。它缺乏相关的组件,当这些组件放在一起时,无法使 Jupyter 成为一个真正有文化的编程环境。

介绍, nbdev

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

nbdev

nbdev 是一个由 fastai 开发的库,只使用笔记本就可以开发 Python 包。我不打算给你一个特性的概要,因为我想让你仔细阅读并找出所有细节。我也没有做代码遍历,因为 fastai 的网站上已经有了一个非常好的教程,所以重复相同的步骤没有意义。

这篇文章的目标是向你介绍这个世界,一个你不知道存在的世界,让你爱上它,让你在下一个项目中使用它。

它是如何工作的?

让我们先来看看 nbdev 是如何工作的。因为我不做代码 walthru,我们将浏览已经使用 nbdev 构建的库的源代码,这个库被称为 fastcore

如果你去 fastcore 的 Github 页面,你会看到它有一个名为 nbs 的文件夹,顾名思义,里面包含了一堆笔记本。

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

每个笔记本代表我们正在构建的包的一个模块。例如 00_test.ipynb 将被转换成一个名为 test.py 的模块。

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

我们软件包的用户可以如下使用它:

from fastcore.test import *

从笔记本到.py文件的转换是在一个名为notebook2script()的函数的帮助下完成的,这个函数在每个笔记本的末尾执行。

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

如果你打开其中一个笔记本,你会发现它看起来就像普通的 Jupyter 笔记本,除了一些东西。

您首先会注意到在某些单元格的开头有一串#export

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

【nbdev 如何确定哪些细胞将成为模块的一部分。根据上面的代码,单元格[1] 将进入 test.py ,但单元格[2]不会。

然而,单元格[2]将成为本模块文档的一部分。

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

这是我最喜欢的部分。你在笔记本上写的任何代码和解释都会自动转换成文档。你不需要在它上面花费任何额外的时间。此外,我们能够在源代码下面编写测试,并且它们也成为文档的一部分,这是一个巨大的好处。

传统 Python 测试模块的情况是,测试存在于不同的文件夹中。这使得识别哪个测试与哪个功能相关变得困难。当你修改源代码时,很难修改相关的测试,因为它们不在你的眼前。

Nbdev 为你解决了这两个问题。另外,任何阅读你的代码的人也可以看到测试是如何设计的,并获得更丰富的学习经验。

最后,请注意,在我们的 markdown 中的backticks中的关键字是在代码库中搜索的,如果找到,也是超链接的(参见上图中的 test_eq_type)。这真是不可思议。当开发软件时,自动化平凡的任务只是将更多的创造力放在你的手中。

nbdev 的特点

现在让我们看看 nbdev 的特性列表,我可以给你一个每个特性的简单解释

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

  • 自动生成单据

这个我已经解释过了。

  • 自动发布到 PyPI 和 conda 包的实用程序

无论何时做pip install bla,bla 必须存在于 Python 包索引(PyPI)上。康达也是如此。发布到 PyPI 需要你以某种方式打包你的项目并创建一堆文件。Nbdev 通过自动化任务和提供实用程序来帮助您轻松发布,使这一过程变得非常简单。

  • 笔记本和源代码之间的双向同步

ide 对于很多任务都很有用,例如,它们提供了更好的调试工具。使用 nbdev,您可以编辑源代码(。py 文件),这些更改将反映在您的笔记本中。这允许你使用两种媒体的最佳功能。

  • 对隐藏/显示单元格的细粒度控制

完整的 Jupyter 笔记本会转换为文档,但如果您愿意,可以隐藏某些单元格。就像#export一样,nbdev 包含一个#hide关键字。将它放在任何单元格的顶部,它就不会出现在生成的文档中。

  • 直接在笔记本上写测试

我提到过您可以这样做,但是我提到过您可以像使用 pytest 一样通过 CLI 运行这些测试吗?如果你不想每次都运行长时间的,你也可以将它们分组。

  • 合并/冲突解决

Jupyter 笔记本的一个问题是版本控制不太好用。Git 经常给出合并冲突,Github 的 visual diff 显示 Jupyter 笔记本底层 json 的变化,而不是实际的单元格变化。这很烦人。好吧,让 nbdev 帮你处理。它清理笔记本,以避免这些冲突,如果它们确实发生了,给你一个人可读的格式的错误。

Github Actions 允许您自动执行工作流程,比如当您推动新的变更、创建新的问题或提交 PR 时会发生什么。nbdev 为您设置此功能,无需任何手动干预。

  • 降价的所有功能

现在我们使用 Markdown 进行文档记录,我们可以很容易地包含图像、格式化文本甚至数学方程。

  • …还有更多

在这一点上,我建议你浏览一下教程,了解更多让你兴奋的部分。

为什么是这个标题?

Joel Grus 有一个非常著名的演讲叫做“我不喜欢笔记本”。Joel 是一个优秀的演示者,他的演讲非常有趣,但它不鼓励人们使用笔记本进行严肃的开发。

现在,这个话题真的很老了,一些现在存在的东西,在当时是不存在的。但是,在专业人士中仍然有一个普遍的共识,Jupyter 笔记本只是用于实验,如果你想编写将被部署的严肃软件,你必须使用 ide。现在不再是这样了。

通过这篇文章,我希望能改变这种情况。希望你给这个彼岸一个尝试,希望更多的人用 Jupyter 笔记本做正经的软件开发。

~快乐学习。

无服务器的采用:成本仍然是主要因素吗?

原文:https://towardsdatascience.com/serverless-adoption-is-cost-still-the-main-factor-c5e910cf8b12?source=collection_archive---------41-----------------------

对无服务器的低成本认知正在改变吗?如果有,原因是什么?

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

基础图像来源: pixabay

按使用付费 是许多组织采用无服务器的主要驱动因素。在给定的前提下,每个人使用无服务器的动机都是为了降低运营成本。几乎每个无服务器成功案例都与成本因素有关。

错误的成本比较

我曾经比较过 EC2 实例和 Lambda 函数的成本。刚开始还挺有意思的。

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

来源:https://www.prerender.cloud/

很快我意识到这是误导。我就是觉得不对劲。我认为我对服务器和无服务器都不公平。

  • 我在比较裸机吗?
  • 我考虑过那些在 EC2 上运行的应用程序的许可费吗?
  • 第二个可用性区域中 EC2 实例的成本如何?
  • 无服务器不仅仅是 Lambda 函数。我增加了其他服务的成本吗?
  • 我如何解释混合情况下的成本?

诸如此类的问题迫使我永远停止玩数字游戏。

每个功能的成本估计

现在,我已经形成了无服务器优先的思维模式。我没有浪费时间比较苹果和橘子,而是将注意力转向根据应用程序的高级架构来估计它们的成本。虽然不准确,但这让我对我们正在构建的那些功能的成本有了深入的了解。

作为一名工程师,这无疑帮助我了解了无服务器成本的影响因素。重要的是,它允许我与业务利益相关者分享这些数字。在我们推进无服务器的过程中,拥有成本可见性被证明是很有价值的。

这种方法也有它的挑战。

  • 对于复杂的架构,评估变得很困难
  • 适应不可预测的交通高峰的影响被证明是困难的
  • 将间接成本(如 CloudWatch 指标)相加是很棘手的

然而,它提高了团队中无服务器成本的意识,这对于开发无服务器解决方案的每个人来说都是至关重要的。即使有一些误差,这些数字也符合每个人对无服务器的低成本预期。

那么低成本到底有多低将成为无服务器的谜团之一!

平衡成本和性能

降低成本是一项重要的工作。通常,它是自上而下的。当它进入无服务器生态系统时,它会遇到一个被称为优化的模糊活动。它以两种不同的形式存在。

  • 成本优化,以及
  • 性能优化

在无服务器中,成本和性能交织在一起。问题是,当我们考虑降低无服务器成本的方法时,这两种方法会将我们引向相反的方向。

成本和性能之间的冲突

众所周知,每个应用都有很多部分——微服务、API、存储、特性等。这取决于我们如何识别和分组它们。

无服务器应用程序的好处之一是,我们可以在粒度级别上可视化和优化每个部分。它允许我们在细粒度级别上执行成本和性能优化。然而,复杂性在于成本和性能并不总是相辅相成的。它们往往会造成成本失衡!

  • 成本优化不能保证性能,并且
  • 性能优化并不总是经济高效的

性价比高

当我们针对性能进行优化时,无服务器的低成本观念会发生巨大变化。这里有几个案例可以证明这一点。

  • 为 Lambda 函数设置提供的并发可能会很昂贵。但是,为了获得更好的性能和最终用户体验,在需要的情况下,我们同意支付额外费用

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

与 Lambda 计算成本相比,调配的并发成本较高。作者图片

  • 为了保持高可用性,我们使用使用 DynamoDB 全局表的跨区域数据复制。这给我们的 DynamoDB 成本增加了更高的价格

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

与正常数据库操作相比,数据复制费用较高。作者图片

  • 设计具有更好的监控和可观察性的安全解决方案是一项业务重点。使用 CloudWatch 指标会产生更高的成本

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

CloudWatch 指标成本可能会让许多人感到惊讶。作者图片

安全性、数据保护、低延迟、高可用性、弹性和可观察性是优先于成本优化的无服务器应用的几个核心方面。最终用户体验和满意度是另一个没有企业愿意为了削减成本而牺牲的领域。

简而言之,设计更好的无服务器解决方案成为当务之急。

朝向 DevOps

构建无服务器应用程序确实需要一种不同于我们过去概念化应用程序的思维方式。构建安全和高性能的解决方案与使用最佳计算模型实现最佳业务逻辑同样重要。

  • 工程师们花几个月的时间制作出一份详细的设计规范并交给一个离岸团队进行编码的日子已经一去不复返了。
  • 工程师编写代码,编译代码,然后把代码扔给其他团队的日子已经一去不复返了。
  • 公司保留一个没有动力的维护团队来修复生产缺陷的日子已经一去不复返了。
  • T2 单一用途软件工程师只知道如何用特定编程语言编码的日子也一去不复返了。

欢迎来到 DevOps!

与过去形成对比的是,这个时代的工程师在编写单一用途的 Lambda 函数的同时,已经发展成为多资源多方面的独石,能够做许多事情!

拉近商业和技术的距离

DevOps 运动无疑缩小了工程和运营之间的差距。它导致更小的无所不包的团队拥有从需求到生产甚至更多的特性。

这些团队遵循敏捷和精益原则,以变得高效和成本有效。它有助于建立项目涉众对工程团队的信任。信任让团队有信心更快地交付功能,以满足不断变化的客户需求。

新世界新需求

为我们的现代世界构建解决方案有许多需求。

  • 应用程序有望抵御残酷的网络攻击。
  • 企业面临着遵守监管和行业标准以保护个人数据的巨大压力。
  • 客户的关注点每隔几秒钟就会发生变化。让他们参与进来并更快地为他们服务至关重要。

在整个企业世界中,传统的 IT 部门变得分散,有利于自治的产品团队。它允许技术和非技术同事坐在一起,构建更好的解决方案。反过来,它有助于培养尊重和加强相互理解。

无服务器催化剂

无服务器带来的是满足这种需求的灵活性和便利性*。更快地设计、开发、部署和改进功能。软件特性的生命周期比以往任何时候都要快。无服务器是一项让用户更容易跟上进度的技术。*

这种业务和技术协作增加了业务价值。以客户为中心的、快节奏的、功能驱动的开发使业务蓬勃发展。

多亏了无服务器,加速变得更快了。

疫情效应

2020 年!

虽然它因为疫情的原因而留在了历史书上,但它也给企业家智囊团上了严酷的一课,注入了新的理念。

  • 许多组织为了生存改变了他们的运作模式。
  • 许多人陷入混乱,只有一线希望和有限的时间做出反应。
  • 对其他人来说,这是一个保持活力或爆发的选择。

我们认为不可能的事情变成了可能。业务优先级每隔一天就会发生变化。那些迅速适应的人经受住了考验。那些将业务建立在可扩展基础设施上的企业能够根据不可预测的客户需求快速进行调整。

锁定期间的业务增长

BBC 最近在英国进行的一项调查显示,在疫情期间,新业务的开展显著增加。这可能会让一些人感到惊讶,但从现代云技术的角度来看,这是一种可能性。

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

来源: BBC

在混乱、心痛和困惑中,每个人都需要一种技术,可以用来更快地构建解决方案,并从他们的客厅进行管理。对于大多数成功的人来说,他们对云和无服务器的采用肯定起到了至关重要的作用。

这种商业模式和无服务器的价值差异将在 2021 年及以后继续加强。

无服务器建筑的便利将开始挣脱其成本思维的束缚。

便利计算的出现

AWS Lambda 是无服务器计算的核心。Lambda 自诞生以来发生了很大的变化。它仍在发展。随着更长的执行时间、更多的内存、更高的处理器、更重的工作负载等,它无疑变得更加复杂。然而,它有助于编写简单的函数和轻松构建无服务器解决方案。如果无服务器只是为了低成本,那么 Lambda 服务就不会发展到现在。

成为最便宜的并不总是许多技术采用背后的主要原因。需求随着时间而变化。这些天来,

  • 企业正在寻找最简单的方式来运行计算工作负载
  • 产品所有者正在寻找最快的方式来发布一个特性
  • 工程师们正在寻找处理客户数据的最安全的方式
  • 顾客正在寻找购买产品的最简单的方式

名单还在增长。当试图满足这样的需求时,团队并不总是将成本作为阻碍因素。通常,他们选择方便的方式来经营,以获得竞争力和成功。当谈到提供这种舒适度的技术时,无服务器显然是赢家。

我前面提到的英国广播公司的调查也强调了以下几点。

  • 在疫情时代,在家经营企业是有意义的
  • 专注于网络的公司做得很好
  • 不是所有这些企业都是永久性的

传统的商业模式不断被改写。根据需要扩大和缩小规模已经成为正常的操作模式。

临时和权宜之计的企业是常见的这些天。许多在线业务根据交易条件和业务限制自动开始运作或进入休眠状态。现代云和无服务器技术让这一切成为可能。

我们可以说这是新的便利云模式*。使用无服务器,从一开始就可以保证这一点。*

结论

无服务器在其相对较短的存在时间内成功地赢得了许多企业。作为一项技术,几个用例已经证明了无服务器的多功能性。每天都有大量的新用例被自信而舒适地构建出来。它以成本为中心的类型正在改变。

然而,挑战在于如何在复杂的事物中保持简单。简单性使得每个人都能更快地方便构建解决方案。

也许是时候为无服务器设计一个新的标语了。让 便利计算 成为那个无服务器自信地朝着未来正确方向前进的人吧!

将数据存储导出到 BigQuery 的无服务器方法

原文:https://towardsdatascience.com/serverless-approach-to-export-datastore-to-bigquery-4156fadb8509?source=collection_archive---------15-----------------------

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

Maksym Kaharlytskyi 在 Unsplash 上的照片

一种在 Google 云平台上使用无服务器方法定期将数据存储导出到 BigQuery 的简单方法

概述一下, Google Datastore 是一个完全托管的 NoSQL 服务,自 2008 年开始在 Google 云平台上提供。它可以被视为一个键值和一个文档数据库,提供了一个类似 SQL 的查询语言和绑定到许多编程语言的 SDK。

数据库被组织成实体(或记录)。每个属性可以有一个或多个命名属性,其中每个属性可以有一个或多个值。实体通过由名称空间、种类和标识符(字符串或整数)组成的键来标识。应用程序可以使用该键来获取特定的实体。值得注意的是,相同种类的实体不需要具有相同的属性,并且同名属性的值不需要具有相同类型的值。简而言之,你可以把任何你喜欢的文件存放在这个键下。

虽然 Datastore 允许各种查询,但是从数据探索和分析的角度来看,将记录放在容易查询的常规数据库中更可行,例如, BigQuery

我们开始吧

一个可能的解决方案是将这些类型从 datastore 导出到 BigQuery。导出分两步完成:

  1. 将选定的种类导出到云存储中的存储桶
  2. 将导出的种类从云存储导入到 BigQuery

BigQuery 加载作业可以选择直接从云存储中读取导出的数据存储种类,因此我们不需要任何其他转换。BigQuery 加载作业的约束是必须逐个导出这些类型。同样值得注意的是,BigQuery 中现有的导出表将被新数据替换。

这个解决方案很简单,但是有一些缺点。主要的一个问题是,该过程不允许指定要导出的记录类型的子集。换句话说,您每次都必须导出-导入所有记录。对于小型数据存储,这仍然是可行的,但是对于较大的数据库,这种解决方案不是最佳的—请注意这一点。在下一篇文章中,我将告诉你如何解决这个问题——敬请期待。

对于多种类型,一种简单的优化技术是重叠导出/导入作业,如下所示:

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

平行导出/导入作业的重叠(按作者)

这样,我们可以减少导出整个数据存储的总时间。请记住,您只能有 50 个并发导出作业,对于一个项目,您每分钟最多可以执行 20 个导出请求。

命令行方法

可以使用两个命令行工具运行导出/导入: gcloudbq *。*在第一个示例中,您将运行数据存储到存储桶的导出:gcloud datastore export gs://bucket-name/Kind1 --project gcp-project --kinds Kind1

使用第二种方法,您可以在 BigQuery 中运行作业导入,它将从 bucket:
bq load --source_format=DATASTORE_BACKUP datastore_export.Kind1 gs://bucket-name/Kind1/default_namespace/kind_Kind1/default_namespace_kind_Kind1.export_metadata中获取数据

无服务器方法

命令行方法听起来是一个很好的起点,可以探索解决方案是否有效,作为在 BigQuery 中获得即时数据的一次性导出方法。但是,如果您喜欢每天运行此任务,最好将此作业安排在其他地方。

虽然上面两个命令可以从一个虚拟机上执行,但是使用 cron 等,这不是一个最佳的解决方案。首先,如果任务必须运行,例如每天运行,您将浪费资源,因为资源每天只使用几分钟。其次,您必须监控虚拟机是否在运行,系统是否是最新的,等等。又来了一个无服务器。

无服务器是一个流行的概念,你可以将所有的基础设施任务委托给其他地方。作为开发人员,您需要提供的只是解决问题的代码。因此,您不需要管理虚拟机、升级主机操作系统、担心网络等问题。—这都是由云提供商完成的。

在这个小故事中,我将展示如何使用无服务器组件构建导出/导入过程。这是可能的,因为最终我们将只调用GCPAPI 并等待结果——工作将在后台完成。
该解决方案的架构图如下所示。

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

无服务器解决方案的架构图(作者)

该架构包括两个云功能:

  • 数据存储 _ 导出器
  • bigquery_importer

datastore_exporter 负责调度输入类型的数据存储导出。下一个函数 bigquery_importer ,负责调度 bigquery 加载作业。

图中的其他组件用于协调流程。让我通过一步一步地列举来详细说明它是如何工作的。

函数数据存储导出器

类似 cron 的作业由 Google Scheduler、管理,它触发datastore _ exporterCloud 函数,其中列出了数据存储中所有可能的类型,并为它们中的每一个安排导出到云存储。产生的对象位于云存储桶中。

时间表本身是用

我们定义该函数将在每天 6.00 执行。调度器将通过调用 HTTP 触发器来触发云功能。它使用关联的服务帐户对请求进行身份验证。

schedule 使用的服务帐户的定义如下所示。该账户有权限调用 datastore_exporter 云函数。

gcf_datastore_exporter 函数定义为

在这里我们设置这个函数将由 HTTP 触发。截至 2020 年 1 月 15 日,云功能默认要求触发认证。我们保持原样。

当给定类型的导出完成时,会引发一个由 bigquery_importer 函数捕获的事件Google . storage . object . finalize

函数 BigQuery 导入程序

该函数的目的是处理 bucket 事件,并安排将导出的数据存储导入到 BigQuery。

函数本身是使用Google _ cloud functions _ function资源定义的

其中我们定义了该函数将在来自数据存储输出桶的事件上被触发。我们只对事件感兴趣**

函数的主体非常简单。

该函数正在监听所有的对象完成事件,但只有当对象名为all _ namespaces _ kind _时。创建 export_metadata* ,然后计划导入到 BigQuery。*

负责运行 BigQuery 导入的函数非常简单。我们实际上必须定义的是一个作业,它基本上包含与命令行相同的属性:

**完整的功能你可以在这里找到:https://github.com/jkrajniak/demo-datastore-export

*https://github.com/jkrajniak/demo-datastore-export

许可

合适的权限集非常重要,我们应该始终遵循最小权限原则。两种云功能都有自己的服务账号。对于数据存储导出器,我们附加以下角色

"roles/monitoring.metricWriter",
"roles/logging.logWriter",
"roles/datastore.importExportAdmin",
"roles/datastore.viewer"

第二个函数需要以下权限

"roles/monitoring.metricWriter",
"roles/logging.logWriter",
"roles/bigquery.jobUser",

此外,它需要访问输出桶和输出数据集。这是通过绑定 IAM 权限来实现的

部署

简单说一下这两个云功能的部署。由于“基础设施”的其他部分内置在 terraform 中,我认为云功能的部署也应该由 Terraform (TF)负责。为此,我使用了两个 TF 资源 archive_fileGoogle _ storage _ bucket _ object。

archive_file 资源将从源目录的内容创建一个 zip 文件。然后这个文件会被复制到云存储。这里,云存储中的对象有一个根据文件的 SHA1 计算的后缀——这就像简单的版本控制一样。对于生产运行,我将使用 Git commit hash 和 Git 标记作为对象后缀。

在 https://github.com/jkrajniak/demo-datastore-export,你会找到基础设施和两个云功能的代码。*

最后的几点

  1. 我总是鼓励使用无服务器的方法。只关注方法,把所有基础设施的麻烦都留给巨人,这样会更容易、更快。
  2. 始终将您的基础设施作为一个代码,例如使用自动气象站云形成地形CDK 。它比任何其他处理项目/服务配置的方法都更加可靠和可重复。每当您必须在一个新的 GCP 项目中重建基础设施时,您将立即从这种方法中受益,否则就会出现问题。此外,通过这种方式,您可以像处理应用程序的部署一样,自动化基础设施变更的部署。
  3. 数据工程任务不应该是任何常规和标准软件开发方式的例外——编写单元测试,使用 CI/CD 进行代码和基础设施部署,并将您的代码保存在存储库中;不要依赖在任何花哨的网络界面点击的解决方案。

我希望你喜欢这个故事,它会对你的日常工作有所帮助。如果您有任何问题或建议,请随时通过 TwitterLinkedin 联系我。

Prefect 和 AWS ECS Fargate 简化了无服务器数据管道

原文:https://towardsdatascience.com/serverless-data-pipelines-made-easy-with-prefect-and-aws-ecs-fargate-7e25bacb450c?source=collection_archive---------9-----------------------

编排 Python 数据管道的最简单方法

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

照片由突发发自像素

E 尽管有这么多的工作流程编排解决方案和云服务来构建数据工作负载,但很难找到一个真正好用并能让你快速上手的。在 Python 中构建数据管道最流行的工具之一是 perfect——一个工作流管理平台,具有基于混合代理的执行模型。

混合执行模式需要什么?这意味着即使您使用云编排平台( Prefect Cloud ),您仍然拥有并管理您的代理。事实上,Prefect 不能直接访问您的代码或数据。相反,它只对注册代理和流时发送给它们的 API 的元数据进行操作。首先,这意味着该平台可以满足严格的安全性&合规性要求,因为整个工作流的执行都在您选择的计算资源内进行。另一方面,它提供了令人难以置信的灵活性。您的代理可以是 Kubernetes 集群、AWS 上的 ECS Fargate 集群、本地或云中的任何计算服务器,或者它们的组合。甚至你的笔记本电脑也可以注册为完美代理。

尽管混合执行模型有很多好处,但是正确配置执行层可能是一个挑战。在本文中,我们将了解如何使用一个 AWS ECS Fargate 代理和 S3 存储来设置 Prefect,这允许一个完全无服务器的NoOps 执行环境。

**更新:**你可以在这篇文章中找到 ECS 代理设置的更新版本。

目录

· [Getting started with Prefect Cloud](#289a)
· [Prefect Cloud setup](#a045)
 ∘ [Create your Prefect account](#c005)
 ∘ [Install Prefect](#f483)
 ∘ [Create a personal access token to authenticate with Prefect Cloud](#98c3)
· [Creating AWS resources](#7f89)
 ∘ [Creating an IAM role for our ECS tasks](#8815)
 ∘ [Creating an S3 bucket to store our flow code](#3d13)
 ∘ [Creating an EC2 instance for our agent process](#5cdb)
 ∘ [SSH to the EC2 instance to configure the ECS Prefect agent](#7af6)
 ∘ [Creating a Fargate cluster](#4a07)
· [Deploying our first serverless flow](#6b1a)
 ∘ [ECSRun configuration & Prefect Storage](#7289)
 ∘ [Registering a flow for ECS agent](#3e93)
· [Conclusion](#f807)

完美的云设置

创建您的高级帐户

首先,在https://cloud.prefect.io/上注册一个免费的入门账户。

安装提督

以下命令将安装带有 AWS 子包的提督(而不是 [aws] 如果您想安装外部系统的所有提督扩展,您可以使用 [all_extras] ):

pip install "prefect[aws]"

为了确保我们使用 Prefect Cloud 作为编排层,而不是开源的 Prefect Server,将上下文切换到*“Cloud”*:

prefect backend cloud

创建一个个人访问令牌,以便通过 Prefect Cloud 进行身份验证

注册免费账户后,您需要创建一个个人访问令牌来使用 Prefect Cloud 验证您的本地终端。这将允许直接从您的本地机器向 Prefect Cloud API 注册您的流(即您的 ETL & ML 数据管道)。从主菜单中,选择:用户→个人访问令牌→ + CREATE TOKEN按钮。

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

完美的云用户界面——作者图片

选择一些有意义的名字。YourAuthTokenToPrefectCloud。然后复制令牌,并在您的终端中运行以下命令:

prefect auth login -t <YourAuthTokenToPrefectCloud>

认证步骤允许您的笔记本电脑与 Prefect Cloud API 通信,以注册您的代理和流。然后,API 负责调度您的工作流,您的代理不断轮询 API 以了解它是否需要触发一些流运行。一旦计划触发流,代理就会得到通知并开始执行。

下一步,我们将在 AWS 上设置一个 ECS Fargate 集群作为我们的执行层。除此之外,我们还需要一个代理,也就是轮询工作 ( 即流程执行)的 API。为此,我们将创建一个带有后台进程的 EC2 实例——您可以创建一个 ECS 服务来代替。

在进入 AWS 设置之前,让我们创建一个 RUNNER 令牌,我们将使用它向 Prefect Cloud 认证我们的代理。

prefect auth create-token -n DemoFargateAgentToken -s RUNNER

你可以用任何你喜欢的名字代替DemoFargateAgentToken。将作用域( -s 标志)设置为 RUNNER,并将令牌保存在安全的地方,这一点很重要。我们将在下一节用到它。

创建 AWS 资源

如上所述,我们需要:

  • 一个 t2.micro EC2 实例,我们将在其中部署我们的代理——这个实例的全部目的是拥有一个单独的进程,它为流运行轮询完美的 API,
  • 我们将把一个 IAM 角色分配给我们的 ECS Fargate 任务,这样我们的容器就可以访问包含我们流代码的 S3 桶。此外,这将允许我们缓存到 S3 的流的中间结果,
  • 一个 S3 桶作为我们流代码的默认存储,
  • 一个 ECS Fargate 集群,它将为我们的容器化数据管道按需旋转计算资源,即无服务器。这样,我们就没有空闲的计算资源,我们可以创建一个按需 Dask 集群来在需要时跨几个 Fargate 容器并行化我们的 Python 代码。

为我们的 ECS 任务创建 IAM 职责(结果:任务职责 ARN)

在这一步中,我们创建一个任务角色,它将赋予我们的 ECS 任务(您可以把它看作是您的流的容器)访问 S3 中的对象的权限。

理想情况下,您应该遵循最小特权原则。出于开发目的,您可以为 S3 和 ECR 分配完全访问权限,以便您的 ECS 容器可以与存储在 S3 的对象以及 ECR 容器映像进行通信。

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

为 ECS 任务创建 IAM 角色(第 1 部分)—作者图片

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

为 ECS 任务创建 IAM 角色(第 2 部分)—作者图片

创建一个 S3 桶来存储我们的流代码

请记住,您的 bucket 名称必须是全球唯一的(就像网站的域名)。您可以在单个 CLI 命令中或从管理控制台创建存储桶。

aws s3 mb s3://yourbucket

为我们的代理进程创建 EC2 实例

用 Amazon Linux 2 AMI 选择 t2-micro 实例类型(对于单个进程应该绰绰有余)。

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

EC2 启动向导—作者图片

然后遵循默认值,直到到达安全组部分,在这里您需要允许您的 IP 地址 SSH 访问实例。

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

EC2 启动向导—作者图片

之后,点击查看并启动,继续创建密钥对(aT28)。pem 文件)以便可以用它来 SSH 到实例。

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

创建密钥对(。pem 文件)SSH 到实例—由作者创建的图像

SSH 到 EC2 实例,以配置 ECS 提督代理

一旦实例处于运行状态,您就可以直接从浏览器或使用 SSH 客户机进行连接。现在,我们需要在 EC2 实例上安装 Python 3:

让我们检查一下 Python 和包的版本,以便您确切地知道我在这个 EC2 设置中使用了什么:

我们的 ECS Fargate 代理将需要几个环境变量。让我们使用export来设置它们:

上面的第 1 行引用了我们在上一节中创建的 RUNNER 令牌(不要与我们用来授权我们的机器向 Prefect Cloud API 注册流的个人访问令牌混淆)。要找到子网 id(第 5 行),请转到 VPC 部分,从您的默认 VPC 中复制 id。当然,如果你愿意,你可以创建自己的 VPC。出于开发目的,默认的 VPC 就可以了。

另外,如果您没有ecsTaskExecutionRole,您可以按照 AWS 管理控制台中的“创建 ECS 集群”向导来创建它。

注: *executionRoleArn* *task_role_arn* 不同。而 执行角色 则赋予代理在 ECS ( ex)上执行容器的权限。从 ECR 中提取图像,将日志存储在 CloudWatch )、 任务角色 (作为章节的一部分创建:为我们的 ECS 任务创建 IAM 角色 ) 为您的流的容器提供访问其他 AWS 资源的权限,比如保存您的完美流的元数据的 S3 桶,或者其他一些 AWS 服务,比如 SQS、SNS 或 DynamoDB。

创建 Fargate 集群

现在让我们使用aws configure来配置 AWS CLI,这样我们就可以直接从这个 EC2 实例创建一个 ECS Fargate 集群。如果您没有 AWS 密钥对,您应该首先创建一个 IAM 用户,该用户有权创建 ECS 集群。

为了简化设置,我们使用标准 ECS 配置来创建一个集群,其默认名称为*“default”,兼容性为“Fargate”(,即无服务器数据平面*)。

aws ecs create-cluster

就是这样!我们的集群已经创建。剩下要做的就是启动一个 Prefect agent 进程,该进程将轮询 Prefect Cloud API 的流运行,并将工作提交给 AWS 上的无服务器 ECS 容器平台。我们可以在一个 CLI 命令中完成:

注意:

  • ECSTaskS3Role是我们之前创建的 IAM 角色(部分: 为我们的 ECS 任务 创建一个 IAM 角色),它将由 ECS 任务(容器)承担,以便拥有访问 S3 的权限,
  • 我们添加了标签**“fargate-dev”“S3-flow-storage”**—这些标签非常重要,因为这样我们可以“告诉”Prefect Cloud API 哪个代理应该接收特定流的流运行(即数据管道)。由于我们的代理分配了这些标签,任何带有匹配标签的RunConfig流都将由该代理编排。一旦我们部署了一个示例流,这将变得更加清晰。
  • 我们在末尾添加了> /dev/null 2>&1 &,以确保命令在后台运行(守护进程),并抑制对stdoutstderr的日志记录。如果你知道一个更好的方法来运行这个命令作为后台进程,请在评论或私信中告诉我。

如果我们转到用户界面,我们可以看到我们的 ECS 代理可用并准备好执行计划的流程运行:

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

ECS 代理在 UI 中是可见的——作者的图像

因为我们在 EC2 上的 ECS 代理 在后台进程中运行,所以您可以从 SSH 会话断开连接。如果在某个时候,您的完美代理不再健康,您总是可以再次 SSH 到 EC2 实例,终止该进程,然后再次启动代理。Prefect Cloud 的好处在于,您可以直接在 UI 中看到代理的健康状况——不需要实现任何额外的监控层来跟踪这些信息。

部署我们的第一个无服务器流程

ECSRun 配置和完美存储

在当前的完美版本( 0.14.x )中,您需要定义一个运行配置来确定哪个代理将获取您的流代码来执行。在下面的代码中,您可以看到ECSRun()使用了一个标签s3-flow-storage来确保这个流只被带有相应标签的 ECS 代理获取。它的工作原理类似于 Kubernetes 中的标签和选择器。

在下面的例子中,我们简单地构造了一个 Pandas dataframe 并打印了一个 Pandas 版本,向您展示您可以使用您最喜欢的 Python 包并运行任何 Python 函数,只要您用@task装饰器调用它。然后,我们还传递运行配置和关于放在哪里的信息,以及从哪里检索我们的流的元数据(提督 存储 ) —这里,它是一个 S3 桶。

用作你的流的基础图像的image,可以是来自 Dockerhub 的一个提督的图像。 级/级:0.14.1 。我们使用我们自己的定制 Docker 映像,它只是 Prefect 的基本映像的一个副本,在其上安装了附加的 Pydata 包,以包含构建 ETL 或 ML 数据流所需的所有组件。

这是我们用于公开图片anisienia/prefect-pydata的 docker 文件:

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

显然,您可以指定确切的包版本,并在您的映像中包含您可能需要的任何自定义依赖项。此外,您可以使用 ECR 来代替 Dockerhub。存储公共 Dockerhub 图像是 100%免费的——如果你没有凭证,也没有定制公司的内部业务逻辑(只是 Python 包依赖),你可以通过这种方式节省一些 AWS 成本。

如果您想了解更多关于如何构建 Dockerhub 容器映像的信息,这里有一个适合您的方法:

</7-steps-to-your-own-dockerhub-image-7d1d92d2a3e0>

为 ECS 代理注册流

下面是我们可以使用的流程示例:

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

进一步说明&附加信息:

  • task _ role _ arn是我们作为部分创建的 IAM 角色的 ARN:为 ECS 任务 创建 IAM 角色。
  • ECSRun()内部,我们定义了一个标签 s3-flow-storage ( 第 8 行),这样我们的 ECS 代理就可以获取这个流来执行。这种机制允许在适当的代理之间编排流程以供执行。注意代理和流之间的标签必须完全匹配。这意味着来自代理的所有标签必须匹配来自流的所有标签。
  • ECSRun()内部,我们还定义了一个定制的 Docker 映像(这里是:我们来自 Dockerhub 第 10 行的映像),以确保我们的流环境包含所有 Python 包以及我们需要的确切版本。
  • 命令 flow.register() 需要指定项目名称。你可以在 UI 中创建一个项目或者使用命令:提督创建项目<项目名称>

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

上面显示的流示例中的日志—图片由作者提供

结论

在本文中,我们研究了如何使用 Prefect 创建 ECS Fargate 代理。我们创建了一个 ECS 集群和一个 EC2 实例,其中一个 Prefect ECS 代理作为后台进程运行,持续轮询 Prefect Cloud API 以获取新的流运行。

然后,我们运行了一个示例流,它使用我们的 Docker 映像作为基础来反映定制 Python 包的依赖性。当注册我们的流时,流的元数据被发送到指定的 S3 桶(代码片段中的第 12 行)。每次 Prefect Cloud API 调度并触发流运行时,ECS Fargate 代理都会检索相同流的元数据。**

***注意:*如果您对代理设置有任何问题,可能有人已经经历过相同的问题,并在完美社区 Slack 中分享了他们的解决方案:https://prefect-community.slack.com/

感谢您的阅读!

参考资料&其他资源:

[1] 提督 0.14.0:改进流道配置

[2] 提督用 Fargate 部署流程——YouTube 直播

[3] ECS 有效的 CPU 和内存配置

无服务器功能和将 AWS Lambda 与 S3 存储桶一起使用

原文:https://towardsdatascience.com/serverless-functions-and-using-aws-lambda-with-s3-buckets-8c174fd066a1?source=collection_archive---------3-----------------------

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

Unsplash 上由 C Dustin 拍摄的照片

了解如何构建一个由 S3 PUT 事件触发的 Lambda 函数来对 S3 桶中的文件进行排序。

在我以前的文章中,你可能已经看到我不断地在云上的服务器实例上部署代码,构建服务来管理这些实例,在这些服务之上构建反向代理等等。毫无疑问,你们中的一些人可能希望只需编写代码,将其部署到某个地方,而不必担心设置和管理服务器实例的过度复杂性。根据您的使用情况,可能会有一个解决方案——无服务器功能。

无服务器功能允许部署代码,而无需为代码分配任何基础架构。AWS Lambda 是一个 FaaS(功能即服务)平台,允许您构建无服务器功能。AWS Lambda 支持大多数主流编程语言,如 Go、Java、Ruby、Python2 和 Python3。在本教程中,我们将使用 Python3。尽管它们被称为“无服务器”,但它们实际上运行在云服务器实例上的各种运行时环境中。

无服务器功能是无状态的,也就是说,一个功能的一次执行并不保持一个后续执行可以识别或使用的状态。换句话说,一个无服务器功能的执行不会以任何方式与另一个执行进行通信。由于无服务器功能是受时间和资源限制的,所以它们适用于短期任务。它们在内存、CPU、存储等分配方面提供的灵活性非常小。采用某个 FaaS 平台来实现无服务器的一个含义是,对于您的无服务器功能可能与之交互的大多数其他云服务,您会被该平台的供应商所束缚。

稍微了解一下微服务…

无服务器功能可用于构建微服务架构,其中您的软件由提供特定功能的较小的独立微服务构建而成。微服务让开发者更容易以敏捷的方式构建、测试和管理软件。微服务是软件中完全独立的部分,因此不同的微服务可以并行编码、测试和部署。定位和修复微服务架构中的错误要容易得多,因为您只需处理出现故障的微服务。

例如,网飞在 2009 年开始将其软件迁移到 AWS 云上,成为了基于微服务架构的最早采用者之一。他们目前维护着一个 API 网关,每天接收数十亿个请求,由独立的微服务组成,用于用户注册、下载电影等流程。通过切换到微服务架构,网飞能够加快其软件的开发和测试,并在遇到错误时轻松回滚。

Lambda 与其他 AWS 服务

当与其他 AWS 服务结合使用时,AWS Lambda 上的无服务器功能或简单的 Lambda 功能可以做一些非常酷的事情,比如使用亚马逊 Alexa 来打开和关闭 EC2 实例,或者当有东西被推送到 CodeCommit(甚至 GitHub)库时点亮灯泡。

有 3 种方法可以将 Lambda 与其他 AWS 服务结合使用:

  1. 使用其他 AWS 服务作为触发器来调用 lambda 函数*。一个 lambda 函数可以有多个触发器,使用广泛的 AWS 服务,如 S3 存储桶放置或删除事件、对 API 网关端点的调用等。
  2. 从 lambda 函数内部与 AWS 服务交互,比如在 DynamoDB 数据库中添加或删除数据,或者获取 EC2 实例的状态。你可以使用 AWS 为你的 lambda 函数代码中的 JavaPython **、 Ruby 等构建的各种 SDK(软件开发工具包)来做到这一点。使用这些 SDK,可以控制一长串 AWS 服务或与之通信。
  3. 每当调用 Lambda 函数时,使用 AWS 服务作为其调用记录的目的地。截至目前,只有 4 种 AWS 服务可以这样使用:SNS、SQS、EventBridge 或 Lambda 本身。

*当另一个 AWS 服务调用 Lambda 函数时,Lambda 使用 事件 对象将特定信息从该 AWS 服务传递给该函数。这将包括诸如哪个 DynamoDB 数据库中的哪个项目触发了 Lambda 函数之类的信息。

***** Boto3*** 是一个由 AWS 构建的 python 库(或 SDK),允许你与 AWS 服务交互,如 EC2、ECS、S3、DynamoDB 等。在本教程中,我们将使用 Boto3 管理 AWS S3 桶内的文件。Boto3 的完整文档可以在 这里 找到。

将 Lambda 与 AWS S3 桶一起使用

**本教程的先决条件:**AWS 自由层帐户。

一个 S3 桶 只是 AWS 云中的一个存储空间,用于存储任何类型的数据(如视频、代码、AWS 模板等)。).S3 存储桶中的每个目录和文件都可以使用一个键来唯一标识,这个键就是它相对于根目录(也就是存储桶本身)的路径。比如“car.jpg”或者“images/car.jpg”。

除了作为开发基于微服务的软件的强大资源之外, Lambda 函数还是高效的 DevOps 工具。 让我们来看一个例子,上面提到的前两种使用 Lambda 函数和 S3 桶来解决一个简单的 DevOps 问题:)

假设您正从三个不同的煤气表接收 XML 数据,并将其直接放入 AWS S3 桶中。您希望根据数据来自哪个燃气表,将 XML 文件分类到三个独立的文件夹中。了解数据源的唯一方法是查看 XML 文件内部,如下所示:

<data>    
   <data-source>gas_meter3</data-source>    
   <data-content>bla bla bla</data-content>
</data>

您将如何自动化这一过程?这就是 AWS lambda 可以派上用场的地方。让我们看看如何做到这一点。

1 -创建一个 S3 桶

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

让我们从构建一个空的 S3 桶开始。你所要做的就是从你的 AWS 控制台进入 S3 页面,点击“创建桶”按钮。确保选中“阻止所有公共访问”复选框,然后单击“创建存储桶”。

现在,添加一个名为“unsorted”的目录,所有 XML 文件最初都将存储在这个目录中。创建一个名为“testdata.xml”的. xml 文件,其内容如下:

<data>    
   <data-source>gas_meter3</data-source>    
   <data-content>bla bla bla</data-content>
</data>

2 -创建 Lambda 函数

在 AWS 控制台的服务选项卡中,单击“Lambda”。在 Lambda 页面的左侧窗格中,选择“函数”,然后选择“创建函数”。

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

选择“从头开始创作”,并给函数取一个合适的名字。因为我将使用 Python3,所以我选择“Python3.8”作为运行时语言。Python2 和 Python3 还有其他版本。选择一种运行时语言,然后单击“创建函数”按钮。从“函数”页面上的 Lambda 函数列表中,选择您刚刚创建的函数,您将被带到该函数的页面。

Lambda 会自动创建一个 IAM 角色供您与 Lambda 函数一起使用。IAM 角色可以在函数页面的“权限”选项卡下找到。您需要确保该函数的 IAM 角色有权访问和/或管理您从函数内部连接到的 AWS 服务。

确保将“S3”权限添加到 IAM 角色的权限列表中,可通过 IAM 控制台访问。

3 -为我们的 Lambda 函数添加一个触发器

我们希望 Lambda 函数在每次 XML 文件上传到“未排序”文件夹时被调用。为此,我们将使用一个 S3 存储桶 PUT 事件作为函数的触发器。

在 Lambda 函数页面的“设计器”部分,点击“添加触发器”按钮。

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

选择“S3”触发器和您刚刚创建的桶。选择“上传”事件类型。将前缀和后缀设置为“未排序/”和”。xml”。最后,点击“添加”。

4 -给我们的 Lambda 函数添加代码

有三种方法可以向 Lambda 函数添加代码:

  1. 通过控制台上的代码编辑器。
  2. 上传一个包含所有代码和依赖项的. zip 文件。
  3. 通过从 S3 桶上传代码。

在本教程中,我们将使用第一种方法。在您的函数页面上,转到“函数代码”部分找到代码编辑器。

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

将以下代码复制并粘贴到代码编辑器中:

import json
import boto3
import uuid
from urllib.parse import unquote_plus
import xml.etree.ElementTree as ETdef lambda_handler(event, context):
    s3 = boto3.resource('s3', region_name='')#Replace with your region name #Loops through every file uploaded
    for record in event['Records']:
        bucket_name = record['s3']['bucket']['name']
        bucket = s3.Bucket(bucket_name)
        key = unquote_plus(record['s3']['object']['key']) # Temporarily download the xml file for processing
        tmpkey = key.replace('/', '')
        download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)
        bucket.download_file( key, download_path) machine_id = get_machine_id_from_file(download_path) bucket.upload_file(download_path, machine_id+'/'+key[9:])

        s3.Object(bucket_name,key).delete()def get_machine_id_from_file(path):
    tree = ET.parse(path)
    root = tree.getroot() return root[0].text

不要忘记替换地区名称。

确保处理程序值为“<文件名>。λ_ handler”。处理程序值指定哪个函数包含 Lambda 执行的主代码。

每当 Lambda 运行您的函数时,它会将一个上下文对象 和一个事件对象 传递给它。这个对象可以用来获取关于函数本身及其调用的信息,例如函数名、内存限制、日志组 id 等。上下文对象对于日志记录、监控和数据分析非常有用。

如前所述,Lambda 使用事件对象从调用 Lamda 函数的 AWS 服务向 Lamda 函数提供特定信息。最初以 JSON 格式出现的信息在传递给函数之前被转换成一个对象。在 Python 的例子中,这个对象通常是一个字典。在上面的代码中,您可以看到事件对象被用来获取 S3 存储桶的名称和触发我们函数的 S3 存储桶中的对象的键。

上面的代码很容易理解。它执行以下操作:

  1. 事件对象获取信息。
  2. 下载导致 Lambda 函数被调用的 XML 文件。
  3. 处理 XML 文件,从 XML 文件的第一行找到 machine_id
  4. 将文件上传回 S3 桶,但放在一个名为 machine_id 的值文件夹中。
  5. 删除原始文件。

现在,按下“部署”按钮,我们的功能应该准备运行。

5 -测试我们的 Lambda 函数

AWS 使得通过 Lambda 控制台测试 Lambda 函数变得非常容易。无论您的 Lambda 函数使用什么触发器,您都可以使用 Lambda 控制台上的 测试 功能来模拟您的 Lambda 函数的调用。这一切都需要定义什么 事件 对象将被传递到函数中。为了帮助你做到这一点,Lambda 提供了特定于每种类型触发器的 JSON 模板。例如,S3 看跌事件的模板如下:

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "us-west-2",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "EXAMPLE"
      },
      "requestParameters": {
        "sourceIPAddress": "126.0.0.1"
      },
      "responseElements": {
        "x-amz-request-id": "EXAMPLE123456789",
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "testConfigRule",
        "bucket": {
          "name": "example-bucket",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },
          "arn": "arn:aws:s3:::example-bucket"
        },
        "object": {
          "key": "test/key",
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}

为了测试您刚刚创建的 Lambda 函数,您需要为您的函数配置一个测试事件。为此,单击 Lambda 代码编辑器正上方的“选择测试事件”下拉菜单,然后单击“配置测试事件”。

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

从弹出菜单中,确保“创建新的测试事件”单选按钮被选中,并选择“亚马逊 S3 Put”事件模板。应该为您提供类似于上面代码片段中的 JSON 数据。我们只关心 Lambda 函数中使用的数据,即桶名和对象键。编辑这两个值,使其适合于您之前创建的 S3 存储桶和 XML 文件。最后,为测试事件命名,并单击“Create”。

现在你已经有了 Lambda 函数的测试事件,你所要做的就是点击代码编辑器顶部的“test”按钮。控制台将告诉您功能代码是否被正确执行。要检查是否一切正常,请转到您的 S3 存储桶,查看 XML 文件是否已经移动到新创建的“gas-meter3/”目录中。

你可能已经注意到了,通过控制台进行测试的一个缺点是 Lambda 函数实际上会与其他 AWS 服务进行通信。这可能会无意中改变您的 AWS 资源,甚至丢失有价值的工作。这个问题的解决方案是在你的机器上构建并运行你的 lambda 函数。局部测试 Lambda 函数并不简单。您需要使用像 SAM CLI 和 Localstack 这样的工具来完成这项工作。

6 -全部搞定!

现在,如果 XML 数据是本教程中指定的格式,Lambda 函数应该将上传到 S3 存储桶的“未排序”文件夹中的任何 XML 文件排序到单独的文件夹中。

我希望这篇文章能让你体会到使用 AWS Lambda 可以实现什么,以及对无服务器功能的一些总体认识。 现在是你用 AWS Lambda 发挥创造力的时候了。

感谢您的阅读!

无服务器 GPU 驱动的机器学习模型托管

原文:https://towardsdatascience.com/serverless-gpu-powered-hosting-of-machine-learning-models-9f2b2be98294?source=collection_archive---------11-----------------------

Algorithmia 的一个工作示例

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

卡斯帕·卡米尔·鲁宾在 Unsplash 上的照片

动机

随着近年来 MLOps 的兴起,运行机器学习模型进行推理任务变得容易多了。根据使用情况,适当优化的深度学习模型甚至可以直接在移动设备上运行。在客户端-服务器/微服务架构中,具有高精度要求的较大模型通常集中托管,并由下游服务通过定义明确的接口进行查询。TensorFlow Serving 等工具现在也使这些用例在适当配置的服务器基础设施上成为可管理的问题。

然而,从软件工程的角度来看,我们知道自我管理的基础设施会变得多么复杂。毫不奇怪,云提供商的无服务器解决方案在应用程序开发领域越来越受欢迎。没有基础设施管理和随用随付是主要优势,这就是为什么我现在几乎只使用这种解决方案。

2021 年的无服务器 GPU

然而,当我发现自己处于将一个相当复杂的用于在线预测的深度学习模型集成到这样一个微服务的无服务器架构中时,我有些惊讶。在我的用例中,要求是以不规则的时间间隔(几秒到几小时)用 base64 编码的图像处理单个请求,并使用自我训练的深度学习模型返回正确的类。在我看来,一个没有深度复杂性的标准任务。被 Cloud Run,Cloud Functions,AWS Lambda 等宠坏了。,我天真地认为应该有一个“GPU 启用”复选框,然后我们就开始了…

不完全是。事实上,找到一个真正的无服务器解决方案并不容易。正如已经描述过的这里的,传统的无服务器解决方案更适合 CPU 工作负载。在我的例子中,仅使用 CPU 进行推理是不可能的,因为这种方式无法满足服务的延迟需求。

Google AI 平台预测和 AWS SageMaker?

与此同时,拥有人工智能平台预测的谷歌和拥有 SageMaker 的 AWS 提供了包括深度学习模型推理加速器在内的解决方案。只是简单总结一下为什么这些服务不符合我的要求(目前)。

从 AWS SageMaker 开始,最小实例计数要求为 1 或更高(https://docs . AWS . Amazon . com/sage maker/latest/DG/endpoint-auto-scaling-prerequisites . html)。对于许多持续负载的用例来说,这应该不是问题。然而,对于我来说,这将是一种资源浪费,并且不是 100%符合我所寻求的量入为出原则。

Google AI 平台预测目前只允许使用 TensorFlow SavedModel 格式的 GPU。例如,PyTorch 模型只能在没有 GPU 支持的定制容器(目前是预 GA)中使用。此外,谷歌确实允许自动缩放到 0,但如果一个请求触发了你的服务,你将被收取最少 10 分钟的计算时间,即使这个请求只花了几分之一秒(【https://cloud.google.com/ai-platform/prediction/pricing】T2)

algorithm ia——真正的无服务器替代方案?

除了主要的供应商, Algorithmia 正在吹捧自己填补了真正无服务器 GPU 模型托管市场的空白。Algorithmia 提供了具有模型版本控制、无服务器基础设施和透明的现收现付选项的 MLOps 管道。与谷歌人工智能平台预测相比,你放弃了选择计算资源的灵活性(你必须相信 Algorithmia,他们为你的服务分配了足够的 CPU、RAM 和 GPU 资源),但作为回报,你只需支付算法的实际计算时间,并获得真正的无服务器体验。

例如,您还可以通过使用常见的 python 代码实现单个函数来完全定制预处理和后处理步骤。一个已部署的算法可以作为一个带有预测端点的 REST-API 来使用,并且可以用一个 API 密钥来保护。实际执行时间是从算法的起始点开始计算,直到它返回。

目前,服务的 CPU 版本收费为 0.0001 美元/秒,GPU 服务收费为 0.0003 美元/秒。付款以 Algorithmia 信用计算,而 10,000 信用相当于 1 美元。每个月你可以免费获得 5000 积分。听起来至少对我的要求来说是完美的匹配。所以我们来看看。

用 Algorithmia 实现一个工作示例

注册后,您可以切换到您的主页部分,它为您提供了当前算法的清晰概述。您可以通过点击“新建”按钮并选择“算法”来添加一个新的。

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

Algorithmia 主屏幕

给你的算法起一个好听的名字,选择你是想在 GitHub 还是 Algorithmia 上托管代码,指定一个预定义的环境(比如 Python 3.8 + TensorFlow GPU 2.3),你就可以开始了。创建第一个算法后,您可以将新的存储库克隆到您的本地计算机上,或者直接使用 Web IDE。让我们继续使用 Web IDE 进行测试。

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

Algorithmia Web IDE

这看起来很眼熟。左边是您的项目结构,中间的主要区域显示您的代码。我已经为这篇文章准备了一个简单的例子,你可以从下面复制。

这里实际发生了什么…在一些必要的导入之后,我们首先定义一个函数,它基本上接受一个 base64 字符串作为输入,并返回一个图像对象。接下来,我们从 TensorFlow Hub 加载一个用于图像分类的预训练模型。在我们的例子中,它是一个 Mobilenet V2,被训练来分类 1000 个不同的类。你也可以将自己的模型免费上传到 Algorithmia 数据商店,或者使用 Dropbox 或 S3。由于模型输出是代表图像类别的单个整数,我们必须加载对应于这些整数的相应标签。现在,我们可以实现强制应用功能。

每当客户端向我们的服务发送 POST 请求时,都会调用该函数,并且将主体作为输入提供给该函数。确保在应用函数之外加载模型,以避免每次请求服务时重新加载。在我们的例子中,我们期望一个代表图像的 base64 字符串。由于我们的模型只需要 224×224 像素的图像,我们必须相应地缩放输入,将其转换为预期的 numpy 数组结构,并将所有像素值转换为 0 到 1 之间的范围。最后,我们检查我们是否真的有可用的 GPU,并返回一个带有 GPU 数量和输入图像的预测类别的格式化字符串。

要构建项目,您必须以熟悉的 requirements.txt 格式指定必要的依赖项。因此,单击依赖项并相应地调整条目。

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

Algorithmia 需求编辑器

现在我们可以开始建造了。单击右上角的绿色构建按钮,等待该过程完成。尤其是第一次做这一步,可能需要一段时间。根据我的经验,构建应该在大约 3-5 分钟后准备好。构建过程完成后,您会在 Web IDE 底部的控制台中看到一个输出,表明您的算法现已联机。您可以通过直接将输入粘贴到控制台来测试该算法。我们在这里跳过这一步,直接部署模型。因此,点击右上角的“发布”按钮,指定一个发布说明和一个你喜欢的示例输入,最后将可调用性指定为“私有”,点击“发布版本 x.x.x”。

要从外部请求您的服务,您现在需要一个 API 密钥。在您的 Algorithmia 主页部分,再次单击“新建”,这次选择“API 密钥”。给你的密钥起个名字,现在选择“完全访问”。例如,以后你可以指定只允许调用特定算法的键。

现在我们准备好出发了。例如,我们编写了一个简单的 python 脚本,它加载一个图像,将其转换为 base64 字符串,并向我们新创建的服务发出请求。为了检查模型的结果,我们使用下面的狮子图片。

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

罗伯特·蒂曼在 Unsplash上的照片

代码使用了 Algorithmia 包,但是您也可以使用简单的 POST 请求。有关请求服务的可能选项列表,请单击 Algorithmia 主页部分中的算法,向下滚动到“安装和使用”并选择您的首选选项。

输出应该是这样的:Num GPUs: 1 and prediction class: lion

瞧,你有一个可用的 GPU,它实际上是一只狮子!

结论

在写这篇文章的时候,Algorithmia 是唯一一个真正的无服务器平台,可以为 GPU 支持的模型提供服务,你只需要为实际的计算时间付费。因此,Algorithmia 非常适合请求数量相当少(没有恒定负载)的用例。在我的实验中,我注意到在没有请求的特定时间之后,算法必须为下一次调用完全重新加载(冷启动)。这导致了长时间运行的第一个请求。随后的查询又相当快了。这不是 Algorithmia 的无服务器解决方案的特定行为,但仍然应该作为一种限制来提及。对于真实的在线预测用例,这并不理想。如果你需要即时的答案,请记住这一点。在这些情况下,你可能应该考虑 Google AI 平台预测,其中至少有一个节点始终处于准备状态。另一种选择是通过从另一个服务发送定期查询来保持您的服务“温暖”,但是请记住,这增加了成本。否则,Algorithmia 是一个超级易用的无服务器机器学习平台,所以如果你的用例符合,我肯定建议你尝试一下。

基于顶点人工智能的无服务器机器学习管道:介绍

原文:https://towardsdatascience.com/serverless-machine-learning-pipelines-with-vertex-ai-an-introduction-30af8b53188e?source=collection_archive---------2-----------------------

谷歌终于做到了,现在梦想成真了:我们现在能够从以前的人工智能平台运行无服务器的 Kubeflow 管道

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

照片由米切尔罗Unsplash

对于在小公司(或小团队)工作的数据科学家和 ML 工程师来说,有一个大问题:人力资源和时间的极度缺乏。正因为如此,我们能够使用甚至测试的技术范围非常有限。

在 MLOps 方面,范围是一个问题。GCP 上没有任何托管的 MLOps 管道解决方案,采用实验管道的唯一方法是部署一个成熟的 Kubeflow 实例。我们可以依靠人工智能平台管道,进行半管理部署,但 GKE 集群保姆仍然存在问题,这需要时间(而且很无聊)。

Vertex AI 从天而降,用一种管理有序且价格合理的替代方案来解决我们的 MLOps 问题。Vertex AI 附带了所有的 AI 平台经典资源,加上一个 ML 元数据存储,一个完全管理的功能存储和一个完全管理的 Kubeflow Pipelines runner。

在这篇文章中,我们将讨论 ML 管道,Kubeflow 管道,如何创建它们来满足您的自定义 ML 需求,以及如何在 Vertex AI 管道中运行它们并分析它们的结果,并附有一个小的示例代码。

如果你只是为了示例代码而来,那么这里就是了。

快速回顾一下 MLOps

顶点 AI docs 状态:

机器学习操作( MLOps )是将 DevOps 策略应用于机器学习(ML)系统的实践。DevOps 策略让您高效地构建和发布代码变更,并监控系统以确保您满足可靠性目标。

MLOps 扩展了这一实践,以帮助您减少从数据接收到在生产中部署模型所花费的时间,从而让您能够监控和了解您的 ML 系统。

总之,MLOps 是让您“组织”您的数据科学和 ML 领域以创建可靠系统的实践,以满足您公司的需求。

因此,要应用良好的 MLOps 实践,您需要可靠、易用的工具,以便您可以管理、监控和执行所有数据作业,从接收到建模再到监控。

管道、库伯流和顶点

要应用 MLOps,最重要的步骤之一是实验,因此我们需要一个强大的实验工具。我们希望能够跟踪我们的实验,比较它们,重现它们,并保存所有使用的结果和数据。

Kubeflow 管道来解决这个问题。简而言之,KFP 是一个致力于在 Kubernetes 上运行 ML 工作流(作为模型训练的实验)的工具包,它以一种非常聪明的方式完成它:

与其他方法一样,Kubeflow 让我们将工作流定义为一系列 Python 函数,这些函数相互传递结果和工件。

对于每个 Python 函数,我们可以定义依赖关系(对于所使用的库), Kubeflow 将创建一个容器,以隔离的方式运行每个函数,并将任何想要的对象传递给工作流的下一步。我们可以设置所需的资源(如内存或 GPU),它将为我们的工作流步骤提供这些资源。感觉像魔术一样。

一旦您运行了您的管道,您将能够在一个漂亮的 UI 中看到它,就像这样:

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

来源:作者打印,运行示例开放源代码

唯一的问题是 Kubeflow 管道必须部署在 Kubernetes 集群上。如果你在一家使用敏感数据的小公司工作,你将面临权限、VPC 以及部署和使用它的许多问题,这使得它有点难以被采用

Vertex AI 通过一个托管管道运行器解决了这个问题:你可以定义一个管道,它将执行它,负责提供所有资源,存储所有你想要的工件,并通过每个想要的步骤传递它们。

我们现在将看到如何使用 sklearn breast_cancer_dataset 定义 Kubeflow 管道并在 Vertex AI 中运行它。

定义管道:带有玩具数据集的定制示例

我们现在用 3 个简单的步骤定义一个管道,在 KFP 称为…

  1. 接收数据并分离训练和测试分割。
  2. 使用步骤 1 中分离的列车,训练出模型。
  3. 使用步骤 2 中的模型和步骤 1 中的测试分割,评估我们的 ROC 曲线和混淆矩阵模型。

首先,让我们安装 Kubeflow Pipelines SDK:

pip3 install kfp --upgrade

你可以在这篇文章的 Github repo 中看到完整的 Jupyter 笔记本。我们将在这里仔细检查每个代码块,使其更容易理解。首先,一些进口:

我们从kfp.v2导入,因为它是新的 Kubeflow Pipelines SDK 版本,与 Vertex AI 兼容。我们引入了代表“特定领域语言”的dsl,因为它是管道定义 SDK 的主要模块。

我们从kfp.v2.dsl导入工件、数据集、输入、模型、输出、度量和分类度量,因为它们是我们在组件之间传递对象的方式。当我们定义一个组件时,我们在参数类型上声明 can state,暗示组件的输入和输出。

这样,它创建了一个具有“path”(用于在组件之间存储和重用对象)和“metadata”(用于存储对象元数据)属性的对象,还创建了一些特定于类型的方法,如 ClassificationMetrics 方法,用于在 UI 上绘制漂亮的 ROC 曲线。

让我们看看它在第一个例子中是如何工作的,这个例子是get_data操作符:

注意,我们没有返回任何值,但是我们将组件的参数定义为dataset_train: Output[Data]。这意味着,在函数上,我们可以访问类数据集的输出对象(将在函数的使用中创建),带有路径和元数据属性。

这样,您可以将数据集保存在特定的路径上,并在需要时在下一个操作符上访问它。调用对象组件后,可以访问它的outputs属性。例如,如果你想访问dataset_train对象,你可以在定义完整管道时使用:ds_train = get_data().outputs["dataset_train"]来完成。

我们还使用了@component装饰器,在这里我们可以定义创建能够运行我们功能的容器所需的包。

对于 train 步骤,我们将使用我们的一个输出对象,并访问之前创建的一个对象。让我们看看这是怎么做到的:

我们所要做的就是定义dataset: Input[Dataset],如果我们在调用组件时传递get_data().outputs["dataset_train"],它将访问dataset_train对象,并通过使用它的path属性下载它。

注意,我们还为我们的模型定义了一些元数据:train_score表示模型在训练时间中的得分,它的framework

这个逻辑在我们的最后一个组件上继续:对训练数据集的模型评估:

我们在这里新做的是传递输出指标和分类指标对象。这将让我们在顶点 AI UI 上为 ROC 曲线和混淆矩阵保存模型分类指标和一些漂亮的交互图。

完成所有工作后,我们只需创建管道并将其编译成一个 json 文件:

请注意,我们可以访问前面步骤的输出。我们把它编译成一个 json 文件,然后可以提交它在 Vertex AI 上运行。确保你在你的 GCP 项目上激活了顶点人工智能,并且你在 GCP 上被正确认证。

检查用户界面

恭喜你。点击 jupyter 上的链接,您将被引导至管道运行。您会看到类似这样的内容:

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

来源:作者。从我的 GCP 控制台打印。

您还可以检查度量图:

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

来源:作者,来自我的控制台的美丽打印

很漂亮,对吧?

结论

就是这样。有了 Vertex AI,你将拥有更轻松更美好的生活,拥有所有与 MLOps 相关的事物。在顶点管道中还可以做更多的事情,比如使用 TFx 或其他顶点人工智能工具作为特征库。每一个试图举办盛宴的人都知道我在说什么。

如果你确实喜欢这篇文章,在 Github 上开始回购,在 LinkedIn 上 ping 我,或者做任何你想做的事情。如果你有任何反馈,对帖子的修正,或者只是想谈谈,请联系我们。

我是数据科学家@ Acordo Certo,也是机器学习领域的谷歌开发者专家。我是 MLOps 的拥护者,对 Vertex AI 一见钟情。

以下是一些其他链接:

https://github.com/piEsposito/vertex-ai-tutorials https://github.com/piEsposito https://www.linkedin.com/in/piesposito/

AWS 上的无服务器 ML

原文:https://towardsdatascience.com/serverless-ml-is-this-the-cheapest-way-to-host-machine-learning-models-on-aws-83ba3dee8be4?source=collection_archive---------23-----------------------

这是托管机器学习模型最便宜的方式吗?

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

影像经 跋元素许可给菲尔·惠兰

我最近在上制作了一个视频,使用 vast.ai 廉价地构建机器学习模型。这对于像我这样想要在没有预算的情况下构建模型的人来说很有用。使用 vast.ai (我不隶属于他们),我能够构建合理大小的模型,例如基于resnet 152(152 层 CNN)的图像分类模型,只需几美元。我的工作流程是跳到一个 vast.ai GPU 上,比如 RTX 3090,每小时支付 80 美分,做一些训练,做分析,然后跳回到我的笔记本电脑上,进一步制定我的攻击计划。如此反复几次,我就可以走了。

但是去哪里?

理想情况下,您希望将您的模型托管在 GPU 上,以便进行快速推理。但是对于很多型号正常的快速推理可以在合理的 CPU 上实现。即便如此,一个模型可能会占用几千兆字节的内存,你需要把它放在云中的某个地方。你可以获得每小时几美分的低成本云托管服务。但是这些时间累积起来,如果您想要托管多个模型,如果您的工作流看起来像我的工作流,您的模型推理成本可能会大大超过您的模型构建成本。

我没有明显的初始收入流来自我的模型来支付他们的托管,但我想建立一些模型,并托管他们。如果我友好的邻居弗雷德太忙而没有时间去看,那么我就不想支付闲置模特的托管费用。这就是“无服务器”的用武之地。

无服务器

无服务器是良好的不稳定流量模式。“无服务器”不是无服务器。你还在用服务器。你只是以黑盒上下文切换的方式与他人分享它们。您和服务器之间的不透明关系意味着很难针对您的特定用例优化底层服务器。该服务器的不同用户之间的上下文切换意味着,在您不知道的情况下,资源被不断地载入和载出。这些低效率是有代价的,但是你为少得多的使用支付的每使用额外费用意味着每个人都是赢家。

随着利用率的提高,这些经济性对消费者来说显然变得不那么有吸引力了,但是您的云提供商将尝试尽可能地通过缓存和相同的服务器重用来缩小差距。

EC2 vs SageMaker vs Lambda

当我开始寻找在 AWS 上托管机器学习模型的选项时,我发现几乎所有的路都通向亚马逊 SageMaker,但我发现长期托管成本仍然超出了我的预算。从那时起,我开始研究 AWS Lambda 是否能做到这一点。

为了比较成本,最好看看等效的 EC2 实例。AWS Lambda 为您提供 6 个 vCPUs 和高达 10Gb 的 RAM。我能看到的最接近的 EC2 实例是一个 c5.2xlarge ,有 8 个 vCPUs 和 16 GiB RAM。这台机器在 EC2 上是每小时 0.34 美元,在 SageMaker 上是 0.476 美元。我对 SageMaker 还不够熟悉,无法辨别其中的区别,而且我的主机需求也很简单,所以还是 0.34 美元吧。每月 244 美元,每年将近 3000 美元。这将会增加业余爱好者的预算,从而激发我寻找其他选择的欲望。

无服务器成本

https://aws.amazon.com/lambda/pricing/为我们提供了一个计算器,用于确定托管我们模型的成本,即内存(RAM)乘以时间。

我的测试表明,对于我的模型,每个请求需要 720Mb 到 860Mb 的 RAM,这取决于请求包含的图像量。我用 1024Mb 给 20%的开销。

并非所有的请求都花费相同的时间。如果没有人使用这个模型,它就不在 RAM 中。如果它不在 RAM 中,就需要加载 Python 代码,目前大约需要 10 秒钟。

10 秒的冷启动请求时间似乎很长,但如果价格合适,这是可以承受的,也是一个公平的权衡。如果模型变得更受欢迎(这是一个好问题),那么这个启动时间可能会更少。

非冷启动请求电流需要大约 1.5 秒,这也不是很大。但是电脑在表演魔术,你想要什么?!还有一些优化我没试过,比如用 pillow-simd

冷启动和非冷启动请求之间的成本差异的大小意味着总成本在很大程度上取决于请求模式。为了简单起见,让我们假设我每天收到 1000 个请求,它们都是冷启动。现在,碰巧的是,这正好在 AWS 的免费等级之内,它将花费我高达 0 美元。但是我们希望这种方法是可持续和可扩展的,因此我们将在计算中忽略自由层。

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

如你所见,即使我每天有 1000 次点击,我一个月也只花 5 美元。如果达到每天 1,000,000 个请求,那么我们会看到更少的冷启动,持续时间会更接近 1,500 毫秒。这将把它放在每月 756 美元,虽然我可能会在此之前看其他优化。我还会有更多关于内存使用的统计数据来压缩我添加的 20%的 RAM 缓冲区。但总的来说,我会比没有服务器的人活得长,如果我能在回答风投关于我新的热门模型的电话之间找到一些时间,我会把它转移到持久的机器上,进行一些进一步的优化,加入一两个 GPU,然后…你明白了。

寒冷开始升温

为了让 10 秒的 Lambda 函数启动时间变得更容易忍受,我做了两件关键的事情。

第一个是对加载模型的 Lambda 函数的一次性请求,但是没有使用模型。这是我的“醒了!”当你访问模型所在的网页时,我调用它。人类是相当慢的(无意冒犯),当他们弄清楚网页是关于什么的时候,选择一张图片上传或者输入一些文本,你已经进入了 10 秒钟。在发送实际的模型请求时,函数应该已经准备好了。这可能会使请求的数量翻倍,但只会增加我 15%的成本(10 秒+1.5 秒),因为我是根据请求的持续时间付费的。不能保证 AWS 在后台会对这些请求做什么,但是缓存你的函数符合他们的利益,在实践中,这看起来做得足够好了。

第二个“优化”是简单地添加一个可视化的进度条,开始很快,然后越来越慢,直到请求完成,然后跳到结束。这足以分散我们的注意力,确保我们至少有 10 秒钟的时间,直到人们开始怀疑互联网的力量。对于耗时较长的车型,我不太清楚。等待音乐?

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

Progressbar 正在运行

对等

这种无服务器路线的最大优势显然是成本。这不是 GPT-3 ,但我服务于一个相当大的 152 层 CNN 模型,这是一个有能力的架构。它仍然可以很好地执行推理,而不需要 GPU。现在,除了血汗资本,我什么也没花。

下降趋势

最大的缺点是架构和部署的复杂性。在上找到这篇关于用 AWS Lambda 进行机器学习推理的帖子后,我开始走上了 AWS API Gateway + AWS Lambda + AWS EFS 的道路。

AWS Lambda 是一种无服务器计算服务,按使用付费。然而,像 XGBoost 这样的 ML 框架太大了,不适合 250 MB 的应用程序工件大小限制,或者 512 MB /tmp 空间限制。虽然你可以将包存储在亚马逊 S3 并下载到 Lambda(最大 3 GB),但这可能会增加成本。

为了解决这个问题,Lambda 函数现在可以挂载一个 Amazon 弹性文件系统(EFS)。这是一个可扩展的弹性 NFS 文件系统,在多个可用性区域(AZ)内和之间存储数据,以实现高可用性和耐用性。

此设置要求您将代码部署到 AWS Lambda 和 AWS EFS 卷。因此,您必须确保在两个地方都部署了兼容的代码。

如果您正在使用 joblib 来持久化模型,就像我和上面的帖子所建议的那样,那么在 EFS 卷上特定于版本的 lib/目录中安装了 Python 依赖项之后,您将希望从同一个 EFS 卷中执行该操作。模型再水合时的任何不匹配都将导致停机。

到目前为止,我还没有解决这方面的 CI/CD 复杂性,因为我已经感觉到它正在走一条过于复杂的道路。我想退一步,写这篇博客,思考什么是更好的解决方案。

也许码头工人能帮上忙。这是我接下来要研究的东西。

结论

做 CI/CD 的困难和 Lambda + EFS + API Gateway 的复杂性(API Gateway 非常复杂)使得这很难推荐给其他人。虽然,当我看着我预计的 3 月份 AWS 账单时,它只有 6.72 加元,但很难就其价值进行争论。这包括用于前端的 CloudFront + S3、VPC、Route53 和我用于电子邮件的 se。当然,没有流量是有帮助的。

贾斯汀·平克尼在上发表了一篇文章,在 GCP 上主持卡通。乍一看,这似乎是一个更简单的选择,至少在基础设施方面是如此。冷启动请求延迟似乎更长,但他的模型更大。

我可能会跟进更多关于基础设施如何连接在一起以及我如何使用 Terraform Cloud 和 CircleCI 部署这些基础设施的细节,但如果您对某些特定的东西感兴趣或者想告诉我更好的方法,请告诉我。

如果你对踢轮胎感兴趣,你可以找到我在 https://dogedreams.ai/举办的最新模型

祝你愉快!

使用 Docker、AWS Lambda 和 API 网关的无服务器模型托管

原文:https://towardsdatascience.com/serverless-model-hosting-with-docker-aws-lambda-and-api-gateway-2d79382ecb45?source=collection_archive---------6-----------------------

充分利用 Lambda 中的 Docker 支持来托管您的模型,而无需专用服务器。

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

由 Markus Spiske 在 Unsplash 上拍摄的图片

以前,AWS Lambda 部署包被限制在 250MB(包括需求)的最大解压缩大小。当试图使用该服务托管机器学习模型时,这被证明是一个障碍,因为常见的 ML 库和复杂的模型导致部署包远远超过 250MB 的限制。

然而在 2020 年 12 月,AWS 宣布支持将 Lambda 函数打包和部署为 Docker 镜像。在机器学习的背景下,这些图像的大小最大可达 10GB。这意味着图像中可以包含大型依赖关系(例如张量流)和中等大小的模型,因此可以使用 Lambda 进行模型预测。

在本文中,我们将通过一个示例来构建和部署 Lambda 上的模型托管。所有使用的相关代码都可以在这里找到。

建筑概述

该解决方案可以分为三个部分:

  1. Docker 映像:Docker 映像包含我们的依赖项、训练好的模型管道和功能代码。AWS 为各种运行时提供了一个基本映像,可以在其上构建以确保与服务的兼容性。
  2. Lambda Function :基于输入事件/请求运行 Docker 映像中的功能代码的无服务器资源。
  3. API 网关端点:用作 Lambda 函数的触发器和客户端请求的入口点。当在端点接收到预测请求时,Lambda 函数被触发,请求体包含在发送给该函数的事件中。然后,该函数返回的值将作为响应返回给客户端。

型号

在这个例子中,我们的模型将是在虹膜分类数据集上训练的简单 KNN 实现。本文不涉及培训,但结果是一个 scikit-learn Pipeline 对象,由以下对象组成:

1.StandardScaler:根据训练样本的平均值和标准偏差标准化输入。

2.KNeighborsClassifier:实际的预训练模型。用 K = 5 训练。

使用 scikit-learn 的 Joblib 实现将管道保存到’ model_pipeline.joblib '中。

功能代码

让我们首先考虑 Lambda 将用来处理预测请求事件的函数代码(predict\app.py)。

Lambda_handler 拥有 Lambda 使用的函数所需的参数。管道对象在处理程序之外加载,以避免在每次调用时加载。Lambda 会让容器在一段时间内保持活动状态,直到没有事件发生,所以在创建时加载一次模型意味着它可以在容器被 Lambda 保持活动状态时被重用。

处理函数本身非常简单;从事件主体中提取所需的输入,并用于生成预测。预测作为 JSON 响应的一部分返回。API 网关会将函数的响应返回给客户端。进行一些检查以确保输入符合预期,并捕捉和记录任何预测错误。

码头工人图像

Dockerfile 文件的结构如下:

1.拉 AWS 的基本 Python 3.6 图像

2.将所需文件从本地目录复制到映像的根目录

3.安装要求

4.运行处理函数

部署

为了管理部署和 AWS 资源,我们将使用 AWS 无服务器应用程序管理器(SAM) CLI *。*安装 SAM 及其依赖项的说明可以在这里找到。

要使用 SAM 进行构建和部署,必须配置模板文件。这用于指定所需的 AWS 资源和相关配置。

对于此项目,SAM 模板包含以下内容:

  • 杂项信息,如堆栈名称和 Lambda 超时的全局配置。
  • MLPredictionFunction 资源:这是我们要部署的 Lambda 函数。本节包含所需配置的大部分内容:
  • 属性:这里我们指定将使用 Docker 映像( PackageType: Image )来定义该函数,并且该函数将通过 API 网关( Type: API )来触发。API 路径路由名称和类型也在这里定义。
  • 元数据包含将用于构建图像的标签和用于构建图像的 docker 文件的位置/名称。
  • Outputs 列出了将由 SAM 创建的所有必需资源。在这种情况下,SAM 需要的是 API 网关端点、Lambda 函数和关联的 IAM 角色。

运行以下命令,使用定义的 SAM 模板在本地构建应用程序映像:

!sam build

如果成功,可以使用以下命令通过示例事件在本地调用该函数(参见 repo 中的示例事件):

!sam local invoke -e events/event.json

一旦在本地测试了该功能,就需要将图像推送到 AWS ECR。首先创建一个新的存储库:

!aws ecr create-repository --repository-name ml-deploy-sam

在推送映像之前,您需要登录 ECR 的托管 Docker 服务:

!aws ecr get-login-password --region <region> | docker login --username AWS \ --password-stdin <account id>.dkr.ecr.<region>.amazonaws.com

现在,您可以使用以下工具部署应用程序:

!sam deploy -g

这将在“引导”模式下运行部署,您需要确认应用程序的名称、AWS 区域和之前创建的图像存储库。在大多数情况下,接受其余设置的默认选项应该没问题。

然后将开始部署过程,并提供 AWS 资源。完成后,每个资源都将显示在控制台中。

考虑

  • 映像更新:要部署更新的模型或功能代码,您可以简单地在本地重建映像并重新运行 deploy 命令。SAM 将检测应用程序的哪些方面发生了变化,并相应地更新相关资源。
  • **冷启动:**每次 Lambda 使用我们的功能代码旋转一个容器时,模型将在处理开始前被加载。这导致冷启动场景,其中第一个请求将比后面的请求慢得多。解决这个问题的一个方法是使用 CloudWatch 定期触发函数,这样容器就可以随时加载模型。
  • **多个功能:**可以部署多个 Lambda 功能,由一个 API 提供服务。如果您有多个模型要服务,或者如果您想要有一个单独的预处理/验证端点,这可能是有用的。要对此进行配置,您只需在 SAM 模板资源中包含附加功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值