NLP 的深度学习:用 Keras 创建聊天机器人!
了解如何使用 Keras 构建递归神经网络并创建聊天机器人!谁不喜欢友好的机器人私人助理呢?
在之前的帖子中,我们了解了什么是人工神经网络和深度学习。此外,还介绍了一些利用文本或音频等序列数据的神经网络结构。如果你还没有看过那篇文章,你应该坐下来,喝杯咖啡,慢慢地享受它。这里可以找到。
这篇新帖将讲述如何使用 Keras ,一个非常流行的神经网络库来构建聊天机器人。将解释这个库的主要概念,然后我们将逐步指导如何使用它来创建 Python 中的是/否回答机器人。我们将利用 Keras 的易用性来实现 Sukhbaatar 等人的论文“端到端存储网络”中的 RNN 结构(你可以在这里找到)。****
这很有趣,因为定义了一个任务或应用程序(创建一个是/否聊天机器人来回答特定的问题),我们将学习如何将研究工作中的见解转化为实际模型**,然后我们可以使用该模型来实现我们的应用程序目标。**
如果这是你第一次实现 NLP 模型**,不要害怕;我会仔细检查每一步,并在最后添加一个代码链接。对于最佳学习体验,我建议你首先阅读帖子,然后浏览代码,同时浏览帖子中的相关部分。**
最后,在我们开始之前,这里有一些额外的资源可以让你的机器学习生涯突飞猛进:
*Awesome Machine Learning Resources:**- For* ***learning resources*** *go to* [***How to Learn Machine Learning***](https://howtolearnmachinelearning.com/books/machine-learning-books/)*!
- For* ***professional******resources*** *(jobs, events, skill tests) go to* [***AIgents.co — A career community for Data Scientists & Machine Learning Engineers***](https://aigents.co/)***.***
让我们开始吧!
Keras:Python 中的简易神经网络
Keras 是一个用于开发神经网络模型的开源高级库**。它是由谷歌的深度学习研究员弗朗索瓦·乔莱(Franç ois Chollet)开发的。它的核心原则是使构建神经网络、训练神经网络、然后使用神经网络进行预测的过程对任何具有基本编程知识的人来说都是容易和可访问的,同时仍然允许开发人员完全定制人工神经网络的参数。**
基本上,Keras 实际上只是一个可以运行在不同深度学习框架之上的接口,例如 CNTK、Tensorflow 或 Theano 。它的工作方式是一样的,与所使用的后端无关。
Layered structure of the Keras API. As it can be seen, it can run on top of different frameworks seamlessly.
正如我们在上一篇文章中提到的,在神经网络中,特定层中的每个节点都采用前一层输出的加权和,对它们应用数学函数,然后将结果传递给下一层。
使用 Keras,我们可以创建一个表示每一层的块,其中可以轻松定义这些数学运算和层中的节点数。这些不同的层可以通过输入一行直观的代码来创建。****
创建 Keras 模型的步骤如下:****
第一步:首先我们必须定义一个网络模型,这个模型在大多数情况下是SS模型:网络将被定义为一系列的层,每个层都有自己可定制的大小和激活功能。在这些模型中,第一层将是输入层,这需要我们定义我们将馈送给网络的输入的大小。之后,越来越多的层可以添加和定制,直到我们达到最终的输出层。**
#Define Sequential Model
model = Sequential()
#Create input layer
model.add(Dense(32, input_dim=784))
#Create hidden layer
model.add(Activation('relu'))
#Create Output layer
model.add(Activation('sigmoid'))
步骤 2: 以这种方式创建网络结构后,我们必须对其进行编译,这将我们之前定义的简单层序列转换为一组复杂的矩阵运算,这些运算决定了网络的行为方式。在这里,我们必须定义将用于训练网络的优化算法,并选择将被最小化的损失函数。
#Compiling the model with a mean squared error loss and RMSProp #optimizer
model.compile(optimizer='rmsprop',loss='mse')
第三步:**一旦完成,我们可以训练或 拟合 网络,这是使用前一篇文章中提到的反向传播算法完成的。
*# Train the model, iterating on the data in batches of 32 samples* model.fit(data, labels, epochs=10, batch_size=32)
****第四步:万岁!我们的网络训练有素。现在我们可以用它对新数据进行预测。
**正如你所看到的,**使用 Keras 建立一个网络是相当容易的,所以让我们使用它来创建我们的聊天机器人!上面使用的代码块并不代表实际的具体神经网络模型,它们只是帮助说明使用 Keras API 构建神经网络有多简单的每个步骤的示例。
你可以在它的官方网页找到所有关于 Keras 以及如何安装的文档。
该项目:使用递归神经网络建立一个聊天机器人
现在我们知道了所有这些不同类型的神经网络是什么,让我们用它们来建立一个可以回答我们一些问题的聊天室。
大多数时候,神经网络结构比标准的输入-隐藏层-输出更复杂。有时我们可能想发明一个我们自己的神经网络并尝试不同的节点或层组合。此外,在某些场合,我们可能希望实现一个我们在某处见过的模型**,比如在一篇科学论文中。**
在这篇文章中,我们将通过第二种情况的一个例子,从 Sukhbaatar 等人的论文"端到端记忆网络 " (你可以在这里找到)中构建神经模型。
此外,我们还将了解如何保存训练好的模型,这样我们就不必在每次想要使用我们建立的模型进行预测时训练网络。那我们走吧!
模型:灵感
如前所述,本文中使用的 RNN 摘自论文 " 端到端内存网络 " ,因此我建议您在继续之前先看一下,尽管我将在下面几行解释最相关的部分。
本文实现了一个类似 RNN 的结构,它使用一个注意力模型来补偿我们在上一篇文章中讨论过的关于 RNNs 的长期记忆问题。
不知道什么是注意力模型?不要担心,我会用简单的语言解释给你听。注意力模型吸引了很多人的兴趣,因为它们在像机器翻译这样的任务中表现非常好。他们解决了前面提到的 RNNs 的长序列和短期记忆的问题。
为了收集注意力做什么的直觉,想想人类如何将一个长句从一种语言翻译成另一种语言。不是拿起whooooole的句子,然后一口气翻译出来,而是把句子分成小块,然后一个一个地翻译这些小块。我们一部分一部分地学习这个句子,因为很难完全记住它,然后马上翻译它。
How a human would translate the text on the top from English to Spanish
注意力机制就是这样做的。在每个时间步中,模型在输出中给输入句子中与我们试图完成的任务更相关的部分更高的权重。这就是这个名字的来源: it 把注意力放在更重要的上。上面的例子很好地说明了这一点;要翻译句子的第一部分,看整个句子或句子的最后一部分没有什么意义。
下图显示了当我们增加输入句子的长度时,RNN 与注意力模型的表现。当面对一个很长的句子,并要求执行一个特定的任务时,RNN 在处理完所有的句子后,可能会忘记它最初的输入。****
Performance vs Sentence Length for RNNs and Attention models.
好了,现在我们知道了什么是注意力模型,让我们仔细看看我们将要使用的模型的结构。这个模型接受一个输入Xi(一个句子),一个查询 q 关于这样的句子,并输出一个是/否回答 一个 。****
On the left (a) a representation of a single layer of the model. On the right (b) 3 of these layers stacked together.
在上一个图像的左边部分,我们可以看到这个模型的一个单层的表示。每个句子计算两个不同的嵌入, A 和 C 。同样,使用 B 嵌入来嵌入查询或问题 q。****
A 嵌入 mi ,然后使用内积计算问题嵌入(这是注意力发生的部分*,因为通过计算这些嵌入之间的内积,我们正在做的是从查询和句子中寻找词语的匹配,然后使用soft max赋予这些匹配更多的重要性***
最后,我们使用来自 C【ci】的嵌入以及从点积获得的权重或概率【pi】来计算输出向量。有了这个输出向量 o ,权重矩阵 W ,以及问题的嵌入,我们就可以最终算出预测答案 一个帽子 。****
为了构建整个网络,我们只需在不同的层上重复这些过程,使用其中一层的预测输出作为下一层的输入。这显示在上一个图像的右边部分。
如果这些对你来说太快了,不要担心,希望当我们通过不同的步骤用 Python 实现这个模型时,你会得到更好和完整的理解。
数据:故事、问题和答案
2015 年,脸书在 bAbI 项目中提出了一个 bAbI 数据集和 20 个测试文本理解和推理的任务。文中详细描述了 这里 。
每个任务的目标是挑战机器文本相关活动的一个独特方面,测试学习模型的不同能力。在这篇文章中,我们将面对这些任务中的一个,特别是“带有单一支持事实的 QA”。
下图显示了这种 QA 机器人的预期行为示例:
**FACT: Sandra went back to the hallway. Sandra moved to the office. QUESTION: Is Sandra in the office?ANSWER: yes**
数据集已经被分成训练数据(10k 实例)和测试数据(1k 实例),其中每个实例都有一个事实,一个问题,以及对该问题的一个是/否答案。
现在我们已经看到了数据的结构,我们需要从数据中建立一个词汇表。在一个自然语言处理模型上,一个词汇表基本上是一组模型知道并能理解的单词。如果在构建词汇表之后,模型在句子中发现了一个不在词汇表中的单词,它要么在其句子向量中给它一个 0 值,要么将其表示为未知。
**VOCABULARY:
'.', '?', 'Daniel', 'Is', 'John', 'Mary', 'Sandra', 'apple','back','bathroom', 'bedroom', 'discarded', 'down','dropped','football', 'garden', 'got', 'grabbed', 'hallway','in', 'journeyed', 'kitchen', 'left', 'milk', 'moved','no', 'office', 'picked', 'put', 'the', 'there', 'to','took', 'travelled', 'up', 'went', 'yes'**
由于我们的训练数据变化不大(大多数问题使用相同的动词和名词,但有不同的组合),我们的词汇量不是很大,但在中等规模的 NLP 项目中,词汇量可以很大。
考虑到为了建立一个词汇表,我们应该在大多数时候只使用训练数据;在机器学习项目的最开始,测试数据应该从训练数据中分离出来,并且在评估已经选择和调整的模型的性能之前不要接触。
构建词汇后,我们需要 矢量化 我们的数据。由于我们使用普通的单词作为模型的输入,而计算机只能在引擎盖下处理数字,我们需要一种方式来表示我们的句子,即词组,作为数字的向量。矢量化就是这么做的。
有许多向量化我们的句子的方法,像 单词包 模型,或者 Tf-Idf ,但是,为了简单起见,我们将只使用一种索引向量化技术,其中我们给词汇表中的每个单词一个从 1 到词汇表长度的唯一索引。
**VECTORIZATION INDEX:
'the': 1, 'bedroom': 2, 'bathroom': 3, 'took': 4, 'no': 5, 'hallway': 6, '.': 7, 'went': 8, 'is': 9, 'picked': 10, 'yes': 11, 'journeyed': 12, 'back': 13, 'down': 14, 'discarded': 15, 'office': 16, 'football': 17, 'daniel': 18, 'travelled': 19, 'mary': 20, 'sandra': 21, 'up': 22, 'dropped': 23, 'to': 24, '?': 25, 'milk': 26, 'got': 27, 'in': 28, 'there': 29, 'moved': 30, 'garden': 31, 'apple': 32, 'grabbed': 33, 'kitchen': 34, 'put': 35, 'left': 36, 'john': 37}**
考虑到这种矢量化是使用随机种子开始的,所以即使你使用和我一样的数据,你也可能为每个单词得到不同的索引。不用担心;这不会影响项目的结果。此外,我们的词汇表中的单词有大写和小写;在进行这种矢量化时,为了统一,所有的单词都将小写。
在此之后,由于 Keras 的工作方式,我们需要填充句子。这是什么意思?这意味着我们需要搜索最长句子的长度,将每个句子转换为该长度的向量,并用零填充每个句子的字数和最长句子的字数之间的差距。
这样做之后,数据集的一个随机句子应该看起来像这样:
**FIRST TRAINING SENTENCE VECTORIZED AND PADDED:
array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 20, 30, 24, 1, 3, 7, 21, 12, 24, 1, 2, 7])**
正如我们所见,除了结尾(这个句子比最长的句子短很多)有一些数字之外,它到处都有零。这些数字是什么?嗯,它们是代表句子不同单词的索引:20 是代表单词 玛丽 , 30 是 移动了 , 24 是 到 ,1 是,3 代表 浴室实际的句子是:**
**FIRST TRAINING SENTENCE:
"Mary moved to the bathroom . Sandra journeyed to the bedroom ."**
好了,现在我们已经准备好了数据,我们准备建立我们的神经网络!
神经网络:建立模型
创建网络的第一步是为输入创建 Keras 中所谓的 占位符 ,在我们的例子中是故事和问题。简单地说,这些占位符是容器,在将我们的训练数据馈送到模型之前,将在其中放置这些数据。
***#Example of a Placeholder
question = Input((max_question_len,batch_size))***
它们必须与将要输入的数据具有相同的尺寸,并且还可以定义一个批量大小,尽管如果我们在创建占位符时不知道,可以将其留空。
现在我们必须创建论文中提到的嵌入、 A、C 和 b、一个嵌入将一个整数(在这种情况下是一个单词的索引)变成一个 d 维向量,其中上下文被考虑到。单词嵌入在自然语言处理中被广泛使用,并且是近年来使该领域取得巨大进步的技术之一。
**#Create input encoder A:
input_encoder_m = Sequential()
input_encoder_m.add(Embedding(input_dim=vocab_len,output_dim = 64))
input_encoder_m.add(Dropout(0.3))#Outputs: (Samples, story_maxlen,embedding_dim) -- Gives a list of #the lenght of the samples where each item has the
#lenght of the max story lenght and every word is embedded in the embbeding dimension**
上面的代码是论文中嵌入的一个例子(一个嵌入)。像在 Keras 中一样,我们首先定义模型(顺序的),然后添加嵌入层和丢弃层,通过触发网络的节点来减少模型过拟合的机会。
一旦我们为输入句子创建了两个嵌入,并为问题创建了嵌入,我们就可以开始定义模型中发生的操作。如前所述,我们通过在问题嵌入和故事嵌入之间做点积来计算关注度,然后做一个 softmax。下面的程序块显示了这是如何实现的:
**match = dot([input_encoded_m,question_encoded], axes = (2,2))
match = Activation('softmax')(match)**
在此之后,我们需要计算将匹配矩阵与第二个输入向量序列相加的输出 o ,然后使用该输出和编码的问题计算响应。
**response = add([match,input_encoded_c])
response = Permute((2,1))(response)
answer = concatenate([response, question_encoded])**
最后,一旦完成,我们添加模型的其余层,添加一个 LSTM 层(而不是论文中的 RNN),一个 dropout 层和一个最终的 softmax 来计算输出。
**answer = LSTM(32)(answer)
answer = Dropout(0.5)(answer)
#Output layer:
answer = Dense(vocab_len)(answer)
#Output shape: (Samples, Vocab_size) #Yes or no and all 0s
answer = Activation('softmax')(answer)**
这里注意,输出是一个词汇量大小的向量(即模型已知的单词数的长度),其中除了索引‘yes’和‘no’处的位置外,所有位置都应该为零。****
从数据中学习:训练模型
现在我们准备编译模型,并训练它!
**model = Model([input_sequence,question], answer)
model.compile(optimizer='rmsprop', loss = 'categorical_crossentropy', metrics = ['accuracy'])**
有了这两行,我们构建最终模型,并编译它,也就是说,通过指定一个优化器、一个损失函数和一个度量来优化,定义所有将在后台进行的数学运算。
现在是训练模型的时间,这里我们需要定义训练的输入(输入故事、问题和答案)、我们将向模型提供的批量(即,一次有多少输入),以及我们将训练模型的时期数(即,模型将经历多少次训练数据以更新权重)。我使用了 1000 个历元,获得了 98%的准确率,但即使使用 100 到 200 个历元,你也应该得到一些相当好的结果。****
请注意,根据您的硬件,此培训可能需要一段时间。放松,坐好,继续阅读,直到完成。
完成培训后,你可能会疑惑“我每次想用这个模型时都要等这么久吗?”很明显我朋友的答案是, 没有 。Keras 允许开发者保存它已经训练好的某个模型,以及权重和所有配置。下面的代码块显示了这是如何实现的。
**filename = 'medium_chatbot_1000_epochs.h5'
model.save(filename)**
现在,当我们想使用这个模型时就像加载一样简单,就像这样:
**model.load_weights('medium_chatbot_1000_epochs.h5')**
酷酷。现在我们已经训练好了我们的模型,让我们看看它在新数据上的表现,然后用它玩一会儿!
查看结果:测试和播放
让我们看看我们的模型在测试数据上表现如何!
**pred_results = model.predict(([inputs_test,questions_test]))**
这些结果是一个数组,如前所述,它在每个位置包含词汇表中每个单词成为问题答案的概率。如果我们看这个数组的第一个元素,我们会看到一个词汇大小的向量,其中除了对应是或否的时间以外,所有时间都接近 0。
在这些中,如果我们选择数组的最高值的索引,然后查看它对应于哪个单词,我们应该找出答案是肯定的还是否定的。
我们现在可以做的一件有趣的事情是创造我们自己的故事和问题,并把它们喂给机器人看他说什么!
**my_story = 'Sandra picked up the milk . Mary travelled left . '
my_story.split()
my_question = 'Sandra got the milk ?'
my_question.split()**
我以某种方式创造了一个故事和一个问题类似于我们的小 bot 在之前看过的,在改编成神经网络想要的格式后 bot 回答了’ YES '(小写 tough,他没有我热情)。
让我们尝试一些不同的东西:
**my_story = 'Medium is cool . Jaime really likes it. '
my_story.split()
my_question = 'Does Jaime like Medium ?'
my_question.split()**
这次的回答是:’ 当然有,谁没有呢?’
开个玩笑,我没有尝试故事/问题的组合,因为其中的许多单词不在我们的小答录机的词汇中。此外,他只知道如何说“是”和“不是”,通常不会给出任何其他答案。然而,有了更多的训练数据和一些变通办法,这很容易实现。
今天到此为止!我希望你们能像我喜欢写这篇文章一样喜欢读这篇文章。祝你愉快,保重,享受人工智能!
你可以在我的 Github 页面找到代码和数据。
其他资源:
如果你想更深入地了解注意力模型,或者理解我提到的一些单词矢量化技术,请查看我为你整理的这些额外资源。尽情享受吧!
注意力机制和记忆网络初学者指南
好好读!
有关机器学习和数据科学的更多资源,请查看以下资源库: 如何学习机器学习 !有关职业资源(工作、事件、技能测试),请访问 AIgents.co——一个数据科学家&机器学习工程师 的职业社区。
最后,看看我关于 NLP 深度学习的其他文章:
**** [## NLP 的深度学习:ann,RNNs 和 LSTMs 解释!
了解人工神经网络,深度学习,循环神经网络和 LSTMs 前所未有地使用…
towardsdatascience.com](/deep-learning-for-nlp-anns-rnns-and-lstms-explained-95866c1db2e4) [## 自然语言处理的深度学习:单词嵌入
简单直观的单词嵌入
towardsdatascience.com](/deep-learning-for-nlp-word-embeddings-4f5c90bcdab5)
尽情享受吧!
此外,要获得更多学习机器学习和人工智能的资源,请查看以下 repo:
lost 试图发现如何学习机器学习?现在是学习这项技术的大好时机,但是…
howtolearnmachinelearning.com](https://howtolearnmachinelearning.com/)****
自动驾驶汽车的深度学习
利用英伟达的研究在 Pytorch 建立自动驾驶的 CNN
更新 2:
这篇文章是很多年前写的,我已经不在这个领域工作了,所以如果下面的代码不起作用,我提前道歉。😅
更新:
非常感谢 Valohai 使用我的 rusty 教程作为他们令人敬畏的机器学习平台的介绍😍。我建议你们都去看看他们的例子关于如何使用 Valohai 机器学习平台(www.valohai.com)在云上用完全版本控制训练网络。
我们都知道自动驾驶汽车是科技巨头最热门的研究和商业领域之一。几年前看起来像科幻小说的东西,现在看起来更像是即将成为生活一部分的东西。我说“很快”的原因是因为即使像特斯拉、日产、凯迪拉克这样的公司确实有自动驾驶汽车辅助软件,但是,它们仍然需要人盯着道路,并在需要时进行控制。然而,看到我们在创新方面走了多远,技术进步有多快,这是令人着迷的。以至于现在,在基本的深度学习、神经网络魔法的帮助下,我们可以为自动驾驶建立自己的管道!激动吗?我当然是!那我们就直接进入正题吧…
先决条件: 1。本文假设对卷积神经网络及其工作有一个基本的了解。
2。这里提到的代码是使用 Pytorch 框架用 Python 编写的,因此建议您具备该语言和框架的基础知识。
如果以上对你来说是胡言乱语,不要惊慌!这个由 Udacity 提供的免费课程将为你提供你需要了解的关于深度学习和 Pytorch 基础知识的一切。
我的背景
我从脸书赞助的 Udacity 奖学金项目开始了我的深度学习之旅,通过这个项目,我从上面提到的课程中学到了 Pytorch 的基础知识。与此同时,我还参加了由 KPIT 赞助的 Udacity 自动驾驶汽车工程师纳米学位课程,在那里,作为我的项目之一,我在 Keras 为自动驾驶汽车编写了一个端到端深度学习模型。因此,我决定用 Pytorch 重写代码,并分享我在这个过程中学到的东西。好了,我说的够多了,让我们用一件事来设置我们的机器——对过度合身说不!
项目资源 1。 Udacity 的自动驾驶汽车模拟器
2。当然还有 Python 和 Pytorch 框架
3。如果你的机器不支持 GPU,那么我会推荐使用 Google Colab 来训练你的网络。它免费提供 GPU 和 TPU 时间!
4。如果你在收集训练数据时遇到问题,你可以使用 Udacity 提供的来训练你的网络。
5。完整代码可在此处获得,Colab 笔记本可在此处获得。6。本文提到的 Nvidia 研究论文可以在这里找到。
收集数据 Udacity 提供的数据集工作良好,但不足以让汽车在复杂的地形中行驶(就像 uda city 模拟器中的第二条赛道)。为了从 track 2 收集数据,我们首先需要在我们的项目目录中创建一个文件夹。我们姑且称这个文件夹——数据。现在,启动我们的模拟器。从菜单中选择第二个轨道,并转到训练模式选项。
The simulator main menu
一旦进入训练模式,您将在屏幕的右上角看到一个录制选项。点击图标,浏览到数据文件夹。按选择。
Browsing to the data folder
再次按下录制图标后,您就可以开始录制您的骑行了!现在,如果你像我一样是一个游戏新手,我会建议慢慢来,尽量确保你的车尽可能停在路中央,即使是在转弯的时候。这将有助于获得更好的训练数据,最终形成一个好的模型。我们将记录在赛道的一个方向上行驶 2 圈,以及在相反方向上行驶 2 圈,以确保转弯是反向的。这将确保我们的模型不会过度拟合,使更好的左转弯和右转弯。我们开始吧!
Capturing training data
训练数据现在存储在数据文件夹中。里面一个文件夹一个文件: IMG 和 driving_log.csv 。我们的下一个工作是从 CSV 文件中读取图像的名称及其相关的导向数据,并从 Python 中的 IMG 文件夹中加载相应的图像。
编码时间到了!
如果你不想在本地机器上安装不同的库和框架,或者你想利用免费的 GPU 时间,那么使用 Colab 会更好。另外,如果您不喜欢收集数据,那么您可以使用!wget URL
导入 Udacity 的数据集,并使用!unzip
解压缩文件。最重要的是。导入邮件头:
读取和分割数据
上面的代码从日志文件中读取所有内容,并将其存储到sample
数组中。行next(reader, None)
带走包含列名的第一行。我们将使用这个数组将我们的数据分成训练和验证。据我所知,一个很好的实践是将 20–30%的训练数据作为验证集来比较验证损失和训练损失,这样我们可以避免过度拟合。让我们这样做:
在数据加载器中加载图像 现在我们已经制作了样本,是时候读取图像并对其进行扩充了。这是重要的一步,因为这将有助于推广我们的模型。但是即使对于 GPU 来说,这个过程也是计算量大且耗时的。诀窍是通过批量获取数据、扩充数据并将其发送到模型进行训练来并行化这一过程。Keras 使用 python generators
和fit_generator
函数实现了这个过程。在 Pytorch 中,我们将使用Dataset
类和Dataloader
函数来实现这个功能。为了实现这一点,我们必须重载这个类的一些函数,即__getitem__
、 __len__
和__init__
函数。我们还必须定义一些扩充过程。我编写了一个基本的函数,它将拍摄一张图像,随机裁剪它,水平翻转它,同时拍摄转向数据的负片。基本上,裁剪有助于模型通过去除图像中的天空和其他分散注意力的东西来专注于道路,翻转是为了确保图像被推广到左转弯和右转弯,本质上是将汽车保持在道路的中心。其他技术可以是添加随机亮度来模拟一天的不同持续时间,在图像上叠加一层失真和噪声来模拟下雨,在道路上添加随机阴影等。但是我们现在只关注最基本的。
接下来,我们定义Dataloader
类,并将这个augment
函数传递给输入批量样本,连接操纵数据和图像并返回它。
注意还有一个论点叫做transform
。我们的转换将使用一个lambda
函数将图像数组值归一化到范围0–1。接下来,我们使用Dataloader
函数将所有内容添加到一个生成器中,该生成器将在训练期间被批量调用。我们定义一个 32 的批处理大小,并在将它传递给 DataLoader
时对它们进行洗牌。num_workers
定义了多少工人将并行创建批处理。
模型架构
是时候建立我们的模型了。让我们仔细看看 Nvidia 的研究论文。继续并在新标签页中打开它。链接在上面的参考资料部分。
如果你向下滚动到 pdf 的第 5 页,你会看到他们建造的 CNN 的架构。
好吧,你这个懒人,这就是我说的形象😝。如果你看这些数字,你会看到卷积层的深度和全连接层的输入和输出特征。现在,每个特征地图都有一些提到过的内核。正如论文中提到的,Nvidia 的人使用 YUV 图像作为输入,并在前三个卷积层中使用 2×2 步幅和 5×5 内核的步长卷积,在最后两个卷积层中使用 3×3 内核大小的非步长卷积。不过有趣的是,并没有提到 maxpool 层。我试图虔诚地遵循上述架构,建立 CNN。这是我想到的:
不幸的是,这种方法有问题。也许是缺少数据,也许是缺少最大池层,网络表现得很糟糕。即使在直道上,汽车也总是偏离道路。经过谷歌搜索,我发现了这个回购协议。这里使用的模型是 Nvidia 架构的简化版本。我试过了,当用足够多的纪元训练时,效果非常好。所以对我来说,最后的架构是这样的:
但是,您可以随意试用带有 maxpool 层的第一个模型。它需要一些计算填充和输出的高度和宽度。让我们花点时间来看看这里的一些东西-
a)*nn.Module*
*-*py torch 中使用了nn.Module
类来创建 CNN。我们必须过载__init__()
和forward()
功能来构建网络。为了避免编写重复的代码,我使用了nn.Sequential()
。无论nn.Sequential()
函数中有什么,都会被顺序应用于输入。很漂亮,是吧? a) elu 激活- 这里使用的激活函数是 elu(指数线性单位)。与 relu(校正线性单元)不同,elu 加快了训练过程,还解决了消失梯度问题。更多细节和 elu 函数的方程式可在此处找到。
b)图像展平- 卷积层的输出在传递到全连接层之前的展平用下面的行完成:output.view(output.size(0), -1)
。
优化器和标准
接着,本文还讨论了使用均方误差损失作为标准和 Adam 优化器。让我们把它编码出来!我把学习率设为 0.0001。可以做相应的调整。
嗯,我们有进展了。在我们编写最后的训练和验证部分之前,让我们进入 GPU 的世界吧!
Pytorch 和 CUDA Pytorch 提供了与支持 CUDA 的 GPU(对不起 AMD)的轻松集成。这是通过一个简单的device()
函数完成的。它可以极大地加快训练过程,比普通 CPU 快 10 倍。为什么不利用这一点呢?为此,我们需要将数据和模型传输到 GPU 进行处理。这确实比听起来容易。我们定义了一个函数,它将对所有接收到的输入执行此操作。
请注意,我已经将它转换为float()
,以便模型能够计算输入。
训练
是时候训练我们的杰作了!我们首先将模型传输到 GPU,然后,使用生成器获取数据,并将数据传输到 GPU。接下来,我们使用optimizer.zero_grad()
函数设置优化器在反向传播过程中不累积梯度。最后,我们计算总训练损失,并除以批量大小,以获得每个时期的平均训练损失。非常简单。
验证 验证也是一样,但这次我们将确保我们的模型处于评估模式,这样我们就不会错误地更新梯度和反向传播错误。我们使用model.eval()
来改变模式,并使用torch.set_grad_enabled(False)
来确保模型不会跟踪。损失的计算方法相同。
保存模型 代码的最后一步到了!训练完成后,我们保存模型,以便在模拟器中自动驾驶汽车。我们制作一个state
字典,并使用torch.save()
将模型保存为 .h5 格式。
有趣的事情开始了 在我们开始测试我们的模型之前,我们需要一个文件来加载我们的模型,从模拟器中获取轨道的帧来处理我们的模型,并将转向预测发送回模拟器。不要害怕!我做了一个drive.py
文件,基本上是我在项目中使用的 Udacity 的 [drive.py](https://github.com/ManajitPal/BehavioralCloning/blob/master/model.py)
文件的 Pytorch 版本。如果你想要不同的节流等,你可以通过代码和实验。现在,让我们复制粘贴以下代码的内容。
[## ManajitPal/deeplearningforself 驾驶汽车
这是 Nvidia 的模型在 Pytorch 中的一个实现,用于为自动驾驶汽车构建深度学习神经网络。…
github.com](https://github.com/ManajitPal/DeepLearningForSelfDrivingCars/blob/master/drive.py)
此外,我们需要一个包含模型架构的model.py
文件。创建文件并粘贴您的网络架构。如果你面临任何问题,可以随意看看我在回购中的model.py
文件。
如果你一直在使用 Google Colab 编写你的代码,在同一个目录下下载model.h5
文件。启动终端,cd
到您的目录,用我们的模型运行脚本:
python drive.py model.h5
如果您机器上安装了两个不同的 python 版本,请使用python3
而不是python
。当您看到任何弹出窗口时,单击允许。
再次打开模拟器,现在选择自主模式。车要像老板一样自己开!
这就对了。你自己的无人驾驶汽车管道。多酷啊!😁
这里有一个你可能会期待的小演示:
故障排除 你可能会看到汽车摇晃得很厉害,或者它被限制在道路的一边。这可能意味着数据没有被适当地扩充和概括。尝试获取更多的训练数据或增加更多的随机性。
你也可能看到汽车根本不动。在这种情况下,请在运行期间检查终端是否有任何错误。大多数错误应该通过安装适当的库依赖项来解决。
结论 非常感谢您花时间阅读我的文章。我真的希望这能帮助到想学习一些关于深度学习在自动驾驶汽车中使用的概念的人。此外,这是我第一篇与人工智能相关的文章,我是一个完全的初学者,所以如果你能在下面的评论中留下任何积极或消极的反馈,你的想法或其他你可能认为是为自动驾驶汽车构建人工智能的更好方式的资源,我将非常感激。干杯伙计们!
用于船只检测和分割的深度学习
卫星图像深度学习的端到端管道
Photo by Cameron Venti on Unsplash
被困在付费墙后面?点击这里阅读完整故事与我的朋友链接!
从遥感图像中检测船舶是海事安全的一个重要应用,海事安全包括交通监视、防止非法捕鱼、石油排放控制和海洋污染监测等。这通常是通过使用自动识别系统(AIS)来完成的,该系统使用甚高频无线电频率向附近其他船只和陆基系统上的接收装置无线广播船只的位置、目的地和身份。
自动识别系统在监测法律要求安装甚高频应答器的船只方面非常有效,但无法检测到没有安装的船只和断开应答器的船只。那么如何检测这些不合作的船呢?这就是卫星图像可以发挥作用的地方。合成孔径雷达(SAR)图像使用无线电波对地球表面进行成像。与光学成像不同,这些仪器使用的波长不受时间或气象条件的影响,因此无论是白天还是晚上,无论是多云还是晴朗的天空,都可以获得图像。卫星正在收集这些图像,这些图像可用于制作船只检测和分割算法。
这个项目是在卡格尔举行的空中客车船只探测挑战赛的一部分。
挑战
建立自动识别遥感目标是否为船只的算法。该算法必须非常精确,因为生命和数十亿美元的能源基础设施正处于危险之中。
Ship detection and segmentation
环境和工具
- sci kit-学习
- sci kit-图像
- numpy
- 熊猫
- matplotlib
数据
数据集可以从 kaggle 网站下载,可以在这里找到。
基础
这是一个典型的实例分割问题。我在这个项目中使用过 Mask-R-CNN。
- 图像分类:对图像中的主要物体类别进行分类。
- 对象检测:识别对象类别,并使用图像中每个已知对象的边界框定位位置。
- 语义分割:为图像中的每个已知对象识别每个像素的对象类别。标签是类感知的。
- 实例分割:识别图像中每个已知对象的每个像素的每个对象实例。标签是实例感知的。
代码在哪里?
事不宜迟,让我们从代码开始吧。github 上的完整项目可以在这里找到。
我从加载所有需要的库和依赖项开始。
接下来,我设置工作目录和文件。
我继续定义函数来显示一些带有船只遮罩和编码解码遮罩的样本图像。这里面具被用作地面真实图像。
Sample-1
Sample-3
接下来,我将图像分成两组,即训练集和验证集。
之后,我从我的分叉存储库中加载 Mask-R-CNN 模型。原来的储存库可以在这里找到。
然后我创建了一个类,它有三个函数,分别用于加载数据集、加载蒙版和将图像作为参考。
我还为类似的工作创建了另一个启用 gpu 的类。由于巨大的数据集大小,在这种情况下使用 gpu 是必须的。作为一个额外的信息,google colab 和 kaggle 内核目前是免费的基于云的 gpu 提供商。
我继续编写脚本来加载训练数据集。
让我们想象一下到目前为止我们得到了什么。
到目前为止一切顺利。我继续从我分叉的 github 存储库中加载预训练的 coco 权重。
接下来我训练了模型。为了更快的结果,我只训练了两个时期。为了适当的融合和良好的结果,需要做的远不止这些。请随意使用这里的超参数。
结果
Sample Result 1
Sample Result 2
在某些情况下,当该模型检测到一个小岛或海岸岩石作为船只时,它会失败。换句话说,这个模型正在产生假阳性。
False positive
而在其他时候,该模型未能检测到船只,如下图所示。换句话说,这个模型正在产生假阴性。
False negative
结论
虽然这个项目还远未完成,但在如此多样的现实世界问题中看到深度学习的成功是令人瞩目的。如果我们能够检测和分割图像中的船只,这将对瑞典、挪威和加拿大等北方国家的物流和运输团队有很大的帮助。通过从卫星图像中实时跟踪船只,它可以为集装箱船和船只带来一个全新的运输层面。
参考资料/进一步阅读
使用行星卫星图像对旧金山湾的船只进行分类
medium.com](https://medium.com/dataseries/detecting-ships-in-satellite-imagery-7f0ca04e7964) [## 使用高分辨率卫星图像和天基 AIS - IEEE 会议
本文介绍了 9 月在挪威北部特罗姆瑟市附近的马兰根地区进行的一项试验…
ieeexplore.ieee.org](https://ieeexplore.ieee.org/abstract/document/5730248/) [## 大卫电视/卡格尔-空中客车-船舶-检测
空中客车船只探测挑战(Kaggle) -尽快在卫星图像上找到船只…
github.com](https://github.com/davidtvs/kaggle-airbus-ship-detection)
在你走之前
相应的源代码可以在这里找到。
Kaggle 竞赛笔记本样本。查看相应的媒体博客文章细胞核分割使用…
github.com](https://github.com/abhinavsagar/Kaggle-Solutions)
快乐阅读,快乐学习,快乐编码。
联系人
如果你想了解我最新的文章和项目,请关注我的媒体。以下是我的一些联系人详细信息:
单细胞生物学的深度学习
生命科学的深度学习
通过深度学习解析细胞架构
这是系列生命科学深度学习的第二篇文章。在前一篇中,我展示了如何在古代 DNA 上使用深度学习。今天是时候谈谈深度学习如何帮助细胞生物学捕捉细胞群体的多样性和复杂性了。
单细胞 RNA 测序(scRNAseq) 几年前带来了生命科学的革命,带来了前所未有的分辨率来研究细胞群体中的异质性。影响如此巨大,以至于《科学》杂志宣布 scRNAseq 技术为 2018 年的突破。主要的进步是认识到尽管生物细胞在显微镜下看起来形态相似,但它们表达的基因可能非常不同,这反过来导致细胞之间的功能差异。为了捕捉这种细胞多样性,人类细胞图谱社区宣布了一个雄心勃勃的目标,要建立一个人体内存在的数万亿个细胞的综合图谱。
随着 10X 基因组学 单细胞基因表达平台的发展,从几十万甚至百万个单个细胞中获取完整的转录组信息几乎成为一种常规。因此,scRNAseq(连同生物医学成像和基因组学)代表了目前真正的大数据,它具有卓越的统计能力,并为应用机器和深度学习进行单细胞数据分析打开了新的视野。
在这里,我将简要概述该领域,阐述主要的分析挑战,并展示如何将深度学习与 Keras 和 TensorFlow 一起用于单细胞 RNA 测序数据分析中的无监督学习问题。
为什么单细胞生物学非常适合深度学习?
对一些数据进行统计分析,我们通常需要了解 a) 特征数量 p (基因、蛋白质、遗传变异、图像像素等)之间的平衡。),以及 b) 观察次数 n (样本、细胞、序列等)。).人类基因组大约有 p=20K 蛋白质编码基因,而最近发表的 10X scRNAseq 数据集包括 n~1.3M 和 n~2M 个体细胞。这意味着对于 scRNAseq 来说 n > > p 这是一个典型的深度学习限制,即在这个限制下工作,我们可以远远超出基于线性代数的分析,并捕获 scRNAseq 数据中的高度非线性结构。
Recent studies report unprecedented scRNAseq sample sizes which is ideal setup for Deep Learning
对于其他限制,即当 n << p or n ~ p, Bayesian and Frequentist statistical frameworks, respectively, are more appropriate. In other words, working with scRNAseq data we have a luxury problem: while 过拟合和缺乏可推广性是计算生物学中常见的问题时,这里对于 scRNAseq,我们必须注意欠拟合,即如何使用大多数数据。
不仅 scRNAseq 目前在生命科学领域蓬勃发展,而且在单细胞水平上传递其他类型信息(生物信息学术语中的组学)的技术也变得越来越普遍。研究染色质可及区域(scATACseq) 的最新进展产生了具有> 100K 单细胞的数据集。虽然单独的 scATACseq 可能无法保证发现稀有细胞群体的新方法(单细胞数据分析的主要目标),但它为 与 scRNAseq 的集成提供了巨大的潜力,从而提高了将细胞分配到特定群体的准确性。
Chromatin accessibility regions (ATACseq) is complementary for scRNAseq analysis
最后,单细胞多组学技术 ( CITE-seq , scNMTseq 等。),即来自相同生物细胞的多个信息来源,尚未达到 scRNAseq 典型的巨大样本量,但对于未来与深度学习的数据整合挑战而言非常有希望。
通过深度学习降低维度
由于 scRNAseq 分析的主要目标是发现新的细胞群体,因此在机器学习术语中,它是一种无监督分析。因此,用于 scRNAseq 的两个最重要的分析技术是维度缩减和聚类。Autoencoder 是一种无监督的人工神经网络(ANN ),具有有趣的“蝴蝶”结构,通常用于降维。与诸如主成分分析(PCA)、多维标度(MDS)、因子分析(FA)等线性技术相反。,自动编码器执行非线性降维,因此可以捕获单细胞数据的高度非线性结构。
Autoencoder is an Artificial Neural Network (ANN) with the “butterfly” architecture
在这里,我将使用约 8K 脐带血单核细胞(CBMCs) CITEseq scRNAseq 数据集为例,展示线性(PCA)和非线性(Autoencoder)维数缩减技术之间单细胞分辨率的差异。请注意,下面的代码假设输入文件为表格格式,基因为列,细胞为行,文件的最后一列必须是使用您最喜欢的 scRNAseq 聚类技术获得的细胞注释。我推荐使用基于图的聚类和 Louvaine 社区检测,这对于高维数据是健壮的,在流行的seurascrna seq 工作流中实现。
为了比较,我在这里也要加上t-分布式随机邻居嵌入(tSNE) 图,这是 scRNAseq 领域目前的金标准非线性降维技术。tSNE 的一个问题是它不能处理高维数据,比如 scRNAseq。因此,通常的做法是执行 PCA(线性!)作为预降维,并将输出馈入 tSNE。然而,我们可以通过使用自动编码器以非线性方式执行预降维步骤来做得更好。让我们展示两种策略的 tSNE 图:
如果你不习惯看这种图,这里一个点是一个细胞,颜色对应不同的细胞类型。你应该观察 12 个细胞群体,但是你基本上不能从 PCA 图中看到它们(细胞严重重叠),因为线性维数减少不能解析单个细胞结构。Autoencoder 图片看起来更好,不同的细胞群体是明显可检测的。tSNE 通常提供更清晰的小区斑点。然而,在这种特殊情况下,自动编码器上的 tSNE 似乎提供了更密集和透明的集群,尤其是在 PCA 图的 tSNE 中,紫色细胞群遍布蓝色集群。因此,深度学习有望提高检测新细胞群体的分辨率。
寻找可扩展的维度缩减
除了难以处理高维数据之外,当细胞数量达到数十万甚至数百万时,tSNE 的伸缩性很差。FItSNE 是 Barnes-Hut tSNE 的一个新的有前途的修改,它似乎对大量数据有更好的伸缩性。然而,在 130 万小鼠脑细胞上运行 FItSNE 时,我很难将它放入内存。特别是,我想获得高度复杂的 tSNE 图,以便检查数据的全局结构。然而,困惑= 350 是我在一个计算机集群上使用一个 256GB RAM 的节点所能达到的最大困惑。运行 FItSNE 非常简单,类似于他们在 R 中执行 tSNE 的方式(同样,Cluster 列包含单元格注释):
均匀流形逼近和投影(UMAP ) 是另一种非常有趣的非线性降维技术,目前似乎在许多方面优于 tSNE。它比 tSNE 快,与 FItSNE 一样快,但不需要那么多内存,并且它似乎可以捕获 scRNAseq 数据的局部和全局结构。也许我看到的唯一缺点是我目前正在经历的 UMAP 背后的一点不透明的数学。
最近发布了一些基于 变型自动编码器 的有趣方法。其中之一是**SCVIS这是一种神经网络,它捕捉并可视化单细胞基因表达数据中的低维结构,此外还保留了局部和全局邻居结构。为了在 130 万小鼠脑细胞上运行 SCVIS,我使用了以下命令行:**
下面,我使用来自 10X Genomics 的 130 万小鼠脑细胞,对上述 4 种降维技术(即 PCA、tSNE / FItSNE、UMAP 和 SCVIS)进行了比较:
Comparison of dimensionality reduction techniques on 1.3M 10X mouse brain data set
对于上述 CITEseq 的情况,我们可以看到,与 PCA 相比,非线性维度减少技术(SCVIS、UMAP 和 tSNE / FItSNE)能够分辨 scRNAseq 数据中的所有细胞群体。在这三种技术中,UMAP 是最快的,并且提供了相当好的数据低维表示。为了更精确地计算时间,SCVIS 用了大约 6 小时,FItSNE 用了 3 小时和大量内存,UMAP 在我的笔记本电脑上用了大约 3 小时。
考虑到不断增长的 scRNAseq 数据量,我预测 UMAP 和自动编码器将在未来取代 tSNE 。
带 Keras 的 scRNAseq 深度自动编码器
最后,在这里我将演示如何使用 Keras 从头实现并运行一个深度自动编码器。正如你将看到的,这并不难。为了避免将整个数据集加载到内存中的困难,我选择了前 19 个主成分,通过重采样,即改组基因表达矩阵并检查由置换矩阵(零假设)解释的方差百分比,我发现它们是显著的。自动编码器逐渐将维数从 19 减少到 2(自动编码器的瓶颈),每个隐藏层减少一个维数。
Deep Autoencoder for dimensionality reduction of 1.3M 10X mouse brain cell, Keras implementation
我们可以看到,尽管我没有特别试图找到一个可能提供更好分辨率的神经网络的最佳配置,但细胞群体是完全可以区分的。 Deep Autoencoder 的一个巨大优势是,它看起来非常快,因此可伸缩对于大量的 scRNAseq 数据,我的笔记本电脑只花了几分钟就让模型收敛并获得了上面的图。
带 TensorFlow 的 scRNAseq 深度自动编码器
Keras 很棒,很快,很容易,但有时我觉得我用 TensorFlow 控制神经网络要好得多。例如,使用 Keras,人们永远不会有“手动”连接节点的感觉,这是我很欣赏使用 TensorFlow 实现的理解深度。后者的一个小缺点是,像小批量学习这样有用的技巧必须在 TensorFlow 中手工编码,而在 Keras 中是自动包含的。总之,下面是 TensorFlow Deep Autoencoder 的代码和降维图:
Deep Autoencoder for dimensionality reduction of 1.3M 10X mouse brain cells, TensorFlow implementation
同样,低维表示看起来很有希望。通过对配置和其他超参数的一些调整,人们有可能获得更好的分辨率。同样,对于 Keras 来说,TensorFlow 自动编码器的实现速度非常快,与 FItSNE、UMAP 和 SCVIS 制作这种降维图所用的时间相比,只需几分钟。如果出于某种原因,你的分析需要重采样过程**,这对于 FItSNE、UMAP 和 SCVIS 来说不太可行,但对于深度学习来说应该非常简单。**
摘要
在这里,我们了解到单细胞 RNA 测序(scRNAseq)正在迅速提高我们对生物细胞中功能多样性的理解。维度缩减可能是典型 scRNAseq 分析背后最重要的分析工具。金标准降维技术 tSNE 由于 scRNAseq technologies 提供的大量数据,目前在可扩展性方面遇到了困难。通过自动编码器和 UMAP 的深度学习提供了目前最灵活和可扩展的方式来获得 scRNAseq 数据的低维表示,并且很可能在未来取代 tSNE**。最后,我们已经学会了如何使用 Keras 和 TensorFlow 为巨大的 10X Genomics 1.3M 小鼠脑细胞 scRNAseq 数据集实现深度自动编码器。**
希望你喜欢阅读这篇文章,让我在评论中知道你对人工智能和深度学习感兴趣的生命科学方向,我希望听到你的反馈。在媒体关注我,在推特 @NikolayOskolkov,关注我,在我的 github 上查看这个帖子的完整 Jupyter 笔记本。下一篇文章将是关于使用深度学习进行多组学生物医学数据集成,敬请关注。
用于生存分析的深度学习
最近我得到了一个从事生存分析的机会。像任何其他项目一样,我很兴奋,并开始探索更多关于生存分析的内容。根据维基百科,
生存分析是统计学的一个分支,用于分析一个或多个事件发生前的预期持续时间,如生物有机体的死亡和机械系统的故障
简而言之,这是一个时间事件分析,它关注于感兴趣的事件发生的时间。事件可以是死亡、传感器故障或疾病的发生等。生存分析是一个热门领域,在医学、流行病学、工程学等领域有广泛的应用。
**你想知道深度学习是如何改变如此重要的领域的吗?**如果是的话,那么你来对地方了。
当我开始看一看深度学习如何被用于生存分析时,令我惊讶的是,我找不到任何好文章。我接触到的所有材料和教程都只使用了统计方法。但是当我稍微深入挖掘时,我发现涉及神经网络的生存分析的重要研究最初是由 Faraggi 和 Simon 在 1995 年发表的[5]。
生存分析简介
将通过理解生存分析中的关键定义从基础开始。
设 T 为随机变量,表示事件发生前的等待时间。除了通常的概率函数,我们还可以定义一些与生存分析相关的基本函数,如生存函数、风险函数等。
生存函数 S(t) 是到时间 t 感兴趣的事件没有发生的概率。属性包括 S(0) = 1 、 S(∞) = 0 、 S(t) 为非递增*。*
并且危险函数 λ(t) 可以被视为事件在时间 t 瞬间发生的概率,假设事件在时间 t 之前没有发生。
生存分析数据集
需要注意的一个关键点是,我们不是在处理一个通常带有标签的数据集。生存分析的数据不同于标准回归或分类问题。在生存分析中,我们处理的是删失数据。删失是一种缺失数据问题。
每当我们进行生存分析时,都会得到一个学习周期内的训练数据。如果被研究对象在研究期内没有经历该事件会怎样?。则称之为右删失数据。类似地,我们的数据集中也可以有左删失和区间删失样本。通常,我们将处理具有右删失样本的数据集。
Example dataset — **lifelines.datasets.load_static_test**
在上面的示例数据集中,列 id 标识所研究的单个对象。列 E 将*告诉我们数据是否被审查。换句话说,如果列 E 的值为 *1,则相应的对象在研究期间经历了感兴趣的事件。这里,除了 id 为 3 的对象外,所有对象都经历了该事件。对象 id 3 被右删。列 t 是事件发生所用的时间,在删失数据的情况下,是研究时间。列 var1 , var2 这里是对象的特征或协变量。例如,协变量可以是性别、年龄等。同时预测患者器官衰竭或心脏病发作的概率。
标准方法
在使用神经网络解决生存分析问题之前,我们现在将简要地研究传统的统计方法。我们可以把标准方法大致分为非参数方法、半参数方法和参数方法。
用于估计生存函数的最流行的非参数方法是Kaplan–Meier 估计法。最大的限制是它不能估计考虑协变量的存活率。
考虑协变量的生存数据的基本模型是比例风险模型。该模型由 D. Cox 教授(1972 年)提出,也被称为 Cox 回归模型。
Cox 比例风险模型(CoxPH)假设风险函数由两个非负函数组成:基线风险函数*【λ₀(t】*和风险比或风险得分 r(x) = exp{h(x)} 。风险分值被定义为对象的观察协变量对基线危害的影响。Cox 模型使用线性函数和潜在基线风险函数来估计对数风险函数 h(x) ,而不采用任何特定形式。这种半参数方法比参数方法更灵活,成为更受欢迎的选择。
这种比例风险假设也可以用生存函数来表示,如下所示。这里的 S₀(t) 是基线生存函数*。*
CoxPH 适应神经网络
许多人已经尝试使用神经网络进行生存分析。随着深度学习领域的进步,最近的结果很有希望。
当涉及到用于生存分析的深度学习时,我们有两种主要的综合方法。一种方法可以看作是对 Cox 比例风险假设的修改,另一种方法使用完全参数化的生存模型。deep surv【1】,Cox-Nnet【2】将属于 CoxPH 适应方法,而Nnet-survival【3】,RNN-SURV【4】将属于第二种方法。我们将更加关注 CoxPH 适应方法,因为 Cox 模型已被证明非常有用,并且为大多数医学研究人员所熟悉[3]。
在 Cox 模型中,除了比例风险假设,我们在估计对数风险函数 h(x) 时还有另一个假设。我们用一个线性函数来估计 h(x) 。在许多情况下,例如,建模非线性基因相互作用,我们不能假设数据满足线性比例风险条件[1]。我们需要一个更复杂的非线性模型来预测对数风险函数h(x),而神经网络可以满足我们的要求。
DeepSurv
在本节中,我们将详细讨论 DeepSurv,以了解深度学习如何准确地用于生存分析。DeepSurv 是一个深度前馈神经网络,它预测由网络权重 θ 参数化的对数风险函数 h(x) 。
DeepSurv Architecture
对象的观测协变量或称为特征作为网络的输入给出。网络的隐藏层包括一个完全连接的节点层,后面是一个断开层。输出层有一个线性激活的节点,用于估计 Cox 模型中的对数风险函数。网络的损失函数如下所示。
这是损失函数背后的直觉。为了最小化损失函数,我们需要最大化每个具有可观测事件 (E = 1) 的对象在红框内的部分。为了最大化该部分,我们需要增加具有可观察事件的对象 i 的风险因子,并降低直到时间 Ti 之前没有经历该事件的对象 j 的风险因子,其中 Ti 是对象 i 经历该事件的时间。
现代深度学习技术,如缩放指数单元、Adam 优化器等。用于 DeepSurv 以获得更好的性能。Cox-nnet 与 DeepSurv 非常相似,但 Cox-nnet 和 DeepSurv 都只输出风险系数。他们没有估计基线函数。我们可以使用 Breslow 估计器等方法来生成基线函数[3]。
我前面说过,从 90 年代中期开始,人们就在尝试使用深度学习方法进行生存分析。鉴于深度学习的最新进展,在生存分析中使用深度学习的结果很有希望。当一个对象的协变量与其危险之间存在复杂关系时,深度学习技术的表现与其他最先进的生存模型一样好,甚至更好[1]。仍有很大的改进和研究空间。对于像我这样相信人工智能可以积极重塑许多重要领域的人来说,这个话题非常有趣。
这是我的第一篇文章,我希望这将是有益的。谢谢:)
参考文献
[1]卡兹曼·JL、沙哈姆·U、克洛宁格·A、贝茨·J、江·T 和克鲁格·Y、 DeepSurv :使用 Cox 比例风险深度神经网络的个性化治疗推荐系统(2018),BMC 医学研究方法学
[2]程婷,朱 X,加米尔 LX, Cox-nnet :高通量组学数据预后预测的人工神经网络方法(2018),计算生物学
[3] Michael F. Gensheimer 和 Balasubramanian Narasimhan,神经网络的可扩展离散时间生存模型 (2019),arXiv:1805.00917
[4]埃莉诺拉·久奇利亚、安东·涅姆琴科和米哈埃拉·范德沙尔, RNN-SURV :生存分析的深度循环模型(2018),LNCS 11139–11141
[5] Faraggi D,和 Simon R,生存数据的神经网络模型 (1995),医学统计学
符号数学的深度学习
用于绝对精确任务的神经网络。
介绍
本文试图描述 Guillaume Lample 和 Franç ois Charton 的论文“符号数学的深度学习”的主要内容。
深度学习方法已经成功地用于许多任务,最常见的是大幅度提高当前的艺术水平。例子包括:
- 图像分类。(80%的把握图片显示的是一只狗)
- 翻译。(将文本从一种语言翻译成另一种语言)
- 自动驾驶。(给定当前传感器输入,向右转向 5.785 度)
Different applications of DeepLearning. Sources: Cat (pascualamaia), Car ( Paul Sableman)
所有这些场景的共同点是,对于任何给定的输入,一定范围的输出都是可接受的:
- 图像分类。“高信心”表示为 80%还是 83%都没关系。
- 翻译。一个句子有多个有效的翻译。
- 自动驾驶。准确的转向角度并不重要,只要方向正确,幅度可以接受。
上面提到的论文探索了一种不同的场景。一种输出要么 100%正确,要么 100%不正确:求解数学表达式。
更具体地说,本文探讨了两项任务:
- 对函数进行积分
- 求解一阶或二阶常微分方程(ODE)
在本文中,我将只描述函数集成的过程。通常使用以下符号:
- f 是任意函数,其积分为 F
- F 是任意函数,它的导数是 f
对于积分的任务,给定一个函数 f 并且它的积分 F 是期望的答案。这个答案有多种正确的表达方式,但每种方式都是 100%正确的。其他任何表述都是 100%不正确。
深度学习模型:Seq2Seq
用来解决这个问题的深度学习架构被称为 Seq2Seq 。关于它是什么以及如何工作的详细解释可以在这里找到。
现在您需要知道的是,Seq2Seq 模型接受任意长度的输入序列,并将其转换为任意长度的输出序列。
Input sequence in german, Output sequence translated to english.
对于功能集成任务,该模型最重要的特性是:
- 输入和输出序列可以具有任意长度,且这些长度可以不同
- 从输入序列中的项目到输出序列中的项目的一对一关系是不必要的
这两个特性使得这种模型非常适合当前的任务。输入序列是定义输入函数的符号,输出序列是定义积分的符号。
但是,我们究竟如何将数学表达式输入到这个模型中呢?
作为序列的数学表达式
通常数学表达式已经是序列形式,即所谓的中缀符号。这样称呼是因为二元运算符写在它们所引用的两个参数之间。
但是,这种表示法不太适合在 seq2seq 模型中进行处理。这是因为为了使运算的顺序明确,需要大量的括号:
Top: Commonly used infix-notation. Bottom: Parenthesis for unambiguous order of operations
为了避免这个问题,本文使用了所谓的前缀符号。要从中缀符号表达式构建前缀符号表达式,请使用以下步骤:
首先,构建一个树来捕获表达式中操作的顺序和值。
第二,按照以下规则从上到下从左到右遍历树:
- 如果当前节点是一个原始值(一个数字),则将其添加到序列字符串中
- 如果当前节点是二元运算,则将运算符号添加到序列字符串中。然后,添加左侧子节点的表示(可以是递归的)。然后,添加右子节点的表示。
在上面的例子中,这个过程将导致表达式:
数据生成
每个深度学习应用程序都需要大量数据进行训练,集成符号表达式也不例外。幸运的是,有一些方法可以自动生成任意数量的训练数据。论文提出了 3 种不同的生成函数->积分对的方法。
向前一代
这个很简单。随机生成一个符号函数 f,然后使用外部工具计算符号整数 f。外部工具可以是像 SymPy 这样的库。然后将对(F,F)用作训练样本。
这种方法有两个主要缺点:
- 它依赖于一些其他的库,这些库实现了我们试图解决的完全相同的任务
- 即使使用第三方库,自动符号集成也不总是有效。这意味着在训练集中只有对(F,F)存在,对于这些对,存在可以求解 F 的积分的库,因此限制了多样性。
此外,由这种方法产生的对(F,F)具有这样的性质,即 F 通常由比 F 少得多的符号组成。这是自动符号积分如何工作的结果。
落后一代(BWD)
利用微分容易,积分难的事实。随机生成一个函数 F,然后将其自动微分得到函数 F。然后将(F,F)对作为训练样本。
由这种方法产生的对(F,F)具有这样的性质,即 F 通常比 F 包含更少的符号。这是自动符号微分如何工作的结果。
零件集成(IBP)
这种方法利用了被相乘的函数的积分的数学性质。该属性如下所示:
用这个技巧生成函数的算法:
- 随机生成函数 F 和 G
- 自动微分得到 f 和 g
- 如果 Fg 已经是训练集的一部分,我们就知道它的积分。使用上面的公式计算 fG 的积分。
- 如果 fG 已经是训练集的一部分,我们就知道它的积分。使用上面的公式计算 Fg 的积分。
附加步骤
在用上述方法中的一种或组合建立训练集之后,执行这两个附加步骤:
- 简化。表达式被简化,以强制模型也输出简化的表达式。
Simplifiying expressions
- 删除无效表达式。由于表达式的随机生成性质,它们可能包含无效的子术语。如果有,从表达式树中删除这些术语。
Invalid expressions are trimmed from the expression trees
结果
现在基础工作已经完成,让我们看看纪尧姆·兰普尔和弗朗索瓦·查顿取得的成果。
单台发电机的培训/测试
使用仅来自 FWD、BWD 或 IBP 中的一个的训练数据,并根据从相同方法产生的数据评估模型,产生非常好的结果:
- 前进:96.2%的准确性
- BWD:99.7%的准确率
- IBP:99.5%的准确率
与流行的数学框架相比
接下来,作者将他们的精确度与 Mathematica 、 Maple 和 Matlab 产生的结果进行了比较。仅评估了 BWD 发生器。结果很明显:
- Mathematica(超时 30 秒):84.0%
- Matlab: 65.2%
- 枫叶:67.4%
- seq 2 序列:99.6%
seq2seq 模型明显优于 BWD 方法生成的方程的数学框架。
这是一个 Mathematica 无法解决的方程的例子。如果分母简化,Mathematica 就能成功求解积分:
Example failure case from the original paper.
跨生成器比较
最后,作者评估了在一个生成器上使用另一个生成器的方程训练的模型。
- 接受过 FWD 培训:17.2%(BWD),88.9%(IBP)
- 在 BWD 接受培训:27.5%(前进),59.2%(IBP)
- 在 BWD+IBP 接受培训:56.1%(前进)
仅在一个生成器上训练模型似乎不能很好地推广到其他生成器。这可能是由于来自每个生成器的训练对(F,F)在长度方面具有不同的特性。例如长 F 和短 F,或者短 F 和长 F。
然而,根据来自所有 3 个发生器的方程训练模型工作良好:
- 接受过 FWD+BWD+IBP 培训:94.3%(FWD),99.7%(BWD),99.7%(IBP)
结论
总而言之,作者证明了神经网络方法甚至可以用于要求输出绝对精确的任务。在某些情况下,它们甚至超越了流行的数学框架。
如果你有时间,你应该读一下原文。它写得很好,很容易理解,即使没有太多的数学背景!
视觉搜索和绘图的深度学习
通过使用预训练的神经网络减少遥感应用中对训练数据注释的需要
深度学习是一种出色的方法,可用于卫星或航空照片等遥感数据集中的对象检测和分割/映射应用。然而,就像深度学习的许多其他用途一样,获得足够的带注释的训练数据可能非常耗时。在这篇文章中,我将介绍我们的一些工作,使用预训练的网络,以消除在注释遥感数据中的目标检测的大型训练数据集的繁琐工作。
【2019 年 9 月中旬我参加了北欧遥感会议。从许多演讲中可以清楚地看到,深度学习已经进入了许多遥感专家的工具箱。观众对这个话题的兴趣似乎很大,并且对深度学习技术在各种应用中的影响和适用性进行了一些讨论。
讨论的一个问题是使用为一种数据(通常是自然图像)开发和训练的神经网络,并将其应用于其他类型的(遥感)数据源。例如,挪威计算中心的 ivind Due Trier 介绍了他的工作,在该工作中,为计算机视觉应用而开发的标准物体探测网络被应用于过滤后的高程图,以确定挪威考古遗址的位置。这里,来自观众的反对意见是,使用这种模型没有意义。对此我坚决不同意;尽管神经网络是为自然图像开发的,但在其他数据源上测试它也是有意义的。在这种情况下,演示者可以证明它是有效的!在我看来,甚至尝试在数据源之间进行迁移学习也是有意义的——为什么用在另一种数据集上训练的过滤器来初始化网络比随机初始化更糟糕呢?开发的模型可能太大,容易过度拟合,但是用现有的代码库和预先训练的模型做一个快速实验的好处通常是如此之大,以至于尝试一下很有意义。
在这篇文章的其余部分,我想介绍一些我们在实验室中所做的工作,应用在一个领域(ImageNet 自然图像)中训练的网络,在另一个领域(航空正射影像)中执行基于图像的搜索。希望我能让你相信这种方法是有意义的。我并不是说 ImageNet 网络可以带来最佳的结果,而是说,考虑到原本需要的注释工作量,使用跨域网络确实有意义。
视觉搜索和对训练数据的需求
深度学习或其他机器学习技术可以用于开发用于识别图像中的对象的鲁棒方法。利用飞机的正射影像或高分辨率卫星照片,这将能够对不同类型的物体进行测绘、计数或分割。然而,使用深度学习需要大量的训练数据,除非你已经有了所需对象类型的可用注册表数据(可用于从数据集中剪切训练图像的多边形数据),否则创建这样的训练数据集是一个非常耗时的过程,因此成本也很高。
因此,在与哥本哈根市的合作中,我们向一种工具迈进了一步,这种工具可用于映射所需的对象类型**,而不需要提前创建训练数据。该工具基于亚历山德拉研究所先前的地理视觉搜索项目背后的技术。这个在线演示的灵感很大程度上来自笛卡尔实验室开发的类似技术,它可以让你点击丹麦正射影像数据集上的一个地方,查看丹麦 100 个看起来最相似的地方。相似性度量是基于被训练来区分不同对象类型的神经网络来计算的。例如,单击码头或风力涡轮机将导致以下结果:**
基本上,该技术的工作原理是将数据集分成一大堆小片段(在这种情况下有 4800 万个片段),并为每个片段运行一个经过训练的 Resnet-34 网络,以区分 ImageNet 数据集中的 1000 个不同对象。我们不使用最终分类(1000 个类别中的一个),而是从网络中为每个切出提取一个所谓的描述符,由 2048 个数字组成。为了节省内存和减少计算负担,我们训练了一个自动编码器神经网络来将 2048 个数字压缩到 512 位。之后,来自正射影像数据集的 4800 万个图像裁剪部分可以在不到 80 毫秒的时间内与新的裁剪部分进行比较!自动编码器是为这个特定数据集训练的,这意味着它以自我监督的方式适应相关特征。
从一开始,该解决方案就有一些弱点,为了使技术更加强大,我们解决了这些弱点:
- 我们通过将提取的描述符基于具有旋转了 0、90、180 和 270 度的剪切的网络的输出来改进旋转不变性。
- 我们根据不同尺度的截断点计算了描述符。这允许你寻找不同大小的物体。
- 我们开发了一种交互式的方法来“提炼”搜索,这样映射就不仅仅是基于一个单一的参考剪裁,而是基于几个剪裁。
根据 2016 年公开发布的 12.5 厘米分辨率的丹麦春季正射影像数据集,我们计算了哥本哈根周围以下地区 3 种不同比例的 8,838,984 个裁剪图的描述符:
交互式映射
交互式地图目前处于原型阶段,最好用一个例子来解释:假设我们想要绘制在一个区域航行的所有船只的地图。我们首先选择包含一艘船的裁剪图:
基于存储的描述符,系统计算所选剪切部分和所有其它剪切部分之间的“距离”(相似性)。然后,进行分类,并向用户显示 100 个最相似的剪切部分:
可以看到,其中一些切口包含船只,但结果远远不够好。用户现在可以选择一些他或她满意的裁剪图:
此后,在所有选定的剪切部分和数据库中所有剪切部分的描述符之间进行比较,并再次基于它们的平均相似性距离进行分类。这就产生了以下 100 强:
可以看到显著的改善。我们可以选择运行另一次迭代搜索,方法是选择更多我们满意的裁剪部分,然后再次运行排序:
船只仍然在前 100 名之列,这是一个好现象。请注意,我们之前标记为满意的裁剪不再出现在交互式优化中。
从排序到映射
该迭代方法基于与在交互改进过程中选择的切出区的平均相似性距离,对所有 880 万个切出区进行排序。理想情况下,包含船只的前 N 个切口和不包含船只的其余切口之间应存在边界。然而,在实践中,更确切的情况是,前 M 个切口包含船,之后在切口 M 和切口 N 之间有一个间隔,其中一些切口而不是所有切口包含船。为了避免误报,在分类中 M 之后的截断点被假定为不包含船。我们已经创建了一个快捷的用户界面,用户可以在其中检查已排序的裁剪部分,并为 M 和 n 建立一些有用的值。
如果排序很好,并且 M 和 N 设置得很合理,那么您现在就有了由包含船只的裁剪部分组成的干净的训练数据(排序等级 N)。这可用于训练分类网络(或可能的目标检测网络)来识别船只。然而,在我们的例子中,我们选择了测试一个更简单的用于绘制船只的启发式方法:我们从排序中的 M 之前选择了 100 个随机切出(正面例子)并且在 N 之后选择了 100 个随机切出(负面例子)。这些切口形成了 200 个例子的对比组。对于 M 和 N 之间的每个剪切点,我们已经找到了比较集中的 2 个剪切点,它们的描述符是最相似的。如果这两个切口都是正例,则切口被接受为船,切口的轮廓被保存为形状文件中的多边形。对于所有正面的例子(排序等级
Zoomed in, you can see something like this (the different boxes are missing a side in the visualization for some reason):
Mapping is not perfect, but in less than a quarter of an hour the technique can give an overview of the situation. And at the same time you have also created a really good starting point for a training dataset that can be used to train a neural network or another machine learning methodology.
Mapping trees
Repeating the same process with trees instead of boats gives a mapping that looks like this:
Zoomed in, it looks like this:
Again, the mapping is not perfect, but it provides a good starting point for further work.
I hope this post has sparked some inspiration on how objects can be localized using a pre-trained neural network, e.g. for extracting training data from maps. I am very interested in hearing about more potential use cases, so if you have ever had a need for finding certain objects in large images such as maps, please leave a comment!
Also, I am very eager to hear your ideas on how to use self-supervised methods to create an even better embedding/representation of the image patches.
我在亚历山德拉研究所的视觉计算实验室工作;丹麦的一家非营利公司,帮助公司应用最新的 it 研究。我的实验室专注于高级计算机图形学和计算机视觉研究。我们永远欢迎合作!
从程序员的角度看深度学习(又名可区分编程)
或者为什么神经网络不再那么神经化了
2018 年的主要教训:深度学习很“酷”。其中一个主要原因是,DL 面临的基本问题非常普遍会引起大量学科的兴趣,从计算机视觉到神经机器翻译再到语音接口。更重要的是,DL 概念还可以从广泛的观点中衍生和研究**,这就是为什么你可以找到机器学习书籍和文章,它们来自统计、信息论、信号处理、数学和许多其他领域。**
神经网络本身,DL 中的关键工具,在第二次世界大战后从一种独特的混合中诞生,涉及神经生理学、控制论、行为主义心理学、电学和后来的计算工程,然后以一种或另一种形式通过多次更名幸存下来,最著名的形式是今天的“连接主义”和“深度学习”。
Source: https://twitter.com/benblume/status/932226883764342784.
从业者在过去几年见证了进一步的品牌重塑,这始于高度灵活的编程库的传播,如 PyTorch 、 Chainer 等等。尽管存在差异,所有这些库都有两个基本特征:(I)反向传播对于用户来说是完全自动和透明的(通过使用自动微分);以及(ii)网络和模型逻辑的代码与其他编程结构(如条件分支和循环)无缝集成。
因此,尽管它们在生物学上同名,**神经网络今天更适合程序员的思维,**及其模块化和封装的知识,而不是例如生物学家及其突触适应和化学神经递质的知识。
这种观点的转变有很多名字,最著名的是“可微分编程”(一年前由 Yann LeCun 推广的一个更老的想法)和“软件 2.0 ”。可微分程序(DP)是使用“可微分”操作符(也称为神经网络)实现的一段代码,其内部逻辑由一个或多个优化例程以数据驱动的方式进行调整。与“标准”神经网络的概念差异在于可使用的可微分算子的多样性(例如,可微分读/写操作、神经算术单元等)。),以及这些操作符与各种各样的标准结构和“软件 1.0”部分混合在一起的事实。
可微分编程只不过是对[现代]深度学习技术的重塑[……],但重要的一点是,人们现在正在通过组装参数化功能块的网络,并通过使用某种形式的基于梯度的优化从示例中训练它们,来构建一种新的软件。(来源: Yann LeCun 论脸书)。
作为推论,所有的软件设计问题,从调试到安全、隐私和模糊化,都可以在新扩展的“可区分软件”堆栈中找到扩展及其位置。
这篇文章的目的
DP 不仅仅是一个品牌重塑,还可以被视为一种思维模式的改变:深度网络不再是像我们的大脑一样以某种方式“学习”的生物学启发的工具*—它们是编程结构。按照这种推理,在这篇文章中我想展示当从纯编程开始时,有多少机器学习/深度学习概念可以自然产生,即单元测试、封装、模块化等思想。这不是另一篇“*深度学习向程序员解释”的文章——或者至少我希望如此!这更像是一篇“深度学习来自程序员的文章的梗概:迈向差异化编程的自然步骤。
注意:这是一个正在进行的工作。非常感谢任何评论或反馈。
单元测试和“软”断言
DP 就像它们的标准对应物一样,由函数组成。函数是(最好是小的)代码片段,它接受一些输入参数 x ,并返回一些输出值 y :
Source: https://tectrick.org/programming-function-definition/function/.
任何程序都可以表示为一系列基本操作,与基本控制 流程和循环交错。任何有经验的程序员都知道,编写函数比确保函数正确要简单得多。这就是为什么在现代编程实践中,任何函数都应该带有一个或多个单元测试,这些测试评估它在一系列用例上的正确行为:
An abstract example of unit test.
在机器学习术语中,这组用例被称为测试集。单元测试的一个有趣的特性是,它们通常比它们测试的功能更容易设计和实现(这就是为什么整个编程哲学都建立在它们之上)。
例如,考虑一家银行的程序员编写一个函数来确定给定的客户 x 是否应该获得贷款( y=1 )或不获得贷款( y=0 )。这个函数的整个主体将(可能)是一个混乱的东西,充满了他/她的内部知识、嵌套的 if-else 分支、判断性评估等等。然而,测试功能是很简单的:人们可以简单地选择一系列已知的客户端,并在这些客户端上评估功能。
在一个标准的单元测试中,给我们测试集中的一个客户打分很低将会导致整个程序失败。然而,没有什么可以阻止我们编写 软测试断言 来评估而不一定失败。例如,如果测试集中超过 75%的客户端从我们的例程中被正确分类,我们可能认为我们的测试在这个场景中是成功的。
软单元测试允许优化?
如上所述的软测试方法带来了优化我们的程序的想法:一个得分 80%的函数可能比一个得分 77%的函数更好,同时仍然有改进的空间。遗憾的是,我们缺乏一种结构化的方法来决定如何修改函数。
注意:我们可以决定随机改变函数中的每一条指令(例如,将“如果 a > 0”子句改为“如果 a ≤ 0”子句),并测试新的函数集,也称为遗传编程。然而,我们不能保证这些可能的 成千上万 变异函数中的任何一个会比我们原来的函数更好!
DPs 之外的见解是,如果我们适当地限制我们在程序中使用的基本操作的类型,那么就有可能从我们的数据中设计出一个更好的程序来优化它。顾名思义,DP 要求所有初等函数都是可微的,即:
让我们来看一个有单个输入参数的可微函数的例子, b :
Source: https://mathinsight.org/image/derivative_example_function_3_derivative.
蓝线是连续的**:其输入参数的任何值与直接接近的值之间没有不连续。该函数还允许求导(绿线),我们可以检查该求导,以查看当我们增加或减少输入 b 时,该函数是否会增加或减少。可微函数的例子有和、积、平方根…**
将我们自己局限于可微函数看起来是一个巨大的挑战,因为任何“清晰”的决定,导致我们的图中明显的不连续,将永远超出我们的算法的掌握。即使是简单的 0/1 二进制决策,或者决定从数据库中读取单个条目,都是无法以这种方式编码的指令。在人工智能领域,这被称为符号对抗子符号挑战:基于连续函数的方法无法以直接的方式操纵离散的符号,如单词或心理类别。
除了 f(x)的可微性,我们还需要确保 测试过程是可微的。如果这两个约束都满足了,我们就获得了一个非常强大的工具,以数字优化的形式来交换我们缺乏的表现力。使用导数的信息,我们可以设计自动迭代算法,能够通过最大化测试度量来自动学习函数的“形状”。您可以将此视为编译器的扩展,除了生成可执行代码之外,它还“校准”函数的内部参数,这些参数决定组成基本函数如何变化。
“信息泄漏”和过度拟合
到目前为止,我们的讨论有一个我们没有提到的“房间里的大象”:对我们想要测试的相同性能度量进行数值优化是一个相当糟糕的想法。为了看到这一点,考虑通过查看单元测试,我们总是可以实现一个简单的模拟其测试用例的查找表,这将总是在测试中达到 100%的准确性。另一种说法是"学习不是记忆":银行只有在能够了解到一些迄今为止还没有看到的未来客户的情况下,才会对其客户的历史信息感兴趣。
在机器学习中,一个过度适应其测试数据的函数被称为过度适应**。这个问题的解决方案很简单:我们只需要确保我们用于优化的数据不同于我们用于测试的数据。回到我们的编程例子,任何同时编写函数和单元测试的程序员都容易“信息泄露”并可能作弊,但是如果我们使用两个不同的程序员(又名,黑盒测试),那么我们完全有信心我们的测试例程告诉我们一些有意义的东西。**
Black-box unit testing requires the tester to have no knowledge of the underlying program. In DPs, this is achieved trivially by using separate datasets for the optimization phase and the testing phase (source: http://softwaretestingfundamentals.com/black-box-testing/).
训练/测试分离还有另一个优点:虽然训练标准必须是可微分的,但是测试标准没有这样的要求。再次考虑对用户分类的问题:即使是一个非常简单的目标如“f(x1)= = y1”(ML 术语中称之为0/1 损失**)也无法区分,更不用说直接优化了。然而,我们可以优化一个合适的代理项(比如交叉熵),并且仍然能够在准确性方面测试我们的应用程序。**
差异化程序员的角色
在“软件 1.0”中,程序员为功能选择一系列操作,然后为单元测试选择一系列用例。在一个 DP 中,测试用例更适合收集而不是选择**,因为它们代表了我们想要从中提取一些洞察力的历史信息。因为 DPs 在他们的优化阶段也需要数据,并且因为这些数据通常需要比测试用例大至少一个数量级,可区分编程是一个数据饥渴的学科:寻找数据,标记它,确保它正确地描述我们的问题域,消除偏见都是解决“2.0”版本软件问题的先决条件。**
接下来,程序员需要选择一个正确的度量来优化(损耗和 f(x)的具体形状)。正如目前在世界各地执行的所有程序都是从相对少量的原语中派生出来的一样,少量的可微运算符允许我们为 f(x)定义指数数量的可能“程序结构”,而直观地做到这一点的能力是具有多年经验的深度学习工程师与初学者的区别。****
许多营销活动倡导深度学习作为一种工具,通过向问题扔越来越多的数据来自动解决任务。显然,这与真相相去甚远。程序员的精神角色正在从定义一个非常精确的符号运算序列转移到指定一个可微分运算的模板,其细节应该从数据中学习。这不是一个简单的任务,因为我们的结构不适合用次符号术语进行推理,而且我们发现很难在头脑中想象一系列次符号操作。结果,构建一个 DP 变成了直觉、经验、技巧和聪明调试的迷人组合。
It looks cool, but only until it doesn’t work and you have no idea what to do with these bunches of numbers (source: https://bdtechtalks.com/2018/02/27/limits-challenges-deep-learning-gary-marcus/).
更一般地说,将“编译器”(优化例程)与程序的其余部分完全隔离也是困难的,因此人们不得不修改优化参数和标志,甚至修改模型本身以使它们更容易优化。
可微分例程
原型可微运算是一个线性组合**。例如,两个输入 a 和 b 的线性组合为:**
a 和 b 同时决定 c 的值,每一个都具有可以通过算法找到的特定权重。线性组合是所有 DPs 的构建块,因为它们代表了在我们的程序中插入对象之间的参数关系的最简单的可能方式。 c 可以是我们计算的中间步骤,甚至是最终的输出值。
数学上,线性组合不能堆叠**:线性组合的一个线性组合和参数不同的单个线性组合是一样的(这个你大概需要读两遍)。如果我们想要线性操作的序列,我们需要用一个或多个非线性*T21 来交错它们。在深度网络的术语中,这些被称为*激活功能。线性组合和激活函数是经典神经网络的基础,松散地表示“突触”(上图中的连接线),以及阈值。
然而,DPs 并不局限于具有生物学相似性的手术。今天的“DP 工具包”非常广泛,我们可以只提到几个有代表性的例子。
可微分支和注意
考虑"形式的一般条件指令,如果满足条件 a,则执行 f(x),否则执行 g(x) 。只要条件 a 不是我们程序的可微部分的一部分,那么我们就没有问题。然而,当我们还想学习(优化)子句时,事情就变得更难了,因为如上所述,我们不能对二元决策进行区分。
分支的可微版本有两个组成部分。第一个是用所谓的s 形函数对条件 a 进行预处理:
The sigmoid function (taken from Wikipedia).
从图中可以看出,不管 a 的值如何,σ(a)(sigmoid 的输出)的值将是 0 到 1 之间的一个数字,可能更接近两个极端值中的一个。不是简单地选择两个分支中的一个,然后,一个“可微 if 取由条件本身加权的两个分支的组合:
A differentiable equivalent of branching.
这样,条件 a 就可以和其余的一起作为另一个 DP 的输出。由于之前表达的形式,这个想法在深度学习文献中也被冠以门控的名称。一个类似的机制,注意,允许实现不同的例程,给或多或少的权重给程序的不同组件。
可区分的阅读和写作
从内存中读写是大多数程序的另一个关键组成部分。然而,如果这些操作需要成为 DP 的一部分,它们需要被“平滑”以使它们可区分(因为在存储器中选择一个单个地址是一个不可区分的操作)。有趣的是,人们可以使用与以前相同的逻辑来设计可区分的读/写操作:我们让程序通过元素的适当线性组合来读/写所有的位置。
Source: https://distill.pub/2016/augmented-rnns/.
可微分算法
经典算术也超出了 DPs 的范围,因为我们没有简单的方法来强制程序的权重为精确的整数。尽管如此,我们可以尝试让我们的架构偏向于进行类似算术的计算。最近的 神经算术逻辑单元 就是这种情况,它利用非线性和注意力机制的巧妙结合,迫使权重接近-1、0 或+1。
Source: https://arxiv.org/pdf/1808.00508.pdf.
可微分循环
现在考虑一个通用的循环机制,其中我们迭代数组 a 的元素,并通过应用函数 f 收集结果:
这种运算在可微世界中不需要任何修改!事实上,如果 f 是一个 DP,我们获得一个已知的对象,称为递归神经网络**,一个具有小内存(以中间值 z 的形式)的网络,它可以学习处理元素序列:**
Source: http://colah.github.io/posts/2015-08-Understanding-LSTMs/.
递归网络也可以与 gates 结合来提高它们的能力,或者与小的注意机制结合来自动学习何时停止迭代。
其他可微分运算
显然,还有更多可微的操作符!如果您正在处理特殊类型的数据(例如,图像、图表),您可以为它们定义特定的操作,例如卷积或扩散运算符。类似地,如果您需要一个更结构化的输出(例如,序列),您可以结合其他操作符来使您的 DP 偏向这些特殊情况。
最后得出结论
如果一个人真的想将深度学习推向可区分的编程,为程序员提供数学教程是不够的:我们需要用编程术语重新表述/重新思考整个领域。这篇文章是我对这种重新措辞的“心理草图”。
用“从数据中学习”来描述深度学习是很常见的。然而,使程序适应手边的数据对程序员来说并不一定是陌生的概念:一个通过从数据库中读取摘要来微调其内部逻辑的软件可以说是执行了一个非常粗糙的版本。对于一个有经验的程序员来说,很难从概念上想到一个混合了“crisp”和可微的程序,以及一个人如何能够对如何用一组原始可微操作符解决一个问题产生直觉。我相信,这将是全面采用软件 2.0 堆栈的主要“心理障碍”。
从零开始深度学习并在 Python 中使用 Tensorflow
深度学习是目前在现实世界、数据科学应用中使用的最流行的模型之一。在从图像到文本到语音/音乐的各个领域,这都是一个有效的模式。随着其使用的增加,快速和可扩展地实现深度学习的能力变得至关重要。Tensorflow 等深度学习平台的兴起,帮助开发者以更简单的方式实现他们需要的东西。
在本文中,我们将了解深度学习是如何工作的,并熟悉它的术语——如反向传播和批量大小。我们将为 Python 中预定义的输入和输出实现一个简单的深度学习模型——从理论到零实现——然后使用 Keras 和 Tensorflow 等深度学习平台做同样的事情。我们使用 Keras 和 tensor flow 1 . x 版和 2.0 版编写了这个简单的深度学习模型,具有三个不同的复杂程度和易于编码的程度。
深度学习从无到有的实现
考虑一个简单的多层感知器,它有四个输入神经元,一个隐藏层有三个神经元,一个输出层有一个神经元。我们有三个数据样本用于表示为 X 的输入,三个数据样本用于表示为 yt 的期望输出。因此,每个输入数据样本有四个特征。
# Inputs and outputs of the neural net:
import numpy as npX=np.array([[1.0, 0.0, 1.0, 0.0],[1.0, 0.0, 1.0, 1.0],[0.0, 1.0, 0.0, 1.0]])
yt=np.array([[1.0],[1.0],[0.0]])
Neural Network with four input neurons, one hidden layer with three neurons and an output layer with one neuron
图中的 x (m) 为 X , h (m)为输入X*(m)WI和 W h*
神经网络(NN)的目标是获得权重和偏差,以便对于给定的输入,NN 提供期望的输出。但是,我们事先不知道适当的权重和偏差,所以我们更新权重和偏差,使得 NN、 yp(m) 和期望的输出、 yt(m) 之间的误差最小。这个迭代最小化过程被称为 NN 训练。
假设隐藏层和输出层的激活函数都是 sigmoid 函数。因此,
The size of weights, biases and the relationships between input and outputs of the neural net
其中激活函数是 sigmoid, m 是第 m 个数据样本, yp(m) 是 NN 输出。
误差函数测量神经网络的输出与期望输出之间的差异,可以用数学方法表示为:
The Error defined for the neural net which is squared error
上述 NN 的伪代码总结如下:
pseudocode for the neural net training
从我们的伪代码中,我们认识到应该计算误差(E)相对于参数(权重和偏差)的偏导数。使用微积分中的链式法则,我们可以写出:
Derivative of Error function with respect to the weights
这里我们有两个选项来更新反向路径中的权重和偏差(反向路径意味着更新权重和偏差,使得误差最小化):
- 使用训练数据的所有 N 个样本
- 使用一个样本(或几个样本)
对于第一个,我们说批量大小是 N 。对于第二种情况,如果使用一个样本来更新参数,我们说批量大小为 1。因此,批量意味着有多少数据样本被用于更新权重和偏差。
你可以找到上述神经网络的实现,其中误差相对于参数的梯度被象征性地计算,具有不同的批量大小这里是。
从上面的例子可以看出,从头开始创建一个简单的深度学习模型涉及到非常复杂的方法。在下一节中,我们将看到深度学习框架如何帮助我们的模型实现可扩展性和更大的易用性。
使用 Keras、Tensorflow 1.x 和 2.0 的深度学习实现
在上一节中,我们使用链式法则计算了误差 w.r.t .参数的梯度。我们亲眼看到这不是一个简单或可扩展的方法。此外,请记住,我们在每次迭代中计算偏导数,因此不需要符号梯度,尽管它的值很重要。这就是深度学习框架如 Keras 和 Tensorflow 可以发挥作用的地方。深度学习框架使用自动 Diff 方法进行部分梯度的数值计算。如果你不熟悉 AutoDiff,StackExchange 有一个很好的例子来介绍一下。
自动 Diff 将复杂的表达式分解成一组原始表达式,即最多由单个函数调用组成的表达式。由于每个单独表达式的微分规则都是已知的,所以可以用有效的方式计算出最终结果。
我们在 Keras、Tensorflow 1.x 和 Tensorflow 2.0 中实现了具有三个不同级别的 NN 模型:
1-高级(Keras 和 Tensorflow 2.0): 批量为 1 的高级 tensor flow 2.0
2-中级(Tensorflow 1.x 和 2.0): 中级 Tensorflow 1.x 批量 1 ,中级 Tensorflow 1.x 批量 N ,中级 Tensorflow 2.0 批量 1 ,中级 Tensorflow v 2.0 批量 N
3-低级(Tensorflow 1.x): 批量为 N 的低级 tensor flow 1 . x
代码片段:
对于高层,我们使用 Keras 和 Tensorflow v 2.0 通过 model.train_on_batch 完成了实现:
# High-Level implementation of the neural net in Tensorflow:
model.compile(loss=mse, optimizer=optimizer)
**for** _ **in** range(2000):
**for** step, (x, y) **in** enumerate(zip(X_data, y_data)):
model.train_on_batch(np.array([x]), np.array([y]))
在使用 Tensorflow 1.x 的中级中,我们定义了:
E = tf.reduce_sum(tf.pow(ypred - Y, 2))
optimizer = tf.train.GradientDescentOptimizer(0.1)
grads = optimizer.compute_gradients(E, [W_h, b_h, W_o, b_o])
updates = optimizer.apply_gradients(grads)
这确保了在循环的中,更新变量将被更新。对于中级,梯度和它们的更新在 for_loop 外部定义,而在 for_loop 更新内部迭代更新。在中级使用 Tensorflow v 2.x 中,我们使用了:
# Medium-Level implementation of the neural net in Tensorflow**#** In for_loop**with** tf.GradientTape() **as** tape:
x = tf.convert_to_tensor(np.array([x]), dtype=tf.float64)
y = tf.convert_to_tensor(np.array([y]), dtype=tf.float64)
ypred = model(x)
loss = mse(y, ypred)
gradients = tape.gradient(loss, model.trainable_weights)
optimizer.apply_gradients(zip(gradients, model.trainable_weights))
在低级实现中,每个权重和偏差被单独更新。在使用 Tensorflow v 1.x 的低级中,我们定义了:
# Low-Level implementation of the neural net in Tensorflow:
E = tf.reduce_sum(tf.pow(ypred - Y, 2))
dE_dW_h = tf.gradients(E, [W_h])[0]
dE_db_h = tf.gradients(E, [b_h])[0]
dE_dW_o = tf.gradients(E, [W_o])[0]
dE_db_o = tf.gradients(E, [b_o])[0]
# In for_loop:
evaluated_dE_dW_h = sess.run(dE_dW_h,
feed_dict={W_h: W_h_i, b_h: b_h_i, W_o: W_o_i, b_o: b_o_i, X: X_data.T, Y: y_data.T})
W_h_i = W_h_i - 0.1 * evaluated_dE_dW_h
evaluated_dE_db_h = sess.run(dE_db_h,
feed_dict={W_h: W_h_i, b_h: b_h_i, W_o: W_o_i, b_o: b_o_i, X: X_data.T, Y: y_data.T})
b_h_i = b_h_i - 0.1 * evaluated_dE_db_h
evaluated_dE_dW_o = sess.run(dE_dW_o,
feed_dict={W_h: W_h_i, b_h: b_h_i, W_o: W_o_i, b_o: b_o_i, X: X_data.T, Y: y_data.T})
W_o_i = W_o_i - 0.1 * evaluated_dE_dW_o
evaluated_dE_db_o = sess.run(dE_db_o,
feed_dict={W_h: W_h_i, b_h: b_h_i, W_o: W_o_i, b_o: b_o_i, X: X_data.T, Y: y_data.T})
b_o_i = b_o_i - 0.1 * evaluated_dE_db_o
正如你在上面的低级实现中看到的,开发者对数字操作和计算的每一步都有更多的控制。
结论
我们现在已经表明,通过使用用于权重和偏差更新的符号梯度计算,从零开始实现即使是简单的深度学习模型也不是一种容易或可扩展的方法。由于使用了 AutoDiff,使用深度学习框架加速了这一过程,AutoDiff 基本上是用于更新权重和偏差的稳定的数值梯度计算。
Ubuntu 18.4 上的深度学习 GPU 安装
在安装了几次驱动程序、CUDA 等之后,为了让我的深度学习库与我的 GPU 对话,我决定编写适用于 Ubuntu18.04 的安装步骤。
1.NVIDIA 驱动程序安装
第一步:确保你的 GPU 是英伟达 GPU
首先需要做的是,使用以下命令确保 GPU 是 NVIDIA GPU:
$ ubuntu-drivers devices
第二步:移除 NVIDIA 驱动
首先要做的是运行以下命令,以确保清除任何预安装的驱动程序:
$ sudo apt-get autoremove$ sudo apt-get remove nvidia*$ sudo apt-get purge cuda*
步骤 3:禁用新的 NVIDIA 驱动程序
上一步之后这一步有时候就没必要了,但是我还是强烈建议去做(做了不疼!).
首先,您需要打开黑名单-nouveau.conf 文件(我使用 gedit,但也可以随意使用任何其他类型的编辑器)。我使用的命令如下:
$ sudo gedit /etc/modprobe.d/blacklist-nouveau.conf
现在,将下面几行添加到文件中。
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off
保存并关闭文件。
禁用内核新功能:
$ echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
步骤 4:添加 PPA 驱动程序库
要将ppa:graphics-drivers/ppa
存储库添加到您的系统中,请键入以下命令:
$ sudo add-apt-repository ppa:graphics-drivers/ppa
步骤 5:安装 NVIDIA 驱动程序
过去,我常常从英伟达下载网站(https://www.nvidia.co.uk/Download/index.aspx?lang=en-uk)下载驱动程序。
最简单和最可靠的方法是直接从终端安装它(这是我在 NVIDIA 论坛上的一篇帖子中来自 NVIDIA 的直接建议)。安装驱动程序的命令应该是(确保您安装了正确的驱动程序!):
$ sudo apt install nvidia-driver-435
另一个选择是直接从 Ubuntu 的软件和更新设置中安装它:
现在,选择正确的驱动程序(这是一个棘手的问题,如果这一步没有成功,你可能不得不回来测试一个新的驱动程序)。点击应用更改,一切就绪!
第六步:重启电脑
别忘了这一步!
步骤 7:检查驱动程序是否正常工作
通过键入以下命令,您将知道安装已经成功:
$ nvidia-smi
您应该会看到类似于
如果你在这里得到一个 NVIDIA 错误,从头开始尝试所有的步骤,但是这次选择一个新的驱动程序!
2.CUDA 安装
在安装 CUDA 的时候,我一般都是按照 CUDA 安装指南来的,这个指南非常完整(https://docs . NVIDIA . com/CUDA/CUDA-installation-guide-Linux/index . html)。
步骤 1:预安装检查
- 首先检查你的 GPU 是否可以处理 CUDA:
$ lspci | grep -i nvidia
- 检查您是否有受支持的 Linux 版本:
$ uname -m && cat /etc/*release
这应该会返回类似于
x86_64
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION=”Ubuntu 18.04.3 LTS”
NAME=”Ubuntu”
VERSION=”18.04.3 LTS (Bionic Beaver)”
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME=”Ubuntu 18.04.3 LTS”
VERSION_ID=”18.04"
HOME_URL=”[https://www.ubuntu.com/](https://www.ubuntu.com/)"
SUPPORT_URL=”[https://help.ubuntu.com/](https://help.ubuntu.com/)"
BUG_REPORT_URL=”[https://bugs.launchpad.net/ubuntu/](https://bugs.launchpad.net/ubuntu/)"
PRIVACY_POLICY_URL=”[https://www.ubuntu.com/legal/terms-and-policies/privacy-policy](https://www.ubuntu.com/legal/terms-and-policies/privacy-policy)"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
- 检查 gcc 是否已安装
$ gcc --version
- 检查您的内核头文件是否与 CUDA 兼容(您可以在 CUDA 安装指南中找到兼容性表):
$ uname -r
- 使用以下命令安装内核头文件和包:
$ sudo apt-get install linux-headers-$(uname -r)
步骤 2:下载 CUDA
您可以通过以下链接下载 CUDA 工具包:
编辑描述
developer.nvidia.com](https://developer.nvidia.com/cuda-downloads)
对于 Ubuntu 18.04,您需要下载以下内容
现在,你只需要等待,这个下载可能需要一段时间!
步骤 3:安装 CUDA
安装 CUDA 的步骤非常简单。只需在您的终端上键入以下命令:
$ wget [http://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda_10.1.243_418.87.00_linux.run](http://developer.download.nvidia.com/compute/cuda/10.1/Prod/local_installers/cuda_10.1.243_418.87.00_linux.run)
$ sudo sh cuda_10.1.243_418.87.00_linux.run
您应该会看到以下屏幕:
确保此次安装不会安装新的驱动程序!!!!!
Unselect Driver when installing CUDA
如果安装成功,您应该会看到以下屏幕:
3.安装 cuDNN
这是您可以开始使用 GPU 进行深度学习之前的最后几个步骤!
第一步:下载 cuDNN
以下链接将带您进入 cuDNN 下载网站:
https://developer.nvidia.com/rdp/form/cudnn-download-survey
你必须先登录才能下载任何东西。进入后,下载:
- cuDNN 图书馆
- cuDNN 运行时库(Deb)
- cuDNN 开发者库(Deb)
- cuDNN 代码示例(Deb)
步骤 2:安装 cuDNN
这些步骤主要遵循 cuDNN 安装网站https://docs . NVIDIA . com/deep learning/SDK/cud nn-install/index . html中的说明
- cd 到你的下载文件夹(或者下载文件所在的地方)
- 使用以下命令解包归档文件:
$ tar -zxvf cudnn-10.1-linux-x64-v7.6.5.32.tgz
- 将文件复制到 CUDA 工具包目录中,并更改权限
$ sudo cp cuda/include/cudnn.h /usr/local/cuda/include
$ sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
$ sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
- 使用以下命令安装这三个库
$ sudo dpkg -i libcudnn7_7.6.5.32–1+cuda10.1_amd64.deb
$ sudo dpkg -i libcudnn7-dev_7.6.5.32-1+cuda10.1_amd64.deb
$ sudo dpkg -i libcudnn7-doc_7.6.5.32-1+cuda10.1_amd64.deb
4.检查一切是否正常!
为了做到这一点,cuDNN 创建了一个样本代码,它将使用您的 GPU 在 MNIST 数据集上运行一些计算。为此,您需要遵循以下步骤:
$ cp -r /usr/src/cudnn_samples_v7/ $HOME
$ cd $HOME/cudnn_samples_v7/mnistCUDNN
$ make clean && make
$ ./mnistCUDNN
如果一切正常,您应该会看到如下内容:
现在你可以很好地使用你的 GPU 了!
深度学习&手写阿拉伯数字
使用 fast.ai 库以 99%的准确率对 AHCD 进行分类!
photo: Morocco, 2000
深度学习的“hello world”通常是 MNIST 手写数字数据集,我想将同样的技术应用到一个更有趣的应用程序中:阿拉伯语手写字符数据集(AHCD),由美国大学开发的数据集。
在这个例子中,我使用 fast.ai 库来训练一个卷积神经网络(CNN ),以 99+%的准确率对 AHCD 进行正确分类。方法如下:
首先,导入我们需要的库,并设置我们的 GPU 使用 cuda:
%reload_ext autoreload
%autoreload 2
%matplotlib inline**from** **fastai.vision** **import** *
**from** **fastai.metrics** **import** error_rate
**import** **csv**
**import** **numpy** **as** **np**
**import** **PIL**
**import** **pandas** **as** **pd**defaults.device = torch.device('cuda')
与许多数据科学工作流一样,数据预处理是最重要的组成部分。以下是为我们的卷积神经网络准备数据的步骤:
1 —从 csv 摄取
与 MNIST 拉丁字母版本一样,AHCD 也是一个 784 列的 csv,其中每行包含一个 28x28 的图像,该图像被展平为一行数值。
第一个任务是将它加载到内存中,由于数据集有 60k 行,为了加速这个过程,我设置了一个任意的 4k 训练集限制。我们将 Pandas 作为 pd 导入,所以这使用了内置的 Pandas read_csv 函数:
trainrows = 4000
train = pd.read_csv('csvtrain.csv', nrows=trainrows)
2-转换为 3D 数据结构以进行图像处理
我们在内存中有数据,但是每个要生成的图像仍然是平面的(1 高 784 宽),我们希望它是正方形和多维的,这样我们可以使用 matplotlib 将其转换为 RGB 图像。为什么是 RGB?我们将使用基于 RGB 图像开发的预训练 restnet34 模型。
这个简单的函数获取我们的 Pandas train
数据帧并提取一行(作为变量传递),将该行重新整形为一个正方形结构,将数字规范化为范围[0,1],添加两个全零的额外维度,并使用 matplotlib.plot 库将图像作为 png 保存在我们的path/digits/
文件夹中。
注意:最后,我将添加逻辑来将文件夹作为变量传递。目前,它是硬编码的。
**def** pdMakePlot(row):
pixels = np.array(train.iloc[[row]], dtype='uint8')
pixels = pixels.reshape((28, 28)).T
pixels = np.true_divide(pixels, 255)
dim2 = np.zeros((28,28))
dim3 = np.zeros((28,28))
pix = np.stack((pixels, dim2,dim3), axis=2)
row += 1
filename = "digits/**%s**.png" % row
plt.imsave(filename, pix)
plt.close('all')
**return**
3-准备我们的事实来源数据框架
我们正在使用 fast.ai ImageDataBunch.from_df
方法为这个卷积神经网络摄取图像数据,因此我们需要一个 Pandas 数据帧,其中包含我们的训练文件名&和有效标签。
#import training labels into numpy arraycsv = np.genfromtxt ('csvtrainlabel.csv', delimiter=",")
csv = csv[0:trainrows]
csv = csv.astype('int32')
csv = np.add(csv,1)
csv[csv == 10] = 0*#np array that we'll make into the filenames*
*#from 1 to trainrows*
trainrange = trainrows +1
files = np.arange(1,trainrange)
files = files.astype(str)*#convert to filenames*
i = 0;
j = 1;
**for** file **in** files:
files[i] = "**%s**.png" % j
i += 1
j += 1
**if** i >= trainrange: **break***#combine two arrays into dataframe and add header*
df = pd.DataFrame({'name':files, 'label':csv})
df.head()
our dataframe
同样,我将再次讨论 ETL 过程的一部分。
4 —处理并保存我们的培训图像
有了这些,我们可以使用我们之前定义的pdMakePlot()
函数来处理训练图像。处理的图像数量也由我们之前设置的trainrange
变量设置。
i = 0
max = trainrange-1
for x in range(i,max):
pdMakePlot(i)
i += 1
现在我们已经准备好进行深度学习了!只有几行代码:
#define our transforms
tfms = get_transforms(do_flip=False)#define our DataBunch
data = ImageDataBunch.from_df(path=path, df = df, ds_tfms=tfms, size=24)#define our learner
learn = create_cnn(data, models.resnet34, metrics=accuracy)
在我们训练之前,我们可以从我们的数据集中查看一小部分选择,以确认我们已经正确处理了所有内容:
data.show_batch(rows=3, figsize=(7,6))
9 handwritten characters & labels
一切都好!我们还可以运行learn.model
来详细了解学习者架构。如果你感兴趣,它是可用的。不管怎样,我们训练吧!
初步训练
learn.fit_one_cycle(4)
transfer learning from resnet34, 95% accuracy in 16 seconds
我认为我们可以做得更好。让我们找到最佳的学习率,重新训练。
learn.lr_find()LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.learn.recorder.plot()
learning rate against loss
我们看到最优学习率确实很高。让我们试着获得一个比最小化损失的学习率低一点的学习率,比如 0.05?然后我们会解冻 CNN 的一些层,重新训练。
learn.unfreeze()
learn.fit_one_cycle(3, max_lr=slice(.006, .004))
much better
15 秒钟后,我们有了一个模型,它对我们留在一边进行验证的训练数据子集有 99.6%的准确性。
使用模型
既然有了模型,那就用起来吧!使用上面的函数从测试 csv 中读取一些测试数据后:
img = open_image('/path/3.png')pred_class,pred_idx,outputs = learn.predict(img)
pred_class**Category 4 <--- that is correct**
然后
现在我们有了一个工作模型,而且是一个准确的模型,我想更新管道代码,使它更加优雅。我还想对全套测试数据运行模型,看看它如何与最先进的技术相比较。更多来了!
也
附加代码在我的 github 上:www.github.com/matthewarthur。我的 LinkedIn 是 https://www.linkedin.com/in/matt-a-8208aaa/的。打个招呼。
笔记
https://www.kaggle.com/mloey1/ahcd1&http://datacenter.aucegypt.edu/shazeem/
[2]https://docs . fast . ai/vision . data . html # imagedata bunch . from _ df
深度学习有了一个新朋友——表格数据集
超越图像数据集的深度学习
当你想到深度学习时,我们首先想到的不是表格数据集。我们首先想到的是图像数据集。这是因为深度学习和图像数据集有一种特殊的关系。深度学习变得流行主要是因为它能够在图像上创造奇迹。几年前,当深度学习能够区分狗的图像和猫的图像,或者马和斑马时,我们都很兴奋。当深度学习进入图像中的对象检测领域时,兴奋感才增加。图像中不同物体周围各种颜色的边框看起来很酷
图像和深度学习的这种特殊关系也推动了几乎所有围绕深度学习教程的文献。对于许多技术,如理解黑盒模型,使用的例子是图像数据集。MNIST 数字图像数据集已经成为深度学习教程的“Hello World”。图像数据集已经成为理解深度学习的一个很好的来源。
但是好的旧表格数据呢?大多数企业数据以及我们的个人数据都是表格数据的形式。将深度学习用于表格数据将有巨大的价值。然而,将深度学习应用于表格数据的文献很少
通过这个故事,我试图展示深度学习如何对表格数据集非常有用。
为了说明这一点,让我们举一个非常简单的泰坦尼克号生存数据的例子。许多数据科学家已经从 Kaggle 那里知道了这个非常著名的数据集。对于那些不知道这个数据集的人来说,它是致命的泰坦尼克号事故中乘客的数据。为了便于说明,下面是该数据集的样本摘录
Sample extract of Titanic passenger data
现在让我们将深度学习应用于这个表格数据集。深度学习是基于受我们大脑工作方式启发的神经网络。你有“输入”神经元,它接收信号并将它们发送给“输出”神经元
在我们的例子中,输入是像家庭(父母+兄弟)、费用、年龄、乘客级别(Pclass)、登机港口、性别这样的字段。输出是乘客是否幸存。
我们的深度学习架构,如图所示,有输入神经元,后面是 10 个中间神经元和 2 个输出神经元。输入神经元向中间神经元发送信号,中间神经元再向输出神经元发送信号。这个神经元网络,也称为神经网络,为了可视化的目的显示如下。“蓝色”线表示“正”信号,“红色”线表示“负”信号
Feed Forward Neural Network on Titanic dataset
看起来很乱,不是吗?然而,让我们探索不同的部分,看看我们能解释什么
查找表格数据集中列的重要性
表格数据集主要是行和列的集合。我们总是有兴趣知道这些列的重要性。在泰坦尼克号数据集的情况下,检查列的重要性的一种方法是看它是否对人是否幸存有影响。
表格数据上的神经网络可以告知哪些输入列会影响输出列。下图所示为仅用于神经元“Sex_Male”发出的高强度信号的神经网络。信号被传递到“死亡”的神经元。这意味着大多数男性乘客没有生还
因此,深度学习可以帮助我们进行这样的分析,而不必浏览每一篇专栏文章
自动查找重要的列组合
与图像相比,表格数据集更加丰富和复杂。假设有许多列,找出哪些是重要的列组合总是有用的。通常,我们习惯于手动查找任何表格数据集中的重要列。为了找到重要的列组合,我们倾向于制作数据透视表、排序、应用公式。
如果我告诉你深度学习会自动为你做到这一点呢?这听起来很神奇,但却是真的。也正因为如此,它被称为“深度”学习。神经网络的中间层将试图找到对输出有影响的所有输入组合。
titanic 数据集中的一个这样的例子如下所示。“红色”表示“负面”信号。我们看到神经元“Age”和神经元“Pclass”(乘客类)的组合向神经元“Died”传递了一个负信号。这意味着 少了 这个年龄(负信号)而 少了 这个乘客阶层(负信号),这个乘客没有死亡(幸存)
泰坦尼克号上的乘客分为一等舱、二等舱和三等舱。所以从数字的角度来看,更小的等级值意味着第一等级。
为了证实这一点,我们可以制作一个乘客等级和年龄的散点图,如下所示。点的颜色显示乘客是否幸存。该散点图分析表明头等舱或二等舱中年龄较小乘客(儿童)幸存。
现在,如果没有深度学习,您将不得不手动绘制所有列组合的散点图。但是深度学习能够自动从数据中学习数据中的重要组合
对表格数据进行简短总结
假设你被要求对表格数据做一个简短的总结。你怎么能只看一堆行和列?深度学习可以帮助你。由于深度学习受到“大脑”架构的启发,它试图“理解”表格数据的底层结构。
这样做的方法是观察每个神经元“学习”或“理解”数据的内容。出于说明的目的,下面显示的是影响“存活”神经元的所有神经元。正如我们从可视化中看到的,神经元 7 和神经元 8 对“存活”的神经元有影响。
我们可以看到,神经元 7 具有朝向神经元“存活”的“正”(蓝色)信号,而神经元 8 具有朝向神经元“存活”(意味着死亡)的“负”(红色)信号。
现在我们可以分析神经元 7 和 8 的“内部”是什么。这将向我们展示这些神经元从数据中学到了什么。我们可以“窥视”神经元内部来看到这一点。每个神经元可以用从输入神经元接收的强度来表示。我们可以用雷达图来显示神经元的“内部”
Peeking inside the neurons to see what it has learned
所以在 neuron7 内部,我们看到它在女性、车费、年龄上的价值高,在 Pclass 上的价值低。而 neuron7 则向存活下来的神经元发出正(蓝色)信号。
同样,neuron8 在 Pclass 上的价值较高,在 Fare 上的价值较低,女性。这个神经元正在向存活下来的神经元发送一个负(红色)信号
所以我们可以做以下两行总结
女性乘客,支付高价,乘坐头等舱的乘客生还的可能性很高。
男性乘客,支付较低的票价,在二等或三等舱,生还的可能性较小
这太神奇了。这就像你身边有一个专家分析师,他会查看行和列,并试图理解数据的含义。感觉你是钢铁侠,深度学习是贾维斯,他在协助你进行所有的分析
这就是我们如何使用深度学习来分析表格数据的简要概述。还有很多其他有趣的方式。所以朋友们,让我们打破深度学习和图像数据集之间的这种紧密联系。
现在深度学习有了一个新朋友——表格数据集。
额外资源
网站(全球资讯网的主机站)
你可以访问我的网站进行零编码分析。【https://experiencedatascience.com
请订阅每当我发布一个新的故事时,请随时关注。
[## 每当 Pranay Dave 发表文章时,您都会收到电子邮件。
每当 Pranay Dave 发表文章时,您都会收到电子邮件。通过注册,您将创建一个中型帐户,如果您还没有…
pranay-dave9.medium.com](https://pranay-dave9.medium.com/subscribe)
你也可以通过我的推荐链接加入 Medium。
[## 通过我的推荐链接加入 Medium—Pranay Dave
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
pranay-dave9.medium.com](https://pranay-dave9.medium.com/membership)
Youtube 频道
这里是我的 Youtube 频道
https://www.youtube.com/c/DataScienceDemonstrated的链接
科学中的深度学习
对机会和趋势的调查
哥林多前书 10:23
“The AI revolution in science”, Science Mag, 2017
概述
在这篇文章中,我将调查将深度学习(DL)应用于科学和工程应用的机会。我将从对经验模型出现的展望开始,然后简要介绍神经网络的一些显著特征。主要的焦点将涵盖在各种科学领域中应用 DL 的新出现的一般趋势和问题类型。
实证模型的兴起
人类一直在建造东西。但直到最近,我们才开始设计极其复杂的东西:摩天大楼、商用飞机等。为了实现从岩石到工字钢的飞跃,我们建造了模型:简化的,简洁的,世界的代表。通过这种方式,我们可以构建复杂的东西,相信它们会按照我们想要的方式工作,因为我们已经预先对它们进行了建模。这些分析模型取得了巨大的成功:一些方程可以代表我们感兴趣的大多数现象,并允许我们操纵它们为我们所用。
然而,这些解析方程虽然简洁,却极难求解。在许多情况下,即使对于简单的现象,推导这些方程也需要人类多年的集中努力。例如,虽然几个世纪以来人们已经知道了钟摆运动和单透镜设计的近似解决方案,但是仅仅在过去的十年中,对于如此简单的问题( 1 , 2 )才获得了闭合形式的解决方案。相反,我们经常使用迭代的数值模型,这些模型通常基于迭代求解的偏微分方程,并慢慢地向某个答案收敛(尽管通常没有理论保证答案是正确的)。
Numerical Models
在过去的几十年里,另一种模型开始流行起来:经验模型。纯粹由数据驱动,它们的上升可归因于 3 个主要因素:分析/数值模型未能捕捉某些领域的现象,如生物学、心理学、经济学和医学;大量数据的快速增长;统计学和计算机科学的进步提高了这些模型的性能。
经验模型不同于它们的分析/数值模型,因为它们明确地对世界不做任何假设。相反,他们试图在数据中找到模式,简单地对呈现给他们的数据进行“曲线拟合”。这些差异带来了微妙的危险,因为不充分或有偏见的数据集将创建看似有效但无法准确捕捉现实的经验模型。事实上,经验模型永远不能真正代表现实,只是一种近似。我们用结果来证明经验模型的合理性,但我们永远不能仅仅因为它似乎有效就相信它。验证模型并在适当的上下文中使用它需要更深入的领域专业知识。
因此,这些实证模型的兴起是由软件和在线科技公司推动的就不足为奇了,因为整个行业都建立在收集数据的基础上。随着这些公司在范围和规模上的增长,他们引导新兴的人工智能领域专注于对他们来说重要的问题:推荐系统、图像分类、文本处理。然而,最近这种经验模型,特别是深度学习模型,在各个科学领域中的流行和使用已经爆炸。在接下来的章节中,我们将考察科学领域中数字逻辑的认识论模式。
为什么要深度学习?
深度学习是由许多层组成的神经网络的术语,显然是一种经验模型。但是为什么要深度学习呢?为什么不是另一个经验模型家族,比如在 90 年代被大量研究和描述的支持向量机?有几个原因可以解释为什么深度学习,从经验模型的大家庭中,已经上升到顶端并统治了这个领域。
之前,我讨论了经验模型出现的驱动因素之一是数据的快速增长。但是隐含的假设是更多的数据意味着更好的性能。事实证明,这并不总是正确的。
模型性能和数据之间的关系取决于模型容量(模型可以逼近的函数族)和模型偏差(模型对基础数据做出的先验假设)。例如,线性回归具有非常高的模型偏差,因为它假设基础数据是近似线性的,这限制了它的模型容量。相反,神经网络可以逼近任何实函数(通过通用逼近定理)。根据经验,我们发现神经网络在大型数据集上的伸缩性非常好(尽管神经网络仍然稀疏的理论依据,见这里和这里)。需要注意的是,深度学习的优势只在非常大的数据集上。在“小数据”领域中,不清楚哪种模型类型更好,为了让模型表现良好,您很可能必须使用某种形式的领域专业知识和特性工程。
Model Performance with respect to Dataset Size
神经网络的另一个重要特征是它们能够接受原始的、非结构化的数据作为输入。这种数据类型包括图像、音频、视频等。人们可以很容易地想象,今天网上的大多数数据都是这种非结构化的形式,只有通过大量的人工努力,这些数据才能转换成机器可读的形式。在这些领域,人类专家确定相关特征,将数据塑造成设计矩阵,并提供经验模型。但是神经网络可以接受原始数据,并在没有任何人类指导的情况下,自己学习它们的相关特征!我们将在后面看到,这种接受非结构化数据的能力也允许多种多样的神经架构,从而开启了广泛的潜在应用。
科学中的深度学习
三大支柱
建模有 3 个主要支柱:数据、计算和算法。计算通常不是科学应用的限制因素——事实上,深度学习经常被使用,因为与需要求解偏耦合微分方程的数值方法相比,它的计算效率非常高。按需云计算的兴起(以及专用硬件的增长趋势)意味着计算也非常便宜。这也有助于科学数据集通常比在线应用程序使用的大规模数据集(数百万到数十亿个示例)小得多(数百到数千个示例),这意味着需要的计算资源少得多。最后,学习理论和推理模型的改进,如深度学习本身,导致了标准化架构的创建,这些架构工作良好,可以开箱即用,例如 Keras 中的简单 CNN。
这些支柱隐含着重心:利用所有三个支柱的专业知识。遗憾的是,DL 在很多非计算机科学的研究群体中扎根还需要相当长的时间。一个强大的驱动因素是存在严重的市场失衡:科技公司(几乎每个行业)都渴望获得自己的内部 DL 专业知识,可以支付比传统学术路线高得多的费用。
然而,这种情况正在慢慢改变,因为许多职业科学家开始在职业生涯中期改变关注点,而且随着对 DL 的兴趣日益增长,理解 DL 的学生数量慢慢增加,尽管从大学挖走专门研究人工智能的教授的竞争激烈。深度学习开源框架(如 Tensorflow 和 Pytorch)的爆炸式增长,通过 Coursera、EdX 等大规模开放在线课程(MOOC)甚至 Medium 等资源(如 TDS 团队)的在线学习增长,都有助于人工智能领域真正的开源在线教育。大型科技公司意识到需要帮助外部培养人才,如谷歌开发人员的 ML 速成班和微软的人工智能学校,也起到了帮助作用。所有这些因素都导致了数字图书馆慢慢进入科学应用。
“数据是可防御的屏障,而不是算法”——吴恩达
描述不同领域的数字图书馆采用率
限制因素,尤其是在科学应用中,是数据。这就是为什么对经验模型最有经验的领域(如生物信息学、基因组学、高能物理学)也是拥有最多开源大规模数据集的领域。相反,最容易被深度学习颠覆的领域是那些目前缺乏清晰的标准化开源基准数据集,并且难以获得大量高质量数据的领域(例如,工业设计的机械属性,纳米材料属性,保险和医疗保健)。传统开源基准数据集,如 ImageNet、Cifar-10、Youtube 10M 等。有助于推动深度学习架构的基本创新——对于特定领域的数据集,可以预期类似的效果。
数据的结构也很重要。例如,对乳房 x 光照片中的恶性和良性肿瘤进行分类很容易转化为图像分类或分割问题。反过来,如何预测化学分子和物种的属性更困难——我们如何以一种模型可以理解的方式来表示这些分子?一个化学计量公式就够了吗?是否应该包括晶体群,合成条件,量子力学描述等。?确定如何将分子“指纹化”以传入机器学习模型是一个更加困难的问题,这比简单地传入矩阵需要更多的领域专业知识。深度学习在每个领域的采用率将受到数据可以被表示为传统数据结构的难易程度的影响,但反过来,这也代表了开发新模型的机会,这些模型可以在复杂的领域特定数据中进行本机读取。影响采用的其他因素包括从数值模型中获取数据的难度以及此类数值模型的可信度,缺乏领域专业知识的机器学习专家的准入门槛有多高,等等。
早期采用深度学习的领域的另一个标志是,他们优先考虑推理而不是解释,认为一些不确定性是可以接受的,并接受偶尔出错。如果我们的目标是优化材料设计或加速物理模拟,我们可能不会关心我们是如何实现的,甚至不会关心答案是否有一点错误,只要它足够接近并且比我们之前拥有的更好。但如果我们控制和设计国家电网,或提供医疗诊断,那么我们可能会更加谨慎。机器学习特别适合回答某些类型的问题,而不太适合回答其他类型的问题:理解不同科学领域的问题规范和设计约束将缓和经验模型所发挥的作用,并可能为新的模型公式开辟机会。
最后,“后采用者”领域的一个特殊特征是它们有孤立的数据。私人患者数据和电网数据就是很好的例子。在这些领域中,第一步是鼓励就如何开发现实且可公开的基准数据集进行对话,以便该领域开展工作并跟踪进展。大规模、开源、基准数据集非常重要,因为它们推动该领域在公共数据集上以开放的方式开发新的方法,加速创新和知识共享。建立数据匿名、数据共享和数据报告的约定也很重要。联合学习的新发展是开发算法保证以确保安全、隐私优先的数据共享的重要的第一步。在数据高度孤岛化的领域,人们还应该预料到,拥有数据访问特权的群体将比没有数据访问特权的群体拥有更大的优势。
如您所见,在检查不同科学领域的数字图书馆采用率时,要考虑的最重要的特征之一是数据。特别是,数量、多样性和我所说的“可采纳性”,即数据对 DL 架构的服从程度,是至关重要的因素。随着各种学科的科学数据爆炸式增长,许多领域目前正在经历所谓的 ImageNet 时刻。
深度学习和科学哲学
深度学习已经展示了惊人的自主学习功能的能力,并且在某些情况下,摧毁了某些领域几十年的专家工作。这可能自然会导致一些担忧,即深度学习可能会使科学家的工作自动化。至少在不久的将来,这是不可能的,原因有几个。首先,深度学习不是解释性的,科学(可以说)是一门机械学科。深度学习可以作为发展理论的辅助手段,但它本身还不能发展任何想法。其次,深度学习的许多进步都是为了增强或改善收集或可视化数据的能力,但解释这一科学方法中最重要的部分仍然是人类的领域。最后,深度学习迄今为止一直是网络技术人员的领域;谷歌、脸书等公司面临的问题推动了数字图书馆的发展。科学问题与科技公司面临的问题有不同的成功标准、数据类型和问题。将需要新颖的架构和方法来满足这些需求,并且它们将需要由那些真正理解潜在问题的人来精心制作。事实上,制作考虑物理约束的神经网络模型,例如通过损失函数定制,是一个不断发展的研究领域。
或许最适用的建议是:跟随数据。如果你有将深度学习应用于特定领域的专业知识,那么就寻找能够让你获得大量数据的合作者。相反,如果你坐在计算资源或大型未使用的数据集上,寻找在深度学习方面有良好记录的人,甚至更好,鼓励这些领域的内部培训。您也可以创建自己的数据!挖掘旧实验室笔记本、研究论文,甚至花几周时间生成自己的数据,都是利用实验室资产的独特方式。最优秀的研究团队将在深度学习这一特定科学领域积累内部专业知识,并获得稳定的新数据。
Data Science requires domain expertise
理科 DL 通用问题模板
基于我将 DL 应用于各种科学应用的经验,我注意到许多问题描述都属于类似的模板。我概述了这些案例研究中常见的几个通用问题模板。每个模板中包括几个遵循该模板的已出版作品。如果你有一个符合这些模板之一的科学问题,那么它不仅最有可能被深度学习破坏,而且已经存在一套众所周知和充分理解的技术可以采用。
**拟合和优化:**我们要么得到 1)现有的非常慢的数值模型,例如有限元法、流体动力学、粒子物理碰撞模拟器等。或者 2)不能用传统方法(例如基因组学)表征的非常大的数据集。我们的任务是一个连续的两步过程。首先,我们希望能够创建一个能够很好地表示数值模型或底层数据集的模型。这是一个标准的监督学习问题,我们应用深度学习来加快现有的数值方法,或者理解极其复杂的数据,并根据给定的数据进行推理。通常,我们的问题的自然下一步是优化一些成本函数,这可以通过数值求解器(如梯度下降或进化算法)或生成模型来完成。生成模型很好,因为只需要构建一个模型,而不是同时构建一个推理模型和一个优化器。这也可以被视为一个逆向设计问题,其中一次性学习是可取的。
这是我在工作中观察到的最常见的问题模板。任何时候你想为一些期望的属性找到最佳的设计,这个模板是合适的。虽然最终目标是一次性的逆向设计,但拟合和优化是目前研究得最多的范式,因为代理 DL 模型可以很容易地取代计算昂贵的数值模型。谷歌的 DeepMind 团队使用神经网络进行推理和梯度下降进行优化的组合来预测蛋白质折叠构型,并使用 AlphaFold 模型击败了其他团队的表现。刘等人。艾尔。使用神经网络进行纳米光子学的逆向设计,使用两步训练程序找到具有给定透射光谱的纳米结构。在这项工作中,逆向设计是在没有拟合和优化框架的情况下完成的,但使用了聪明的神经网络架构和训练程序,展示了 DL 专业知识和技术如何改进传统的代理模型思想。
作为拟合和优化的子集,也有一些情况下,我们只想加速数值模型,例如密度泛函计算 ns、多尺度物理模型、混沌系统等。,以加速不同理论的模拟或加速理论预测来验证实验数据。
**去噪:**我们给出了一个要测量的系统,但是物理测量结果由所需信号和噪声组成,很多时候,从我们的测量结果中消除噪声是一个难题。也有可能我们正在校准我们的测量设备,或者理解测量对人类来说太难了(例如超光谱数据)。在任何情况下,都需要有一个既定的、真实的、金标准的案例来与传统的测量方法进行比较。对于这个问题,有三个主要部分需要考虑:什么是噪声数据,什么是去噪数据,以及如何获得去噪数据作为标签;如何提出问题,即有监督的、无监督的、半监督的;以及如何衡量去噪性能。一个类似的场景是,当我们得到两个不同的数值模型/模拟时,其中一个是快速且不准确的,而另一个是缓慢且准确的,我们希望拥有后者的准确性和前者的速度。
例如,Schawinski 等人。艾尔。在瑞士联邦理工学院,苏黎世使用甘斯去噪星系图像。为了训练 GAN,他们使用了人工退化的图像,并表明 GAN 能够比传统技术更好地恢复原始图像。他们混合使用了几种传统和新技术来测量去噪性能。在相反的长度尺度上,瑞文森等人。艾尔。使用全卷积神经网络(CNN)自动编码器型架构来恢复仅强度细胞测量的相位。为了获得一个“黄金标准”的真相标签,他们使用了 8 个不同样本到传感器高度的测量值来恢复相位,并用作 CNN 的标签。更一般地说,CNN 用于恢复以前需要多次测量才能获得的信号的一部分。
Actor-Models: 我们有一个与其环境交互的代理,我们希望这个代理学习一些策略来最大化一些成本函数,例如控制商业 HVAC 系统,调节电网能源供应,用显微镜跟踪移动的生物样本等。在许多情况下,这样的问题实际上可以被转化为先前的问题模板之一,例如,预测不久的将来的值和基于领域专业知识应用已知的分析策略、对样本去噪而不是学习更好的策略等。由于这种强化学习(RL)类型的问题比监督学习困难得多,所以结合基于我们对系统的理解开发的简单启发式策略使用推理模型通常是有意义的,因为这种系统中的不确定性较少。问题结构严重影响问题的难度以及所用模型的类型——对于这种参与者-模型类型的问题,通常更简单的方法是将这些问题转化为更简单的问题模板,例如回归/分类。
作为将政策问题转化为回归问题的一个例子,艾尔。使用深度学习在活细胞显微术中自动聚焦显微镜。然而,他们没有使用非常复杂的 RL 方法,而是简单地使用 CNN 来预测给定输入图像的正确显微镜参数。这样的 CNN 可以用于每几秒钟更新一次显微镜焦点,而不需要 RL。令人印象深刻的是,这样一个模型比一组人类实验者显示出更少的差异。
魏等人也将 RL 应用于暖通空调系统。艾尔。最大限度降低建筑用电成本。建筑物 HVAC 被建模为马尔可夫决策过程(MDP)和用于 Q 值估计的神经网络。与基于规则的模型相比,RL 算法表现出显著的成本节约。事实上, RL 目前是一种快速发展的电网建模方法,它通常结合使用 MDP、Q-learning 和传统的电力系统经济/物理模型,以最大限度地减少能源使用和经济成本。
“传统 DL 问题”与科学问题的重要区别
上述模板提供了科学问题和传统深度学习问题类型之间的有用映射,并有助于识别文献中关于哪些问题容易转化为经验建模方法的当前趋势。然而,强调深度学习问题的传统开发(通常由互联网公司推动)和科学领域的开发之间的差异也很重要。
也许最明显的区别是科学领域处理的数据集要小得多。获取数据通常受到计算或进行高通量实验的能力的限制。数据一般不会简单地漂浮在虚无缥缈的互联网上,随时可以被抓取;它必须使用昂贵的计算机生成或使用可重复的实验记录。虽然现代 DL 研究通常专注于如何帮助超大型模型在更大的数据集上学习,例如罗伯塔,但我们需要对样本高效模型进行更多研究。
令人欣慰的是,我们也更加了解我们的投入和目标之间的关系。人类几个世纪以来的知识没有白费!在许多情况下,我们知道输入和输出之间关系的特定约束,或者输出的特定形式,例如能量守恒,在多输出模型中加强元素之间的已知关系。主要的困难是如何在模型本身中有效地传达或编码我们的先验知识,这本身就是一个重要而活跃的研究子领域。
许多从事“传统”深度学习问题的科学家和工程师,无论是在工业界还是在学术界,都经常抱怨神经网络的训练和推理时间太长。但对于科学界来说,深度学习作为一种随机训练模型,比传统的迭代、数值模型(如有限元、密度泛函理论等)快很多个数量级。还需要注意的是,神经网络的推理和训练时间在未来只会减少,因为 NVIDIA 和 Intel 等公司在创建专用硬件以加速神经网络操作(如矩阵累加)方面投入了大量精力。传统的数值方法肯定不是这样,在大多数情况下,传统的数值方法将运行时优化推到了最大可能,这是几十年来人们投入精力寻找更有效、科学合理的算法的结果。
我计划继续更新传统 DL 问题和科学问题之间的差异列表。希望这将作为 DL 进步和科学需求不匹配的领域的指南,并有助于激励针对科学需求的 DL 研究的进一步研究。
新的前进方向
深度学习领域目前被科技行业的担忧所主导:他们大量投资计算基础设施的能力,拥有大型专有数据集,最重要的是,吸引人才的巨额资金,已经将科学界的担忧边缘化。令人惊讶的是,G oogle 在 NeurIPS 2018 上发表了最多的论文,并且在论文数量排名前十的机构中,有 3 家是盈利性公司。此外,在社交媒体互动的大规模数据集上训练的非常成功的模型的使用导致了对隐私、偏见、道德以及这种技术对我们民主的影响的越来越多的担忧。
但与我们在新闻中看到的相反,除了搜索推荐、新闻提要算法和面部识别之外,人工智能还有其他用途。我们可以使用人工智能来加速科学模拟,以发现新材料来对抗不断增加的碳排放,改善药物输送和癌症治疗,并更好地了解我们周围的世界。有许多重要的人工智能用例缺乏许多(但不是全部)科技行业追求科学进步的棘手和道德模糊的问题。
要做到这一点,需要新一代的双语科学家,他们精通科学和机器学习。事实上,这种需求已经在某些领域得到了认可,比如高能物理。关于人工智能和人工智能有许多浮夸的说法——但可以毫不夸张地说,深度学习已经彻底改变了我们做科学的方式。但这首先需要科学家熟练使用这种新工具。
结论
深度学习系统在玩棋盘游戏、驾驶汽车和识别图像方面表现出的类似人类的能力产生了令人难以置信的兴奋。但这些进步是由基于网络的科技公司推动的,这些公司对与其收入流相关的特定问题子集感兴趣。深度学习有大量的机会应用于科学和工程中更基本的问题。利用深度学习,我们可以提高对宇宙中星系的理解,翻译基因组序列,并为一个不断进化(更热)的世界确定下一代材料。我的希望是,随着我们教育第一代深度学习科学家,也许他们中的一些人可能会决定使用他们独特的技能来更好地了解他们周围的自然世界。
我最近开始了一个关于机器学习和人工智能在科学领域和工程问题中的应用的免费通讯(ml4sci)。你可以在ml4sci.substack.com上找到。请随意发表建议的文章或主题,如果你真的喜欢你所看到的,请订阅!
太空中的深度学习
人工智能和机器学习如何支持航天器对接。
Magellan space probe meant to map the surface of Venus, simulated in orbit around earth using Unity (credits and info at the end).
人工智能无处不在。家电、汽车、娱乐系统,凡是你能想到的,它们都在包装人工智能能力。航天工业也不例外。
在过去的几个月里,我一直在开发一个机器学习应用程序,通过简单的摄像头视频来帮助卫星对接。如果你想知道深度学习、神经网络和 Tensorflow 对卫星对接有多有用,请继续阅读。
在这篇博文中,我将向你介绍我学到的方法、工作原理、结果和教训。我一点也不想挑战物体识别的技术水平。但是,当追溯我的脚步时,我意识到我学到了很多。因此,我希望我的故事对你有用,并激励你创建自己的机器学习应用程序。
如果你想跳过阅读直接进入代码,GitHub 上什么都有:https://github.com/nevers/space-dl
请注意,这篇文章假设读者熟悉张量流、卷积神经网络(CNN)的基本原理以及如何使用反向传播来训练它们。
信用
- 非常感谢 Rani Pinchuk 的支持,无数次的讨论,由此产生的见解以及花费在繁琐的标注所有训练数据上的时间。
- OS-SIM 设施的训练和评估图像由 DLR 提供。
- 麦哲伦太空探测器,由 Xavier Martinez Gonzalez 使用 Unity 模拟。
索引
Intermezzo——张量流估值器与人工抽象。
数据集准备
知道卫星的详细尺寸,目标是创建一种算法,可以准确预测其姿态和与相机的相对距离。这个项目的数据集是从安装在德国航天中心 OS-SIM 设施的机械臂上的卫星实物模型中创建的。手臂模拟各种动作,同时摄像机记录视频。
The satellite mockup captured by the video camera on the robotic arm. Source: OSM-SIM facility DLR.
我决定集中精力寻找卫星的尖端。如果我能准确地定位它,我相信我可以对模型上的至少两个其他标签做同样的事情。(卫星的“尖端”实际上是其对接机构的一部分。)给定这 3 个(或更多)点和卫星的 3D 模型,然后我可以重建卫星的姿态和相对于相机的相对位置。
相机记录了 14,424 张未标记的图像,我想用它们来训练和评估一个神经网络。我的一个担忧是,我将不得不花很长时间在每张图片上手动标注小费。幸运的是,我了解到 OpenCV 的优秀图像标记工具: CVAT 。
使用 CVAT 你可以批量导入所有你想要添加注释的图像,将它们作为电影播放,并插入相隔许多帧的注释。它还允许在多人之间分割工作,它甚至有一个很好的 docker-compose 文件,允许你点击一个按钮来运行它。
CVAT 节省了大量的时间和工作:只花了几个小时就在 14,424 张图片上标注了提示。(其实这个工作我不能拿的功劳。)对于卫星的线性运动,我们只需标注开始和结束位置,CVAT 将在它们之间插入并添加所有标签。如果你需要视频或图像注释工具,强烈推荐 CVAT。
Annotating the tip of the satellite using boxes in OpenCV’s CVAT.
然而,有一些改进的机会,或者更确切地说,是我希望拥有的功能。例如,CVAT 不支持点之间的插值。作为一个变通办法,所有的注释都必须用方框来代替点。(框的左上角坐标用于匹配笔尖的位置。)此外,任何未加注释的帧,即提示不可见的帧,都不包括在 XML 输出中。
XML output from CVAT after annotating the images.
为了使这个 XML 文件适合于训练和评估模型,必须对它进行后处理,使其成为正确的格式。有趣的是:这个看似琐碎的任务,实际上需要相当多的迭代才能完成。我经常不得不回去修改标签、添加新标签、更新输出格式等等。对我来说,这是一个教训。
将原始数据和注释转换成适合训练和评估的数据集的代码是代码库的重要组成部分。它不仅仅是一堆晦涩难懂的一次性终端命令。你应该尊重它,因为它是剧本的一部分,允许你重现你的结果和你的文档。对你的代码进行版本化,审查它,对你的数据集版本使用语义版本化,最重要的是,通过压缩数据集并提供下载,使其他处理相同问题的人能够容易地使用数据集。
一旦我有了数据集构建脚本的基线,同事们就能够重用它并分享他们的更改。我已经在我们公司引入了 Nexus ,我们现在使用它来分发来自 Java、Python 和 Docker 的所有代码工件,包括数据集等等。
数据集构建脚本还允许对不同版本的数据集进行快速实验:
- 应用数据增强:旋转,模糊,锐化。
- 尝试不同的培训和评估方法。
- 将数据定制为适合您的模型的表示形式。
- 将数据转换和打包成合适的格式。
这最后一点值得多加注意。因为我使用的是 Tensorflow ,所以我想使用 TFRecords 数据格式。不仅仅是因为它很好地集成到了 TF Dataset API 中,更重要的是因为我认为这种二进制数据格式从磁盘读取会更有效。下面是我如何使用 Python 多重处理将图像和标签转换成 TFRecords 文件的代码摘录。(我想使用多线程,但是……在 Python-land 中,线程并不酷,而且 GIL 也这么说。)
Convert images and labels to a TFRecords file using multi-processing in Python.
在创建了 TFRecords 文件之后,我创建了这个脚本来测试和比较从 TFRecords 文件中读取 13,198 个训练图像与简单地从磁盘中读取每个图像并动态解码它们所花费的时间。令人惊讶的是,TFRecords 数据格式并没有真正提高读取训练数据集的速度。下面的时序输出显示,从 TFRecords 文件中顺序读取比从磁盘中读取每个图像并即时解码要慢*。差别很小,但我肯定 TFRecords 会更快。*
如果您真的想提高数据导入管道的性能,可以考虑并行处理和数据的预取。通过在解析数据集时简单地设置TF . data . dataset . map num _ parallel _ calls参数,从 TFRecords 文件中并行读取这些完全相同的图像要比顺序读取快 2 倍。从磁盘上读取每张图片并即时解码甚至比 T8 快 3 倍。然而,在并行示例中,读取 TFRecords 文件几乎比动态读取图像慢 2 倍。又不是我所期待的。如果有人可以指出这个问题并分享他们与 TFRecords 的经历,我会很高兴。
最后,结合并行解析和预取使我能够消除训练期间的任何 CPU 瓶颈,并将平均 GPU 利用率从 75%提高到 95%以上,这是用 nvidia-smi 命令测量的。
以下是脚本在我的旧 2011 iMac(2.7 GHz 英特尔酷睿 i5)上运行时的时序输出:
13198 幅图像的顺序解析:
- TFRecords 数据集:50.13s
- 普通 PNG 文件数据集:49.46 秒
并行解析 13198 幅图像:
- TFRecords 数据集:26.78s
- 普通 PNG 文件数据集:15.96 秒
示范原则
最近,我在Coursera 上完成了吴恩达的深度学习专精。(Ng 的发音有点像《歌》结尾的 n 音。)这五门课程涵盖了深度学习和神经网络的核心概念,包括卷积网络、RNNs、LSTM、Adam、Dropout、BatchNorm、Xavier/He 初始化等等。该课程还详细介绍了医疗保健、自动驾驶、手语阅读、音乐生成和自然语言处理的实际案例研究。除了安德鲁惊人的成绩之外,他还是一位伟大的老师,我必须说这是一次美妙的经历。我可以向任何想进入深度学习的人推荐这门课程。
在涵盖卷积神经网络的第四门课程中,他对使用 YOLO 算法的物体检测做了精彩的解释(你只看一次)。该算法执行实时对象检测,如下图所示。
Object detection using YOLO. Source: https://pjreddie.com/darknet/yolo/
“YOLO 是最有效的对象检测算法之一,它包含了整个计算机视觉文献中与对象检测相关的许多最佳想法。”— 吴恩达
就这样,我忍不住实现了我自己的算法的天真版本。我不会在这篇文章中解释最初 YOLO 论文的全部工作原理和细节,因为有太多优秀的博客文章都是这么做的。(像这个举个例子。)相反,我将着重于我如何使用 YOLO 来解决我的具体本地化问题。
物体分割、检测和定位。
物体分割、检测和定位是有区别的。对象分割的目的是找到各种形状的片段,这些片段给出图像中要检测的对象的轮廓的逐像素描述。对象检测是在给定图像中的一个或多个对象周围找到矩形边界框的过程。目标定位是寻找一个或多个目标的位置。
Object segmentation, detection and localization from left to right.
该算法的主要原理很简单:获取输入图像并应用大量的卷积层,每个卷积层都有自己的一组滤波器。每组卷积层都会降低图像的特征空间或分辨率。请记住,卷积保持空间局部性,因为每一层都有与其相邻层的局部连接模式。因此,输出层中的每个元素代表输入处原始图像的一小块区域。每个卷积步长的滤波器可以从 64 到 1024 或者甚至 4096 变化。然而,在最终的输出层中,过滤器的数量减少到 3 个。换句话说,输出层有 3 个通道,每个通道将被训练为针对图像中特定区域的不同目的而激活:
- 通道 1 —预测位:表示在 0 和 1 之间卫星提示出现在图像的该区域中的机会。
- 通道 2-相对 X 位置:尖端的垂直位置(如果可用),相对于该区域的左上原点。
- 通道 3 —相对 Y 位置:与通道 2 相同,但不同。
看看下面的图片,这是我试图描绘的概念。
The input image in the top layer is dimensionally reduced to the output layer at the bottom (omitting the convolutional layers in between). The grey lines between the input and output layer show how each neuron along the depth dimension (or per channel) is dedicated to a specific region of the image. Per region, the output volume predicts whether a tip is visible and its X and Y coordinate relative to the origin of that region. In an ideal scenario, a prediction would have all elements set to zero except for the highlighted volume where the tip is visible.
在我的算法的第一个天真的版本中,我没有花很多时间来找出解决我的问题的完美的 CNN 模型架构。相反,我想专注于代码中允许我训练和评估模型的部分。因此,我简单地实现了与最初 YOLO 论文中的架构图相同的模型布局(如下)。
YOLO v1 CNN model (source: https://arxiv.org/pdf/1506.02640.pdf)
这就是我简单的头脑如何将这些层解释成代码。
My naive interpretation of the Yolo v1 model.
我很高兴我没有在模型上花太多时间,因为建立损失函数和训练/评估需要花费更多的时间。此外,现在有太多优秀的模特,很难被击败。例如,看看 Tensorflow Hub ,或者看看在 Keras 提供的模型。出于这个原因,我并不太关心模型的性能。相反,我的主要目标是让算法的所有活动部分都工作起来:输入端的数据集管道、可训练模型、损失函数和评估指标。
损失函数
为了计算损耗,我的第一步是将所有标签(基本上是卫星尖端的 x,y 位置)转换成输出体积,如上图所示。这是我想出来的。或者,如果您喜欢跳过大部分代码,只需查看脚本第 20 行的简单示例。
Code excerpt that parses a given label (i.e. the x and y position of the tip of the satellite) into a volume similar to the output of the model.
下一步是将给定的解析标签与模型的输出进行比较,并设置允许梯度下降以优化模型参数的损失函数。我尝试了许多替代方案,摆弄着均方误差和均方对数误差。最后,我决定使用交叉熵损失(如果你愿意,也可以使用对数损失),因为它对于概率值在 0 到 1 之间的分类任务特别有效,比如预测损失。
损失函数本身是两部分的加权和:
- 预测损失:模型预测输出体积中每个盒子是否有卫星提示的程度。我给这个预测损失的权重是 5,因为它是获得正确预测的主要因素。
- XY-loss:如果盒子里有尖端,模型预测尖端位置的准确性如何。如果图中没有可用的提示,损失函数的这一部分应该为零,这样只有预测损失决定最终损失。我给这个预测损失的权重是 1。
看看下面实现这个损失函数的代码。这样,我就可以使用 Adam 优化器来训练模型了,万岁!
The loss function of the model.
事后想来,写这个的时候,我意识到这个损失函数还是可以改进很多的。如果图像中有一个尖端,则为输出体积中的每个框计算 XY 损耗。这意味着 XY 损耗也被考虑到所有没有可见尖端的盒子中,这不是我想要的。因此,XY-loss 主要被训练来探测背景,而不是卫星提示…哎呀。此外,XY 损失不像预测损失那样是一项分类任务。因此,使用均方误差或类似策略来计算可能更好。有趣的是:这个损失函数表现很好。所以,这实际上是个好消息:它可以表现得更好:)
迁移学习
一旦我有了模型和损失函数,运行和训练正常,我想把我对 YOLO 模型的天真解释换成一个经过战斗考验和预先训练的版本。因为我只有有限的数据集,所以我假设需要迁移学习来解决这个问题。
一种选择是简单地从 Tensorflow Hub 中挑选一个模型。然而,TensorFlow 使得使用这些模型太容易了,我想走一条更具挑战性的路线,这样我可以学到更多。我决定使用原作者的最新版本的 YOLO 模型,因为它是为暗网编写的,我想了解如何将该模型导入 Tensorflow。
当我开始研究最新的 YOLO 模型定义时,我很快意识到我需要解析定义文件中的每一个部分并将其映射到正确的 Tensorflow 层。也许我应该对我的愿望更加小心,因为这是一项乏味又费时的工作。幸运的是,我找到了这个将 YOLO 模型定义转换成 Keras 模型的脚本,我可以使用 Tensorflow 加载它。
迁移学习是指重用在不同但相似的数据集上预先训练的现有模型的部分层权重,并仅重新训练剩余的层。一旦我加载了所有的 252 个模型层,我必须弄清楚哪些层(及其相关权重)我想要保持不变,哪些层我想要重新训练以及它们的每个维度。为此,我编写了一个简短的脚本,将 Keras 模型绘制成图像并从给定的图层列表中计算尺寸。
使用这个脚本,我可以简单地预览整个模型布局,包括所有的图层名称。然后,我在模型的正中间手动选择了一个图层:“add_19”。在我的实现中,使用 layer.trainable 属性,前半部分的所有层的权重保持不变,后半部分的所有层的权重被重新训练。模型中的最后一层是“conv2d_75 ”,它有 255 个通道。我添加了一个额外的卷积层,内核/过滤器大小为 3,以减少模型输出并使其符合我的最终目标。
Loading the YOLO model in Keras, enabling transfer learning and matching the output layer dimensionality to match the labels and loss function.
结果
首先,让我们看看迁移学习是如何影响结果的。看看下面的图片。重用 YOLO 模式的前半部分,重新训练后半部分,会产生巨大的不同。事实上,结果是无可比拟的。没有迁移学习,损失函数停滞在 80 左右,而有了迁移学习,损失函数立即下降到几乎为零。
Model loss function output per training step. The dark blue line shows the loss without transfer learning or simply a randomly initialized model. The light blue line shows the loss when half of the model reuses weights from the YOLO model.
下图显示了不使用迁移学习时的模型输出。请注意,该模型能够过滤掉背景并专注于提示,但永远无法做出准确的预测。
Model prediction output when not using transfer learning. Each output volume of the model is shown as a semi-transparent box with a color that ranges from (very transparent) blue (indicating a low chance of a tip present in that box) to green and then to red (indicating a high chance).
The model prediction output visualized for the same image over 42 training epochs when not using transfer learning. Notice how the model learns how to filter out the background, but never succeeds into narrowing down on the tip.
这是整个评估数据集的样子,仍然没有迁移学习。
Video animation of the model predictions for the evaluation data without transfer learning.
然而,这是在启用迁移学习的情况下,整个评估数据集的情况。
Video animation of the model predictions for the evaluation data using transfer learning.
很明显,迁移学习对结果有着巨大的影响。因此,本文的其余部分和结果假设迁移学习是启用的。
除了损失函数的输出,模型的性能以 4 种方式测量:
- metrics/dist_mean: 对于模型正确预测存在吸头的所有样本,从预测到标签的平均距离是多少(以像素为单位)。
- accuracy/point_mean: 对于模型正确预测存在吸头的所有样本,这些样本中距离标记吸头 10 个像素以内的样本所占的百分比。
- accuracy/prob_mean: 模型预测小费存在的准确程度。即预测位必须高于 0.5。
- ***准确性/总体均值:*正确预测样本的百分比。即,如果没有尖端,模型也预测同样的情况,并且如果有尖端,它在离标签 10 个像素之内。
以下是对 2885 个样本的评估数据集进行约 8 个小时的模型训练后得出的评估结果。
- ***度量/距离 _ 平均值:*1.352 像素
- 准确率/点均值: 98.2%
- 准确率/概率均值: 98.7%
- 准确率/总体均值: 98.7%
下面你可以在 Tensorboard 上看到这些数字随时间的变化。简单来说,算法平均差一个像素。
**
Four evaluation metrics and the loss function calculated after every training epoch during a training period of 8 hours.
在 2885 个评估样本中,有 32 张图片的预测是错误的。当我看着它们的时候,有 28 张图片的尖端位置被相当精确地探测到了,但是这个模型根本就没有足够的信心说有一个尖端。即,预测器比特没有超过 0.5,但是选择了正确的盒子。这里有一个例子。
The model predicts the tip within 10px but the confidence level is just below 0.5 and therefore it is marked as an erroneous prediction. It’s so close to 0.5 that when rounding the predictor bit, it yields exactly 0.50.
剩下的四个负面预测更有意思。它们大多被贴错了标签,或者至少是模棱两可的。当尖端隐藏在物体后面,但人类仍然容易定位时,一些图像被不一致地标记。这正是模型所捕捉到的。下面显示了两个示例:尖端隐藏在对象后面,并被标记为没有可见的尖端。而模型预测存在尖端并且在正确的位置。
**
Examples of a negative prediction where the tip of the satellite is hidden behind an object. These images are labeled as not having a visible tip (hence the label -1, -1), whilst the model is still able to predict a correct position.
intermezzo——张量流估值器与人工抽象。
Tensorflow 包括评估器,以保护开发人员免受样板代码的影响,并将他们的代码引导到一个可以轻松扩展到多台机器的结构中。我总是使用评估者,并假设我对他们的忠诚会得到高效率、干净代码和免费特性的回报。在 Tensorflow 1.12 中,这些假设的一部分是正确的,但我仍然决定创建自己的抽象。下面我解释一下原因。
为了确保一致性,每次您调用 estimator 时,estimator 都会从磁盘重新加载模型。{train(),predict(),evaluate()}。(train_and_evaluate 方法只是一个调用 estimator.train 和 estimator.evaluate 的循环)如果您有一个大模型(这很常见),并且您希望在同一台机器上交错训练和评估,重新加载模型确实会减慢训练过程。
评估人员重新加载模型的原因是为了确保分布模型时的一致性。这是他们背后设计理念的很大一部分,但正如你可以在这里读到的,经济放缓确实会导致挫折。此外,并不是每个人都需要也没有闲心拥有一大群 GPU,或者更重要的是,有时间让他们的模型并发,因为这需要仔细的(重新)设计和努力。Tensorflow 确实有一个 InMemoryEvaluatorHook 来克服这个问题。我试过了,效果不错,但感觉更像是一种变通办法,而不是真正的解决办法。
此外,当我尝试从估计器模型函数中加载我的 Keras 模型时,我花了一些时间才意识到必须在每次训练或评估调用后手动清除 Keras 模型。真尴尬。
这些东西并不是真正的亮点,但加上学习 Tensorflow 如何工作的冲动,它们足以说服我创建自己的微抽象。
随着 Tensorflow 2.0 的出现,我相信大部分我纠结的事情都会迎刃而解。Keras 将被集成到 Tensorflow 的核心,并成为其主要接口之一。估值器仍然是首选。如果你想了解更多关于 Tensorflow 2.0 的信息,请查看这个博客和这个视频。
惨痛的教训
我不敢相信我在做这个的时候犯了多少错误。有些很傻,很容易得到,但有些真的很难发现。以下是我学到的一些可能对你有用的经验:
- 双重、三重和四重检查你的评估/培训指标的语义、解释和正确性。例如,我的模型从一开始就获得了 100%的准确率。这并不是因为模型超级准确,而是因为这个指标只考虑了那些模型正确预测有小费的样本。如果 10000 个样本中只有 5 个样本检测到正确的 tip,100%的准确性仍然意味着在 10px 内只检测到 5 个图像。
- 特别是 tf.metrics API 不止一次愚弄了我。明智地使用 tf.metrics。它们用于评估,即汇总多个批处理操作和整个评估数据集的结果。确保在适当的时候重置它们的状态。
- 如果在 Tensorflow 中使用批量定额,不要忘记在训练期间更新移动平均值和方差。这些更新操作自动存储在 tf 中。UPDATE_OPS 集合,所以不要忘记运行它们。
Two code examples on how to update moving mean and variance when performing batch norm in Tensorflow.
- 编写单元测试作为一个健康检查,或者至少将您快速和肮脏的测试脚本保存到一个单独的文件中,以供以后参考。彻底测试损失函数尤其有意义。
- 每次训练模型时,请确保所有输出指标和其他数据都保存在一个唯一的、带有时间标签的目录中。此外,存储 git 标签(例如 heads/master-0-g5936b9e)。这样,无论何时你搞乱了模型,它都会帮助你恢复到以前的工作版本。
Example code on how to write the git description to a file.
- 将您的指标写入 Tensorboard,用于培训和评估。这是非常值得的,因为可视化让你对你的工作表现有了深入的了解。这有一些挑战,但反过来你可以更快地迭代和测试你的想法。
- 在 TensorBoard 中跟踪所有可训练变量,以帮助您尽早发现爆炸或消失的梯度。这里有一些如何做到这一点的灵感。
Example code on how to visualize the mean value and a histogram for each trainable variables in the model and an overall histogram for all trainable variables.
- 尝试自动并定期暂停训练过程以评估模型。确保在 Tensorboard 中将训练曲线和评估曲线渲染到同一个图形中。这样,您就可以可视化模型在训练过程中从未见过的数据上的性能,并在发现问题时立即停止。请注意,您不能通过简单地重用同一个标签在同一个图中显示多个汇总。Tensorboard 将通过在标签名称中添加“_1”来自动使这些摘要具有唯一性,从而强制它们显示在单独的绘图中。如果您想解决这个限制,您可以自己生成总结协议缓冲区,然后手动将它们添加到总结中。FileWriter()。有点尴尬,但很管用。
Example on how to save a metric with the tag “metrics/loss” during evaluation whilst, during training, a metric with the very same tag was used. This allows having both the training and evaluation curves shown on the same graph in Tensorboard.
- 监控 GPU 利用率和内存消耗,并尝试获得尽可能高的 GPU 利用率。如果你使用 NVIDIA 显卡,你可以使用 nvidia-smi 命令来完成。您还可以使用 htop 监控 CPU 和内存消耗。
五金器具
- NVIDIA Geforce RTX2080TI (11GB,4352 个 Cuda 内核,600 瓦,INNO3D 游戏 OC X3)
- 超微 X9DRG-QF 双 CPU 主板
- 2 枚英特尔至强 E5–2630(12 核)
- 三星 860 EVO SD(500 克)
- 128 克内存
结论和下一步措施
当我开始写这篇文章的时候,我的目标是一个简短但内容丰富的信息。我一点也不知道,这将是这样一个怪物的职位,很抱歉。这个项目让我接触了监督学习算法的许多方面,这可能解释了它的大小。
利用给定的评估数据,该模型能够在 98%的时间内精确定位卫星的尖端,误差为一个像素。我对这些结果很满意。然而,如果我想将这款车型投入生产,我还有很多事情要做。当前的数据集太有限,无法训练一个鲁棒的模型:图像彼此非常相似,并且只覆盖了少量不同的姿态。由于我没有机会获得更多的数据,一位同事决定帮助并使用 unity 渲染卫星图像。这篇文章顶部的麦哲伦太空探测器的图片就是这个数据集的一个例子。我意识到这不会产生一个现实的模型,但它将允许我继续我的学习过程。
此外,仅识别卫星的一个点不足以精确计算相对于观测相机的姿态和距离。理论上,必须跟踪至少 3 个点,而在实践中,该模型应该预测更多的点以获得可靠的输出。
您已经完成了这篇文章,感谢您的阅读!我希望它能激励你从事自己的人工智能项目和挑战。
深度学习在威斯康星州乳腺癌诊断中的应用
面向医疗保健的深度学习方法
1.介绍
机器学习方法长期以来一直用于医疗诊断[1]。威斯康星州乳腺癌数据库(WBCD)数据集[2]已被广泛用于研究实验。
大多数出版物集中于传统的机器学习方法,如决策树和基于决策树的集成方法[5]。
最近有监督的深度学习方法开始受到关注。例如,Stahl [3]和 Geekette [4]将这种方法应用于 WBCD 数据集[2],使用从乳腺肿块的细针抽吸(FNA)的数字化图像计算的特征值进行乳腺癌诊断。这些特征描述了图像中出现的细胞核的特征。
Stahl [3]使用了具有衍生特征(例如,平均值、标准误差等)的 WBCD 数据集。)并实验了三种深度神经元网络:1、2、3 个隐层 30 个神经元,没有任何数据预处理。Geekette [4]只使用了最初识别的具有中心和尺度等预处理的特征,但没有提供数据预处理或使用的神经元网络架构的详细信息。
本文提出了一种新的监督深度学习模型,用于使用公共开源库分析相同的 WBCD 数据集[2]进行乳腺癌诊断。新的监督深度学习模型继承了 Stahl [3]和 Geekette [4]实验的方法的优点。具体来说,与[4]类似,新方法使用最初识别的特征[2],使用中心和尺度对数据进行预处理,并将乳腺癌诊断问题视为 2 类分类问题。与[3]一样,新方法采用多个(三个)隐层的深层神经元网络。
1.1 问题陈述
给定从来自患者的乳房肿块的 FNA 的数字化图像计算的特征(即,特征向量)的列表(详见 2.1 节),问题是如何诊断(确定)患者是否患有乳腺癌。
类似于 Stahl [3]和 Geekette [4]的实践,在本文中,该问题被视为 2 类(B- 良性、 M- 恶性)分类问题。
解决这种分类问题的策略是利用一种新的深度学习模型,该模型具有多个隐藏和丢弃层(详见 2.3 节)。新的深度学习模型的输入是从 FNA 的数字化图像计算的特征值,并且来自该模型的输出是两个识别的分类诊断类别 B 或 m
1.2 指标
与 Geekette [4]采用的评估方法类似,预测准确性被用作本文中的主要评估指标。
具体来说, Keras 二进制准确性指标 API 用于计算 WBCD 诊断二进制分类问题的所有预测的平均准确率,如下所示:
平均准确率= ( m / n ) * 100%
其中 n 为测试样本总数, m 为匹配测试用标记响应的预测总数。
2.分析
本节首先探索和分析数据集,以确定数据预处理需求,然后描述深度学习模型和相关技术。
2.1 探索数据
本文中使用的数据集是公共的 [WBCD 数据集](https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast- cancer-wisconsin.data)【2】。如 WBCD 数据集[1]中所述,为每个细胞核计算了以下特征,并将用作新的深度学习模型的输入:
- 团块厚度
- 细胞大小的均匀性
- 细胞形状的均匀性
- 边缘粘连
- 单一上皮细胞大小
- 裸核
- 平淡的染色质
- 正常核仁
- 有丝分裂
以下代码用于获取数据集的统计摘要:
import pandas as pdheaders = ["ID","CT","UCSize","UCShape","MA","SECSize","BN","BC","NN","Mitoses","Diagnosis"]
data = pd.read_csv('breast-cancer-wisconsin.csv', na_values='?',
header=None, index_col=['ID'], names = headers)
data = data.reset_index(drop=True)
data = data.fillna(0)
data.describe()
观察到数据集存在以下问题:
- 缺失数据
- 小数据集大小
- 各种范围的数据值
- 不平衡数据
- 扭曲的数据
数据集的一个常见问题是缺少数据,WBCD 数据集也不例外。具体来说,如表 1 所示,有 16 个裸核条目缺失(标记为?在原始 WBCD 数据集中)。
WBCD 数据集[2]仅包含 699 个样本,在将数据集划分为训练和测试子集后,对于深度学习来说太小了。
不同特征的特征值范围是不同的。平均特征值从大约 1.5 变化到 4.5(关于特征值的各种范围的可视化,参见第 2.2 节)。
不同标签的数据样本总数不平衡。事实上,标记为 B 的数据样本总数(458)几乎是标记为 M 的数据样本总数(241)的两倍(参见第 2.2 节了解这些数字的可视化)。
与数据集相关的另一个常见问题是偏斜度(详见第 2.2 节)。
第 2.2 节提供了这些数据集问题的可视化,第 3.1 节描述了这些数据集问题的解决方案。
2.2 可视化数据
本节通过数据可视化展示了第 2.1 节中描述的一些数据集问题。
图 1 使用以下代码显示了不同特性的各种平均值范围:
import seaborn as sns
data_mean = data.describe().loc['mean']
data_mean.plot(kind='bar', figsize=(14,6))
为了直观显示不平衡的数据集问题,图 2 使用以下代码显示了标记为 B 和 M 的样本总数:
data_B = data[data['Diagnosis'] == 2]
data_M = data[data['Diagnosis'] == 4]
B_M_data = {'B': [data_B.shape[0]], 'M': [data_M.shape[0]]}
B_M_df = pd.DataFrame(data=B_M_data)
B_M_df.plot(kind='bar', figsize=(10,4))
为了直观显示数据偏斜问题,图 3 显示了数据预处理后 Pandas 生成的数据集散点图矩阵(详情见第 3.1 节):
diagnosis = data['Diagnosis']
features = data.drop(['Diagnosis'], axis = 1)
pd.plotting.scatter_matrix(features, alpha = 0.3, figsize = (14,8), diagonal = 'kde');
从图中可以看出,数据集明显向右倾斜。
2.3 深度学习模型
如前所述,在本文中,乳腺癌诊断问题被视为 2 类(良性或恶性)分类问题。
一种新的监督深度学习模型用于分类。新的深度学习模型的架构如图 4 所示。
这种新的监督深度学习模型继承了 Stahl [3]和 Geekette [4]实验的方法的优点。
具体来说,与[4]类似,新方法使用最初识别的特征[2],使用中心和尺度对数据进行预处理(详见 3.1 节),并将乳腺癌诊断问题视为 2 类(良性或恶性)分类问题。
与[3]一样,新方法采用多个(三个)隐层的深层神经元网络。
此外,数据集的不平衡和偏斜问题也作为数据预处理的一部分进行处理。
如图 4 所示,新的深度学习模型的输入是从 FNA 的数字化图像计算的特征值,模型的输出是两个识别的分类诊断类 B ( 良性)或 M ( 恶性)。
第一个隐层用 9 个神经元,最后一个隐层用 1 个神经元分别匹配输入特征数和输出类别数。中间的隐藏层的大小(5 个神经元)是第一个和最后一个隐藏层的大小的中间。
此外,在隐藏层之间引入了辍学率为 50%的脱落层,以避免过拟合,并潜在地提高新的深度学习模型在准确性方面的性能。
公共整流线性单元(ReLU)激活功能 relu 用于隐藏层 1 和 2。广泛使用的 sigmoid 激活函数被用在最终隐藏层 3 中,以产生(0,1)范围内的连续输出。阈值 0.5 固有地用于从连续输出产生二进制诊断输出。
以下损失函数、优化器和度量函数用于训练新的深度学习网络模型:
- **损失函数:**二元交叉熵
- 优化器功能: Adam(自适应力矩估计)
- **度量函数:**准确度
选择二元交叉熵损失函数是因为 WBCD 分类是二元分类问题。
选择精度而不是二进制精度度量函数是因为精度度量函数支持模型定型中的精度历史,但二进制精度度量函数不支持。
选择 Adam 优化器函数是因为它是用于训练深度学习模型的随机梯度下降(SGD)的替代优化算法。
关于新的深度学习网络架构的更多信息在第 3.2 节中提供。
2.4 基准
新的监督深度学习模型的结果将与应用具有默认设置的随机森林分类器[6]的开源 scikit-learn 开箱即用实现的结果进行比较,以测量相对性能(详细信息请参见第 3 部分)。
3.方法学
在这一节中,首先描述数据预处理的方法,然后提供端到端的实现细节。
3.1 数据预处理
在本文中,丢失的数据条目简单地用 0 替换,原因如下。缺失条目的数量(总共 16 个)相对较小,因此用 0 替换它们不会对数据集的统计数据模式产生显著影响。
如 2.1 节所述,具有不同标签的数据样本的总数是不平衡的。这种不平衡的数据问题通过生成标记为 M 的新数据样本来解决。具体而言,通过向标记为 M 的现有数据样本引入正态分布随机噪声,标记为 M 的 241 个数据样本的集合被加倍(482)。如图 5 所示,标记为 M 的所得新数据样本集合与标记为 b 的数据样本集合相当平衡
如 2.1 节所述,原始数据集仅包含 699 个样本。本文通过生成如下新数据样本解决了这个小数据量问题。
首先,从标记为 M 的数据样本中分离标记为 B 的数据样本。然后,通过引入正态分布随机噪声,将标记为 M 的数据样本集加倍。最后,类似于扩展标记为 M 的数据样本集,通过引入正态分布随机噪声,新的组合数据集加倍。
通过使用 Numpy 随机数生成库Numpy . random . normal(mean,sigma,features.shap e)生成与给定数据集具有相同特征维数的正态分布随机数的数组来实现噪声生成,其中表示 = 0,标准差 sigma = 0.1。之后,将生成的随机数数组逐个元素地添加到给定的数据集中,以形成新的数据集。
WBCD 数据集[2]中最后一列“诊断/类别”中的值在本文中用作训练新深度学习模型的标签。通过将新生成的特征值阵列与来自给定数据集的“诊断/类别”列组合成新的数据集,这些标签被重新用来标记新生成的数据集中的相应样本(特征向量)。
数据集扩展后,最终的新数据集总共包含 1,880 个样本,用于模型训练和测试。
作为一种常见的做法,对于每个特征,特征值被缩放到[0,1]的范围内用于深度学习,如下所示:
(值-最小值 ) / ( 最大值-最小值)
通过对特征值求平方根来处理所识别的数据偏斜问题。这是通过 Numpy API 实现的,如下所示:
Value = Numpy.sqrt(Value)
图 6 显示了对数据集应用平方根变换的结果。
3.2 端到端实施
以下常见开源库用于实现数据预处理和新的深度学习模型:
- Numpy
- 熊猫
- scikit-lean
- 克拉斯
- matplotlib
本节的其余部分描述了具体的实现细节。
3.2.1 加载数据
作为实现的第一步,使用 Pandas API 加载数据集 csv 文件(有关代码,请参见 2.1 节)。
缺失数据问题在数据加载中分两步处理。首先是丢失的数据问号“?”换成了楠。然后那些 NaN 值用 0 填充。
3.2.2 增补数据
为了解决数据不平衡和小数据集大小的问题,给定一个数据集,定义以下函数,通过引入正态分布随机噪声来生成相同维数的新数据集。
def generateData(data1):
# make a copy of data
data2 = data1.copy()
# separate labels from features
diagnosis2 = data2['Diagnosis'] # labels
features2 = data2.drop(['Diagnosis'], axis = 1)
features2_headers =
["CT","UCSize","UCShape","MA","SECSize","BN","BC","NN","Mitoses"] mean, sigma = 0, 0.1
# creating a noise with the same dimension as the dataset
noise = np.random.normal(mean, sigma, features2.shape)
features2 = features2.apply(pd.to_numeric, errors='ignore')
features2_with_noise = features2.add(pd.DataFrame(noise, columns = features2_headers), fill_value=0)
data2 = pd.concat([features2_with_noise,
pd.DataFrame(diagnosis2)], axis = 1) return data2
上面的数据集生成函数被如下调用,以将新生成的数据集与给定的数据集组合。
new_data = generateData(data)
data = data.append(new_data, ignore_index=True)
3.2.3 缩放数据集
如前所述,不同特征的值具有不同的范围,并且这些值的大部分在[0,1]的范围之外。然而,新的深度学习模型要求输入值在[0,1]的范围内,以获得更好的性能。为此,数据集的值被缩放到[0,1]的范围内,如下所示:
from sklearn.preprocessing import MinMaxScalerscaler = MinMaxScaler()
numerical =["Diagnosis","CT","UCSize","UCShape","MA","SECSize","BN","BC","NN","Mitoses"]
data[numerical] = scaler.fit_transform(data[numerical])
3.2.4 处理数据集偏斜度
如前所述,数据集偏斜问题是通过将要素从标注中分离出来,然后仅对要素值应用平方根变换来处理的。这是通过以下方式实现的:
diagnosis = data[‘Diagnosis’]
features = data.drop([‘Diagnosis’], axis = 1)
sqrt_features = features.copy()
for feature_name in sqrt_features.columns:
sqrt_features[feature_name] =
np.sqrt(sqrt_features[feature_name])
features = pd.DataFrame(sqrt_features)
3.2.5 将数据集分割成训练和测试子集
如前所述,数据集分为两部分:75%用于模型训练,25%用于模型测试:
from sklearn.model_selection import train_test_split# Shuffle and split the data into training and testing subsets
X_train, X_test, y_train, y_test = train_test_split(features,
diagnosis, test_size=0.25, random_state=42)
3.2.6 重新格式化数据集
拆分数据集后,必须按如下方式重新索引生成的数据子集,以避免数据集键不匹配问题:
X_train = X_train.reset_index(drop=True)
X_test = X_test.reset_index(drop=True)
y_train = y_train.reset_index(drop=True)
y_test = y_test.reset_index(drop=True)
那么产生的 Pandas 数据帧必须转换成 Numpy 数组,如下所示,因为 Pandas 数据帧不受 Keras API 支持。
X_train = X_train.values
y_train = y_train.values
X_test = X_test.values
y_test = y_test.values
3.2.7 基准测试
随机森林分类器的 scikit-learn 开箱即用实现用于生成基准预测结果以进行比较,如下所示:
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
score = rfc.score(X_test, y_test)
3.2.8 实施新的深度学习模型
流行的开源 Keras 深度学习库[7]用于实现新的深度学习模型。首先,可以定义一个可重用的函数来创建新的模型实例:
from keras.layers import Dense
from keras.layers import Dropout
from keras.models import Sequential import keras
import keras.utils
from keras import utils as np_utilsdef createModel():
model = Sequential()
model.add(Dense(9, activation='relu', input_dim=9))
model.add(Dropout(0.5))
model.add(Dense(5, activation='relu', input_shape=(9,)))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid', input_shape=(5,))) model.compile(loss='binary_crossentropy', optimizer='Adam', metrics=['accuracy']) return model
模型训练执行如下:
model = createModel()
model.fit(X_train, y_train, epochs=500, batch_size=32)
此外,如下执行 10 重交叉验证,以验证新的深度学习模型的鲁棒性。
from sklearn.model_selection import StratifiedKFold # fix random seed for reproducibility
seed = 7
np.random.seed(seed)X = X_train
Y = y_train# define 10-fold cross validation test harness
kfold = StratifiedKFold(n_splits=10, shuffle=True,random_state=seed)
cvscores = []
for train, test in kfold.split(X, Y):
model = createModel()
model.fit(X[train], Y[train], epochs=500, batch_size=10,
verbose=0)
scores = model.evaluate(X[test], Y[test], verbose=0)
print("{}: {.2f}".format(model.metrics_names[1], scores[1]*100))
cvscores.append(scores[1] * 100)print("{.2f} (+/- {.2f})".format(np.mean(cvscores), np.std(cvscores)))
最后,按如下方式进行模型测试:
score = model.evaluate(X_test, y_test, batch_size=32)
GitHub [8]中有一个 Jupyter 笔记本,里面有本文中使用的所有源代码。
3.3 改进
本节将讨论不同模型超参数和优化器的准确性影响。
3.3.1 网络深度
本文使用了 1,880 个样本的相对较小的数据集。在这种情况下,使用最少三个隐藏层的深度学习网络是合适的,以获得最佳性能。
如下表所示,由于没有足够的数据来训练深度学习模型,因此使用三个以上的隐藏层会对精度性能产生负面影响。
3.3.2 辍学
理论上,添加辍学层应该有助于避免过度拟合,从而潜在地提高深度学习模型在准确性方面的性能。然而,根据实验结果,一旦时期的数量为 500 或更多,通过使用 50%速率的丢弃,没有获得显著的性能增益。
如下表所示,在使用退学率时,50%的退学率似乎是一个甜蜜点。例如,在所有其他配置参数固定的情况下,使用 30%的丢弃率产生大约 97.1428%的预测准确度,而使用 50%的丢弃率获得准确度为 97.7143%的预测性能。
3.3.3 批量
新的深度学习模型的精度性能对批量大小很敏感。如下表所示,批量大小为 16 似乎效果最好。
3.3.4 历元
实验结果表明,使用 500 个历元足以在有或没有丢失的情况下获得稳定的精度性能。可以减少时期的数量(例如,300)以获得稳定的性能而没有丢失。
3.3.5 优化器
如下表所示,Adam 优化器在准确性方面的性能最好。这并不奇怪,因为 Adam 是 SGD 的改进。
4.结果
该部分提供了模型评估和验证结果以及基准测试结果。
4.1 模型评估和验证结果
与[4]类似,数据集分为两部分:75%用于训练,其余 25%用于测试。
为了避免不平衡和小数据集大小的问题,本文通过引入正态分布随机噪声,将 699 个样本的原始数据集扩展为 1,880 个样本的新数据集。
如前所述,类似于 Geekette [4]实施的评估方法,预测精度被用作主要评估指标。
为了验证新的深度学习模型在小数据集变化的情况下的鲁棒性,使用 500 个时期和批量大小 16 执行了 10 倍交叉验证,以下是结果:
从上表可以看出,在数据集发生变化的情况下,新的深度学习模型的精度性能相当稳定。
4.2 基准测试结果
新的监督深度学习模型的预测准确性与应用具有默认设置的随机森林分类器的开源 scikit-learn 开箱即用实现[6]的结果进行比较,以测量相对性能。
下表显示了将 25%测试数据集应用于训练的随机森林分类器和训练的新深度学习模型的比较结果的汇总。
在上表中可以看出,新的深度学习模型的性能在准确性上与随机森林分类器具有竞争力。两者的预测准确率都达到了 97.4468%。
这种新的深度学习模型的性能超过了 Stahl [3]和 Geekette[4]报告的结果。
5.结论
本节总结了新的深度学习模型的实现结果以及未来可能的改进。
5.1 模型性能可视化
为了验证在将数据集分成两部分(即,75%用于模型训练,25%用于模型测试)的情况下新的监督深度学习模型的精度性能,图 7 示出了新模型在模型训练中的预测精度历史,图 8 示出了新模型在模型训练中的损失历史。
从这些图中可以看出,新模型的精度性能迅速增加并稳定到大约 90%,而损失历史下降并稳定到大约 0.25。
5.2 反射
本文提出了一种新的监督深度学习模型,用于 WBCD 数据集的分类[1][2](详见 2.3 节)。
还提出了一种新的数据生成方法,通过在现有数据样本中引入正态分布随机噪声,解决了不平衡数据集问题,并将 699 个样本的原始数据集扩展到 1,880 个样本的新数据集。
具有裸核特征的缺失数据条目被替换为零,然后数据值被缩放到[0,1]的范围内用于深度学习。通过对特征值求平方根,数据集的偏斜问题得到了显著缓解。
实验结果表明,通过使用深度学习(具有 3 个隐藏层)并在最终隐藏层中引入丢弃层和 Sigmoid 激活函数,新的深度学习模型在 WBCD 数据集的分类中与传统的随机森林分类器具有竞争力[1][2]。新的监督深度学习模型的性能是稳健的,并且优于 Stahl [3]和 Geekette[4]报告的性能结果。
新的深度学习模型是用 Python 实现的,使用了著名的开源库,如 Numpy、Pandas、scikit-learn、Keras、Matplotlib 等。Github [8]中提供了 Jupyter 笔记本的源代码。
5.3 改进
未来可能的改进之一是识别和实现自动化机制,以识别超参数的最佳组合,例如隐藏层的数量、每个隐藏层中的神经元数量、退出和退出率、激活函数、批量大小、时期等。
本文中的实验结果表明,在像 WSCD 数据集[1][2]这样的简单数据集的情况下,有时使用简单的机器学习模型比更高级的深度学习模型更好。
参考文献
- 乳腺癌威斯康星州(诊断)数据集
- WBCD 数据文件
- K.Stahl 、、威斯康星乳腺癌诊断深度学习、、2017 年 7 月 17 日
- D.Geekette,乳腺癌数据:机器学习&分析 ,2016 年 11 月 25 日
- C.Nguyen,Y. Wang,H. N. Nguyen,结合特征选择的随机森林分类器在乳腺癌诊断和预后中的应用,科学研究,第 6 卷第 5 期,2013 年 5 月
- [scikit-learn 随机森林分类器](http://scikit- learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html)
- Keras:Python 深度学习库
- Y.张 GitHub 中 Jupyter 笔记本源代码
披露声明:2019 首创一。观点是作者个人的观点。除非本帖中另有说明,否则 Capital One 不隶属于所提及的任何公司,也不被这些公司认可。使用或展示的所有商标和其他知识产权是其各自所有者的财产。