CNTK - Phân loại mạng thần kinh
Trong chương này, chúng ta sẽ nghiên cứu cách phân loại mạng nơron bằng CNTK.
Giới thiệu
Phân loại có thể được định nghĩa là quá trình dự đoán nhãn đầu ra phân loại hoặc phản hồi cho dữ liệu đầu vào nhất định. Đầu ra được phân loại, sẽ dựa trên những gì mô hình đã học được trong giai đoạn đào tạo, có thể có dạng như "Đen" hoặc "Trắng" hoặc "thư rác" hoặc "không có thư rác".
Mặt khác, về mặt toán học, nhiệm vụ xấp xỉ một hàm ánh xạ nói f từ biến đầu vào nói X đến biến đầu ra nói Y.
Một ví dụ điển hình về vấn đề phân loại có thể là phát hiện thư rác trong e-mail. Rõ ràng là chỉ có thể có hai loại đầu ra, "thư rác" và "không có thư rác".
Để thực hiện phân loại như vậy, trước tiên chúng ta cần thực hiện đào tạo bộ phân loại nơi các email "spam" và "không spam" sẽ được sử dụng làm dữ liệu đào tạo. Sau khi đã đào tạo thành công trình phân loại, nó có thể được sử dụng để phát hiện một email không xác định.
Ở đây, chúng ta sẽ tạo 4-5-3 NN bằng cách sử dụng tập dữ liệu hoa iris có như sau:
4 nút đầu vào (một nút cho mỗi giá trị dự đoán).
5-nút xử lý ẩn.
3 nút đầu ra (vì có thể có ba loài trong tập dữ liệu mống mắt).
Đang tải tập dữ liệu
Chúng tôi sẽ sử dụng bộ dữ liệu hoa iris, từ đó chúng tôi muốn phân loại các loài hoa iris dựa trên các đặc tính vật lý của chiều rộng và chiều dài đài hoa, chiều rộng và chiều dài của cánh hoa. Bộ dữ liệu mô tả các đặc tính vật lý của các giống hoa iris khác nhau -
Chiều dài riêng lẻ
Chiều rộng vách ngăn
Chiều dài cánh hoa
Chiều rộng cánh hoa
Loại iris setosa hoặc iris versicolor hoặc iris virginica
Chúng ta có iris.CSVtệp mà chúng tôi đã sử dụng trước đây trong các chương trước. Nó có thể được tải với sự trợ giúp củaPandasthư viện. Tuy nhiên, trước khi sử dụng nó hoặc tải nó cho bộ phân loại của chúng tôi, chúng ta cần chuẩn bị các tệp đào tạo và thử nghiệm để nó có thể được sử dụng dễ dàng với CNTK.
Chuẩn bị các tệp đào tạo và kiểm tra
Bộ dữ liệu Iris là một trong những bộ dữ liệu phổ biến nhất cho các dự án ML. Nó có 150 mục dữ liệu và dữ liệu thô trông như sau:
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
…
7.0 3.2 4.7 1.4 versicolor
6.4 3.2 4.5 1.5 versicolor
…
6.3 3.3 6.0 2.5 virginica
5.8 2.7 5.1 1.9 virginica
Như đã nói trước đó, bốn giá trị đầu tiên trên mỗi dòng mô tả các đặc tính vật lý của các giống khác nhau, tức là chiều dài Sepal, chiều rộng Sepal, chiều dài cánh hoa, chiều rộng cánh hoa của hoa iris.
Tuy nhiên, chúng ta phải chuyển đổi dữ liệu theo định dạng mà CNTK có thể dễ dàng sử dụng và định dạng đó là tệp .ctf (chúng tôi cũng đã tạo một iris.ctf trong phần trước). Nó sẽ giống như sau:
|attribs 5.1 3.5 1.4 0.2|species 1 0 0
|attribs 4.9 3.0 1.4 0.2|species 1 0 0
…
|attribs 7.0 3.2 4.7 1.4|species 0 1 0
|attribs 6.4 3.2 4.5 1.5|species 0 1 0
…
|attribs 6.3 3.3 6.0 2.5|species 0 0 1
|attribs 5.8 2.7 5.1 1.9|species 0 0 1
Trong dữ liệu trên, thẻ | attribs đánh dấu điểm bắt đầu của giá trị đặc trưng và thẻ | loài đánh dấu giá trị nhãn lớp. Chúng tôi cũng có thể sử dụng bất kỳ tên thẻ nào khác mà chúng tôi muốn, thậm chí chúng tôi cũng có thể thêm ID mặt hàng. Ví dụ, hãy xem dữ liệu sau:
|ID 001 |attribs 5.1 3.5 1.4 0.2|species 1 0 0 |#setosa
|ID 002 |attribs 4.9 3.0 1.4 0.2|species 1 0 0 |#setosa
…
|ID 051 |attribs 7.0 3.2 4.7 1.4|species 0 1 0 |#versicolor
|ID 052 |attribs 6.4 3.2 4.5 1.5|species 0 1 0 |#versicolor
…
Có tổng số 150 mục dữ liệu trong tập dữ liệu mống mắt và đối với ví dụ này, chúng tôi sẽ sử dụng quy tắc giữ tập dữ liệu 80-20 tức là 80% (120 mục) mục dữ liệu cho mục đích đào tạo và 20% (30 mục) mục dữ liệu còn lại để kiểm tra mục đích.
Xây dựng mô hình phân loại
Đầu tiên, chúng ta cần xử lý các tệp dữ liệu ở định dạng CNTK và chúng ta sẽ sử dụng hàm trợ giúp có tên create_reader như sau -
def create_reader(path, input_dim, output_dim, rnd_order, sweeps):
x_strm = C.io.StreamDef(field='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', 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
Bây giờ, chúng ta cần thiết lập các đối số kiến trúc cho NN của chúng ta và cũng cung cấp vị trí của các tệp dữ liệu. Nó có thể được thực hiện với sự trợ giúp của mã python sau:
def main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 data items)
Bây giờ, với sự trợ giúp của dòng mã sau, chương trình của chúng tôi sẽ tạo ra NN chưa được đào tạo -
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)
nnet = oLayer
model = C.ops.softmax(nnet)
Bây giờ, khi chúng ta đã tạo mô hình kép không được đào tạo, chúng ta cần thiết lập đối tượng thuật toán Người học và sau đó sử dụng nó để tạo đối tượng đào tạo Người huấn luyện. Chúng tôi sẽ sử dụng trình học SGD vàcross_entropy_with_softmax mất chức năng -
tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
Mã thuật toán học tập như sau:
max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
Bây giờ, khi chúng ta đã hoàn thành với đối tượng Trainer, chúng ta cần tạo một hàm reader để đọc dữ liệu huấn luyện−
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
Bây giờ là lúc đào tạo mô hình NN của chúng ta−
for i in range(0, max_iter):
curr_batch = rdr.next_minibatch(batch_size, input_map=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))
Khi chúng tôi đã hoàn thành việc đào tạo, hãy đánh giá mô hình bằng cách sử dụng các mục dữ liệu thử nghiệm -
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)
Sau khi đánh giá độ chính xác của mô hình NN được đào tạo của chúng tôi, chúng tôi sẽ sử dụng nó để đưa ra dự đoán trên dữ liệu không nhìn thấy -
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[6.4, 3.2, 4.5, 1.5]], dtype=np.float32)
print("\nPredicting Iris species for input features: ")
print(unknown[0]) pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities are: ")
print(pred_prob[0])
Mô hình phân loại hoàn chỉnh
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='attribs', shape=input_dim, is_sparse=False)
y_strm = C.io.StreamDef(field='species', 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 main():
print("Using CNTK version = " + str(C.__version__) + "\n")
input_dim = 4
hidden_dim = 5
output_dim = 3
train_file = ".\\...\\" #provide the name of the training file(120 data items)
test_file = ".\\...\\" #provide the name of the test file(30 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)
nnet = oLayer
model = C.ops.softmax(nnet)
tr_loss = C.cross_entropy_with_softmax(nnet, Y)
tr_clas = C.classification_error(nnet, Y)
max_iter = 2000
batch_size = 10
learn_rate = 0.01
learner = C.sgd(nnet.parameters, learn_rate)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
max_iter = 2000
batch_size = 10
lr_schedule = C.learning_parameter_schedule_per_sample([(1000, 0.05), (1, 0.01)])
mom_sch = C.momentum_schedule([(100, 0.99), (0, 0.95)], batch_size)
learner = C.fsadagrad(nnet.parameters, lr=lr_schedule, momentum=mom_sch)
trainer = C.Trainer(nnet, (tr_loss, tr_clas), [learner])
rdr = create_reader(train_file, input_dim, output_dim, rnd_order=True, sweeps=C.io.INFINITELY_REPEAT)
iris_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=iris_input_map) trainer.train_minibatch(curr_batch)
if i % 500 == 0:
mcee = trainer.previous_minibatch_loss_average
macc = (1.0 - trainer.previous_minibatch_evaluation_average) * 100
print("batch %4d: mean loss = %0.4f, accuracy = %0.2f%% " \ % (i, mcee, macc))
print("\nEvaluating test data \n")
rdr = create_reader(test_file, input_dim, output_dim, rnd_order=False, sweeps=1)
iris_input_map = { X : rdr.streams.x_src, Y : rdr.streams.y_src }
num_test = 30
all_test = rdr.next_minibatch(num_test, input_map=iris_input_map) acc = (1.0 - trainer.test_minibatch(all_test)) * 100
print("Classification accuracy = %0.2f%%" % acc)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])
if __name__== ”__main__”:
main()
Đầu ra
Using CNTK version = 2.7
batch 0: mean loss = 1.0986, mean accuracy = 40.00%
batch 500: mean loss = 0.6677, mean accuracy = 80.00%
batch 1000: mean loss = 0.5332, mean accuracy = 70.00%
batch 1500: mean loss = 0.2408, mean accuracy = 100.00%
Evaluating test data
Classification accuracy = 94.58%
Predicting species for input features:
[7.0 3.2 4.7 1.4]
Prediction probabilities:
[0.0847 0.736 0.113]
Lưu mô hình được đào tạo
Tập dữ liệu Iris này chỉ có 150 mục dữ liệu, do đó sẽ chỉ mất vài giây để đào tạo mô hình phân loại NN, nhưng việc đào tạo trên một tập dữ liệu lớn có hàng trăm hoặc nghìn mục dữ liệu có thể mất hàng giờ hoặc thậm chí vài ngày.
Chúng tôi có thể lưu mô hình của mình để không phải giữ lại từ đầu. Với sự trợ giúp của mã Python sau đây, chúng ta có thể lưu NN được đào tạo của mình -
nn_classifier = “.\\neuralclassifier.model” #provide the name of the file
model.save(nn_classifier, format=C.ModelFormat.CNTKv2)
Sau đây là các đối số của save() hàm được sử dụng ở trên -
Tên tệp là đối số đầu tiên của save()chức năng. Nó cũng có thể được ghi cùng với đường dẫn của tệp.
Một tham số khác là format tham số có giá trị mặc định C.ModelFormat.CNTKv2.
Đang tải mô hình được đào tạo
Khi bạn đã lưu mô hình được đào tạo, rất dễ dàng tải mô hình đó. Chúng tôi chỉ cần sử dụngload ()chức năng. Hãy kiểm tra điều này trong ví dụ sau:
import numpy as np
import cntk as C
model = C.ops.functions.Function.load(“.\\neuralclassifier.model”)
np.set_printoptions(precision = 1, suppress=True)
unknown = np.array([[7.0, 3.2, 4.7, 1.4]], dtype=np.float32)
print("\nPredicting species for input features: ")
print(unknown[0])
pred_prob = model.eval(unknown)
np.set_printoptions(precision = 4, suppress=True)
print("Prediction probabilities: ")
print(pred_prob[0])
Lợi ích của mô hình đã lưu là khi bạn tải một mô hình đã lưu, nó có thể được sử dụng chính xác như thể mô hình vừa được huấn luyện.