在大型数据集上的培训

神经网络非常适于在大型数据集上进行培训,甚至是那些太大而不适合内存的数据集. 培训神经网络最流行的算法(例如,NetTrain 中的 "ADAM""RMSProp") 是称之为随机梯度下降方法的变体. 在该方法中,从完全培训的数据集中随机采样一小批数据并用于执行参数更新. 因此,神经网络是在线学习算法的一个范例,它不需要整个培训数据集储存在内存. 这与支持向量机 (SVM) 和随机森林算法是相反的,它们一般需要在培训时,整个数据集存在于内存中.
然而,如果把 NetTrain 用于不需要适合内存的数据集上,则需要特殊的处理,因为整个培训数据集不能加载进 Wolfram 语言会话中. 有两种方法可以培训这么大的数据集. 第一种方法是,用户编写一个生成器函数 f,计算时,可以从外部资源,例如,磁盘或数据库加载一小批数据. NetTrain[net,f,] 在每个培训批迭代中调用 f,因此只在内存中保留单批培训数据. 这是进行脱离核心学习最灵活的方法. 然而,它取决于用户来确保 f 的计算足够快来避免降速网络培训(这个对于在完全强大的 GPU 上的培训尤其重要)并且从整个培训数据集中正确的进行采样.
第二种方法适合包括图像或音频文件的培训数据集的特殊情况. 这种情况下,编码器,例如,"Image" NetEncoder 可以有效地读取和预处理存于磁盘中的图像.
查找 ExampleData 中的文件:
把编码器应用于文件中:
NetTrain[net,{File[]->,},] 然后在数据集上自动进行脱离核心计算,其中,File[] 表示脱离核心图像和音频文件.
脱离核心学习的一些通用性能窍门:
MNIST 上的脱离核心培训
该范例显示如何在 MNIST 数据集上培训网络,其中,图像以 "JPEG" 文件形式存在磁盘上而不是内存中. 虽然没有必要培训 MNIST,但是该方法可用于在 TB 级图像数据集(例如:ImageNet 数据集)上培训网络.
我们可以使用特殊语法 NetTrain[net,{File[]class1,},] 以及把 "Image" NetEncoder 附加在 net 的输入口上. 也可以使用更灵活的 NetTrain 生成器函数语法显示如何重现.

准备数据

首先,需要创建一个 MNIST 脱离核心的版本,格式为 {File[]class1,}.
获取 MNIST 培训和测试集:
把图像以 "JPEG" 文件的形式存在默认的临时目录 $TemporaryDirectory 中. 每个导出的文件也需要一个唯一的名称. 创建唯一名称的一个好方法是使用 Hash 函数,该函数为每个唯一图像返回一个唯一的哈希值.
定义一个函数,把图像导出到 $TemporaryDirectory 目录的 "JPEG" 文件:
导出图像:
当培训图像时,一般情况下,网络需要图像是单个尺寸、颜色空间等. 在 LeNet 情况下,期望图像是灰度的且尺寸为 2828. 如果从磁盘读取的图像已经与网络期待的符合,一般会加速培训,否则,每次从磁盘加载时,需要转换. 如果图像不符合,那么推荐修改 exportImage,使用 ConformImages 使图像符合.
现在可以把导出函数映射到培训和测试集. 一种优化是使用 ParallelMap 而不是 Map 并行导出.
导出图像并创建格式为 {File[]->class,} 的新的培训和测试集:
显示新培训集的 RandomSample
现在只有图像文件的引用需要保存在内存,这个比在内存中保存图像要小很多.
获取两个培训集的 ByteCount

简单的脱离核心培训

定义有 "Image" NetEncoder 附在输入端口的卷积神经网络:
由于该网络有 "Image" NetEncoder 附在输入端口,它可以把由 File 对象表示的图像作为输入.
从培训集中获取文件:
NetInitialize 初始化网络并把它应用于文件中:
在格式为 {File[]->class1,} 的数据上培训网络与在格式为 {image1->class1,} 数据上培训完全一样.
进行三轮训练网络:
直接在验证集上随机采样的图像上计算培训网络:
获取测试集上培训网络的精确度:

用生成器函数培训

我们也可以使用更多的 NetTrain 的一般生成器语法. 该方法更灵活,允许自定义图像处理、数据增强等.
定义返回批量培训数据的生成器函数:
产生一批四个培训范例:
用生成器函数培训网络:
获取测试集上培训网络的精确度:

导入与 NetEncoder 性能

使用 NetEncoder 加载数据通常比使用高级 Wolfram 语言代码编写数据加载器更快. 作为一个范例,让我们比较简单的图像导入器和 "Image" NetEncoder.
定义一个自定义的图像数据加载器:
定义一个 "Image" NetEncoder
每个编码器会产生 4 阶数值数组,应用于输入文件的列表.
Create a batch of 4 files:
把图像编码器应用到文件列表并获取输出维度和计算所花时间:
获取 "Image" NetEncoder 比自定义的图像编码器快多少:
由上可见,"Image" NetEncoder 比自定义图像编码器快 100 倍!如果增加批的尺寸,差别会更大.
使用 MongoDB 数据库
MongoDB 数据库是存储大型数据集的一个解决方案. Wolfram 语言有与 MongoDB 数据库交互的 MongoLink 程序包.
该范例显示如何在存在 MongoDB 数据库上的 Fisher Iris 数据集上培训网络. 在每个培训迭代中只有一小部分数据会从数据库中随机采样. 因此,该方法扩展到不能存储到内存的数据集.
我们假设您已经熟悉 MongoLink 和 MongoDB 数据库. 如果不熟悉,在继续前,推荐阅读 MongoLink Introduction 教程.
并且假设 MongoDB 服务器是运行在默认的主机和端口的本地服务器上. 对于本地运行 MongoDB 服务器的平台独立的介绍,请参见这里.

数据插入

我们所使用的数据集是 Fisher Iris 数据集,任务是给予一些数值特征将花分类为 4 类.
获取 Fisher Iris 数据集:
现在把培训数据插入 MongoDB 数据库.
Load MongoLink:
使用默认的主机 "localhost" 和端口 27017 创建一个客户连接(这是当在你的本地机器上运行 MongoDB 服务器的默认主机名和端口):
在数据库 "WolframNNTutorialDatabase" 中创建一个 MongoDB 集合名为 "WolframNNTutorialCollection".
使用 MongoGetCollection 创建一个集合:
如果集合和数据库不存在,首次插入数据时会被创建.
被培训数据转换成 MongoDB 文档列表:
把培训数据插入集合:
获取集合中的随机范例验证插入的数据:

构建分类网络

现在构建一个可以在数据集上执行分类的网络. 首先,需要所有可能类的列表,这最好是由数据库查询生成.
构建一个唯一标签列表,每个范例用 MongoCollectionDistinct 分配:
创建一个 NetChain 执行回归,使用 "Class" 解码器诠释网络的输出为每个类的概率:

构建一个生成器函数

我们需要定义一个用在 NetTrain 的生成函数. 该函数需要从 "WolframNNTutorialCollection" 随机采样文档.
使用带有 "$sample" 聚合算子的 MongoCollectionAggregate"WolframNNTutorialCollection" 集合中获取两个随机采样:
这等同于在集合上使用 RandomSample
然而,我们不需要 "_id" 字段. 我们可以通过修改 Wolfram 语言输出,或更高效些,通过添加 "$project" 算子到聚合管道删除它.
从集合中读取,其中 "_id" 字段已被删除:
定义使用于 NetTrain 的生成器函数:
该生成器函数正确返回了范例的随机采样列表,当指定批大小时:
培训数据有两种主要有效的格式,生成器函数可以生成:范例列表关联 {<|key1val11,key2val21,|>,<|key1val12,|>,} 由生成器产生,或单个 Association,每个键有范例值列表 <|key1->{val11,val12,},key2{val21,val22,},|>. 生成器函数输出 out 的一种格式可以通过 Transpose[out,AllowedHeads->All] 转换成其他.
MongoDB 使用 $group 聚合阶段直接生成讲范例组合在一起的第二种格式. 这比产生第一种格式更有效.
定义生成器函数返回一批组合在一起的范例:
使用第二个生成器产生一批两个范例:
分组生成器在产生批大小为 64 时更快:
获取由第二个生成器每秒产生的样本:

培训网络

用生成器函数培训网络:
这种方法存在一个问题:测试集合上的性能是在每批已被培训后计算的,与通常情况相比,是在单个通过整个培训数据集(一个回合)之后计算的. 当使用生成器,NetTrain 不知道一个回合的大小,除非我们明确指定.
使用 MongoCollectionCount 获取集合中范例的总数:
用指定的回合大小,2000 回培训网络:
测试在测试集上培训网络的精确度: