Python 中的装饰函数
什么是高阶函数?
在这篇文章中,我将解释什么是 Python decorators,以及如何实现它。我们开始吧!
什么是室内设计师?
装饰器只不过是一种调用高阶函数的舒适方式。你可能已经看过很多次了,它是关于那些“@dostuff”字符串的,你会不时地在函数的签名上面找到它们:
@dostuff
def foo():
pass
好的,但是现在,什么是高阶函数?高阶函数就是任何一个以一个(或多个)函数作为参数和/或返回一个函数的函数。例如,在上面的例子中,“@dostuff”是修饰者,“dostuff”是高阶函数的名称,“foo”是被修饰的函数和高阶函数的参数。
安全了吗?太好了,让我们开始实现我们的第一个装饰器吧!
打造我们的第一个室内设计师
为了开始实现我们的装饰器,我将向您介绍 functools : Python 的高阶函数模块。具体来说,我们将使用包装函数。
让我们创建一个高阶函数,它将打印被修饰函数的执行时间:我们称它为“timeme”。这样,每当我们想要计算函数的执行时间时,我们只需要在目标方法的签名上添加装饰符“@timeme”。让我们开始定义“timeme”的签名:
def timeme(func):
pass
如前所述,一个高阶函数将另一个函数(修饰函数)作为它的参数,所以我们在它的签名中包含了“func”。现在,我们需要添加一个包含计时逻辑的包装函数。为此,我们将创建一个“包装器”函数,它将被 functools 的包装器函数包装:
from functools import wrapsdef timeme(func):
@wraps(func)
def wrapper(*args, **kwargs):
pass return wrapper
注意,“timeme”返回函数“wrapper ”,该函数除了打印执行时间之外,还将返回修饰函数的结果。
现在,让我们通过实现计时逻辑来完成包装器:
from functools import wraps
import timedef timeme(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Let's call our decorated function")
start = time.time()
result = func(*args, **kwargs)
print('Execution time: {} seconds'.format(time.time() - start))
return result
return wrapper
注意,修饰函数“func”是用它的位置和关键字参数执行的。我添加了一些打印消息,供您观察执行顺序。好吧!让我们试一试,我将创建一个简单的函数,带有一条打印消息,用“timeme”来修饰:
@timeme
def decorated_func():
print("Decorated func!")
如果您运行它,您将看到如下内容:
Let's call our decorated function
Decorated func!
Execution time: 4.792213439941406e-05 seconds
如您所见,第一个打印消息被放在高阶函数中。然后,我们调用修饰的函数并打印它自己的消息。最后,我们计算执行时间并打印出来。
重复数据删除
是的,这就是我想帮你解决的问题。删除那些造成伤害、阻碍某些任务的效率甚至污染我们系统的肮脏的小副本。
重复数据删除
/diːˌdjuːplɪˈkeɪʃ(ə)n/名词消除重复或多余的信息,尤其是计算机数据。
“重复数据删除在存储之前删除重复信息”
正如定义所说,我们要做的任务是删除重复的文本/句子等等。这只不过是检查文本彼此有多相似的行为。他们可以一模一样的像:
深度学习牛逼!和深度学习牛逼!。或者,就句子试图传达的内容而言,它们可能非常相似,比如:
深度学习太棒了!和深度学习太酷了。 我们知道这两句话传达的是同一个东西,这也是我们希望我们的机器捕捉到的东西。
这样的任务在文献中被称为语义文本相似性(STS)。它处理确定两段文本有多相似。这将不仅包括句法相似度,即两个句子中使用的单词有多相似或相同,还包括语义相似度,它捕捉了使用两个句子所传达的内容的相似度,即文本的含义在确定相似和不相似方面起着重要作用。
问题
问题。是的,这是我们的主要目标。来解决问题。我给你举个例子。比方说,你必须通过电子邮件向一群人发送非常有趣的笑话(你的笑话可以是一句话或一串话)。你的老板要求你确保人们不会收到同样的笑话。所以你必须确保你所有的笑话都是独一无二的,人们不会对其内容感到厌烦。
什么工作,认真?
作为一名出色的程序员,你决定自动完成这项任务。你有这个神奇的 API,可以免费给你很多笑话,你写一个脚本,把这些笑话发给你老板喜欢的那群人。但是,我们不能真的相信这个神奇的 API,不是吗?简直*神奇。*API 给你开类似的玩笑怎么办?你不能冒险惹恼你的老板。
这是你可以使用 重复数据删除引擎 的地方,确保发送的笑话不会与过去发送的笑话相似。
我在这里的主要目的不是谈论这些模型。而是为了帮助您在实际工作中使用它们,就像上面提到的那样。我承认,为了给你的老板留下深刻印象而向别人发送笑话并不实际。
在 STS 的空间里…
让我们试着把它分解成这种相似性度量是如何定义的,以及我们试图找出哪两个实体之间的相似性(字面上是文本本身,还是别的什么?).
首先是,说到相似性度量,可以使用的有不少。只是为了完整起见,列举几个:
1。 Jaccard 相似度2。余弦相似度3。推土机距离4。詹森-香农距离
但是为了切入正题,我们将使用**余弦相似度。**数学上,余弦相似度是内积空间的两个向量(非零)之间相似度的度量,度量它们之间角度的余弦。
如果两个文档相似,并且在欧几里得空间中相距很远,它们仍然可以彼此非常接近。这是由余弦距离捕获的,因此是有利的。
**其次,**这个余弦距离我们用在哪里?成对的句子串之间?没有。这就是我们利用自然语言处理和深度学习的力量。我们使用向量。
一个单词/句子向量是一行实数值 (与虚拟数字相反),其中 每个点捕捉单词/句子的一个维度的含义 和 ,其中语义相似的单词/句子具有相似的向量。
同样,有很多方法可以得到这些向量。举几个:
单词嵌入 : word2vec、GloVe、BERT 单词嵌入、ELMo 等等。
语句嵌入 : BERT 语句嵌入,通用语句编码器等。
我将直接进入我亲自试验过的方法,这些方法对我非常有效。
[word2vec](https://github.com/mmihaltz/word2vec-GoogleNews-vectors) + [Universal Sentence Encoder](https://tfhub.dev/google/universal-sentence-encoder-large/3)
为了避免这篇文章成为一篇纯粹的面向实现的文章(这正是我们想要的),我将试着简单地解释一下这些模型是什么。
word2vec
word2vec 有两种变体: Skip-Gram 和**连续单词包模型(CBOW)。**如果你想寻找详细的解释,关于这两种变体有大量的材料。我会很干脆的。skip-gram 模型速度稍慢,但通常在处理不常用的单词时效果更好。因此,这是经常使用的。这个我们简单说一下。
你会在几乎所有的 word2vec (Skip-Gram model)博客和教程中找到这个图表。在这种架构中,模型使用当前单词来预测上下文单词的周围窗口。它对附近的上下文单词的加权比对远处的上下文单词的加权更重。
这里,我们看一个上下文单词的窗口(在这种情况下,每边 2 个单词),并尝试预测中心单词。
The Skip-gram model architecture (https://arxiv.org/pdf/1301.3781.pdf)
考虑 w(t) 是输入字,通常权重矩阵和输入向量 w(t) 之间的点积是由单隐层完成的。我们将 softmax 函数应用于隐藏层的输出向量和权重矩阵之间的点积。这给出了单词在当前单词位置出现在 w(t) 的上下文中的概率。
隐藏层中的矢量成为了这个单词的矢量表示。但是这些都是’*字’嵌入,*和我们要找的相似的’句子’。那么,我们如何得到句子的向量表示而不仅仅是单词嵌入呢?
一种简单而琐碎的方法(我今天将展示的方法)是简单地对该句子的所有单词的单词嵌入进行平均。很简单,不是吗?
现在对于主要部分,让我们把它编码进去。
w2vmodel = **gensim.models.KeyedVectors.load_word2vec_format**(
'models/GoogleNews-vectors-negative300.bin.gz'), binary=True) **def** sent2vec**(s)**:
'''
Finding word2vec vector representation of sentences @param s : sentence
'''
words = **str**(s).**lower**()
words = **word_tokenize**(words)
words = [w **for** w **in** words **if** **not** w **in** stop_words]
words = [w **for** w **in** words **if** w.**isalpha**()]
featureVec = **np.zeros**((300,), dtype="float32")
nwords = 0
**for** w **in** words:
**try**:
nwords = nwords + 1
featureVec = **np.add**(featureVec, w2vmodel[w])
**except**:
**continue**
# averaging
**if** nwords > 0:
featureVec = **np.divide**(featureVec, nwords)
**return** featureVec **def** get_w2v_vectors**(list_text1, list_text2)**:
‘’’
Computing the word2vec vector representation of list of sentences
@param list_text1 : first list of sentences
@param list_text2 : second list of sentences
‘’’
**print**(“Computing first vectors…”) text1_vectors = **np.zeros**((len(list_text1), 300))
**for** i, q **in** tqdm(enumerate(list_text1)):
text1_vectors[i, :] = sent2vec(q) text2_vectors = **np.zeros**((len(list_text2), 300))
**for** i, q **in** tqdm(enumerate(list_text2)):
text2_vectors[i, :] = sent2vec(q) **return** text1_vectors, text2_vectors
就是这样!🤷♂你有你的句子嵌入使用 word2vec 。
通用句子编码器
谷歌展示了一系列用于将句子编码成向量的模型。作者特别针对下游任务,即迁移学习任务。STS 就是这样一个任务。
它有两种变体:
1。一个带有 变压器 编码器
2。一用一 深度平均网络
他们每个人都有不同的设计目标:
1。以更大的模型复杂性和资源消耗为代价来实现高精度。
2。目标是以稍微降低的准确度进行有效的推理。
我已经用我最喜欢的博客将这两种架构都做了超链接,这些博客对它们都做了很好的解释。让我们更关注如何实现它们。
usemodel = **hub.Module**('models/sentence_encoder')**def** get_use_vectors**(list_text1, list_text2)**:
'''
Computing the USE vector representation of list of sentences
@param list_text1 : first list of sentences
@param list_text2 : second list of sentences
'''
**print**("Computing second vectors...")
messages1 = list_text1
messages2 = list_text2 num_batches = **math.ceil**(len(messages1) / BATCH_SIZE) # Reduce logging output.
**tf.logging.set_verbosity**(tf.logging.ERROR) message_embeddings1 = []
message_embeddings2 = [] **with** tf.Session() **as** session:
session.**run**([tf.global_variables_initializer(),
tf.tables_initializer()]) **for** batch **in** range(num_batches):
**print**(batch * BATCH_SIZE, batch *
BATCH_SIZE + BATCH_SIZE)
batch_msgs1 = messages1[batch * BATCH_SIZE: batch *
BATCH_SIZE + BATCH_SIZE]
batch_msgs2 = messages2[batch * BATCH_SIZE: batch *
BATCH_SIZE + BATCH_SIZE] message_embeddings1_temp, message_embeddings2_temp = session.**run**([usemodel(batch_msgs1), usemodel(batch_msgs2)])
message_embeddings1.**append**(message_embeddings1_temp)
message_embeddings2.**append**(message_embeddings2_temp) all_embedding1 = **np**.**concatenate**(**tuple**(message_embeddings1))
all_embedding2 = **np**.**concatenate**(**tuple**(message_embeddings2)) **return** all_embedding1, all_embedding2
再说一遍,就是这样!🤷♂
现在我们有了来自两个不同模型的笑话的句子嵌入。
现在我们需要余弦相似度!
**def** cosine_similarity**(list_vec1, list_vec2)**:
'''
Computing the cosine similarity between two vector representation
[@param](http://twitter.com/param) list_text1 : first list of sentences
[@param](http://twitter.com/param) list_text2 : second list of sentences
'''
cosine_dist = [cosine(x, y) **for** (x, y) **in** **zip**(np.nan_to_num(list_vec1), np.nan_to_num(list_vec2))] cosine_sim = [(1 - dist) **for** dist **in** cosine_dist] **return** cosine_sim
当我在你之前做这份工作时,我有一堆不重复的笑话,很少有重复的。具体来说,我有 385K 非重复对和 10K 重复对。我仅使用 word2vec 模型绘制了这项任务的 AUC-ROC 。
AUC-ROC
不错!曲线看起来很漂亮。(我故意省略了混淆矩阵)。
TPR/召回率/敏感度:77%
FPR:2.2%
让我们看看通用句子编码器的表现如何。
AUC-ROC
曲线下的区域稍微好一点,不是吗?
TPR/召回/敏感度:77%
FPR:2.2%
让我们看看当我们把它们结合在一起时会发生什么。通过组合,我的意思是平均来自两种方法的余弦相似性,并检查度量。“一个平均的集合的模型”。
迄今为止最好的一个!
TPR/召回/敏感度:78.2%
FPR:1.5%
喔喔喔!🎉🎉我们有一个明确的赢家!
这是一种快速查找重复项的方法。无需培训,只需下载现有的优秀模型并将其用于您的 STS 任务!
有了这一块,您可以轻松构建您的重复数据删除引擎。只需存储你第一天发送到老板小组的所有笑话,然后对于每个新来的笑话,将它们与之前看到的所有笑话配对,并使用这个集合模型来确定它们是否重复。如果是,就扔掉。
通过这种方式,让你老板的朋友开心,老板开心,得到一份不错的薪水,让你自己开心:)
使用 spark 的 MLlib 进行数据集重复数据删除
对于拥有大量数据的公司来说,重复数据删除过程始终非常重要。首先,重复数据删除最大限度地减少了存储业务数据所需的空间,并将为我们的管道带来更低的基础设施成本和更好的性能。另一方面,通过持续集成和持续交付 (CI/CD) ,减少重复的数量将降低管道的复杂性,并增加业务时间。
有时,重复数据删除过程由简单的文本到文本匹配组成,您可以简单地选择 CRC32 校验和或 MD5 匹配。然而,在一些情况下,数据集的行仅仅因为一些列上的一些小的文本差异而不同,即使它们表示相同的实体**。因此,本文展示了一个实体识别和链接过程**使用了两种不同的 spark 方法,对报废电子商务网站收集的特定产品数据集进行处理。
下面描述完整代码和过程可以在这里找到:
[## Ronald-Smith-angel/dataset _ 重复数据删除 _sparkml
使用 spark ML 库和 Scala-Ronald-Smith-angel/dataset _ de duplication _ spark ML 进行数据集重复数据删除
github.com](https://github.com/ronald-smith-angel/dataset_deduplication_sparkml)
一般的过程可以在这个特质上找到( …是的,我用 scala 做数据科学!!!):
package com.sample.utils
import org.apache.spark.sql.DataFrame
trait OperationsHelper {
def ds: DataFrame
def preparedDataSet()(df: DataFrame): DataFrame
def deduplicateDataSet()(df: DataFrame): DataFrame
def resultsDataFrame()(df: DataFrame): DataFrame
}
正如你将看到的,这个助手背后的想法将是有一个函数管道,从这里可以轻松地调用链数据帧 转换 。
预处理产品数据
数据科学界广泛使用降维技术来获得更小的特征集,以便在训练和评估模型时进行分析并获得更好的性能。PCA 方法允许降维,同时保留那些描述大量信息的特征。因此**,**该预处理阶段遵循以下步骤:
- 数据清洗: 清洗数据要有一个通用的刻度。对于产品的情况,数据集由一个简单的文本清理组成,包括大小写、空白、编码和符号。
- **特征选择:**使用 PCA 技术选择一组特征。(“标题块”、“内容块”、“颜色”、“产品类型”)
上述特性中的内容包含候选重复产品的大部分差异。
1 —方法 A:区分位置的散列法(LSH)
位置敏感散列是一种用于实体解析的技术,然后将找到代表相同实体的记录。spark MLlib 有一个自定义的 LSH 实现,这里使用它来查找如下重复项:
- 首先,使用所选特征的串联来生成散列(上面的 PC)。对于真实世界的例子,可以生成每个特征的散列。但是,对于这个示例,为了更快地获得结果,使用了一个简单的串联列。
- 然后,该列用于生成 LSH 向量,如下所示:
—分词器使用 单词停止器 为记录生成单词列表。
—计数矢量模型为 LSH 算法创建带有哈希和桶(类似哈希)的矢量。
**val** pccTokenizer = **new** Tokenizer()
.setInputCol(OperationsHelperLSH.*ConcatComments*)
.setOutputCol(OperationsHelperLSH.*ColumnWordsArray*)
**val** wordsArrayDF = pccTokenizer.transform(df)
**val** remover = **new** StopWordsRemover()
.setCaseSensitive(**false**)
.setStopWords(OperationsHelperLSH.*stopWords*)
.setInputCol(OperationsHelperLSH.*ColumnWordsArray*)
.setOutputCol(OperationsHelperLSH.*ColumnFilteredWordsArray*)
**val** wordsFiltered = remover.transform(wordsArrayDF)
**val** validateEmptyVector = *udf*({ v: Vector => v.numNonzeros > 0 }, DataTypes.*BooleanType*)**val** vectorModeler: CountVectorizerModel = **new** CountVectorizer()
.setInputCol(OperationsHelperLSH.*ColumnFilteredWordsArray*)
.setOutputCol(OperationsHelperLSH.*ColumnFeaturesArray*)
.setVocabSize(*VocabularySHLSize*)
.setMinDF(10)
.fit(wordsFiltered)
**val** vectorizedProductsDF = vectorModeler.transform(wordsFiltered)
.filter(validateEmptyVector(*col*(OperationsHelperLSH.*ColumnFeaturesArray*)))
.select(*col*(OperationsHelperWindowStrategy.*ConcatComments*),
*col*(OperationsHelperLSH.*ColumnUniqueId*),
*col*(OperationsHelperLSH.*ColumnFilteredWordsArray*),
*col*(OperationsHelperLSH.*ColumnFeaturesArray*))
(vectorizedProductsDF, vectorModeler)
class:com . sample . products . operations helper LSH . Scala
- 为了完成训练步骤,使用 MinHashLSHModel 来训练产品数据,生成类似产品的最终桶。
- 最后,使用 KNN 相似的哈希可以找到一个类别。
*/**
* Uses the dataset to train the model.
*
*/* **def** deduplicateDataSet(df: DataFrame): (DataFrame, MinHashLSHModel) = {
**val** minLshConfig = **new** MinHashLSH().setNumHashTables(hashesNumber)
.setInputCol(OperationsHelperLSH.*ColumnFeaturesArray*)
.setOutputCol(OperationsHelperLSH.*hashValuesColumn*)
**val** lshModel = minLshConfig.fit(df)
(lshModel.transform(df), lshModel)
}
*/**
* Applies KNN to find similar records.
****/* **def** filterResults(df: DataFrame,
vectorModeler: CountVectorizerModel,
lshModel: MinHashLSHModel,
categoryQuery: (String, String)
): DataFrame = {
**val** key = Vectors.*sparse*(*VocabularySHLSize*,
*Seq*((vectorModeler.vocabulary.indexOf(categoryQuery._1), 1.0),
(vectorModeler.vocabulary.indexOf(categoryQuery._2), 1.0)))
**lshModel**.approxNearestNeighbors(df, key, nearNeighboursNumber).toDF()}
运行一个例子:转到测试com.sample.processor.products.ProcessorProductsLshTest
,你会看到一个完整的流程在运行。
输入参数:
类别 → color = 'negro '和产品类型 = 'tdi '。
近邻
散列数 → 3 (散列越多精度越高,但计算开销越大)。
3 products with almost the same text for selected features.
结果分析:
优点:
- *准确:*如果使用了一组完整的字段(表示字符串),正确的哈希值和邻居值可以检测到几乎所有的重复值。
- 更快:与其他 ML 策略如项频反等相比。
缺点:
- 需要一个资源好的集群。
- 需要一个数据清理的过程。
2 —方法 B:使用 Levenshtein +火花窗口的模糊匹配:
Levenshtein 是一种用于字符串模糊匹配的算法。基本上,这个方法测量两个字符串之间的差异。此外,spark 窗口函数以简洁的方式允许数据集分析功能,避免了多个 groupBy 和 Join 操作。因此,该方法定义了一个 2 级窗口来分组相似的数据,然后将 Levenshtein 应用于相同窗口中的值以发现重复项。该过程描述如下:
- 首先选择一组描述为非模糊的记录**。该列表包含代表类别**的列,并且在 PCA 过程中大多数时候是没有错误的:(“产品类型”、“城市”、“国家”、“地区”、“年份”)。
此窗口表示用于分析的常规窗口哈希。
- 其次,应用第二个窗口来发现非常相似的记录。该列表表示既不是模糊列表(PCA) 中的零件,也不是非模糊列表中的零件的记录:(“门”、“燃料”、“制造”、“里程”、“型号”、“颜色”、“价格”)
注意:“日期”字段有助于仅订购和获取最新的。
- 然后,对于每个组,将 levenshtein (仅在第二个窗口中的字符串差异)应用于来自 PCA 结果的串接的最模糊字段: (“标题块”、“内容块”)。
如您所见,使用了列的 MD5 表示,而不是每个字符串,以获得更好的性能:
keyhash: MD5 为类别列集合。下图显示了同一类别的许多产品。
hashDiff :表示非模糊集合的 MD5 hash。下图显示了属于同一类别但具有不同描述(> levenshteinThreshold)的产品,以及具有相同 hashDiff 且 levenshtein(<levenshteinThreshold)差异较小的产品。
- 最后,hashes(两者)和 rank 相同的值只改变 row_num 。过滤 row_num == 1 有可能得到去重数据集。
*/**
* Applies windows functions and Levenshtein to group similar categories.
****/* **override def** deduplicateDataSet()(df: DataFrame): DataFrame = {
df
.withColumn(OperationsHelperWindowStrategy.*ColumnRank*, *dense_rank*().over(*windowProductKeyHash*))
.withColumn(OperationsHelperWindowStrategy.*ColumnHashWithDiff*,
*concat*(*col*(OperationsHelperWindowStrategy.*ColumnCategoryFieldsHash*),
*when*(*levenshtein*(
*first*(OperationsHelperWindowStrategy.*ConcatComments*).over(*windowProductsCategoryRank*),
*col*(OperationsHelperWindowStrategy.*ConcatComments*)) >= levenshteinThreshold, *lit*("1"))
.otherwise(*lit*(""))))
.withColumn(OperationsHelperWindowStrategy.*ColumnRowNum*, *row_number*().over(*windowProductsCategoryRank*))
}
class:com . sample . products . operationshelperwindowstrategy . Scala
运行一个例子:转到测试com.sample.processor.products.ProcessorProductsWindowsTest
,你会看到一个完整的流程在运行。
输入参数: levenshteinThreshold → 6
结果:
2 groups example with almost exact values.
过滤 rn == 1 后,会对结果进行重复数据删除。这将删除样本数据集中的 > 1/3 。
结果分析:
优点:
- 更多的控制在火花分割和功能。
缺点:
- 可能会有更多的假阳性。
最终结论
重复数据删除流程始终取决于公司需求和要分析的数据量。本文描述了两种不同的策略。因此,带有窗口函数的 Levenshtein 对于小维数问题已经足够好了;否则,LSH 永远是最好的选择
递归神经主动噪声消除
RNN 预测一个结构化的噪音,以抑制它在复杂的声学环境
Flickr, CC BY-NC 2.0
在我的上一篇文章中,我讲述了我基于神经网络的主动噪声消除系统。在这里,我概述了我用递归神经网络进行声音预测的实验,这是我为了改进我的降噪器而做的。
噪声声音预测对于主动噪声消除系统可能变得重要,因为非平稳噪声难以通过诸如 FxLMS 的经典方法来抑制。这就是我之前尝试简单的两层感知器的原因,也是我这次尝试递归网络的原因。
工作很简单:我挑战预测未来样本的任务,我用莱瓦的波尔卡作为试验品。这项任务需要大量的计算能力,所以我将这首歌缩短到前 5 秒,以便能够在没有独立 GPU 的笔记本电脑上训练 RNN。
回传脉冲
Image from Magenta blog
网络架构的核心思想源自 Magenta 项目博客中的帖子。作者在 RNN 域中引入了多速率信号处理的思想。帖子完美地描述了这个想法,它甚至有清晰的插图,所以我不打算与之竞争。虽然,我在这里给出了这个想法的简短描述。
一般来说,音乐或音频具有长期的潜在过程,因此需要用这样长的例子来学习模型。在那个实验中,我制作了具有 400 个样本输入宽度的神经网络。只有 50 毫秒,其他信息 NN 从以前的输出。
RNN 在音乐预测(或生成)问题上的主要问题是学习的复杂性。截断反向传播将输入样本和输入状态的历史展开数十或数百次。这意味着前馈路径的计算速度比反馈路径快几十倍或几百倍。
主要思想是建立几层公共递归神经网络单元,通常包括获取前一级的状态和输入值并返回下一状态和输出的单元。
履行
与之前的实验一样,我使用了 python 3.4、tensorflow 1.0 和 Linux Mint 17.2,但由于大量的计算需求,没有进行实时实验。
我制作了一个由 GRU 细胞组成的三层深度神经网络。GRU 单元也是我自己实现的,因为它更容易集成到整个系统中。每一层都接受来自以下方面的输入:
- 下面一层的输出,它是更快的一层(更大的采样率);
- 本身以前的输出;
- 上一层的输出。
第一层以 8 kHz 的采样率获取原始样本,输入的宽度为 1 个样本。内部状态是 64 个值的向量。
Outline
我也尝试过我自己的由普通感知器组成的细胞,它也工作,但 GRU 细胞的性能更好,我停止了使用它们。最顶层在那个实验中没有给出任何足够的值,但我还是把它留下了。
结果
用于实验的歌曲部分:
原始和复制样品(上图)及其光谱:
另一部分:
目标范数是均方误差,第一个历元具有 0.0176689 的误差范数,最后第 800 个历元具有 0.000453576 的范数。
这个问题没有专利,到目前为止我也没有商业计划。然而,我希望有一份全职工作致力于这个主题,这就是为什么我不把源代码放在 github.com。然而,也许有一天我会释放他们。
深度偏见?修正艾无意的偏见
随着人工智能(AI)在这十年里引起了很大的轰动,这个生态系统中的算法模型无疑已经进入了我们日常生活的方方面面。无论它们是用来解决紧迫的社会问题,还是为你的通勤推荐新的歌曲播放列表,这些模型都很常见。随着研究和技术进步为更先进的系统让路成为常态,必须认真考虑偏见和成见的意外后果。如果系统建立在我们对种族、性别和文化多样性的偏见之上,人类真的能够创造出取代我们自己认知能力的人工超级智能吗?
过去的表现并不代表未来的表现
我不是第一个写这个的人,也不会是最后一个。我真的相信人工智能给社会带来的好处会超过它的成本。然而,过于信任当前的机器学习系统所带来的问题越来越明显。简单地说,监督机器学习算法采用现有的数据集,并学习从输入到输出的映射,以便做出未来的预测。如果这些现有的数据集有偏差,那么输出也会有偏差。去年这个时候,路透社宣布亚马逊放弃了一个潜在的人工智能招聘工具,许多人希望它成为招聘的“圣杯”。
“……亚马逊的计算机模型被训练成通过观察 10 年间提交给公司的简历模式来审查申请人。大多数来自男性,反映了男性在整个科技行业的主导地位。
同样,在过去五年里,也出现了许多错误的行业算法。例如,深色皮肤的人被错误地归类为 gorrilas,或者相机将亚洲人的特征误读为眨眼。其他形式的计算机视觉算法可能会给个人带来更严重的后果,特别是如果用于预测性分析、数据驱动的政策执行措施或就业推荐引擎。
金融界有一个非常典型的免责声明,警告投资者过去的表现并不代表未来的表现。这非常贴切。机器学习系统的好坏取决于所使用的训练数据。当我们进入 2020 年时,所有的“…主义”和“…恐惧症”都真正地爆发了。已知超过 180 种人类偏见,人类的这些负面倾向可能被认为是不可治愈的,但在人工智能模型中修复偏见可能要简单得多。人工智能的竞赛正在迫使人们就道德使用展开公开讨论,因为我们的先入之见可能会因数据驱动的模型对商业决策产生不利影响而加剧。
伦理框架?好吧,这是个开始。
从根本上说,这是一个数据问题。如果算法继续从有缺陷的数据中学习,输出将继续没有代表性。上面写的案例很有可能已经被纠正,但是规范和共享未来的训练数据库必须取得进展。自 2016 年以来,AI 上的伙伴关系无疑是朝着正确方向迈出的一步;世界科技巨头走向自我监管。PAI 寻求的一个解决方案是减少科技公司中的代表性不足,允许从数据收集到产品开发的更加多样化。
“这种持续的危机在设计下一代产品的技术团队中尤为明显,这些产品会影响来自各种背景的人,通常与开发它们的团队不同。”
个人与科技公司的关系在不断变化。尽管最近进行了监管,但持续的数据泄露和数据共享政策带来了一个话题:信任。数据是新的石油 ”用那句话来说,每个个体生产的商品应该带来新的公民权利,而不仅仅是消费者权利。
围绕减少无意识偏见建立法律伦理框架或文化,无疑是提高企业信任度的一个开端。围绕数据使用建立正确的公司文化框架将使企业脱颖而出,并创造出更具包容性的思维定势。例如,谷歌人工智能概述了他们的原则完全有益于社会,为安全和负责任而建造,并对此保持透明。其他公司如 T2 的 IBM T3 和 T4 的微软 T5 也这么做了。Alan Turing Institute 还提供了对待个人数据的全面价值观原则。
(Source: Leslie, D. 2019 - Alan Turing Institute)
过程也应该被监控。敏捷实践正在成为规范,随着企业经历产品开发生命周期,质疑新产品或新功能的影响也应该成为规范。
数据集会变得无偏吗?
“因为人工智能可以帮助揭示杂乱数据集内的真相,算法有可能帮助我们更好地理解我们尚未隔离的偏见。”
除了监管和监控之外,实际实现允许审查数据源的过程无疑是困难的。IBM 的 K. Varney 提出了一个有趣的解决方案,通过三个目标和约束条件:群体歧视控制、个体扭曲控制和效用保护,数据“与具有一个或多个属性(如种族或性别)的人有关”。学术研究也看这个问题。 Kleigr、Bahnik 和 Furnkranz (2019)也概述了一项关于如何减少算法系统中的偏差的研究。
“涵盖了 20 种认知偏差,以及机器学习算法和软件的设计者可能采用的去偏差技术。”
有许多科学方法,如确保选择的模型是合适的,加强监测以减少样本、排除、偏见和观察偏差。我们会有一个既有代表性又实用的人工智能设计,同时不降低程序的公平性,最终不需要任何人类治理吗?就我而言,我不能确定——但我们已经有了一个开始。
深度汽车 Pytorch 迁移学习
完成 Hackathon Auto-matic 的逐步指南
Source: Honda Small Sports EV Concept Electric Car
你如何教计算机识别不同的汽车品牌?你想给任何一辆车拍照,然后你的手机自动告诉你这辆车的品牌吗?
如果这让你兴奋,那么你来对地方了。我们要写一个可以识别 196 种不同类型汽车的模型。
侧注
自动黑客马拉松是我和四位女士(来自世界各地)发起的组织周末黑客马拉松的第二个项目
作为 facebook 赞助的 Udacity 上的**安全和私人 AI 奖学金挑战赛的 5000 名学生的一部分,**我们决定组织周末黑客马拉松;用 Pytorch 解决一个问题的 48 小时,玩得开心,互相竞争。令我们惊讶的是,在我们的第一次黑客马拉松中,有 41 个团队参加了🙌。 黑客马拉松开花 是给第一届黑客马拉松起的名字。Hackathon Auto-matic和 Hackathon Blossom 一样也是基于图像分类。
我可以继续讲述这个机会是多么不可思议,以及我们在那里拥有的令人惊叹的社区。我最好就此打住,回到我们今天的目标:)
入门指南
我们将使用神经网络来实现我们的目标。更准确地说,我们将使用一个非常深的神经网络,因此命名为深车。****
本教程分为两部分:
第 1 部分:构建汽车分类器
第 2 部分:部署分类器(进行中…)
在本文中,我们将浏览第 1 部分
第 1 部分:构建汽车分类器
先决条件:
为了跟进,需要以下方面的一些知识:
- Python——uda city 提供了一个关于Python 简介的很棒的课程
- 卷积神经网络 — Adit 在 CNN 上提供了一个伟大的什么是迁移学习?
迁移学习是深度学习中的一种方法,其中为解决一项任务而开发的模型被重新用作另一项任务的起点。比方说,你想建立一个网络来识别鸟类,而不是从头开始编写一个模型,这可能是一个非常复杂的任务,至少可以使用一个已经存在的模型来完成相同或类似的任务(在我们识别鸟类的情况下,我们可以使用一个识别其他动物的网络)。运用迁移学习的优势;学习过程更快、更准确,需要的训练数据更少。已经存在的模型被称为预训练模型。****
迁移学习中使用的大多数预训练模型都基于大型卷积神经网络。一些人预训练的模型有 VGGNet,ResNet,DenseNet,Google 的 Inception 等。这些网络中的大多数都是在 ImageNet 上训练出来的。ImageNet 是一个大规模数据集,包含 1000 个类别中超过 100 万个带标签的图像。
在 Pytorch 中,很容易加载基于 ImageNet 的预训练网络,这些网络可从 torchvision 获得。我们将使用这些预先训练好的模型来训练我们的网络。
我们的模型将使用以下步骤在 Google Colab 上构建(笔记本可在此处找到):
- 加载数据并执行转换
- 建立模型
- 训练模型
- 在看不见的数据上测试模型
导入库
在这里,我们只是加载库,并确保 GPU 是打开的。由于我们将使用预先训练的模型,这些模型是非常深的网络,所以 CPU 上的训练不是一个真正的选项,因为这将需要很长时间。GPU 并行执行线性代数计算,因此训练速度提高了 100 倍。
如果你的 GPU 是关闭的,并且你正在使用 Colab,在你的笔记本上进入编辑= >笔记本设置*。确保运行时设置为 Python 3 并且在硬件加速器下选择 GPU。***
你会注意到我们正在检查 cuda 是否可用。大多数深度学习框架使用 CUDA 来计算 GPU 上的向前和向后传递。
1。执行转换并加载数据集
1.1 下载数据集
现在我们的库已经导入,我们从 Kaggle 加载数据集。该数据集包含 196 个汽车品牌。
在这里,我们下载数据集并使用 Pytorch 数据加载器加载它们。我们将数据直接下载到谷歌硬盘,因此我们必须获得授权访问。
*#Mounting google drive inorder to access data from google.colab import drive drive.mount('/content/drive')*
运行后:点击出现的链接,登录到你的帐户,点击允许,然后复制生成的文本并粘贴到你的笔记本上。查看这篇文章,这篇文章向您展示了如何轻松获得 API 密钥和下载数据集。我们加上这一行!解压缩*。zip 解压下载的文件。您的代码应该是这样的:**
注意我们有两个目录;培训和测试目录。稍后,我们将使用我们的模型来预测测试集的值。我们必须将训练数据分为训练数据和验证数据。在拆分之前,让我们了解什么是转换,并写出我们的转换。
1.2 数据转换
既然数据集已经下载,我们就对数据执行转换。转换是将数据从一种形式转换成另一种形式。我们将对我们的图像应用两个主要的变换:
- 数据增强
这是一种在不实际收集新数据的情况下增加用于训练的数据集的多样性和大小的策略。诸如调整大小、裁剪、水平翻转、填充甚至 GANs 等技术被应用于数据集上的图像,并且“新的”图像被创建。它有两个主要优点:从有限的数据中生成更多的数据,并防止过拟合。
但是,不要期望在数据集中看到这些生成的图像。它们仅在批量生成期间创建,因此即使您没有看到数据集中的图像数量增加,训练期间的实际图像也会增加。
在我们的模型中,我们应用了 3 种增强策略;调整大小(RandomResize)、裁剪(RandomCrop)和水平翻转(HorizontalFlip)。
请注意,对于测试数据,我们不执行 RandomResizedCrop、RandomRotation 和 RandomHorizontalFlip 转换。相反,我们只是将测试图像的大小调整为 256×256,并裁剪掉中心 224×224,以便能够将它们用于预训练的模型。
- 数据标准化
执行增强后,图像被转换为张量,并通过使用 ImageNet 中所有图像的平均值和标准偏差进行归一化。通常,对于非常大的数据集,使用数据集本身的平均值和标准差。鉴于我们的数据集不是太大,我们使用 ImageNet 的数据集:【0.485,0.456,0.406】,【0.229,0.224,0.225】**
执行这些转换后,我们使用 Pytorch 中的 ImageFolder 加载数据。但是首先我们需要验证数据,所以我们拆分了训练集。我们的数据中只有 1%被选择用于验证,其余的用于训练。
- 可视化标签
我们可视化我们的标签来查看文件的结构。
Output from printing names.csv
我们看到 0 上面出现了一个车名。因此,在读取 csv 文件时,我们必须添加一个头名,这样才能得到正确的输出。需要注意的是,我们的标签从 0 到 195 开始(非常重要)
3 可视化图像
我们现在可以加载和可视化我们的数据。创建了一个方法 imshow() (来自挑战课程)来显示我们的图像。
训练集中的图像如下所示。我们注意到其中一些已经翻转或旋转。
Images from train set after transformations
2。构建和训练模型
如前所述,我们将使用基于 ImageNet 的预训练模型。
我们将用于构建和培训的步骤是:
- 加载预训练模型
- 冻结卷积层中的参数
- 创建自定义分类器并定义超参数
- 训练自定义分类器
2.2 加载预训练模型
我们将尝试不同的架构; densenet161 、 inceptionv3 、 resnet121 和 vggnet 架构。在这里,我们加载不同的模型,并在模型的全连接层中指定输入要素的数量,因为我们在构建自定义分类器时将需要这一点。
2.3 冻结参数并创建自定义分类器
因为我们的预训练模型中的大多数参数已经为我们训练好了,所以我们不通过它们进行反向投影。这将允许我们保留早期卷积层的预训练权重(其目的是用于特征提取)。我们通过将 requires_grad 字段重置为 false 来实现这一点。
在此之后,我们替换完全连接的网络,该网络将具有与我们的预训练神经元相同的输入、自定义隐藏层和我们的输出。我们的build _ classifier方法很灵活,当我们不希望网络中有隐藏层,或者我们希望有多个隐藏层时,这种方法很有效。激活功能(在本例中为 relu )和漏失也被定义。**
现在我们指定我们的超参数和隐藏层。
我们指定了标准,不同的优化器,如 Adam,Adadelta,SGD,其中包含了学习率和动量。我们为不同的预训练网络使用这些超参数,并选择给我们最好结果的那些。我们为 resnet 和 vggnet 使用两种不同的调度程序。他们是这样做的:
torch.optim.lr_scheduler
提供了几种根据时期数调整学习率的方法。[torch.optim.lr_scheduler.ReduceLROnPlateau](https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau)
允许基于某些验证测量的动态学习率降低。更多阅读此处2.4 培训和验证
为了用 PyTorch 训练我们的模型,我们通常在迭代每个时期时执行以下步骤:
- 使用 forward(images) 向前通过网络
- 使用标准功能中的网络输出来计算损耗**
- 使用 loss.backward() 对网络进行反向遍历,以计算梯度
- 与优化器一起更新权重 optimizer.step()
optimizer.zero_grad() 用于清除累积的梯度
称为提前停止的技术用于防止过度拟合。当验证数据集的性能开始下降时,它会导致训练停止。随着训练的进行,当我们获得最佳准确度时,我们也保存模型(检查点)。这样,如果断电或训练由于某种原因中断,可以恢复检查点并继续训练。**
该模型改编自 PyTorch 网站
现在我们训练我们的模型。
*Epoch 1/60 ---------- train Loss: 0.5672 Acc: 0.8441 valid Loss: 0.6750 Acc: 0.8329 Epoch 2/60 ---------- train Loss: 0.6184 Acc: 0.8357 valid Loss: 0.5980 Acc: 0.8415 Epoch 3/60 ---------- train Loss: 0.5695 Acc: 0.8487 valid Loss: 0.5503 Acc: 0.8575 ...*
这看起来很有希望。这个模型似乎在不断学习。此外,我们的模型似乎没有过度拟合(至少是过度拟合),因为训练和验证指标没有偏离太多。该模型的特定时期结果是通过 ResNet 架构获得的,这是第二次培训。精度开始很低,但随着时间的推移而提高。对我们得到的精度影响很大的超参数是优化器、调度器、历元数和架构*。调整这些值要么给出非常低的精度(低至 0,甚至为负),要么以 0.013 这样的精度开始,该精度随着历元数的增加而增加(这里耐心是关键)。***
4。在看不见的数据上测试模型
一旦我们对我们的验证准确性感到满意,我们就加载我们保存的模型,并对测试数据进行预测。课堂竞赛要求我们以 csv 格式提交结果,格式为 Id,预测。 Id 这是我们图像文件的名称,不带扩展名。jpg 和预测的是我们的模型为每张图片预测的类(应该在 1 到 196 之间)。请记住,我们的标签从 0 到 195 开始,所以我们必须在预测的类中加 1 才能得到正确的值。**
我们加载我们保存的模型
*model.load_state_dict(torch.load('/content/drive/MyDrive/ResnetCars.pt')) model.to(device)*
现在,我们加载测试数据集,并通过数据集传递我们的模型。因为我们只做预测,所以不需要计算梯度。我们通过 torch.no_grad() 并设置为 evaluation model.eval()来实现这一点。我们计算预测。
得到结果后,我们打印数据框,并将结果写入一个. csv 文件,然后在竞赛网站上提交。
CSV FIle to be submitted
看看 Khush Patel 的令人惊叹的内核,它以 99.18%的准确率赢得了黑客马拉松的冠军。他使用了 inceptionV3 架构,带有 CrossEntropyLoss 和一个 SGD 优化器。你的模型能打败这个吗?😃
你可以在 Kaggle 上参加的班级竞赛。
我们结束了。
恭喜👏这是一篇很长的文章,但你坚持到了最后。现在你可以用迁移学习建立你自己的模型。代码是可重用的,您也可以将它用于其他数据集。
感谢阅读!你可以随时在 Twitter 和 LinkedIn 上联系。
参考文献
[1] F. Zaidi,py torch 中的迁移学习,第 1 部分:如何使用数据加载器并构建完全连接的类 (2019)
[2] G. Adjei,用 PyTorch ,(2019),心跳
金融市场细分的深度聚类
一种无监督的信用卡客户聚类深度学习方法
无监督学习、监督学习和强化学习是机器学习方法的三大类。无监督学习有许多应用,如聚类、降维等。机器学习算法 K-means 和主成分分析 (PCA)分别广泛用于聚类和降维。与 PCA 类似,T-分布式随机邻居嵌入 (t-SNE)是另一种用于维数约简的无监督机器学习算法。t-SNE 通常用于在二维或三维空间中嵌入高维数据以进行数据可视化。
随着无监督深度学习的发展,自动编码器神经网络现在经常用于高维度(例如,具有数千或更多特征的数据集)的约简。Autoencoder 也可以与监督学习(如随机森林)相结合,形成半监督学习方法(见深度病人举例)。
最近发表了一个深度嵌入聚类 (DEC)方法【1】。它将 autoencoder 与 K-means 和其他机器学习技术相结合,用于聚类而不是降维。DEC 的原实现基于 Caffe 。在【2】中可以找到 MNIST 数据集的 Keras 中 DEC 的实现。
在本文中,与[2]类似,我在 Keras 中实现了 DEC 算法,并使用公共数据集 Kaggle 信用卡数据集进行聚类 [3]来展示如何使用新实现的 DEC 模型对信用卡数据集进行聚类以进行客户细分。本文其余部分安排如下:
- 数据准备
- 在 Keras 中实现 DEC 方法
- 摘要
1.数据准备
本节描述聚类所需的常见数据预处理步骤。
1.1 加载数据
将 Kaggle 信用卡数据集[3]下载到本地机器后,可以将其加载到 Pandas 数据框架中,如下所示:
import Pandas as pd data = pd.read_csv('./data/CC_GENRAL.csv') data.head()
1.2 选择功能
从上面的数据帧可以看出,CUST ID 字段对于每个客户数据记录都是唯一的。具有唯一值的该字段对聚类没有用,因此可以删除:
data_x = data.drop(['CUST_ID'], axis=1)
1.3 重缩放特征
从数据帧中还可以看出,对于不同的字段/特征,值的范围是非常不同的。众所周知,K-means 对特征值的尺度很敏感,因为它使用欧氏距离作为相似性度量。为了避免这个问题,所有要素的值都被重新调整到[0,1]的范围内:
from sklearn.preprocessing import MinMaxScaler numeric_columns = data_x.columns.values.tolist() scaler = MinMaxScaler() data_x[numeric_columns] = scaler.fit_transform(data_x[numeric_columns]) data_x.head()
1.4 处理缺失数据
以下代码用于检查数据集中是否存在任何缺失的数据:
data_x.isnull().sum()
上表显示有一个缺失的信用限额记录和 313 个缺失的最低付款额。在这种情况下,用零填充缺失的数据是有意义的:
data_x.fillna(0, inplace=True)
2.在 Keras 中实现 DEC 方法
与[2]类似,[1]中的 DEC 算法在本文中用 Keras 实现如下:
- 步骤 1:估计聚类数
- 步骤 2:创建和训练 K 均值模型
- 步骤 3:创建和训练自动编码器
- 步骤 4:实施 DEC 软标签
- 步骤 5:创建一个新的 DEC 模型
- 步骤 6:训练新的 DEC 模型
- 步骤 7:使用训练好的 DEC 模型预测聚类类
- 第八步:共同细化 DEC 模型
- 步骤 9:使用改进的 DEC 模型预测聚类类
- 步骤 10:与 K 均值比较
2.1 估计聚类数
如前所述,DEC 方法将 Autoencoder 与 K-means 和其他机器学习技术相结合。为了训练 K-均值模型,需要估计的聚类数。本文通过研究不同 K-means 模型执行的剪影值来估计聚类的数量:
for num_clusters in range(2,10): clusterer = KMeans(n_clusters=num_clusters, n_jobs=4) preds = clusterer.fit_predict(x) # centers = clusterer.cluster_centers_ score = silhouette_score (x, preds, metric='euclidean') print ("For n_clusters = {}, Kmeans silhouette score is {})".format(num_clusters, score))
轮廓值衡量数据记录与其自己的分类(内聚力)相比与其他分类的相似程度。轮廓值的范围从 1 到+1,其中高值表示数据记录与其自己的分类匹配良好,而与其相邻的分类匹配较差。
上面的轮廓值表明聚类数的前两个选择是 2 和 3。本文选择了 3 个簇的数目。
2.2 创建和训练 K 均值模型
一旦确定了聚类的数量,就可以创建 K 均值模型:
n_clusters = 3 kmeans = KMeans(n_clusters=n_clusters, n_jobs=4) y_pred_kmeans = kmeans.fit_predict(x)
2.3 创建和培训自动编码器
除了 K-means,DEC 算法中还需要一个自动编码器[1]。以下函数用于创建自动编码器:
def autoencoder(dims, act='relu', init='glorot_uniform'): n_stacks = len(dims) - 1 input_data = Input(shape=(dims[0],), name='input') x = input_data # internal layers of encoder for i in range(n_stacks-1): x = Dense(dims[i + 1], activation=act, kernel_initializer=init, name='encoder_%d' % i)(x) # latent hidden layer encoded = Dense(dims[-1], kernel_initializer=init, name='encoder_%d' % (n_stacks - 1))(x) x = encoded # internal layers of decoder for i in range(n_stacks-1, 0, -1): x = Dense(dims[i], activation=act, kernel_initializer=init, name='decoder_%d' % i)(x) # decoder output x = Dense(dims[0], kernel_initializer=init, name='decoder_0')(x) decoded = x autoencoder_model = Model(inputs=input_data, outputs=decoded, name='autoencoder') encoder_model = Model(inputs=input_data, outputs=encoded, name='encoder') return autoencoder_model, encoder_model
自动编码器模型创建如下:
n_epochs = 100 batch_size = 128 dims = [x.shape[-1], 500, 500, 2000, 10] init = VarianceScaling(scale=1\. / 3., mode='fan_in', distribution='uniform') pretrain_optimizer = SGD(lr=1, momentum=0.9) pretrain_epochs = n_epochs batch_size = batch_size save_dir = './results'autoencoder, encoder = autoencoder(dims, init=init)
如[1]中所述,层的大小[500,500,2000,10]被选择作为用于任何数据集的自动编码器神经网络的一般配置。
生成的编码器模型的图表可以创建如下:
from keras.utils import plot_model plot_model(encoder, to_file='encoder.png', show_shapes=True) from IPython.display import Image Image(filename='encoder.png')
自动编码器的训练如下:
autoencoder.compile(optimizer=pretrain_optimizer, loss='mse') autoencoder.fit(x, x, batch_size=batch_size, epochs=pretrain_epochs) autoencoder.save_weights(save_dir + '/ae_weights.h5')
被训练的自动编码器的权重被保存以备后用:
autoencoder.save_weights(save_dir + '/ae_weights.h5') autoencoder.load_weights(save_dir + '/ae_weights.h5')
2.4 实施 DEC 软标签
DEC 方法[1]中的一个关键组成部分是软标记,也就是说,为每个数据样本分配一个估计类,以使其可以迭代地改进。为此,与[2]类似,定义了一个新的 ClusteringLayer 类:
class ClusteringLayer(Layer): def __init__(self, n_clusters, weights=None, alpha=1.0, **kwargs): if 'input_shape' not in kwargs and 'input_dim' in kwargs: kwargs['input_shape'] = (kwargs.pop('input_dim'),) super(ClusteringLayer, self).__init__(**kwargs) self.n_clusters = n_clusters self.alpha = alpha self.initial_weights = weights self.input_spec = InputSpec(ndim=2) def build(self, input_shape): assert len(input_shape) == 2 input_dim = input_shape[1] self.input_spec = InputSpec(dtype=K.floatx(), shape=(None, input_dim)) self.clusters = self.add_weight(name='clusters', shape=(self.n_clusters, input_dim), initializer='glorot_uniform') if self.initial_weights is not None: self.set_weights(self.initial_weights) del self.initial_weights self.built = True def call(self, inputs, **kwargs): q = 1.0 / (1.0 + (K.sum(K.square(K.expand_dims(inputs, axis=1) - self.clusters), axis=2) / self.alpha)) q **= (self.alpha + 1.0) / 2.0 q = K.transpose(K.transpose(q) / K.sum(q, axis=1)) return q def compute_output_shape(self, input_shape): assert input_shape and len(input_shape) == 2 return input_shape[0], self.n_clusters def get_config(self): config = {'n_clusters': self.n_clusters} base_config = super(ClusteringLayer, self).get_config() return dict(list(base_config.items()) + list(config.items()))
2.5 创建新的 DEC 模型
一旦定义了软标注图层,就可以使用它来形成 DEC 模型,如下所示:
clustering_layer = ClusteringLayer(n_clusters, name='clustering')(encoder.output) model = Model(inputs=encoder.input, outputs=clustering_layer)
可以创建新 DEC 模型的图表,如下所示:
from keras.utils import plot_model plot_model(model, to_file='model.png', show_shapes=True) from IPython.display import Image Image(filename='model.png')
新的 DEC 模型可以编译如下:
model.compile(optimizer=SGD(0.01, 0.9), loss='kld') model.get_layer(name='clustering').set_weights([kmeans.cluster_centers_])
2.6 培训新的 DEC 模型
迭代训练新的 DEC 模型:
# computing an auxiliary target distribution def target_distribution(q): weight = q ** 2 / q.sum(0) return (weight.T / weight.sum(1)).Tloss = 0 index = 0 maxiter = 1000 update_interval = 100 tol = 0.001 # tolerance threshold to stop trainingindex_array = np.arange(x.shape[0]) for ite in range(int(maxiter)): if ite % update_interval == 0: q = model.predict(x, verbose=0) p = target_distribution(q) idx = index_array[index * batch_size: min((index+1) * batch_size, x.shape[0])] loss = model.train_on_batch(x=x[idx], y=p[idx]) index = index + 1 if (index + 1) * batch_size <= x.shape[0] else 0
如[1]中所述,上述训练过程通过在辅助目标分布函数 target_distribution )的帮助下从高置信度分配中学习来迭代地改进聚类。具体而言,通过将软分配与目标分布相匹配来训练 DEC 模型。为此,在 DEC 模型中,目标/损失函数被定义为软分配和辅助分布之间的 Kullback-Leibler (KL)发散损失。
已训练模型的模型权重被保存以备后用:
model.save_weights(save_dir + '/DEC_model_final.h5') model.load_weights(save_dir + '/DEC_model_final.h5')
2.7 使用训练的 DEC 模型来预测聚类类别
一旦 DEC 模型被定型,它就可以用于预测聚类类,如下所示:
q = model.predict(x, verbose=0) p = target_distribution(q) y_pred = q.argmax(1)
如下获得 0.291 的轮廓分数:
from sklearn.metrics import silhouette_score score = silhouette_score(x, y_pred, metric='euclidean')
以下代码可用于使用 t-SNE 将数据集嵌入二维空间,然后使用预测聚类标签的颜色编码来可视化预测聚类结果:
import numpy as np from sklearn.manifold import TSNEx_embedded = TSNE(n_components=2).fit_transform(x)vis_x = x_embedded[:, 0] vis_y = x_embedded[:, 1] plt.scatter(vis_x, vis_y, c=y_pred, cmap=plt.cm.get_cmap("jet", 256)) plt.colorbar(ticks=range(256)) plt.clim(-0.5, 9.5) plt.show()
图 1: 剪影得分为 0.291 的新 DEC 模型的聚类。
2.8 联合提炼 DEC 模型
DEC 方法[1]背后的主要思想是使用深度神经网络同时学习特征表示和聚类分配。为此,以下代码使用预训练的 autoencoder 和 K-means 模型来定义一个新模型,该模型将预处理的信用卡数据集作为输入,并输出预测的聚类分析类和解码的输入数据记录。
autoencoder, encoder = autoencoder(dims, init=init) autoencoder.load_weights(save_dir + '/ae_weights.h5') clustering_layer = ClusteringLayer(n_clusters, name='clustering')(encoder.output) model = Model(inputs=encoder.input, outputs=[clustering_layer, autoencoder.output])
可以按如下方式创建连接模型的图表:
from keras.utils import plot_model plot_model(model, to_file='model.png', show_shapes=True) from IPython.display import Image Image(filename='model.png')
DEC 模型的优化执行如下:
kmeans = KMeans(n_clusters=n_clusters, n_init=20) y_pred = kmeans.fit_predict(encoder.predict(x)) model.get_layer(name='clustering').set_weights([kmeans.cluster_centers_]) y_pred_last = np.copy(y_pred)model.compile(loss=['kld', 'mse'], loss_weights=[0.1, 1], optimizer=pretrain_optimizer)for ite in range(int(maxiter)): if ite % update_interval == 0: q, _ = model.predict(x, verbose=0) p = target_distribution(q) y_pred = q.argmax(1) # check stop criterion delta_label = np.sum(y_pred != y_pred_last).astype(np.float32) / y_pred.shape[0] y_pred_last = np.copy(y_pred) if ite > 0 and delta_label < tol: print('delta_label ', delta_label, '< tol ', tol) print('Reached tolerance threshold. Stopping training.') break idx = index_array[index * batch_size: min((index+1) * batch_size, x.shape[0])] loss = model.train_on_batch(x=x[idx], y=[p[idx], x[idx]]) index = index + 1 if (index + 1) * batch_size <= x.shape[0] else 0
保存联合细化的模型权重:
model.save_weights(save_dir + '/b_DEC_model_final.h5') model.load_weights(save_dir + '/b_DEC_model_final.h5')
2.9 使用改进的 DEC 模型预测聚类类别
以下代码将使用改进的 DEC 模型来预测聚类分析类:
q, _ = model.predict(x, verbose=0) p = target_distribution(q) y_pred = q.argmax(1)
下面的代码可用于重用 t-SNE 嵌入的二维空间( vis_x , vis_y ),并使用新的预测聚类标签的颜色编码来可视化新的预测聚类结果:
plt.scatter(vis_x, vis_y, c=y_pred, cmap=plt.cm.get_cmap("jet", 256)) plt.colorbar(ticks=range(256)) plt.clim(-0.5, 9.5) plt.show()
图 2: 轮廓得分为 0.318 的细化 DEC 模型的聚类。
2.10 与 K 均值比较
图 3 显示了 K-means 的聚类结果。通过比较图 3 和图 2,我们可以看到 K-means 取得了相对较高的轮廓得分。然而,可以看出,改进的 DEC 模型预测了具有更清晰可分边界的聚类。
图 3:轮廓得分为 0.372 的 K 均值模型的聚类。
摘要
在本文中,与[2]类似,我基于[1]中的原始 DEC 算法在 Keras 中实现了一个新的 DEC 模型,然后将新模型应用于公共数据集 Kaggle 信用卡数据集进行聚类【3】。
模型评估结果表明,与 K-means 方法相比,新的改进的 DEC 模型更清楚地预测了信用卡数据集的可分离聚类。这种新的 DEC 模型具有用于信用卡客户细分、其他金融市场细分等的潜力。
Github [4]中提供了一个 Jupyter 笔记本,其中包含了本文中使用的所有源代码。
参考
[1] J .谢,r .吉希克,a .,聚类分析的无监督深度嵌入,2016 年 5 月 24 日
[2]程维,如何用 Keras 做无监督聚类
[3] Kaggle 用于聚类的信用卡数据集
[4] Y. Zhang, Github 中的 Jupyter 笔记本
披露声明:2019 首创一。观点是作者个人的观点。除非本帖中另有说明,否则 Capital One 不隶属于所提及的任何公司,也不被这些公司认可。使用或展示的所有商标和其他知识产权是其各自所有者的财产。
深度压缩
在目前的形式下,深度神经网络需要巨大的内存来支持其大规模的过度参数化。AlexNet 和 VGG-16 等经典神经网络分别需要大约 240 和 552 MB。已经进行了许多努力来减小神经网络的文件大小,通常依赖于诸如权重修剪或量化或者权重矩阵的 SVD 分解之类的技术。这篇名为 Deep Compression 的论文将剪枝、量化和霍夫曼编码结合到一个三级流水线中,将 AlexNet 的大小减少了 35 倍,将 VGG-16 的大小减少了 49 倍。这导致 AlexNet 从 240 兆字节减少到 6.9 兆字节,VGG-16 从 552 兆字节减少到 11.3 兆字节。
管道由三个阶段组成:
Pruning, Quantization, and Huffman Encoding
修剪
修剪描述了在深度神经网络中屏蔽掉某些权重的过程。这需要在神经网络层上实现一个掩码,以便它们通过 y = Wx + b 运算进行不同的迭代。权重修剪不同于简单地将某些权重设置为 0。在论文中实现的修剪操作屏蔽了低于某个阈值的权重。例如,如果权重位于区间[-0.5,0.5]之间,它将被屏蔽掉。
修剪后,权重以压缩的稀疏行格式表示。这样做是为了不浪费稀疏权重矩阵的空间。下图描述了这种 CSR 格式:
量化
量化是一种通过权重共享来减少在神经网络中存储每个权重所需的位数的技术。深度神经网络中的权重通常由 32 位浮点表示,采取例如“2.70381”的形式。在量化中,使用 k-Means 算法来搜索描述网络中权重的聚类。如果权重用 3 比特表示,这将导致 2 = 8 个质心用于聚类权重。然后,每个权重被映射到其各自的质心。比如‘2.70381’→‘2’。因此,这 8 个质心形成了用于将原始权重映射到相应的 3 比特权重的“码本”。然后,在训练期间对该码本进行微调。
码本通过与经典 backprop / SGD 类似的机制进行微调。计算每个权重的偏导数,并对每个离散的 3 位权重进行合计。例如,一系列“2”3 位权重可以具有“0.2”、“0.1”、“0.2”和“0.3”的相应偏导数更新。这些导数被聚合,并且“2”被优化为“2.2”。
这个过程描述如下:
霍夫曼编码
霍夫曼编码是一种流行的压缩技术,它利用了值的偏斜/有偏分布。例如,如果 20 个权重映射到“2”,10 个权重映射到“3”,3 个权重映射到“8”,则将 2 编码为“00”,将 3 编码为“10”,将 8 编码为类似“1110”的内容是有意义的。在这种情况下,使用霍夫曼编码来减少表示量化码本中的权重所需的比特数量。
放在一起
我发现剪枝和权重量化如何在不破坏网络准确性的情况下协同工作非常有趣。我希望通过使用分布式同步 SGD 等机制,使用这种技术来改善元学习算法的周转时间。我希望其他人发现这很有用,并可以找到移动和嵌入式系统的深度学习应用。请查看下面的视频以了解更多关于深度压缩的信息,感谢阅读!
深度压缩:推理和效率的优化技术
随着技术迎合摩尔定律的物理极限,计算越来越受到散热的限制,而不是在给定的硅面积上可以封装的晶体管数量。现代芯片已经经常闲置其区域的整个部分,形成所谓的“暗硅”,指的是在危险地超过热设计限制之前,限制芯片可以长时间通电的比例的设计。因此,对于任何机器学习加速器,包括经过试验的和真正的通用图形处理单元(GPU ),一个重要的度量是设备在大约 250 W 功耗下的训练或推理性能。
正是这种对效率的驱动力促使谷歌开发了他们自己的张量处理单元(TPU) ,用于提高模型推理的效率,以及在其数据中心的 v2 单元中的培训。过去几年已经出现了过多的深度学习硬件创业公司,它们寻求生产高能效的深度学习芯片,这些芯片专门从事当前流行的深度学习架构所需的有限混合操作。如果深度学习主要由矩阵乘法和卷积组成,为什么不建造一个芯片来做这些,用通用计算能力换取专用效率?但是这种权衡比看起来要复杂得多。
深度学习的能源成本
包括大规模机器学习在内的现代高性能计算的主要动力来源不是计算,而是通信。对 32 位数据执行乘法运算通常需要不到 4 pJ 的,而从 DRAM 中读取相同数量的数据需要大约 640 pJ,这使得片外存储器读取比常用的数学运算符多消耗大约 160 倍的能量。当我们考虑发送超过几厘米的数据时,这种不平衡的功耗变得更糟(导致数据中心用光纤取代中等长度的数据通信线)。突然之间,将你的深度学习推理需求外包到谷歌云平台的 TPUs 上运行,似乎并不像它本来可以做到的那样环保。
几乎不用说,鉴于人工智能和机器学习的创新步伐,在投资 2 年开发周期开发仅限于卷积和矩阵乘法高性能的专用硬件后,无法保证主导架构将保持不变足够长的时间,以充分获得回报。就在过去的几个月里,我们已经看到了有前途的神经微分方程网络的演示,它的操作与我们备受尊敬的 conv 网络截然不同,这十年来对深度学习的兴趣增加只能意味着更多的创新和新型模型。任何专门为加速当前一代顶级机型而开发的专用硬件都有迅速过时的风险。
深度压缩:受生物启发的效率提升
深度学习卷积神经网络,顾名思义,以其深度和宽度而闻名,其中一些例外的例子是大约有 1000 层的 resnets。在训练结束时,所有这些参数中的所有精度都可能是过度的,只不过是浪费了对电力有着贪婪胃口的计算资源。这是 Nvidia 可变精度张量内核背后的一个主要原因,它支持最新一代图灵架构 GPU中低至 8 位整数的计算。
因此,用更小的模型(如恰当命名的 SqueezeNet )实现最先进的性能是一个活跃的研究领域。经过充分训练的较小模型非常适合在自动驾驶汽车、物联网设备和智能手机中进行移动部署,但当参数搜索量很大时,训练仍然是最有效的。幸运的是,在人类大脑的发展过程中有一种生物模拟。使用突触修剪,随着人们从童年进入成年,人类大脑变得更加有效。正是哺乳动物神经发育的这一特征,激发了一套深度学习模型的压缩技术。
据估计,在儿童早期发育期间,突触的最大数量高达 1000 万亿个,但在突触修剪后,成年人的突触数量减少了约 10 倍,约为 100 万亿个。这不仅降低了组织的代谢需求,而且有助于学习对世界更复杂的结构理解。同样在深度学习中,在 GPU 上的广泛训练出现之前,修剪权重源于一种用于改善模型泛化的正则化 技术。将参数剪枝、参数量化、参数编码结合在一个被称为深度压缩的模型压缩优化过程中,获得了宋瀚等2016 年 ICLR 最佳论文奖。深度压缩不仅使模型尺寸缩小了 35-50 倍,运行速度更快,所需能源更少(非常适合部署在电池供电的应用中),而且这些模型通常比原始的未压缩模型具有更好的性能。
密集-稀疏-密集训练
就像新生儿多变的思维一样,典型的多层感知器架构以神经元之间密集的互连为特征,如下图所示:
训练之后,如果我们要探索定义每个加权连接的参数值,我们会发现两个重要的特征。首先,许多权重值非常接近于零,因此我们应该能够丢弃它们,而不会显著影响网络的整体性能。第二,权重所代表的许多信息实际上是多余的。丢弃几乎无关紧要的权重并在多次迭代中重新训练网络减少了网络学习的冗余,这很像优雅有效的丢失正则化技术。在所谓的密集-稀疏-密集训练中反复修剪和重新训练模型可以移除高达 90%的参数,而不会损失测试精度(PDF) 。
参数量化
参数减少 90%相当不错,但此时仍有充分的机会来优化模型,它可能仍然太小,无法挤入片内 SRAM。在训练过程中,我们通常会使用高精度数据类型,如 64 位浮点数,但在一天结束时,我们通常会发现,无论权重值是正还是负 1e-33,在测试时都不会有太大的差异。通过量化其余参数,我们可以利用 Nvidia 的 INT8 推理精度等功能的效率和加速,并进一步减小模型大小。如果我们正在为自动驾驶汽车或物联网设备部署空中更新,较小的型号相当于为我们的客户和我们自己节省了通信成本和时间,同时避免了常规功能的设备外云计算的一些陷阱。
霍夫曼编码(额外学分)
在密集-稀疏-密集训练和参数量化后停止已经足以将标志性的 AlexNet 的存储需求减少超过 26 倍,而没有任何明显的性能损失。要实现深度压缩的全部优势,还有一个步骤,那就是重量分担。您应该还记得,在从完全连接到卷积神经网络架构的过程中,我们已经受益于显著的权重共享优势,因为每个卷积内核中的每个权重都作为滑动窗口应用于整个前一层。这将给定模型中的参数总数减少了几个数量级,仅次于可比的密集连接的多层感知器。但是,我们可以通过将 k 均值聚类应用于权重群体,使用质心值作为每个组的参数值,并将这些值放在查找表中,来实现进一步的权重共享优势。
在漫画中,这个概念看起来像这样:
结论
深度压缩是一种鼓励深度学习模型更智能地工作而不是更困难的方法,并能够提高能效、推理速度和移动部署。此外,在灵活的通用 GPU 上训练大模型,然后压缩它们以进行推理和部署,这结合了深度和广度模型的一些最佳功能,主要是在学习过程中在参数搜索方面撒下一张大网,并能够部署小得多的成品模型以用于设备上部署。设备上的机器学习增强了隐私,并为自动驾驶等应用的基本功能提供了更高的可靠性。深度压缩等模型优化技术缩小了科技巨头周围的护城河,使其有资源雇佣半导体工程师团队来开发内部机器学习硬件,并减少了对云服务上运行大模型的依赖。
原载于 2019 年 2 月 12 日【blog.exxactcorp.com。
解释了深层确定性策略梯度
连续动作空间中的强化学习
这篇文章是对 Deepmind 的出版物*“深度强化学习的连续控制”* (Lillicrap 等人,2015 年)的彻底的回顾,其中提出了深度确定性政策梯度(DDPG),并且是为希望理解 DDPG 算法的人写的。如果你只对实现感兴趣,你可以跳到本文的最后一节。
本文假设读者熟悉基本的强化学习概念、价值&政策学习和行动者评论方法。如果你不完全熟悉这些概念,我还写过关于政策梯度和演员评论方法的文章。
熟悉 python 和 PyTorch 对阅读这篇文章也很有帮助。如果您不熟悉 PyTorch,请尝试按照代码片段进行操作,就像它们是伪代码一样。
浏览报纸
网络示意图
DDPG 使用四种神经网络:Q 网络、确定性策略网络、目标 Q 网络和目标策略网络。
Q 网络和策略网络非常类似于简单的优势行动者-批评家,但是在 DDPG,行动者直接将状态映射到行动(网络的输出直接是输出),而不是输出跨离散行动空间的概率分布
目标网络是其原始网络的延时副本,缓慢地跟踪已学习的网络。使用这些目标值网络大大提高了学习的稳定性。原因如下:在不使用目标网络的方法中,网络的更新方程依赖于网络本身计算的值,这使得它容易发散。例如:
因此,我们有了确定性策略网络和 Q 网络的标准参与者和批评家架构:
我们将网络和目标网络初始化为:
学问
这是我们想要实现的算法的伪代码:
Taken from “Continuous Control With Deep Reinforcement Learning” (Lillicrap et al, 2015)
我们将把它分解为:
- 体验回放
- 演员和评论家网络更新
- 目标网络更新
- 探测
重放缓冲器
正如在深度 Q 学习(和许多其他 RL 算法)中使用的那样,DDPG 也使用重放缓冲区对经验进行采样,以更新神经网络参数。在每次轨迹推出期间,我们保存所有的体验元组(状态、动作、奖励、下一个状态),并将它们存储在一个有限大小的缓存中——一个“重放缓冲区”然后,当我们更新值和策略网络时,我们从重放缓冲器中随机抽取小批量的经验。
以下是重放缓冲区的样子:
我们为什么要用经验回放?在优化任务中,我们希望数据独立分布。当我们以一种基于策略的方式优化一个连续的决策过程时,情况就不是这样了,因为那时的数据不会是相互独立的。当我们将它们存储在重放缓冲区中并随机进行批量训练时,我们克服了这个问题。
行动者(政策)和批评家(价值)网络更新
价值网络的更新类似于 Q-learning 中所做的。更新的 Q 值通过贝尔曼方程获得:
然而,在 DDPG,下一状态 Q 值是用目标值网络和目标策略网络计算的。然后,我们将更新后的 Q 值与原始 Q 值之间的均方损耗降至最低:
*注意原 Q 值是用价值网计算的,不是目标价值网。
在代码中,这看起来像:
对于保单功能,我们的目标是最大化预期收益:
为了计算保单损失,我们取目标函数相对于保单参数的导数。请记住,参与者(策略)函数是可微的,因此我们必须应用链式法则。
但是,由于我们是通过批量经验以非策略方式更新策略,因此我们采用从小批量计算的梯度总和的平均值:
在代码中,这看起来像:
其中优化器使用自适应矩估计(ADAM):
目标网络更新
我们复制目标网络参数,并让它们通过“软更新”缓慢跟踪已学习网络的参数,如下所示:
这可以非常简单地实现:
探测
在离散动作空间的强化学习中,探索是通过概率性地选择随机动作来完成的(例如ε-贪婪或玻尔兹曼探索)。对于连续动作空间,探索是通过向动作本身添加噪声来完成的(也有参数空间噪声,但我们现在将跳过它)。在 DDPG 的论文中,作者使用奥恩斯坦-乌伦贝克过程将噪声添加到动作输出中(乌伦贝克&奥恩斯坦,1930):
奥恩斯坦-乌伦贝克过程产生与先前噪声相关的噪声,以防止噪声抵消或“冻结”整体动态**【1】**。维基百科对奥恩斯坦-乌伦贝克过程提供了详尽的解释。
下面是 Pong 等人编写的 python 实现:
于是我们把演员网络产生的动作输入到
get_action()
函数中,得到一个新的动作,在这个动作中加入了时间相关噪声。我们现在都准备好了!
把它们放在一起
我们在这里有重放缓冲区,奥恩斯坦-乌伦贝克过程,以及 OpenAI Gym 连续控制环境的规范化动作包装器,在 utils.py 中:
以及 models.py 中的演员&评论家网络:
以及 ddpg.py 中的 DDPG 代理:
以及 main.py 中的测试:
我们可以看到 DDPG 代理是否学习到经典倒立摆任务的最优策略:
这就是 DDPG!
点击此处查看完整实施:
用 Python 和 PyTorch 实现强化学习算法的模块化…
github.com](https://github.com/thechrisyoon08/Reinforcement-Learning)
参考
**【1】Edouard leu rent 对 Quora post 的回答“**我们为什么要在 DDPG 的探索中使用奥恩斯坦乌伦贝克过程?”
索尼 NNabla 的深度确定性策略梯度
你好,我是一名研究深度强化学习的研究生。我之前写过一篇关于用 NNabla 实现 Deep Q-Network 的博文。
NNABLA 是什么?
towardsdatascience.com](/deep-q-network-implementation-with-sonys-nnabla-490d945deb8e)
在这里,我将通过 NNabla 引入深度确定性策略梯度(DDPG)。完整实现是这里。
DDPG
DDPG 是一种用于连续控制任务的策略梯度方法。
[## 具有深度强化学习的连续控制
我们将深度 Q 学习成功背后的思想应用于持续行动领域。我们提出一个…
arxiv.org](https://arxiv.org/abs/1509.02971)
在 DDPG,有两个网络:一个政策网络(行动者)和一个行动价值网络(批评家)。这种算法被称为“行动者-评论家”,因为行动者学习政策函数以最大化累积回报,评论家学习(行动)价值函数以正确预测回报。
让我们用 NNabla 制作这两个神经网络。
import nnabla as nn import nnabla.functions as F import nnabla.parametric_functions as PFdef q_network(obs_t, action_t): with nn.parameter_scope('critic'): out = PF.affine(obs_t, 64, name='fc1') out = F.tanh(out) out = F.concatenate(out, action_t, axis=1) out = PF.affine(out, 64, name='fc2') out = F.tanh(out) out = PF.affine(out, 1, name='fc3') return outdef policy_network(obs, action_size): with nn.parameter_scope('actor'): out = PF.affine(obs, 64, name='fc1') out = F.tanh(out) out = PF.affine(out, 64, name='fc2') out = F.tanh(out) out = PF.affine(out, action_size, name='fc3') return F.tanh(out)
相当简单!NNabla 基于由
nn.parameter_scope()
声明的类似 TensorFlow 的命名空间系统来管理权重和偏差。批评家的流失
用一步时差(TD)误差训练评论家:
from the original paper.
这可以用 NNabla 写成如下形式:
# N is a batch size # state_size is a size of input vectors # action_size is a size of the policy output obs_t = nn.Variable((N, state_size)) # observation at t act_t = nn.Variable((N, action_size)) # take action at t rew_tp1 = nn.Variable((N, 1)) # reward value at t+1 obs_tp1 = nn.Variable((N, state_size)) # observation at t+1 ter_tp1 = nn.Variable((N, 1)) # 1.0 if terminal statewith nn.parameter_scope('trainable'): q_t = q_function(obs_t, act_t)with nn.parameter_scope('target'): act_tp1 = policy_function(obs_tp1, action_size) q_tp1 = q_function(obs_tp1, act_tp1)y = rew_tp1 + gamma * q_tp1 * (1.0 - ter_tp1) critic_loss = F.mean(F.squared_error(q_t, y))
上面的代码构造了计算 TD 误差平方的计算图。
演员的损失
相比之下,地面实况操作不是直接可用的。因此,演员被训练来最大化评论家的价值估计。策略网络的梯度计算如下。
from the original paper
这个梯度计算也可以写成 NNabla。
with nn.parameter_scope('trainable'): policy_t = policy_function(obs_t, action_size) q_t_with_actor = q_function(obs_t, policy_t)actor_loss = -F.mean(q_t_with_actor) # gradient ascent
-
有必要更新行动者以最大化价值估计。最终,行动者被引导到在行动-价值函数中获得的高价值空间。目标更新
与 DQN 不同,DDPG 的目标更新是逐步将目标功能与最新参数同步。
with nn.parameter_scope('trainable'): trainable_params = nn.get_parameters()with nn.parameter_scope('target'): target_params = nn.get_parameters()update_ops = [] for key, src in trainable_params.items(): dst = target_params[key] update_ops.append(F.assign(dst, (1.0 - tau) * dst + tau * src))) target_update = F.sink(*update_ops)
F.assign
和tf.assign
差不多。F.sink
是同时运行所有输入的终端节点。放在一起
结论
我介绍了索尼深度学习框架 NNabla 的 DDPG 实现。如果你用 GPU 尝试这个实现,你会发现它的训练速度很快。
如果您需要更多关于 NNabla 的信息,请访问此处。
深潜 AUC
Jheison Huerta photograph of the via lactea reflecting in the salt desert
将机器学习指标转化为现实世界
在本帖中,我们将解释如何将统计数据和机器学习指标转化为对业务团队的更接近的解释。让我们从解释 AUC 的值开始,然后回来解释如何计算它,这将为我们提供一个更好的背景,并帮助您理解它的优势。
上一篇文章(深入困惑矩阵)
如何解读 AUC
AUC 被计算为范围从 0 到 1 的面积,但是对 AUC 值的解释是一种可能性。如果我们从预测中选取任意两个观察值,它们将会以正确的方式排序的可能性。也就是说,AUC 为。90(其面积为 90%)的解释是,如果对任何预测值进行两次观察,它们被正确排序的概率是 AUC 本身,90%。这就解释了为什么最小 AUC 是. 50,因为如果你的模型是完全随机的,两个观测值被正确排序的概率是 50%,即随机。正如最大 AUC 为 1。
Source of gif: https://www.spectrumnews.org/opinion/viewpoint/quest-autism-biomarkers-faces-steep-statistical-challenges/
但毕竟这是什么这样的 AUC。
ROC 曲线的每一端由选定的阈值形成。下面的例子有助于我们理解。想象一下,我们从 20%的削减开始,注意假阴性率和假阳性率,我们在不同的阈值上移动以形成曲线。实际上,当我们要求 sklearn 绘制 ROC 曲线时,它通过如下观察进行观察:
- 计算类为真的几率。P (y = 1)
- 从最高概率到最低概率排序。
- 它从左角开始,如果最可能的观察是正确的,它就向上,如果是错误的,它就向右。
- 对所有的观察重复这个过程后,我们就有了 ROC 曲线。
- 我们将 AUC 计算为 ROC 曲线下的面积。
AUC 只不过是在 ROC 曲线下形成的面积。但是它带来了非常有趣的解释。
Source of gif: https://www.spectrumnews.org/opinion/viewpoint/quest-autism-biomarkers-faces-steep-statistical-challenges/
AUC 曲线给出了类别分离程度的概念
一个好的模型是一个可以很好地分离两个类别的模型,所以我们的模型在两个类别之间的交集越少,它就越好,因此 AUC 就越大。
AUC 对患病率不敏感
我们在混淆矩阵中遇到的一个非常恼人的问题是,普遍性(即类别之间的比率)极大地影响了这些指标,但 AUC 不受此影响,在下面的 gif 中,我们有一个真实的例子。AUC 曲线在右边的绿色部分,我们注意到它没有移动到任何患病率水平。
Source of gif: https://www.spectrumnews.org/opinion/viewpoint/quest-autism-biomarkers-faces-steep-statistical-challenges/
解释曲线的形状
当我们有两条不同的 AUC 曲线时,我们必须在每种情况下决定哪一条最适合我们。在下图的情况下,很明显模型 3 是最好的,模型 1 是最差的。这个决定不仅来自于 AUC 值更高,而且曲线形状显示模型 3 对于任何选择的阈值都更好。请注意,在曲线的开始(最容易预测的地方),三条曲线几乎相同,随着我们向更困难的预测移动,模型越向右开始区分。
现在一个更难的问题,如果曲线有相同的面积,但形状不同,如下图所示?这两种型号哪个更好?在这种情况下,曲线 A 对于疾病检测等问题会更好,因为它比曲线 b 更敏感
一个有趣的特征是,如果这两条曲线具有相同的 AUC 为 80,并且我们组装了这两个模型,则很可能最终模型将优于两个初始模型,因为它们可以结合两个模型的优点并获得两条曲线的最佳效果。
将 AUC 与人类专家进行比较
一个经过训练的机器学习模型有一个完整的 ROC 曲线,但在实践中,我们只能使用曲线上的单个点,并选择与该点相关的比率。在一个比较检测皮肤癌的模型(蓝色曲线)和多个医生(红点)的例子旁边,注意每个医生是一个单点。有些医生更敏感,有些更准确,但他们仍然选择单个切口,所以他们用点来表示,因为我们的模型有所有点的曲线。
以前的帖子
将机器学习指标转化为现实世界
medium.com](https://medium.com/@marcos.silva0/confusion-matrix-deep-dive-8a028b005a97)
参见:
深入研究用于模型解释的 Catboost 功能
我们真的了解我们构建的 ML 模型内部发生了什么吗?我们来探索一下。
在我之前的博客中,我们看到了 XGBoost 和 LightGBM 的对比研究。通过分析,我们可以得出结论,catboost 在速度和准确性方面都优于其他两个。在这一部分中,我们将深入研究 catboost,探索 catboost 为高效建模和理解超参数提供的新特性。
对于新读者, catboost 是 Yandex 团队在 2017 年开发的开源梯度提升算法。这是一种机器学习算法,允许用户快速处理大型数据集的分类特征,这与 XGBoost & LightGBM 不同。Catboost 可以用来解决回归、分类、排序问题。
作为数据科学家,我们可以轻松地训练模型并做出预测,但是,我们经常无法理解那些花哨的算法内部发生了什么。这也是为什么我们看到离线评测和最终生产的模型性能存在巨大差异的原因之一。我们早就应该停止将 ML 作为一个**【黑箱】**来对待,并在提高模型准确性的同时重视模型解释。这也将帮助我们识别数据偏差。在本部分中,我们将了解 catboost 如何通过以下功能帮助我们分析模型并提高可见性:
特征重要性
为什么要知道?
除了选择要素重要性的类型之外,我们还应该知道要使用哪些数据来确定要素的重要性——训练、测试或完整数据集。选择一个比另一个有利也有弊,但是最终,您需要决定您是否想要知道模型在多大程度上依赖每个特征来进行预测(使用训练数据)或者该特征在多大程度上有助于模型在看不见的数据上的性能(使用测试数据)。我们将在本博客的后面看到,只有一些方法可以用来发现不用于训练模型的数据的特征重要性。
如果你关心第二个,并假设你有所有的时间和资源,找到特性重要性的最粗略和最可靠的方法是训练多个模型,一次留下一个特性,并在测试集上比较性能。如果性能相对于基线(当我们使用所有特性时的性能)变化很大,这意味着该特性很重要**。**但是由于我们生活在一个需要优化准确性和计算时间的现实世界中,这种方法是不必要的。以下是 catboost 让您找到模型最佳功能的几种智能方法:
预测值变化
对于每个要素,PredictionValuesChange 显示了当要素值发生变化时,预测的平均变化量。重要性的值越大,如果该特征被改变,则预测值的平均改变越大。
优点:计算成本很低,因为你不必进行多次训练或测试,也不用存储任何额外的信息。您将得到作为输出的标准化值(所有的重要性加起来为 100)。
**缺点:**它可能会给排名目标带来误导性的结果,它可能会将 groupwise 功能放在顶部,即使它们对最终的损失值有一点影响。LossFunctionChange
为了获得该特征的重要性,catboost 简单地采用在正常情况下(当我们包括该特征时)使用模型获得的度量(损失函数)和没有该特征的模型(该模型近似地使用原始模型构建,该特征从集合中的所有树中移除)之间的差异。差异越大,该特征越重要。catboost 文档中没有明确提到我们如何找到没有特征的模型。
**优点&缺点:**这适用于大多数类型的问题,不像
*predictionvalueschange*
那样,在排序问题时会得到误导性的结果,同时,它的计算量很大。形状值
https://github.com/slundberg/shap
SHAP值将预测值分解成每个特征的贡献。与基线预测(训练数据集的目标值的平均值)相比,它测量特征对单个预测值的影响。
shap 值的两个主要用例:
- 特征的对象级贡献
https://github.com/slundberg/shap
2。整个数据集的摘要(整体特征重要性)
shap.summary_plot(shap_values, X_test)
虽然我们可以通过 shap 获得准确的特征重要性,但它们在计算上比 catboost 内置的特征重要性更昂贵。关于 SHAP 值的更多细节,请阅读这个内核。
加成
另一个基于相同概念但不同实现的特征重要性是——基于排列的特征重要性 。尽管 catboost 不使用这个,但这纯粹是与模型无关的并且易于计算。我们如何选择一个呢?
虽然
PredictionValuesChange
&LossFunctionChange
都可用于所有类型的指标,但建议使用LossFunctionChange
对指标进行排名。除了PredictionValuesChange
之外,其他所有方法都可以使用测试数据,使用在训练数据上训练的模型来发现特征重要性。为了更好地理解差异,下面是我们讨论的所有方法的结果:
****
Results of catboost feature imp. to predict if people will report over $50k of income from the classic “adult” census dataset (using log-loss)
****
从上面的图中,我们可以看到大多数方法在顶部特性上是一致的。看起来
LossFunctionChange
最接近 shap(更可靠)。然而,直接比较这些方法是不公平的,因为predictionvalueschange
是基于列车数据,而所有其他方法都是基于测试数据。我们还应该看到运行所有这些应用程序所需的时间:
互动
使用此参数,可以找到一对特征的强度(两个特征加在一起的重要性)。
在输出中,您将获得每对要素的列表。该列表将有 3 个值,第一个值是该对中第一个要素的索引,第二个值是该对中第二个要素的索引,第三个值是该对的要素重要性分数。有关实现细节,请查看嵌入式笔记本。
有趣的是,单个特征重要性中的前两个特征不一定是最强的一对。
笔记本
对象重要性
你为什么要知道?
- 从训练数据中移除最无用的训练对象
- 根据哪些对象被认为是最“有帮助”的,对一批新对象进行优先排序,类似于主动学习
利用这个功能,您可以计算每个对象对测试数据的优化指标的影响。正值反映优化指标增加,负值反映优化指标减少。这个方法是在[这篇文章](http://This mode is an implementation of the approach described in the Finding Influential Training Samples for Gradient Boosted Decision Trees paper)中描述的方法的一个实现。这些算法的细节超出了本博客的范围。
对象重要性的 Catboost 教程
CatBoost 教程存储库。在 GitHub 上创建一个帐户,为 catboost/教程开发做贡献。
github.com](https://github.com/catboost/tutorials/blob/master/model_analysis/object_importance_tutorial.ipynb)
cb.get_object_importance
中有三种类型的update_method
:- 单点:最快和最不精确的方法
- TopKLeaves:指定叶子的数量。该值越高,计算越精确,速度越慢
- AllPoints:最慢也是最准确的方法
例如,以下值将方法设置为 TopKLeaves,并将叶子数限制为 3:
TopKLeaves:top=3
模型分析图
Catboost 最近在其最新更新**中推出了这一功能。**有了这个功能,我们将能够直观地看到算法如何分割每个特征的数据,并查看特定于特征的统计数据。更具体地说,我们将能够看到:
- 每个条柱(条柱用于连续要素)或类别(当前仅支持 OHE 要素)的平均目标值
- 每个箱/类别的平均预测值
- 每个箱中的对象数量
- 不同特征值的预测:对于每个对象,特征值是变化的,以使其落入某个箱中。然后,该模型根据该特征的新值来预测目标,并在一个箱(由红点给出)中取预测的平均值。
该图将为我们提供信息,如我们的分割有多均匀(我们不希望所有对象都在一个容器中),我们的预测是否接近目标(蓝色和橙色线),红线将告诉我们我们的预测对某个特征有多敏感。
数字特征分析
一键编码特征分析
感谢您阅读本文。希望下次您能够利用这些工具来更好地理解您的模型。
在机器学习社区对我之前关于CatBoost vs . Light GBM vs . XGBoost的博客做出积极回应后,CatBoost 团队联系我,看我是否有兴趣报道关于该库的更深入的主题。感谢 CatBoost 团队帮助回答我的问题!
**关于我:**我目前是优步地图团队的一名数据科学家。如果你有兴趣在优步解决具有挑战性的问题,请通过 LinkedIn 联系我。你可以在这里阅读我的其他博客。
参考
深入了解卷积网络
Visualization from http://terencebroad.com/convnetvis/vis.html
从积木到最先进的架构,触及可解释性和偏见。
By the end of this post you will understand this diagram. Image courtesy of FloydHub.
介绍
卷积网络(ConvNets)是一类高效的神经网络,在感知任务(如对象识别)中实现了令人印象深刻的性能。他们的建筑是由视觉皮层松散地启发而来的。2012 年 AlexNet ,一种 ConvNet,以较大优势赢得了 ILSVRC 2012 竞赛,引发了对深度学习的巨大兴趣,这种兴趣一直持续到今天。2019 年,对象检测的最先进架构是 ResNet,这是一种 ConvNet。
在本文中,我假设对标准的全连接神经网络(或多层感知器,MLP)有所了解。在概述了 ConvNets 激活之后,我将深入了解卷积的概念和其他构建模块(池化、批处理规范化、1x1 过滤器等)。接下来,我将简要说明一些实现最先进结果的高级架构(Inception、ResNet)。在最后部分,我将触及可解释性和偏见的话题。每个部分都包含一个参考文献和链接列表,以供进一步研究。一些概念通常适用于深度神经网络,但我将在 ConvNets 的上下文中说明它们。
如果您是 ConvNets 的新手,需要花一些时间来消化这些材料,慢慢来,阅读许多资料。你可以用这篇文章作为围绕 ConvNets 的想法的快速参考。如果您发现任何错误,或者如果您认为我错过了其他主题,请在评论部分告诉我。
目录
一个网络的概述
卷积神经网络(ConvNets)是一类专门用于图像处理的神经网络。与其他神经网络一样,它们通过许多层将输入转换为输出。在 ConvNets 中,层有一个卷积步骤,一个汇集步骤(可选)和一个非线性激活。神经网络中的每一层通过线性和非线性运算将输入张量转换为输出张量。所有这些中间张量(包括网络输入和输出)被称为激活,它们都是输入的不同表示。
Figure 1. Activation tensors in a convolutional neural net.
当我们从输入到输出时,我喜欢通过可视化激活的形状来开始说明 ConvNets(参见图 1 )。每一层都通过线性和非线性操作来转换激活(我们将在下一节的中看到细节)。当我们穿过这些层时,激活的空间维度会缩小,而深度会增加。ConvNet 的最后一部分将 3D 激活转换为 1D,通常通过平均池化(参见池化部分)。最后,1 或 2 个完全连接的层将激活投射到最终分类的输出空间。在这篇文章中,我用分类作为最终任务的例子。一些架构通过直接生成长度与类别数量匹配的 1D 激活来避免最终的密集层。
激活的流程显示了输入是如何在一个越来越“丰富”的特征空间(增加的深度)中表示的,同时牺牲了空间信息(降低的高度/宽度)。最后完全连接的层放弃任何空间信息,以实现最终的分类任务。当我们经过各层时,特征不仅在数量上(深度大小)增加,而且复杂性也增加,是前一层特征的组合。换句话说,网络构建输入的层次表示:第一层根据基本特征(如边)表示输入,第二层根据更复杂的特征(如角等)表示输入。更深的一层可以识别抽象的特征,如眼睛甚至人脸。引人注目的是,ConvNet 将在训练过程中自主学习这一特征层次。
在训练过程中,网络将学习一种有利于解决指定任务的表示法。对于像 ImageNet(数百万张图像,分为 1000 个类别)这样的大型和多样化的数据集,学习到的表示将足够通用,可用于许多其他视觉感知任务,即使是在不同或非常特定的领域。这是迁移学习的基础:在大数据集上训练一次模型,然后在新的特定领域(可能很小)数据集上微调模型。这允许快速调整预先训练的网络,以快速和高精度地解决新问题。
卷积步骤
现在让我们放大到一个卷积层。请记住,我们在神经网络中所说的卷积与信号处理中的经典 2D 卷积有点不同。虽然广义的想法是相似的,但在数学上并不相同。
Figure 1.1 Convolution of a 5x5 input (blue) with 3x3 kernel (grey) with a stride of 2 and padding of 1. The 3x3 output is in green (source).
经典卷积和深度学习卷积都是通过对输入数组应用核来计算输出的。每个输出像素是输入和内核之间的逐元素乘积之和(点积)。通过在输入上移动核,我们获得不同的输出像素。我们每步移动的像素数(1 或更多)称为步幅。
一个基本的区别是输入和输出张量的形状:在神经网络中,我们有额外的维度。
如果你不熟悉 2D 卷积,看看这个伟大的互动演示获得一些直觉。
Figure 2. A single convolution layer. The convolution output is a tensor with increased depth. Each spatial position in the output (yellow “rod”, middle) depends on a portion of the input (the “receptive field”, left) and on a bank of filters (kernels).
与经典 2D 卷积的区别
在 2D 卷积网中,卷积具有以下性质:
- 输入和输出激活(也叫特征图 ) 是 3D 数组(高度、宽度、深度)。第一层输入深度为 3 (RGB)。我们越深入地层,深度就越大。注意,当考虑小批量时,输入实际上是 4D。
- 和输入和输出一样,内核也是 3D 的。空间大小通常为 3x3、5x5 或 7x7,深度等于输入深度。内核也被称为过滤器。
- 每层有多个内核 称为一个**滤波器组。**内核的数量决定了输出的深度(通常大于输入深度)。
- 与经典卷积不同,在 ConvNets 中,我们在单个步骤中计算多个卷积(一个卷积对应一层中的一个内核)。
- 与经典卷积不同,在乘法之前,核不沿空间维度翻转(这使得卷积不可交换,但该属性与神经网络无关)。
感受野
感受域是对输出像素有贡献的输入的 3D 区域(见图 2 中的黄色立方体)。注意,一个输出像素有许多“值”,每个内核一个(图 2 中的 64)。通过排列对应于不同感受野的所有输出向量,我们获得了完整的 3D 激活。
通常,两个相邻输出位置的感受野会部分重叠。只有当步幅等于内核大小时,才没有重叠。
参数数量
层中的所有核(图 2 中的 64)可以排列成单个 4-D 形状张量
(#内核,内核大小,内核大小,输入深度)
这些参数包括核中的所有权重加上 1D 偏移向量。
偏差为每个内核引入了一个额外的参数。像核一样,每个空间位置的偏差都是相同的,因此偏差参数与核的数量(或输出深度)一样多。
将偏差和权重放在一起,层中的总参数总计为:
(#内核数 x 内核大小 x 内核大小 x 输入深度)
- #内核
小批量
实际上,图 1 的激活不是针对单个图像计算的,而是针对小批量计算的。在这种情况下,所有激活都将有一个大小为 batch_size 的额外维度。必须考虑批量大小,因为它直接影响训练和评估模型所需的 RAM。通常,我们使用 GPU RAM 中能够容纳的最大批量。
批量标准化
批处理规范化(BatchNorm)是近年来深度学习领域最重要的进展之一。BatchNorm 可以在几乎任何神经网络架构上加速和稳定训练,包括 ConvNets。
Figure 3. The batch normalization algorithm from the original paper. Before entering the ReLU, each batch is normalized with zero mean and unit standard deviation. Then, each activation is scaled and shifted using two parameters (gamma and beta). This last addition turns out to be the critical step making BatchNorm so effective. The scale-shift transform allows the optimization to directly control the scale of each activation through one parameter (gamma). Without it, a change of scale can only be achieved with a coordinated change in multiple weights that contribute to the activation.
奇怪的是,最初的 BatchNorm 作者将性能的提高归因于“内部协方差偏移的减少。但最近发现,BatchNorm 反而平滑了优化前景,允许更大的学习率快速收敛到更准确的解决方案。只是提醒一下,理论,即使是令人信服的或“直觉的”,也必须经过经验验证。
- “批量标准化:通过减少内部协变量转移加速深度网络训练”,Sergey Ioffe,Christian Szegedy,arXiv:1502.03167(2015)
- 《批量归一化》,I. Goodfellow,J. Bengio,a .库维尔,深度学习书 Ch 8.7.1 ( 2016 )
- “批处理规范化如何帮助优化?”、桑图尔卡等人arXiv:1805.11604(2018)
其他标准化
BatchNorm 无疑是深度学习中最流行的规范化方法,但不是唯一的。这一领域的研究非常活跃,在不久的将来我们可能会看到新的进展。问题是双重的。一方面,BachNorm 难以应用于递归网络,因为它依赖于小批量均值和标准差。另一方面,BatchNorm 的效果是相当偶然的,对 BatchNorm 如何帮助优化的更多研究可以带来更好的规范化方法。
为了简洁起见,我将只提到一种替代的归一化方案:**权重归一化。**在该方案中,我们对权重进行归一化,而不是对激活进行归一化。特别地,我们将每个核(对单次激活有贡献的所有权重)归一化为具有单位范数。然后,为了保持模型的表现力,我们还为每个激活添加了一个比例参数。原则上,这应该有助于以类似于 BatchNorm 的方式进行训练,通过提供一个单一的直接“旋钮”来改变每个激活,从而提供一个通向最小值的“更容易”(即更平滑)的路径。
Figure 4. Different approaches to normalize of activations in a mini-batch. (source)
已经提出了许多其他的归一化方法,每种方法都有其利弊。要获得出色的概述,请参见 Keita Kurita 的“深度学习中的规范化方法概述”。
- “权重归一化:加速深度神经网络训练的简单重新参数化”,Tim Salimans,Diederik P. Kingma,arXiv:1602.07868(2016)
- 深度学习中归一化方法概述, Keita Kurita,(2018 年 11 月 30 日**)**
联营
Figure 5. Example of a max-pooling block.
卷积块之后通常是汇集块,以减少激活空间维度。池有助于减少更深层的内存消耗。这也是将空间信息转化为特征的重要步骤。根据伊恩·戈德费罗等人的深度学习书籍****
池化有助于使表示对于输入的小平移近似不变。
有不同的汇集策略。最常见的是最大轮询和平均池**。在所有情况下,池化将输入“块”(感受野)减少为 1×1 输出块,同时保持深度不变。通过选择最大输入激活(max-pooling)或取平均值(average-pooling)来实现减少。与卷积类似,汇集块将感受野映射到输出中的单个“像素”。出于这个原因,我们可以定义一个轮询空间大小(2x2、3x3 等。)和大步走。通常,步幅被选择为具有不重叠的感受野,以实现空间尺寸的减小。通常,最后的汇集层是整个空间激活的平均值(全局平均汇集或间隙),导致 1x1 输出激活(图 1 中大小为 512 的 1D 激活)。与卷积不同,池化没有任何参数,输出要素(深度)的数量始终与输入相同。**
具有“可学习结构”的池层已被提出,但迄今为止受欢迎程度有限(贾等人 2012 )。
- 网络中的网络,,,水城颜,arXiv:1312.4400(2013)
- “Ch 9.3:Pooling” I . good fellow,J. Bengio,a .库维尔,深度学习书Ch 9.3(2016)
- “超越空间金字塔:融合图像特征的感受野学习”,贾,黄畅,Trevor Darrell doi:10.1109/cvpr . 2012.6248076(2012)
1x1 卷积
一些架构使用 1x1 滤波器。在这种情况下,过滤器映射形状的输入
(数量 _ 过滤器 _i,高度 _i,宽度 _i)
到形状的输出:
(数量 _ 过滤器 _o,高度 _i,宽度 _i)
注意只有特征的数量发生变化**,而高度和宽度保持不变。在这种情况下,每个输出像素是仅依赖于一个输入像素的 num_filters_o 特征的向量(大小为 num_filters_i 的向量)。每个输出特征是同一像素的输入特征的(不同)线性组合,该像素是大小为 1x1 的感受野。**
1x1 滤波器用于减少输出要素的数量,从而在保持空间维度不变的同时降低计算成本。例如, inception network 使用 1x1 过滤器来减少功能并创建“瓶颈”,从而使架构在计算上更加经济实惠。然而,如果瓶颈太紧,可能会损害网络性能。
当卷积核的大小大于 1×1 时,
每个输出特征仍然是感受野中所有输入特征
的线性组合,在这种情况下是> 1 像素宽。在林等人的原始论文中,1x1 卷积被称为网络中的网络原始论文将其描述为 1x1 输入和输出特性之间的“迷你”全连接层。请注意,使用相同的权重将相同的全连接层应用于每个空间位置。
- 网络中的网络,,,水城颜,arXiv:1312.4400(2013
开始
ILSVRC 2014 获奖者是 Szgedy 等人的 GoogLeNet 架构。其中介绍了下面所示的初始模块**。**
Figure 6. Inception module, the building block of the GoogLeNet architecture.
在卷积网络中,一个重要的选择是卷积核的空间大小。第一层的大小通常为 7x7,后面所有层的大小通常为 3x3。初始模块并行执行许多卷积,而不是为卷积选择一个大小。图 5 显示了在 inception v1 论文中提出的 inception 块。对同一输入执行大小为 1x1、3x3 和 5x5 的卷积(蓝色块)以及最大池(红色块)。额外的 1x1 卷积(黄色块)减少了深度大小,从而大大降低了内存需求。这些平行路径产生输出张量(具有相同的空间大小),这些输出张量沿着深度被连接起来以形成层输出。
自第一篇论文以来,已经提出了对 inception 架构的许多更新,包括 inception v2、v3、v4 和 inception-resnet 。后者结合了多重卷积和跳跃连接的初始思想(参见下一节)。
- “用卷积更深入”,C. Szegedy 等人(2014)arXiv:1409.4842
- 《Inception-v4、Inception-ResNet 以及剩余连接对学习的影响》,克里斯蒂安·塞格迪、谢尔盖·约菲、文森特·范霍克、亚历克斯·阿莱米,(2016)arXiv:1602.07261
- 盗梦空间网络版本的简单指南,Bharath Raj(2018 年 5 月)****
雷斯内特
多层神经网络中的一个已知问题是消失梯度。本质上,在反向传播期间,导数乘以前一层的导数。所以,当我们到达第一层的时候,梯度会变得非常小或者爆炸(溢出)。这种效应使得很难训练深度神经网络,包括神经网络。为了解决这个问题,何等人引入了“跳过连接”这一构成 ResNet 架构的构建模块。**
Figure 7. Illustration of the skip-connection, the building block of the ResNet architecture. (source)
在 ResNet 中,一层的输出不仅被馈送到下一层,而且被馈送到前面两层的输入。输入被添加到层输出,然后被馈送到下一层。
自从赢得 ILSVRC 2015 竞赛以来,ResNet 仍然是最先进的 ConvNet 架构。预训练的 ResNet34 或 ResNet50 是迁移学习中事实上的标准,用于实现从医学成像到泰迪熊探测器的专业应用。
- 《深度残差学习用于图像识别》,,,,,任,,(2015)arXiv:1512.03385
- “ResNet 及其变种概述”,Vincent Fung ( 2017 )
可解释性
为了建立对智能系统的信任,并将其有意义地融入我们的日常生活,很明显,我们必须建立“透明”的模型,解释它们为什么预测它们所预测的东西。
来自Grad-CAMarXiv:1610.02391。
众所周知,理解神经网络如何做出决定是一项艰巨的任务。解释神经网络的结果不仅是重要的科学努力,也是许多应用所需要的。神经网络可解释性是一个活跃的研究课题,涉及多种网络可视化技术。
概括地说,有两种广义的可解释性技术。一个称为属性,旨在找到输入图像中用于做出决定的区域。第二种称为特征可视化*,旨在可视化输入图像中的哪些特征激活了特定的神经元或神经元群。*****
Figure 8. Two approaches in interpreting ConvNets: feature visualization and attribution. Source Olah et al. 2017.
在一些架构上,属性可以通过将隐藏层中的空间激活与输入图像叠加并绘制所谓的显著性图来完成(图 8,右图)。显著图具有与上一次 3D 激活相同的空间分辨率,这是低的,但通常是足够的。适用于任何架构的这种方法的扩展是 Grad-CAM,其中显著图是最后空间激活(具有 3D 形状的最后激活)的加权平均值。这个加权平均值中的权重是从关于每次激活的损失函数的梯度计算的。Grad-CAM 可以应用于任何网络,甚至非分类任务。
Figure 9. Feature visualization. The top row shows the “optimization objective”: single neuron, channel, layer, a class before soft-max, a class after soft-max. The bottom row shows an input image resulting from optimizing the corresponding objective. Source Olah et al. 2017.
对于特征可视化,我们可以在每一层中绘制内核权重。每个内核显示在层输入中检测到的模式。在这种情况下,解释在第一层比较容易,但在更深的层变得更加困难。另一种简单的方法是绘制给定输入的激活。****
生成(通过优化)输入图像以最大限度地激活神经元、通道、层或类的更细致的方法(图 9)。这允许构建“特征”的地图集,其可视地表示网络在每一层中响应什么。这种方法的缺点是生成的图像缺乏多样性,可能无法代表网络所响应的全部空间特征。关于进一步的信息,Distill.pub 发表的论文既有深刻的见解,又有令人惊叹的图表。
- " Grad-CAM ",R. R. Selvaraju,M. Cogswell,A. Das,R. Vedantam,D. Parikh,D. Batra ( 2016 ), arXiv:1610.02391
- “理解 CNN ”,安德烈·卡帕西,CS231n 课程
- " 特征可视化 " ,克里斯奥拉,亚历山大莫尔德温采夫,路德维希舒伯特( 2017 ),distilt . pub,doi:10.23915/distilt . 00007
- 《用激活图谱探索神经网络》,Shan Carte,Zan Armstrong,Ludwig Schubert,Ian Johnson,Chris Olah ( 2018 ),distilt . pub,doi:10.23915/distilt . 00015
偏见
Figure 10. Bias in state-of-the-art face-recognition systems (source).
如果不提到偏倚问题,对 ConvNets 的讨论是不完整的。机器学习中的偏差来自数据集和/或算法中的偏差,这反过来反映了创建系统的人的偏差。虽然偏见是机器学习中的一个严重问题,但 ConvNets 应用程序提供了一些突出的例子,说明它如何影响人们的生活。
请记住,网络将“学习”对解决任务有用的表示。例如,如果我们的目标是识别人脸,理想的数据集应该尽可能多样化,以便以平衡的方式表示所有的种族、年龄和性别组。实际上,大多数流行的数据集都过度代表了白人男性。正如研究员 Joy Buolamwini 发现的那样,这导致了当前商业人脸识别系统的严重偏见。在这些系统中,有色人种女性的面部识别准确率比男性低个数量级(图 4)。例如,这些系统已经或将要被部署来识别犯罪嫌疑人。不幸的是,如果你是一个黑皮肤的女人,你会被误认为是一个比白人高一百倍的罪犯!
作为机器学习实践者,我们不能放弃我们的道德责任。我们知道我们创造的系统会以前所未有的规模扰乱人们的生活。因此,我们必须采取措施克服这种偏见。根据《福布斯》杂志,雷切尔·托马斯是“人工智能领域 20 位不可思议的女性”之一,她写了很多关于偏见问题的文章,她的帖子是一个极好的信息来源。
- 关于 AI 让我害怕的五件事,Rachel Thomas,fast.ai 博客( 2019 )
- 性别阴影,Joy Buolamwini,( 2018 )麻省理工学院媒体实验室
- AI 安全需要社会科学家,杰弗里欧文,阿曼达阿斯克尔,(2019doi:10.23915/distilt . 00014
其他主题
这里涵盖的主题还远未完成。这里有几个我没有谈到的话题:
- 优化:培训需要使用众多优化方法中的一种。
- 卷积运算:步幅和填充的效果形成一个题目叫做“卷积运算”。一个分数步距定义了转置卷积(也称为不恰当的“去卷积”),其在生成模型中用于生成图像。**
- 敌对攻击:网络很容易被微小的敌对干扰所欺骗。精心选择的图像扰动(人眼不可见)可以改变网络输出。使 ConvNets 对敌对例子具有鲁棒性的研究正在进行中。
结论
在这篇文章中,我谈到了 ConvNets 的几个基本方面。即使是最先进的架构也是基于卷积层的基本构建模块。
ConvNets 可能已经“解决”了图像识别问题,但许多问题仍然存在。尽管最近取得了进展,解释结果仍然是一个挑战,一个阻碍某些领域应用的问题。用更小的数据集进行更好的泛化也将极大地扩展可处理问题的类别。但是,最重要的是,我们需要承认并努力克服社会偏见。鉴于对个人和社区的巨大影响,在这些系统中争取更多的公平是至关重要的。
参考
在这里你可以找到关于 ConvNets 的一般参考资料。具体主题的参考资料在每一节的末尾。
- Ch。9.卷积网络》,I. Goodfellow,J. Bengio,a .库维尔,深度学习著作 (2016)。
- “第六课:正规化;盘旋;数据伦理、 Fast.ai 程序员实用深度学习、v3"
- 谓 Ch。6:深度学习、神经网络与深度学习,迈克尔·尼尔森(2015)https://neuralnetworksanddeeplearning.com/
- 用于视觉识别的 CS231n 卷积神经网络安德烈·卡帕西斯坦福 CS231n 讲座****
- 《深度学习的卷积算法指南》,文森特·杜穆林,弗朗切斯科·维辛( 2016 ), arXiv:1603.07285 (另见他们的动画)
其他博文:
- Adit Deshpande 的《理解卷积神经网络的初学者指南》
- Irhum Shafkat 的“直观理解用于深度学习的卷积”
来自卷积神经网络拓扑可视化的标题图像。
深入探究科幻犯罪
生成数据可视化以分析旧金山的犯罪率
旧金山因许多事情而闻名:它充满活力的科技环境、标志性的金门大桥、迷人的缆车和(可以说是)世界上最好的餐馆。它也是 LGBT 和潮人文化的中心,这使它成为极具吸引力的旅游和移民目的地。然而,随着旅游业的蓬勃发展,财富不平等的加剧,以及成千上万的无家可归者,这个城市并不缺少犯罪。在本帖中,我邀请您深入研究旧金山的犯罪数据,以获得对旧金山犯罪环境的一些见解,并为您自己的犯罪分类模型设计特征。
探索性分析
你可以从 Kaggle 下载旧金山犯罪分类数据。该数据集包含 2003 年至 2015 年来自该市所有社区的近 800,000 份犯罪报告。它包括以下变量:
San Francisco Crime Rates Dataset Variable Description
让我们首先探索我们的目标变量,并找出旧金山最常见的 10 种犯罪类型。我们将根据事件数量对类别进行排序,然后使用水平条形图展示我们的调查结果:
*# Get 10 most common crimes* most_common_cat = train['Category'].value_counts()[0:9].sort_values() most_common_cat.values categs = most_common_cat.index y_pos = np.arange(len(categs)) counts = most_common_cat.values plt.barh(y_pos, counts, align='center', alpha=0.5) plt.barh(y_pos, counts, align='center', alpha=0.5) plt.yticks(y_pos, categs) plt.xlabel('Number of Incidences') plt.show()
Most Common Crime Types
得知暴力犯罪不在犯罪发生率之首,令人颇感欣慰。然而,财产犯罪似乎相当普遍。现在让我们来看看哪些区的登记犯罪数量最高。
为此,我们将使用叶,这是一个易于使用的工具,创建交互式地图。要运行下面的代码块,你需要在你的终端上运行
pip install folium
来安装 Folium,或者直接在笔记本上添加“!”在司令部前面。然后,您需要下载这个单元格中指定的 JSON 文件:by_zone = train.apply(pd.Series.value_counts).reset_index() *# Load SF data* !wget --quiet https://cocl.us/sanfran_geojson -O sf_neighborhoods.json sf_zones = r'sf_neighborhoods.json' SF_COORDINATES = (37.76, -122.45) *# Create an empty map zoomed in on San Francisco* sf_crime_map = folium.Map(location=SF_COORDINATES, zoom_start=12) sf_crime_map.choropleth( geo_data=sf_zones, data=by_zone, columns=['index', 'PdDistrict'], key_on='feature.properties.DISTRICT', fill_color='YlOrRd', fill_opacity=0.7, line_opacity=0.2, legend_name='San Fransisco Crime by Neighborhood' ) sf_crime_map
该单元的输出是一个交互式地图,其中包含按警察局辖区分类的犯罪率:
San Francisco Crime Rate by Neighborhood
您可以通过绘制单个犯罪类别或检查分布随时间的变化来随意试验这个情节。
接下来,我们来看看犯罪在工作日的分布。我首先构建了一个交叉表来获取每个工作日的犯罪数量。之后,我使用 seaborn library 中的热图对计数进行了标准化和可视化:
*# Extract the most common crimes from the data* most_commons = train[train['Category'].apply(**lambda** x: x **in** categs)] *# Build a cross table to get the number of each crime type per day of week* cat_per_week_common = pd.crosstab(most_commons['Category'], most_commons['DayOfWeek']) *# Calculate percentages of crimes* cat_per_week_common = cat_per_week_common.div(cat_per_week_common.sum(axis=1), axis=0) *# Rearrange columns* cat_per_week_common = cat_per_week_common[['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday','Sunday']] *# Transform into a heat map* fig = plt.figure(figsize=(10,10)) ax = sns.heatmap(cat_per_week_common, cmap="BuPu", linewidths=.5) plt.xticks(fontsize=12,rotation=45,ha='right') plt.yticks(fontsize=12) plt.xlabel("") plt.ylabel("")
Most Common Crimes per Day of Week
如上图所示,大多数犯罪类型,如袭击和破坏行为,都发生在周末人们外出的时候。一些其他类型的犯罪更经常发生在工作日,这可能与警察工作时间有关。
最后,我们来看看 SF 警察局的成功率。具体来说,有多少暴力犯罪得到解决。让我们先从类别列表中划分出暴力犯罪的子集。我选择了我认为有趣的,但也可以随意探索其他类别!之后,我们可以创建逮捕变量,将所有可能的决议分为两类:起诉或不起诉。我假设“未被起诉”和“无”是仅有的两个对应于负面类别的决议。我们将计算已解决案件的比例,并使用水平图绘制它们。这一次,我们将绘制比例图,而不是绝对计数:
*# Pick crime types of interest* violent = train[train.Category.isin(['ASSAULT', 'BURGLARY', 'KIDNAPPING', 'ROBBERY', 'SEX OFFENSES FORCIBLE'])].copy() *# Create Arrest variable* violent['Arrest'] = np.where(violent['Resolution'].isin(['NONE', 'NOT PROSECUTED']), 0,1) *# Calculate counts* arrest_counts = violent['Category'][violent.Arrest==1].value_counts()[0:9] total_counts = violent['Category'].value_counts()[0:9] arrest_counts = arrest_counts/(total_counts).sort_index() total_counts = total_counts/(total_counts).sort_index() *# Plot values* total_counts.plot.barh(color='crimson', label= 'Unsolved') arrest_counts.plot.barh(color='mediumseagreen', label='Solved') plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.) plt.xlabel('Proportion') plt.show()
Solved and unsolved violent crimes in SF
我们可以看到,在我们挑选的所有暴力犯罪中,警方的成功率都在 50%以下。在入室盗窃案中,这一比例仅为 17%。
特征工程
我们的数据集有许多观测值,但只有有限数量的要素。在本节中,我们将创建两组要素:时间要素和空间要素。时态特征可以从日期变量中提取。除了月、日和小时等明显的特征之外,我还提取了营业时间、周末和国定假日。要访问所有的美国假日,只需从 pandas.tseries.holiday 导入 USFederalHolidayCalendar。下面的函数将帮助您提取所有的功能:
**def** time_engineer(data): *'''* *Extract temporal features from dates.* *'''* *# Turn strings into timestamp objects* data.Dates = pd.to_datetime(data.Dates) *# Extract years, months, times of the day, and weeks of year* data['Year'] = data['Dates'].dt.year data['Month'] = data['Dates'].dt.month data['Day'] = data['Dates'].dt.day data['Hour'] = data['Dates'].dt.hour data['WeekOfYear'] = data['Dates'].dt.weekofyear *# Add a dummy for public holidays* cal = calendar() holidays = cal.holidays(start=data['Dates'].min(), end=data['Dates'].max()) data['Holiday'] = data['Dates'].dt.date.astype('datetime64').isin(holidays).astype('bool') *# Add times of a day* data['Night'] = np.where((data['Hour']< 6), 1, 0) data['Morning'] = np.where((data['Hour']>=6) & (data['Hour']<12), 1, 0) data['Afternoon'] = np.where((data['Hour']>= 12) & (data['Hour']<18), 1, 0) data['Evening'] = np.where((data['Hour']>= 18) & (data['Hour']<24), 1, 0) data['BusinessHour'] = np.where((data['Hour']>= 8) & (data['Hour']<18), 1, 0) *# Add seasons* data['Spring'] = np.where((data['Month']>=3) & (data['Month']<6), 1, 0) data['Summer'] = np.where((data['Month']>=6) & (data['Month']<9), 1, 0) data['Autumn'] = np.where((data['Month']>=9) & (data['Month']<12), 1, 0) data['Winter'] = np.where((data['Month']<=2) | (data['Month']==12), 1, 0) *# Encode weekdays* data_dummies = pd.get_dummies(data['DayOfWeek']) data = pd.concat([data, data_dummies], axis=1) *# Create a dummy for weekends* data['Weekend'] = np.where((data['DayOfWeek']=='Saturday') & (data['DayOfWeek']=='Sunday'), 1, 0) *# Encode districts* data_dummies = pd.get_dummies(data['PdDistrict']) data = pd.concat([data, data_dummies], axis=1) data = data.drop(columns=['PdDistrict']) *# Drop categorical variables and variables that are not in test set* *# School valiables contain too many NaNs* data.drop(columns=(['Address', 'Dates', 'Descript', 'DayOfWeek', 'Resolution', 'Enrolled In Public School', 'Enrolled In Private School', 'Not Enrolled In School'])) **return** data
Word Cloud of Temporal Features
提取空间特征有点复杂,因为它们基于可以作为包加载的
uszipcode
数据库。在笔记本中,您将找到清理邮政编码数据和提取相关人口统计特征所需的所有功能。请注意,要素工程过程需要花费大量时间(几个小时),主要是因为需要输入每个纬度和经度的邮政编码。您的最终数据集应包括 89 个变量,这些变量包含犯罪发生率的时间和空间方面的信息。现在,您可以随意使用这些数据并训练自己的模型,它将在 Kaggle 排行榜上名列前茅!首先,这里有一个简单的函数,它训练一个模型,对测试集进行预测,并计算挑战中指定的 logloss:
# Try out different models models = [LogisticRegression, RandomForestClassifier, KNeighborsClassifier]def run_model(model, X_train, y_train, X_test, y_test): model = model() model.fit(X_train, y_train) y_preds = model.predict(X_test) return (log_loss(y_test, y_preds)) results = [run_model(model) for model in models]
结论
在这篇文章中,我们研究了旧金山犯罪分类数据集,并了解了如何制作数据可视化来探索数据的不同方面。我们还使用地理位置和日期来设计空间和时间特征。在另一篇文章中(希望如此),我们将探索模型和特征选择技术、超参数调整和一些流行的降维方法!敬请期待:)
完整笔记本:https://github . com/ritakurban/Practical-Data-Science/blob/master/SF _ crime . ipynb
深入了解计算机视觉世界:第 1 部分
从 VGG、ResNet、GoogLeNet 和 MobileNet 开始
在完成了神经网络的基础知识之后,下一步将是学习这个领域中的一些“著名摇滚明星模型”。ResNet,Inception Net,Faster R-CNN,YOLO 等等。研究这些模型可以分为三个部分:这些架构背后的应用程序、实现和直觉。关于如何使用预训练模型以及如何构建它们,已经有大量的资源。但抓住模型背后真正的直觉有时会被忽略。研究人员用这种结构建立模型的意图是什么?是什么促使他们采取这样的方法?我们能从结果中推断出什么?
本文是下一个系列 最直观最简单的指南 教程,该系列的完整设置如下:
- 从 VGG 开始,ResNet,Inception Network 和 MobileNet
- CNN 地区,让我们开始物体探测吧!
- YOLO,SSD 和 RetinaNet,比较统一的
- 从对象检测到实例分割(TBU)
本文假设你已经熟悉了卷积神经网络的基本概念。除此之外,我们还将深入了解 VGG、ResNet、Inception Network 和 MobileNet 的各种卷积变换和修改。一个接一个地浏览它们,我们将回答上面提到的问题,这样我们才能真正理解这些架构的潜在含义。
VGG
ImageNet 是一个用于计算机视觉领域研究的大型数据集。自 2010 年以来,每年都举办名为 ImageNet 大规模视觉识别挑战赛 (ILSVRC)的比赛。VGGNet 是 2014 年 ILSVRC 竞赛的获胜者。尽管与其他复杂的网络相比,它的体系结构简单,但它仍然是最受欢迎的网络之一。
这个网络的一个有趣的部分是,即使在第一层中,它也只使用了 3×3 滤波器。如果和之前的比较, AlexNet **,**2012 年的赢家,在前两层使用了 11x11 和 5x5 滤镜。还有 ZFnet **,**2013 年的冠军,用的是 7x7 滤镜。代替在第一卷积层中使用相对大尺寸的滤波器,所使用的 VGG 网络滤波器的尺寸仅为 3×3。
那么尝试这个的意图是什么呢?答案是减少参数的数量。让我们在这里做一些计算。通道尺寸为 C 的单个 7x7 卷积层需要多少个参数?是 49C 。现在,通道尺寸相同的 3 层 3x3 卷积层的数量是多少?(9C )x3 = 27C 。看看有多少参数减少了。减少权重的数量可以通过降低网络的复杂性来处理过拟合。此外,由于我们可以为每个卷积层设置一个激活层,这也有助于模型的学习。
与 VGG 网络或 AlexNet 一样,大多数卷积网络都遵循基本结构:一系列卷积层、一个汇集层和一个带有一些规范化的激活层。但是越来越深入,人们遇到了一些严重的问题,并开始重新设计这种方法。
雷斯内特
直觉上,我们希望“越深越好”然而,研究人员发现事实并非如此。随着网络变得越来越深,性能越来越差。原因之一是消失/爆炸梯度问题。虽然我们已经有几种方法来解决这个问题,如梯度裁剪,有一个退化问题,不是由于过度拟合。ResNet 的诞生就是从这里开始的。 为什么会这样?
让我们假设我们有一个具有理想精确度的良好网络。现在,我们将复制这个网络,只添加 1 层,但没有额外的功能。这被称为身份映射,这意味着获得与输入完全相同的输出。与其他具有许多参数的复杂层相比,这对于我们的“智能”模型来说是小菜一碟。所以对网络的性能应该没有什么危害吧?
那么如果我们附加越来越多的身份层会有什么结果呢?由于身份层对输出没有影响,因此性能不会下降。这似乎是一个合理的猜测,但这个实验的结果与我们的预期不同。该模型的性能比没有身份层的较浅模型差。
这个结果表明“越深越好”不适用于神经网络,即使有身份映射。仅仅将身份层直接附加到网络上就很难训练。好吧,那么把身份层作为一个附加层怎么样?
现在,这就是 ResNet 发挥作用的地方。假设 H(x) 是网络的结果。而如果我们放一条额外的路径,原来的函数就变成了 F(x) + x 其中 F(x) 是主分支的函数如上图。身份层也被称为快捷连接或跳过连接。这就给网络带来了“剩余学习”的概念。现在主分支被训练为逼近 H(x) — x 并使 F(x) 更接近零。这意味着给予各层一定的学习方向,从而使培训更容易。此外,网络可以通过身份层跳过一些层。这允许我们有更深的层,但仍然具有高性能。
你可能会问,当两层的大小不同时,怎么可能把 F(x) 和 x 相加。我们可以通过在快捷连接处进行零填充或线性投影来解决这个问题。所以 ResNet 中有两种快捷连接,一种是没有权重的,一种是有权重的。
上图是 ResNet 50 层的卷积块。它有一个具有 3 个回旋层的主分支和一个 1x1 回旋的快捷连接。这里我们可能需要问, 为什么要 1x1–3x 3–1x1 卷积?
要回答这个问题,需要了解数据的维度是如何根据过滤器大小而变化的。请看看右边的图片。如果我们说输入的形状是(32,32,256),那么与上一步相比,当它通过 3x3 过滤器时,维数会减小。当它通过第二个 1x1 滤波器时,它再次增加。这是一个瓶颈。通过强制数据适应更小的维度,我们可以获得更有效的特征表示。
The comparison of a plain network and ResNet
用更少的滤波器、更少的计算量和更高的精度来容易地优化深度神经网络。这种简单而新颖的重构带来了如此美丽的成就,这就是 ResNet 在 2015 年如何震撼人们的心灵。带着 ResNet 上的这种根本直觉,我想让你从 原论文 开始探索网络。而 这里的 是实验残块变体研究的第二部分。或者你可以在 ResNet 这里 找到一个简单的解释。
谷歌网
高性能越深入越好。我们需要深度神经网络来执行复杂而具有挑战性的任务。但是,当我们评估网络时,还有一个因素需要考虑。想想我们什么时候必须在移动应用程序中嵌入模型。肯定不希望有一个“太重”的模型。但除此之外,还有一个在实际应用中非常关键的计算成本问题。所以现在的问题就变成了, 怎样才能以更高的效率深入?
研究人员发现低效计算发生的一个地方是完全连接的架构。在卷积方法中,全连接架构表示层 l 从层l-1馈入,并连接到下一层 l+1 ,如下左图所示。研究人员发现,过滤器数量的任何均匀增加都会使计算加倍。所以他们建议从密集连接的架构转移到稀疏连接的架构。
不是实现一个 类型 的卷积,稀疏架构执行具有多个滤波器大小的多个卷积,如上所示。并且来自这些层的输出的维度可以与“相同的”填充相匹配。
这里有几个不同尺寸的过滤器有一个重要的意义。在训练过程中,网络检测到的特征的规模起初是小的和局部的,并且随着其深入而变大。例如,假设模型检测到一只猫。该模型看到小比例的特征,例如猫的皮毛图案,然后它移动到更大比例,例如它的耳朵形状,然后是腿的数量。
**
因此,即使图片中的猫处于不同的比例,模型仍然处理相同比例的特征映射。这是低效的,并且会损害性能。因此,拥有多个过滤器表明它现在知道如何根据输入图像“放大和缩小”。它使模型能够一次检测不同比例的图像。通过这样做,我们还可以处理选择参数的工作以及减少无效的计算。这是《盗梦空间》的第一脚。
因此,Inception 模块看起来就像上图左边的那个。但是有一个问题。 但是计算成本呢? 无论如何,稀疏连接的架构仍然需要相同或更多的计算量!研究人员解决这个问题的方法是实现 1x1 卷积,如上图右侧所示。这里的 1x1 卷积的目的是降维,就像我们在 ResNet 中讨论的那样。考虑到输入图像的(N,N,C)形状,计算时间减少了。如果图像的大小是 32×32,有 129 个通道,我们可以将参数的数量减少 9 倍!
The architecture of Inception Network
GoogleNet 的最终架构如上图所示。这些模块串联在一起,总共形成 22 层。这是一个相当深的网络,它也无法避免臭名昭著的消失梯度问题。所以研究人员处理这个问题的方法是制造侧枝。
“渐变消失”是什么意思它表明梯度的值随着深度的增加而变得越来越小,这意味着梯度没有多少信息可以学习。所以我们可以说,从早期阶段的梯度携带更多的信息。换句话说,我们可以通过在中间层添加辅助分类器来获得额外的信息。此外,正如我们上面讨论的,检测到的特征随着层的不同而不同。因此,“中间产品”也有利于标签的分类。我们将这些支路的损耗加到加权网络的总损耗中。
MobileNet
受我们上面讨论的网络的启发,“更深入和更复杂”是 CNN 研究的高度趋势。虽然这些网络带来了更高的准确性,但对于现实世界的应用来说,它们不够高效或“轻便”。为了在计算有限的平台上及时执行,它们需要更小更快。
研究人员提出的一个解决方案是形成分解卷积。分解卷积表示将标准卷积分解成深度卷积和点态卷积。这被称为深度方向可分卷积。
在深度方向可分离卷积中,我们首先分离输入和滤波器的每个通道,然后用相应的滤波器或以深度方向的方式对输入进行卷积。然后将输出连接在一起。这是 深度方向的卷积 。之后我们做 逐点卷积 ,和 1x1 卷积一样。现在看最后的结局。和标准的 3x3 卷积不一样吗?如果是,那么这样做有什么意义?
答案是计算。我们来比较一下两者的计算成本。当输入的波形为( N 、 N 、 C1 ),输出通道为 C2 ,滤波器大小为 F 时,两者的总运算量应该如左图所示。如你所见,深度方向可分离卷积降低了计算成本。根据原始论文中的所述,与采用标准卷积的相同架构相比,MobileNet 所需的计算量减少了 8 到 9 倍,精确度仅略有下降。
深度方向可分卷积也用于 Xception,其论文发表早于 MobileNet。但是我发现 MobileNet 论文对深度方向可分离卷积的概念给出了更直接的解释。
减去
现在,架构对你来说变得更简单和有形了吗?如我所说,理解结构背后的论点是至关重要的。所以我想再回顾一下电视网的一些亮点。
首先,卷积层的滤波器大小不仅仅具有特征映射的意义。它可以像 VGG 一样改变参数的数量。我们还可以创建瓶颈来提取有意义的数据表示。 1x1 卷积不仅仅是线性变换。它可以作为一个有用的技巧,在不显著影响输入数据的情况下,给出更多的非线性,改变维度,并减少计算。
为了获得更高的性能,ResNet 通过快捷连接来利用残差。这一层通过跨层有效地传递权重来更好地促进优化。另一方面,初始网络的策略是通过构建稀疏架构来使用多个过滤器。这是为了应对训练中音阶的变化。最后,MobileNet 选择将卷积分解为两个步骤。利用深度方向可分离的卷积,MobileNet 可以显著减少计算量和模型大小。
参考
- 卡伦·西蒙扬和安德鲁·齐泽曼, 用于大规模图像识别的极深度卷积网络 ,2015
- 、何等 深度残差学习用于图像识别 ,2015
- Christian Szegedy 等人2014 年
- Christian Szegedy 等人, Inception-v4,Inception-ResNet 以及剩余连接对学习的影响,2016
- Franc ois Chollet,异常:深度可分卷积深度学习,2017
- Andrew G. Howard 等人, MobileNets:面向移动视觉应用的高效卷积神经网络,2017
这个故事引起你的共鸣了吗?请与我们分享您的见解。我总是乐于交谈,所以请在下面留下评论,分享你的想法。我还在 LinkedIn 上分享有趣和有用的资源,所以请随时关注并联系我。下次我会带来另一个有趣的故事。一如既往,敬请期待!
深入计算机视觉世界:第 2 部分
有 CNN 的地区,让我们开始物体检测!
这是“深入计算机视觉世界”的第二个故事,该系列的完整集如下:
- 从 VGG 开始,ResNet,Inception Network 和 MobileNet
- CNN 地区,让我们开始目标检测
- YOLO,SSD 和 RetinaNet,比较统一的那些
- 从对象检测到实例分割(TBU)
在前一篇文章中,我们讨论了五个流行的网络,VGG、ResNet、Inception Network、Xception 和 MobileNet。这些网络现在是高级网络的主要组成部分,因此有必要了解它们的架构。
现在,我们进入下一页。从图像分类到目标检测。到目前为止,我们讨论的是一个大型卷积神经网络。虽然它们有很多层,但最终是一个网络。但是 R-CNN 和它的变体将是我们的焦点,这个网络是它的一部分。CNN 现在是整个“系统”的一部分,处理更复杂的任务,如对象检测和图像分割。从 R-CNN 开始,我们将看到这些网络是如何转变的,以及这些变化背后的想法。
从图像分类到目标检测
在我们直接进入 R-CNN“家族”之前,让我们简单检查一下图像分类和图像检测的基本思想。两者有什么区别?为了检测图像中的物体,我们还需要做哪些额外的工作?
首先,无论我们有多少个班级,都会有一个额外的班级-背景。需要一个对象检测器来回答这个问题,“有对象吗?”,这不是图像分类的情况。第二,当有一个对象时,仅仅说“是的,有”还是不够的(想象起来相当可笑…😅)它还应该告诉我们,“物体位于哪里?”我们需要探测到的物体的位置。这听起来可能很简单,但实现起来并不容易。当我们考虑速度和效率挑战时,事情变得更加复杂。
因此,物体检测就像…寻找一个物体的区域,定位它并对它进行分类。有了这个基本概念,我们现在准备开始 R-CNN 的第二个话题。
R-CNN
R-CNN 回答问题,“在 ImageNet 上的 CNN 分类结果能在多大程度上概括为物体检测结果?”所以这个网络可以说是物体检测家谱的开始,在神经网络的应用中有很大的重要性。基本结构由三个步骤组成:提取区域建议、计算 CNN 和分类。
首先,我们从输入图像中提取一些看起来有希望有物体的区域。R-CNN 使用选择性搜索来获得那些感兴趣的区域(ROI)。选择性搜索是一种基于像素强度分割图像的区域提议算法。如果你想深入了解选择性搜索,这里有 原文 。基本思路如下图。它首先从过度分割的图片开始,并在每个片段周围绘制一个边界框。并且基于它们在颜色、纹理、大小和形状兼容性方面的相似性,它不断将相邻的分组并形成更大的片段。R-CNN 通过这种方法提取了大约 2000 个地区提案,并将它们提供给 CNN。这也是它被命名为 R-CNN 的原因,具有 CNN 特色的区域。
Selective Search for Object Recognition
得到候选后,第二步是进入一个大型卷积神经网络。每个提议都被调整为固定大小,并分别输入 CNN。R-CNN 用的是 AlexNet(那是 2014 年,当时还没有 ResNet 和 InceptionNet)我们从每一个提案中得到 4096 维的特征向量。
并且在最后一步,从 CNN 提取的输出被馈送到一组类特定的线性 SVM 模型。我们为每个类优化一个线性 SVM,并且我们得到具有得分高于阈值的边界框的输出图像。在具有重叠框的情况下,通过应用非最大抑制,只需要一个。
值得一提的一个有趣部分是它如何克服数据稀缺问题。研究人员面临的挑战是,仅用少量的标记数据训练如此庞大的网络。解决方案是用不同的标签数据对 CNN 进行预训练(这是监督学习),然后用原始数据集进行微调。
您可能已经注意到了一些可以改进的低效部分。选择性搜索是计算密集型的。并且为每个 ROI 处理 CNN 是重复的工作,这再次需要大量的计算成本。对预训练过程和分离的分类器的需要是没有吸引力的。而且这些机型的存储量太大。虽然 R-CNN 是一个里程碑式的成就,但它有几个缺点需要改进。
快速 R-CNN
快速 R-CNN 是上一部作品的下一个版本。这里发生了什么变化?重复处理卷积映射得到了改进。第一个变化发生在重复卷积层。
假设计算一个卷积网络需要 N 秒。由于 R-CNN 分别向网络输入 2000 个 RoI,总处理时间将为 2000N 秒。现在,我们不再单独处理 CNN,而是通过与所有建议共享卷积,只处理一次。*
正如您在上面看到的,这个网络接受两个数据输入,一个原始图像和一组区域建议作为输入。整个图像通过网络前馈产生特征图。有了这个特征地图,每个区域提议通过一个汇集层和完全连接的层来创建一个特征向量。因此,卷积计算是一次完成的,而不是针对每个建议。
并且用两个兄弟层替换多个分类器。一个是 softmax 函数,用于利用每一类的可能性估计对对象进行分类,另一个是边界框回归器,用于返回检测到的对象的坐标。所以得到的特征向量被送入这两层,我们从这两层得到结果。
现在,这个模型进行了更改,以共享卷积并分离附加的分类器。通过将“多个主体”合并为一个并去掉“沉重的尾巴”,我们可以实现更少的计算和存储。这种架构允许我们一起训练所有权重,甚至包括 softmax 分类器和多元回归器的权重。这意味着传播将来回更新所有的权重。惊人的进步!然而,我们仍然有机会获得更好的表现。
更快的 R-CNN
然而,快速 R-CNN 很难用于实时检测。造成这种时间延迟的主要原因是选择性搜索。它存在计算瓶颈,需要用更有效的方法来替代。*但是如何?如果没有选择性搜索,我们如何获得区域提案?如何最大限度地利用 ConvNet 呢?*研究人员发现,Fast R-CNN 中的特征地图也可用于生成区域提议。因此,通过避免选择性搜索,可以开发更高效的网络。
快速 R-CNN 由两个模块组成,区域提议网络(RPN)和快速 R-CNN。我们首先输入一幅图像到一个“迷你网络”,它将输出特征图。通过在特征图上滑动小窗口,我们提取区域提议。并且每个提议被馈送到两个兄弟层,softmax 分类器和包围盒回归器。
这两层可能看起来类似于快速 R-CNN 的最后几层,但它们是为了不同的目的而衍生的。对于每个提议,分类器估计图像中对象存在的概率。回归器返回边界框的坐标。所以它们是用来产生候选者的,而不是预测实际的物体。
我们只取得分高于某个阈值的建议,将它们与特征图一起输入到快速 R-CNN。以下步骤相同。它们被输入到卷积网络和 RoI 池层。最后一层将是分类器和回归器,最终预测图像中的真实对象。
Faster R-CNN architecture (left) and Region Proposal Network (right)
这个网络的一个重要属性是平移不变量,这是通过锚和它计算相对于锚的提议的方式来实现的。 什么是平移不变? 简单来说,就是不管物体旋转、移位、大小变化什么的,我们都能检测到。图像中的对象可以位于中心或左上角。根据视角不同,同一物体可以是宽的或长的。为了防止模型因为平移而无法定位物体,我们制作了多种比例和纵横比的锚框,如上图所示。这些盒子放在推拉窗的中央。所以如果在某个位置有 K 个盒子,我们得到 2K 个盒子的分数和 4K 坐标。
总之,在区域提议网络,我们在特征图上滑动具有多个锚框的窗口,并通过分类器和回归器评估每个框。低于阈值的建议被拒绝,因此,只有有希望的建议进入下一步。
不仅如此,该模型通过分别微调 RPN 和 Fast R-CNN 特有的层,同时修复共享层,优化了 4 步交替训练。这允许模型共享权重,形成统一的网络,并在效率和准确性方面带来更高的性能。为了比较性能,建议更快的 R-CNN 的时间是每幅图像 10 毫秒(整个过程每秒 5 帧),而使用 CPU 进行选择性搜索的时间是 2 秒。
减去
从 R-CNN 到更快的 R-CNN,网络得到了转变,不再依赖其他组件。R-CNN 可以通过丢弃线性支持向量机和共享卷积计算来增强。而快速 R-CNN 也改为共享卷积去除选择性搜索。通过将整个过程集成到一个网络中,我们可以实现更高的精度和更快的速度。
参考
- J.R.R. Uijlings 等人, 物体识别的选择性搜索 ,2012
- Ross Girshick 等人, 用于精确对象检测和语义分割的丰富特征层次 ,2014 年
- 何等, [视觉识别深度卷积网络中的空间金字塔池](http://Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition) ,2015
- 罗斯·吉希克, 快速 R-CNN ,2015
- 任等, 更快的 R-CNN:面向实时目标检测的区域提议网络 ,2015
- 何等 面具 R-CNN ,2018
这个故事引起你的共鸣了吗?请与我们分享您的见解。我总是乐于交谈,所以请在下面留下评论,分享你的想法。我还在 LinkedIn上分享有趣和有用的资源,所以请随时关注并联系我。下次我会带来另一个有趣的故事。一如既往,敬请期待!