Tabular
这就是NLP。我们将在本课程的后期学习更多关于NLP的知识。但现在,我想切换并查看tabular(表格)。现在表格数据非常有趣,因为对于很多人来说,这实际上就是你在电子表格、关系数据库等中日常工作使用的东西。
问题:学习率中的魔法数(2.6的4次方)从何而来?[33:38]
learn.fit_one_cycle(2, slice(1e-3/(2.6**4),1e-3), moms=(0.8,0.7))
好问题。所以学习率是各种各样的东西除以2.6到第四。这是第四次的原因,你将在今天结束时了解到。所以让我们关注2.6。为什么2.6?基本上,正如我们今天稍后将要看到的,这个数字,切片的底部和切片的顶部之间的差异,基本上就是模型的最低层学习速度与模型的最高层学习速度之间的差异。所以这被称为判别学习率(discriminative learning rates)。所以真正的问题是当你从一层到另一层时,我会减少多少学习率?我们发现对于NLP RNN,答案是2.6。
我们如何发现它是2.6?我使用了许多不同类型的各种类型的超参数(丢失,学习率和判别学习率等)来运行大量不同的模型,然后我创建了一个叫做随机森林的东西,这是一种模型,我试图根据超参数来预测我的NLP分类器的准确程度。然后我使用随机森林解释方法来基本弄清楚最佳参数设置是什么,我发现这个数字的答案是2.6。所以这实际上不是我发表的东西,或者我认为我之前甚至没有谈过它,所以有一条新的信息。实际上,在我这样做几个月之后,Stephen Merity和其他人确实发表了一篇描述类似方法的论文,所以基本的想法可能已经存在。
其中一些想法来自一位名叫Frank Hutter的研究员和他的一位合作者。他们做了一些有趣的工作,展示了如何使用随机森林来实际找到最佳超参数。所以这是一个巧妙的伎俩。很多人对这个名为Auto ML的东西很感兴趣,这就像建立模型以了解如何训练你的模型一样。我们整体上并不是它的忠实粉丝。但是我们确实发现建立模型以更好地理解你的超参数如何工作,然后找到那些经验法则,基本上它总是2.6非常有用。所以我们一直在玩这种东西。
回到表格
我们来谈谈表格数据。您可能会在电子表格,关系数据库或财务报表中看到的表格数据,它可以包含各种不同的内容。我试着列出一些我见过表格数据分析的东西:
使用神经网络分析表格数据 - 当我们第一次提出这一点时,人们对此持怀疑态度。他们认为使用神经网络来分析表格数据是一个糟糕的主意,因为每个人都知道你应该使用逻辑回归,随机森林或梯度增强机器(所有这些机器都适用于某些类型的事物)。但从那个时候开始,人们普遍认为普遍存在的智慧是错误的。神经网络对表格数据无用是不正确的,事实上它们非常有用。我们在很多课程中都展示了这一点,但真正有用的是,一些真正有效的组织已经开始发表论文和帖子,描述他们如何使用神经网络来分析表格数据。
一次又一次出现的关键问题之一是虽然特征工程不会消失,但它肯定会变得更简单。例如,Pinterest取代了他们用来决定如何用神经网络将东西放在主页上的梯度增强机器。他们在会议上提出了这种方法,他们描述了它如何使工程变得更加容易,因为很多手工创建的功能都不再需要了。你仍然需要一些,但它只是更简单。因此他们最终获得了更准确的东西,但更重要的是,它需要更少的维护。所以我不会说你是工具箱中用于分析表格数据的唯一工具。但是在其他地方,当我使用表格数据进行机器学习时,我曾经99%使用随机森林,我现在90%的时间使用神经网络。这是我现在的标准首选方法,它往往非常可靠和有效。
其中一件令人困难的事情是,直到现在还没有一种简单的方法来创建和训练表格神经网络。没有人真正在库中提供它。所以我们实际上刚刚创建了fastai.tabular,而且我认为这是第一次使用带有表格数据的神经网络变得非常容易。所以让我告诉你它有多容易。
表格案例
这实际上直接来自fastai repo中的examples文件夹。我根本没有改变它。按照惯例,以及导入fastai,导入您的应用程序 - 所以在这种情况下,它是表格式。
from fastai import *
from fastai.tabular import *
我们假设您的数据位于Pandas DataFram中。Pandas DataFrame是Python中表格数据的标准格式。有很多方法可以在那里获得它,但最常见的可能是pd.read_csv。但无论您的数据是什么,您都可以轻松地将其放入Pandas数据框中。
path = untar_data(URLs.ADULT_SAMPLE)
df = pd.read_csv(path/'adult.csv')
问题:你不会默认使用神经网络的10%的情况是什么?
好问题。我想我还是倾向于尝试一下。但是,我不知道。这有点像你做了一段时间的事情,你开始意识到事情不太合适的领域。本周我必须考虑这一点。我不认为我有一个经验法则。但我想说,你也可以试试两者。我会说尝试随机森林并尝试神经网络。它们既快速又容易运行,并且看起来如何。如果它们大致相似,我可能会深入研究它们,看看我是否可以让它们变得更好。但如果随机森林做得更好,我可能会坚持下去。使用任何有用的。
所以我们从数据框架中的数据开始,因此我们有一个成人样本 - 它是一个经典的旧数据集。这是一个非常小的简单旧数据集,非常适合进行实验。它是一个CSV文件,因此您可以将其读入数据框,并使用Pandas读取CSV(pd.read_csv)。如果您的数据位于关系数据库中,Pandas可以从中读取数据。如果它在spark或Hadoop中,Pandas可以从中读取。Pandas可以阅读你可以投入的大多数东西。这就是为什么我们将它作为默认起点。
dep_var = 'salary'
cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race']
cont_names = ['age', 'fnlwgt', 'education-num']
procs = [FillMissing, Categorify, Normalize]
test = TabularList.from_df(df.iloc[800:1000].copy(), path=path, cat_names=cat_names, cont_names=cont_names)
data = (TabularList.from_df(df, path=path, cat_names=cat_names, cont_names=cont_names, procs=procs)
.split_by_idx(list(range(800,1000)))
.label_from_df(cols=dep_var)
.add_test(test, label=0)
.databunch())
按照惯例,我认为使用数据块API很好。所以在这种情况下,我们尝试创建的列表是表格列表,我们将从数据框创建它。所以你可以告诉它:
- 数据框是什么。
- 您将用于保存模型和中间步骤的路径是什么。
- 然后你需要告诉它你的分类变量是什么,你的连续变量是什么。
连续与分类
您的自变量是您用来进行预测的内容。所以像教育,婚姻状况,年龄等等。其中一些变量如年龄基本上是数字。它们可以是任何数字。你可能是13.36岁或19.4岁或其他什么。在其他地方,婚姻状况等选项可以从一个独立的群体中选择:已婚,单身,离婚等等。有时这些选择可能会更多,比如职业。有很多可能的职业。有时,它们可能是二进制的(即真或假)。但是,你可以从一小组可能性中选择答案的任何东西都称为分类变量。因此,我们需要在神经网络中使用不同的方法来将分类变量建模为我们用于连续变量的变量。但是,你可以从一小组可能性中选择答案的任何东西都称为分类变量。因此,我们需要在神经网络中使用不同的方法来将分类变量建模为我们用于连续变量的变量。对于分类变量,我们将使用一种称为嵌入的东西,我们将在今天晚些时候学习。对于连续变量,它们可以像神经网络中的像素一样被发送到神经网络中。因为神经网络中的像素已经是数字;这些连续的东西也已经是数字了。这很容易。
这就是为什么你必须从数据框中告诉表格列表哪些是哪些。还有其他一些方法可以通过在Pandas中预处理它们来制作分类变量,但是有一个API可以做任何事情,这样做很好。你不必过多考虑它。
处理器processor
然后我们得到的东西很像计算机视觉中的变换。计算机视觉中的变换可以做一些事情,比如在轴上翻转照片,稍微转动它,照亮它或将其标准化。但是对于表格数据,我们有一些称为流程的东西,而不是变换。它们几乎完全相同,但关键的区别,非常重要,是处理器是提前发生的事情。所以我们基本上预先处理数据框,而不是像我们一样去做。因此,转换实际上是用于数据扩充 - 我们希望将其随机化并且每次都以不同方式进行。或者,流程是您希望提前完成的事情。
procs = [FillMissing, Categorify, Normalize]
我们在fastai库中有许多流程(processes)。我们这次要使用的是:
- FillMissing:寻找缺失值并以某种方式处理它们。
- categorify:查找分类变量并将其转换为Pandas类别
- Normalize :提前进行归一化,即采用连续变量并减去它们的平均值并除以它们的标准偏差,这样它们就是零一变量。
我们处理缺失数据的方式,我们将在下周详细讨论,但简而言之,我们用中位数替换它并添加一个新列,这是一个二进制列,说明是否缺失。
对于所有这些事情,无论您对训练集做什么,您都需要对验证集和测试集做同样的事情。因此,无论您使用什么替换缺失值,都需要在验证集中使用完全相同的内容替换它们。所以fastai为您处理所有这些细节。如果你必须手动操作它们就是那种东西,如果你像我一样,你会搞砸很多次,直到你最终做对了。这就是这些流程的所在。
然后我们将分为训练与验证集。在这种情况下,我们通过提供索引列表来实现,因此索引从800到1000。这很常见。我不太记得这个数据集的细节,但是想要将验证集保持为连续的事物组是很常见的。如果它们是地图图块,则它们应该是彼此相邻的地图图块,如果他们的时间段,他们应该是彼此相邻的日子,如果它们是视频帧,它们应该是彼此相邻的视频帧。因为否则你就是在作弊。因此,如果您的数据具有某种类似的结构或者找到以这种方式构造它的其他方式,那么使用split_by_idx并获取彼此相邻的范围通常是个好主意。
好的,现在给我们一个训练和验证集。我们现在需要添加标签。在这种情况下,标签可以直接来自我们之前抓取的数据框,因此我们只需告诉它它是哪一列。因此,因变量是他们是否超过50,000美元的薪水。这就是我们想要预测的事情。
我们稍后会讨论测试集,但在这种情况下我们可以添加测试集。最后得到我们的数据。那时,我们有一些看起来像这样的东西:
data.show_batch(rows=10)
有我们的数据。然后使用它,它看起来非常熟悉。你得到一个学习者,在这种情况下,它是一个表格学习者,传递数据,一些有关你的架构的信息,以及一些指标。然后你称之为健康。
learn = tabular_learner(data, layers=[200,100], metrics=accuracy)
learn.fit(1, 1e-2)
Total time: 00:03
epoch train_loss valid_loss accuracy
1 0.362837 0.413169 0.785000 (00:03)
问题:你认为像scikit-learn和xgboost这样的东西最终会变得过时吗?将来每个人都会使用深度学习工具吗?除了小数据集?[50:36]
我不知道。我不善于做出预测。我不是机器学习模型。我的意思是xgboost是一个非常好的软件。有一些非常好的软件可用于梯度增强。实际上,随机森林尤其具有一些非常好的解释功能,我相信我们会发现神经网络的类似版本,但它们并不一定存在。所以我不知道。目前,它们都是有用的工具。scikit-learn是一个经常用于预处理和运行模型的库。同样,很难预测事情会在哪里结束。在某些方面,它更侧重于一些较旧的建模方法,但我不知道。他们不断添加新东西,所以我们会看到。我一直试图将更多的scikit-learn内容纳入fastai,然后我不断寻找各种方法,我认为我可以做得更好,然后再把它扔掉,这就是为什么在fastai中仍然没有scikit-learn依赖。我一直在寻找其他办法。
我们将学习什么 layers= 意味着今天的课程结束或下周的课程开始,但这就是我们基本上定义我们的架构的地方,就像我们选择ResNet 34或其他任何转换网络一样。我们稍后会详细介绍指标,但只是提醒您,指标只是打印出来的内容。它们根本不会改变我们的模型。所以在这种情况下,我们说我希望你打印出准确性,看看我们是怎么做的。
所以这就是如何操作表格。这将非常有效,因为我们很快就会打破我们的休息时间。我们的想法是,在经过三个半课程后,我们将完成对应用程序的所有快速概述的结束,然后我将在另一方面继续下去。我想我们将要做到这一刻,我们要打它。因为下一个是协同过滤。
协同过滤
通过协作过滤,您可以获得有关谁购买了什么,或者谁喜欢什么的信息 - 基本上您拥有类似用户,评论者或其他任何东西的信息,以及有关他们购买了什么,他们写了什么,或者他们回顾了什么。因此,在最基本的协同过滤版本中,您只有两列:用户ID和电影ID等,只是说用户购买了该电影。因此,例如,亚马逊有一个非常大的用户ID列表和产品ID,就像你买的那样。然后你可以在该表中添加其他信息,例如哦,他们留下了评论,他们给了什么评论?所以现在它就像用户ID,电影ID,明星数量。您可以添加时间码,以便此用户此时购买此产品并进行此审核。但它们基本上都是相同的结构。
有两种方法可以绘制协同过滤结构。一种是两列方法,你有用户和电影。并且你有用户ID,电影ID-每对基本上描述用户观看该电影,可能还有星数(3,4等)。另一种你可以写它的方式就是你可以像这里的所有用户一样喜欢这里的所有电影。然后,您可以在那里查找并查找特定单元格,以找出该电影的该用户的评级,或者如果该用户观看该电影或其他任何内容,则只有1。
因此,有两种不同的方式来表示相同的信息。从概念上讲,通过这种方式(右边的矩阵)通常更容易想到它,但大多数时候你不会以这种方式存储它。显然,因为在大多数情况下,你会有一个非常稀疏的矩阵,也就是说大多数用户没有看过大多数电影,或者大多数客户没有购买过大多数产品。因此,如果您将其存储为矩阵,其中客户和产品的每个组合都是该矩阵中的单独单元格,那么它将是巨大的。因此,您倾向于将其存储为左侧,或者您可以使用某种特殊的稀疏矩阵格式将其存储为矩阵。如果这听起来很有趣,你应该看看Rachel在fastai的计算线性代数课程,其中我们有很多关于稀疏矩阵存储方法的信息。但就目前而言,我们只是想在左侧保留这种格式。
lesson4-collab.ipynb
对于协同过滤,GroupLens组创建了一个名为MovieLens的非常好的数据集,您可以下载各种不同的大小(2000万个评级,100,000个评级)。我们实际上已经创建了一个额外的小版本来玩,这就是我们今天要开始的。然后可能在下周,我们将使用更大的版本。
from fastai import *
from fastai.collab import *
from fastai.tabular import *
您可以使用URLs.ML_SAMPLE获取小版本:
user,item,title = 'userId','movieId','title'
path = untar_data(URLs.ML_SAMPLE)
path
PosixPath('/home/jhoward/.fastai/data/movie_lens_sample')
ratings = pd.read_csv(path/'ratings.csv')
ratings.head()
它是一个CSV,所以你可以用Pandas阅读它,就在这里。它基本上是一个用户ID列表 - 我们实际上并不知道这些用户是谁。有一些电影ID。有一些关于电影是什么的信息,但我们不会在下周看到它。然后是评级和时间戳。我们暂时忽略时间戳。这是我们数据的一个子集。
所以现在我们已经有了一个数据框,协同过滤的好处就是非常简单。
data = CollabDataBunch.from_df(ratings, seed=42)
y_range = [0,5.5]
learn = collab_learner(data, n_factors=50, y_range=y_range)
这就是我们需要的所有数据。所以你现在可以继续说得到collab_learner并且你可以传递数据。这个架构,你必须告诉它你想要使用多少因素,我们将在休息后了解这意味着什么。然后可能有用的是告诉它分数范围是什么。我们将在休息之后看看它有何帮助。所以在这种情况下,最低分为0,最高分为5。
learn.fit_one_cycle(3, 5e-3)
Total time: 00:04
epoch train_loss valid_loss
1 1.600185 0.962681 (00:01)
2 0.851333 0.678732 (00:01)
3 0.660136 0.666290 (00:01)
现在你已经有了一个学习者,你可以继续调用fit_one_cycle并训练几个时代,就在那里。所以最后,您现在可以选择用户ID和电影ID,并猜测该用户是否会喜欢该电影。
冷启动问题
这显然是一个非常有用的应用程序,很多人可能会在本周尝试。在过去的课程中,很多人已经将这种协同过滤方法带回了他们的工作场所,并发现在实践中使用它比这更棘手。因为在实践中,你有一个叫做冷启动问题的东西。所以冷启动的问题是,你特别想要擅长推荐电影的时间是你有新用户的时候,你特别关心推荐电影的时间就是新电影。但在那时,您的协作过滤系统中没有任何数据,而且确实很难。
就像我说的那样,我们目前没有内置到fastai来处理冷启动问题,这真的是因为冷启动问题,我知道解决它的唯一方法(事实上,我认为这是概念上的唯一方式)可以解决它)是第二个模型不是协作过滤模型,而是新用户或新电影的元数据驱动模型。
我不知道Netflix是否仍然这样做,但当我注册Netflix时他们曾经做过的事情是他们开始给我看很多电影并说“你见过这个吗?”“你喜欢它吗?”- 他们通过UX解决了冷启动问题,因此没有冷启动问题。他们发现了20部非常普通的电影并问我是否喜欢它们,他们用我对这20部的回复向我展示了我可能已经看到的20多个,当我经历了60年时,再也没有冷启动问题了。
对于新电影来说,这不是一个真正的问题,因为像没有看过电影的前一百个用户进去说他们是否喜欢它,然后接下来的十万,下一个百万,这不再是冷启动问题。
如果你出于某种原因不能通过那种要求人们的用户体验,那么你可以做的另一件事就是你喜欢那些东西(例如,如果你是在销售产品,而你真的不想向他们展示一个大的选择您的产品并说你喜欢这个,因为你只想让他们购买),你可以尝试使用基于元数据的表格模型他们来自哪个地理位置也许你知道他们的年龄和性别,你可以尝试做一些猜测关于最初的建议。
因此,一旦您获得有关您的用户和电影或客户和产品或其他任何信息的信息,协作过滤就是专门的。
问题:以这种方式训练的语言模型如何对代码转换数据(用英语单词写的印地语)或带有大量表情符号的文本执行?
使用表情符号的文字,它会没事的。维基百科中的表情符号并不多,而且它们在维基百科上的位置更像是一个关于表情符号的维基百科页面,而不是在一个明智的地方使用的表情符号。但是你可以(并且应该)进行这种语言模型微调,你可以在这里使用文本语料库,人们以通常的方式使用表情符号,因此你可以将Wikitext语言模型微调到你的reddit或Twitter或任何语言模型。如果你想的话,没有那么多的表情符号。人们可以使用数十万种可能的单词,但可能有少量表情符号。因此,它将很快了解如何使用这些表情符号。所以这是小菜一碟。我对印地语并不熟悉,但我会举一个例子,我非常熟悉普通话。在普通话中,你可以拥有一个用汉字训练的模型。常用的汉字大概有五六千个,但也有一个叫做拼音的字符的罗马化。这有点棘手,因为虽然从角色到拼音有几乎直接的映射(我的意思是直接映射,但是发音并不完全直接),但没有从拼音到角色的直接映射,因为一个拼音对应多个字符。
所以首先要注意的是,如果你要将这种方法用于中文,你需要从中文语言模型开始。
实际上,fastai有一种称为语言模型动物园Language Model Zoo的东西,我们为不同的语言添加越来越多的语言模型,并且越来越多地用于不同的领域,如英语医学文本,甚至是NLP之外的其他领域,如基因组序列,分子数据,音乐MIDI音符,等等。所以你显然会从那里开始。
然后将其(简体中文或繁体中文)转换成拼音,您可以直接映射词汇,或者如您所知,这些多层模型 - 它只是第一层基本上将令牌转换为一组向量,你实际上可以扔掉它并微调模型的第一层。因此,在你完全理解如何做到这一点之前,第二部分将需要几周的学习,但如果这是你有兴趣做的事情,我们可以在论坛上谈论它,因为它是一个很好的理解的考验。
问题:关于表格数据的时间序列怎么样?tableular.models中是否有任何RNN模型?[1点05分09秒]
我们将在下周查看时间序列表格数据,但简短的回答通常是你不使用RNN来表示时间序列表格数据,而是提取一堆列,例如星期几,这是一个周末,是假期,商店是开放的,这样的东西。事实证明,添加那些您可以自动执行的额外列基本上可以为您提供最先进的结果。RNN在时间序列方面有一些很好的用途,但对于这类表格式时间序列(如零售店物流数据库等)并不是真的如此。
使用Microsoft Excel协作过滤器[1:07:25]
我们所做的是从MovieLens数据中抓取观看次数最多的电影和电影的人,并将数据集限制在15个以下。正如您所看到的,当您这样做时,它不是稀疏了。只有少数差距。
这是我们现在可以用它构建模型的东西。我们如何建立模型?我们想要做的是我们想要创建可以为用户预测的东西293,他们是否会喜欢电影49。因此,我们必须提出一些可以代表该决定的功能。
这是一种简单的可行方法。我们将采取一些矩阵乘法的想法。所以我在这里创建了一个随机矩阵。所以这是一个随机数矩阵(左边)。我在这里创建了另一个随机数矩阵(顶部)。更具体地说,对于每部电影,我创建了五个随机数,并且对于每个用户,我创建了五个随机数。
那么我们可以说那个用户14,电影27;他们喜欢与否?好吧,评级,我们可以做的是将这个矢量(红色)和那个矢量(紫色)相乘。我们可以做点积,这里是点积。那么我们基本上可以在这里做所有可能的事情。并且由于电子表格,我们可以在一个地方完成这项工作并将其复制,并为我们填写整个内容。我们为什么要这样做呢?那么,这是神经网络的基本出发点,不是吗?神经网络的一个基本出发点是你采用两个矩阵的矩阵乘法,这就是你的第一层总是如此。因此,我们必须想出一些方法来说明我们可以增加的两个矩阵是什么。显然,你需要一个用户的矢量(所有用户的矩阵)和一个电影的矢量(所有电影的矩阵)并将它们相乘,然后你得到一些数字。所以他们没有任何意义。他们只是随机的。但我们现在可以使用梯度下降来尝试制作这些数字(上图),这些数字(左图)给出的结果更接近我们想要的结果。
那我们该怎么做呢?好吧,我们现在把它设置为线性模型,接下来我们需要的是一个损失函数。我们可以通过说好的电影27来计算我们的损失函数用户ID 14应该是3的等级。对于这个随机矩阵,它实际上是0.91的等级,所以我们可以找到平方误差的总和然后我们可以添加它们。所以实际上Excel中的总和已经和X减去y平方(SUMXMY2),所以我们可以只使用和X减去y平方函数,传递这两个范围然后除以计数得到平均值。
这是一个数字,它是均方误差的平方根。你有时会看到人们谈论MSE,这就是均方误差,有时你会看到RMSE是均方根误差。由于我在前面有一个平方根,这是平方均方误差。
Excel解算器
我们有一个损失,所以我们现在需要做的就是使用梯度下降来尝试修改我们的权重矩阵以使损失更小。Excel会为我做这件事。
如果您没有解算器,请转到Excel选项→加载项,然后启用“求解器加载项”。
Excel中的梯度下降求解器称为“求解器”,它只是正常的梯度下降。你只需要进入数据→解算器(你需要确保在你的设置中你已经启用了Excel附带的求解器扩展),你需要做的就是说哪个单元代表我的损失函数。就是这样,单元格V41。哪个单元格包含你的变量,所以你可以在这里看到,我有H19到V23在这里,而B25到F39就在那里,那么你可以说“好吧,把你的损失函数设置为最小值更改这些单元格“并单击Solve:
你会看到开始是2.81,你可以看到数字下降。所有这一切都是使用梯度下降,就像我们前几天在笔记本中手动完成时一样。但它不是求解Python中@ x的均方误差,而是解决这里的损失函数,即这些向量中每个向量的每个向量的点积的均方误差。
我们会让它运行一段时间,看看会发生什么。但基本上是微观的,这里有一个创建神经网络的简单方法,在这种情况下,它就像一个单一的线性层,具有梯度下降来解决协同过滤问题。
回到笔记本[1:17:02]让我们回过头来看看我们在这做什么。
data = CollabDataBunch.from_df(ratings, seed=42)
y_range = [0,5.5]
learn = collab_learner(data, n_factors=50, y_range=y_range)
learn.fit_one_cycle(3, 5e-3)
Total time: 00:04
epoch train_loss valid_loss
1 1.600185 0.962681 (00:01)
2 0.851333 0.678732 (00:01)
3 0.660136 0.666290 (00:01)
所以在这里我们使用collab_learner来获取模型。所以在笔记本中调用的函数是collab_learner,当你深入深入学习时,深入深度学习的一个非常好的方法是深入研究fastai源代码并看看发生了什么。因此,如果您能够做到这一点,您需要知道如何充分利用您的编辑器来挖掘源代码。基本上你需要知道如何做两件事:
- 1.跳转到特定的“符号”,就像特定的类或函数一样
- 2.当您查看特定符号时,可以跳转到其实现
例如,在这种情况下,我想找到def collab_learner。在大多数编辑器中,包括我使用的编辑器,vim,你可以设置它以便你可以点击tab或者其他东西并跳过所有可能的完成,然后你可以按Enter键直接跳到你的定义。所以这是collab_learner的定义。正如你所看到的,它非常小,因为这些东西往往是,并且它做的关键是创建一个特定类型的模型,这是一个EmbeddingDotBias模型,传递你要求的各种事物。所以你想在你的编辑器中找到你如何跳转到那个的定义,在vim中你只需按Ctrl +],这里是EmbeddingDotBias的定义。
现在,我们立即在屏幕上显示所有内容,正如您所看到的,没有太多事情发生。fastai为您创建的模型实际上是PyTorch模型。PyTorch模型被称为nn.Module,它是PyTorch模型中的名称。它比这更微妙,但这是一个很好的起点。当运行PyTorch nn.Module时(当你计算该层,神经网络等的结果时),具体来说,它总是为你调用一个叫做forward的方法。所以在这里你可以了解这个东西是如何实际计算出来的。
当模型在开始时构建时,它会调用这个名为init的东西,正如我们之前在Python中简要提到的那样,人们倾向于称之为“dunder init”。因此dunder init是我们创建模型的方式,而forward是我们运行模型的方式。
有一件事,如果你仔细观察,你可能会注意到这里没有什么说明如何计算模型的梯度,这是因为PyTorch为我们做了。因此,您只需告诉它如何计算模型的输出,PyTorch将继续为您计算渐变。
所以在这种情况下,模型包含:
- 一组用户的权重
- 一组项目的权重
- 一组用户的偏差
-
一组项目的偏差
而其中每一个都来自这个称为嵌入的东西。以下是嵌入(embedding)的定义:
它所做的就是调用这个名为nn.Embedding的PyTorch。在PyTorch中,他们为您设置了许多标准的神经网络层。所以它创建了一个嵌入。然后这里的事情(trunc_normal_)就是随机化它。这是为嵌入创建正常随机数的东西。
嵌入
什么是嵌入式?毫不奇怪,嵌入是一个权重矩阵。具体来说,嵌入是一个权重矩阵,看起来像这样:
它是一个权重矩阵,您可以基本上查看,并从中抓取一个项目。所以基本上一个嵌入矩阵只是一个权重矩阵,它被设计成你作为一个数组索引它的东西,并从中获取一个向量。这就是嵌入矩阵。在我们的例子中,我们有一个用户的嵌入矩阵和一个电影的嵌入矩阵。在这里,我们一直在采用它们的点积:
但如果你考虑一下,那还不够。因为我们错过了这个想法,也许某些电影每个人都喜欢更多。也许有些用户更倾向于喜欢电影。所以我真的不想将这两个向量相乘,但我真的想添加一个像这部电影一样流行的数字,并添加一个数字,就像这个用户一般喜欢电影的数量。所以这些被称为“偏差(bias)”术语。请记住我是如何说这种bias的想法以及我们在梯度下降笔记本中处理的方式是我们添加了一列1。但我们在实践中倾向于做的是我们实际明确地说我想添加一个偏差项。所以我们不只是希望预测等于这两件事的点积,我们想说它是这两件事的点积加上电影的偏见项加上用户ID的偏差项。
回到代码[1:23:55]
所以这基本上就是发生了什么。我们在设置模型时,为用户设置嵌入矩阵,为项目设置嵌入矩阵。然后我们还为用户设置偏向量,并为项目设置偏向量。
然后,当我们计算模型时,我们实际上只是将两者相乘。就像我们做的那样。我们只拿这个产品,我们称之为dot。然后我们添加偏见,并(暂时搁置y_range)这就是我们返回的东西。所以你可以看到我们的模型实际上正在做我们在电子表格中做的事情,我们也在调整偏差。所以这是一个非常简单的线性模型。对于这些类型的协同过滤问题,这种简单的线性模型实际上往往效果很好。
然后我们在最后做了一个调整,在我们的例子中,我们说y的范围在0到5.5之间。所以这里有一点需要指出。所以,你做那个点积,你添加了两个偏差,这可以给你从数字线上的任何可能的数字,从非常负数到非常正数。但我们知道我们总是希望得到一个介于0和5之间的数字。如果我们将这样的数字行映射到此函数,该怎么办?该函数的形状称为sigmoid。所以,它会渐渐变为五,它会逐渐变为零。
这样,无论我们的点积产生什么数字并添加偏差,如果我们坚持通过这个功能,它永远不会高于5,永远不会小于0.现在严格来说,这是没有必要的。因为我们的参数可以学习一组给出正确数字的权重。那么,如果没有必要,我们为什么要做这个额外的事呢?原因是,我们希望尽可能简化我们的模型。如果我们实际设置它所以它不可能预测得太多或太少,那么它可以花费更多的权重来预测我们关心的事情,这决定了谁会喜欢什么电影。所以这是一个我们将继续回归的想法,就像让神经网络更好地工作一样。这是我们所做的所有这些小决策,基本上使网络更容易学习正确的事情。这是最后的调整:
return torch.sigmoid(res) * (self.y_range[1]-self.y_range[0]) + self.y_range[0]
我们把这个点积的结果加上偏差,我们把它通过一个sigmoid。Sigmoid只是一个基本上是一个函数,但定义并不重要。但它只是具有我刚才提到的形状,并且介于0和1之间。如果你将它乘以y_range [1]减去y_range [0]加y_range [0],那么这将给你一些介于y_range之间的东西[0]和y_range [1]。
所以这意味着这个微小的神经网络,我的意思是将其称为神经网络。但它是一个具有一个权重矩阵且没有非线性的神经网络。所以它是世界上最无聊的神经网络,最后有一个sigmoid。我猜它确实有非线性。最后的S形是非线性,它只有一层重量。这实际上证明了接近最先进的表现。我在网上查了一下,看看人们对这款MovieLens 100k数据库的最佳效果是什么,我从这个小东西得到的结果比我从标准商业产品中找到的任何结果都要好。下载专门为此。诀窍似乎是添加这个小S形有很大的不同。
重要术语概述### [1:31:24]
因此,我今天想要结束的是,采用这个协作过滤示例,并描述我们将如何在接下来的三个课程中构建我们已经看到的更复杂的神经网络。粗略地说,这是我们需要了解的一堆概念:
让我们考虑当您使用神经网络进行图像识别时会发生什么。我们来看一个像素。你有很多像素,但我们只需要一个像素。所以你有一个红色的绿色和蓝色像素。其中每一个都是0到255之间的某个数字,或者我们将它们标准化,使它们的均值为零,标准差为1。但是,让我们做0到255版本。所以红色:10,绿色:20,蓝色30.那么我们如何处理这些呢?那么,我们所做的是基本上将它视为一个向量,并将它乘以矩阵。那么这个矩阵(取决于你如何看待行和列),让我们看待矩阵有三行然后有多少列?你可以选择。就像协同过滤版本一样,我决定为每个嵌入向量选择一个大小为5的向量。所以这意味着它是一个5的嵌入。你可以选择你的权重矩阵有多大。所以让它的大小为5.这是3乘5。
最初,该权重矩阵包含随机数。还记得我们刚刚看过嵌入权重矩阵吗?
有两行;第一行是创建矩阵,第二行是用随机数填充它?这就是我们所做的一切。我的意思是这一切都被fastai和PyTorch隐藏在幕后,但这就是它所做的一切。因此,当您进行设置时,它会创建一个随机数矩阵。行数必须为3才能匹配输入,列数可以根据需要大小。因此,在将输入向量乘以该权重矩阵后,您最终将得到一个大小为5的向量。
人们经常会问我需要知道多少线性代数才能进行深度学习。这是您需要的金额。如果你不熟悉这个,那很好。您需要了解矩阵产品。你不需要了解很多关于它们的知识,你只需要知道它们是什么以及它们做了什么。你必须非常舒服,如果一个大小的矩阵等于矩阵大小的矩阵给出矩阵或大小等等(即尺寸如何匹配)。因此,如果你有3,并且他们在numpy和PyTorch中记得,我们使用@ times 3 by 5给出一个大小为5的向量。
接下来会发生什么;它通过一个激活函数,如ReLU,它只是max(0,x)并吐出一个新的向量,当然,它将是完全相同的大小,因为激活函数没有改变大小 - 它只改变内容。所以它仍然是5号。
接下来发生什么?我们乘以另一个矩阵。同样,它可以是任意数量的列,但行数必须很好地映射。无论如何它都会是5。也许这个有5个,比方说,10个。这将给出一些输出 - 它应该是10号,我们再次通过ReLU,再次给我们一些相同大小的东西。
然后我们可以通过另一个矩阵。实际上,只是为了让它更清晰(你会在一瞬间看到原因),我将使用8而不是10。
假设我们正在进行数字识别。有十个可能的数字,所以我的最后一个权重矩阵必须是10的大小。因为那意味着我的最终输出是一个10的大小的向量。请记住,如果您正在进行数字识别,我们会将实际值设为10。如果我们试图预测的数字是数字3,那么这意味着第三个位置有一个1([0,0,0,1,0,...])。
那么我们的神经网络将从我们的输入开始,并且进入权重矩阵→ReLU→权重矩阵→ReLU→权重矩阵→最终输出。然后我们将这两者结合起来,看看它们有多接近(即它们有多接近)使用一些损失函数,我们将了解下周我们使用的所有损失函数。目前,我们学到的唯一一个是均方误差。我们将输出(您可以将它们视为10个中的每一个的概率)与10个实际中的每一个进行比较以获得损失,然后我们找到每个权重矩阵的相对于此的渐变,以及我们更新权重矩阵。
我现在要展示的主要内容是我们使用的术语,因为它非常重要。
这些东西(黄色)包含数字。具体来说,它们最初是包含随机数的矩阵。我们可以参考这些黄色的东西,在PyTorch中,它们被称为参数。有时我们会将它们称为权重,尽管权重稍微不准确,因为它们也可能是偏差。但是我们可以互换地使用这些术语。严格来说,我们应该称它们为参数。
然后在每个矩阵乘积之后计算数字向量。以下是通过权重矩阵乘法计算的一些数字(蓝色)。然后还有一些其他数字(紫色),这些数字是由ReLU和激活函数计算得出的。任何一个都称为激活。
激活和参数都指数字。他们是数字。但参数Parameters 是存储的数字,它们用于进行计算。激活 Activations是计算的结果 - 计算的数字。所以他们是你需要记住的两件关键事情。
因此,请使用这些术语,并正确准确地使用它们。如果您阅读这些术语,则表示这些非常具体的内容。所以不要把它们混在一起。记住,它们并不奇怪和神奇 - 它们是非常简单的东西。
- 激活是矩阵乘法或激活函数的结果。
- 参数是我们乘以的矩阵内的数字。
然后有一些特殊的层。进行计算的所有这些东西中的所有这些都是计算(红色箭头),都称为层。它们是我们神经网络的层次。因此,每一层都会产生一组激活,因为计算会产生一组结果。
在开始处有一个特殊的层,称为输入层,然后在最后你只有一组激活,我们可以参考那些特殊的数字(我的意思是它们在数学上并不特殊,但它们在语义上是特殊的);我们可以称之为输出。这里要实现的重点是神经网络的输出实际上并不是数学上特殊的,它们只是层的激活。
那么我们在协作过滤示例中做了什么,我们做了一些有趣的事情。我们实际上在最后添加了一个额外的激活功能。我们添加了一个额外的激活函数,它是一个sigmoid,特别是它是一个在0到5之间的缩放的sigmoid。激活函数作为你的最后一层很常见,它几乎永远不会是一个ReLU因为它不太可能你真正想要的是截断为零的东西。它通常是一个sigmoid或类似的东西,因为它实际上你想要的东西很可能是两个值之间的东西,并且以这种方式缩放。
这几乎就是这样。输入,权重,激活,激活函数(我们有时称之为非线性),输出,然后将这两个事物进行比较的函数称为损失函数,到目前为止我们已经使用了MSE。
这对今天来说已经足够了。那么下周我们要做的就是我们要添加一些额外的位,这就是我们要学习用于分类的损失函数,称为交叉熵,我们要去使用用于称为softmax的单标签分类的激活函数,我们还将准确了解当我们根据这些层实际如何进行微调,解冻时会发生什么以及当我们创建传输时会发生什么情况时会发生什么?学习。谢谢大家!期待下周见到你。