CNTK - Regressão da Rede Neural
O capítulo ajudará você a entender a regressão da rede neural em relação ao CNTK.
Introdução
Como sabemos que, para prever um valor numérico de uma ou mais variáveis preditoras, usamos a regressão. Vamos dar um exemplo de previsão do valor mediano de uma casa em, digamos, uma das 100 cidades. Para fazer isso, temos dados que incluem -
Uma estatística de crime para cada cidade.
A idade das casas em cada cidade.
Uma medida da distância de cada cidade a uma localização privilegiada.
A proporção aluno-professor em cada cidade.
Uma estatística demográfica racial para cada cidade.
O valor médio da casa em cada cidade.
Com base nessas cinco variáveis de previsão, gostaríamos de prever o valor médio da casa. E para isso podemos criar um modelo de regressão linear ao longo das linhas de -
Y = a0+a1(crime)+a2(house-age)+(a3)(distance)+(a4)(ratio)+(a5)(racial)
Na equação acima -
Y é um valor mediano previsto
a0 é uma constante e
a1 a a5 todos são constantes associadas aos cinco preditores que discutimos acima.
Também temos uma abordagem alternativa de uso de uma rede neural. Isso criará um modelo de previsão mais preciso.
Aqui, estaremos criando um modelo de regressão de rede neural usando CNTK.
Carregando conjunto de dados
Para implementar a regressão de rede neural usando CNTK, usaremos o conjunto de dados de valores de casas da área de Boston. O conjunto de dados pode ser baixado do UCI Machine Learning Repository, que está disponível emhttps://archive.ics.uci.edu/ml/machine-learning-databases/housing/. Este conjunto de dados tem um total de 14 variáveis e 506 instâncias.
Mas, para nosso programa de implementação, usaremos seis das 14 variáveis e 100 instâncias. De 6, 5 como preditores e um como valor a prever. De 100 instâncias, usaremos 80 para treinamento e 20 para fins de teste. O valor que queremos prever é o preço médio de uma casa em uma cidade. Vamos ver os cinco preditores que usaremos -
Crime per capita in the town - Esperaríamos que valores menores fossem associados a esse preditor.
Proportion of owner - unidades ocupadas construídas antes de 1940 - Esperaríamos que valores menores fossem associados a esse preditor porque um valor maior significa uma casa mais antiga.
Weighed distance of the town to five Boston employment centers.
Area school pupil-to-teacher ratio.
An indirect metric of the proportion of black residents in the town.
Preparando arquivos de treinamento e teste
Como fizemos antes, primeiro precisamos converter os dados brutos para o formato CNTK. Vamos usar os primeiros 80 itens de dados para fins de treinamento, portanto, o formato CNTK delimitado por tabulação é o seguinte -
|predictors 1.612820 96.90 3.76 21.00 248.31 |medval 13.50
|predictors 0.064170 68.20 3.36 19.20 396.90 |medval 18.90
|predictors 0.097440 61.40 3.38 19.20 377.56 |medval 20.00
. . .
Os próximos 20 itens, também convertidos para o formato CNTK, serão usados para fins de teste.
Construindo modelo de regressão
Primeiro, precisamos processar os arquivos de dados no formato CNTK e para isso, vamos usar a função auxiliar chamada create_reader como segue -
def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='predictors', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='medval', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src
Em seguida, precisamos criar uma função auxiliar que aceite um objeto minilote CNTK e calcule uma métrica de precisão personalizada.
def mb_accuracy(mb, x_var, y_var, model, delta):
num_correct = 0
num_wrong = 0
x_mat = mb[x_var].asarray()
y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
v = model.eval(x_mat[i])
y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
num_correct += 1
else:
num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)
Agora, precisamos definir os argumentos de arquitetura para nosso NN e também fornecer a localização dos arquivos de dados. Isso pode ser feito com a ajuda do seguinte código python -
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 data items)
Agora, com a ajuda da seguinte linha de código, nosso programa criará o NN não treinado -
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
model = C.ops.alias(oLayer)
Agora, uma vez que tenhamos criado o modelo dual não treinado, precisamos configurar um objeto de algoritmo de Learner. Vamos usar o aluno SGD esquared_error função de perda -
tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch=C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])
Agora, assim que terminarmos com o objeto de algoritmo de aprendizagem, precisamos criar uma função de leitor para ler os dados de treinamento -
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
Agora é hora de treinar nosso modelo NN -
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
mcee = trainer.previous_minibatch_loss_average
acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))
Depois de concluir o treinamento, vamos avaliar o modelo usando itens de dados de teste -
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)
Depois de avaliar a precisão do nosso modelo NN treinado, iremos usá-lo para fazer uma previsão em dados não vistos -
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])
Modelo de regressão completa
import numpy as np
import cntk as C
def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='predictors', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='medval', shape=output_dim, is_sparse=False)
streams = C.io.StreamDefs(x_src=x_strm, y_src=y_strm)
deserial = C.io.CTFDeserializer(path, streams)
mb_src = C.io.MinibatchSource(deserial, randomize=rnd_order, max_sweeps=sweeps)
return mb_src
def mb_accuracy(mb, x_var, y_var, model, delta):
num_correct = 0
num_wrong = 0
x_mat = mb[x_var].asarray()
y_mat = mb[y_var].asarray()
for i in range(mb[x_var].shape[0]):
v = model.eval(x_mat[i])
y = y_mat[i]
if np.abs(v[0,0] – y[0,0]) < delta:
num_correct += 1
else:
num_wrong += 1
return (num_correct * 100.0)/(num_correct + num_wrong)
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 5
hidden_dim = 20
output_dim = 1
train_file = ".\\...\\" #provide the name of the training file(80 data items)
test_file = ".\\...\\" #provide the name of the test file(20 data items)
X = C.ops.input_variable(input_dim, np.float32)
Y = C.ops.input_variable(output_dim, np.float32)
with C.layers.default_options(init=C.initializer.uniform(scale=0.01, seed=1)):
hLayer = C.layers.Dense(hidden_dim, activation=C.ops.tanh, name='hidLayer')(X)
oLayer = C.layers.Dense(output_dim, activation=None, name='outLayer')(hLayer)
model = C.ops.alias(oLayer)
tr_loss = C.squared_error(model, Y)
max_iter = 3000
batch_size = 5
base_learn_rate = 0.02
sch = C.learning_parameter_schedule([base_learn_rate, base_learn_rate/2], minibatch_size=batch_size, epoch_size=int((max_iter*batch_size)/2))
learner = C.sgd(model.parameters, sch)
trainer = C.Trainer(model, (tr_loss), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=boston_input_map) trainer.train_minibatch(curr_batch)
if i % int(max_iter/10) == 0:
mcee = trainer.previous_minibatch_loss_average
acc = mb_accuracy(curr_batch, X, Y, model, delta=3.00)
print("batch %4d: mean squared error = %8.4f, accuracy = %5.2f%% " \ % (i, mcee, acc))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
boston_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 20
all_test = rdr.next_minibatch(num_test, input_map=boston_input_map)
acc = mb_accuracy(all_test, X, Y, model, delta=3.00)
print("Prediction accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])
if __name__== ”__main__”:
main()
Resultado
Using CNTK version = 2.7
batch 0: mean squared error = 385.6727, accuracy = 0.00%
batch 300: mean squared error = 41.6229, accuracy = 20.00%
batch 600: mean squared error = 28.7667, accuracy = 40.00%
batch 900: mean squared error = 48.6435, accuracy = 40.00%
batch 1200: mean squared error = 77.9562, accuracy = 80.00%
batch 1500: mean squared error = 7.8342, accuracy = 60.00%
batch 1800: mean squared error = 47.7062, accuracy = 60.00%
batch 2100: mean squared error = 40.5068, accuracy = 40.00%
batch 2400: mean squared error = 46.5023, accuracy = 40.00%
batch 2700: mean squared error = 15.6235, accuracy = 60.00%
Evaluating test data
Prediction accuracy = 64.00%
Predicting median home value for feature/predictor values:
[0.09 50. 4.5 17. 350.]
Predicted value is:
$21.02(x1000)
Salvando o modelo treinado
Este conjunto de dados de valores da casa de Boston tem apenas 506 itens de dados (entre os quais processamos apenas 100). Conseqüentemente, levaria apenas alguns segundos para treinar o modelo do regressor NN, mas o treinamento em um grande conjunto de dados com centenas ou milhares de itens de dados pode levar horas ou mesmo dias.
Podemos salvar nosso modelo, para que não tenhamos que retê-lo do zero. Com a ajuda do seguinte código Python, podemos salvar nosso NN treinado -
nn_regressor = “.\\neuralregressor.model” #provide the name of the file
model.save(nn_regressor, format=C.ModelFormat.CNTKv2)
A seguir estão os argumentos da função save () usada acima -
O nome do arquivo é o primeiro argumento de save()função. Também pode ser escrito junto com o caminho do arquivo.
Outro parâmetro é o format parâmetro que tem um valor padrão C.ModelFormat.CNTKv2.
Carregando o modelo treinado
Depois de salvar o modelo treinado, é muito fácil carregar esse modelo. Precisamos apenas usar a função load (). Vamos verificar isso no exemplo a seguir -
import numpy as np
import cntk as C
model = C.ops.functions.Function.load(“.\\neuralregressor.model”)
np.set_printoptions(precision = 2, suppress=True)
unknown = np.array([[0.09, 50.00, 4.5, 17.00, 350.00], dtype=np.float32)
print("\nPredicting area median home value for feature/predictor values: ")
print(unknown[0])
pred_prob = model.eval({X: unknown)
print("\nPredicted value is: ")
print(“$%0.2f (x1000)” %pred_value[0,0])
O benefício do modelo salvo é que, depois de carregar um modelo salvo, ele pode ser usado exatamente como se o modelo tivesse acabado de ser treinado.