CNTK - 記憶體不足的資料集



本章將解釋如何測量記憶體不足資料集的效能。

在之前的章節中,我們討論了驗證 NN 效能的各種方法,但是我們討論的方法都是處理適合記憶體的資料集。

這裡出現了一個問題,即記憶體不足的資料集怎麼辦?因為在生產環境中,我們需要大量資料來訓練NN。在本節中,我們將討論如何在使用小批次資料來源和手動小批次迴圈時測量效能。

小批次資料來源

在處理記憶體不足的資料集(即小批次資料來源)時,我們需要為損失和度量設定與處理小型資料集(即記憶體中資料集)時使用的設定略微不同的設定。首先,我們將瞭解如何設定將資料饋送到 NN 模型訓練器的方法。

以下是實現步驟:

步驟 1 - 首先,從cntk.io模組匯入用於建立小批次資料來源的元件,如下所示:

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

步驟 2 - 接下來,建立一個名為create_datasource的新函式。此函式將有兩個引數,即檔名和限制,預設值為INFINITELY_REPEAT

def create_datasource(filename, limit =INFINITELY_REPEAT)

步驟 3 - 現在,在函式中,使用StreamDef類建立一個用於讀取具有三個特徵的標籤欄位的標籤流定義。我們還需要將is_sparse設定為False,如下所示:

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

步驟 4 - 接下來,建立一個從輸入檔案讀取特徵欄位的StreamDef的另一個例項,如下所示。

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

步驟 5 - 現在,初始化CTFDeserializer例項類。指定我們需要反序列化的檔名和流,如下所示:

deserializer = CTFDeserializer(filename, StreamDefs(labels=
label_stream, features=features_stream)

步驟 6 - 接下來,我們需要使用反序列化器建立minisourceBatch的例項,如下所示:

Minibatch_source = MinibatchSource(deserializer, randomize=True, max_sweeps=limit)
return minibatch_source

步驟 7 - 最後,我們需要提供訓練和測試源,我們在之前的章節中也建立了這些源。我們使用的是鳶尾花資料集。

training_source = create_datasource(‘Iris_train.ctf’)
test_source = create_datasource(‘Iris_test.ctf’, limit=1)

建立MinibatchSource例項後,我們需要對其進行訓練。我們可以使用與處理小型記憶體中資料集時相同的訓練邏輯。在這裡,我們將使用MinibatchSource例項作為損失函式的train方法的輸入,如下所示:

以下是實現步驟:

步驟 1 - 為了記錄訓練會話的輸出,首先從cntk.logging模組匯入ProgressPrinter,如下所示:

from cntk.logging import ProgressPrinter

步驟 2 - 接下來,要設定訓練會話,請從cntk.train模組匯入trainertraining_session,如下所示:

from cntk.train import Trainer, training_session

步驟 3 - 現在,我們需要定義一些常量,例如minibatch_sizesamples_per_epochnum_epochs,如下所示:

minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
max_samples = samples_per_epoch * num_epochs

步驟 4 - 接下來,為了瞭解如何在 CNTK 中在訓練期間讀取資料,我們需要定義網路輸入變數和小批次資料來源中的流之間的對映。

input_map = {
   features: training_source.streams.features,
   labels: training_source.streams.labels
}

步驟 5 - 接下來,要記錄訓練過程的輸出,請使用新的ProgressPrinter例項初始化progress_printer變數。此外,初始化trainer併為其提供模型,如下所示:

progress_writer = ProgressPrinter(0)
trainer: training_source.streams.labels

步驟 6 - 最後,要啟動訓練過程,我們需要呼叫training_session函式,如下所示:

session = training_session(trainer,
   mb_source=training_source,
   mb_size=minibatch_size,
   model_inputs_to_streams=input_map,
   max_samples=max_samples,
   test_config=test_config)
session.train()

訓練模型後,我們可以透過使用TestConfig物件並將其分配給train_session函式的test_config關鍵字引數來為此設定新增驗證。

以下是實現步驟:

步驟 1 - 首先,我們需要從cntk.train模組匯入TestConfig類,如下所示:

from cntk.train import TestConfig

步驟 2 - 現在,我們需要使用test_source作為輸入建立一個新的TestConfig例項:

Test_config = TestConfig(test_source)

完整示例

from cntk.io import StreamDef, StreamDefs, MinibatchSource, CTFDeserializer, INFINITY_REPEAT
def create_datasource(filename, limit =INFINITELY_REPEAT)
labels_stream = StreamDef(field=’labels’, shape=3, is_sparse=False)
feature_stream = StreamDef(field=’features’, shape=4, is_sparse=False)
deserializer = CTFDeserializer(filename, StreamDefs(labels=label_stream, features=features_stream)
Minibatch_source = MinibatchSource(deserializer, randomize=True, max_sweeps=limit)
return minibatch_source
training_source = create_datasource(‘Iris_train.ctf’)
test_source = create_datasource(‘Iris_test.ctf’, limit=1)
from cntk.logging import ProgressPrinter
from cntk.train import Trainer, training_session
minbatch_size = 16
samples_per_epoch = 150
num_epochs = 30
max_samples = samples_per_epoch * num_epochs
input_map = {
   features:   training_source.streams.features,
   labels: training_source.streams.labels
 }
progress_writer = ProgressPrinter(0)
trainer: training_source.streams.labels
session = training_session(trainer,
   mb_source=training_source,
   mb_size=minibatch_size,
   model_inputs_to_streams=input_map,
   max_samples=max_samples,
   test_config=test_config)
session.train()
from cntk.train import TestConfig
Test_config = TestConfig(test_source)

輸出

-------------------------------------------------------------------
average   since   average   since  examples
loss      last    metric    last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.57      1.57     0.214    0.214   16
1.38      1.28     0.264    0.289   48
[………]
Finished Evaluation [1]: Minibatch[1-1]:metric = 69.65*30;

手動小批次迴圈

正如我們上面看到的,透過在使用 CNTK 中的常規 API 進行訓練時使用度量,可以輕鬆測量 NN 模型在訓練期間和訓練後的效能。但是,另一方面,在使用手動小批次迴圈時,情況並非如此簡單。

在這裡,我們使用下面給出的模型,該模型具有 4 個輸入和 3 個輸出,來自我們在前面章節中建立的鳶尾花資料集:

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

接下來,模型的損失被定義為交叉熵損失函式和 F 度量的組合,如前面章節中所用。我們將使用criterion_factory實用程式將其建立為 CNTK 函式物件,如下所示:

import cntk
from cntk.losses import cross_entropy_with_softmax, fmeasure
@cntk.Function
def criterion_factory(outputs, targets):
   loss = cross_entropy_with_softmax(outputs, targets)
   metric = fmeasure(outputs, targets, beta=1)
   return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, 0.1)
label_mapping = {
   'Iris-setosa': 0,
   'Iris-versicolor': 1,
   'Iris-virginica': 2
}

現在,我們已經定義了損失函式,我們將瞭解如何在訓練器中使用它來設定手動訓練會話。

以下是實現步驟:

步驟 1 - 首先,我們需要匯入必要的包,例如numpypandas來載入和預處理資料。

import pandas as pd
import numpy as np

步驟 2 - 接下來,為了在訓練期間記錄資訊,請匯入ProgressPrinter類,如下所示:

from cntk.logging import ProgressPrinter

步驟 3 - 然後,我們需要從cntk.train模組匯入trainer模組,如下所示:

from cntk.train import Trainer

步驟 4 - 接下來,建立一個新的ProgressPrinter例項,如下所示:

progress_writer = ProgressPrinter(0)

步驟 5 - 現在,我們需要使用引數損失、學習器和progress_writer初始化訓練器,如下所示:

trainer = Trainer(z, loss, learner, progress_writer)

步驟 6 - 接下來,為了訓練模型,我們將建立一個迴圈,該迴圈將迭代資料集三十次。這將是外部訓練迴圈。

for _ in range(0,30):

步驟 7 - 現在,我們需要使用 pandas 從磁碟載入資料。然後,為了以小批次載入資料集,將chunksize關鍵字引數設定為 16。

input_data = pd.read_csv('iris.csv',
names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
index_col=False, chunksize=16)

步驟 8 - 現在,建立一個內部訓練 for 迴圈來迭代每個小批次

for df_batch in input_data:

步驟 9 - 現在在這個迴圈內部,使用iloc索引器讀取前四列作為要從中進行訓練的特徵,並將它們轉換為 float32:

feature_values = df_batch.iloc[:,:4].values
feature_values = feature_values.astype(np.float32)

步驟 10 - 現在,讀取最後一列作為要從中進行訓練的標籤,如下所示:

label_values = df_batch.iloc[:,-1]

步驟 11 - 接下來,我們將使用獨熱向量將標籤字串轉換為它們的數字表示,如下所示:

label_values = label_values.map(lambda x: label_mapping[x])

步驟 12 - 此後,獲取標籤的數字表示。接下來,將它們轉換為 numpy 陣列,這樣更容易使用它們,如下所示:

label_values = label_values.values

步驟 13 - 現在,我們需要建立一個新的 numpy 陣列,該陣列的行數與我們轉換的標籤值相同。

encoded_labels = np.zeros((label_values.shape[0], 3))

步驟 14 - 現在,為了建立獨熱編碼的標籤,請根據數字標籤值選擇列。

encoded_labels[np.arange(label_values.shape[0]), label_values] = 1.

步驟 15 - 最後,我們需要在訓練器上呼叫train_minibatch方法,併為小批次提供已處理的特徵和標籤。

trainer.train_minibatch({features: feature_values, labels: encoded_labels})

完整示例

from cntk import default_options, input_variable
from cntk.layers import Dense, Sequential
from cntk.ops import log_softmax, relu, sigmoid
from cntk.learners import sgd
model = Sequential([
   Dense(4, activation=sigmoid),
   Dense(3, activation=log_softmax)
])
features = input_variable(4)
labels = input_variable(3)
z = model(features)
import cntk
from cntk.losses import cross_entropy_with_softmax, fmeasure
@cntk.Function
def criterion_factory(outputs, targets):
   loss = cross_entropy_with_softmax(outputs, targets)
   metric = fmeasure(outputs, targets, beta=1)
   return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, 0.1)
label_mapping = {
   'Iris-setosa': 0,
   'Iris-versicolor': 1,
   'Iris-virginica': 2
}
import pandas as pd
import numpy as np
from cntk.logging import ProgressPrinter
from cntk.train import Trainer
progress_writer = ProgressPrinter(0)
trainer = Trainer(z, loss, learner, progress_writer)
for _ in range(0,30):
   input_data = pd.read_csv('iris.csv',
      names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
      index_col=False, chunksize=16)
for df_batch in input_data:
   feature_values = df_batch.iloc[:,:4].values
   feature_values = feature_values.astype(np.float32)
   label_values = df_batch.iloc[:,-1]
label_values = label_values.map(lambda x: label_mapping[x])
label_values = label_values.values
   encoded_labels = np.zeros((label_values.shape[0], 3))
   encoded_labels[np.arange(label_values.shape[0]), 
label_values] = 1.
   trainer.train_minibatch({features: feature_values, labels: encoded_labels})

輸出

-------------------------------------------------------------------
average    since    average   since  examples
loss       last      metric   last
------------------------------------------------------
Learning rate per minibatch: 0.1
1.45       1.45     -0.189    -0.189   16
1.24       1.13     -0.0382    0.0371  48
[………]

在上面的輸出中,我們在訓練期間獲得了損失和度量的輸出。這是因為我們將度量和損失組合在一個函式物件中,並在訓練器配置中使用了進度列印器。

現在,為了評估模型效能,我們需要執行與訓練模型相同的任務,但是這次我們需要使用Evaluator例項來測試模型。這在下面的 Python 程式碼中顯示:

from cntk import Evaluator
evaluator = Evaluator(loss.outputs[1], [progress_writer])
input_data = pd.read_csv('iris.csv',
   names=['sepal_length', 'sepal_width','petal_length','petal_width', 'species'],
index_col=False, chunksize=16)
for df_batch in input_data:
   feature_values = df_batch.iloc[:,:4].values
   feature_values = feature_values.astype(np.float32)
   label_values = df_batch.iloc[:,-1]
   label_values = label_values.map(lambda x: label_mapping[x])
   label_values = label_values.values
   encoded_labels = np.zeros((label_values.shape[0], 3))
   encoded_labels[np.arange(label_values.shape[0]), label_values] = 1.
   evaluator.test_minibatch({ features: feature_values, labels:
      encoded_labels})
evaluator.summarize_test_progress()

現在,我們將得到類似於以下內容的輸出:

輸出

Finished Evaluation [1]: Minibatch[1-11]:metric = 74.62*143;
廣告
© . All rights reserved.