PaperSpace 博客中文翻译(二十四)

原文:PaperSpace Blog

协议:CC BY-NC-SA 4.0

如何用 Scikit-Learn 实现支持向量机

原文:https://blog.paperspace.com/implementing-support-vector-machine-in-python-using-sklearn/

在本教程中,我们将介绍:

  1. 支持向量机算法简介
  2. 使用 Python 和 Sklearn 实现 SVM

所以,让我们开始吧!

支持向量机简介

支持向量机(SVM)是一种监督机器学习算法,可用于分类和回归问题。SVM 即使在数据量有限的情况下也能表现得很好。

在这篇文章中,我们将专门学习支持向量机分类。让我们先来看看支持向量机算法的一些一般用例。

用例

**疾病分类:**例如,如果我们有关于患有糖尿病等疾病的患者的数据,我们可以预测新患者是否可能患有糖尿病。

**文本的分类:**首先我们需要将文本转换成向量表示。然后,我们可以将支持向量机算法应用于编码文本,以便将其分配到特定的类别。

**图像分类:**图像被转换成包含像素值的矢量,然后 SVM 分配一个类别标签。

现在让我们了解一些与 SVM 相关的关键术语。

关键术语

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

Source: Oscar Contreras Carrasco

支持向量:支持向量是距离超平面较近的数据点,如上图所示。使用支持向量,该算法最大化了类别之间的界限或间隔。如果支持向量改变,超平面的位置也将改变。

**超平面:**二维中的超平面简单来说就是一条最好地分隔数据的直线。这条线是类之间的判定边界,如上图所示。对于三维数据分布,超平面将是二维表面,而不是直线。

Margin: 这是每个支持向量之间的距离,如上图所示。该算法旨在最大化利润。寻找最大余量(以及最佳超平面)的问题是一个优化问题,可以通过优化技术来解决。

**内核:**内核是一种应用于数据点的函数,用于将原始非线性数据点映射到高维空间,在高维空间中它们是可分离的。在许多情况下,不会有一个线性的决策边界,这意味着没有一条直线将两个类别分开。内核解决了这个问题。有很多种内核函数可用。RBF(径向基函数)核通常用于分类问题。

理解了这些关键术语后,让我们开始研究数据。

探索性数据分析

首先,我们将导入所需的库。我们正在导入numpypandasmatplotlib。除此之外,我们还需要从sklearn.svm进口 SVM。

我们还将使用来自sklearn.model_selectiontrain_test_split,以及来自sklearn.metricsaccuracy_score。我们将使用matplotlib.pyplot进行可视化。

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt

一旦库被导入,我们需要从 CSV 文件读取数据到 Pandas 数据框。让我们检查前 10 行数据。

该数据是为潜在糖尿病患者检查的数据的集合。为简单起见,我们考虑两个特征年龄和血糖水平以及一个二元目标变量。值 1 表示糖尿病,0 表示没有糖尿病。

df = pd.read_csv('SVM-Classification-Data.csv')
df.head()

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

Support Vector Machine Classification Data

为了更好地了解数据,我们绘制了一个数据条形图,如下所示。条形图是一种用矩形条表示分类数据的图表,矩形条的高度代表它们所具有的值。条形图可以垂直或水平绘制。

下图是年龄和血糖栏之间的垂直图表。

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

Bar Chart

为了更好地了解异常值,我们也可以看看散点图。下面是数据中出现的特征的散点图。

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

探索完数据后,我们可能想做一些如下的数据预处理任务。

数据预处理:

在将数据输入支持向量分类模型之前,我们需要做一些预处理。

这里我们将创建两个变量 x 和 y。x 代表模型的特征,y 代表模型的标签。我们将创建 x 和 y 变量,方法是从数据集中取出它们,并使用 sklearn 的train_test_split函数将数据分成训练集和测试集。

x = df.drop('diabetes',axis=1)
y = df['diabetes']
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25, random_state=42)

请注意,测试大小为 0.25 表示我们使用了 25%的数据进行测试。random_state确保再现性。对于train_test_split的输出,我们得到x_trainx_testy_trainy_test的值。我们将使用 x_train 和 y_train 来训练模型,然后我们将一起使用 x_test 和 y_test 来测试模型。

数据预处理完成后,现在是定义和拟合模型的时候了。

定义并拟合模型

我们将创建一个model变量并实例化 SVC 类。在此之后,我们将训练模型,但在此之前,让我们讨论支持向量分类器模型的一些重要参数,如下所列。

内核 : kernel是指用于模式分析的算法类。这是一个字符串参数,是可选的。默认值是 RBF。常见的可能值有“线性”、“多边形”、“rbf”、“sigmoid”、“预计算”。

线性核是最常用的核之一。当数据是线性可分离的时使用,这意味着数据可以用一条线来分离。

当数据不是线性可分时,使用 RBF 核。支持向量机的 RBF 核创建给定特征的非线性组合,并将给定数据样本转换到更高维的特征空间,在该空间中,我们可以使用线性决策边界来分离类别。

正则化 C : C是一个正则化参数。正则化与 c 成反比,它必须是正的。

次数 : 次数是多项式核函数的次数。它被所有其他内核忽略,比如 linear。

Verbose*:这将启用详细输出。Verbose 是一个通用编程术语,用于生成大部分日志输出。Verbose 的意思是要求程序告诉所有关于它一直在做什么的事情。*

***Random _ State:*Random _ State 是随机数生成器使用的种子。这用于确保再现性。换句话说,为了在拟合期间获得确定性行为,random_state必须是固定的。

*`SupportVectorClassModel = SVC()
SupportVectorClassModel.fit(x_train,y_train)`*

在我们定义了上面的模型之后,我们需要使用给定的数据来训练模型。为此我们使用了如上图所示的fit()方法。该方法传递了两个参数,这是我们感兴趣的数据(在本例中,年龄和血糖以及数据集的 diebetes 训练部分)。

一旦模型被正确训练,它将输出 SVC 实例,如下面单元格的输出所示。

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

模型训练完成将自动引导您尝试一些预测。

使用模型预测

一旦模型经过训练,它就可以进行预测了。我们可以在模型上使用predict方法,并将x_test作为参数传递,以获得作为y_pred的输出。

请注意,预测输出是一个对应于输入数组的实数数组。

**`y_pred = SupportVectorClassModel.predict(x_test)`**

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

Support Vector Machine Prediction**

一旦预测完成,我们自然会测试模型的准确性。

评估模型

现在是时候检查我们的模型在测试数据上的表现了。为此,我们通过发现模型产生的准确性来评估我们的模型。

我们将使用 accuracy_score 函数,并将两个参数 y_test 和 y_pred 传递给该函数。

**`accuracy = accuracy_score(y_test,y_pred)*100
99.19678714859438`**

正如你在上面看到的,这个模型的精确度大约是 99.19%。

尾注

在本教程中,我们学习了什么是支持向量机算法及其使用案例。对于这个问题,我们还讨论了各种探索性的数据分析图,如条形图和散点图。

最后实现了支持向量分类算法并打印了预测结果。

我希望你喜欢这篇文章,如果需要的话,你可能会在将来的项目中使用它。

快乐学习!

通过迁移学习、数据扩充、LR Finder 等提高模型准确性

原文:https://blog.paperspace.com/improving-model-accuracy/

在处理由专家预先清理、测试、分割和处理的流行数据集时,很容易获得 90%以上的准确率。您只需要将数据集导入并提供给互联网上最流行的模型架构。

在影像分类中,当一个新数据集的某个类别中只有很少的影像,或者影像与您将在生产中处理的影像不相似时,事情会变得有点困难。流行的模型架构似乎没有帮助,迫使你陷入一个只有 50%准确率的角落,然后变成一个概率游戏,而不是机器学习本身。

本文重点探讨所有这些方法、工具以及更多内容,以帮助您构建健壮的模型,这些模型可以在生产中轻松部署。尽管其中一些方法也适用于其他目标,但我们将重点放在图像分类上来探讨这个主题。

为什么自定义数据集达不到高精度?

重要的是要说明为什么定制数据集在实现良好的性能指标方面最失败。当您尝试使用自己创建的数据集或从团队获得的数据集来创建模型时,可能会遇到这种情况。缺乏多样性可能是基于它的模型性能不佳的主要原因之一。图像的光照、颜色、形状等参数可能会有显著变化,在构建数据集时可能不会考虑这一点。数据增强可能会帮助您解决这个问题,我们将进一步讨论这个问题。

另一个原因可能是缺乏对每个类别的关注:一个数据集有一种咖啡的 1000 多张图像,而另一种只有 100 多张图像,这在可以学习的特征方面产生了很大的不平衡。另一个失败可能是数据收集的来源与生产中收集数据的来源不匹配。这种情况的一个很好的例子可以是从具有差的视频质量的安全摄像机中检测到鸟,该差的视频质量作为在高清晰度图像上训练的模型的输入。有各种方法可以处理这种情况。

为什么生产水平的准确性很重要?

既然我们已经讨论了为什么定制数据集在第一次运行时无法达到“生产级别的准确性”,那么理解为什么生产级别的准确性很重要。简而言之,我们的模型应该能够给出在现实场景中可以接受的结果,但不一定要达到 100%的准确性。使用测试数据集图像或文本很容易看到正确的预测,这些图像或文本用于将模型超调至最佳状态。尽管我们不能确定一个阈值精度,超过这个精度,我们的模型就有资格进行部署,但根据经验,如果训练和验证数据是随机分割的,那么至少有 85-90%的验证精度是很好的。始终确保验证数据是多样化的,并且其大部分数据与模型在生产中使用的数据相似。数据预处理可以通过在输入前调整大小或过滤文本来确保图像大小,从而在一定程度上帮助您实现这一点。在开发过程中处理此类错误有助于改进您的生产模式并获得更好的结果。

数据扩充:改善数据集的完美方式

只要你能通过数据扩充等方法充分利用数据集,拥有一个小数据集是没问题的。这个概念侧重于预处理现有数据,以便在我们没有足够数据的时候生成更多样化的数据用于训练。让我们用一个小例子来讨论一下图像数据增强。这里我们有一个来自 TensorFlow 的石头剪子布数据集,我们希望不重复生成更多。 Tensorflow 数据集对象提供了许多有助于数据扩充的操作,等等。这里我们首先缓存数据集,这有助于我们进行内存管理,因为数据集第一次迭代时,它的元素将被缓存在指定的文件或内存中。然后缓存的数据可以在以后使用。

之后我们重复数据集两次,这增加了它的基数。仅仅重复的数据对我们没有帮助,但是我们在加倍的数据集上添加了一个映射层,这在某种程度上帮助我们随着基数的增加生成新的数据。在这个例子中,我们将随机图像左右翻转,这避免了重复并确保了多样性。

import tensorflow as tf
import tensorflow_datasets as tfds

DATASET_NAME = 'rock_paper_scissors'

(dataset_train_raw, dataset_test_raw), dataset_info = tfds.load(
    name=DATASET_NAME,
    data_dir='tmp',
    with_info=True,
    as_supervised=True,
    split=[tfds.Split.TRAIN, tfds.Split.TEST],
)

def preprocess_img(image, label):
    # Make image color values to be float.
    image = tf.cast(image, tf.float32)
    # Make image color values to be in [0..1] range.
    image = image / 255.
    # Make sure that image has a right size
    image = tf.image.resize(image, [256,256])
    return image, label

dataset_train = dataset_train_raw.map(preprocess_img)
dataset_test = dataset_test_raw.map(preprocess_img)

print("Dataset Cardinality Before Augmentation: ",dataset_train.cardinality().numpy())

dataset_train = dataset_train.cache().repeat(2).map(
    lambda image, label: (tf.image.random_flip_left_right(image), label)
)

print("Dataset Cardinality After Augmentation: ",dataset_train.cardinality().numpy())

输出

Dataset Cardinality Before Augmentation:  2520
Dataset Cardinality After Augmentation:  5040

图像上有更多的映射可以探索,可以在对比度、旋转等方面进一步创造更多的变化。阅读这篇文章了解更多细节。您可以对图像执行更多操作,如旋转、剪切、改变对比度等等。在图像数据在照明、背景和其他方面不代表真实世界输入的情况下,数据扩充至关重要。在这里,我们讨论了通过 Tensorflow 等框架进行数据扩充,但是除了旋转和剪切之外,您还可以进行手动数据扩充。

Mapping 是一个强大的工具,因为您可以对单个数据执行任何操作,而无需经历迭代。调整图像大小、格式化文本等等都可以用它来灵活处理。

迁移学习:使用小数据集

有些情况下,您只有少量图像,并且希望构建一个图像分类模型。如果图像很少,模型可能无法学习模式和更多内容,这将导致模型过拟合或欠拟合,在现实世界输入的生产中表现不佳。在这种情况下,建立一个好模型最简单的方法就是通过迁移学习。

有像 VGG16 这样著名的预训练模型,确实很擅长图像分类。由于它在构建时所接触到的各种各样的数据,以及其体系结构的复杂性质(包括许多卷积神经网络),它在图像分类目标方面比我们可以用小数据集构建的小模型更有深度。我们可以使用这样的预训练模型,通过替换最后几层(在大多数情况下)来处理我们问题的相同目标。我们之所以替换最后一层,是为了重构适合我们用例的模型输出,在图像分类的情况下,选择合适的类别数进行分类。如果我们遵循相应的预训练模型架构的文档和围绕它的框架文档,我们不仅可以替换最后一层,还可以替换任意多的层。让我们建立一个样本迁移学习机器学习模型。

首先,我们正在加载和预处理我们之前使用的相同的石头剪刀布数据集。

import tensorflow as tf
import tensorflow_datasets as tfds
from tensorflow.keras.applications import ResNet50
from keras.layers import GlobalAveragePooling2D, Dense
from keras.layers import BatchNormalization, Dropout
from keras.models import Model

DATASET_NAME = 'rock_paper_scissors'

(dataset_train_raw, dataset_test_raw), dataset_info = tfds.load(
    name=DATASET_NAME,
    data_dir='tmp',
    with_info=True,
    as_supervised=True,
    split=[tfds.Split.TRAIN, tfds.Split.TEST],
)

def preprocess_img(image, label):
    # Make image color values to be float.
    image = tf.cast(image, tf.float32)
    # Make image color values to be in [0..1] range.
    image = image / 255.
    # Resize images to ensure same input size
    image = tf.image.resize(image, [256,256])
    return image, label

dataset_train = dataset_train_raw.map(preprocess_img)
dataset_test = dataset_test_raw.map(preprocess_img)

dataset_train = dataset_train.batch(64)
dataset_test = dataset_test.batch(32)

现在我们将使用 ResNet50 作为迁移学习模型。我们将设置training able = false来冻结 ResNet50 架构,不将其暴露于训练。这将为我们节省大量时间,因为模型将只训练最后几层。当我们按小时付费进行培训时,这是有益的。

# ResNet50 with Input shape of our Images
# Include Top is set to false to allow us to add more layers

res = ResNet50(weights ='imagenet', include_top = False, 
               input_shape = (256, 256, 3)) 

# Setting the trainable to false
res.trainable = False

x= res.output
x = GlobalAveragePooling2D()(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x) 
x = Dense(512, activation ='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(3, activation ='softmax')(x)
model = Model(res.input, x)

model.compile(optimizer ='Adam', 
              loss ="sparse_categorical_crossentropy", 
              metrics =["sparse_categorical_accuracy"])

model.summary()

简而言之

( Only the Bottom part of Model Summary Included here as the ResNet Summary is long)
_____________________________________________________________________________
conv5_block3_out (Activation)   (None, 8, 8, 2048)   0           conv5_block3_add[0][0]           
_____________________________________________________________________________
global_average_pooling2d_5 (Glo (None, 2048)         0           conv5_block3_out[0][0]           
_____________________________________________________________________________
batch_normalization_11 (BatchNo (None, 2048)         8192        global_average_pooling2d_5[0][0] 
_____________________________________________________________________________
dropout_11 (Dropout)            (None, 2048)         0           batch_normalization_11[0][0]     
_____________________________________________________________________________
dense_11 (Dense)                (None, 512)          1049088     dropout_11[0][0]                 
_____________________________________________________________________________
batch_normalization_12 (BatchNo (None, 512)          2048        dense_11[0][0]                   
_____________________________________________________________________________
dropout_12 (Dropout)            (None, 512)          0           batch_normalization_12[0][0]     
_____________________________________________________________________________
dense_12 (Dense)                (None, 3)            1539        dropout_12[0][0]                 
=============================================================================
Total params: 24,648,579
Trainable params: 1,055,747
Non-trainable params: 23,592,832

模特培训

model.fit(dataset_train, epochs=6, validation_data=dataset_test)
Epoch 1/10
40/40 [==============================] - 577s 14s/step - loss: 0.2584 - sparse_categorical_accuracy: 0.9147 - val_loss: 1.1330 - val_sparse_categorical_accuracy: 0.4220

Epoch 2/10
40/40 [==============================] - 571s 14s/step - loss: 0.0646 - sparse_categorical_accuracy: 0.9802 - val_loss: 0.8574 - val_sparse_categorical_accuracy: 0.4247

Epoch 3/10
40/40 [==============================] - 571s 14s/step - loss: 0.0524 - sparse_categorical_accuracy: 0.9813 - val_loss: 0.7408 - val_sparse_categorical_accuracy: 0.6425

Epoch 4/10
40/40 [==============================] - 570s 14s/step - loss: 0.0376 - sparse_categorical_accuracy: 0.9881 - val_loss: 0.6260 - val_sparse_categorical_accuracy: 0.7016

Epoch 5/10
40/40 [==============================] - 570s 14s/step - loss: 0.0358 - sparse_categorical_accuracy: 0.9881 - val_loss: 0.5864 - val_sparse_categorical_accuracy: 0.6532

Epoch 6/10
40/40 [==============================] - 570s 14s/step - loss: 0.0366 - sparse_categorical_accuracy: 0.9873 - val_loss: 0.4445 - val_sparse_categorical_accuracy: 0.8602

我们可以看到,在相对较小的数据集上训练的模型表现非常好,验证准确率为 86%。如果你关注每个时期所花费的时间,它不到 10 分钟,因为我们保持 ResNet 层不可训练。ResNet50 帮助我们把它的学习转移到我们的问题上。您可以尝试各种预先训练好的模型,看看它们如何适合您的问题,以及哪种模型性能最好。

LR Finder:寻找完美的学习速度

Learning Rate Finder 是一款功能强大的工具,顾名思义,可以帮助你轻松找到 LR。尝试所有的学习率来找到完美的学习率是一种低效且耗时的方法。LR Finder 是实现这一点的最高效、最省时的方法。我们来看看如何实现。我们继续使用相同的数据集、预处理和模型架构,因此从这里开始不再重复。

!pip install tensorflow-hub
!git clone https://github.com/beringresearch/lrfinder/
!cd lrfinder && python3 -m pip install .

import numpy as np
from lrfinder import LRFinder
K = tf.keras.backend

BATCH = 64

# STEPS_PER_EPOCH = np.ceil(len(train_data) / BATCH)
# here Cardinality or Length of Train dataset is 2520

STEPS_PER_EPOCH = np.ceil(2520 / BATCH)
lr_finder = LRFinder(model)
lr_finder.find(dataset_train, start_lr=1e-6, end_lr=1, epochs=10,
               steps_per_epoch=STEPS_PER_EPOCH)

learning_rates = lr_finder.get_learning_rates()
losses = lr_finder.get_losses()

best_lr = lr_finder.get_best_lr(sma=20)

# Setting it as our model's LR through Keras Backend
K.set_value(model.optimizer.lr, best_lr)
print(best_lr)
Epoch 1/10
40/40 [==============================] - 506s 13s/step - loss: 1.7503 - sparse_categorical_accuracy: 0.3639
Epoch 2/10
40/40 [==============================] - 499s 12s/step - loss: 1.5044 - sparse_categorical_accuracy: 0.4302
Epoch 3/10
40/40 [==============================] - 498s 12s/step - loss: 0.9737 - sparse_categorical_accuracy: 0.6163
Epoch 4/10
40/40 [==============================] - 495s 12s/step - loss: 0.4744 - sparse_categorical_accuracy: 0.8218
Epoch 5/10
40/40 [==============================] - 495s 12s/step - loss: 0.1946 - sparse_categorical_accuracy: 0.9313
Epoch 6/10
40/40 [==============================] - 495s 12s/step - loss: 0.1051 - sparse_categorical_accuracy: 0.9663
Epoch 7/10
40/40 [==============================] - 89s 2s/step - loss: 0.1114 - sparse_categorical_accuracy: 0.9576

我们得到的最佳学习率是 6.31 e-05,,我们使用 Keras 后端将它设置为我们的模型 LR。从输出来看,很明显,这个过程只花了几个时期,它分析了所有可能的学习率,并找到了最好的一个。我们可以使用 Matplotlib 可视化学习率及其性能。红线代表最佳学习率。

import matplotlib.pyplot as plt

def plot_loss(learning_rates, losses, n_skip_beginning=10, n_skip_end=5, x_scale='log'):
    f, ax = plt.subplots()
    ax.set_ylabel("loss")
    ax.set_xlabel("learning rate (log scale)")
    ax.plot(learning_rates[:-1],
            losses[:-1])
    ax.set_xscale(x_scale)
    return(ax)

axs = plot_loss(learning_rates, losses)
axs.axvline(x=lr_finder.get_best_lr(sma=20), c='r', linestyle='-.')

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

learning rate finder graph

提前停止:在你的模型忘记之前拯救它

你可能记得训练一个模型超过 20 个历元,模型的损失在一个点之后开始增加。你被卡住了,你什么也做不了,因为打断会扼杀这个过程,等待会给你一个表现更差的模型。在这种情况下,当损失等参数开始增加时,你可以轻松地获得最佳模型并逃离这个过程,尽早停止正是你想要的。这也将节省您的时间,如果模型开始显示早期的正损失,该过程将通过向您提供最后的最佳损失模型而停止,并且不计算进一步的时期。您也可以根据任何可以监控的参数(如精确度)设置提前停止。提前停车的主要参数之一是耐心。这是您希望看到模型是否停止显示增加的损失并回到学习轨道的次数,否则它将保存增加前的最后最佳损失并停止训练。现在你可能已经有了一个小想法,让我们来看一个例子。

from tensorflow.keras.callbacks import EarlyStopping

earlystop_callback = EarlyStopping(
  monitor='val_loss', min_delta=0.0001, patience=2)

model.fit(dataset_train, epochs=20, validation_data=dataset_test, callbacks=[earlystop_callback])

在本例中,提前停止被设置为监控验证损失。参数最小 delta ,即我们希望损失的最小差值,被设置为 0.0001,耐心被设置为 2。耐心为 2 意味着模型可以在验证损失增加的情况下再运行 2 个时期,但是如果它没有显示减少的损失,那么(低于从其开始增加的损失),该过程将通过返回最后的最佳损失版本而被终止。

( Only the last part of training shown )

Epoch 10/20
40/40 [==============================]  loss: 0.0881 - sparse_categorical_accuracy: 0.9710 - val_loss: 0.4059 
Epoch 11/20
40/40 [==============================]  loss: 0.0825 - sparse_categorical_accuracy: 0.9706 - val_loss: 0.4107 
Epoch 12/20
40/40 [==============================]  loss: 0.0758 - sparse_categorical_accuracy: 0.9770 - val_loss: 0.3681 
Epoch 13/20
40/40 [==============================]  loss: 0.0788 - sparse_categorical_accuracy: 0.9754 - val_loss: 0.3904 
Epoch 14/20
40/40 [==============================]  loss: 0.0726 - sparse_categorical_accuracy: 0.9770 - val_loss: 0.3169 
Epoch 15/20
40/40 [==============================]  loss: 0.0658 - sparse_categorical_accuracy: 0.9786 - val_loss: 0.3422 
Epoch 16/20
40/40 [==============================]  loss: 0.0619 - sparse_categorical_accuracy: 0.9817 - val_loss: 0.3233 

即使设置了 20 个时期来训练,模型也在第 16 个时期后停止训练,从而避免了模型因验证损失增加而遗忘。我们的训练结果有一些非常好的观察,可以帮助我们更深入地了解早期停止。在第 14 个纪元模型是在其最佳损失,0.3168。下一个时期显示了 0.3422 的增加的损失,即使下一个时期显示了 0.3233 的减少的损失,其小于前一个时期,其仍然大于从增加开始的点(0.3168),因此在保存第 14 个时期的模型版本时训练停止。它等待 2 个时期,以查看训练是否会因为耐心参数被设置为 2 而自我纠正。

另一个有趣的观察结果是从第 10 个时期到第 12 个时期,尽管在第 11 个时期损失增加了(0.4107),但是与第 10 个时期的损失(0.4059)相比,第 12 个时期的损失减少了(0.3681)。因此,随着模型回到正轨,训练仍在继续。这可以被看作是对耐心的一个很好的利用,因为让它默认会在第 11 个纪元后终止训练,而不是尝试下一个纪元。

使用早期停止的一些技巧是,如果你正在 CPU 上训练,使用小的耐心设置。如果在 GPU 上训练,使用更大的耐心值。对于甘这样的模型,不如用小耐心,省模型检查点。如果您的数据集不包含大的变化,那么使用更大的耐心。设置 min_delta 参数始终基于运行几个历元并检查验证损失,因为这将使您了解验证损失如何随着历元而变化。

分析您的模型架构

这是一个通用的方法,而不是一个确定的方法。在大多数情况下,例如涉及卷积神经网络的图像分类,非常重要的一点是,即使框架处理流程,您也要很好地了解您的卷积、它们的核大小、输出形状等等。像 ResNet 这样的非常深入的体系结构是为了在 256x256 大小的图像上进行训练而设计的,调整它的大小以适应数据集图像为 64x64 的情况可能会执行得很差,导致某些预训练模型的精度为 10%。这是因为预训练模型中的层数和您的图像大小。很明显,随着通道平行增加,图像张量通过卷积时在尺寸上变得更小。在 256x256 上训练的预训练模型最终将具有至少 8×8 的张量大小,而如果将它重构为 64×64,则最后几个卷积将获得 1×1 的张量,与 8×8 的输入相比,它学习得很少。这是在处理预训练模型时要小心处理的事情。

另一方面是当你建立自己的回旋。确保它有超过 3 层的深度,同时,考虑到你的图像尺寸,它也不会影响输出尺寸。分析模型摘要非常重要,因为您可以根据卷积层的输出形状等因素来决定密集层的设置。在处理多特性和多输出模型时,架构非常重要。在这种情况下,模型可视化会有所帮助。

结论

到目前为止,我们已经讨论了一些最有影响力和最受欢迎的方法,这些方法可以提高您的模型准确性、改善您的数据集以及优化您的模型架构。还有很多其他的方法等着你去探索。除此之外,还有更多次要的方法或指南可以帮助您实现上述所有方面,例如加载数据时的混排、使用 TensorFlow dataset 对象处理您自定义创建的数据集、使用我们之前讨论的映射来处理操作。我建议你在训练时注重验证准确性,而不是训练准确性。验证数据必须得到很好的处理,它的多样性和对模型在生产中将要接触到的真实世界输入的代表性是非常重要的。

尽管我们对一个图像分类问题使用了所有的方法,其中一些像映射、学习率查找器等等。适用于涉及文本和更多的其他问题。构建低于平均精度的模型在现实生活中没有价值,因为精度很重要,在这种情况下,这些方法可以帮助我们构建一个接近完美的模型,并考虑到所有方面。超参数调优是一种流行的方法,本文没有详细讨论。简而言之,就是尝试超参数的各种值,如时期、批量大小等。超参数调整的目的是获得最佳参数,最终得到更好的模型。LR 查找器是超参数调整学习速率的有效方法。在处理 SVR 等其他机器学习算法时,超参数调整起着至关重要的作用。

我希望您已经很好地了解了使用各种想法和方法来处理您的模型以实现更好的性能是多么重要,并为您未来的机器学习之旅尽善尽美。我希望这些方法对你有用。感谢阅读!

如何提高 YOLOv3

原文:https://blog.paperspace.com/improving-yolo/

YOLOv3 是一种流行的快速对象检测算法,但遗憾的是不如 RetinaNet 或更快的 RCNN 准确,你可以在下图中看到。在这篇文章中,我将讨论最近的对象检测文献中提出的两种简单而强大的方法来改进 YOLOv3。这些是:1) 用于对象检测的不同训练试探法,以及 2) 特征金字塔的自适应空间融合。我们将一个一个来看。让我们深入研究一下。

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

Source: YOLOv3 paper

用于对象检测的不同训练启发法

随着精细训练程序的使用,图像分类网络的性能有了很大的提高。关于这些训练技巧的简单讨论可以在这里找到来自 CPVR 2019。类似地,对于对象检测网络,一些人提出了不同的训练试探法(1),例如:

  • 保持几何对齐的图像混淆
  • 使用余弦学习率调度程序
  • 同步批处理规范化
  • 数据扩充
  • 标签平滑

这些修改将 YOLOv3 的 mAP@(.5:.9)分数从 33.0 提高到 37.0,而在推断期间没有任何额外的计算成本,并且在训练期间计算成本的增加可以忽略不计(1)。可以在这里找到经过预训练重量的改良 YOLOv3。为了理解这些启发背后的直觉,我们将一个一个地看它们。

图像 _ 混合

先说 mixup 训练。在图像分类网络中,图像混合只是两幅图像的像素的线性插值(例如下面的左图)。用于图像分类的混合算法中的混合比率的分布是从一个贝塔分布,B(0.2,0.2)中得出的,该分布也用于混合使用相同比率的独热图像标签。为了执行混合,两个图像必须具有相同的尺寸,因此它们通常被调整大小,然而这将需要图像中存在的对象的边界框也被调整大小。为了避免这种麻烦,使用了一种新的图像混合策略。它从两个图像中取出一个最大宽度和最大高度的图像,像素值等于 0 到 255,并向其添加两个图像的线性插值。对于这种混合策略,从β分布 B(1.5,1.5)获得混合比率,因为(1)发现对于对象检测,B(1.5,1.5)给出视觉上连贯的混合图像和经验上更好的地图分数。对象标签被合并为一个新数组。这将在下面演示。现在我们有一种混合方法用于图像分类,另一种用于物体检测。

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

Left: image classification mixup (source). Right: object detection mixup (source).

目标在训练图像中的自然同现在目标检测网络的性能中起着重要作用。例如,一个碗、一个杯子和一个冰箱应该比一个冰箱和一只大象更频繁地出现在一起。这使得在其典型环境之外检测物体变得困难。使用具有增加的混合比率的图像混合使得网络对于这种检测问题更加鲁棒。Mixup 还充当正则化器,并强制网络支持简单的线性行为。

def object_det_mix_up_(image1, image2, mixup_ratio):

    '''
    image1, image2: images to be mixed up, type=ndarray
    mixup_ratio: ratio in which two images are mixed up
    Returns a mixed-up image with new set of smoothed labels
    '''

    height = max(image1.shape[0], image2.shape[0])
    width = max(image1.shape[1], image2.shape[1])
    mix_img = np.zeros((height, width, 3),dtype=np.float32)
    mix_img[:image1.shape[0], :image1.shape[1], :] = image1.astype(np.float32)\
                                                     * mixup_ratio
    mix_img[:image2.shape[0], :image2.shape[1], :] += image2.astype(np.float32)\
                                                     * (1-mixup_ratio)
    return mix_img 

Image mixup code

学习率调度程序

大多数流行的对象检测网络(更快的 RCNN,YOLO 等。)使用学习率计划程序。根据(1),所产生的急剧学习速率转变可能导致优化器在接下来的迭代中重新稳定学习势头。使用带有适当预热(两个时期)的余弦调度器(学习率缓慢下降)可以比使用步进调度器提供更好的验证精度,如下所示。

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

Comparison of step scheduler vs cosine scheduler on the PASCAL VOC 2007 test set (source)

分类标题标签平滑

在标签平滑中,我们使用以下公式将我们的独热编码标签转换为平滑概率分布:

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

source

其中 K 为类数,ε为小常数,q 为地面真值分布。这通过降低模型的置信度来起到正则化的作用。

同步批处理规范化

在当前的深度卷积架构中,批量规范化被认为是一个重要的层。它负责加速训练过程,并通过标准化隐藏层的激活使网络对权重初始化不那么敏感。由于大的输入图像大小、特征金字塔架构的存在以及大量的候选对象提议(在多级网络的情况下),单个 GPU 上可以容纳的批量大小变得非常小(即,每批少于 8 个左右的图像)。

在分布式训练范例中,隐藏的激活在每个 GPU 内被规范化。这会导致计算有噪声的均值和方差估计,从而阻碍整个批量标准化过程。同步批处理标准化因此被建议通过考虑多个 GPU 上的激活来帮助增加批处理大小,以便计算统计估计值。因此,这使得计算的噪声更小。

使用 NVIDIA 的 Apex 库在 PyTorch 中进行混合精度和分布式训练,可以轻松实现同步批量标准化。我们还可以使用convert_syncbn_model方法将 PyTorch 中的任何标准BatchNorm模块转换为SyncBatchNorm,该方法递归遍历传递的模块及其子模块,用apex.parallel.SyncBatchNorm替换torch.nn.modules.batchnorm._BatchNorm的所有实例,其中apex.parallel.SyncBatchNorm是 PyTorch 模块,用于在 NVIDIA GPUs 上执行同步批处理规范。

import apex
sync_bn_model = apex.parallel.convert_syncbn_model(model) 

Converting standard batch normalization to synchronized batch normalization in PyTorch using Apex

数据扩充

数据增强技术似乎也改进了目标检测模型,尽管它们对单级检测器的改进大于多级检测器。根据(1),这背后的原因是在像 fast-RCNN 这样的多级检测器中,从大量生成的 ROI 中采样一定数量的候选对象提议,通过重复裁剪特征图上的相应区域来产生检测结果。由于这种裁剪操作,多阶段模型代替了随机裁剪输入图像的操作,因此这些网络不需要在训练阶段应用大量的几何放大。

根据经验,像随机裁剪(带约束)、扩展、水平浮动、调整大小(带随机插值)和颜色抖动(包括亮度、色调、饱和度和对比度)这样的增强方法在训练期间效果更好。在测试过程中,通过随机选择一种流行的插值技术来调整图像的大小,然后进行归一化。

def horizontal_flip(image, boxes):
	''' 
    Flips the image and its bounding boxes horizontally
    '''

    _, width, _ = image.shape
    if random.randrange(2):
        image = image[:, ::-1]
        boxes = boxes.copy()
        boxes[:, 0::2] = width - boxes[:, 2::-2]
    return image, boxes

def random_crop(image, boxes, labels, ratios = None):
	''' 
    Performs random crop on image and its bounding boxes 
    '''

    height, width, _ = image.shape

    if len(boxes)== 0:
        return image, boxes, labels, ratios

    while True:
        mode = random.choice((
            None,
            (0.1, None),
            (0.3, None),
            (0.5, None),
            (0.7, None),
            (0.9, None),
            (None, None),
        ))

        if mode is None:
            return image, boxes, labels, ratios

        min_iou, max_iou = mode
        if min_iou is None:
            min_iou = float('-inf')
        if max_iou is None:
            max_iou = float('inf')

        for _ in range(50):
            scale = random.uniform(0.3,1.)
            min_ratio = max(0.5, scale*scale)
            max_ratio = min(2, 1\. / scale / scale)
            ratio = math.sqrt(random.uniform(min_ratio, max_ratio))
            w = int(scale * ratio * width)
            h = int((scale / ratio) * height)

            l = random.randrange(width - w)
            t = random.randrange(height - h)
            roi = np.array((l, t, l + w, t + h))

            iou = matrix_iou(boxes, roi[np.newaxis])

            if not (min_iou <= iou.min() and iou.max() <= max_iou):
                continue

            image_t = image[roi[1]:roi[3], roi[0]:roi[2]]

            centers = (boxes[:, :2] + boxes[:, 2:]) / 2
            mask = np.logical_and(roi[:2] < centers, centers < roi[2:]) \
                     .all(axis=1)
            boxes_t = boxes[mask].copy()
            labels_t = labels[mask].copy()
            if ratios is not None:
                ratios_t = ratios[mask].copy()
            else:
                ratios_t=None

            if len(boxes_t) == 0:
                continue

            boxes_t[:, :2] = np.maximum(boxes_t[:, :2], roi[:2])
            boxes_t[:, :2] -= roi[:2]
            boxes_t[:, 2:] = np.minimum(boxes_t[:, 2:], roi[2:])
            boxes_t[:, 2:] -= roi[:2]

            return image_t, boxes_t,labels_t, ratios_t 

Several data augmentations to be applied during training

def preproc_for_test(image, input_size, mean, std):
	''' 
    Data Augmentation applied during testing/validation 
    :image: an ndarray object
    :input_size: tuple of int with two elements (H,W) of image
    :mean: mean of training dataset or image_net rgb mean
    :std: standard deviation of training dataset or imagenet rgb std 
    '''

    interp_methods = [cv2.INTER_LINEAR, cv2.INTER_CUBIC, cv2.INTER_AREA, cv2.INTER_NEAREST, cv2.INTER_LANCZOS4]
    interp_method = interp_methods[random.randrange(5)]
    image = cv2.resize(image, input_size,interpolation=interp_method)
    image = image.astype(np.float32)
    image = image[:,:,::-1]
    image /= 255.
    if mean is not None:
        image -= mean
    if std is not None:
        image /= std
    return image.transpose(2, 0, 1)

Data augmentation to be applied for testing/validation

除了上述试探法,在输入图像的不同比例下训练 YOLOv3 模型,如{ 320 x 320352 x 352384 x 384416 x 416448 x 448480 x 480512 x 512544 x 544576 x 576608 x 608 },降低了过度拟合的风险,并提高了模型的泛化能力,就像标准的 YOLOv3 训练一样。这些变化极大地提高了 YOLOv3 的性能,但接下来我们将研究另一种方法,称为要素金字塔的自适应空间融合。如果与这些训练试探法相结合,这种技术可以使 YOLOv3 的性能甚至比更快的 RCNN 或 Mask RCNN (2)等基线更好。

特征金字塔的自适应空间融合

使用特征金字塔的对象检测网络在不同尺度的特征或者不同尺度的特征的融合下进行预测。例如,YOLOv3 以 32、16 和 8 三种不同的步幅进行预测。换句话说,如果给定一个 416 x 416 T1 的输入图像,它将对 T2 13 x 13 T3、T4 26 x 26 T5 和 T6 52 x 52 T7 进行预测。

低分辨率特征语义价值高,高分辨率特征语义价值低。低分辨率特征图还包含覆盖图像更大区域的网格单元,因此更适合检测更大的对象。相反,来自较高分辨率特征地图的网格单元更适合于检测较小的物体。这意味着仅使用一个尺度的特征来检测不同尺度的对象是困难的。为了解决这个问题,可以在不同的尺度上分别进行检测,以检测不同尺度的对象,如在单次检测器( SSD )架构中。然而,尽管该方法在计算上需要很少的额外成本,但它仍然是次优的,因为高分辨率特征图不能充分地从图像中获得语义特征。像 RetinaNet、YOLOv3 等架构。因此组合高和低语义值特征来创建语义和空间强的特征。对这些特征执行检测在速度和准确性之间呈现了更好的折衷。

不同分辨率特征的组合是通过按元素方式连接或添加它们来完成的。一些人已经提出了一种方法来组合这些特征地图,使得只有来自每个比例特征地图的相关信息被保留用于组合(2)。下图对此进行了总结。简而言之,不是像在标准 YOLOv3 中那样对每个级别的特征进行预测,而是首先对来自三个级别的特征进行重新缩放,然后在每个级别进行自适应组合,然后对这些新特征执行预测/检测。

为了更好地理解这一点,我们将看看这种方法的两个重要步骤:1)相同的重新缩放和 2)自适应特征融合。

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

Illustration of Adaptive Spatial Fusion of Feature Pyramids (source)

相同的重新标度

每个级别的所有要素都将被重新缩放,并且它们的通道数也将被调整。假设大小为416×416的输入图像已经作为输入给出,我们必须将级别 2 的特征(其中特征图大小为26×26,通道数为 512)与级别 3 的更高分辨率特征(分辨率为52×52,通道数为 256)进行组合。然后,该层将被下采样到26×26,同时通道的数量增加到 512。另一方面,较低分辨率级别 1 的特征(分辨率13×13,通道数 1024)将被上采样到26×26,而通道数将减少到 512。

对于上采样,首先应用一个 1 x 1 卷积层来压缩特征的通道数,然后通过插值来进行放大。对于 1/2 比率的下采样,步长为 2 的3×3卷积层用于同时修改通道数量和分辨率。对于 1/4 的比例,在 2 步卷积之前使用 2 步最大池层。下面的代码使用 PyTorch 定义并执行这些操作。

def add_conv(in_ch, out_ch, ksize, stride, leaky=True):
    """
    Add a conv2d / batchnorm / leaky ReLU block.
    Args:
        in_ch (int): number of input channels of the convolution layer.
        out_ch (int): number of output channels of the convolution layer.
        ksize (int): kernel size of the convolution layer.
        stride (int): stride of the convolution layer.
    Returns:
        stage (Sequential) : Sequential layers composing a convolution block.
    """
    stage = nn.Sequential()
    pad = (ksize - 1) // 2
    stage.add_module('conv', nn.Conv2d(in_channels=in_ch,
                                       out_channels=out_ch, kernel_size=ksize, stride=stride,
                                       padding=pad, bias=False))
    stage.add_module('batch_norm', nn.BatchNorm2d(out_ch))
    if leaky:
        stage.add_module('leaky', nn.LeakyReLU(0.1))
    else:
        stage.add_module('relu6', nn.ReLU6(inplace=True))
    return stage

Adds a convolutional block with a sequence of conv, batchnorm and relu layers

def scaling_ops(level, x_level_0, x_level_1, x_level_2):
	"""
    Performs upscaling/downscaling operation for each level of features
    Args:
        level (int): level number of features.
        x_level_0 (Tensor): features obtained from standard YOLOv3 at level 0.
        x_level_1 (Tensor): features obtained from standard YOLOv3 at level 1.
        x_level_2 (Tensor): features obtained from standard YOLOv3 at level 2.
    Returns:
        resized features at all three levels and a conv block
    """
    dim = [512, 256, 256]
    inter_dim = dim[level]
    if level==0:
        stride_level_1 = add_conv(256, inter_dim, 3, 2)
        stride_level_2 = add_conv(256, inter_dim, 3, 2)
        expand = add_conv(inter_dim, 1024, 3, 1)

        level_0_resized = x_level_0
        level_1_resized = stride_level_1(x_level_1)
        level_2_downsampled_inter = F.max_pool2d(x_level_2, 3, stride=2, padding=1)
        level_2_resized = stride_level_2(level_2_downsampled_inter)
    elif level==1:
        compress_level_0 = add_conv(512, inter_dim, 1, 1)
        stride_level_2 = add_conv(256, inter_dim, 3, 2)
        expand = add_conv(inter_dim, 512, 3, 1)

        level_0_compressed = compress_level_0(x_level_0)
        level_0_resized = F.interpolate(level_0_compressed, scale_factor=2, mode='nearest')
        level_1_resized = x_level_1
        level_2_resized = stride_level_2(x_level_2)
    elif level==2:
        compress_level_0 = add_conv(512, inter_dim, 1, 1)
        expand = add_conv(inter_dim, 256, 3, 1)

        level_0_compressed = compress_level_0(x_level_0)
        level_0_resized = F.interpolate(level_0_compressed, scale_factor=4, mode='nearest')
        level_1_resized = F.interpolate(x_level_1, scale_factor=2, mode='nearest')
        level_2_resized = x_level_2

    return level_0_resized, level_1_resized,level_2_resized, expand

Performs upscaling or downscaling given the level number and set of features

自适应特征融合

重新调整要素后,通过对所有三个重新调整的要素地图的每个像素进行加权平均来合并要素(假设所有通道的权重相同)。这些权重是在我们训练网络时动态学习的。这个等式可以更好地解释它:

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

source

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

source

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

source

这里使用 PyTorch 定义这些操作。

def adaptive_feature_fusion(level, level_0_resized, level_1_resized,level_2_resized, expand):
	"""
    Combines the features adaptively.
    Args:
        level (int): level number of features.
        level_0_resized (Tensor): features obtained after rescaling at level 0.
        level_1_resized (Tensor): features obtained after rescaling at at level 1.
        level_2_resized (Tensor): features obtained after rescaling at at level 2.
        expand (Sequential): a conv block
    Returns:
        out (Tensor): new combibed feature on which detection will be performed.
    """
    dim = [512, 256, 256]
    inter_dim = dim[level]
    compress_c = 16  
    weight_level_0 = add_conv(inter_dim, compress_c, 1, 1)
    weight_level_1 = add_conv(inter_dim, compress_c, 1, 1)
    weight_level_2 = add_conv(inter_dim, compress_c, 1, 1)

    weight_levels = nn.Conv2d(compress_c*3, 3, kernel_size=1, stride=1, padding=0)
    level_0_weight_v = weight_level_0(level_0_resized)
    level_1_weight_v = weight_level_1(level_1_resized)
    level_2_weight_v = weight_level_2(level_2_resized)
    levels_weight_v = torch.cat((level_0_weight_v, level_1_weight_v, level_2_weight_v),1)
    levels_weight = weight_levels(levels_weight_v)
    levels_weight = F.softmax(levels_weight, dim=1)

    fused_out_reduced = level_0_resized * levels_weight[:,0:1,:,:]+\
                        level_1_resized * levels_weight[:,1:2,:,:]+\
                        level_2_resized * levels_weight[:,2:,:,:]

    out = expand(fused_out_reduced)
    return out 

Performs Adaptive Feature Fusion given rescaled features

根据(2),新适应的特征过滤掉不同尺度上的不一致性(使用自适应空间融合权重),这是具有特征金字塔的单次检测器的主要限制。当与使用上述训练试探法训练的 YOLOv3 模型一起使用时,它显著提高了(在 COCO test-dev 2014 上,给出的 mAP@(.5:.95)为 42.4,而 YOLOv3 基线 mAP@(.5:.95)为 33.0)(2)在推断期间,YOLOv3 基线的计算成本仅略有增加(也在 COCO test-dev 2014 上测量),即从 YOLOv3 基线的 52 FPS(每秒帧数)提高到 45.5 FPS (1)。此外,还集成了其他几个模块,如 DropBockRFB 等。在自适应特征融合之上,可以超越(2)更快的 RCNN 和掩模 RCNN 基线。你可以在这里下载预先训练好的重量。

尾注

在本文中,我们看到了如何通过使用简单的对象检测训练试探法和自适应特征融合的新技术,在不增加或仅少量增加推理成本的情况下,显著改善 YOLOv3 基线。这些方法需要最少的架构更改,并且可以轻松集成。上面提到的训练试探法也可以直接用于微调预训练的 YOLOv3 模型。改进后的 YOLOv3 无疑在速度和精度之间提供了更好的平衡。您可以在这里找到使用上述方法对您的自定义数据进行微调的完整代码。

SKRohit/Improving-YOLOv3Few training heuristics and small architectural changes that can significantly improve YOLOv3 performance with tiny increase in inference cost. - SKRohit/Improving-YOLOv3外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传GitHubSKRohit外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

参考

  1. 用于训练目标检测神经网络的一包赠品
  2. 学习空间融合进行单镜头物体检测

Paperspace + Insight 数据科学

原文:https://blog.paperspace.com/insight-data-science/

在 Paperspace,我们致力于让专业人士和学者更容易获得云中的机器学习。

一键“ML-in-a-Box”的想法是我们对 ML 社区对更强大的 GPU 和新功能的需求激增的回应。众所周知,传统的云提供商如今主要关注开发运营,并且在许多情况下需要网络和基础设施方面的复杂专业知识。

事实上,很多 ML 研究仍然是在笔记本电脑和台式机上完成的。相比之下,我们希望解决更广泛的需求,包括数据科学家、研究人员,甚至学生,他们可能拥有某个领域的专业知识,但他们自己无法将复杂的云基础架构串联起来,帮助他们将工作流迁移到云。

随着全新的受众将他们的工作流迁移到云,这一新产品的目标是找到计算抽象的最佳点:允许用户只需几次点击就可以将处理能力卸载到云,同时仍然保持深入机器以调试代码的能力。对学术界和专业人士来说都是双赢。

为了突出这些可能性,我们与 Insight Data Science 及其人工智能研究员合作。

Insight Data Science 为他们的学生提供了为期 7 周的强化课程,弥合了学术研究或专业软件工程与人工智能职业生涯之间的差距。他们中的许多人最终在一些最知名的机构工作,比如谷歌和脸书。

赋予研究员启动和运行生产就绪的机器学习环境的能力,使他们能够在强化课程中构建更复杂的人工智能产品。该计划的结果反映了“盒子里的 ML”解决方案的潜力。

“试图进入应用人工智能领域的人们苦于缺乏负担得起的高端 GPU,因此行业专业人士无法获得快节奏的迭代。Insight 的人工智能研究员是一群有天赋的软件工程师和研究人员,他们接受领先行业专家的指导。这与 Paperspace 的尖端 GPU 相结合,使研究人员能够在几分钟内建立并运行模型,并在几天内完成最近发布的研究原型。”
——Jeremy Karnowski,AI 领衔洞察数据科学

在接下来的几个月里,我们将通过各种社交渠道展示人工智能研究员们的惊人作品。请随时联系 Insight Data Science,了解他们的计划和同事的工作。

要开始使用您自己的 ML-in-a-box,在此注册。

可解释机器学习入门

原文:https://blog.paperspace.com/interpretable-machine-learning/

机器学习模型长期以来一直因经常是黑箱或“无法解释”而臭名昭著。甚至使用这些模型的人也不知道模型的内部权重和决策。此外,如果你对利益相关者负责,拥有一个黑箱模型不再是一个选择。

这是一个关于可解释性的经典迷因。

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

Image Source

是不是只有业内人士,才是罪魁祸首?不完全是,人工智能领域几乎所有的研究都集中在更好的架构、超越基准、新颖的学习技术,或者在某些情况下只是建立具有 10 亿个参数的巨大模型。可解释的机器学习的研究相对来说还未被触及。人工智能在媒体中越来越受欢迎(由“点击诱饵”媒体标题引起)和复杂,只会使可解释性的情况恶化。

以下是可解释 ML 如此重要的其他原因。

  • 人类的好奇心和求知欲——人类这个物种天生好奇。当某些事情与人类先前的信念相矛盾时,人类会特别寻找解释。互联网上的人可能会好奇为什么某些产品和电影会被推荐。为了解决这种与生俱来的愿望,公司已经开始解释他们的建议。

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

Image Source

  • 建立信任——当你向潜在买家推销你的 ML 产品时,他们为什么要信任你的模型?他们如何知道模型在所有情况下都会产生好的结果?在我们的日常生活中,需要可解释性来增加 ML 模型的社会接受度。类似地,与他们的个人家庭助理交互的消费者会想要知道某个动作背后的原因。解释有助于我们理解和理解机器。
  • ****调试和检测偏差——当你试图推理一个意想不到的结果或者在你的模型中发现一个 bug 时,可解释性变得非常有用。最近,人工智能模型也因偏向于某些种族和性别而受到关注,在模型部署到现实世界之前,可解释的模型可以检测和纠正这一点。

可解释性和性能并不密切相关

在金融和医疗保健等高风险领域,数据科学家通常会使用更传统的机器学习模型(线性或基于树的模型)。这是因为,模型解释其决策的能力对业务非常重要。例如,如果你的模型拒绝了一个人的贷款申请,你不能因为不知道是什么因素促成了模型的决定而逃脱。尽管简单的最大似然模型的表现不如神经网络等更复杂的模型,但它们在本质上是可解释的,也更透明。决策树可以很容易地被可视化,以理解在哪个级别使用哪个特征来进行决策。它们还带有一个要素重要性属性,该属性告知哪些要素在模型中贡献最大。

然而,使用如此简单的模型总是以性能为代价并不是一个真正的解决方案。我们需要像集成和神经网络这样的复杂模型,它们可以更准确地捕捉数据中的非线性关系。这就是模型不可知解释方法的用武之地。

在这篇博客中,我们将使用一个糖尿病数据集来探索其中的一些解释技术,并在其上训练一个简单的分类算法。我们的目标是根据一个人的特征来预测他是否患有糖尿病,并且我们将尝试推理模型的预测。

所以,让我们开始吧!

import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split 

加载数据集以查看要素。

df = pd.read_csv("diabetes.csv")
df.head() 

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

我简单解释一下特性:

  • 怀孕——患者过去怀孕的次数
  • -血糖浓度(mg/dL)
  • -舒张压(毫米汞柱)
  • -三头肌皮褶厚度(mm)
  • 胰岛素 - 2 小时血清胰岛素(μU/ml)
  • BMI -身体质量指数(体重单位为 kg/(身高在 m)^2)
  • 糖尿病谱系功能——它决定了一个性状具有显性还是隐性的遗传模式。当患者在家族中有糖尿病病史时,它被计算出来。
  • ——年龄以年计。
  • 结果——一个人是否患有糖尿病(0 =否,1 =是)

让我们将数据集分为训练和测试,并拟合一个模型。

*`target=df['Outcome']
df=df.drop(labels=['Outcome'],axis=1)
# train-test split
X_train, X_test, y_train, y_test = train_test_split(df, target, test_size=0.2, random_state=42)
# fit the model 
rfc=RandomForestClassifier(random_state=1234)
rfc.fit(X_train,y_train)
# evaluate the results
rfc.score(X_test,y_test)`* 

*现在,我们有了一个基本的模型,是时候探索解释技术了。第一个是特征重要性,这是一种特定于决策树及其变体的技术。

特征重要性

要素重要性或置换要素重要性通过置换要素并观察模型的误差来测量。直觉是,如果改变一个特征改变了模型的误差,这意味着模型依赖于该特征进行预测,那么该特征是重要的。反之亦然。

import seaborn as sns
features =["Pregnancies","Glucose","BP","SkinThickness","Insulin","BMI","DPFunc","Age"]
all_feat_imp_df = pd.DataFrame(data=[tree.feature_importances_ for tree in 
                                     rfc],
                               columns=features)
(sns.boxplot(data=all_feat_imp_df)
        .set(title='Feature Importance Distributions',
             ylabel='Importance')); 

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

根据特征的重要性,血液中的葡萄糖水平以及身体质量指数和年龄是将患者分类为糖尿病患者的最重要的特征。这个结果似乎是合理的。血液中葡萄糖水平高基本就是糖尿病,肥胖者更容易得。这项研究显示,由于随着年龄的增长,胰岛素抵抗增加和胰岛功能受损的综合影响,老年人处于患二型糖尿病的高风险中。

到目前为止,我们可以说我们的模型在数据分类方面做得很好。它已经学会了正确的权重,是可以信任的。

takealways:

  • 特征重要性提供了对模型行为的高度压缩的全局洞察。
  • 置换特征的重要性来源于模型的误差。在某些情况下,您可能想知道某个特性的模型输出变化有多大,而不考虑它对性能的影响。
  • 具有相关特征可以通过在两个特征之间分割重要性来降低相关特征的重要性。

示例 ML:决策树

使用决策树的一大优势是它们非常直观。接下来,我们将绘制树本身,以理解树中每个节点所做的决策。

from IPython.display import Image  
from sklearn.tree import export_graphviz
import graphviz
import pydotplus
from io import StringIO  

# Get all trees of depth 3 in the random forest
depths3 = [tree for tree in rfc.estimators_ if tree.tree_.max_depth==3]
# grab the first one
tree = depths3[0]
# plot the tree
dot_data = StringIO()
export_graphviz(tree, out_file=dot_data, feature_names=features, 
                filled=True, rounded=True, special_characters=True)
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())  
Image(graph.create_png()) 

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

基于写在节点顶部的特征,每个非叶节点被分割。在树的左边部分,我们将样本分类为非糖尿病,在右边部分分类为糖尿病。最左边叶节点的熵函数变为 0,因为数据变得同质(所有样本不是糖尿病就是非糖尿病)。值数组中的第一个值表示有多少样本被归类为非糖尿病样本,第二个值表示有多少样本为糖尿病样本。对于最左边的叶节点,熵是 0,因为所有 54 个样本都是非糖尿病的。

树可能是最本质上可解释的模型。还有其他这样的模型,如广义线性模型,朴素贝叶斯,K-最近邻,但使用这些方法的问题是,它们对于不同的模型是不同的。因此,解释各不相同。用于解释逻辑回归模型的方法与用于解释 KNN 的方法不同。因此,博客的其余部分将致力于独立于应用它们的模型的方法。

模型不可知的方法

我们将通过可视化特征交互来开始模型不可知方法。因为在现实世界中,特性很少是相互独立的,所以理解它们之间的交互很重要。

特征交互

当预测模型中的功能之间存在交互时,预测不能表示为功能效果的总和,因为一个功能的效果取决于另一个功能的值。两个特征之间的相互作用被计算为在考虑了单个特征的影响之后通过改变特征而发生的预测变化。

这个情节是基于弗里德曼和波佩斯库提出的 H 统计量 。在不涉及技术细节的情况下,H 统计量将特征之间的相互作用定义为由相互作用解释的方差的份额。

R 中有很多实现这个的包。不幸的是,对于 python 用户来说,只有 sklearn-gbmi 包(据我所知)可以计算梯度增强模型的 H 统计量。

from sklearn.ensemble import GradientBoostingClassifier
from sklearn_gbmi import *
# fit the model
gbc = GradientBoostingClassifier(random_state = 2589)
gbc.fit(X_train,y_train)
# d is a dictionary of feature pairs and their respective interaction strength
d=h_all_pairs(gbc,X_train)
l=sorted(d.items(), key=lambda x: x[1])
l=l[-10:] # let's just take the top 10 interactions
data=pd.DataFrame(l)
data.columns=['Feature',"Interaction"]
data.index=data['Feature']
data=data.drop(labels=['Feature'],axis=1)
data.plot(kind='barh', color='teal', title="Feature Interaction Strength") 

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

怀孕次数和年龄之间以及血压和胰岛素之间有很强的相互作用。所有这些互动都是双向的。

take all:-

  • 该统计检测所有类型的交互,不管它们的特定形式。
  • 由于统计量是无量纲的,并且总是在 0 和 1 之间,所以它可以跨要素甚至跨模型进行比较(尽管对于 Python 用户来说还不行)
  • H 统计量告诉我们相互作用的强度,但是它没有告诉我们相互作用看起来如何。下一类解释方法正是为此。

部分相关图

部分相关性图(短 PDP 或 PD 图)显示了一个或两个特征对机器学习模型预测结果的边际效应。它可以显示目标和特征之间的关系的性质,该关系可以是线性的、单调的或更复杂的。

部分相关图是一种全局和局部的方法。该方法考虑了所有实例,并给出了关于特征与预测结果(通过黄线)的全局关系以及所有唯一实例(数据帧中的行)与结果(通过蓝线)的关系的陈述。

from pdpbox import pdp, info_plots
pdp_ = pdp.pdp_isolate(
    model=estimator, dataset=X_train, model_features=X_train.columns, feature='Glucose'
)
fig, axes = pdp.pdp_plot(
    pdp_isolate_out=pdp_, feature_name='Glucose', center=True, 
     plot_lines=True, frac_to_plot=100) 

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

y 轴可以解释为预测值相对于基线或最左侧值的变化。蓝线代表所有实例,黄线代表平均边际效应。不同的影响可以通过蓝线看出。

血糖升高会增加患糖尿病的几率。非糖尿病人的正常空腹血糖在70 ~ 100mg/dL之间,这也是图表所证明的。

pdp_ = pdp.pdp_isolate(
    model=estimator, dataset=X_train, model_features=X_train.columns, feature='Age'
)
fig, axes = pdp.pdp_plot(
    pdp_isolate_out=pdp_, feature_name='Age', center=True, x_quantile=True, 
     plot_lines=True, frac_to_plot=100) 

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

根据我们的模型,23 岁以后的人更容易患糖尿病。

PDP 易于实施且直观。由于 PDP 图显示的是边际效应,根据定义,边际效应假设其他协变量不变,因此它忽略了现实世界中的特征通常是相关的这一事实。因此,对于房价回归问题,两个特征是房子的面积和房间的数量。为了计算房间数量对价格的边际影响,它将保持房子的面积不变,比如说 30 平方米 2 平方米,这对于一个有 10 个房间的房子来说是不太可能的。

累积局部效应(ALE)图通过查看所有特征的条件分布(而非边缘分布)并考虑预测差异(而非平均值)来解决上述问题。

局部可解释模型不可知解释(LIME)

LIME 使用代理模型进行解释。代理模型被训练为使用稀疏线性模型(称为代理)来近似底层黑盒模型的预测。这些代理模型只是近似模型的局部行为,而不是全局行为。

让我们通过一个例子来看看 LIME 执行的步骤。

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

Image Source

原始模型的决策函数由蓝色/粉红色背景表示,这显然是非线性的。亮红色的十字是正在解释的实例(我们称它为 X)。我们对 X 周围的扰动实例进行采样,并根据它们与 X 的接近程度对它们进行加权(图中的权重由大小表示)。原始模型对这些扰动实例的预测用于学习线性模型(虚线),该线性模型很好地逼近 x 附近的模型。因此,该解释在局部而非全局工作良好。

import lime
import lime.lime_tabular
classes=['non-diabetic','diabetic']
explainer = lime.lime_tabular.LimeTabularExplainer(X_train.astype(int).values,  
mode='classification',training_labels=y_train,feature_names=features,class_names=classes)
#Let's take a look for the patient in 100th row
i = 100
exp = explainer.explain_instance(X_train.loc[i,features].astype(int).values, estimator.predict_proba, num_features=5)
# visualize the explanation
exp.show_in_notebook(show_table=True)
``

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

橙色特征支持糖尿病类,蓝色特征支持非糖尿病类。

解释有三个部分:—

  1. 左上部分给出了类别 0 和类别 1 的预测概率。
  2. 中间部分给出了 5 个最重要的特征。橙色要素属于糖尿病类,蓝色要素属于非糖尿病类。
  3. 右侧部分遵循与 1 和 2 相同的颜色编码。它包含前 5 个变量的实际值。

这可以读作: 女方患糖尿病的概率为 0.67。她的葡萄糖水平、身体质量指数、年龄和糖尿病患者的功能都表明患有糖尿病,我们已经在 PDP 图中看到了这是如何发生的。然而,她只有一次怀孕,而不会导致糖尿病,但与确定糖尿病的其他更关键的特征相比,这具有较小的权重。

如果这个可视化激发了你对石灰的兴趣,这里有文档

take all:-

  • 向外行人解释时非常有用的人性化解释。
  • LIME 和我们讨论过的其他方法一样,也有忽略相关性的限制。数据点是从高斯分布中采样的,假设特征不相关。这可能导致不太可能的数据点,然后这些数据点可以用于学习局部解释模型。
  • 这些解释也可能是不稳定的。如果重复采样过程,那么得出的解释可能会不同。

SHAP

SHAP (SHapley 附加解释)是一种流行的解释方法,可用于全局和局部解释。它利用博弈论来衡量特征对预测的影响。为了解释预测,我们可以从假设实例的每个特征值是游戏中的 【玩家】 开始,其中预测是*。然后,shapley 值将告诉您如何在特性之间公平地分配“支出”。*

更准确地说,“游戏”是数据集的单个实例的预测任务。“增益”是该实例的实际预测减去输入到模型中的所有实例的平均预测。“玩家”是协作接收增益或预测某个值的实例的特征值。

让我们从这本中举个例子,更好地理解这一点。

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

Image Source*

回到我们之前预测公寓价格的例子。假设某套公寓的价格预测为 300,000 美元,我们的工作就是解释这一预测。这一预测的一些特征包括:

** 这套公寓的面积为 50 平方米

  • 它位于二楼
  • 它附近有一个公园
  • 禁止养猫。

现在,所有公寓的平均预测是 31 万美元。我们想知道,与平均预测相比,每个特征值对预测的贡献有多大?

答案可能是:公园附近贡献了 30,000 美元,大小- 50 贡献了 10,000 美元,二楼贡献了 0 美元,禁止猫贡献了-50,000 美元。贡献总计为-10,000 美元,最终预测减去准确预测的平均公寓价格。

Shapley 值计算为所有可能联盟中某个特征值的平均边际贡献。联盟只不过是不同的模拟环境,通过改变一个特性,同时保持其他一切不变,并注意效果。例如,如果“禁止养猫”变成了“允许养猫”,而所有其他特征都相同,我们检查预测是如何变化的。

让我们试着解释一下对病人的分类。

import shap
# create our SHAP explainer
shap_explainer = shap.TreeExplainer(estimator)
# calculate the shapley values for our data
shap_values = shap_explainer.shap_values(X_train.iloc[7])
# load JS to use the plotting function
shap.initjs()
shap.force_plot(shap_explainer.expected_value[1], shap_values[1], X_train.iloc[7]) 

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

导致预测增加的要素显示为粉红色,导致预测减少的要素显示为蓝色,它们的值代表影响的大小。基值是 0.3498,我们预测是 0.7。该患者被归类为糖尿病患者,将结果推向糖尿病的特征是葡萄糖水平=161、年龄=47、胰岛素=132 和 10 次怀孕。身体质量指数的功能,这是低,试图否定的影响,但不能,因为组合的影响,粉红色的功能远远超过了它。

如果从粉色条的长度中减去蓝色条的长度,则等于从基准值到输出的距离。

让我们也来看一下 Summary plo t,以了解该型号的整体情况。

shap_values = shap_explainer.shap_values(X_train)
shap.summary_plot(shap_values[1], X_train,auto_size_plot=False) 

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

好吧,我们来试着解读一下这个!这幅图是由许多点组成的。他们每个人都有三个特点:

  • 垂直位置显示了它所描绘的特征。
  • 颜色显示该特征对于数据集的该行是高还是低。
  • 水平位置显示该值对预测有负面影响还是正面影响。

葡萄糖行中最右边的点是粉红色的,这意味着葡萄糖水平高,这增加了患糖尿病的机会,就像我们以前看到的一样。其他特征如身体质量指数、年龄和怀孕也是如此,但对葡萄糖的影响更明显。

外卖:

  • 与其他方法相比,解释速度相当快,而且这种技术在博弈论中有坚实的基础。
  • 预测和平均预测之间的差异是 在实例的特征值中公平分布 而不像石灰。
  • KernelSHAP(我们之前讨论过的)忽略了特征依赖,因为从边缘分布中采样通常更容易。然而,如果特征是相关的,这将导致对不太可能的数据点赋予过多的权重。SHAP 的另一个变体 TreeSHAP 通过显式建模条件预期预测来解决这个问题。

结论

机器学习应用越来越多地被行业采用,在未来几十年里,它只会变得更加无处不在。为了确保这些系统不会在现实世界中灾难性地失败,就像 Zillow 的崩溃一样,我们需要更多地关注可解释性,而不是复杂和花哨的架构。

这个博客旨在让你一瞥可解释性的世界。如果你想了解更多,我强烈推荐这本由 Christoph Molnar 写的书:可解释的 ML Book 。**

解读计算机视觉模型

原文:https://blog.paperspace.com/interpreting-computer-vision-models/

计算机视觉作为一个领域可以追溯到 20 世纪 60 年代末,当时它起源于模仿人类视觉系统的雄心勃勃的目标。然而,在经历了漫长的人工智能冬天之后,这个领域最近在 2012 年成为了焦点,当时 AlexNet 赢得了第一届 ImageNet 挑战赛。AlexNet 在 GPU 上使用深度 CNN 对 ImageNet 中的数百万张图像以及数千个标签进行分类,前 5 名的错误率为 15.3%。

你们中的一些人可能想知道:CNN 是什么?

我简单给你解释一下。

卷积神经网络或 CNN 中神经元之间的连接模式受到动物视觉皮层组织的启发。皮层中的单个神经元只在视野中被称为感受野的有限区域内对刺激做出反应。类似地,CNN 有内核(一个具有共享权重的 n x n 矩阵),它沿着输入图像滑动以捕捉空间信息,而这是多层感知器所做不到的。

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

Source

对于高分辨率图像,拥有完全连接的节点网络在计算上是不可行的。此外,神经元的完全连接对于固有地包含空间局部输入模式的图像是浪费的。我们可以从图案中推断出更精细的细节,并节省成本。

CNN 的兴起和可解释性案例

CNN 在减小网络规模的同时,还增加了参考局部性,这对于图像数据非常重要。因此,CNN 被广泛用于计算机视觉任务。

  • 例如,在自动驾驶汽车中,它们被用于从检测和分类道路上的物体到从人行道分割道路的一切事情。
  • 在医疗保健领域,它们被用于 x 光、核磁共振成像和 CT 扫描来检测疾病。
  • 它们还用于制造和生产线,以检测有缺陷的产品。

这些只是众多用例中的少数几个,但它们正确地传达了这些系统与我们的日常生活是如何交织在一起的。但是,尽管它们很常见,但如果没有深度学习和人工智能领域的知识,对它们的解释可能会很困难。因此,能够解释这些“黑箱”的预测变得极其重要。在这篇博客中,我们将探索解读这些网络预测的技术。

我将把口译技巧大致分为两类:

基于遮挡或扰动的技术

这些方法处理部分图像以生成解释。这到底是怎么回事?我将用两个库来解释它。

  1. 石灰图像讲解器:

本地可解释模型不可知解释(或 LIME)是一个支持几乎所有数据形式的本地解释的库。这些解释是模型不可知的(独立于所使用的模型),并且试图只解释个别的预测而不是整个模型(局部的)。石灰处理图像的方式可以分解为以下步骤:

  • **获得图像的随机扰动:**在时间上,图像的变化是通过将图像分割成“超像素”并关闭或打开它们而产生的。这些超像素相互连接,可以通过将每个像素替换为灰色来关闭。对于每个图像,我们有一组扰动图像。
  • 预测扰动图像的类别:对于每个扰动图像,使用我们试图解释的原始模型来预测类别。
  • 计算扰动的重要性:使用余弦相似度等距离度量来评估每个扰动与原始图像的不同程度。原始图像也是所有超像素开启时的扰动。
  • 训练一个可解释的代理模型:代理模型是一个线性模型,就像逻辑回归一样,本质上是可解释的。该模型接受原始模型的输入和输出,并试图逼近原始模型。初始权重是我们在上一步中计算的权重。模型拟合后,与图像中每个超像素相关的权重或系数告诉我们该超像素对预测类别有多重要。

我们现在将使用预训练的 Inception-V3 模型来对猫和老鼠图像进行预测。

from keras.applications import inception_v3 as inc_net
from keras.preprocessing import image
from keras.applications.imagenet_utils import decode_predictions
from skimage.io import imread
import matplotlib.pyplot as plt
import lime
from lime import lime_image

def load_img(path):
    img = image.load_img(path, target_size=(224, 224))
    img = image.img_to_array(img)
    img = np.expand_dims(img, axis=0)
    return img

def predict_class(img):
    img = inc_net.preprocess_input(img)
    img = np.vstack([img])
    return inet_model.predict(img)

inet_model = inc_net.InceptionV3()

img = load_img('cat-and-mouse.jpg')
preds = predict_class(img)
plt.figure(figsize=(3,3))
plt.imshow(img[0] / 2 + 0.5)
for x in decode_predictions(preds)[0]:
    print(x) 

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

Top 5 predicted labels for the image

接下来,我们将使用石灰来解释这些预测。

# instantiate lime image explainer and get the explaination 
explainer = lime_image.LimeImageExplainer()
explanation = explainer.explain_instance(img[0], inet_model.predict, top_labels=5, hide_color=0, num_samples=1000)

# plot interpretation
temp, mask = explanation.get_image_and_mask(282, positive_only=False, num_features=100, hide_rest=False)
plt.figure(figsize=(3,3))
plt.imshow(skimage.segmentation.mark_boundaries(temp / 2 + 0.5, mask)) 

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

绿色超像素对预测标签即虎猫有积极的贡献。而红色超像素负贡献。

即使有些红色超像素躺在猫身上。该模型在学习图像中的基本概念方面做得很好,颜色反映了这一点。

Lime 对图像的实现与其对表格数据的实现非常相似。但是我们改变超像素,而不是干扰单个像素。由于我们之前讨论过的位置引用,一个类中有多个像素。

  1. SHAP 分区解说:

另一个流行的解释库是 SHAP。它使用来自博弈论的概念来产生解释。考虑一个由一群人合作进行的游戏。每个玩家都对游戏有所贡献,有些玩家可能比其他人贡献更多,有些玩家可能贡献更少。将有一个最终的分配,每个玩家的贡献总和将决定游戏的结果。

我们想知道每个参与者对整体合作有多重要,以及他们能期望什么样的回报。为了更具体地说明手头的任务,每个超像素对图像整体预测类别的贡献有多重要。

Shapley 值提供了一个可能的答案。

让我们试着用 SHAP 来解读同一个猫和老鼠的形象。这里我们将使用一个 Resnet50 来代替一个初始模型。

from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input
import shap
import json 

# load pretrained model
model = ResNet50(weights='imagenet')
def predict(x):
    tmp = x.copy()
    preprocess_input(tmp)
    return model(tmp)

# get imagenet class names
url = "https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json"
with open(shap.datasets.cache(url)) as file:
    class_names = [v[1] for v in json.load(file).values()]

# define a masker that is used to mask out partitions of the input image.
masker = shap.maskers.Image("inpaint_telea", img.shape[1:])

# create an explainer with model and image masker
explainer = shap.Explainer(f, masker, output_names=class_names,algorithm='partition')

# here we explain the same image and use 1000 evaluations of Resnet50 to get the shap values 
shap_values = explainer(img, max_evals=1000, batch_size=50, outputs=shap.Explanation.argsort.flip[:4])

shap.image_plot(shap_values) 

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

第一个被预测的种类是埃及猫,接下来是狐松鼠、虎斑猫和猞猁。猫面部的超像素对预测有积极的贡献。该模型在鼻子或胡须区域放置了很大的重量。

在 SHAP 中使用分区解释器的一个优点是,它不会做出一个潜在的假设,即这里的特征(或超像素)独立于其他特征而存在。这是一个很大的(错误的)假设,是由很多解释模型做出的。

我们现在来看看下一类的解释技巧。

基于梯度的技术

这些方法计算预测相对于输入图像的梯度。简而言之,他们发现像素的变化是否会改变预测。如果您要更改像素的颜色值,预测的类概率将会上升(正梯度)或下降(负梯度)。梯度的大小告诉我们扰动的重要性。

我们将看看一些使用梯度进行解释的技术:

1.Grad-CAM

梯度加权类激活图或 Grad-CAM 使用流入最终卷积层的类的梯度来产生热图,该热图突出显示了用于预测类的图像中的重要区域。该热图随后被放大并叠加在输入图像上以获得可视化效果。获取热图的步骤如下:

  1. 我们通过网络前向传播图像以获得预测,以及全连接层之前的最后一个卷积层的激活。
  2. 然后,我们计算顶部预测类相对于最后一个卷积层的激活的梯度。
  3. 然后,我们通过类别的梯度对每个特征图像素进行加权。这给了我们全局汇集梯度。
  4. 我们计算特征图的平均值,该平均值通过梯度对每个像素进行加权。这是通过将在最后一张地图中获得的特征地图中的每个通道乘以最后一层的输出来实现的。这告诉我们通道对于输出类有多重要。然后,我们对所有通道求和,以获得该类的热图激活。
  5. 然后,我们将像素归一化到 0 和 1 之间,这样就很容易可视化了。
import tensorflow as tf
import keras
import matplotlib.cm as cm
from IPython.display import Image

def make_gradcam_heatmap(img_array, model, LAST_CONV_LAYER_NAME, pred_index=None):
    # Step 1
    grad_model = tf.keras.models.Model(
        [model.inputs], [model.get_layer(LAST_CONV_LAYER_NAME).output, model.output]
    )

    with tf.GradientTape() as tape:
        last_conv_layer_output, preds = grad_model(img_array)
        if pred_index is None:
            pred_index = tf.argmax(preds[0])
        class_channel = preds[:, pred_index]

    # Step 2
    grads = tape.gradient(class_channel, last_conv_layer_output)

    # Step 3
    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))

    # Step 4
    last_conv_layer_output = last_conv_layer_output[0]
    heatmap = last_conv_layer_output @ pooled_grads[..., tf.newaxis]
    heatmap = tf.squeeze(heatmap)

    # Step 5
    heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)
    return heatmap.numpy() 

我们使用与上面例子中相同的 ResNet50 模型。我们还有一个助手功能,可以将热图叠加在原始图像上并显示出来。

def save_and_display_gradcam(img_path, heatmap, alpha=0.4):
    # Load the original image
    img = keras.preprocessing.image.load_img(img_path)
    img = keras.preprocessing.image.img_to_array(img)

    # Rescale heatmap to a range 0-255
    heatmap = np.uint8(255 * heatmap)

    # Use jet colormap to colorize heatmap
    jet = cm.get_cmap("jet")

    # Use RGB values of the colormap
    jet_colors = jet(np.arange(256))[:, :3]
    jet_heatmap = jet_colors[heatmap]

    # Create an image with RGB colorized heatmap
    jet_heatmap = keras.preprocessing.image.array_to_img(jet_heatmap)
    jet_heatmap = jet_heatmap.resize((img.shape[1], img.shape[0]))
    jet_heatmap = keras.preprocessing.image.img_to_array(jet_heatmap)

    # Superimpose the heatmap on original image
    superimposed_img = jet_heatmap * alpha + img
    superimposed_img = keras.preprocessing.image.array_to_img(superimposed_img)
    # Display the image
    plt.figure(figsize=(8,4))
    plt.axis("off")
    plt.imshow(superimposed_img) 

厌倦了猫和老鼠的形象?这次我们将使用新的图像。

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

让我们看看这个图像的顶级类。

# Prepare image
img_array = preprocess_input(load_img('cars.jpg',224))
# Print the top 2 predicted classes
preds = model.predict(img_array)
print("Predicted:", decode_predictions(preds, top=2)[0]) 

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

该模型将汽车分类为跑车,并将站在它们之间的人分类为赛车手。让我们想象一下最后一个卷积层的激活。

heatmap = make_gradcam_heatmap(img_array, model, 'conv5_block3_out', pred_index=class_names.index("sports_car"))
save_and_display_gradcam('cars.jpg', heatmap) 

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

似乎第conv5_block3_out层的神经元被汽车的前部激活了。我们可以确信模型学习了这个类的正确特征。

现在,让我们为“racer”类设想一下。

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

这一次,汽车仍然使用汽车像素来将该图像分类为“赛车”,而不是赋予代表男人的像素重要性。这不符合我们的预期,也许模型使用图像中的全局上下文来预测类。例如,一个不站在跑车旁边的人会被称为赛车手吗?

那要由你自己去发现;)

2.制导摄像机

由于 Grad CAM 使用最后一个卷积层来生成热图,因此定位非常粗略。由于最后一个图层的分辨率比输入图像的分辨率要粗糙得多,因此在将热点图叠加到图像上之前,会对其进行升级。

我们使用引导反向传播来获得高分辨率的定位。我们针对输入图像的像素来计算损失梯度,而不是针对最后一个卷积层的激活来计算损失梯度。然而,这样做可能会产生噪声图像,因此我们在反向传播中使用 ReLu(换句话说,我们剪切所有小于 0 的值)。

@tf.custom_gradient
def guided_relu(x):
    # guided version of relu which allows only postive gradients in backpropogation
    def grad(dy):
        return tf.cast(dy > 0, "float32") * tf.cast(x > 0, "float32") * dy

    return tf.nn.relu(x), grad

class GuidedBackprop:
    def __init__(self, model):
        self.model = model
        self.gb_model = self.build_guided_model()

    def build_guided_model(self):
        # build a guided version of the model by replacing ReLU with guided ReLU in all layers
        gb_model = tf.keras.Model(
            self.model.inputs, self.model.output
        )
        layers = [
            layer for layer in gb_model.layers[1:] if hasattr(layer, "activation")
        ]
        for layer in layers:
            if layer.activation == tf.keras.activations.relu:
                layer.activation = guided_relu
        return gb_model

    def guided_backprop(self, image: np.ndarray, class_index: int):
        # convert to one hot representation to match our softmax activation in the model definition
        expected_output = tf.one_hot([class_index] * image.shape[0], NUM_CLASSES)
        # define the loss
        with tf.GradientTape() as tape:
            inputs = tf.cast(image, tf.float32)
            tape.watch(inputs)
            outputs = self.gb_model(inputs)
            loss = tf.keras.losses.categorical_crossentropy(
                expected_output, outputs
            )
        # get the gradient of the loss with respect to the input image
        grads = tape.gradient(loss, inputs)[0]
        return grads 

让我们看看上面看到的跑车示例的显著性图。我们将使用相同的 ResNet50 型号。

gb = GuidedBackprop(model)
NUM_CLASSES = 1000
saliency_map = gb.guided_backprop(img_array, class_index=class_names.index("sports_car")).numpy()

# Normalize with mean 0 and std 1
saliency_map -= saliency_map.mean()
saliency_map /= saliency_map.std() + tf.keras.backend.epsilon()
# Change mean to 0.5 and std to 0.25
saliency_map *= 0.25
saliency_map += 0.5
# Clip values between 0 and 1
saliency_map = np.clip(saliency_map, 0, 1)
# Change values between 0 and 255
saliency_map *= (2 ** 8) - 1
saliency_map = saliency_map.astype(np.uint8)

plt.axis('off')
plt.imshow(saliency_map) 

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

即使我们通过引导反向传播创建的显著图具有更高的分辨率,它也不是类别区分的,即定位不能区分类别。那是我们用摄像机的地方。Grad-CAM 热图使用双线性插值进行上采样,然后两个图按元素相乘。

gb = GuidedBackprop(model)

# Guided grad_cam is just guided backpropogation with feature importance coming from grad-cam
saliency_map = gb.guided_backprop(img_array, class_index=class_names.index("sports_car")).numpy()
gradcam = cv2.resize(heatmap, (224, 224))
gradcam =
np.clip(gradcam, 0, np.max(gradcam)) / np.max(gradcam)
guided_gradcam = saliency_map * np.repeat(gradcam[..., np.newaxis], 3, axis=2)

# Normalize
guided_gradcam -= guided_gradcam.mean()
guided_gradcam /= guided_gradcam.std() + tf.keras.backend.epsilon()
guided_gradcam *= 0.25
guided_gradcam += 0.5
guided_gradcam = np.clip(guided_gradcam, 0, 1)
guided_gradcam *= (2 ** 8) - 1
guided_gradcam = guided_gradcam.astype(np.uint8)

plt.axis('off')
plt.imshow(guided_gradcam) 

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

Grad-CAM 就像一个镜头,聚焦于通过引导反向传播获得的像素属性图的特定部分。这里,对于“跑车”类,主要是与汽车相关的像素被突出显示。

gb = GuidedBackprop(model)

# Guided grad_cam is just guided backpropogation with feature importance coming from grad-cam
saliency_map = gb.guided_backprop(img_array, class_index=class_names.index("racer")).numpy()
gradcam = cv2.resize(heatmap, (224, 224))
gradcam = np.clip(gradcam, 0, np.max(gradcam)) / np.max(gradcam)
guided_gradcam = saliency_map * np.repeat(gradcam[..., np.newaxis], 3, axis=2)

# Normalize
guided_gradcam -= guided_gradcam.mean()
guided_gradcam /= guided_gradcam.std() + tf.keras.backend.epsilon()
guided_gradcam *= 0.25
guided_gradcam += 0.5
guided_gradcam = np.clip(guided_gradcam, 0, 1)
guided_gradcam *= (2 ** 8) - 1
guided_gradcam = guided_gradcam.astype(np.uint8)

plt.axis('off')
plt.imshow(guided_gradcam) 

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

正如你所看到的,制导 Grad CAM 在定位“赛车”类的像素方面比 Grad CAM 做得更好。

3.预期梯度

接下来是预期梯度。它们结合了三个不同的概念:其中一个你已经在 SHAP 价值观中听说过。除了 SHAP 值,他们还使用综合梯度。积分梯度值与 SHAP 值略有不同,需要一个参考值进行积分。为了使它们接近 SHAP 值,在预期梯度中,我们将积分重新表述为期望值,并将该期望值与从背景数据集中采样的参考值相结合。这导致单一组合的梯度期望,其向属性值收敛,该属性值相加给出期望的模型输出和当前输出之间的差异。

它使用的最后一个概念是局部平滑。在期望值计算过程中,它会将正态分布噪声与标准偏差(指定为参数)相加。这有助于创建更平滑的特征属性,从而更好地捕捉图像的相关区域。

这次我们将使用 VGG16,因为我们已经可视化了来自输入图像和最后一个卷积层的梯度,我们将可视化来自中间层(第 7 层)的梯度。

from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input, decode_predictions
import tensorflow.compat.v1.keras.backend as K
import tensorflow as tf
tf.compat.v1.disable_eager_execution()

# load pre-trained model and choose two images to explain
model = VGG16(weights='imagenet', include_top=True)
X,y = shap.datasets.imagenet50()
to_explain = load_img('cars.jpg',224)

# load the ImageNet class names
url = "https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json"
fname = shap.datasets.cache(url)
with open(fname) as f:
    class_names = json.load(f)

# explain how the input to the 7th layer of the model explains the top two classes
def map2layer(x, layer):
    feed_dict = dict(zip([model.layers[0].input], [preprocess_input(x.copy())]))
    return K.get_session().run(model.layers[layer].input, feed_dict)

e = shap.GradientExplainer((model.layers[7].input, model.layers[-1].output), map2layer(preprocess_input(X.copy()), 7) ,local_smoothing=100)
shap_values,indexes = e.shap_values(map2layer(to_explain, 7), ranked_outputs=3, nsamples=100)

# get the names for the classes
index_names = np.vectorize(lambda x: class_names[str(x)][1])(indexes)

# plot the explanations
shap.image_plot(shap_values, to_explain, index_names) 

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

模型预测的第一个标签是跑车。模型的第 7 层关注用红色突出显示的像素。

结论

我们研究了各种可视化 CNN 的技术。这里需要注意的是,当模型提供的解释与我们的预期不符时,可能有两个原因。要么模型没有正确学习,要么模型学习了比人类能够感知的更复杂的关系。

渐变笔记本上尝试一下,在笔记本创建的“高级选项”中创建一个 TensorFlow 运行时笔记本,并将以下内容作为您的“工作区 URL”:【https://github.com/gradient-ai/interpretable-ml-keras】T2

参考

构建 MLOps 社区:德米特里奥斯·布林克曼访谈

原文:https://blog.paperspace.com/interview-demetrios-brinkmann-mlops-community/

一年多前,我们第一次被介绍给德梅特里奥斯·布林克曼,当时他告诉我们,他正在为机器学习领域的专业人士在网上组建一个新的社区,讨论关于 T2 的 m lops T3。

对于许多人来说,MLOps 仍然是一个新概念,但当我们第一次见到 Demetrios 时,这个术语根本不流行——也就是说,O’Reilly 还没有开始 出版关于 MLOps 的书籍,第一次 MLOps 会议还没有举行,人们的脑海中或搜索历史中几乎没有任何关于 MLOps 的意识。

这是一个已经迅速消失的现实。

MLOps 已经在 ML 世界中扩散开来,现在正受到主流企业的采用和关注。像德勤福布斯谷歌这样受人尊敬的玩家正在权衡这个新兴行业,一系列新的会议主题和招聘信息每天都在涌现,新的课件正在适应这个行业不断变化的需求。有价值的职位向系统架构师敞开大门,他们可以将一家公司的 ML 开发管道变成瑞士铁路网。

布林克曼创立的 MLOps.community ,如今可能是 MLOps 世界的中心。布林克曼和他的团队在 ML 领域策划了一个充满活力的专业人士社区,试图定义最佳的哲学、工具和资源,以将决定论带到 ML 开发中——许多对话都在 slack group 中公开进行,任何人都可以自由加入。

我们非常兴奋能和 Demetrios 谈论 MLOps 社区的第一年。我们不仅想知道他在观察什么趋势,他从哪些团体那里听到的最多,还想知道一个居住在西班牙北部的美国侨民是如何建立起一个 5000 人的会员社区的。

我们还想谈谈-还有什么?-米罗普斯!让我们开始吧。

***纸空间。*你是如何为社区保持这样一个行动议程的?

布林克曼。 我们从一个核心计划开始,随着社区和愿意参与其中的人的增多,我们的计划也随之扩展。人们会过来对我说,“嘿,开一个 Q &频道怎么样?”或者“MLOps 频道的女人怎么样?”90%的新计划被证明是伟大的想法,我们已经能够投入时间和精力来寻找线索,将这些计划付诸实施。

一些项目像办公时间一样,在开始一年后才开始。我们一直希望在一周中有一个固定的时间,人们可以聚集在一起,非正式地谈论他们正在做的事情,但直到最近,我们才能够使它成为一种定期发生的事情。

纸空间。 你能告诉我们关于创建社区的事情吗?有没有一个时刻,你觉得自己“明白”了 MLOps 将会成为一件事,并认为其他人也会有类似的感觉?

***布林克曼。***MLOps 社区一开始只有我在 Slack 里给其他三个人发东西。过了一段时间,我们又多了几个人,现在又多了很多人。但是我记得有一个反馈调查是这样说的:“这还不是一个社区,这只是德米特里奥斯策划的新闻”——这仍然让我发笑。

在早期,我们没有像今天这样的势头,人们提出了这么多伟大的问题,全行业的专家都参与进来,引发了这么多伟大的讨论和辩论。

所以我不确定这是一个突然的变化,但在某个时候,这从我策划的新闻聚合器变成了一个真正的社区。“MLOps 问题解答”频道帮了大忙。突然之间,社区的专业知识变得显而易见——很明显,我们有很多真正有才华的人想要分享他们所知道的。

当我开始从 LinkedIn 或社区 Slack 上收到人们的随机留言,说他们多么喜欢正在发生的事情时,这表明我们正在做一些事情。我也开始有大量的人想和我见面或者提出要求。这是一个信号,表明人们注意到了发生在我们这个互联网小角落的事情。

纸空间。 现在谈 MLOps 都要参考论文吗?你认为这份文件对 MLOps 行业来说是一份很好的基础文件吗?你认为它应该被你的社区所重视吗?

布林克曼。 我想说我们播客的一个亮点是我们能够采访论文的主要作者之一 D . Scully的时刻。他是一个信息丰富的人,并不经常“在媒体上露面”——所以他坐下来和我们交谈令人难以置信地感到谦卑。

至于这篇论文,由于过去几年每篇文章或会议讨论都提到了它,它已经有点像一个迷因了。我认为我们都理解并看到了 d .提出的观点的价值,现在我们正在寻找真正解决论文中提到的一些问题的方法。

纸空间。 太酷了。你还记得其他最喜欢的采访或互动吗?

布林克曼。 我从每个客人身上学到东西。我经常引用某些人的话,最后我写了一篇博文,讲述了我迄今为止的 9 次对话。短名单是与谷歌 ML 的 SRE 负责人托德·安德伍德、ML in Production 的创始人 Luigi Patruno 和德勤的战略数据经理伊丽莎白·查博特的对话。

纸空间。 你对加入社区的成员有什么看法?从公司规模、职位或职能等方面来看,你能想到哪些特质表明你对 MLOps 感兴趣?

布林克曼。 从希望学习更多工程技能的数据科学家,到希望完善自己技能的 MLE,再到过渡到 MLOps 的 DevOps 人员,我们都有。

很难一概而论,因为我们的规模越来越大,但有一点我想说的是,我们中的绝大多数人都是从业者——每天都深陷其中。

我认为这也是我们有这么多好的讨论的原因之一——因为我们都在努力解决我们在日常职业生活中遇到的一些问题。

纸空间。 你怎么知道社区往哪个方向走?你的成员有没有告诉你他们希望你把事情引向何方?

布林克曼。 我确保每六个月至少一次通过反馈表向人们汇报。这有助于我感受社区的脉搏和它想要去的地方。

我们有如此多的计划和可能性,以至于有时很难知道应该优先考虑哪些。最终,我们希望做对社区最有利的事情,因此我们非常重视这种持续的沟通。此外,因为我们是一个分布式社区,我们欢迎任何人带头项目,如果他们有这样做的动力。

纸空间。 最近,对 MLOps 感兴趣的人问你最多的问题是什么?你认为现在有足够的信息让人们开始参与进来吗?

布林克曼。 很少看到来自社区的重复问题(除非是关于 Jupyter 笔记本)——我认为这说明了社区的深度。每个人都在各自的公司努力应对自己的艰难挑战。有无限的方法来构建你的 ML 系统,正因为如此,我们从不缺少讨论点。人们通常希望了解 MLOps 生态系统中非常具体的问题和困难。这是它如此有趣的部分原因!

纸空间。 有没有什么即将到来的举措让你特别兴奋?

布林克曼。 有几个——工程实验室和 MLOps 堆栈项目是首先想到的。

工程实验室是每几个月启动一次的团队,为参与者提供了一个获得 MLOps 问题实践经验的机会。我们把每个人分成小组,给他们一个要解决的问题和一个截止日期,然后让他们放松!在小组结束时,我们要求每个人展示他们的作品,并为评审团认为最好的团队颁发不同的奖项!

MLOps Stacks 项目旨在简化不同开源 MLOps 工具栈的测试。该团队每周都会添加新的堆栈,并且所有这些都已融入您的环境。

纸空间。 多么了不起的社区和一套举措。我们喜欢看着社区成长,喜欢和这么多优秀的主题专家一起参与。你会如何推荐这个博客的读者参与进来,帮助 MLOps 发展成为一个社区和软件工程实践?

布林克曼。 第一件事就是通过 https://mlops.community/ 加入 Slack 群。一旦你加入,请联系我(@Demetrios),让我知道你是否有兴趣加入或领导任何计划。我们永远不会缺少事情去做,我们总是在寻找新的领导者!

如果你是 MLOps 社区的新手,请访问 https://mlops.community/ 并加入 Slack 群组。您还可以在 Twitter @mlopscommunityYouTube 上关注社区,查看所有最新的专家会议。

生成艺术和流动集体意识的科学

原文:https://blog.paperspace.com/interview-with-daniel-canogar-loom/

在与 Bitforms GallerySmall Data Industries 的合作中,Paperspace 采访了艺术家 Daniel Canogar ,他的作品 Loom 正在作为基于云的、24/7 的生成性软件艺术流的一部分呈现

丹尼尔出生在马德里,经常往返于美国和西班牙。他毕业于 NYU 大学,获得了摄影学位,并对作为媒介的投影图像产生了兴趣。在他的职业生涯中,他为美国自然历史博物馆欧盟创作了装置作品,他的个人作品也在时代广场帕克城的圣丹斯电影节展出。

我们非常兴奋有机会与丹尼尔谈论织机和他作为技术第一艺术家的经历。我们发现他对技术和社会的日常共享空间的洞察力是深刻的,值得深入研究。

Paperspace : 艺术和技术值得区分吗?在你心目中有什么不同?

卡诺加 : 我们忘记了艺术一直都有技术的成分。例子包括更精细的画笔和颜料的发展,用于画轮廓的暗箱的精细光学,以及透视系统的发展,这本身就是一项科学发明。我对艺术和技术的交叉如何成为当代现象并不感兴趣;相反,我着迷于了解这种交叉在过去如何发生的许多历史例子,也许意识到在许多方面,同样的老问题一次又一次地重新出现,但随着当前的技术而更新。

纸空间 : 你的第一个媒介是摄影。是什么让你涉足电影和公共装置?你的过程会随着每种媒体而改变吗?

Canogar : 我的确是从摄影师开始的,但我在技术上对媒介非常笨拙。我的底片总是布满灰尘(我是从数码摄影之前开始的),从来没有耐心去完善我的工艺。过了一段时间,我意识到摄影真正让我着迷的是暗室的体验:放大机投射的光和在感光纸上燃烧的图像,化学品的气味,红光,看到图像神奇地出现在一张白纸上的奇迹。这些都是我十几岁时形成的经验,至今仍存在于我现在的作品中。对我来说,开始思考投影图像、体验式装置艺术和使用技术作为实现这些创作的方式是很自然的。

Paperspace : 那么到底什么是生成艺术呢?

卡诺加 : 生成艺术基本上是算法艺术,一个算法被编码,建立一套处理数据的行为规则。一旦这些规则启动,艺术品就有了自己的生命,总是以新的和令人惊讶的方式重新组合信息。在许多方面,生成艺术更接近于行为艺术,而不是视频艺术:它有自己的生命,短暂,并且永远不会以完全相同的方式重复。一旦我开始研究生成艺术,我就再也不想回到录像时代。

Paperspace : 在创作生成艺术的时候,你是否已经对这件作品要表达什么有了一个想法,或者你是在分析了生成的东西之后才得出这个结论的?

卡诺加 : 创造生成性艺术作品的过程就是一场对话。我有一个初步的概念,我与我的程序员分享,还有草图,其他视觉参考,等等。他们开始工作,几天或几周后,他们给我看了艺术作品的初稿。这是与艺术品对话的开始。我仔细看了一下草稿,注意到什么可行,什么不可行,试着去听算法想告诉我什么。我的程序员发现了我与正在开发的作品之间的内部对话,并继续调整。我试着对这个过程保持开放,不强加我最初的概念和我想象中的艺术作品的样子,而是对这个过程中发生的许多令人惊讶的事情保持开放。不用说,在我们的创作过程中,我也会听取程序员的意见。经过无止境的调整,和一件不断变化的艺术品一起生活,我觉得我对这件作品有了深刻的了解,并准备好向世界发布它。

Paperspace : 未知结果的可能性会让你兴奋吗?

卡诺加 : 机缘巧合,同步性,意外的艺术。我也对失去对结果的控制感到兴奋。我已经看到了令人惊奇的事情发生在我从来没有计划过的生殖工作中。它挖掘出无限的组合可能性,让你超越可以计划、组织和控制的范围。例如,当我写这篇文章时,我刚刚看到一个词“抗议”在我的屏幕上滑动,我让织机运行,以一种令人不寒而栗的美丽精度捕捉我们现在生活的时刻。

https://player.vimeo.com/video/410150948?app_id=122963

Paperspace : 你如何选择一个装置的长度?对于织机,我想对这首曲子的理解会随着它是一天、一周、一个月还是一年而改变。你同意吗?

卡诺加 : 时间被织机等艺术品扭曲。真的没有过去,也没有未来。通过使用实时数据,它只存在于现在。与叙事相关的传统时间概念,即视频或电影的时长,并不适用。当考虑艺术品的寿命时,也许我们应该考虑作品何时消亡:当运行它的软件变得过时,再也找不到可以运行的计算机时。

Paperspace : 你认为在实体画廊中展示艺术和在数字微观世界中展示艺术有什么不同?在这个另类的空间里,你的观众对你有新的理解吗?

卡诺加 : 也许观众可能不会改变太多:那些在网上体验织机的人可能会去参观美术馆。我想他们通常对艺术感兴趣,会在线上和线下消费。从根本上改变的是在线观众的态度、情绪和倾向。他们使用屏幕进行多种活动,包括创建 Excel 表格、流式传输网飞,以及通过缩放连接到外部世界。这是一个拥挤繁忙的分享艺术品的平台。也许因为这个原因,我想创造一种宁静的、近乎沉思的艺术作品,来对抗银幕上的商业。

Paperspace : 你希望人们从这个装置中得到什么?

卡诺加 : 我真的希望人们能花些时间来看这部作品,不一定要不停地看,而是把它放在电脑屏幕上,偶尔浏览一下。通过与作品一起生活,你能够看到当前的事件在你面前展开,不是耸人听闻的突发新闻,而是一种诗意的体验。织机抓住了人们现在的想法。他们的在线搜索经过艺术提炼,以便更好地把握当下的集体意识。最重要的是,我希望人们会喜欢这件艺术品。

Paperspace : 你还有什么想分享的吗?

卡诺加 : 我要衷心感谢 Paperspace 让这件艺术品成为现实。没有你我们不可能成功!


一定要参观 Biforms Gallery 的首个虚拟艺术画廊,从 Canogar 的 Loom 开始,它将持续到 2020 年 6 月 9 日。在 Paperspace Core P6000 虚拟机的帮助下,Bitforms Gallery(与小数据合作)将在未来三个月内每周 7 天、每天 24 小时播放另外五幅作品。

将噪音转化为信号:利用人工智能获得科学研究的背景

原文:https://blog.paperspace.com/interview-with-josh-nicholson-scite-ai/

Josh Nicholson 是 scite ( www.scite.ai )的联合创始人兼首席执行官,该公司正在使用深度学习来分析科学文献的整体,以更好地衡量科学工作的准确性。

我们很高兴能和他坐下来,了解更多关于他非凡而雄心勃勃的机器学习项目。

Paperspace :你是如何产生 scite 的?

【尼克尔森:scite 的想法来自于这样一种观察,即癌症研究在独立测试时往往无法重现。这个问题在其他领域也存在,不仅仅是癌症研究。我们想找到一种方法来使科学研究更加可靠,机器学习使我们能够大规模地分析文献。

Paperspace :到目前为止,你对多少篇科学文章进行了分析?

尼克尔森: 到目前为止,我们已经分析了 16,158,032 篇文章中的 526,695,986 条引用语句,这个数字每天都在快速攀升。

:scite 如何帮助读者评价一篇科技文章?

尼克尔森 :通过 scite,我们正在努力引入智能引用。这些引用提供了每个引用的上下文及其含义。例如,我们想知道引用是否提供了支持或反驳的证据——而不仅仅是它之前被引用、浏览或下载的次数。这使得人们可以查看一项研究,并快速确定它是否得到了支持或反驳。

Paperspace :你从哪里获得数据来训练你的模型并创建引用图?

尼克尔森 : scite 通过与领先的学术出版商合作,利用开放获取的文章以及未开放的内容,如威利、IOP、洛克菲勒大学出版社、卡尔格、BMJ 等。

Paperspace :模型是如何工作的?

尼克尔森 : 在我们确定了引用及其上下文之后,我们的深度学习模型将引用语句分为三类:支持、反驳或提及。该模型已经在来自各种科学领域的数万个人工注释片段上进行了训练。

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

paper space:您的主要模型是否全天候运行?正在进行多少调优?

【尼克尔森 :它尽可能有效地运行,因为我们不断吸收新文章,并分析从中提取的引用语句。我们正在努力使这个过程完全自动化,这样一旦我们收到一篇新文章,它就会被处理并添加到数据库中。这些大部分是由 CPU 以及我们自己拥有和运行的 GPU 在云中完成的。

:每天都有那么多关于新冠肺炎的新信息出现。scite 如何跟上海量的入站数据?

【尼克尔森】 : 起初我们并没有真正关注新冠肺炎的研究,因为我不认为我们能提供什么。一篇新论文不会仅仅因为太新而被引用。然而,考虑到人们现在每天都在发布新的内容,某些出版物在几天内就会收到引用,而通常需要几个月或几年。例如,这篇预印本着眼于新冠肺炎与信号分子关系的严重性,仅在五天后得到了另一篇预印本的支持,我们能够用 scite 捕获该预印本。

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

:你最近通过机器学习模型运行了维基百科中的每一条引文。是什么让你想进行这项研究,你有什么发现?

【尼克尔森】 : 我们决定这样做是因为维基百科往往是许多试图更好地理解某些东西的人的第一站,也是唯一一站。我们发现大多数被引用的文章(58%)未经后续研究证实或测试,而其余的在矛盾或支持证据方面表现出很大的可变性(2- 40%)。这听起来很糟糕,但实际上与一般的科学文章没有太大的不同。事实上,维基百科上的科学文章比整个科学文献获得了更多的支持性引用。

我们发现真正有趣的是,文章引用的参考文献在文献中实际上并没有得到支持。例如,维基百科的文章自杀和互联网指出:“一项调查发现,与没有报告更严重自杀风险症状的在线用户相比,出于自杀相关目的上网的有自杀风险的个人更不愿意寻求帮助,也更少获得社会支持。”这句话引用了的一份科学报告,该报告与另一份的报告相矛盾,这只能通过查看 scite 才能看到。拥有这篇维基百科文章的额外信息可能会影响行为选择,这些行为选择可能会对大量人群产生潜在的生死后果。**

Paperspace :这个模型运行了多长时间?

尼科尔森 :我们花了大约一天的时间对大约 1500 万条引用语句进行分类,但这项研究对我们来说很容易完成,因为我们采用了已经完成的分类,然后只查看了维基百科中的文章。

Paperspace :你对 scite 的目标是什么?

我希望 scite 将有助于改变科学家的行为方式,奖励那些做出足够强的工作的人,以便其他人可以验证它,并奖励更多的公开辩论。科学从本质上影响着我们生活的方方面面,我们的使命是让科学更加可靠。

**如需了解更多关于 scite 的信息,请访问:【https://scite.ai/】

自动驾驶汽车理论导论

原文:https://blog.paperspace.com/intro-autonomous-vehicle-theory/

“任何足够先进的技术都和魔法没什么区别”~亚瑟·C·克拉克

我记得我被热门电视剧《硅谷》中的一个场景逗乐了,在这个场景中,角色 Jared 被困在一辆自动驾驶汽车中。他的目的地被意外覆盖,汽车试图带他到 Arallon。当他喊道:“汽车先生!车先生!”

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

自动驾驶汽车从未让我们感到惊讶。虽然我们中的一些人有机会乘坐无人驾驶汽车旅行,但实际上世界上只有一小部分人,大多数人可能不知道无人驾驶汽车是什么,尤其是无人驾驶汽车是如何工作的。本文旨在对此类汽车进行深入介绍。

无人驾驶汽车背后的动机

我们距离拥有真正的自动驾驶汽车还有很长的路要走。所谓真正的自动驾驶汽车,我们指的是一辆基本上可以像人类驾驶汽车一样以任何方式驾驶的汽车。这是一件非常难以实现的事情。

主要汽车公司一直试图实现真正的自动驾驶。这一想法背后的主要动机是:

  • 更安全的道路
  • 生产率增长
  • 更经济
  • 运动将会更有效率
  • 更加环保

致力于这一想法的公司包括但不限于——特斯拉、Pony.ai、Waymo、苹果、起亚现代、福特、奥迪和华为。

自动驾驶汽车中使用的基本术语

在我们进入自动驾驶汽车的工作之前,让我们熟悉一下其中使用的常用术语。

1)自治程度

**0 级(无驾驶自动化)😗*车辆由人类驾驶员手动控制,驾驶员监控周围环境并执行驾驶任务,即加速/减速和转向。集成支持系统,即盲点警告、停车和车道保持辅助系统,属于这一类,因为它们只提供警报,不以任何方式控制车辆。

**1 级(驾驶员辅助)😗*自动系统辅助转向或加速,但驾驶员会监控道路和车辆参数。自适应巡航控制和自动制动属于这一类

**2 级(部分自动化)😗*高级驾驶辅助系统(ADAS)可以控制转向和加速。司机依然执行监控任务,随时待命接管车辆。特斯拉 Autopilot 就属于这一类。

**第 3 级(有条件的自动化)😗*ADAS 被编程为具有环境检测功能,使用来自传感器的输入数据来控制车辆。这种汽车是自动驾驶而不是自主驾驶,可以在特定条件下自动驾驶,但在必要时仍需要人为干预。交通堵塞飞行员就属于这一类。

**第 4 级(高度自动化)😗*这个级别的自动驾驶车辆具有额外的能力,允许它在 ADAS 出现故障的情况下做出决策。人类乘客必须仍然存在。目前,它们通过地理围栏被限制在特定区域。它旨在用于无人驾驶出租车和公共交通,其中车辆行驶固定路线。

**第 5 级(全自动化)😗*ADAS 可以在不同的驾驶模式下导航和处理不同种类的驾驶条件,无需人工干预。这些车辆可以去任何地方,甚至没有人类乘客。他们预计不会有任何方向盘或踏板。

2)激光雷达

根据维基百科:

激光雷达是一种通过用激光瞄准物体并测量反射光返回接收器的时间来确定距离(可变距离)的方法。

在自动驾驶汽车中,激光雷达是汽车的眼睛。它基本上是一个 360 度旋转摄像机,可以检测到任何种类的障碍。

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

3)自适应

无人驾驶汽车的自适应行为意味着它可以根据周围环境设置参数。例如,如果汽车周围的交通流量很大,它会自动减慢速度。

4)自动驾驶仪

自动驾驶仪是一种无需任何手动控制就能自动控制车辆行驶的系统。它不仅用于自动驾驶汽车,还用于飞机和潜艇。

自动驾驶汽车的工作

自动驾驶汽车由三个必不可少的部分组成:车辆、系统硬件和驾驶软件。硬件和软件的完美结合实现了安全驾驶。一系列连续的步骤将前一步骤的输出作为下一步骤的输入。工作流程可以分为五个不同的阶段:

  1. 感知:要采取的主要行动是从周围环境中收集数据,这是通过不同种类的传感器“看”和“听”来完成的。三个主要的传感器,相机,雷达和激光雷达,作为人类的眼睛和大脑一起工作。然后,车辆处理原始信息,从中获得意义。计算机视觉是通过卷积神经网络来实现的,以从相机馈送中识别对象。

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

Image Source

2.**识别:**软件然后处理这些输入,绘制路径,并向车辆的“执行器”发送指令,这些执行器控制加速、制动和转向。硬编码规则、避障算法、预测建模和“智能”物体识别()。知道自行车和摩托车的区别)帮助软件遵守交通规则和穿越障碍。这些系统通过各种接收器(如相机、雷达、激光雷达和导航地图)收集有关车辆、驾驶员和周围环境的数据,然后分析情况,并在驾驶方面做出适当的决策。这表明车辆需要连接到道路上的其他车辆,以及与道路和条件相关的不同类型信息的整体基础设施。车辆及其系统的相互连接程度,以及与其他车辆和多个信息提供者的连接程度变得非常重要。需要分析这些信息,由此产生的步骤将有助于自动驾驶汽车的决策方面。

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

Image Source

硬件组件

硬件组件分为三个主要角色,以完成诸如使用传感器进行观察、使用 V2V 技术进行通信以及通过致动器进行移动等任务。

  1. 传感器融合:传感器可以被认为类似于人的眼睛,使车辆能够吸收周围环境的信息。为了创建高质量的重叠数据模式,不同的传感器收集不同种类的数据,但一起工作以形成一致的观察系统。对于 360 度画面,来自所有传感器的输入以 1 GB/s 的速度合并。使用的包括:相机,激光雷达,雷达。

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

Image Source

  1. V2X tech :这些部件类似于人的嘴巴和耳朵。V2X 代表车辆到一切或车辆到 X,涉及从车辆到与其操作相关的任何对象的信息流,反之亦然。它们旨在允许自动驾驶汽车与另一辆汽车或其他连接系统(如交通灯)进行“对话”。根据目的地,它们可以分为:
  • V2I(车辆到基础设施):汽车和安装在道路旁边的设备之间的数据交换,用于向司机传递交通状况和紧急信息。
  • V2N(车联网):基于云服务的网络接入
  • V2V(车对车):车辆之间的数据交换。
  • V2P(车辆对行人):汽车和行人之间的数据交换。

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

Image Source

3.致动器:这个部分类似于人类肌肉对大脑发出的神经冲动做出反应。致动器由处理器控制执行物理活动,例如制动和转向。

自动驾驶汽车中使用的机器学习算法

软件组件

对于所有意图和目的,软件可以被认为是自动驾驶汽车的大脑。简而言之,在现实生活中训练的算法从传感器获取输入数据,并从中获取意义,以做出必要的驾驶决策。绘制出最合适的路径,并将相关指令传送给执行器。

ADAS 中包含的算法必须引导车辆通过自动驾驶的 4 个主要阶段:

  • 感知:通过对象检测和分类以及邻域中的必要参数来分析障碍物
  • 定位:定义车辆相对于周围区域的位置
  • 规划:考虑感知和定位阶段的数据,规划从当前位置到目的地的最佳路径
  • 控制:以适当的转向角和加速度值跟踪轨迹。

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

Image Source

卷积神经网络(CNN)

CNN 的是第一选择,当谈到特征提取,由于其高精度。其特点在于卷积层,它通过使用滤波器矩阵或内核执行卷积来减少数据。内核通常是 3×3 或 5×5 像素,在输入图像上滑动,并且在矩阵与其所包围的图像的像素值之间获得数学点积。该结果值被分配到特征图中,该特征图表示关于诸如边或角的特征的数据。更深的层将捕捉更复杂和全面的特征,例如物体的形状。CNN 的输出被提供给激活函数,以在数据之间引入非线性关系。ReLU(整流线性单元)是最常用的一种,因为它收敛很快。max-pooling 层用于数据简化,携带有关图像背景和纹理的信息。总的来说,该模型被训练以在不过度拟合的情况下获得最高的精度,然后被应用到真实世界的情况中进行对象检测和分类。

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

Image Source

自动驾驶汽车中使用的特定 CNN 有

  • 特斯拉的 HydraNet
  • 谷歌 Waymo 的司机网
  • 英伟达自动驾驶汽车
尺度不变特征变换

这种算法通过图像匹配和识别来解决部分可见物体的问题,通过提取所讨论的物体的区别特征来实现。例如,考虑一个停止标志的八个角。这些特征不会随着旋转、缩放或噪声干扰而改变,因此它们被认为是比例不变的特征。系统记录并存储对象和特征之间的关系。拍摄图像,将提取的特征与数据库中的 SIFT 特征进行比较。相比之下,车辆因此可以识别物体。

模式识别的数据简化算法

通过传感器融合接收的图像包含不必要的和重叠的数据,这些数据必须被过滤掉。为了确定特定对象类的出现,使用重复模式来帮助识别。这些算法通过将线段拟合到拐角,将圆弧拟合到类似弧形的元素,来帮助减少噪声和不重要的数据。这些线段和圆弧最终组合在一起,形成特定对象类特有的可识别特征。

自动驾驶汽车使用的具体算法有

  • 主成分分析(PCA):降低数据的维度。
  • 支持向量机(SVM):优秀的非概率二元线性分类。
  • 梯度方向直方图(HOG):非常适合人体检测
  • 你只看一次(YOLO):HOG 的一个替代方案,它根据整个图像的上下文来预测每个图像部分。
聚类算法

由于低分辨率或模糊的图像、间歇或稀疏的数据,分类算法可能很难检测到对象,并且可能会完全错过它们。聚类查找数据中存在的内在结构,以便根据最大数量的共同特征对它们进行分类。

自动驾驶汽车中使用的特定聚类算法有:

  • K-means: k 个质心用于定义不同的聚类。数据点被分配到最近的质心。随后,质心移动到聚类中点的平均值。
  • 多类神经网络:涉及使用数据中的固有结构将数据组织成具有最大共享特征的分组。
回归学习算法

与奇异博士不同,这些算法试图预测未来的情景。环境中的重复特征被用于算法的优势,以建立给定图像和特定对象在其中的位置之间的关系的统计模型。计算最少两个变量之间的关系,然后使用回归分析在不同尺度上进行比较。它的依赖关系是回归线的形状、因变量的类型和自变量的数量。最初,模型是离线学习的。当模型处于活动状态时,它对图像进行采样以进行快速检测,从而输出对象的位置及其对该位置的确定性。该模型可进一步应用于其他实体,无需额外建模。

自动驾驶汽车中使用的具体算法有

  • 随机森林回归
  • 贝叶斯回归
  • 神经网络回归

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

Image Source

决策算法

顾名思义,确定正确的选择是这些算法的全部内容。多个模型被分别训练和组合以给出具有最小误差的包含性预测。该决策考虑了算法在对象的识别、分类和运动预测中的置信度。

自适应增强(Adaboost) 是最流行的算法框架之一。它本质上是将一系列在加权数据上训练的弱学习器(低精度)组合成一个集成,以便所涉及的算法相互补充并提高最终性能,从而获得准确的分类器。

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

Image Source

让我们使用上面的图表来理解它是如何工作的。在原始未加权数据集中,正数据点用红色叉号表示,负数据点用蓝色减号表示。第一个模型能够正确地分类三个否定点和四个肯定点,但是也错误地分类一个肯定点和两个否定点。这些错误分类的点被赋予较高的权重,并作为输入来建立第二个模型。第二个模型中的决策边界已经转移,以正确地分类先前的错误,但是在该过程中,错误地分类了三个不同的点。权重被更新以给予新的误分类点更高的值,并且该迭代继续,直到满足指定的条件。我们可以看到,所有模型都有一些错误分类的数据点,因此,它们是弱学习器。通过对模型进行加权平均,这些模型覆盖了其他模型的弱点,并且所有的点都被正确分类,这表明最终的集成模型是强学习器。

TextonBoost 工作原理相同。它使用 textons:具有相同特征的图像数据簇,因此对滤波器的响应相同。它将外观、形状和上下文结合在一起,将图像视为一个整体,并收集上下文信息以理解其关系。例如,船像素总是被水像素包围。

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

Image Source

自动驾驶汽车面临的挑战

自动驾驶汽车自诞生以来已经走过了漫长的道路,但由于涉及的高风险,必须完美地解决技术和安全挑战。在我们能够在道路上看到这些车辆之前,还有一些障碍需要克服。前面的一些障碍是:

  1. 无法理解复杂的社会互动:人类驾驶并不完美,驾驶员通常依靠来自周围环境的社交能力来导航,如眼神交流和手势。与骑自行车的人和行人的互动主要需要对机器人仍然缺乏的社交线索和微妙之处做出反应。到目前为止,自动化系统需要能够理解环境,以及为什么他们遇到的人会有这样的行为,以便能够对每个怪癖做出反应。
  2. 不适用于所有天气条件:在恶劣的天气条件下,自动驾驶汽车将难以解释低能见度情况和失去牵引力。传感器被雪、冰覆盖或被大雨遮挡会降低有效性。此外,厚厚的积雪掩盖了标志和车道标志。传感器上的微型雨刷的解决方案工作良好。
  3. 自动驾驶的地图绘制是复杂的:在任何自动驾驶汽车能够驾驶之前,它必须需要一个预定义地图的组合,这些地图带有分类的障碍物,用作导航路线的参考。随着时间的推移,区域和道路特征会发生变化,需要不断更新。构建和维护这些 3D 地图是一个耗时的过程,并且需要大量资源。完全自动驾驶的汽车也仅限于完全地图化的区域。
  4. 缺乏基础设施:必须为这些车辆提供合适的驾驶环境,但这并不总是可行的,尤其是在发展中国家。即使相距 10 公里,道路基础设施也可能不同。向智能基础设施(包括物联网系统、交通灯连接和 V2V)的过渡非常缓慢。
  5. 网络安全问题:联网汽车中的数字安全是最关键的问题之一。车辆连接得越紧密,就越容易找到攻击系统的方法。人们害怕对汽车软件或部件的网络攻击。
  6. 事故责任:事故发生时的责任问题仍在争论中。要么是乘客,要么是制造商。错误可能是致命的,并耗费人的生命。

自动驾驶汽车的未来

目前,市场上的自动驾驶汽车主要属于 1 级和 2 级,包括特斯拉。经过严格的测试和研究,3 级原型车正慢慢向公众开放,例如本田有限发布的豪华轿车 Legend。自动驾驶汽车的发展已经取得了惊人的进步;然而,研究人员推测,完全自动驾驶汽车还需要几十年才能实现。即使在生产之后,最初,它们也最有可能在工业中被限制使用,以在固定路线上完成自动化任务。

在自动驾驶汽车日益增长的前景中,另一个需要考虑的角度是它们是否会被用于个人用途或用作服务车辆,如出租车、货运或公共交通。通用汽车等传统公司打算在未来向公众零售这些车辆,而 Waymo、AutoX 和特斯拉等新公司打算运营或已经运营 robotaxis。大众汽车(Volkswagen)等其他公司计划以订阅方式租赁这些车辆,客户按小时付费。谷歌的 Waymo 从 2020 年底开始在美国选定的城市中以每周 1000-2000 次的速度运营 4 级 robotaxis。在一个类似的展览中,AutoX 在上海部署了一支由 75 台机器人组成的车队,向公众开放。在大规模采用之前,这些机器人轴的功能中的许多缺陷和问题仍需要纠正,因为机器人在面对复杂情况时仍需努力。

这起事故涉及一辆特斯拉汽车,造成两人死亡,凸显了围绕自动驾驶汽车的安全不确定性。部署的 2 级车辆中的碰撞被推断为人为错误的结果,但汽车制造商有责任建立考虑到人为疏忽和疏忽因素的自主系统。建造 5 级自动驾驶汽车的技术可能比适当的安全和法律法规更容易获得。公众接受是自动驾驶汽车整合的一个重要因素。人类天生对陌生技术带来的变化抱有偏见。至关重要的是,制定公共安全法规时要考虑赢得公众的信任。

用 R 对数据分类的简单介绍

原文:https://blog.paperspace.com/intro-to-datascience/

垃圾邮件还是火腿?

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

我们生成的大部分数据都是非结构化的。这包括算法可能无法立即理解的文本、音频、视频和图像等来源。然而,想象一下,如果一个人必须单独地将每一封电子邮件分类到你的收件箱或垃圾邮件文件夹中!幸运的是,数据科学最令人兴奋的领域之一,尤其是机器学习,是处理这些数据源并找到对这些数据进行有意义分析的方法的任务。

在本文中,我们将构建一个垃圾邮件过滤器,我们可以用它来将文本消息分类为垃圾邮件,即合法邮件和垃圾邮件。这个例子将介绍文本作为数据源,以及帮助说明一些常见的机器学习概念。虽然本教程是为初学者设计的,但是对 R 统计语言不太熟悉但感兴趣的更有经验的用户可能会发现这个实现很有帮助。请随意编码!

R 中文本数据的一些基础知识

要构建垃圾邮件过滤器,我们首先需要将纯文本消息转换成我们的模型可以理解的格式。具体来说,我们需要用字数或频率来表示我们的文本信息。一旦以这种格式表示,就可以使用各种统计模型和程序来理解这些数据。这被称为自然语言处理。

我们可以通过首先将文本文件加载到统计软件包中来做到这一点。本教程将使用强大且广泛使用的统计语言 R,并通过 R Studio 来实现。有关在您的机器上安装和设置 R 的更多信息,请查看此链接。你需要的软件和软件包都是开源的。

让我们加载两个包: quantedaRColorBrewer 。前者是一个流行的文本数据统计分析包,后者为我们将要生成的图形提供了一套颜色选项。library()命令指示 R 加载这些已经安装的包。如果您不熟悉 R(或这些包),那么在从您的库中访问它们之前,用install.packages("")替换这个命令来安装这些包。

library(quanteda) 
library(RColorBrewer) 

加载我们的包后,让我们从这里导入一个公开可用的垃圾短信/垃圾邮件数据集,这是在 Almeida 等人中介绍的。

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

我们从自述文件中了解到,该数据集表示为一个纯文本文件,其中列出了带有相关联的垃圾邮件标签的 SMS 消息内容。短信 5574 条,其中垃圾短信占 13.4%,合法短信占 86.6%。我们的挑战是构建一个监督机器学习分类器,它可以完全独立地分离这两种类型。

首先从上面的 URL 下载数据,然后将您的 R 工作目录设置为您下载文件的文件夹。这告诉 R 在你的计算机上哪里寻找数据。最后,使用read.table命令将数据读入 R,并用引号指定文件名。括号中的其他参数告诉 R 如何读取纯文本文件。我们将使用<-将这个 SMS 消息集合命名为“raw.data”。

setwd("~/Your Folder Path")
raw.data <- read.table("SMSSpamCollection", header=FALSE, sep="\t", quote="", stringsAsFactors=FALSE) 

如果您在尝试导入数据时遇到任何错误消息,请查看 StackExchangeStackOverflow 以获得有用的建议。实际上,数据导入可能是比较繁琐的任务之一!

让我们给这两列信息添加标题。我们将第一列称为“标签”,第二列称为“文本”。这将使我们在以后的分析中容易记住和调用这些变量。最后,我们可以检查垃圾邮件的数量,以再次检查我们的数据是否正确导入。

names(raw.data) <- c("Label", "Text")
table(raw.data$Label) 

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

看起来我们正在处理 4,827 条垃圾邮件和 747 条垃圾邮件。这与数据集的自述文件中的数据描述相符,所以我们应该可以开始了。

我们在数据导入阶段要做的最后一件事是使用sample()命令随机化我们的数据。以防数据不是以随机分布存储的,这将有助于确保我们处理的是从数据中随机抽取的数据。set.seed()命令只是为了确保更加一致的复制,这样您的结果应该反映本教程中的结果。

set.seed(1912)
raw.data <- raw.data[sample(nrow(raw.data)),] 

您可以使用View()命令查看数据的样子。您会注意到,我们已经将一个纯文本文件变成了一个存储良好的数据帧,其中包含带标签的标题和随机观察。

在我们开始构建分类模型之前,让我们用一种直观的可视化方式来感受一下我们的数据:单词 cloud。然后,我们可以从视觉上检查图像,以查看 ham 和垃圾邮件之间的语言是否有所不同。

在自然语言处理中,我们喜欢处理语料库对象。语料库可以被认为是我们的数据集的主副本,我们可以根据需要从中提取子集或观察值。我们将使用quantedacorpus()命令从原始数据的文本字段构建一个语料库,我们可以将其命名为sms.corpus。然后,使用docvars()命令将标签字段作为文档变量附加到语料库。我们将 Label 作为一个变量直接附加到我们的语料库,以便我们可以在稍后的分析中将 SMS 消息与其各自的 ham/spam 标签相关联。

sms.corpus <- corpus(raw.data$Text) 
docvars(sms.corpus) <- raw.data$Label 

随着我们的主语料库的建立,我们现在可以将其分为垃圾邮件和业余邮件,以构建单词云,并查看它们使用的语言的差异。单词显示得越大,该单词在我们的数据中出现的频率就越高。

首先,将语料库分成垃圾邮件子集。请记住,我们需要将这些单词转换成计算机可以计数的东西。因此,使用dfm()命令构建一个文档术语频率矩阵(DFM ),并删除一些杂乱的内容,比如标点符号、数字和经常出现的单词,它们可能没有什么有意义的信息。这就是所谓的词汇袋方法。

spam.plot <- corpus_subset(sms.corpus, docvar1 == "spam")
spam.plot <- dfm(spam.plot, tolower = TRUE, removePunct = TRUE, removeTwitter = TRUE, removeNumbers = TRUE, remove=stopwords("SMART")) 

构建了 DFM 之后,让我们绘制垃圾邮件词云。我们将使用RColorBrewer包中的brewer.pal命令根据词频给单词图着色。我们也可以给情节加个标题。

spam.col <- brewer.pal(10, "BrBG")
spam.cloud <- textplot_wordcloud(spam.plot, min.freq = 16, color = spam.col)
title("Spam Wordcloud", col.main = "grey14") 

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

注意像“免费”、“紧急”和“客户”这样的词。当想到垃圾邮件时,这些词可能会直观地出现在脑海中,因此我们可能会有所发现。我们现在可以对 ham 消息重复这个编码过程,并比较两个云。

ham.plot <- corpus_subset(sms.corpus, docvar1 == "ham")
ham.plot <- dfm(ham.plot, tolower = TRUE, removePunct = TRUE, removeTwitter = TRUE, removeNumbers = TRUE, remove=c("gt", "lt", stopwords("SMART")))
ham.col <- brewer.pal(10, "BrBG")
textplot_wordcloud(ham.plot, min.freq = 50, colors = ham.col, fixed.asp = TRUE)
title("Ham Wordcloud", col.main = "grey14") 

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

注意像“家”、“时间”和“爱”这样的词。这似乎比垃圾邮件中出现的词语更具个人色彩。我们的直觉——这些信息中使用的词语应该不同——似乎得到了验证。现在,让我们继续构建一个机器学习模型,该模型可用于自动将消息分类为垃圾邮件或垃圾邮件类别。

DIY:构建垃圾邮件过滤器

想象你正在阅读一部新电影的评论。你会注意到一些五星评论包括“优秀”或“极好”这样的词。也许一些一星评论包括“可怕”或“糟糕”这样的词。事实上,你会变得非常擅长阅读电影评论,以至于你可以根据评论者使用的单词类型准确预测与给定评论相关的星级。

这是我们任务背后的直觉。在机器学习中,这被称为“有监督的”学习问题。更具体地说,它也被称为“分类”任务。它是受监督的,因为您提供了模型监督:您对标记为垃圾邮件或 ham 的数据训练模型,以便它可以学习垃圾邮件或 ham 消息的样子。这是一个分类问题,因为该模型试图根据新文本消息的内容将新文本消息分类为垃圾邮件或垃圾邮件。

我们可以使用一个简单的朴素贝叶斯分类器来完成这项任务。关于贝叶斯分类器的更多信息,请看这篇 StackOverflow 帖子。简而言之,贝叶斯分类器是基于贝叶斯定理的简单概率分类器,具有强特征独立性假设。

我们已经将我们的文本消息作为语料库(数据的主副本)导入,所以下一步是以 DFM 的形式将文本消息表示为字数。通常,我们会想要丢弃标点符号、数字和常用词,因为这些通常没有什么预测能力。然而,在对短信进行分类的情况下,研究人员发现,包含这样的信息可以提高性能。因此,我们将只对这些数据进行最低限度的预处理,并对字数进行加权。

sms.dfm <- dfm(sms.corpus, tolower = TRUE)
sms.dfm <- dfm_trim(sms.dfm, min_count = 5, min_docfreq = 3)
sms.dfm <- dfm_weight(sms.dfm, type = "tfidf") 

现在,我们需要将数据分成训练样本和测试样本。训练样本训练我们的模型,即帮助它学习火腿和垃圾邮件的样子。然后,可以使用测试样本来测试模型,看它的表现如何。让我们使用 85%的数据来训练我们的模型,看看它能在多大程度上预测剩余 15%数据的垃圾邮件或火腿标签。

在 R 中,我们可以通过调用数据名来对数据进行子集化,并使用方括号对其进行修改。我们数据的前 85%大约对应于第 4738 次观察。剩余的 15%将是最后一行的第 4,739 号(即数据集的nrow())。我们将对原始数据和我们的 DFM 都这样做,这样我们就有了模型所需的一切。

sms.raw.train <- raw.data[1:4738,]
sms.raw.test <- raw.data[4739:nrow(raw.data),]

sms.dfm.train <- sms.dfm[1:4738,]
sms.dfm.test <- sms.dfm[4739:nrow(raw.data),] 

通过将我们的数据分为训练和测试数据集,我们将训练我们的朴素贝叶斯模型,并告诉模型注意文本消息的内容以及消息的垃圾邮件标签。然后,我们将使用经过训练的模型来预测新的测试观察结果本身是垃圾邮件还是有害邮件。最后,我们将制作一个列联表,看看它的执行有多准确。

quanteda包允许我们使用textmodel_NB命令直接访问朴素贝叶斯分类模型。我们插入我们的训练 DFM,我们将其命名为sms.dfm.train,并使用sms.raw.train$Label插入与训练文档相关联的标签向量。我们称之为我们的sms.classifier

sms.classifier <- textmodel_NB(sms.dfm.train, sms.raw.train$Label) 

这产生了一个合适的模型,即一个经过训练的分类器。现在让我们使用这个模型来预测我们的测试数据的垃圾邮件/火腿标签。这意味着我们只给这个模型提供没有标签的文本信息。我们可以通过predict()命令传递我们拟合的模型sms.classifier,指定我们的sms.dfm.test数据作为进行预测的新数据。最后,table命令允许我们查看模型预测的结果。

sms.predictions <- predict(sms.classifier, newdata = sms.dfm.test)
table(sms.predictions$nb.predicted, sms.raw.test$Label) 

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

应该从左到右阅读该表:该模型将 703 条 ham 消息正确地分类为 ham,将 8 条 ham 消息错误地分类为垃圾邮件。该模型错误地将 9 条垃圾邮件分类为 ham,但是将 116 条垃圾邮件正确地分类为 spam。

通过将正确的分类数除以尝试的分类总数,我们发现我们的模型正确地分类了 98.9%的垃圾邮件和 92.8%的垃圾邮件。因此,每收到 100 封邮件,就有一封合法邮件可能会意外地出现在您的垃圾邮件文件夹中。如果你收到 100 封垃圾邮件,其中 7 封可能会偷偷通过垃圾邮件过滤器,最终进入你的收件箱。对于一个简单的分类器来说,这是非常令人印象深刻的!有关评估该模型的更多信息,请查看这篇 StackExchange 帖子

结束语

在本教程中,我们简要讨论了如何将文本作为数据处理,并在 r 中完成了导入和可视化该数据的过程。我们还概述了机器学习中监督分类问题的逻辑,并通过构建一个简单的垃圾邮件过滤器来说明这些概念。

这个例子只是文本数据分析的众多应用之一。如果您对这个主题感兴趣,请阅读 R 的quanteda包,以及用于文本挖掘的 tm 包和用于文本机器学习分类的 RTextTools 包。对实现统计过程更感兴趣的读者可能会发现流行的 e1071 包很有帮助。关于数据集和相关研究的更多信息可以从这篇论文和这篇论文中找到。

希望看到这些机器学习概念的运行有助于使它们的直觉和应用更加具体。也许这也说明了这些模型的潜力——我们建立了一个相对准确的模型,能够在不到一秒钟的时间内对数百条短信进行排序。感谢阅读和快乐编码!

要开始设置自己的简历,请在此注册。

深度学习中的优化介绍:梯度下降

原文:https://blog.paperspace.com/intro-to-optimization-in-deep-learning-gradient-descent/

图片来源:奥赖利媒体

深度学习在很大程度上实际上是解决大量讨厌的优化问题。神经网络仅仅是一个非常复杂的函数,由数百万个参数组成,代表一个问题的数学解决方案。考虑图像分类的任务。AlexNet 是一个数学函数,它采用一个表示图像 RGB 值的数组,并以一组类分数的形式产生输出。

通过训练神经网络,我们基本上意味着我们正在最小化损失函数。这个损失函数的值为我们提供了在给定数据集上我们的网络性能离完美有多远的度量。

损失函数

为了简单起见,让我们假设我们的网络只有两个参数。实际上,这个数字大约是 10 亿,但是我们仍然会在整篇文章中坚持使用两个参数的例子,这样我们就不会在试图可视化事物的时候把自己逼疯。现在,一个非常好的损失函数的计数可能是这样的。

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

损失函数的轮廓

为什么我说一个很好听的损失函数?因为具有如上轮廓的损失函数就像圣诞老人一样,它不存在。然而,它仍然是一个不错的教学工具,可以让你全面了解梯度下降的一些最重要的观点。所以,让我们开始吧!

xy 轴代表两个权重的值。 z 轴代表两个权重的特定值的损失函数值。我们的目标是找到损失最小的特定重量值。这种点被称为损失函数的最小值**。**

**你在开始时已经随机初始化了权重,所以你的神经网络很可能表现得像喝醉了的你,把猫的图像归类为人类。这种情况对应于轮廓上的点 A,在该点处网络性能差,因此损耗高。

我们需要找到一种方法,以某种方式导航到“谷底”的 B 点,在那里损失函数有一个最小值?那么我们该怎么做呢?

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

梯度下降

梯度下降

当我们初始化我们的权重时,我们在损失图中的 A 点。我们做的第一件事是在 x-y 平面的所有可能的方向中,检查沿着哪个方向移动带来损失函数值的最大下降。这是我们必须前进的方向。该方向由与梯度方向完全相反的方向给出。梯度,导数的更高维度的表亲,给了我们上升最快的方向。

要理解这一点,请考虑下图。在曲线的任意一点,我们可以定义一个与该点相切的平面。在更高的维度中,我们总是可以定义一个超平面,但现在让我们坚持 3-D。那么,我们可以在这个平面上有无限个方向。在这些方向中,恰好有一个方向会给我们函数上升最快的方向。这个方向是由梯度给出的。与之相反的方向是最陡下降的方向。这就是算法如何得到它的名字。我们沿着梯度的方向下降,因此,它被称为梯度下降。

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

现在,一旦我们有了我们想要前进的方向,我们必须决定我们必须采取的步骤的大小。这一步的大小称为学习速率。我们必须仔细选择它,以确保我们能达到最低限度。

如果我们走得太快,我们可能会超过最小值,并继续沿着“谷”的脊反弹,永远不会达到最小值。走得太慢,训练可能会变得太长,根本不可行。即使事实并非如此,非常慢的学习速度会使算法更容易陷入极小值,这一点我们将在本文后面讨论。

一旦我们有了梯度和学习率,我们走一步,在我们结束的任何位置重新计算梯度,并重复这个过程。

虽然梯度的方向告诉我们哪个方向的上升最陡,但它的大小告诉我们最陡的上升/下降有多陡。所以,在最小值,轮廓几乎是平的,你会期望梯度几乎为零。事实上,对于极小点来说,它正好是零。

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

动作中的梯度下降

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

使用过大的学习率

实际上,我们可能永远不会精确地达到最小值,但是我们在极小值附近的平坦区域保持振荡。当我们在这个区域振荡时,损耗几乎是我们可以达到的最小值,并且不会改变太多,因为我们只是在实际最小值附近不断反弹。通常,当损失值在预先确定的次数内没有改善时,比如说 10 次或 20 次迭代,我们就停止迭代。当这样的事情发生时,我们说我们的训练已经收敛,或者说已经发生了收敛。

常见的错误

让我离题一下。如果你在谷歌上搜索梯度下降的可视化效果,你可能会看到一条从一个点开始并向一个极小点前进的轨迹,就像上面展示的动画一样。然而,这给了你一个非常不准确的梯度下降图。我们取的轨迹完全局限于 x-y 平面,这个平面包含了重量。

如上面的动画所示,梯度下降根本不涉及在 z 方向移动。这是因为只有权重是自由参数,由 xy 方向描述。我们采用的实际轨迹在 x-y 平面中定义如下。

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

真实梯度下降轨迹

x-y 平面上的每个点代表一个唯一的权重组合,我们希望有一组由最小值描述的权重。

基本方程

描述梯度下降更新规则的基本方程是。

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

这种更新在每次迭代期间执行。这里, w 是位于 x-y 平面的权重向量。从这个向量中,我们减去损失函数相对于乘以α学习速率的权重的梯度。梯度是一个矢量,它给出了损失函数上升最快的方向。最陡下降的方向是与梯度完全相反的方向,这就是为什么我们要从权重向量中减去梯度向量。

如果想象向量对你来说有点困难,那么几乎相同的更新规则同时应用于网络的每个权重。唯一的变化是,因为我们现在对每个权重单独执行更新,所以上面等式中的梯度被替换为梯度向量沿特定权重表示的方向的投影。

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

对所有权重同时进行这种更新。

在减法之前,我们用学习率乘以梯度向量。这代表了我们之前谈到的步骤。要意识到,即使我们保持学习速率不变,步长也会因梯度的大小而变化,而不是损失轮廓的陡度。当我们接近最小值时,梯度接近零,我们向最小值迈越来越小的步。

理论上,这是好的,因为我们希望算法在接近最小值时采取更小的步骤。步长太大可能导致它超过最小值并在最小值的脊之间反弹。

梯度下降中广泛使用的技术是具有可变的学习率,而不是固定的学习率。最初,我们可以负担较大的学习率。但是后来,当我们接近最小值时,我们想放慢速度。一种实现这种策略的方法被称为模拟退火,或衰减学习率。在这种情况下,学习率在每固定数量的迭代中衰减。

梯度下降的挑战#1:局部最小值

好吧,到目前为止,梯度下降的故事似乎是一个真正快乐的故事。好吧。让我来给你捣乱吧。还记得我说过我们的损失函数很好看吗,这样的损失函数并不真的存在?他们没有。

首先,神经网络是复杂的函数,在我们的假设函数中有许多非线性变换。最终的损失函数看起来不像一个漂亮的碗,只有一个我们可以收敛的最小值。事实上,这种漂亮的圣诞老人般的损失函数被称为函数(总是向上弯曲的函数),深网的损失函数几乎不是凸的。事实上,它们可能是这样的。

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

在上面的图像中,存在一个梯度为零的局部最小值。但是,我们知道它们并不是我们能达到的最低损失,这是全局极小值对应的点。现在,如果你在 A 点初始化你的权重,那么你将会收敛到局部极小值,一旦你收敛到局部极小值,梯度下降就不可能让你离开那里。

梯度下降是由梯度驱动的,梯度在任何最小值的底部为零。因为损失函数的值在局部区域中的该点是最小的,所以称为局部最小值。然而,全局最小值之所以被称为全局最小值,是因为损失函数的值在此处最小,在整个域上损失函数是全局的。

更糟糕的是,考虑到我们正在考虑的三维等高线实际上从未出现过,损失等高线甚至可能更加复杂。在实践中,我们的神经网络可能有大约 10 亿个权重,给我们一个大致(10 亿+ 1)维的函数。我甚至不知道那个数字中零的个数。

事实上,很难想象如此高维的函数。然而,鉴于目前深度学习领域的纯粹天赋,人们已经想出了在 3d 中可视化损失函数轮廓的方法。最近的一篇论文开创了一种称为过滤归一化的技术,解释了这超出了本文的范围。然而,它确实给了我们一个关于我们处理的损失函数的潜在复杂性的观点。例如,以下等值线是在 CIFAR-10 数据集上构建的 VGG-56 深度网络损失函数的损失等值线的三维表示。

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

一个复杂的失落景观 图片来源:https://www.cs.umd.edu/~tomg/projects/landscapes/

正如你所看到的,损失景观充满了当地的最小值。

梯度下降的挑战#2:鞍点

关于梯度下降的限制,我们得到的基本教训是,一旦它到达梯度为零的区域,不管最小值的质量如何,它几乎不可能逃脱。我们面临的另一个问题是鞍点,看起来像这样。

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

一个鞍点

你还可以在之前的图片中看到两座“山”交汇处的鞍点。

鞍点的名字来源于一匹马的马鞍,因为它很像它。虽然它在一个方向上是最小值( x ),但它在另一个方向上是局部最大值,如果轮廓在 x 方向上更平坦,GD 将在 y 方向上不断来回振荡,给我们一种已经收敛到最小值的错觉。

随机救援!

那么,我们如何摆脱局部最小值和鞍点,同时试图收敛到一个全局最小值。答案是随机性。

到目前为止,我们一直在使用损失函数进行梯度下降,该损失函数是通过对训练集的所有可能示例的损失求和而创建的。如果我们陷入局部极小值或鞍点,我们就被困住了。帮助 GD 避开这些的一个方法是使用所谓的随机梯度下降。

在随机梯度下降中,我们不是通过计算所有损失函数相加产生的损失函数的梯度来采取步骤,而是通过计算仅一个随机采样(无替换)实例的损失梯度来采取步骤。与随机选择每个样本的随机梯度下降相反,我们早期的方法在一个批次中处理所有样本,因此被称为批次梯度下降。

相应地修改更新规则。

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

更新随机梯度下降规则

这意味着,在每一步,我们都要对一个损失函数求梯度,这个损失函数不同于我们实际的损失函数(它是每个例子损失的总和)。这种“单一实例损失”在某一特定点上的梯度实际上可能指向与“全部实例损失”的梯度略有不同的方向。

这也意味着,虽然“所有示例损失”的梯度可能会将我们推下局部最小值,或让我们卡在鞍点,但“一个示例损失”的梯度可能会指向不同的方向,并可能帮助我们避开这些。

人们也可以考虑一个点,它是“所有示例损失”的局部最小值。如果我们做批量梯度下降,我们会在这里卡住,因为梯度总是指向局部最小值。然而,如果我们使用随机梯度下降,这个点可能不在“一个例子损失”的损失轮廓中的局部最小值附近,允许我们远离它。

即使我们陷入了“一个示例损失”的最小值,下一个随机采样数据点的“一个示例损失”的损失前景可能会不同,这允许我们继续前进。

当它收敛时,它收敛到一个点,该点是几乎所有“单例损失”的最小值。它也显示了鞍点是非常不稳定的,轻轻一推就足以逃脱。

那么,这是否意味着在实践中,应该总是执行这种单示例随机梯度下降?

批量

答案是否定的。虽然从理论的角度来看,随机梯度下降可能会给我们最好的结果,但从计算的角度来看,这不是一个非常可行的选择。当我们使用通过对所有单个损失求和创建的损失函数执行梯度下降时,单个损失的梯度可以并行计算,而在随机梯度下降的情况下,必须一步一步地顺序计算。

所以,我们所做的是一个平衡的行为。我们使用固定数量的样本,比如 16 个、32 个或 128 个,形成所谓的小批量,而不是使用整个数据集,或者只是单个样本来构建我们的损失函数。该词与一次处理所有示例形成对比,通常称为批量梯度下降。选择小批量的大小,以确保我们获得足够的随机性来避免局部最小值,同时利用并行处理的足够计算能力。

局部极小再探:它们没有你想象的那么糟糕

在你反对局部最小值之前,最近的研究表明局部最小值并不必然是坏的。在神经网络的损失图中,有太多的最小值,一个“好的”局部最小值可能表现得和全局最小值一样好。

为什么我说“好”?因为你仍然可能陷入“坏的”局部极小值,这些极小值是由不稳定的训练样本产生的。在给定神经网络的高维损失函数的情况下,“好的”局部最小值,或者在文献中经常被称为最优局部最小值,可以以相当大的数量存在。

也可以注意到,许多神经网络执行分类。如果局部最小值对应于为正确的标签产生 0.7-0.8 之间的分数,而对于相同的例子,全局最小值为正确的标签产生 0.95-0.98 之间的分数,则两者的输出类别预测将是相同的。

最小值的一个理想属性应该是它应该在较平坦的一侧。为什么?因为平坦的最小值很容易收敛,所以很少有机会超过最小值,并在最小值的脊之间跳动。

更重要的是,我们希望测试集的损失面与我们进行训练的训练集略有不同。对于平坦和宽的最小值,损耗不会由于这种移动而改变太多,但是对于窄的最小值就不是这样了。我们试图说明的一点是,更平坦的极小值概括得更好,因此也更可取。

重新审视学习率

最近,关于学习率调度的研究激增,以解决损失景观中的次优最小值。即使学习率下降,也可能陷入局部极小值。传统上,要么在固定的迭代次数内完成训练,要么在损失没有改善的情况下,在比如说 10 次迭代之后停止训练。这在文学上被称为提前停止

快速的学习速度也有助于我们在训练中更早地跳过局部最小值。

人们还将早期停止与学习速率衰减相结合,其中学习速率在每次损失在 10 次迭代后未能改善后衰减,最终在速率低于某个确定的阈值后停止。

近年来,循环学习率已经变得流行,其中学习率缓慢增加,然后降低,并且以循环方式继续。

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

莱斯利·n·史密斯提出的循环学习率的“三角形”和“三角形 2”方法。在左图中,最小和最大 lr 保持不变。右边的差异在每个周期后减半。图片来源:Hafidz Zulkifli

一种叫做热重启随机梯度下降的方法基本上将学习速率退火到一个下限,然后将学习速率恢复到初始值。

对于学习率如何下降,我们也有不同的时间表,从指数衰减到余弦衰减。

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

余弦退火结合重启

最近的一篇论文介绍了一种叫做随机加权平均的技术。作者开发了一种方法,其中他们首先收敛到最小值,缓存权重,然后将学习速率恢复到更高的值。这种更高的学习速率然后将算法从最小值推进到损失表面中的随机点。然后使算法再次收敛到另一个极小值。这样反复几次。最后,它们对所有缓存权重集做出的预测进行平均,以产生最终预测。

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

一种叫做随机加权平均的技术

结论

所以,这是关于梯度下降的介绍性帖子,自从关于反向传播的开创性论文表明你可以通过计算梯度来训练神经网络以来,梯度下降一直是深度学习优化的工作马。然而,还有一个关于梯度下降的缺失,我们在这篇文章中没有谈到,那就是解决病理弯曲的问题。传统随机梯度下降的扩展,如 Momentum、RMSProp 和 Adam 被用来克服这个重要问题。

然而,我认为我们所做的对于一个帖子来说已经足够了,其余的将在另一个帖子中涉及。

进一步阅读

1。神经网络的视觉损失景观(论文)

2。Hafidz Zulkifli 的一篇关于学习进度的精彩文章。

3。随机加权平均(纸)**

深度学习中的优化介绍:Momentum、RMSProp 和 Adam

原文:https://blog.paperspace.com/intro-to-optimization-momentum-rmsprop-adam/

在另一篇文章中,我们讨论了随机梯度下降的基本原理,以及如何解决陷入局部极小值或鞍点等问题。在这篇文章中,我们来看看另一个困扰神经网络训练的问题,病理弯曲

虽然局部最小值和鞍点会拖延我们的训练,但病态曲率会在某种程度上减慢训练,以至于机器学习从业者可能会认为搜索已经收敛到次优马敏。让我们深入了解一下什么是病理性弯曲。

病理弯曲

考虑下面的损失轮廓。

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

*病理弯曲 *

你看,在进入用蓝色标记的峡谷状区域之前,我们随机开始。颜色实际上代表损失函数在特定点的值有多高,红色代表最高值,蓝色代表最低值。

我们想达到最低限度,但为此我们已经走过了峡谷。这个区域就是所谓的病理弯曲。为了理解为什么称之为病理性,让我们深入探究一下。这是病理弯曲放大后的样子…

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

*病理弯曲 *

掌握这里发生的事情并不困难。梯度下降是沿着峡谷的山脊反弹,并向最小值缓慢移动。这是因为脊部的表面在 w1 的方向上弯曲得更加陡峭。

考虑山脊表面上的点 A。我们看到,该点的梯度可以分解成两个分量,一个沿方向 w1 ,另一个沿 w2 。由于损失函数的曲率,梯度在 w1 方向上的分量要大得多,因此梯度的方向更多地朝向 w1 ,而不是朝向 w2 (最小值所在的方向)。

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

正常情况下,我们可以使用一个缓慢的学习速率来处理脊之间的反弹问题,就像我们在上一篇关于梯度下降的文章中提到的那样。然而,这意味着麻烦。

当我们接近最小值时,放慢速度是有意义的,我们希望收敛到最小值。但是考虑一下梯度下降进入病态曲率区域的点,以及到达最小值的绝对距离。如果我们使用一个较慢的学习速率,可能要花太多时间才能达到最小值。事实上,一篇论文报告称,学习率小到足以防止在山脊附近反弹可能会导致练习者认为损失根本没有改善,并放弃所有训练。

并且如果 f 中显著减小的唯一方向是低曲率的方向,则优化可能变得太慢而不实际,甚至看起来完全停止,产生局部最小值的假象

大概我们想要的是能让我们先慢慢进入病态曲率底部的平坦区域,然后向极小值方向加速。二阶导数可以帮助我们做到这一点。

牛顿方法

梯度下降是一种一阶优化方法。它只考虑损失函数的一阶导数,而不考虑高阶导数。这基本上意味着它对损失函数的曲率没有任何线索。它可以判断损失是否在下降,下降速度有多快,但不能区分曲线是平面,向上弯曲还是向下弯曲。

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

发生这种情况是因为梯度下降只关心梯度,对于上面的所有三条曲线,在红色点是相同的。解决办法?考虑二重导数,或者梯度变化的速度。

一种非常流行的技术可以使用二阶导数来解决我们的问题,这种技术叫做牛顿法。为了不偏离 post 的主题,我不会深入研究牛顿法的数学。我要做的是,试着建立一个直觉,牛顿方法是做什么的。

牛顿的方法可以给我们一个理想的步长向梯度方向移动。因为我们现在已经有了关于损失表面曲率的信息,所以可以相应地选择步长,以不超过具有病理曲率的区域的底部。

牛顿的方法通过计算海森矩阵来实现,海森矩阵是损失函数相对于所有权重组合的双导数的矩阵。我所说的重量组合,大概是这样的。

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

然后,一个 Hessian 矩阵将所有这些梯度累积在一个大矩阵中。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Hessian 给出了损失曲面在某一点的曲率估计。损失曲面可以有正曲率,这意味着曲面,这意味着随着我们的移动,曲面会迅速变得不那么陡峭。如果我们有一个负曲率,这意味着随着我们的移动,表面变得越来越陡。

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

注意,如果这一步是负的,这意味着我们可以使用任意一步。换句话说,我们可以切换回原来的算法。这对应于梯度变得更陡的以下情况。

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

然而,如果梯度变得不那么陡,我们可能会走向病理弯曲底部的区域。在这里,牛顿的算法给了我们一个修正的学习步骤,正如你所看到的,它与曲率成反比,或者与表面变得不那么陡峭的速度成反比。

如果表面变得不太陡,则学习步骤减少。

那么我们为什么不更多的使用牛顿的算法呢?

你看到公式中的海森矩阵了吗?hessian 要求你计算损失函数相对于每个权重组合的梯度。如果你知道你的组合,这个值是神经网络中存在的权值的平方的数量级。

对于现代架构,参数的数量可能是数十亿,并且计算十亿平方梯度使得我们难以使用高阶优化方法进行计算。

然而,这里有一个想法。二阶优化是关于整合梯度如何改变自身的信息。虽然我们不能精确地计算这些信息,但我们可以根据梯度的过去行为,选择遵循引导我们寻找最优解的试探法。

动力

与 SGD 一起使用的一个非常流行的技术叫做动量。动量不是只使用当前步骤的梯度来引导搜索,而是累积过去步骤的梯度来确定前进的方向。梯度下降方程修正如下。

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

第一个方程有两部分。第一项是从以前的迭代中保留的梯度。这个保留的梯度乘以一个叫做“动量系数”的值,动量系数是每次迭代保留的梯度的百分比。

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

如果我们将 v 的初始值设置为 0,并将我们的系数选择为 0.9,则后续的更新等式将如下所示。

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

我们看到先前的梯度也被包括在随后的更新中,但是最近的先前梯度的权重大于不太近的梯度。(对于数学上的倾斜,我们取梯度步长的指数平均值)

这对我们的案子有什么帮助?考虑图像,注意大多数渐变更新是在一个之字形方向。还要注意,每个梯度更新已经被分解成沿着 w1w2 方向的分量。如果我们将这些向量单独求和,它们沿着方向 w1 的分量被抵消,而沿着方向 w2 的分量被增强。

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

对于更新,这将增加沿 w2 的分量,同时将沿 w1 方向的分量清零。这有助于我们更快地走向最小值。由于这个原因,在我们的研究中,动量也被认为是一种抑制振荡的技术。

它也建立速度,并加快收敛,但你可能要使用模拟退火的情况下,你过了最小值。

在实践中,动量系数初始化为 0.5,并在多个时期内逐渐退火至 0.9。

RMSProp

RMSprop 或均方根传播有一段有趣的历史。这是传奇人物杰弗里·辛顿在 Coursera 课堂上提出的一个随机想法。

RMSProp 也试图抑制振荡,但方式与动量不同。RMS prop 还消除了调整学习率的需要,并且是自动进行的。更重要的是,RMSProp 为每个参数选择不同的学习速率。

在 RMS prop 中,每次更新都是根据下述公式完成的。对每个参数分别进行更新。

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

那么,让我们来分析一下这里发生了什么。

在第一个等式中,我们计算梯度平方的指数平均值。因为我们对每个参数分别进行处理,所以这里的梯度 Gt 对应于投影,或者沿着我们正在更新的参数所表示的方向的梯度分量。

为此,我们将计算出的指数平均值乘以一个超参数,用希腊符号 nu 表示。然后我们将当前梯度的平方乘以 (1 - nu) 。然后我们将它们相加,得到当前时间点的指数平均值。

我们之所以使用指数平均,是因为正如我们在动量例子中看到的,它有助于我们更多地权衡最近的梯度更新。事实上,“指数”这个名字来源于前面几项的权重呈指数下降(最近一项的权重为 p ,下一项为 p 的平方,然后是 p 的立方,以此类推。)

注意我们表示病理弯曲的图,沿着 w1 的梯度分量比沿着 w2 的梯度分量大得多。因为我们将它们平方并相加,所以它们不会抵消,并且对于 w2 更新,指数平均值很大。

然后在第二个等式中,我们决定了步长。我们沿着梯度的方向移动,但是我们的步长受到指数平均值的影响。我们选择一个初始学习率 eta ,然后除以平均值。在我们的例子中,由于 w1 的平均值比 w2 大得多,因此 w1 的学习步长比 w2 的学习步长小得多。因此,这将帮助我们避免在脊线之间跳跃,并向最小值移动。

第三个等式只是更新步骤。超参数 p 通常选择为 0.9,但是您可能需要对其进行调整。ε是等式 2,是为了确保我们最终不会被零除,一般选择为 1e-10。

还需要注意的是,RMSProp 隐式执行模拟退火。假设我们正朝着最小值前进,我们想放慢速度以免超过最小值。当步长太大时,RMSProp 会自动向最小值减小梯度步长(大的步长会使我们容易过冲)

圣经》和《古兰经》传统中)亚当(人类第一人的名字

到目前为止,我们已经看到 RMSProp 和 Momentum 采用了截然不同的方法。动量加速了我们在极小值方向的搜索,而 RMSProp 阻碍了我们在振荡方向的搜索。

亚当自适应力矩优化算法结合了动量和 RMSProp 的启发式算法。这是更新方程式。

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

这里,我们计算梯度的指数平均值以及每个参数的梯度平方(等式 1 和等式 2)。为了决定我们的学习步骤,我们将我们的学习速率乘以梯度的平均值(动量的情况也是如此)并除以等式 3 中梯度平方的指数平均值的均方根(动量的情况也是如此)。然后,我们添加更新。

超参数β1一般保持在 0.9 左右,而β2保持在 0.99。ε一般选择为 1e-10。

结论

在这篇文章中,我们看到了 3 种方法来建立梯度下降,以解决病理弯曲的问题,同时加快搜索速度。这些方法通常被称为“自适应方法”,因为学习步骤是根据轮廓的拓扑来调整的。

在以上三个因素中,你可能会发现动力是最普遍的,尽管亚当在理论上看起来最有希望。实验结果表明,在损失相同的情况下,所有这些算法都能收敛到不同的最优局部极小值。然而,具有动量的 SGD 似乎比 Adam 找到更多平坦的最小值,而自适应方法倾向于快速收敛到更尖锐的最小值。平坦的最小值比尖锐的最小值概括得更好。

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

尽管自适应方法有助于我们驯服深层网络的损失函数的不规则轮廓,但它们还不够,尤其是随着网络每天变得越来越深。在选择更好的优化方法的同时,大量的研究正在进行,以提出能够产生更平滑损失函数的架构。批量规范化和剩余连接是这一努力的一部分,我们将很快在博客上详细讨论它们。但是这篇文章就说到这里。欢迎在评论中提问。

进一步阅读

  1. 指数加权平均值视频
  2. 从数学角度来看,动量的精彩解释
  3. 关于病理曲率和二阶优化的更多信息
  4. 论牛顿法和一般最优化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值