当前位置: 首页 > news >正文

苏州网站设计服务80端口被封怎么做网站

苏州网站设计服务,80端口被封怎么做网站,陕西建设网综合服务中心网站,花都网站设计机器学习 1#xff1a;第 11 课 原文#xff1a;medium.com/hiromi_suenaga/machine-learning-1-lesson-11-7564c3c18bbb 译者#xff1a;飞龙 协议#xff1a;CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它#xff0c;这些笔记将继续…机器学习 1第 11 课 原文medium.com/hiromi_suenaga/machine-learning-1-lesson-11-7564c3c18bbb 译者飞龙 协议CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它这些笔记将继续更新和改进。非常感谢 Jeremy 和 Rachel 给了我这个学习的机会。 使用 SGD 优化多层函数的回顾[0:00] 这个想法是我们有一些数据x然后我们对这些数据做一些操作例如我们用一个权重矩阵乘以它f(x)。然后我们对这个结果做一些操作例如我们通过 softmax 或 sigmoid 函数处理它g(f(x))。然后我们对这个结果做一些操作比如计算交叉熵损失或均方根误差损失h(g(f(x)))。这将给我们一些标量。这里没有隐藏层。这有一个线性层一个非线性激活函数是 softmax一个损失函数是均方根误差或交叉熵。然后我们有我们的输入数据。 例如[1:16]如果非线性激活函数是 sigmoid 或 softmax损失函数是交叉熵那就是逻辑回归。那么我们如何计算对权重的导数 为了做到这一点基本上我们使用链式法则 因此为了对权重求导我们只需使用那个确切的公式计算对 w 的导数[3:29]。然后如果我们在这里进一步有另一个带有权重 w2 的线性层现在计算对所有参数的导数没有区别。我们仍然可以使用完全相同的链式法则。 所以不要把多层网络想象成在不同时间发生的事情。它只是函数的组合。所以我们只需使用链式法则一次计算所有导数。它们只是在函数的不同部分出现的一组参数但微积分并没有不同。所以计算对 w1 和 w2 的导数你现在可以称之为 w说 w1 就是所有这些权重。 那么你将会得到一个参数列表[5:26]。这里是 w1可能是某种高阶张量。如果是卷积层它将是一个三阶张量但我们可以展开它。我们将把它变成一个参数列表。这里是 w2。这只是另一个参数列表。这是我们的损失是一个单一的数字。因此我们的导数就是同样长度的向量。改变 w 的值会对损失产生多大影响你可以把它想象成一个函数比如y ax1 bx2 c然后问对 a、b 和 c 的导数是多少你会得到三个数字对 a、b 和 c 的导数。就是这样。如果对那个权重求导那个权重… 为了到达这一点在链式法则中我们必须计算像雅可比这样的导数当你进行矩阵乘法时你现在得到的是一个权重矩阵和输入向量这些是来自前一层的激活还有一些新的输出激活。所以现在你必须说对于这个特定的权重改变这个特定的权重如何改变这个特定的输出改变这个特定的权重如何改变这个特定的输出等等。所以你最终会得到这些更高维度的张量显示每个权重如何影响每个输出。然后当你到达损失函数时损失函数将有一个均值或和所以它们最终会被加起来。 尝试手动计算或逐步考虑这一点让我有点疯狂因为你倾向于像…你只需要记住对于每个权重对于每个输出你都必须有一个单独的梯度。 一个很好的方法是学习使用 PyTorch 的.grad属性和.backward方法并手动查阅 PyTorch 教程。这样你就可以开始设置一些具有向量输入和向量输出的计算然后输入.backward然后输入grad并查看它。然后对只有 2 或 3 个项目的输入和输出向量进行一些非常小的操作比如加 2 或其他操作看看形状是什么确保它是有意义的。因为向量矩阵微积分在严格意义上并没有为你在高中学到的任何概念引入新的概念。但是对这些形状如何移动有了一定的感觉需要大量的练习。好消息是你几乎永远不必担心这个。 NLP 的朴素贝叶斯和逻辑回归回顾[9:53] 笔记本 / Excel 我们正在讨论使用这种逻辑回归进行 NLP。在达到这一点之前我们正在讨论使用朴素贝叶斯进行 NLP。基本思想是我们可以取一个文档例如电影评论并将其转换为一个词袋表示其中包含每个单词出现的次数。我们称单词的唯一列表为词汇表。我们使用 sklearn 的 CountVectorizer 自动生成词汇表他们称之为“特征”并创建词袋表示所有这些袋表示的整体称为术语文档矩阵。 我们有点意识到我们可以通过简单地平均积极评论中单词“this”出现的次数来计算积极评论包含单词“this”的概率我们可以对消极评论做同样的事情然后我们可以取它们的比率得到一个结果如果大于一则表示该单词在积极评论中出现得更频繁如果小于一则表示该单词在消极评论中出现得更频繁。 然后我们意识到使用贝叶斯规则并取对数我们基本上可以得到一个结果我们可以将这些下面突出显示的的对数加起来再加上类别 1 与类别 0 的概率比的对数最终得到一个可以与零进行比较的结果[11:32]。如果结果大于零我们可以预测文档是积极的如果结果小于零我们可以预测文档是消极的。这就是我们的贝叶斯规则。 我们从数学的第一原理开始做了这个我认为我们都同意“朴素”在朴素贝叶斯中是一个很好的描述因为它假设了独立性而这显然是不正确的。但这是一个有趣的起点当我们实际上到达这一点时我们计算了概率的比率并取了对数现在不是将它们相乘当然我们必须将它们相加。当我们实际写下这个时我们意识到哦这只是一个标准的权重矩阵乘积加上一个偏差 然后我们意识到如果这不是很好的准确率80%为什么不通过说嘿我们知道其他计算一堆系数和一堆偏差的方法即在逻辑回归中学习它们来改进呢换句话说这是我们用于逻辑回归的公式那么为什么我们不只是创建一个逻辑回归并拟合它呢它会给我们同样的结果但与基于独立性假设和贝叶斯规则的理论上正确的系数和偏差不同它们将是实际上在这些数据中最好的系数和偏差。这就是我们的结论。 这里的关键见解是几乎所有的机器学习最终都变成了一棵树或一堆矩阵乘积和非线性[13:54]。一切似乎最终都归结为相同的事情包括贝叶斯规则。然后事实证明无论该函数中的参数是什么它们都比基于理论计算更好地学习。事实上当我们实际尝试学习这些系数时我们得到了 85%的准确率。 然后我们注意到与其采用整个术语文档矩阵我们可以只取单词存在或不存在的一和零。有时这样做同样有效但后来我们实际尝试了另一种方法即添加正则化。通过正则化二值化方法结果略好一些。 然后正则化是我们取损失函数再次让我们从 RMSE 开始然后我们将讨论交叉熵。损失函数是我们的预测减去我们的实际值将其相加取平均再加上一个惩罚。 具体来说这是 L2 惩罚。如果这是 w 的绝对值那就是 L1 惩罚。我们还注意到我们实际上并不关心损失函数本身我们只关心它的导数这实际上是更新权重的东西因此因为这是一个总和我们可以分别对每个部分求导所以惩罚的导数只是 2aw。因此我们了解到尽管这些在数学上是等价的但它们有不同的名称。这个版本2aw被称为权重衰减这个术语在神经网络文献中使用。 交叉熵[16:34] Excel 另一方面交叉熵只是另一个损失函数就像均方根误差一样但它专门设计用于分类。这是一个二元交叉熵的例子。假设这是我们的“是猫还是狗”所以说isCat是 1 还是 0。而Preds是我们的预测这是我们神经网络的最终层的输出一个逻辑回归等等。 然后我们所做的就是说好吧让我们取实际值乘以预测的对数然后加上 1 减去实际值乘以 1 减去预测的对数然后取整个东西的负值。 我建议你们尝试写出这个 if 语句版本希望你们现在已经做到了否则我将为你们揭示。所以这是 我们如何将这写成一个 if 语句 if y 1: return -log(ŷ) else: return -log(1-ŷ)所以关键的洞察是 y 有两种可能性1 或 0。所以很多时候数学会隐藏关键的洞察我认为这里发生了直到你真正思考它可以取什么值。所以这就是它所说的。要么给我-log(ŷ)要么给我-log(1-ŷ) 好的那么多类别版本就是同样的事情但你说的不仅仅是 y 1而是 y 0, 1, 2, 3, 4, 5 . . . 例如 [19:26]。所以这个损失函数有一个特别简单的导数另外一个你可以在家里尝试的东西是想一想在它之前加上一个 sigmoid 或 softmax 之后导数是什么样子。结果会是非常好的导数。 人们使用均方根误差用于回归和交叉熵用于分类的原因有很多但大部分都可以追溯到最佳线性无偏估计的统计概念基于可能性函数的结果表明这些函数具有一些良好的统计性质。然而实际上尤其是均方根误差的性质可能更多是理论上的而不是实际的实际上现在使用绝对偏差而不是平方偏差的和通常效果更好。所以在实践中机器学习中的一切我通常都会尝试两种。对于特定的数据集我会尝试两种损失函数看哪一个效果更好。当然如果是 Kaggle 竞赛的话那么你会被告知 Kaggle 将如何评判你应该使用与 Kaggle 评估指标相同的损失函数。 所以这真的是关键的洞察 [21:16]。让我们不要使用理论而是从数据中学习。我们希望我们会得到更好的结果。特别是在正则化方面我们确实得到了。然后我认为这里的关键正则化洞察是让我们不要试图减少模型中的参数数量而是使用大量的参数然后使用正则化来找出哪些实际上是有用的。 更多的 n-grams 特征 [21:41] 笔记本 然后我们进一步说鉴于我们可以通过正则化做到这一点让我们通过添加二元组和三元组来创建更多。例如 by vast、by vengeance 这样的二元组以及 by vengeance .、by vera miles 这样的三元组。为了让事情运行得更快一些我们将其限制为 800,000 个特征但即使使用完整的 70 百万个特征它的效果也一样好而且速度并没有慢多少。 veczr CountVectorizer(ngram_range(1,3), tokenizertokenize, max_features800000 ) trn_term_doc veczr.fit_transform(trn) val_term_doc veczr.transform(val) trn_term_doc.shape(25000, 800000)vocab veczr.get_feature_names() vocab[200000:200005][by vast, by vengeance, by vengeance ., by vera, by vera miles]所以我们使用了完整的 n-grams 集合为训练集和验证集创建了一个术语文档矩阵。现在我们可以继续说我们的标签是训练集标签如前所述我们的自变量是二值化的术语文档矩阵如前所述 ytrn_y xtrn_term_doc.sign() val_x val_term_doc.sign() p x[y1].sum(0)1 q x[y0].sum(0)1 r np.log((p/p.sum())/(q/q.sum())) b np.log(len(p)/len(q))然后让我们对其进行逻辑回归拟合并进行一些预测我们得到了 90% 的准确率 m LogisticRegression(C0.1, dualTrue) m.fit(x, y);preds m.predict(val_x) (preds.Tval_y).mean()0.90500000000000003所以看起来很不错。 回到朴素贝叶斯 [22:54] 让我们回到我们的朴素贝叶斯。在我们的朴素贝叶斯中我们有这个术语文档矩阵然后对于每个特征我们正在计算如果它是类别 1 出现的概率如果它是类别 0 出现的概率以及这两者的比率。 在我们实际基于的论文中他们将 p(f|1) 称为 p将 p(f|0) 称为 q将比率称为 r。 然后我们说让我们不要把这些比率作为矩阵乘法中的系数。而是尝试学习一些系数。也许开始用一些随机数然后尝试使用随机梯度下降找到稍微更好的系数。 所以你会注意到这里一些重要的特征。r向量是一个秩为 1 的向量其长度等于特征的数量。当然我们的逻辑回归系数矩阵也是秩为 1 且长度等于特征数量的。我们说它们是计算相同类型的东西的两种方式一种基于理论一种基于数据。所以这里是r中的一些数字 r.shape, r((1, 800000), matrix([[-0.05468, -0.161 , -0.24784, ..., 1.09861, -0.69315, -0.69315]]))记住它使用对数所以这些小于零的数字代表更有可能是负数的东西而大于零的数字可能是正数。所以这里是 e 的幂次方。所以这些是我们可以与 1 而不是 0 进行比较的数字 np.exp(r)matrix([[ 0.94678, 0.85129, 0.78049, ..., 3\. , 0.5 , 0.5 ]])\我要做一些希望看起来很奇怪的事情。首先我会说我们要做什么然后我会尝试描述为什么这很奇怪然后我们会讨论为什么它可能并不像我们最初想的那么奇怪。所以这就是我们要做的事情。我们将取我们的术语文档矩阵然后将其乘以r。这意味着我可以在 Excel 中做到这一点我们将说让我们抓取我们的术语文档矩阵中的所有内容并将其乘以向量r中的等值。所以这就像是一个广播的逐元素乘法而不是矩阵乘法。 所以这是术语文档矩阵乘以r的值换句话说在术语文档矩阵中出现零的地方在乘以版本中也出现零。而在术语文档矩阵中每次出现一个的地方等效的r值出现在底部。所以我们并没有真正改变太多。我们只是将一个变成了其他东西即来自该特征的r。所以我们现在要做的是我们将使用这些独立变量而不是在我们的逻辑回归中。 所以在这里。x_nbx 朴素贝叶斯版本是x乘以r。现在让我们使用这些独立变量进行逻辑回归拟合。然后对验证集进行预测结果我们得到了一个更好的数字 x_nb x.multiply(r) m LogisticRegression(dualTrue, C0.1) m.fit(x_nb, y);val_x_nb val_x.multiply(r) preds m.predict(val_x_nb) (preds.Tval_y).mean()0.91768000000000005让我解释为什么这可能会令人惊讶。这是我们的独立变量下面突出显示然后逻辑回归得出了一些系数集假设这些是它恰好得出的系数。 现在我们可以说好吧让我们不使用这组独立变量x_nb而是使用原始的二值化特征矩阵。然后将所有系数除以r中的值数学上我们将得到完全相同的结果。 所以我们有了我们的独立变量的 x 朴素贝叶斯版本x_nb以及一组权重/系数w1它发现这是一个用于进行预测的好系数集。但是 x_nb 简单地等于x乘以逐元素r。 换句话说这xnb·w1等于x*r·w1。所以我们可以只改变权重为r·w1得到相同的数字。这应该意味着我们对独立变量所做的更改不应该有任何影响因为我们可以在不进行这种改变的情况下计算出完全相同的结果。所以问题就在这里。为什么会有所不同呢为了回答这个问题你需要考虑哪些数学上不同的事情。为什么它们不完全相同提出一些假设也许我们实际上得到了更好的答案的一些原因。要弄清楚这一点首先我们需要弄清楚为什么会有不同的答案这是微妙的。 讨论 它们受到正则化的影响是不同的。我们的损失等于基于预测和实际值的交叉熵损失加上我们的惩罚 所以如果你的权重很大那么惩罚aw²就会变大而且会淹没掉交叉熵部分x.e.(xw, y)。但那实际上是我们关心的部分。我们实际上希望它是一个很好的拟合。所以我们希望尽可能少地进行正则化。所以我们希望权重更小我有点把“更少”和“更小”这两个词用得有点等同这不太公平我同意但想法是接近零的权重实际上是不存在的。 这就是问题所在。我们的r值我不是一个贝叶斯怪胎但我仍然要使用“先验”这个词。它们有点像一个先验 - 我们认为不同级别的重要性和这些不同特征的积极或消极可能是这样的。我们认为“坏”可能与负面更相关而不是“好”。所以我们之前的隐含假设是我们没有先验换句话说当我们说平方权重w²时我们是在说非零权重是我们不想要的。但实际上我想说的是与朴素贝叶斯的期望不同是我不想做的事情。除非你有充分的理由相信其他情况否则只有与朴素贝叶斯先验有所不同。 这实际上就是这样做的。我们最终说我们认为这个值可能是 3。所以如果你要把它变得更大或更小那将会导致权重的变化从而使平方项增加。所以如果可以的话就让所有这些值保持与现在大致相似。这就是现在惩罚项正在做的事情。当我们的输入已经乘以r时它在说惩罚那些与我们的朴素贝叶斯先验有所不同的事物。 问题为什么只与 r 相乘而不是像 r²这样这次方差会高得多呢因为我们的先验来自一个实际的理论模型。所以我说我不喜欢依赖理论但如果我有一些理论那么也许我们应该将其作为我们的起点而不是假设一切都是相等的。所以我们的先验说嘿我们有这个叫做朴素贝叶斯的模型朴素贝叶斯模型说如果朴素贝叶斯的假设是正确的那么r就是这个特定公式中的正确系数。这就是我们选择它的原因因为我们的先验是基于那个理论的。 这是一个非常有趣的见解我从未真正看到过。这个想法是我们可以使用这些传统的机器学习技术通过将我们的理论期望纳入我们给模型的数据中赋予它们这种贝叶斯感。当我们这样做时这意味着我们就不必那么经常进行正则化了。这很好因为我们经常进行正则化…让我们试试吧 记住在 sklearn 逻辑回归中C是正则化惩罚的倒数。所以我们通过使其变小1e-5来增加大量的正则化。 这真的会影响我们的准确性因为现在它非常努力地降低这些权重损失函数被需要减少权重的需求所压倒。而现在使其具有预测性似乎完全不重要。所以通过开始并说不要推动权重降低以至于最终忽略这些项而是推动它们降低以便尝试消除那些忽略了我们基于朴素贝叶斯公式期望的差异的权重。这最终给我们带来了一个非常好的结果 基线和二元组简单、良好的情感和主题分类 论文 这种技术最初是在 2012 年提出的。Chris Manning 是斯坦福大学出色的自然语言处理研究人员而 Sida Wang 我不认识但我认为他很棒因为他的论文很棒。他们基本上提出了这个想法。他们所做的是将其与其他方法在其他数据集上进行比较。其中一件事是他们尝试了 IMDB 数据集。这里是大二元组上的朴素贝叶斯 SVM 正如你所看到的这种方法胜过了他们研究的其他基于线性的方法以及他们研究的一些受限玻尔兹曼机的神经网络方法。如今有更好的方法来做这个事实上在深度学习课程中我们展示了我们在 Fast AI 刚刚开发的最新成果可以达到 94%以上的准确率。但是特别是对于一种简单、快速、直观的线性技术来说这还是相当不错的。你会注意到当他们这样做时他们只使用了二元组。我猜这是因为我看了他们的代码发现它相当慢且难看。我找到了一种更优化的方法正如你所看到的所以我们能够使用三元组因此我们得到了更好的结果我们的准确率是 91.8%而不是 91.2%但除此之外它是相同的。哦他们还使用了支持向量机在这种情况下几乎与逻辑回归相同所以有一些细微的差异。所以我认为这是一个相当酷的结果。 我要提一下在课堂上你看到的是我经过多周甚至多个月的研究得出的结果。所以我不希望你认为这些东西是显而易见的。完全不是。就像阅读这篇论文论文中没有描述为什么他们使用这个模型它与其他模型有何不同为什么他们认为它有效。我花了一两周的时间才意识到它在数学上等同于普通的逻辑回归然后又花了几周的时间才意识到区别实际上在于正则化。这有点像机器学习我相信你从你参加的 Kaggle 竞赛中已经注意到了。就像你提出了一千个好主意其中 999 个无论你有多么自信它们会很棒最终都会变成垃圾。然后最终在四周后其中一个终于奏效给了你继续度过另外四周的痛苦和挫折的热情。这是正常的。而且我可以确定我所认识的机器学习领域最优秀的从业者都有一个共同的特点那就是他们非常顽强也被称为固执和执着这绝对是我似乎拥有的声誉可能是公平的还有另一点他们都是非常擅长编码的。他们非常擅长将他们的想法转化为新的代码。对我来说几个月前通过这个工作是一个非常有趣的经历试图至少弄清楚为什么这个当时的最新成果存在。 更好的版本NBSVM [43:31] 所以一旦我弄清楚了我实际上能够在此基础上进行改进并且我会向你展示我做了什么。这就是我非常幸运能够使用 PyTorch 的原因因为我能够创建出我想要的定制化内容并且通过使用 GPU 也非常快速。这就是 Fast AI 版本的 NBSVM。实际上我的朋友 Stephen Merity 是一位在自然语言处理领域出色的研究人员他将其命名为 NBSVM我觉得这很可爱所以这就是尽管没有 SVM但是它是一个逻辑回归但正如我所说几乎完全相同。 所以首先让我向你展示代码。一旦我弄清楚这是我能想到的最好的线性词袋模型的方法我将其嵌入到 Fast AI 中这样你只需写几行代码就可以了。 sl2000 # Here is how we get a model from a bag of words md TextClassifierData.from_bow(trn_term_doc, trn_y, val_term_doc,val_y, sl )所以代码基本上是嘿我想为文本分类创建一个数据类我想从词袋from_bow中创建它。这是我的词袋trn_term_doc这是我们的标签trn_y这是验证集的相同内容并且每个评论最多使用 2000 个独特的单词这已经足够了。 然后从那个模型数据中构建一个学习器这是 Fast AI 对基于朴素贝叶斯点积的模型的泛化然后拟合该模型。 learner md.dotprod_nb_learner() learner.fit(0.02, 1, wds1e-6, cycle_len1)[ 0\. 0.0251 0.12003 0.91552]learner.fit(0.02, 2, wds1e-6, cycle_len1)[ 0\. 0.02014 0.11387 0.92012] [ 1\. 0.01275 0.11149 0.92124]learner.fit(0.02, 2, wds1e-6, cycle_len1)[ 0\. 0.01681 0.11089 0.92129] [ 1\. 0.00949 0.10951 0.92223]经过 5 个时代我的准确率已经达到了 92.2。所以现在已经远远超过了线性基准在原始论文中。所以让我给你展示一下那段代码。 所以代码非常简短。就是这样。这看起来也非常熟悉。这里有一些小调整假装这个写着Embedding的东西实际上写着Linear。我马上会展示给你看 embedding。所以我们基本上有一个线性层特征的数量作为行记住sklearn 特征意味着基本上是单词的数量。然后对于每个单词我们将创建一个权重这是有道理的——逻辑回归每个单词有一个权重。然后我们将它乘以r值所以每个单词我们有一个r值每个类。所以我实际上做了这个这样可以处理不仅仅是正面和负面还可以找出是哪个作者创作了这个作品——例如可能有五六个作者。 基本上我们使用这些线性层来得到权重和r的值然后我们取权重乘以r然后相加。所以这只是一个简单的点积就像我们为任何逻辑回归所做的那样然后进行 softmax。我们为了获得更好的结果所做的非常小的调整是这个self.w_adj 我添加的东西是这是一个参数但我几乎总是使用这个默认值 0.4。那么这是做什么的呢这再次改变了先验。如果你考虑一下即使我们将这个r乘以文档矩阵作为它们的自变量你真的想从一个问题开始好的惩罚项仍然在将w推向零。 那么w为零意味着什么如果我们的系数都是 0 会怎么样 当我们将这个矩阵与这些系数相乘时我们仍然得到零。所以权重为零最终会说“我对这个事情是正面还是负面没有意见。”另一方面如果它们都是 1那么基本上就是说我的意见是朴素贝叶斯系数是完全正确的。所以我说零几乎肯定不是正确的先验。我们不应该真的说如果没有系数那就意味着忽略朴素贝叶斯系数。1 可能太高了因为我们实际上认为朴素贝叶斯只是答案的一部分。所以我尝试了几个不同的数据集基本上是说取这些权重并加上一些常数。所以零在这种情况下会变成 0.4。换句话说正则化惩罚将权重推向这个值而不是零。我发现在许多数据集中0.4 效果非常好且非常稳健。再次基本思想是在使用简单模型从数据中学习的同时尽可能地融入我们的先验知识。所以结果是当你说让权重矩阵的零实际上意味着你应该使用大约一半的r值时这比权重应该全部为零的先验效果更好。 问题w是表示所需正则化量的点吗w是权重。所以x ((wself.w_adj)*r/self.r_adj).sum(1)正在计算我们的激活。我们计算我们的激活等于权重乘以r然后求和。所以这只是我们的正常线性函数。被惩罚的是我的权重矩阵。这就是受到惩罚的地方。所以通过说嘿你知道不要只使用w —— 使用w0.4。0.4即self.w_adj不受惩罚。它不是权重矩阵的一部分。因此权重矩阵实际上免费获得了 0.4。 问题通过这样做即使经过正则化每个特征都会获得一些形式的最小权重吗不一定因为它最终可能会为一个特征选择一个系数为-0.4这将表示“你知道即使朴素贝叶斯说对于这个特征r应该是什么我认为你应该完全忽略它”。 休息期间有几个问题。第一个是关于这里正在发生的事情的总结 这里有w加上权重调整乘以r 所以通常我们所做的是说逻辑回归基本上是wx我将忽略偏差。然后我们将其更改为rx·w。然后我们说让我们先做x·w这部分。这里的这个东西我实际上称之为 w这可能很糟糕实际上是w乘以x 所以我没有r(x·w)我有w·x加上一个常数乘以r。所以这里的关键思想是正则化希望权重为零因为它试图减少Σw²。所以我们所说的是好吧我们希望将权重推向零因为这是我们的默认起点期望。所以我们希望处于这样一种情况即如果权重为零那么我们有一个对我们来说在理论上或直观上有意义的模型。这个模型r(x·w)如果权重为零对我们来说没有直观意义。因为它在说嘿将所有东西乘以零会消除一切。我们实际上在说“不我们实际上认为我们的r是有用的我们实际上想保留它。”所以让我们取(x·w)并加上 0.4。所以现在如果正则化器将权重推向零那么它将将总和的值推向 0.4。 因此它将整个模型推向 0.4 倍r。换句话说如果您将所有权重一起正则化到 0.4 倍r那么我们的默认起点是说“是的您知道让我们使用一点r。这可能是一个好主意。”这就是这个想法。这个想法基本上是当权重为零时会发生什么。您希望那是有意义的否则正则化权重朝着那个方向移动就不是一个好主意。 第二个问题是关于 n-grams。所以 n-gram 中的 N 可以是 unibitri等等。123等等个 grams。所以“This movie is good”有四个 unigramsThismovieisgood。它有三个 bigramsThis moviemovie isis good。它有两个 trigramsThis movie ismovie is good。 问题您介意回到w_adj或0.4的内容吗我在想这种调整会不会损害模型的可预测性因为想象一下极端情况如果不是 0.4如果是 4,000那么所有系数基本上会是…确切地说。因此我们的先验需要有意义。这就是为什么它被称为 DotProdNB因此先验是我们认为朴素贝叶斯是一个好的先验的地方。因此朴素贝叶斯认为r p/q是一个好的先验我们不仅认为这是一个好的先验而且我们认为rxb是一个好的模型。这就是朴素贝叶斯模型。换句话说我们期望系数为 1 是一个好的系数而不是 4,000。具体来说我们认为零可能不是一个好的系数。但我们也认为也许朴素贝叶斯版本有点过于自信。所以也许 1 有点高。因此我们相当确定假设朴素贝叶斯模型是适当的正确的数字在 0 和 1 之间。 问题继续但我在想的是只要不是零您就会将那些应该为零的系数推到非零的地方并使高系数与零系数之间的差异变小。嗯但是您看它们本来就不应该是零。它们应该是r。请记住这是在我们的前向函数中所以这是我们正在计算梯度的一部分。所以基本上是说好吧您仍然可以将 self.w 设置为您喜欢的任何值。但是正则化器希望它为零。所以我们所说的是好吧如果您希望它为零那么我将尝试使零给出一个合理的答案。 没有人说 0.4 对于每个数据集都是完美的。我尝试了一些不同的数据集并发现在 0.3 和 0.6 之间有一些最佳值。但我从未发现一个比零更好的数据集这并不奇怪。我也从未发现一个更好的数据集。因此这个想法是一个合理的默认值但这是另一个您可以玩耍的参数我有点喜欢。这是另一件您可以使用网格搜索或其他方法来找出对您的数据集最佳的东西。实际上关键在于在这个模型之前的每个模型据我所知都隐含地假设它应该为零因为它们没有这个参数。顺便说一句我实际上还有第二个参数r_adj10它是我对 r 做的相同的事情实际上是通过一个参数除以 r我现在不会太担心但这是另一个您可以用来调整正则化性质的参数。最终我是一个实证主义者而不是一个理论家。我认为这似乎是一个好主意。几乎所有我认为是一个好主意的事情最终都被证明是愚蠢的。这个特定的想法在这个数据集上给出了良好的结果也在其他一些数据集上给出了良好的结果。 **问题**我仍然对w w_adj感到困惑。你提到我们执行w w_adj是为了不让系数设为零我们对先验赋予了一些重要性。但你也说过学习的效果可能是w被设为负值这可能会使w w_adj为零。所以如果我们允许学习过程确实将系数设为零那为什么这与只有w不同呢因为正则化。因为我们通过Σw²对其进行惩罚。换句话说我们在说你知道如果忽略r是最好的选择那将会花费你Σw²。你将不得不将w设为负数。所以只有在这显然是一个好主意的情况下才这样做。除非这显然是一个好主意否则你应该将其保留在原处。这是唯一的原因。今天我们所做的所有事情基本上都是为了最大化我们从正则化中获得的优势并且说正则化将我们推向某种默认假设几乎所有的机器学习文献都假设默认假设是所有事物都是零。我在说的是从理论上讲这是有道理的而从经验上讲事实证明你应该决定你的默认假设是什么这将给你带来更好的结果。 **问题继续**那么可以这样说在某种程度上你是在前往将所有系数设为零的过程中设置了一个额外的障碍如果确实值得的话它将能够做到这一点吗是的确实如此。所以我会说没有这个默认障碍使系数非零是障碍。现在我要说的是不障碍是使系数不等于 0.4r。 **问题**所以这是 w²乘以某个常数的总和。如果常数是比如说 0.1那么权重可能不会趋向于零。那么我们可能就不需要权重衰减了如果常数的值为零那么就没有正则化。但如果这个值大于零那么就会有一些惩罚。而且可以推测我们将其设置为非零是因为我们过拟合了。所以我们想要一些惩罚。所以如果有一些惩罚那么我的观点是我们应该惩罚那些与我们的先验不同的事物而不是惩罚那些与零不同的事物。我们的先验是事物应该大致等于r。 嵌入[1:05:17] 我想谈谈嵌入。我说假装它是线性的实际上我们可以假装它是线性的。让我向你展示我们可以多么地假装它是线性的就像nn.Linear创建一个线性层。 这是我们的数据矩阵这是我们的系数r如果我们正在进行r版本。所以如果我们将r放入列向量中那么我们可以通过系数对数据矩阵进行矩阵乘法。 因此这个自变量矩阵乘以这个系数矩阵的矩阵乘法将给我们一个答案。所以问题是好吧为什么 Jeremy 没有写nn.Linear为什么 Jeremy 写了nn.Embedding原因是如果你回忆一下我们实际上并不是这样存储的。因为这实际上是宽度为 800,000高度为 25,000。所以我们实际上是这样存储的 我们的存储方式是这个词袋包含哪些单词索引。这是一种稀疏的存储方式。它只列出每个句子中的索引。鉴于此我现在想要执行我刚刚向你展示的那种矩阵乘法以创建相同的结果。但我想要从稀疏表示中执行。这基本上是一种独热编码 这有点像一个虚拟矩阵版本。它有一个单词“this”吗它有一个单词“movie”吗等等。所以如果我们采用简单版本的有没有单词“this”即 1, 0, 0, 0, 0, 0然后我们将其乘以r那么它只会返回第一个项目 总的来说一个独热编码向量乘以一个矩阵等同于查找该矩阵中的第 n 行。 所以这只是说找到第 0、第一个、第二个和第五个系数 它们完全相同。 在这种情况下每个特征只有一个系数但实际上我这样做的方式是为每个类别的每个特征都有一个系数。 所以在这种情况下类别是正面和负面。 所以我实际上有 r 正面 (p/q)r 负面 (q/r) 在二进制情况下显然同时拥有两者是多余的。 但是如果是像这个文本的作者是谁 是 JeremySavannah 还是 Terrence 现在我们有三个类别我们想要三个 r 的值。 所以做这个稀疏版本的好处是你可以查找第 0、第一个、第二个和第五个。 再次强调从数学上讲这与乘以一个独热编码矩阵是相同的。 但是当输入稀疏时效率显然要高得多。 因此这个计算技巧在数学上与乘以一个独热编码矩阵是相同的而不是概念上类似于。 这被称为嵌入。 我相信大多数人可能已经听说过嵌入比如词嵌入Word2VecGloVe 等。 人们喜欢把它们说成是这种令人惊叹的新复杂神经网络东西。 但事实并非如此。 嵌入意味着通过简单的数组查找来加快乘以一个独热编码矩阵的过程。 这就是为什么我说你可以把这个想象成说 self.w nn.Linear(nf1, 1) 因为它实际上做的是相同的事情。 它实际上是一个具有这些维度的矩阵。 这是一个线性层但它期望我们要给它的输入实际上不是一个独热编码矩阵而是一个整数列表 —— 每个项目的每个单词的索引。 所以你可以看到 Fast AI 中的 forward 函数自动获取对于 DotProdNB leaner特征索引feature_idx 所以它们自动来自稀疏矩阵。 Numpy 使得很容易只需抓取这些索引。 换句话说我们在这里feat_idx有一个包含这个文档中的 800,000 个单词索引的列表。 所以这里self.w(feat_idx)说的是查找我们的嵌入矩阵中的每一个该矩阵有 800,000 行并返回你找到的每一个东西。 从数学上讲这与乘以一个独热编码矩阵是相同的。 这就是所有嵌入的含义。 这意味着我们现在可以处理构建任何类型的模型比如任何类型的神经网络其中我们的输入可能是非常高基数的分类变量。 然后我们只需将它们转换为介于零和级别数之间的数字代码然后我们可以学习一个线性层就好像我们已经对其进行了独热编码而实际上并没有构建独热编码版本也没有进行矩阵乘法。 相反我们将只存储索引版本并简单地进行数组查找。 因此回流的梯度基本上是在独热编码版本中所有为零的东西都没有梯度因此回流的梯度只会更新我们使用的嵌入矩阵的特定行。 这对于自然语言处理非常重要就像在这里一样我想创建一个 PyTorch 模型该模型将实现这个非常简单的方程。 如果没有这个技巧那意味着我要输入一个 25,000 x 80,000 元素的数组这将有点疯狂。 所以这个技巧让我写下了这个。 我只是用 Embedding 替换了 Linear用一些只输入索引而不是输入独热编码的东西来替换那个就这样。 然后它继续工作所以现在每个时代的训练时间大约是一分钟。 现在我们可以把这个想法应用到不仅仅是语言而是任何东西上。 例如预测杂货店商品的销售情况。 问题我们实际上并没有查找任何东西对吧我们只是看到了那个带有索引的数组表示所以我们正在查找。现在存储的词袋的表示不再是 1 1 1 0 0 1而是 0 1 2 5。因此我们实际上必须进行矩阵乘法。但是我们不是进行矩阵乘法而是查找第零个东西第一个东西第二个东西和第五个东西。 问题继续这意味着我们仍然保留了独热编码矩阵吗不我们没有。这里没有使用独热编码矩阵。目前没有突出显示独热编码矩阵。我们目前突出显示的是索引列表和权重矩阵中的系数列表 所以现在我们要做的是更进一步我们要说根本不使用线性模型让我们使用一个多层神经网络。让我们的输入可能包括一些分类变量。这些分类变量我们将只将其作为数值索引。因此这些的第一层不会是一个普通的线性层它们将是一个嵌入层我们知道在数学上它的行为与线性层完全相同。因此我们的希望是现在我们可以使用这个来为任何类型的数据创建一个神经网络。 罗斯曼竞赛 笔记本 几年前在 Kaggle 上有一个名为 Rossmann 的竞赛这是一个德国的杂货连锁店他们要求预测他们商店中商品的销售情况。这包括分类和连续变量的混合。在 Guo/Berkhahn 的这篇论文中他们描述了他们的第三名作品这比第一名作品简单得多但几乎一样好但简单得多因为他们利用了这个所谓的实体嵌入的想法。在论文中他们认为他们发明了这个实际上早些时候由 Yoshua Bengio 和他的合著者在另一个 Kaggle 竞赛中写过。尽管如此我觉得 Guo 在描述这个如何在许多其他方面使用上走得更远所以我们也会谈论这个。 笔记本在深度学习存储库中因为我们在深度学习课程中讨论了一些深度学习特定方面在这门课程中我们主要将讨论特征工程我们还将讨论这个嵌入的想法。 让我们从数据开始。所以数据是2015 年 7 月 31 日第 1 号店开业。他们正在进行促销活动。有学校假期。不是国家假期他们卖出了 5263 件商品。这是他们提供的关键数据。所以目标显然是在没有销售信息的测试集中预测销售额。他们还告诉你对于每家商店它是某种特定类型的销售某种特定种类的商品其最近的竞争对手距离一定距离竞争对手在 2008 年 9 月开业还有一些关于促销的更多信息我不知道这意味着什么。就像许多 Kaggle 竞赛一样他们允许您下载外部数据集只要您与其他竞争者分享。他们还告诉您每家商店所在的州因此人们下载了德国不同州的名称他们为德国每周下载了一些谷歌趋势数据。我不知道他们得到了什么具体的谷歌趋势但是有的。对于每个日期他们下载了一堆温度信息。就是这样。 这里一个有趣的见解是Rossmann 可能在某种程度上犯了一个错误设计这个比赛是一个可以使用外部数据的比赛。因为实际上你并不能知道下周的天气或下周的谷歌趋势。但当你参加 Kaggle 比赛时你并不在乎这些。你只是想赢所以你会利用一切可以得到的。 数据清理 首先让我们谈谈数据清理。在这个获得第三名的参赛作品中实际上并没有进行太多的特征工程特别是按照 Kaggle 的标准通常每一个细节都很重要。这是一个很好的例子展示了使用神经网络可以取得多大的成就这让我想起了昨天我们谈到的索赔预测比赛获胜者没有进行任何特征工程完全依赖深度学习。房间里的笑声我猜是来自那些在比赛中进行了一点点特征工程的人们 顺便提一下我发现在比赛中努力工作然后比赛结束了你没有赢得比赛。然后获胜者出来说这就是我赢得比赛的方法。这是你学到最多的时候。有时候这种情况发生在我身上我会想哦我想到了那个我试过了然后我回去发现我那里有个 bug我没有正确测试然后我意识到哦好吧我真的需要学会以不同的方式测试这个东西。有时候就像哦我想到了那个但我假设它不会起作用我真的要记住在做任何假设之前检查一切。你知道有时候就像哦我没有想到那个技术哇现在我知道它比我刚刚尝试的一切都要好。否则如果有人说嘿你知道这是一个非常好的技术你会说好的。但是当你花了几个月的时间尝试做某事然后别人用那个技术做得更好时那就相当有说服力了。所以这有点困难我站在你面前说这里有一堆我用过的技术我赢得了一些 Kaggle 比赛我得到了一些最先进的结果。但是当这些信息传达给你时已经是二手信息了。所以尝试一些东西真的很棒。而且尤其是在深度学习课程中我注意到我的一些学生尝试了我说的这个技术他们第二天就进入了 Kaggle 比赛的前十名他们说好的这算是非常有效。Kaggle 比赛有很多原因是有帮助的。但其中一个最好的方式是比赛结束后发生的事情所以对于现在即将结束的比赛确保你观看论坛看看人们在分享解决方案方面分享了什么如果你想了解更多可以自由地问问获胜者嘿你能告诉我更多关于这个或那个吗。人们通常很乐意解释。然后最好是尝试自己复制一下。这可以变成一个很棒的博客文章或很棒的内核可以说某某说他们使用了这个技术这里是这个技术的一个非常简短的解释这里是一点代码展示它是如何实现的这里是结果展示你可以得到相同的结果。这也可以是一个非常有趣的写作。 数据尽可能易于理解总是很好的。因此在这种情况下来自 Kaggle 的数据使用各种整数表示假期。我们可以只使用一个布尔值来表示是否是假期。所以只需清理一下 train.StateHoliday train.StateHoliday!0 test.StateHoliday test.StateHoliday!0我们有很多不同的表需要将它们全部合并在一起。我有一种用 Pandas 合并事物的标准方法。我只是使用了 Pandas 的合并函数具体来说我总是进行左连接。左连接是保留左表中的所有行你有一个关键列将其与右侧表中的关键列匹配然后合并那些也存在于右表中的行。 def join_df(left, right, left_on, right_onNone, suffix_y):if right_on is None: right_on left_onreturn left.merge(right, howleft, left_onleft_on,right_onright_on, suffixes(, suffix))我总是进行左连接的关键原因是在进行连接之后我总是检查右侧是否有现在为空的内容 store join_df(store, store_states, Store) len(store[store.State.isnull()])因为如果是这样那就意味着我漏掉了一些东西。我没有在这里展示但我也检查了行数在之前和之后是否有变化。如果有变化那就意味着右侧表不是唯一的。所以即使我确定某件事是真的我也总是假设我搞砸了。所以我总是检查。 我可以继续将州名合并到天气中 weather join_df(weather, state_names, file, StateName)如果你看一下谷歌趋势表它有这个周范围我需要将其转换为日期以便加入它 在 Pandas 中这样做的好处是Pandas 让我们可以访问所有的 Python。例如在系列对象内部有一个.str属性可以让你访问所有的字符串处理函数。就像.cat让你访问分类函数一样.dt让你访问日期时间函数。所以现在我可以拆分该列中的所有内容。 googletrend[Date]googletrend.week.str.split( - ,expandTrue)[0] googletrend[State]googletrend.file.str.split(_, expandTrue)[2] googletrend.loc[googletrend.StateNI, State] HB,NI使用这些 Pandas 函数非常重要因为它们将被向量化加速通常通过 SIMD 至少通过 C 代码以便运行得又快又顺利。 和往常一样让我们为我们的日期添加日期元数据 add_datepart(weather, Date, dropFalse) add_datepart(googletrend, Date, dropFalse) add_datepart(train, Date, dropFalse) add_datepart(test, Date, dropFalse)最后我们基本上是在对所有这些表进行去规范化。我们将把它们全部放入一个表中。因此在谷歌趋势表中它们主要是按州划分的趋势但也有整个德国的趋势所以我们将整个德国的趋势放入一个单独的数据框中以便我们可以加入它 trend_de googletrend[googletrend.file Rossmann_DE]因此我们将有这个州的谷歌趋势和整个德国的谷歌趋势。 现在我们可以继续为训练集和测试集同时加入。然后检查两者都没有空值。 store join_df(store, store_states, Store) len(store[store.State.isnull()])0joined join_df(train, store, Store) joined_test join_df(test, store, Store) len(joined[joined.StoreType.isnull()]),len(joined_test[joined_test.StoreType.isnull()])(0, 0)joined join_df(joined, googletrend, [State,Year, Week]) joined_test join_df(joined_test, googletrend, [State,Year, Week]) len(joined[joined.trend.isnull()]),len(joined_test[joined_test.trend.isnull()])(0, 0)joined joined.merge(trend_de, left, [Year, Week], suffixes(, _DE)) joined_test joined_test.merge(trend_de, left, [Year, Week], suffixes(, _DE)) len(joined[joined.trend_DE.isnull()]),len(joined_test[joined_test.trend_DE.isnull()])(0, 0)joined join_df(joined, weather, [State,Date]) joined_test join_df(joined_test, weather, [State,Date]) len(joined[joined.Mean_TemperatureC.isnull()]),len(joined_test[joined_test.Mean_TemperatureC.isnull()])(0, 0)我的合并函数如果有两列是相同的我将左侧的后缀设置为空这样它就不会影响名称右侧设置为_y。 在这种情况下我不想要任何重复的内容所以我只是浏览并删除了它们 for df in (joined, joined_test):for c in df.columns:if c.endswith(_y):if c in df.columns: df.drop(c, inplaceTrue, axis1) for df in (joined,joined_test):df[CompetitionOpenSinceYear] \df.CompetitionOpenSinceYear.fillna(1900).astype(np.int32)df[CompetitionOpenSinceMonth] \df.CompetitionOpenSinceMonth.fillna(1).astype(np.int32)df[Promo2SinceYear] \df.Promo2SinceYear.fillna(1900).astype(np.int32)df[Promo2SinceWeek] \df.Promo2SinceWeek.fillna(1).astype(np.int32)这家商店的主要竞争对手自某个日期以来一直开业。因此我们可以使用 Pandas 的to_datetime我传入年、月和日。所以这将给我们一个错误除非它们都有年和月所以我们将缺失的部分填充为 1900 年和 1 月见上文。而我们真正想知道的是这家商店在这个特定记录时已经开业多久了所以我们可以进行日期相减 for df in (joined,joined_test):df[CompetitionOpenSince] \pd.to_datetime(dict(yeardf.CompetitionOpenSinceYear,monthdf.CompetitionOpenSinceMonth, day15))df[CompetitionDaysOpen] \df.Date.subtract(df.CompetitionOpenSince).dt.days现在如果你考虑一下有时竞争对手的开业时间晚于这一行所以有时会是负数。而且可能没有意义有负数即将在 x 天后开业。现在话虽如此我绝不会在没有先运行包含它和不包含它的模型的情况下放入这样的东西。因为我们对数据的假设往往是不正确的。在这种情况下我没有发明任何这些预处理步骤。我写了所有的代码但它都是基于第三名获奖者的 GitHub 存储库。因此知道在 Kaggle 竞赛中获得第三名需要做什么我相当肯定他们会检查每一个这些预处理步骤并确保它实际上提高了他们的验证集分数。 for df in (joined,joined_test):df.loc[df.CompetitionDaysOpen0, CompetitionDaysOpen] 0df.loc[df.CompetitionOpenSinceYear1990,CompetitionDaysOpen]0[1:30:44] 因此我们将创建一个神经网络其中一些输入是连续的而另一些是分类的。这意味着在我们的神经网络中我们基本上会有这种初始权重矩阵。我们将有这个输入特征向量。一些输入将只是普通的连续数字例如最高温度到最近商店的公里数而另一些将被有效地独热编码。但我们实际上不会将其存储为独热编码。我们实际上会将其存储为索引。 因此神经网络模型需要知道这些列中的哪些应该基本上创建一个嵌入即哪些应该被视为独热编码哪些应该直接输入到线性层中。当我们到达那里时我们将告诉模型哪个是哪个但实际上我们需要提前考虑哪些我们想要视为分类变量哪些是连续变量。特别是我们要将其视为分类的东西我们不希望创建比我们需要的更多的类别。让我告诉你我的意思。 这次比赛的第三名决定将比赛开放的月数作为一个他们要用作分类变量的东西。为了避免创建比需要的更多的类别他们将其截断到 24 个月。他们说超过 24 个月的任何东西截断到 24 个。因此这里是比赛开放的唯一值从零到 24。这意味着将会有一个嵌入矩阵基本上会有一个嵌入向量用于尚未开放的事物0用于一个月开放的事物1依此类推。 for df in (joined,joined_test):df[CompetitionMonthsOpen] df[CompetitionDaysOpen]//30df.loc[df.CompetitionMonthsOpen24,CompetitionMonthsOpen] 24 joined.CompetitionMonthsOpen.unique()array([24, 3, 19, 9, 0, 16, 17, 7, 15, 22, 11, 13, 2, 23, 12, 4, 10, 1, 14, 20, 8, 18, 6, 21, 5]现在他们绝对可以将其作为一个连续变量来处理[1:33:14]。他们本可以只是在这里放一个数字表示开放了多少个月然后将其视为连续变量直接输入到初始权重矩阵中。但我发现显然这些竞争对手也发现了尽可能地将事物视为分类变量是最好的。这样做的原因是当你通过一个嵌入矩阵传递一些内容时意味着每个级别可以被完全不同地处理。例如在这种情况下某物是否开放了零个月或一个月是非常不同的。因此如果你将其作为连续变量输入神经网络将很难找到具有这种巨大差异的功能形式。这是可能的因为神经网络可以做任何事情。但如果你不让它变得容易。另一方面如果你使用嵌入将其视为分类变量那么零和一将有完全不同的向量。因此尤其是在你有足够的数据时尽可能地将列视为分类变量是一个更好的主意。当我说尽可能时基本上意味着基数不要太高。因此如果这是每一行上唯一不同的销售 ID 号码你不能将其视为分类变量。因为那将是一个巨大的嵌入矩阵而且每样东西只出现一次或者是距离最近商店的公里数到小数点后两位你也不会将其作为分类变量。 这是他们在这次比赛中都使用的经验法则。事实上如果我们滚动到他们的选择这是他们的做法 他们的连续变量是真正连续的东西比如到竞争对手的公里数温度等。而其他一切基本上他们都视为分类变量。 今天就到这里。下次我们将结束这个话题。我们将看看如何将这个转化为神经网络并总结一下。到时见 机器学习 1第 12 课 原文medium.com/hiromi_suenaga/machine-learning-1-lesson-12-6c2512e005a3 译者飞龙 协议CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它这些笔记将继续更新和改进。非常感谢 Jeremy 和 Rachel 给了我这个学习的机会。 视频 / 笔记本 我想今天我们可以完成在这个 Rossmann 笔记本中的工作看一下时间序列预测和结构化数据分析。然后我们可能会对我们学到的一切进行一个小小的复习因为信不信由你这就是结尾。关于机器学习没有更多需要知道的东西只有你将在下个学期和余生中学到的一切。但无论如何我没有别的要教的了。所以我会做一个小小的复习然后我们将涵盖课程中最重要的部分那就是思考如何正确、有效地使用这种技术以及如何让它对社会产生积极影响的方式。 上次我们谈到了这样一个想法当我们试图构建这个 CompetitionMonthsOpen 派生变量时实际上我们将其截断为不超过 24 个月我们谈到了原因因为我们实际上希望将其用作分类变量因为分类变量由于嵌入具有更多的灵活性神经网络可以如何使用它们。所以这就是我们离开的地方。 for df in (joined,joined_test):df[CompetitionMonthsOpen] df[CompetitionDaysOpen]//30df.loc[df.CompetitionMonthsOpen24, CompetitionMonthsOpen] 24 joined.CompetitionMonthsOpen.unique()array([24, 3, 19, 9, 0, 16, 17, 7, 15, 22, 11, 13, 2, 23, 12, 4, 10, 1, 14, 20, 8, 18, 6, 21, 5])让我们继续进行下去。因为这个笔记本中发生的事情可能适用于你处理的大多数时间序列数据集。正如我们所讨论的虽然我们在这里使用了df.apply但这是在每一行上运行一段 Python 代码速度非常慢。所以只有在找不到可以一次对整列进行操作的矢量化 pandas 或 numpy 函数时才这样做。但在这种情况下我找不到一种方法可以在不使用任意 Python 的情况下将年份和周数转换为日期。 还值得记住这个 lambda 函数的概念。每当你尝试将一个函数应用到某个东西的每一行或张量的每个元素时如果没有已经存在的矢量化版本你将不得不调用像DataFrame.apply这样的东西它将运行你传递给每个元素的函数。所以这基本上是函数式编程中的映射因为很多时候你想要传递给它的函数是你只会使用一次然后丢弃的东西。使用这种 lambda 方法非常常见。所以这个 lambda 是为了告诉df.apply要使用什么而创建的函数。 for df in (joined,joined_test):df[Promo2Since] pd.to_datetime(df.apply(lambda x: Week(x.Promo2SinceYear, x.Promo2SinceWeek).monday(), axis1).astype(pd.datetime))df[Promo2Days] df.Date.subtract(df[Promo2Since]).dt.days我们也可以用不同的方式来写这个 [3:16]。以下两个单元格是相同的 一种方法是定义函数create_promo2since(x)然后通过名称传递它另一种方法是使用 lambda 在现场定义函数。所以如果你不熟悉创建和使用 lambda练习和玩弄df.apply是一个很好的练习方法。 持续时间 [4:32] 让我们来谈谈这个持续时间部分起初可能看起来有点具体但实际上并不是。我们要做的是看三个字段“促销”、“州假期”、“学校假期” 所以基本上我们有一个表格 对于每个商店对于每个日期那个商店在那天有促销活动 那个地区的那家店铺在那天有学校假期吗 那个地区的那家店铺在那天有州假期吗 这些事情是事件。带有事件的时间序列非常常见。如果你正在查看石油和天然气钻探数据你试图说的是通过这根管道的流量这里是一个代表何时触发了某个警报的事件或者这里是一个钻头卡住的事件或者其他。所以像大多数时间序列一样某种程度上会倾向于代表一些事件。事件发生在某个时间点本身就很有趣但很多时候时间序列也会显示事件发生前后的情况。例如在这种情况下我们正在进行杂货销售预测。如果即将到来一个假期销售额在假期前后很可能会更高在假期期间会更低如果这是一个城市店铺的话。因为你要在离开前备货带东西然后回来时你就得重新填满冰箱例如。虽然我们不必进行这种特征工程来专门创建关于假期前后的特征但是神经网络我们能够给神经网络提供它需要的信息它就不必学习这些信息。它学习的越少我们就能够利用我们已有的数据做更多事情利用我们已有的规模架构做更多事情。因此即使对于神经网络这样的东西特征工程仍然很重要因为这意味着我们将能够利用我们拥有的有限数据取得更好的结果利用我们拥有的有限计算能力取得更好的结果。 因此这里的基本思想是当我们的时间序列中有事件时我们希望为每个事件创建两个新列[7:20] 还有多久这个事件再次发生。 上次那个事件发生已经多久了。 换句话说距离下一个州假期还有多久距离上一个州假期已经多久了。所以这不是我知道存在的库或任何其他东西。所以我手工写在这里。 def get_elapsed(fld, pre):day1 np.timedelta64(1, D)last_date np.datetime64()last_store 0res []for s,v,d in zip(df.Store.values,df[fld].values, df.Date.values):if s ! last_store:last_date np.datetime64()last_store sif v: last_date dres.append(((d-last_date).astype(timedelta64[D]) / day1))df[prefld] res因此重要的是我需要按店铺来做这个。所以我想说对于这家店铺上次促销是什么时候即自上次促销以来多长时间下次促销还有多长时间例如。 我要做的是这样的。我将创建一个小函数它将接受一个字段名然后我将依次传递Promo、StateHoliday和SchoolHoliday。让我们以学校假期为例。所以我们说字段等于学校假期然后我们说get_elapsed(SchoolHoliday, After)。让我告诉你这将会做什么。我们首先按店铺和日期排序。现在当我们循环遍历时我们将在店铺内循环遍历。所以店铺11 月 1 日1 月 2 日1 月 3 日依此类推。 fld SchoolHoliday df df.sort_values([Store, Date]) get_elapsed(fld, After) df df.sort_values([Store, Date], ascending[True, False]) get_elapsed(fld, Before)当我们循环遍历每家店铺时我们基本上会说这一行是学校假期还是不是[8:56]。如果是学校假期那么我们将跟踪名为last_date的变量表示我们看到学校假期的最后日期。然后我们将追加到我们的结果中自上次学校假期以来的天数。 使用zip的重要性[9:26] 有一些有趣的特性。其中一个是使用zip。我实际上可以通过编写for row in df.iterrows():然后从每行中获取我们想要的字段来更简单地编写这个。结果表明这比我现在的版本慢 300 倍。基本上遍历 DataFrame 并从行中提取特定字段具有很多开销。更快的方法是遍历 numpy 数组。因此如果您取一个 Series例如df.Store然后在其后添加.values那么就会获取该系列的 numpy 数组。 这里有三个 numpy 数组。一个是商店 ID一个是fld是什么在这种情况下那是学校假期还有日期。因此现在我想要循环遍历每个列表的第一个、第二个和第三个。这是一个非常常见的模式。我基本上在我写的每个笔记本中都需要做类似的事情。而要做到这一点的方法就是使用 zip。因此zip意味着逐个循环遍历这些列表。然后这里是我们可以从第一个列表、第二个列表和第三个列表中获取元素的地方 因此如果您还没有使用 zip 进行过多尝试那么这是一个非常重要的函数需要练习。就像我说的我几乎在我写的每个笔记本中都使用它——每次您都必须同时循环遍历一堆列表。 因此我们将循环遍历每个商店、每个学校假期和每个日期。 问题它是否循环遍历了所有可能的组合不是。只有 111、222 等。 因此在这种情况下我们基本上想要说让我们获取第一个商店、第一个学校假期和第一个日期。因此对于商店 11 月 1 日学校假期是真还是假。因此如果是学校假期我会通过记录上次看到学校的日期来跟踪这一事实并附加自上次学校假期以来的时间长度。如果商店 ID 与上一个商店 ID 不同那么我现在已经到了一个全新的商店这种情况下我基本上必须重置一切。 问题对于我们没有最后一个假期的第一个点会发生什么是的所以我只是将其设置为一些任意的起始点np.datetime64()最终会得到我记不清了要么是最大的日期要么是最小的日期。您可能需要在之后用缺失值或零替换它。不过好处是由于 ReLU 的存在神经网络很容易截断极端值。因此在这种情况下我没有对其做任何特殊处理。我最终得到了这些像负十亿日期时间戳但仍然可以正常工作。 接下来要注意的是我需要对训练集和测试集进行一些处理。在前一节中我实际上添加了一个循环对训练 DataFrame 和测试 DataFrame 进行以下操作 对于每个数据框中的每个单元格我都进行了以下操作 接下来有一系列单元格我首先要为训练集和测试集运行。在这种情况下我有两个不同的单元格一个将 df 设置为训练集一个将其设置为测试集。 我使用的方法是我只运行第一个单元格即跳过 dftest[columns]然后运行下面的所有单元格这样就可以对训练集进行全部操作。然后我回来运行第二个单元格然后运行下面的所有单元格。因此这个笔记本不是设计为从头到尾顺序运行的。但是它被设计为以这种特定方式运行。我提到这一点是因为这可能是一个有用的技巧。当然你可以将下面的所有内容放在一个函数中将数据框传递给它并在测试集上调用一次在训练集上调用一次。但我更喜欢有点实验更交互地看着每一步。因此这种方式是在不将其转换为函数的情况下在不同数据框上运行某些内容的简单方法。 如果我按店铺和日期排序那么这就是在追踪上次发生某事的时间[15:11]。因此 d - last_date 最终会告诉我距离上次学校假期有多少天 现在如果我按日期降序排列并调用完全相同的函数那么它会告诉我距离下一个假期还有多久 所以这是一个很好的技巧可以将任意事件时间添加到你的时间序列模型中。例如如果你现在正在进行厄瓜多尔杂货比赛也许这种方法对其中的各种事件也会有用。 为了国家假期为了促销我们来做一下 fld StateHoliday df df.sort_values([Store, Date]) get_elapsed(fld, After) df df.sort_values([Store, Date], ascending[True, False]) get_elapsed(fld, Before) fld Promo df df.sort_values([Store, Date]) get_elapsed(fld, After) df df.sort_values([Store, Date], ascending[True, False]) get_elapsed(fld, Before)滚动函数[16:11] 我们在这里看的下一件事是滚动函数。在 pandas 中滚动是我们创建所谓的窗口函数的方式。假设我有这样的一些数据。我可以说好让我们在这个点周围创建一个大约 7 天的窗口。 然后我可以取得那七天窗口内的平均销售额。然后我可以在这里做同样的事情取得那七天窗口内的平均销售额。 所以如果对每个点都这样做并连接起那些平均值你最终会得到一个移动平均值 移动平均值的更通用版本是窗口函数即将某个函数应用于每个点周围的一些数据窗口。很多时候我在这里展示的窗口实际上并不是你想要的。如果你试图构建一个预测模型你不能将未来作为移动平均的一部分。因此通常你实际上需要一个在某个点结束的窗口而不是点位于窗口中间。那就是我们的窗口函数 Pandas 允许你使用这里的滚动来创建任意窗口函数 bwd df[[Store]columns].sort_index() \.groupby(Store).rolling(7, min_periods1).sum() fwd df[[Store]columns].sort_index(ascendingFalse) \.groupby(Store).rolling(7, min_periods1).sum()第一个参数表示我想将函数应用到多少个时间步。第二个参数表示如果我处于边缘换句话说如果我处于上图的左边缘你应该将其设置为缺失值因为我没有七天的平均值或者要使用的最小时间段数是多少。所以这里我设置为 1。然后你还可以选择设置窗口在周期的开始、结束或中间。然后在其中你可以应用任何你喜欢的函数。所以这里我有我的按店铺每周求和。所以有一个很简单的方法来得到移动平均值或其他内容。 我应该提到如果你去 Pandas 的时间序列页面左侧有一个很长的索引列表。这是因为 Wes McKinney 创造了这个他最初是在对冲基金交易中我相信。他的工作都是关于时间序列的。所以我认为 Pandas 最初非常专注于时间序列而且现在它可能仍然是 Pandas 最强大的部分。所以如果你在处理时间序列计算你绝对应该尝试学习整个 API。关于时间戳、日期偏移、重采样等方面有很多概念性的内容需要理解。但这绝对值得否则你将手动编写这些循环。这将比利用 Pandas 已经做的事情花费更多时间。当然Pandas 将为你使用高度优化的向量化 C 代码而你的版本将在 Python 中循环。所以如果你在处理时间序列的工作学习完整的 Pandas 时间序列 API 是绝对值得的。它们几乎和其他任何时间序列 API 一样强大。 好的经过所有这些你可以看到这些起始值我提到的 —— 稍微偏向极端。所以你可以看到9 月 17 日商店 1 距上次学校假期 13 天。16 日是 121110依此类推。 我们目前处于促销期。这里这是促销前一天 在它的左边我们在上次促销之后有 9 天等等。这就是我们如何可以向我们的时间序列添加事件计数器的方式当你在处理时间序列时这通常是一个好主意。 分类与连续 [21:46] 现在我们已经做到了我们的数据集中有很多列所以我们将它们分成分类和连续列。我们将在回顾部分更多地讨论这一点但这些将是我将为其创建嵌入的所有内容 而 contin_vars 是我将直接输入模型的所有东西。例如我们有 CompetitionDistance这是到最近竞争对手的距离最高温度以及我们有一个分类值 DayOfWeek。所以这里我们有最高温度可能是 22.1因为德国使用摄氏度我们有到最近竞争对手的距离可能是 321.7 公里。然后我们有星期几也许星期六是 6。前两个数字将直接进入我们要输入神经网络的向量中。我们将在稍后看到但实际上我们会对它们进行归一化或多或少。但这个分类变量我们不会。我们需要将它通过一个嵌入层。所以我们将有一个 7x4 的嵌入矩阵例如维度为 4 的嵌入。这将查找第 6 行以获取四个项目。所以星期六将变成长度为 4 的向量然后添加到这里。 这就是我们的连续和分类变量将如何工作。 然后我们将所有的分类变量转换为 Pandas 的分类变量方式与之前相同 for v in cat_vars: joined[v] joined[v].astype(category).cat.as_ordered()然后我们将应用相同的映射到测试集。如果在训练集中星期六是 6apply_cats 确保在测试集中星期六也是 6 apply_cats(joined_test, joined)对于连续变量确保它们都是浮点数因为 PyTorch 期望所有东西都是浮点数。 for v in contin_vars:joined[v] joined[v].fillna(0).astype(float32)joined_test[v] joined_test[v].fillna(0).astype(float32)然后这是我使用的另一个小技巧。 idxs get_cv_idxs(n, val_pct150000/n) joined_samp joined.iloc[idxs].set_index(Date) samp_size len(joined_samp); samp_size150000这两个单元格上面和下面都定义了一个叫做joined_samp的东西。其中一个将它们定义为整个训练集另一个将它们定义为一个随机子集。所以我的想法是我在样本上做所有的工作确保一切都运行良好尝试不同的超参数和架构。然后当我对此满意时我会回过头来运行下面这行代码说好现在让整个数据集成为样本然后重新运行它。 samp_size n joined_samp joined.set_index(Date)这是一个很好的方法与我之前向您展示的类似它让您可以在笔记本中使用相同的单元格首先在样本上运行然后稍后回来并在完整数据集上运行。 数据标准化 现在我们有了joined_samp我们可以像以前一样将其传递给 proc_df 来获取因变量以处理缺失值。在这种情况下我们传递了一个额外的参数do_scaleTrue。这将减去均值并除以标准差。 df, y, nas, mapper proc_df(joined_samp, Sales, do_scaleTrue) yl np.log(y)这是因为如果我们的第一层只是一个矩阵乘法。这是我们的权重集。我们的输入大约是 0.001 和另一个是 10⁶例如然后我们的权重矩阵已经初始化为 0 到 1 之间的随机数。然后基本上 10⁶的梯度将比 0.001 大 9 个数量级这对优化不利。因此通过将所有内容标准化为均值为零标准差为 1 开始这意味着所有的梯度将在同一种规模上。 我们在随机森林中不需要这样做因为在随机森林中我们只关心排序。我们根本不关心值。但是对于线性模型和由线性模型层构建而成的东西即神经网络我们非常关心规模。因此do_scaleTrue为我们归一化我们的数据。现在由于它为我们归一化了数据它会返回一个额外的对象mapper其中包含了每个连续变量被归一化时的均值和标准差。原因是我们将不得不在测试集上使用相同的均值和标准差因为我们需要我们的测试集和训练集以完全相同的方式进行缩放否则它们将具有不同的含义。 因此确保您的测试集和训练集具有相同的分类编码、相同的缺失值替换和相同的缩放归一化的细节非常重要因为如果您没有做对那么您的测试集根本不会起作用。但是如果您按照这些步骤操作它将正常工作。我们还对因变量取对数这是因为在这个 Kaggle 竞赛中评估指标是均方根百分比误差。均方根百分比误差意味着我们根据我们的答案和正确答案之间的比率受到惩罚。我们在 PyTorch 中没有一个叫做均方根百分比误差的损失函数。我们可以编写一个但更简单的方法是对因变量取对数因为对数之间的差异与比率相同。因此通过取对数我们可以轻松地得到这个效果。 你会注意到 Kaggle 上绝大多数的回归竞赛要么使用均方根百分比误差要么使用对数的均方根误差作为他们的评估指标。这是因为在现实世界的问题中大多数时候我们更关心比率而不是原始差异。因此如果您正在设计自己的项目很可能您会考虑使用因变量的对数。 然后我们创建一个验证集正如我们之前学到的大多数情况下如果你的问题涉及时间因素你的验证集可能应该是最近的时间段而不是一个随机子集。所以这就是我在这里做的 val_idx np.flatnonzero((df.indexdatetime.datetime(2014,9,17)) (df.indexdatetime.datetime(2014,8,1)))当我完成建模并找到一个架构、一组超参数、一定数量的 epochs 以及所有能够很好工作的东西时如果我想让我的模型尽可能好我会重新在整个数据集上进行训练 — 包括验证集。现在至少目前为止Fast AI 假设你有一个验证集所以我的一种折中方法是将我的验证集设置为只有一个索引即第一行 val_idx[0]这样所有的代码都能继续运行但实际上没有真正的验证集。显然如果你这样做你需要确保你的最终训练与之前的完全相同包括相同的超参数、相同数量的 epochs因为现在你实际上没有一个正确的验证集来进行检查。 问题我有一个关于之前讨论过的 get_elapsed 函数的问题。在 get_elapsed 函数中我们试图找出下一个假期还有多少天。所以每年假期基本上是固定的比如 7 月 4 日、12 月 25 日都会有假期几乎没有变化。那么我们不能从以前的年份查找然后列出今年将要发生的所有假期吗也许可以。我的意思是在这种情况下我猜对于Promo和一些假期会改变比如复活节这种方法可以适用于所有情况。而且运行起来也不会花太长时间。如果你的数据集太大导致运行时间太长你可以在一年内运行一次然后以某种方式复制。但在这种情况下没有必要。我总是把我的时间看得比电脑的时间更重要所以我尽量保持事情尽可能简单。 创建一个模型 现在我们可以创建我们的模型。要创建我们的模型我们必须像在 Fast AI 中一样创建一个模型数据对象。所以一个列模型数据对象只是一个代表训练集、验证集和可选测试集的标准列结构化数据的模型数据对象。 md ColumnarModelData.from_data_frame(PATH, val_idx, df, yl.astype(np.float32), cat_fldscat_vars, bs128, test_dfdf_test )我们只需要告诉它哪些变量应该被视为分类变量。然后传入我们的数据框。 对于我们的每个分类变量这里是它所拥有的类别数量。因此对于我们的每个嵌入矩阵这告诉我们该嵌入矩阵中的行数。然后我们定义我们想要的嵌入维度。如果你在进行自然语言处理那么需要捕捉一个词的含义和使用方式的所有细微差别的维度数量经验性地被发现大约是 600。事实证明当你使用小于 600 的嵌入矩阵进行自然语言处理模型时结果不如使用大小为 600 的好。超过 600 后似乎没有太大的改进。我会说人类语言是我们建模的最复杂的事物之一所以我不会指望你会遇到许多或任何需要超过 600 维度的嵌入矩阵的分类变量。另一方面有些事物可能具有相当简单的因果关系。例如StateHoliday ——也许如果某事是假日那么在城市中的商店会有一些行为在乡村中的商店会有一些其他行为就是这样。也许这是一个相当简单的关系。因此理想情况下当你决定使用什么嵌入大小时你应该利用你对领域的知识来决定关系有多复杂因此我需要多大的嵌入。实际上你几乎永远不会知道这一点。你只知道这一点因为也许别人以前已经做过这方面的研究并找到了答案就像在自然语言处理中一样。因此在实践中你可能需要使用一些经验法则并尝试一些经验法则后你可以尝试再高一点再低一点看看哪种方法有帮助。所以这有点像实验。 cat_sz[(c, len(joined_samp[c].cat.categories)1) for c in cat_vars ] cat_sz[(Store, 1116),(DayOfWeek, 8),(Year, 4),(Month, 13),(Day, 32),(StateHoliday, 3),(CompetitionMonthsOpen, 26),(Promo2Weeks, 27),(StoreType, 5),(Assortment, 4),(PromoInterval, 4),(CompetitionOpenSinceYear, 24),(Promo2SinceYear, 9),(State, 13),(Week, 53),(Events, 22),(Promo_fw, 7),(Promo_bw, 7),(StateHoliday_fw, 4),(StateHoliday_bw, 4),(SchoolHoliday_fw, 9),(SchoolHoliday_bw, 9)]这里是我的经验法则。我的经验法则是看看该类别有多少个离散值即嵌入矩阵中的行数并使嵌入的维度为该值的一半。所以如果是星期几第二个有八行和四列。这里是(c1)//2 ——列数除以二。但是我说不要超过 50。在这里你可以看到对于商店第一行有 116 家商店只有一个维度为 50。为什么是 50我不知道。到目前为止似乎效果还不错。你可能会发现你需要一些稍微不同的东西。实际上对于厄瓜多尔杂货比赛我还没有真正尝试过调整这个但我认为我们可能需要一些更大的嵌入大小。但这是可以摆弄的东西。 emb_szs [(c, min(50, (c1)//2)) for _,c in cat_sz] emb_szs[(1116, 50),(8, 4),(4, 2),(13, 7),(32, 16),(3, 2),(26, 13),(27, 14),(5, 3),(4, 2),(4, 2),(24, 12),(9, 5),(13, 7),(53, 27),(22, 11),(7, 4),(7, 4),(4, 2),(4, 2),(9, 5),(9, 5)]问题随着基数大小变得越来越大您正在创建越来越宽的嵌入矩阵。因此您是否会因为选择了 70 个参数而极大地增加过拟合的风险因为模型永远不可能捕捉到数据实际巨大的所有变化[36:44]这是一个很好的问题所以让我提醒您一下现代机器学习和旧机器学习之间的区别的黄金法则。在旧的机器学习中我们通过减少参数数量来控制复杂性。在现代机器学习中我们通过正则化来控制复杂性。所以简短的答案是不。我不担心过拟合因为我避免过拟合的方式不是通过减少参数数量而是通过增加丢弃率或增加权重衰减。现在说到这一点对于特定的嵌入没有必要使用比我需要的更多的参数。因为正则化是通过给模型更多的随机数据或实际上对权重进行惩罚来惩罚模型。所以我们宁愿不使用比必要更多的参数。但是在设计架构时我的一般经验法则是在参数数量方面慷慨一些。在这种情况下如果经过一些工作后我们觉得商店实际上似乎并不那么重要。那么我可能会手动去修改它使其更小。或者如果我真的发现这里的数据不够我要么过拟合了要么使用的正则化比我感到舒适的要多那么您可能会回去。但我总是会从参数慷慨的角度开始。在这种情况下这个模型表现得相当不错。 好的现在我们有一个包含每个嵌入矩阵的行数和列数的元组列表[38:41]。所以当我们调用get_learner来创建我们的神经网络时这是我们传入的第一件事 emb_szs: 我们的每个嵌入有多大 len(df.columns)-len(cat_vars): 我们有多少连续变量 [1000,500]: 每一层要创建多少个激活 [0.001,0.01]: 每一层使用的丢弃率是多少 m md.get_learner(emb_szs, len(df.columns)-len(cat_vars),0.04, 1, [1000,500], [0.001,0.01], y_rangey_range ) m.summary()然后我们可以继续调用fit。我们训练了一段时间得到了大约 0.1 的分数。 m.fit(lr, 1, metrics[exp_rmspe])[ 0\. 0.01456 0.01544 0.1148 ]m.fit(lr, 3, metrics[exp_rmspe])[ 0\. 0.01418 0.02066 0.12765] [ 1\. 0.01081 0.01276 0.11221] [ 2\. 0.00976 0.01233 0.10987]m.fit(lr, 3, metrics[exp_rmspe], cycle_len1)[ 0\. 0.00801 0.01081 0.09899] [ 1\. 0.00714 0.01083 0.09846] [ 2\. 0.00707 0.01088 0.09878]所以我尝试在测试集上运行这个并且上周我把它提交到了 Kaggle这里是结果[39:25] 私人分数 0.107公共分数 0.103。所以让我们看看这将如何进行。让我们从公共排行榜开始 在 3000 个参赛者中排名第 340。这不太好。让我们试试私人排行榜排名是 0.107。 哦第 5 名[40:30]。所以希望您现在在想哦有一些 Kaggle 比赛即将结束我参加了并且花了很多时间在公共排行榜上取得好成绩。我想知道那是否是个好主意。答案是否定的那不是。Kaggle 公共排行榜并不是要取代您精心开发的验证集。例如如果您正在进行冰山比赛哪些是船只哪些是冰山那么他们实际上在公共排行榜中放入了大约 4000 张合成图像而在私人排行榜中没有放入任何图像。所以这是 Kaggle 测试您的一个非常好的方面“您是否创建了一个好的验证集并且是否信任它”因为如果您更信任排行榜的反馈而不是验证反馈那么当您认为自己排名第 5 时您可能会发现自己排名第 350。在这种情况下我们实际上有一个相当不错的验证集因为正如您所看到的它大约是 0.1而我们实际上确实得到了大约 0.1。所以在这种情况下这个比赛的公共排行榜完全没有用。 问题那么公共排行榜的前几名实际上与私人排行榜的前几名有多少对应呢因为在流失预测挑战中有 4 个人完全超过了其他人[42:07]。这完全取决于情况。如果他们随机抽取公共和私人排行榜那么这应该是非常有指示性的。但也可能不是。所以在这种情况下公共排行榜上的第二名最终赢得了比赛。公共排行榜上的第一名排在第七位。事实上你可以看到这里的小绿色标记。而另外一个人则跃升了 96 个名次。 如果我们用刚刚看过的神经网络进入我们将跃升 350 个名次。所以这取决于情况。有时他们会告诉你公共排行榜是随机抽样的。有时他们会告诉你不是。通常你必须通过查看验证集结果和公共排行榜结果之间的相关性来判断它们之间的相关性有多好。有时如果有 2 或 3 个人远远领先于其他人他们可能已经发现了某种泄漏或类似的情况。这通常是一种存在某种技巧的迹象。 好的这就是 Rossmann这也是我们所有材料的结束。 回顾[44:21] 我们学会了两种训练模型的方法。一种是通过构建树另一种是使用 SGD。因此SGD 方法是一种可以训练线性模型或具有非线性层之间的线性层堆叠的模型的方法。而树构建具体将给我们一棵树。然后我们可以将树构建与装袋结合起来创建随机森林或者与提升结合起来创建 GBM或者其他一些略有不同的变体比如极端随机树。因此值得提醒自己这些东西是做什么的。所以让我们看一些数据。实际上让我们具体看看分类数据。因此分类数据可能看起来有几种可能性。比如我们有邮政编码所以我们有 94003 作为我们的邮政编码。然后我们有销售额比如 50。对于 94131销售额为 22等等。因此我们有一些分类变量。我们可以表示这种分类变量的几种方式。一种是只使用数字。也许一开始它不是一个数字。也许根本不是一个数字。也许一个分类变量是像旧金山、纽约、孟买和悉尼这样的城市。但我们可以通过任意决定给它们编号来将其转换为数字。因此它最终成为一个数字。我们可以使用这种任意的数字。因此如果发现相邻的邮政编码具有相似的行为那么邮政编码与销售额的图表可能看起来像这样例如 或者如果相邻的两个邮政编码在任何方面都没有相似的销售行为你会期望看到更像这样的情况 有点到处都是。所以有两种可能性。如果我们只是用这种方式对邮政编码进行编码那么随机森林会做什么是它会说好的我需要找到我的最佳分割点——使两侧的标准差尽可能小或在数学上等效地具有最低均方根误差的分割点。因此在这种情况下它可能会选择这里作为第一个分割点因为在左侧有一个平均值在另一侧有另一个平均值[48:07]。 然后对于它的第二个分割点它会说如何分割右侧它可能会说我会在这里分割因为现在我们有了这个平均值和这个平均值 最后它会说我们如何拆分中间部分然后它会说好的我会在中间拆分。所以你可以看到即使它贪婪地自上而下一次一次地进行拆分它仍然能够专注于它需要的拆分集合。唯一的原因是如果两半总是完全平衡那么它就无法做到这一点。但即使发生这种情况也不会是世界末日。它会在其他地方拆分下一次两部分树仍然完全平衡的可能性非常小。因此在实践中这完全没问题。 在第二种情况下它可以做同样的事情。即使一个邮政编码与其相邻的邮政编码之间在数字上没有关系。我们仍然可以看到如果在这里拆分一侧的平均值另一侧的平均值可能大约在这里 那么接下来它会在哪里拆分可能是在这里因为这一侧的平均值另一侧的平均值在这里。 所以可以做同样的事情。它将需要更多的拆分因为它将需要缩小到每个单独的大邮政编码和每个单独的小邮政编码。但这仍然没问题。所以当我们处理为随机森林或 GBM 构建决策树时我们 tend to encode our variables just as ordinals. 另一方面如果我们正在做神经网络或者像线性回归或逻辑回归这样的最简单版本它能做的最好就是绿色这一点一点也不好 而且这个也是一样的 所以一个序数对于线性模型或将线性和非线性模型堆叠在一起的模型来说并不是一个有用的编码。所以我们创建一个独热编码。就像这样 通过这种编码可以有效地创建一个小直方图其中每个级别都会有一个不同的系数。这样它可以做到它需要做的事情。 问题在什么时候这对你的系统变得太繁琐几乎从来没有。因为请记住在现实生活中我们实际上不需要创建那个矩阵。相反我们可以只有四个系数然后进行索引查找这在数学上等同于在独热编码上进行乘法。所以这不是问题。 有一件事要提到。我知道你们已经学到了更多关于事物的分析解决方案。在像线性回归这样的分析解决方案中你无法解决这种程度的共线性问题。换句话说如果不是孟买、纽约或旧金山你就知道某样东西在悉尼。换句话说这四个类别中的第四个与其他三个之间存在百分之百的共线性。因此如果你尝试以这种方式在分析上解决线性回归问题整个事情就会崩溃。现在请注意对于 SGD我们没有这样的问题。像 SGD 为什么会在乎呢我们只是沿着导数走一步。它会在乎一点因为最终共线性的主要问题在于有无限数量的同样好的解决方案。换句话说我们可以增加左边的所有这些减少这个。或者减少所有这些增加这个。它们会平衡。 当存在无限多个好的解决方案时意味着损失曲面上有很多平坦区域这可能会使优化变得更加困难。因此摆脱所有这些平坦区域的真正简单方法是添加一点正则化。因此如果我们添加了一点权重衰减比如 1e-7那么这就表示这些解决方案不再是完全相同的最好的解决方案是参数最小且彼此最相似的解决方案这将使其再次成为一个良好的损失函数。 问题您能澄清一下您提到为什么独热编码不会那么繁琐的那一点吗当然。如果我们有一个独热编码向量并且将其乘以一组系数那么这完全等同于简单地说让我们找到其中值为 1 的那个值。换句话说如果我们将1000存储为零0100存储为一0020存储为二那么这完全等同于只是说嘿查找数组中的那个值。 所以我们称这个版本为嵌入。因此嵌入是一个权重矩阵您可以将其与独热编码相乘。这只是一个计算快捷方式。但从数学上讲它是一样的。 解决线性模型的解析方法与使用 SGD 解决的方法之间存在关键差异。使用 SGD我们不必担心共线性等问题至少不像解析方法那样。然后使用 SGD 解决线性模型或单层或多层模型与使用树的区别树会对更少的事情提出异议。特别是您可以将序数作为您的分类变量并且正如我们之前学到的对于树我们也不必担心对连续变量进行归一化但是对于这些使用 SGD 训练的模型我们必须担心。 然后我们还学到了很多关于解释随机森林的知识。如果您感兴趣您可能会尝试使用相同的技术来解释神经网络。如果您想知道在神经网络中哪些特征很重要您可以尝试同样的方法依次对每列进行洗牌看看它对准确性的影响有多大。这将是您神经网络的特征重要性。然后如果您真的想玩得开心认识到那么对该列进行洗牌只是计算输出对该输入的敏感性的一种方式换句话说就是输出对该输入的导数。因此也许您可以直接要求 PyTorch 给您输出关于输入的导数看看是否会得到相同类型的答案。 您可以对偏依赖图做同样的事情。您可以尝试使用神经网络做完全相同的事情用相同的值替换列中的所有内容对 1960、1961、1962 进行绘图。我不知道有没有人在以前做过这些事情不是因为这是火箭科学而只是可能没有人想到或者不在库中我不知道。但如果有人尝试过我认为您会发现它很有用。这将成为一篇很棒的博客文章。甚至如果您想进一步也可以写成论文。所以这是一个您可以尝试的想法。因此大多数这些解释技术并不特别适用于随机森林。像树解释器这样的东西当然适用因为它们都是关于树内部的东西。 问题在树解释器中我们正在查看特征的路径及其贡献。在神经网络的情况下我猜每个激活在其路径上的贡献会是相同的对吗是的也许。我不知道。我还没有考虑过这个。问题继续我们如何从激活中推断出结论Jeremy说“推断”这个词要小心因为人们通常使用“推断”这个词来特指测试时间的预测。你的意思是对模型进行一种询问。我不确定。我们应该考虑一下。实际上Hinton 和他的一位学生刚刚发表了一篇关于如何用树来近似神经网络的论文就是出于这个原因。我还没有看过这篇论文。 问题在线性回归和传统统计学中我们关注的一件事是变化的统计显著性之类的东西。所以在考虑树解释器或者瀑布图我猜这只是一种可视化。我猜这在哪里适用因为我们可以看到哦是的这看起来很重要因为它导致了很大的变化但我们怎么知道它在传统上是否具有统计显著性所以大多数时候我不关心传统的统计显著性原因是现在统计显著性的主要驱动因素是数据量而不是实际重要性。而且现在您构建的大多数模型都会有如此多的数据以至于每一个微小的事情都会在统计上显著但其中大多数在实际上并不重要。因此我的主要关注点是实际重要性即这种影响的大小是否影响您的业务在我们处理的数据较少时统计显著性更为重要。如果您确实需要了解统计显著性例如因为您有一个非常小的数据集因为标记成本很高或者很难收集或者是一个罕见疾病的医疗数据集您总是可以通过自助法来获得统计显著性也就是说您可以随机重新对数据集进行多次抽样多次训练您的模型然后您可以看到预测的实际变化。因此通过自助法您可以将任何模型转化为能够给出置信区间的东西。有一篇由 Michael Jordan 撰写的论文其中有一种被称为小自助袋的技术实际上将这一点推进了一步如果您感兴趣那么这篇论文是值得一读的。 问题你说如果你在做随机森林时不需要一个独热编码矩阵。如果我们这样做会发生什么模型会有多糟糕我们实际上确实这样做了。记得我们有那个最大类别大小我们确实创建了一个独热编码我们这样做的原因是我们的特征重要性会告诉我们个别级别的重要性我们的部分依赖图我们可以包括个别级别。所以这并不一定会使模型变得更糟它可能会使它变得更好但它可能根本不会改变太多。在这种情况下它几乎没有改变。问题继续这也是我们在真实数据中注意到的一点如果基数更高比如说有 50 个级别如果你做独热编码随机森林表现得非常糟糕Jeremy是的没错。这就是为什么在 Fast.AI 中我们有最大分类大小因为在某个时候你的独热编码变量会变得太稀疏。所以我通常在 6 或 7 处截断。另外当你超过那个点时它变得不那么有用因为对于特征重要性来说要看的级别太多了。问题继续它是否可以只查看那些不重要的级别然后将那些显著的特征视为重要Jeremy是的这样也可以。就像一旦基数增加得太高你基本上就是把你的数据分割得太多了所以在实践中你的有序版本可能会更好。 没有时间来审查所有内容但这是关键概念然后记住我们可以使用的嵌入矩阵可能不只有一个系数实际上我们将有几个系数的维度这对于大多数线性模型来说并不实用。但一旦你有了多层模型那么现在就创建了一个相当丰富的类别表示你可以用它做更多的事情。 伦理与数据科学 幻灯片 现在让我们谈谈最重要的部分。我们在这门课程的早期谈到了很多机器学习实际上是有些误导的。人们关注预测准确性比如亚马逊有一个协同过滤算法用于推荐书籍最终推荐出它认为你最有可能高评的书。结果他们最终可能会推荐一本你已经有或者你已经知道并且本来就会购买的书这并没有太大价值。他们应该做的是找出哪本书可以推荐给你从而改变你的行为。这样我们实际上最大化了由于推荐而带来的销售增长。所以这种优化影响你的行为与仅仅提高预测准确性之间的区别的想法。提高预测准确性是一个非常重要的区别在学术界或行业中很少被讨论令人惊讶。在行业中更多地被讨论但在大多数学术界中被忽视。所以这是一个非常重要的想法即最终你的模型的目标想必是影响行为。所以请记住我实际上提到了我写的一篇关于这个的论文在那里我介绍了一种叫做传动系统方法的东西我谈到了如何将机器学习纳入到我们如何实际影响行为的方式中。这是一个起点但接下来的问题是如果我们试图影响行为我们应该影响什么样的行为以及如何影响当我们开始影响行为时可能意味着什么。因为现在很多公司你最终会在那里工作都是大公司你将会构建能够影响数百万人的东西。那意味着什么呢 实际上我不会告诉你这意味着什么因为我不知道[1:05:34]。我要做的只是让你意识到一些问题并让你相信其中两件事 你应该关心。 这些是重大的当前问题。 我希望你关心的主要原因是因为我希望你想成为一个好人并向你展示不考虑这些事情会让你成为一个坏人。但如果你不觉得有说服力我会告诉你这个事实。大众汽车被发现在排放测试中作弊。最终被判刑的人是实施那段代码的程序员。他们只是按照指示去做。所以如果你认为自己只是一个技术人员只是按照指示去做那是我的工作。我告诉你如果你这样做你可能会因为听从指示而被送进监狱所以 a)不要只是听从指示因为你可能会成为一个坏人b)你可能会被送进监狱。 第二件要意识到的事情是在当下你在工作中与二十个人开会大家都在讨论如何实施这个新功能每个人都在讨论[1:06:49]。每个人都在说“我们可以这样做这是一种建模的方式然后我们可以实施它这是这些约束条件”你心里有一部分在想我们是否应该这样做那不是考虑这个问题的正确时机因为在那时很难站出来说“对不起我不确定这是一个好主意”。你实际上需要提前考虑如何处理这种情况。所以我希望你现在考虑这些问题并意识到当你陷入其中时你可能甚至意识不到正在发生什么。那只是一个像其他会议一样的会议一群人在讨论如何解决这个技术问题。你需要能够认识到哦这实际上是一个具有道德影响的事情。 Rachel 实际上写了所有这些幻灯片。很抱歉她不能在这里展示因为她对这个问题进行了深入研究。她实际上曾身处困难环境亲眼目睹这些事情发生我们知道这是多么困难。但让我给你们一个了解发生的情况。 所以工程师试图解决工程问题并导致问题并不是一件新事。在纳粹德国IBM被称为 Hollerith 的集团Hollerith 是 IBM 的原始名称它来自于实际发明用于跟踪美国人口普查的打孔卡的人。这是世界上第一次大规模使用打孔卡进行数据收集。这变成了 IBM所以在这一点上仍然被称为 Hollerith。因此Hollerith 向纳粹德国出售了一个打孔卡系统每张打孔卡都会编码比如这是犹太人8吉普赛人12用毒气室处决6。这里有一张描述如何杀死这些不同人的卡片。因此一名瑞士法官裁定 IBM 的技术协助促成了纳粹分子的任务并犯下了反人类罪行。这导致了大约二千万平民的死亡。根据我从犹太虚拟图书馆得到这些图片和引用的观点他们认为“犹太人民的毁灭变得更不重要因为 IBM 的技术成就的振奋性质只会因为可以获得的奇幻利润而进一步提高”。这是很久以前的事情希望你们不会最终在促成种族灭绝的公司工作。但也许你们会。 www.nytimes.com/2017/10/27/world/asia/myanmar-government-facebook-rohingya.html www.nytimes.com/2017/10/24/world/asia/myanmar-rohingya-ethnic-cleansing.html 也许你们会去 Facebook他们现在正在促成种族灭绝。我认识在 Facebook 工作的人他们根本不知道他们在做什么。现在在 Facebook罗辛亚人正处于缅甸的种族灭绝中他们是缅甸的一个穆斯林族群。婴儿被从母亲怀中抢走扔进火里人们被杀害数以百千计的难民。在接受采访时进行这些行为的缅甸将军表示我们非常感谢 Facebook 让我们知道“罗辛亚假新闻”这些人实际上不是人类他们实际上是动物。现在Facebook 并不是要促成缅甸罗辛亚人的种族灭绝不是。相反发生的是他们想要最大化印象和点击量。结果是Facebook 的数据科学家发现如果你拿人们感兴趣的东西并向他们提供稍微更极端的版本你实际上会得到更多的印象项目经理们说要最大化这些印象人们点击了这就产生了这种情况。潜在的影响是非常巨大和全球性的。这实际上正在发生。这是 2017 年 10 月。正在发生。 问题我只是想澄清这里发生了什么。所以这是在促进虚假新闻或不准确的媒体吗是的让我详细介绍一下发生的事情是在 2016 年中期Facebook 解雇了它的人类编辑。所以是人类决定如何在你的主页上排序的。这些人被解雇被机器学习算法取代。所以这些机器学习算法是由像你们这样的数据科学家编写的他们有清晰的指标他们试图最大化他们的预测准确性并且像“我们认为如果我们把这个东西放在比这个东西更高的位置我们会得到更多的点击”。结果表明这些用于在 Facebook 新闻源上放置内容的算法倾向于说“哦人类的本性是我们倾向于点击那些刺激我们观点的东西因此更极端版本的我们已经看到的东西”。这对于最大化参与度的 Facebook 收入模型来说是很好的它在他们所有的关键绩效指标上看起来都很好。那时有一些负面新闻我不确定 Facebook 现在放在他们的热门部分的东西是否真的那么准确但从人们在 Facebook 优化的指标的角度来看这看起来很棒。所以回到 2016 年 10 月人们开始注意到一些严重的问题。 例如在美国将住房针对某些种族是非法的。这是非法的然而一个新闻机构发现 Facebook 在 2016 年 10 月确实在做这件事。再次强调并不是因为数据科学团队中的某个人说“让黑人不能住在好社区”。而是他们发现他们的自动聚类和分割算法发现了一群不喜欢非裔美国人的人如果你用这种广告针对他们那么他们更有可能选择这种住房或其他什么。但有趣的是即使被告知了三次Facebook 仍然没有解决这个问题。这就是说这些不仅仅是技术问题。它们也是经济问题。当你开始说你得到报酬的事情也就是广告你必须改变你构建这些方式的方式这样你要么使用更多花钱的人要么减少对少数群体或其他基于算法的人的针对性这可能会影响收入。我提到这个原因是因为在你的职业生涯中你会在某个时候发现自己在一次对话中你会想“我不确定这在道德上是否可以接受”而你正在与之交谈的人在心里想“这会让我们赚很多钱”你永远不会成功地进行对话因为你在谈论不同的事情。所以当你与比你更有经验和更资深的人交谈时他们可能听起来像他们知道他们在谈论什么只要意识到他们的激励并不一定会集中在如何成为一个好人上。就像他们并不是在想如何成为一个坏人但在我看来你在这个行业中花的时间越多你对这些事情的麻木程度就越高比如也许得到晋升和赚钱并不是最重要的事情。 例如我有很多擅长计算机视觉的朋友其中一些人已经创建了似乎几乎是为了帮助威权政府监视他们的公民而量身定制的初创公司。当我问我的朋友们你们有没有考虑过这种方式的使用他们通常会对我提出的问题感到有点冒犯。但我要求你们考虑这个问题。无论你最终在哪里工作如果你最终创建了一个初创公司工具可以被用于善良或邪恶。所以我并不是说不要创建优秀的计算机视觉目标跟踪和检测工具因为你可以继续创建一个更好的外科手术干预机器人工具包。我只是说要意识到这一点考虑一下谈论一下。 所以我发现这个很有趣。这实际上是一个很酷的事情meetup.com 做了。他们考虑到了这一点。他们实际上考虑到了这一点。他们认为你知道如果我们建立一个像我们在课堂上学到的协同过滤系统来帮助人们决定去哪个 meetup。它可能会注意到在旧金山比起女性更多的男性倾向于参加技术 meetup因此它可能会开始决定向更多男性推荐技术 meetup。结果是更多男性会参加技术 meetup结果是当女性参加技术 meetup 时她们会觉得哦这里都是男性我真的不想去技术 meetup。结果是算法会得到新的数据表明男性更喜欢技术 meetup所以继续下去。因此算法的这种初步推动可能会产生这种恶性循环。最终你可能会得到几乎全是男性的技术 meetup。因此这种反馈循环是一个微妙的问题当你考虑构建算法时你真的要考虑到你正在改变的行为是什么。 所以另一个有点可怕的例子是在这篇论文中作者描述了美国许多部门现在正在使用预测性执法算法。那么我们去哪里找即将犯罪的人。你知道算法简单地反馈给你基本上你给它的数据。所以如果你的警察局过去曾经进行过种族歧视那么它可能会稍微更频繁地建议你去黑人社区检查是否有人犯罪。结果是你的警察会更多地去黑人社区结果是他们逮捕更多黑人结果是数据显示黑人社区更不安全。结果是算法告诉警察也许你应该更频繁地去黑人社区依此类推。 这不像是未来可能发生的模糊可能性。这是来自认真研究数据和理论的顶尖学者的记录工作。这些严肃的学术工作表明不这正在发生。再次我相信开始创建这种预测性执法算法的人并没有想过如何逮捕更多黑人。希望他们在想天哪我希望我的孩子在街上更安全我该如何创造一个更安全的社会。但他们没有考虑到这种恶性循环。 关于社交网络算法的这篇文章实际上是最近《纽约时报》上我一个朋友 Renee Diresta 写的她做了一些令人惊讶的事情。她建立了一个第二个 Facebook 账号一个假账号。那时她对反疫苗运动非常感兴趣所以她开始关注一些反疫苗者并访问了一些反疫苗链接。突然间她的新闻动态开始充斥着反疫苗者的新闻以及其他一些东西比如化学尾迹和深层国家阴谋论等等。于是她开始点击这些内容她点击得越多Facebook 推荐的极端离谱的阴谋论就越多。所以现在当 Renee 去那个 Facebook 账号时整个页面都充满了愤怒、疯狂、极端的阴谋论内容。这就是她看到的一切。所以如果这是你的世界那么在你看来这就像是一个不断提醒和证明所有这些东西的连续。所以再次强调这种失控的反馈循环最终告诉缅甸将军们他们的 Facebook 主页上罗兴亚人是动物、假新闻以及其他一切。 很多这些也来自偏见。所以让我们具体谈谈偏见。图像软件中的偏见来自数据中的偏见。所以我认识的大多数在谷歌大脑构建计算机视觉算法的人很少有人是有色人种。所以当他们用家人和朋友的照片来训练算法时他们用的是很少有色人种的照片。所以当 FaceApp 决定我们要尝试查看很多 Instagram 照片看看哪些被点赞最多时他们并没有意识到答案是浅色面孔。所以他们建立了一个生成模型让你看起来更“性感”这是实际照片这是更性感的版本。所以更性感的版本更白鼻孔更少看起来更欧洲化。这显然不受欢迎。再次强调我不认为 FaceApp 的任何人会说“让我们创造一些让人看起来更白的东西”。他们只是用周围的人的一堆图像来训练它。这也有严重的商业影响。他们不得不撤回这个功能。他们受到了大量的负面反弹这是应该的。 这里有另一个例子。谷歌照片创建了这个照片分类器飞机、摩天大楼、汽车、毕业典礼和大猩猩。所以想想这对大多数人来说是什么样子。对大多数人来说他们看到这个他们不了解机器学习他们会说“搞什么鬼谷歌的某个人写了一些代码把黑人称为大猩猩”。这就是它看起来的样子。我们知道那不是发生的事情。我们知道发生的是谷歌计算机视觉专家团队中没有或只有少数有色人种的人建立了一个分类器使用他们可以获得的所有照片所以当系统遇到皮肤较黑的人时它会认为“哦我之前主要只见过大猩猩中的这种情况所以我会把它放在那个类别中”。再次强调数据中的偏见会导致软件中的偏见商业影响也非常显著。谷歌因此受到了很多负面公关影响这是应该的。有人在他们的 Twitter 上发布了这张照片。他们说看看谷歌照片刚刚决定做的事情。 你可以想象第一届由人工智能评选的国际选美大赛发生了什么。基本上结果是所有美丽的人都是白人。所以你可以看到这种图像软件中的偏见这要归功于数据中的偏见也要归功于构建团队缺乏多样性。 在自然语言处理中也可以看到同样的情况。这里是土耳其语。O 是土耳其语中没有性别的代词。没有他和她之分。但当然在英语中我们并没有一个广泛使用的无性别单数代词所以谷歌翻译将其转换为这个。现在有很多人在网上看到这个并且字面上说“那又怎样”它正确地反馈了英语中的通常用法。我知道这是如何训练的就像 Word2vec 词向量一样它是在谷歌新闻语料库、谷歌图书语料库上训练的它只是告诉我们事情是如何的。从某种角度来看这是完全正确的。用来创建这种有偏见算法的有偏见数据实际上是人们几十年来写书和报纸文章的实际数据。但这是否意味着这是你想要创建的产品这是否意味着这是你必须创建的产品仅仅因为你训练模型的特定方式导致它最终做出这样的结果这真的是你想要的设计吗你能想到这可能会产生什么负面影响和反馈循环吗如果这些事情中的任何一件让你感到不安那么现在幸运的是你有一个新的很酷的工程问题要解决。我如何创建无偏见的自然语言处理解决方案现在有一些初创公司开始做这个并开始赚钱。所以这对你来说是机会。就像嘿这里有一些人因为他们糟糕的模型而创造出了扭曲的社会结果。你可以去建立一些更好的东西。Word2vec 词向量中的偏见的另一个例子是餐厅评论中排名较低的墨西哥餐厅因为“墨西哥”这个词在美国新闻和书籍中更常与犯罪相关的词语联系在一起。同样这是一个正在发生的真实问题。 Rachel 实际上对普通的 Word2vec 词向量进行了一些有趣的分析。她基本上把它们拿出来根据一些在其他地方进行的研究来看这些类比。所以你可以看到Word2vec 向量方向显示父亲对医生就像母亲对护士一样。男人对计算机程序员就像女人对家庭主妇一样等等。所以很容易看出这些词向量中包含了什么。它们在我们今天使用的几乎所有自然语言处理软件中都是基础的。 这里有一个很好的例子。ProPublica 实际上在这个领域做了很多有益的工作。现在许多法官都可以访问判决指南软件。因此判决指南软件告诉法官对于这个个体我们建议这种类型的刑罚。当然法官不懂机器学习所以他们有两个选择要么按照软件的建议行事要么完全忽视它有些人属于每个类别。对于那些属于按照软件建议行事的人这里是发生的事情。对于那些被标记为高风险的人实际上没有再次犯罪的人中白人约四分之一非裔美国人约一半。所以那些没有再次犯罪的人中如果是非裔美国人他们被标记为高风险的情况几乎是白人的两倍。而那些被标记为低风险但实际上再次犯罪的人中白人约一半非裔美国人只有 28%。所以这是数据我希望没有人会刻意创造这样的情况。但是当你从有偏见的数据开始数据显示白人和黑人吸食大麻的比率大致相同但黑人被监禁的频率大约是白人的 5 倍美国的司法系统的性质至少目前来看是不平等的不公平的。因此输入到机器学习模型中的数据基本上会支持这种现状。然后由于负面反馈循环情况只会变得越来越糟。 现在我要告诉你关于这个有趣的事情研究员阿贝·龚指出了一些问题。以下是一些正在被问到的问题。所以让我们来看一个。你的父亲是否曾被逮捕过你对这个问题的回答将决定你是否被关押以及关押多久。现在作为一个机器学习研究员你认为这可能会提高你算法的预测准确性并获得更好的 R²。可能会但我不知道。也许会。你试试看哦我有了更好的 R²。那么这意味着你应该使用它吗还有另一个问题。你认为因为一个人的父亲是谁而把他关押更长时间是合理的吗然而这些实际上是我们现在问罪犯的问题的例子然后将其放入一个机器学习系统中来决定他们的命运。再次设计这个的人可能他们是专注于技术卓越获得 ROC 曲线下面积的最大值我发现了这些很好的预测因子让我又多了 0.02。我猜他们没有停下来思考这样决定谁应该更长时间被关押是否合理。 因此将这些放在一起你可以看到这会变得越来越可怕。我们以 Taser 这样的公司为例Taser 是一种会给你一个大电击的设备Taser 设法与一些学术研究人员建立了良好的关系这些研究人员似乎会说他们要他们说的话以至于现在如果你看数据结果表明如果你被电击你可能会死亡的概率相当高。这并不罕见。然而他们支付给研究这个问题的研究人员一直回来说“哦不这与电击无关。他们之后立即死亡完全无关。这只是一个偶然事件事情发生了”。因此这家公司现在拥有 80%的身体摄像机市场份额。他们开始收购计算机视觉 AI 公司。他们将尝试使用这些警察身体摄像机视频来预测犯罪活动。那意味着什么这就像是我现在有一些增强现实显示告诉我电击这个人因为他们即将做一些坏事这是一个令人担忧的方向所以我确信没有人在 Taser 或他们收购的公司中的数据科学家会认为这是他们想要帮助创造的世界但他们可能会发现自己或你可能会发现自己处于这种讨论的中心虽然这不是明确讨论的话题但你内心可能会有一部分在想“我想知道这可能会被如何使用”。我不知道在这种情况下应该做什么才是正确的因为你可以询问当然人们会说“不不不”。那你能做什么你可以要求一些书面承诺你可以决定离开你可以开始研究事情的合法性比如说至少保护自己的法律情况。我不知道。想一想你会如何应对。 这些是 Rachel 提出的一些问题作为需要考虑的事情。如果你正在考虑构建一个数据产品或使用模型如果你正在构建机器学习模型那是有原因的。你正在尝试做某事。那么数据中可能存在什么偏见因为无论数据中存在什么偏见最终都会成为你预测的偏见潜在地影响你正在影响的行动潜在地影响你返回的数据你可能会得到一个反馈循环。 如果构建它的团队不够多样化你可能会错过什么例如Twitter 的一位高级执行官在选举之前很久就警告了 Twitter 存在严重的俄罗斯机器人问题。那时 Twitter 高管团队中唯一的黑人。唯一的一个。不久之后他们失去了工作。因此拥有一个更多样化的团队意味着拥有更多样化的观点、信仰、想法和寻找的事物等等。因此非多样化的团队似乎会犯更多这样的错误。 我们能审计代码吗它是开源的吗检查不同群体之间的不同错误率。我们是否可以使用一个极易解释和易于沟通的简单规则如果出了问题我们是否有一个处理问题的好方法 当我们与人们谈论这个问题时很多人都去找 Rachel 说我对我的组织正在做的事情感到担忧我该怎么办[1:36:21]或者我只是担心我的 toxic workplace我该怎么办而 Rachel 往往会说你有考虑过离开吗他们会说我不想失去工作。但实际上如果你会编程你是整个人口的 0.3%。如果你会编程和做机器学习你可能是整个人口的 0.01%。你是极其极其受欢迎的。所以实际上显然一个组织不希望你觉得自己可以随时离开找另一份工作这不符合他们的利益。但这绝对是真的。所以我希望你们在这门课程中能够获得足够的自信认识到你有能力找到工作特别是一旦你有了第一份工作第二份工作就会容易很多。所以这很重要不仅是为了让你觉得你实际上有能力去做出道德行为而且也很重要意识到如果你发现自己处在一个 toxic 环境中这是相当普遍的不幸。在湾区尤其存在很多糟糕的科技文化/环境。如果你发现自己处在这样的环境中最好的做法就是赶紧离开。如果你没有自信认为自己可以找到另一份工作你就会被困住。所以这真的很重要。很重要的是要知道你在结束这个项目时拥有非常受欢迎的技能特别是在你有了第一份工作之后你现在是一个拥有受欢迎技能和在该领域就业记录的人。 问题这只是一个广泛的问题你知道人们正在做一些什么来处理数据中的偏见吗[1:38:41]你知道这目前是一个有争议的话题有人试图使用算法方法他们基本上试图说我们如何识别偏见并将其减去。但我知道的最有效的方法是试图在数据层面上处理它。所以从一个更多元化的团队开始特别是一个团队包括来自人文学科的人比如社会学家、心理学家、经济学家了解反馈循环和对人类行为的影响他们往往配备了识别和跟踪这类问题的良好工具。然后尝试将解决方案纳入到过程中。但我无法告诉你有一个标准的处理方法告诉你如何解决它。如果有这样的东西我们还没有找到。简短的答案是需要一个多样化的聪明团队意识到问题并努力解决。 评论这只是针对整个班级的一个普遍性建议如果你对这些感兴趣我读过一本很酷的书Jeremy 你可能听说过Cathy O’Neil 的《Weapons of Math Destruction》。它涵盖了很多相同的内容[1:40:09]。是的谢谢你的推荐。Kathy 很棒。她还有一个 TED 演讲。我没能完成这本书。它太令人沮丧了。我只是说“不要再看了”。但是它确实很好。 好的。就这样了。谢谢大家。对我来说这真的很紧张。显然这原本是我和 Rachel 分享的事情。所以我最终做了我一生中最困难的事情之一那就是独自教授两个人的课程照顾生病的妻子和一个幼儿还要学习深度学习课程。而且还要用我刚写的新库来完成所有这些。所以我期待着能好好休息一下。但这一切都是完全值得的。因为你们太棒了。我对你们对我给予的机会作出的反应以及我给予你们的反馈感到非常高兴。所以恭喜。
http://www.tj-hxxt.cn/news/134945.html

相关文章:

  • 常见的cms网站程序有哪些王占山战斗英雄简历
  • 高端网站建设磐石网络好开发公司官网
  • 网站建设季度考核评价工作总结株洲专业建设网站
  • 化妆品营销型网站案例wordpress 自动分页插件
  • 响应式网站预览体验营销理论
  • 天津网站建设找哪家企业查询系统官网
  • 塘厦做网站wordpress取消菜单
  • 网站seo外包价格网站文件上传wordpress修改
  • 德阳网站建设求职简历做电影网站
  • vs2013做网站网站设计一级网页
  • 中国是唯一一个拥有空间站软文营销的五个步骤
  • 诸城做网站的qq小程序开发平台
  • 网站关键词排名seo室内设计师培训机构
  • 惠州网站建设推广公司广东省建设监理协会官方网站
  • 旅游产品推广方案移动端网站如何优化
  • 网站建设兼职招聘wordpress页脚小工具栏
  • 湘潭网站建设 要选磐石网络h5制作模板免费永久
  • discuz做服务网站建设旅游网站
  • 设计网站会员哪个好用python 网站开发 linux
  • 山西省建设厅网站打不开浏览器打不开wordpress
  • 怎样做下载网站改版网站会影响百度
  • 服务平台网站设计怎么做直播视频教学视频网站
  • 各大中文网站外观设计
  • 合肥商城网站开发嘉兴个人建站
  • 网站前端改版涉及到的问题wordpress企业官网主题
  • 网站建设中提示页面下载金华做网站报价
  • 张槎网站建设制作做视频点播网站如何赚钱
  • html怎么做查询网站青柠视频免费观看高清视频
  • 做网站用哪个编程语言重庆市建设工程信息网 安全监督
  • 喊别人做的网站不肯给代码抖音开放平台注册