📜  CNTK-内存中和大数据集

📅  最后修改于: 2020-12-10 05:04:09             🧑  作者: Mango


在本章中,我们将学习如何使用CNTK中的内存和大型数据集。

使用内存较小的数据集进行训练

当我们谈论将数据馈入CNTK培训器时,可以有很多方法,但这取决于数据集的大小和数据的格式。数据集可以是小型内存数据集,也可以是大型数据集。

在本节中,我们将使用内存数据集。为此,我们将使用以下两个框架-

  • 脾气暴躁的
  • 大熊猫

使用Numpy数组

在这里,我们将使用CNTK中基于numpy的随机生成的数据集。在此示例中,我们将模拟二进制分类问题的数据。假设我们有一组具有4个特征的观察结果,并希望使用我们的深度学习模型预测两个可能的标签。

实施实例

为此,首先我们必须生成一组标签,其中包含我们要预测的标签的单热矢量表示。可以通过以下步骤完成-

步骤1-如下导入numpy包-

import numpy as np
num_samples = 20000

步骤2-接下来,使用np.eye函数生成标签映射,如下所示-

label_mapping = np.eye(2)

步骤3-现在通过使用np.random.choice函数,如下收集20000个随机样本-

y = label_mapping[np.random.choice(2,num_samples)].astype(np.float32)

步骤4-现在最后通过使用np.random.random函数,生成如下所示的随机浮点值数组-

x = np.random.random(size=(num_samples, 4)).astype(np.float32)

一次,我们生成了一个随机浮点值数组,我们需要将它们转换为32位浮点数,以便它可以与CNTK期望的格式匹配。让我们按照以下步骤进行操作-

步骤5-从cntk.layers模块导入密集和顺序图层功能,如下所示-

from cntk.layers import Dense, Sequential

步骤6-现在,我们需要为网络中的层导入激活函数。让我们导入Sigmoid作为激活函数-

from cntk import input_variable, default_options
from cntk.ops import sigmoid

步骤7-现在,我们需要导入损失函数来训练网络。让我们导入binary_cross_entropy作为损失函数-

from cntk.losses import binary_cross_entropy

步骤8-接下来,我们需要定义网络的默认选项。在这里,我们将提供S型激活函数作为默认设置。另外,通过使用顺序图层函数创建模型,如下所示:

with default_options(activation=sigmoid):
model = Sequential([Dense(6),Dense(2)])

步骤9-接下来,使用4个输入要素(用作网络的输入)初始化input_variable

features = input_variable(4)

步骤10-现在,为了完成它,我们需要将要素变量连接到NN。

z = model(features)

所以,现在我们有了一个NN,在以下步骤的帮助下,让我们使用内存数据集训练它-

步骤11-要训练该NN,首先我们需要从cntk.learners模块导入学习者。我们将如下导入sgd学习器-

from cntk.learners import sgd

步骤12-以及从cntk.logging模块导入ProgressPrinter的步骤

from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)

步骤13-接下来,为标签定义一个新的输入变量,如下所示-

labels = input_variable(2)

步骤14-为了训练NN模型,接下来,我们需要使用binary_cross_entropy函数定义一个损失。另外,提供模型z和标签变量。

loss = binary_cross_entropy(z, labels)

步骤15-接下来,如下初始化sgd学习器-

learner = sgd(z.parameters, lr=0.1)

步骤16-最后,在损失函数上调用train方法。另外,向其提供输入数据, sgd学习器和progress_printer。

training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer])

完整的实施示例

import numpy as np
num_samples = 20000
label_mapping = np.eye(2)
y = label_mapping[np.random.choice(2,num_samples)].astype(np.float32)
x = np.random.random(size=(num_samples, 4)).astype(np.float32)
from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid
from cntk.losses import binary_cross_entropy
with default_options(activation=sigmoid):
   model = Sequential([Dense(6),Dense(2)])
features = input_variable(4)
z = model(features)
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)
labels = input_variable(2)
loss = binary_cross_entropy(z, labels)
learner = sgd(z.parameters, lr=0.1)
training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer])

输出

Build info:
     Built time: *** ** **** 21:40:10
     Last modified date: *** *** ** 21:08:46 2019
     Build type: Release
     Build target: CPU-only
     With ASGD: yes
     Math lib: mkl
     Build Branch: HEAD
     Build SHA1:ae9c9c7c5f9e6072cc9c94c254f816dbdc1c5be6 (modified)
     MPI distribution: Microsoft MPI
     MPI version: 7.0.12437.6
-------------------------------------------------------------------
average   since   average   since examples
loss      last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.52      1.52      0         0     32
1.51      1.51      0         0     96
1.48      1.46      0         0    224
1.45      1.42      0         0    480
1.42       1.4      0         0    992
1.41      1.39      0         0   2016
1.4       1.39      0         0   4064
1.39      1.39      0         0   8160
1.39      1.39      0         0  16352

使用熊猫数据框

Numpy数组可以包含的内容以及存储数据的最基本方法之一非常有限。例如,单个n维数组可以包含单个数据类型的数据。但另一方面,对于许多实际情况,我们需要一个可处理单个数据集中多个数据类型的库。

一个名为Pandas的Python库使使用这种数据集变得更加容易。它介绍了DataFrame(DF)的概念,并允许我们从以DF格式存储的磁盘中加载数据集。例如,我们可以读取以CSV,JSON,Excel等格式存储的DF。

您可以在https://www.tutorialspoint.com/python_pandas/index.htm上详细了解Python Pandas库

实施实例

在此示例中,我们将使用基于四个属性对鸢尾花的三种可能物种进行分类的示例。我们也在之前的部分中创建了这种深度学习模型。模型如下-

from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid, log_softmax
from cntk.losses import binary_cross_entropy
model = Sequential([
Dense(4, activation=sigmoid),
Dense(3, activation=log_softmax)
])
features = input_variable(4)
z = model(features)

上面的模型包含一个隐藏层和一个包含三个神经元的输出层,以匹配我们可以预测的类数。

接下来,我们将使用训练方法和损失函数来训练网络。为此,首先我们必须加载和预处理虹膜数据集,以使其与NN的预期布局和数据格式匹配。可以通过以下步骤完成-

步骤1-如下导入numpyPandas包-

import numpy as np
import pandas as pd

步骤2-接下来,使用read_csv函数将数据集加载到内存中-

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’,
 ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)

步骤3-现在,我们需要创建一个字典,该字典将映射数据集中的标签及其对应的数字表示形式。

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

步骤4-现在,通过在DataFrame上使用iloc索引器,如下选择前四列:

x = df_source.iloc[:, :4].values

步骤5-接下来,我们需要选择种类列作为数据集的标签。它可以做到如下-

y = df_source[‘species’].values

步骤6-现在,我们需要在数据集中映射标签,这可以通过使用label_mapping来完成。另外,使用one_hot编码将它们转换为one-hot编码数组。

y = np.array([one_hot(label_mapping[v], 3) for v in y])

步骤7-接下来,要将特征和映射标签与CNTK一起使用,我们需要将它们都转换为浮点数-

x= x.astype(np.float32)
y= y.astype(np.float32)

众所周知,标签以字符串形式存储在数据集中,而CNTK不能与这些字符串。这就是原因,它需要表示标签的一键编码矢量。为此,我们可以定义一个函数one_hot ,如下所示:

def one_hot(index, length):
result = np.zeros(length)
result[index] = index
return result

现在,我们以正确的格式设置了numpy数组,在以下步骤的帮助下,我们可以使用它们来训练我们的模型-

步骤8-首先,我们需要导入损失函数来训练网络。让我们导入binary_cross_entropy_with_softmax作为损失函数-

from cntk.losses import binary_cross_entropy_with_softmax

步骤9-要训练该NN,我们还需要从cntk.learners模块导入学习者。我们将如下导入sgd学习器-

from cntk.learners import sgd

步骤10-以及从cntk.logging模块导入ProgressPrinter的步骤

from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)

步骤11-接下来,为标签定义一个新的输入变量,如下所示-

labels = input_variable(3)

步骤12-为了训练NN模型,接下来,我们需要使用binary_cross_entropy_with_softmax函数来定义损失。还提供模型z和标签变量。

loss = binary_cross_entropy_with_softmax (z, labels)

步骤13-接下来,如下初始化sgd学习器-

learner = sgd(z.parameters, 0.1)

步骤14-最后,在损失函数上调用train方法。另外,向其提供输入数据, sgd学习者和progress_printer

training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=
[progress_writer],minibatch_size=16,max_epochs=5)

完整的实施示例

from cntk.layers import Dense, Sequential
from cntk import input_variable, default_options
from cntk.ops import sigmoid, log_softmax
from cntk.losses import binary_cross_entropy
model = Sequential([
Dense(4, activation=sigmoid),
Dense(3, activation=log_softmax)
])
features = input_variable(4)
z = model(features)
import numpy as np
import pandas as pd
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
x = df_source.iloc[:, :4].values
y = df_source[‘species’].values
y = np.array([one_hot(label_mapping[v], 3) for v in y])
x= x.astype(np.float32)
y= y.astype(np.float32)
def one_hot(index, length):
result = np.zeros(length)
result[index] = index
return result
from cntk.losses import binary_cross_entropy_with_softmax
from cntk.learners import sgd
from cntk.logging import ProgressPrinter
progress_writer = ProgressPrinter(0)
labels = input_variable(3)
loss = binary_cross_entropy_with_softmax (z, labels)
learner = sgd(z.parameters, 0.1)
training_summary=loss.train((x,y),parameter_learners=[learner],callbacks=[progress_writer],minibatch_size=16,max_epochs=5)

输出

Build info:
     Built time: *** ** **** 21:40:10
     Last modified date: *** *** ** 21:08:46 2019
     Build type: Release
     Build target: CPU-only
     With ASGD: yes
     Math lib: mkl
     Build Branch: HEAD
     Build SHA1:ae9c9c7c5f9e6072cc9c94c254f816dbdc1c5be6 (modified)
     MPI distribution: Microsoft MPI
     MPI version: 7.0.12437.6
-------------------------------------------------------------------
average    since    average   since   examples
loss        last     metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.1         1.1        0       0      16
0.835     0.704        0       0      32
1.993      1.11        0       0      48
1.14       1.14        0       0     112
[………]

大型数据集训练

在上一节中,我们使用Numpy和pandas处理了较小的内存数据集,但并非所有数据集都这么小。特别是包含图像,视频,声音样本的数据集很大。 MinibatchSource是一个组件,可以按块加载数据,由CNTK提供,可以处理如此大的数据集。 MinibatchSource组件的一些功能如下-

  • MinibatchSource可以通过自动随机化从数据源读取的样本来防止NN过度拟合。

  • 它具有内置的转换管道,可用于扩充数据。

  • 它将数据加载到与训练过程分开的后台线程中。

在以下各节中,我们将探讨如何使用带有内存不足数据的小批量源处理大型数据集。我们还将探索如何使用它来训练神经网络。

创建MinibatchSource实例

在上一节中,我们使用了鸢尾花示例,并使用Pandas DataFrames处理了较小的内存数据集。在这里,我们将使用MinibatchSource替换使用熊猫DF数据的代码。首先,我们需要在以下步骤的帮助下创建MinibatchSource的实例-

实施实例

步骤1-首先,从cntk.io模块导入minibatchsource的组件,如下所示-

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer,
 INFINITY_REPEAT

步骤2-现在,通过使用StreamDef类,为标签创建流定义。

labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)

步骤3-接下来,创建以读取输入文件中归档的功能,如下所示创建另一个StreamDef实例。

feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)

步骤4-现在,我们需要提供iris.ctf文件作为输入并按如下方式初始化解串器

deserializer = CTFDeserializer(‘iris.ctf’, StreamDefs(labels=
label_stream, features=features_stream)

步骤5-最后,我们需要使用反序列化器创建minisourceBatch的实例,如下所示-

Minibatch_source = MinibatchSource(deserializer, randomize=True)

创建一个MinibatchSource实例-完整的实现示例

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer, INFINITY_REPEAT
labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)
feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)
deserializer = CTFDeserializer(‘iris.ctf’, StreamDefs(labels=label_stream, features=features_stream)
Minibatch_source = MinibatchSource(deserializer, randomize=True)

创建MCTF文件

如您在上面看到的,我们正在从“ iris.ctf”文件中获取数据。它具有称为CNTK文本格式(CTF)的文件格式。必须创建一个CTF文件来获取上面创建的MinibatchSource实例的数据。让我们看看如何创建CTF文件。

实施实例

步骤1-首先,我们需要如下导入pandas和numpy包-

import pandas as pd
import numpy as np

步骤2-接下来,我们需要将数据文件(即iris.csv)加载到内存中。然后,将其存储在df_source变量中。

df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)

步骤3-现在,通过使用iloc索引器作为功能,获取前四列的内容。另外,使用来自物种列的数据,如下所示:

features = df_source.iloc[: , :4].values
labels = df_source[‘species’].values

步骤4-接下来,我们需要在标签名称与其数字表示形式之间创建映射。可以通过如下创建label_mapping来完成-

label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}

步骤5-现在,将标签转换为一组单热编码矢量,如下所示-

labels = [one_hot(label_mapping[v], 3) for v in labels]

现在,像我们之前所做的那样,创建一个称为one_hot的实用程序函数来对标签进行编码。它可以做到如下-

def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result

由于我们已经加载并预处理了数据,是时候以CTF文件格式将其存储在磁盘上了。我们可以在以下Python代码的帮助下做到这一点-

With open(‘iris.ctf’, ‘w’) as output_file:
for index in range(0, feature.shape[0]):
feature_values = ‘ ‘.join([str(x) for x in np.nditer(features[index])])
label_values = ‘ ‘.join([str(x) for x in np.nditer(labels[index])])
output_file.write(‘features {} | labels {} \n’.format(feature_values, label_values))

创建MCTF文件-完整的实现示例

import pandas as pd
import numpy as np
df_source = pd.read_csv(‘iris.csv’, names = [‘sepal_length’, ‘sepal_width’, ‘petal_length’, ‘petal_width’, ‘species’], index_col=False)
features = df_source.iloc[: , :4].values
labels = df_source[‘species’].values
label_mapping = {‘Iris-Setosa’ : 0, ‘Iris-Versicolor’ : 1, ‘Iris-Virginica’ : 2}
labels = [one_hot(label_mapping[v], 3) for v in labels]
def one_hot(index, length):
result = np.zeros(length)
result[index] = 1
return result
With open(‘iris.ctf’, ‘w’) as output_file:
for index in range(0, feature.shape[0]):
feature_values = ‘ ‘.join([str(x) for x in np.nditer(features[index])])
label_values = ‘ ‘.join([str(x) for x in np.nditer(labels[index])])
output_file.write(‘features {} | labels {} \n’.format(feature_values, label_values))

馈送数据

创建实例MinibatchSource之后,我们需要对其进行培训。我们可以使用与处理小型内存数据集时相同的训练逻辑。在这里,我们将使用MinibatchSource实例作为损失函数的train方法的输入,如下所示:

实施实例

步骤1-为了记录培训课程的输出,请首先从cntk.logging模块导入ProgressPrinter,如下所示:

from cntk.logging import ProgressPrinter

步骤2-接下来,要设置培训课程,请从cntk.train模块中导入trainertraining_session ,如下所示:

from cntk.train import Trainer, 

步骤3-现在,我们需要定义一些常量集,例如minibatch_sizesamples_per_epochnum_epochs ,如下所示:

minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30

步骤4-接下来,为了知道CNTK如何在训练期间读取数据,我们需要定义网络的输入变量和minibatch源中的流之间的映射。

input_map = {
     features: minibatch.source.streams.features,
     labels: minibatch.source.streams.features
}

步骤5-接下来,要记录训练过程的输出,请使用新的ProgressPrinter实例初始化progress_printer变量,如下所示:

progress_writer = ProgressPrinter(0)

步骤6-最后,我们需要对损失调用以下方法:

train_history = loss.train(minibatch_source,
parameter_learners=[learner],
  model_inputs_to_streams=input_map,
callbacks=[progress_writer],
epoch_size=samples_per_epoch,
max_epochs=num_epochs)

馈送数据-完整的实现示例

from cntk.logging import ProgressPrinter
from cntk.train import Trainer, training_session
minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
input_map = {
   features: minibatch.source.streams.features,
   labels: minibatch.source.streams.features
}
progress_writer = ProgressPrinter(0)
train_history = loss.train(minibatch_source,
parameter_learners=[learner],
model_inputs_to_streams=input_map,
callbacks=[progress_writer],
epoch_size=samples_per_epoch,
max_epochs=num_epochs)

输出

-------------------------------------------------------------------
average   since   average   since  examples
loss      last     metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.21      1.21      0        0       32
1.15      0.12      0        0       96
[………]