CNTK - Mạng nơ-ron hợp pháp
Trong chương này, chúng ta hãy nghiên cứu cách xây dựng Mạng nơ-ron liên kết (CNN) trong CNTK.
Giới thiệu
Mạng nơ-ron chuyển đổi (CNN) cũng được tạo thành từ các nơ-ron, có trọng số và độ lệch có thể học được. Đó là lý do tại sao theo cách này, chúng giống như các mạng nơ-ron thông thường (NN).
Nếu chúng ta nhớ lại hoạt động của các NN thông thường, mỗi tế bào thần kinh nhận được một hoặc nhiều đầu vào, lấy tổng trọng số và nó được chuyển qua một hàm kích hoạt để tạo ra đầu ra cuối cùng. Ở đây, câu hỏi được đặt ra là nếu CNN và NN thông thường có nhiều điểm giống nhau như vậy thì điều gì khiến hai mạng này khác biệt với nhau?
Điều gì làm cho chúng khác biệt là việc xử lý dữ liệu đầu vào và các loại lớp? Cấu trúc của dữ liệu đầu vào được bỏ qua trong NN thông thường và tất cả dữ liệu được chuyển đổi thành mảng 1-D trước khi đưa nó vào mạng.
Tuy nhiên, kiến trúc Mạng nơ ron Convolutional có thể xem xét cấu trúc 2D của hình ảnh, xử lý chúng và cho phép nó trích xuất các thuộc tính đặc trưng cho hình ảnh. Hơn nữa, CNN có lợi thế là có một hoặc nhiều lớp Convolutional và lớp gộp, là các khối xây dựng chính của CNN.
Các lớp này được theo sau bởi một hoặc nhiều lớp được kết nối đầy đủ như trong NN nhiều lớp tiêu chuẩn. Vì vậy, chúng ta có thể coi CNN, như một trường hợp đặc biệt của các mạng được kết nối đầy đủ.
Kiến trúc mạng nơ-ron hợp pháp (CNN)
Kiến trúc của CNN về cơ bản là một danh sách các lớp biến đổi 3 chiều, tức là chiều rộng, chiều cao và chiều sâu của khối lượng hình ảnh thành khối lượng đầu ra 3 chiều. Một điểm quan trọng cần lưu ý ở đây là, mọi nơ-ron trong lớp hiện tại được kết nối với một bản vá nhỏ của đầu ra từ lớp trước, điều này giống như phủ một bộ lọc N * N lên hình ảnh đầu vào.
Nó sử dụng bộ lọc M, về cơ bản là các bộ trích xuất tính năng để trích xuất các tính năng như cạnh, góc, v.v. Sau đây là các lớp [INPUT-CONV-RELU-POOL-FC] được sử dụng để xây dựng mạng nơ-ron phù hợp (CNN) -
INPUT- Như tên của nó, lớp này giữ các giá trị pixel thô. Giá trị pixel thô có nghĩa là dữ liệu của hình ảnh như nó vốn có. Ví dụ, INPUT [64 × 64 × 3] là hình ảnh RGB 3 kênh có chiều rộng-64, chiều cao-64 và chiều sâu-3.
CONV- Lớp này là một trong những khối xây dựng của CNN vì hầu hết các tính toán được thực hiện trong lớp này. Ví dụ - nếu chúng ta sử dụng 6 bộ lọc trên INPUT [64 × 64 × 3] được đề cập ở trên, điều này có thể dẫn đến khối lượng [64 × 64 × 6].
RELU−Còn được gọi là lớp đơn vị tuyến tính được chỉnh lưu, áp dụng một hàm kích hoạt cho đầu ra của lớp trước đó. Theo cách khác, một độ không tuyến tính sẽ được thêm vào mạng bởi RELU.
POOL- Lớp này, tức là lớp Pooling là một khối xây dựng khác của CNN. Nhiệm vụ chính của lớp này là lấy mẫu xuống, có nghĩa là nó hoạt động độc lập trên mọi lát của đầu vào và thay đổi kích thước của nó trong không gian.
FC- Nó được gọi là lớp Kết nối đầy đủ hay cụ thể hơn là lớp đầu ra. Nó được sử dụng để tính điểm đầu ra của lớp và kết quả đầu ra là khối lượng có kích thước 1 * 1 * L trong đó L là số tương ứng với điểm của lớp.
Sơ đồ dưới đây thể hiện kiến trúc điển hình của CNNs−
Tạo cấu trúc CNN
Chúng ta đã thấy kiến trúc và những điều cơ bản của CNN, bây giờ chúng ta sẽ xây dựng mạng phức hợp bằng CNTK. Ở đây, trước tiên chúng ta sẽ xem cách đặt cấu trúc của CNN lại với nhau và sau đó chúng ta sẽ xem xét cách huấn luyện các tham số của nó.
Cuối cùng, chúng ta sẽ thấy, làm thế nào chúng ta có thể cải thiện mạng nơ-ron bằng cách thay đổi cấu trúc của nó với nhiều thiết lập lớp khác nhau. Chúng tôi sẽ sử dụng tập dữ liệu hình ảnh MNIST.
Vì vậy, trước tiên hãy tạo một cấu trúc CNN. Nói chung, khi chúng tôi xây dựng CNN để nhận dạng các mẫu trong hình ảnh, chúng tôi thực hiện như sau:
Chúng tôi sử dụng kết hợp các lớp tích chập và gộp.
Một hoặc nhiều lớp ẩn ở cuối mạng.
Cuối cùng, chúng tôi kết thúc mạng với một lớp softmax cho mục đích phân loại.
Với sự trợ giúp của các bước sau, chúng ta có thể xây dựng cấu trúc mạng−
Step 1- Đầu tiên, chúng ta cần nhập các lớp cần thiết cho CNN.
from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
Step 2- Tiếp theo, chúng ta cần nhập các chức năng kích hoạt cho CNN.
from cntk.ops import log_softmax, relu
Step 3- Sau đó, để khởi tạo các lớp phức hợp sau này, chúng ta cần nhập glorot_uniform_initializer như sau
from cntk.initializer import glorot_uniform
Step 4- Tiếp theo, để tạo biến đầu vào, hãy nhập input_variablechức năng. Và nhập khẩudefault_option để làm cho cấu hình NN dễ dàng hơn một chút.
from cntk import input_variable, default_options
Step 5- Bây giờ để lưu trữ các hình ảnh đầu vào, hãy tạo một input_variable. Nó sẽ chứa ba kênh là đỏ, lục và lam. Nó sẽ có kích thước 28 x 28 pixel.
features = input_variable((3,28,28))
Step 6−Tiếp theo, chúng ta cần tạo một input_variable để lưu trữ các nhãn để dự đoán.
labels = input_variable(10)
Step 7- Bây giờ, chúng ta cần tạo default_optioncho NN. Và, chúng ta cần sử dụngglorot_uniform làm hàm khởi tạo.
with default_options(initialization=glorot_uniform, activation=relu):
Step 8- Tiếp theo, để thiết lập cấu trúc của NN, chúng ta cần tạo một Sequential tập hợp lớp.
Step 9- Bây giờ chúng ta cần thêm một Convolutional2D lớp với một filter_shape của 5 và a strides thiết lập của 1, trong Sequentialtập hợp lớp. Ngoài ra, hãy bật đệm để hình ảnh được đệm để giữ nguyên kích thước ban đầu.
model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
Step 10- Bây giờ là lúc để thêm một MaxPooling lớp với filter_shape của 2, và a strides cài đặt 2 để nén hình ảnh xuống một nửa.
MaxPooling(filter_shape=(2,2), strides=(2,2)),
Step 11- Bây giờ, như chúng ta đã làm ở bước 9, chúng ta cần thêm một Convolutional2D lớp với một filter_shape của 5 và a stridescài đặt 1, sử dụng 16 bộ lọc. Ngoài ra, hãy bật đệm, để kích thước của hình ảnh được tạo bởi lớp gộp trước đó sẽ được giữ lại.
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
Step 12- Bây giờ, như chúng ta đã làm ở bước 10, hãy thêm một MaxPooling lớp với một filter_shape của 3 và a strides cài đặt 3 để giảm hình ảnh xuống một phần ba.
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Step 13- Cuối cùng, thêm một lớp dày đặc với mười tế bào thần kinh cho 10 lớp có thể, mạng có thể dự đoán. Để biến mạng thành một mô hình phân loại, hãy sử dụnglog_siftmax chức năng kích hoạt.
Dense(10, activation=log_softmax)
])
Hoàn thành ví dụ để tạo cấu trúc CNN
from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)
Đào tạo CNN bằng hình ảnh
Khi chúng ta đã tạo ra cấu trúc của mạng, đã đến lúc đào tạo mạng. Nhưng trước khi bắt đầu đào tạo mạng của mình, chúng ta cần thiết lập các nguồn minibatch, bởi vì đào tạo NN hoạt động với hình ảnh đòi hỏi nhiều bộ nhớ hơn hầu hết các máy tính có.
Chúng tôi đã tạo các nguồn minibatch trong các phần trước. Sau đây là mã Python để thiết lập hai nguồn minibatch:
Như chúng ta có create_datasource , bây giờ chúng ta có thể tạo hai nguồn dữ liệu riêng biệt (đào tạo và kiểm tra một) để đào tạo mô hình.
train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)
Bây giờ, khi chúng ta đã chuẩn bị các hình ảnh, chúng ta có thể bắt đầu đào tạo NN của mình. Như chúng ta đã làm trong các phần trước, chúng ta có thể sử dụng phương thức train trên hàm mất mát để bắt đầu quá trình đào tạo. Sau đây là mã cho điều này -
from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
loss = cross_entropy_with_softmax(output, targets)
metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)
Với sự trợ giúp của mã trước đó, chúng tôi đã thiết lập mất và học cho NN. Đoạn mã sau sẽ đào tạo và xác thực NN−
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
features: train_datasource.streams.features,
labels: train_datasource.streams.labels
}
loss.train(train_datasource,
max_epochs=10,
minibatch_size=64,
epoch_size=60000,
parameter_learners=[learner],
model_inputs_to_streams=input_map,
callbacks=[progress_writer, test_config])
Hoàn thành ví dụ triển khai
from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)
import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
mapping_file = os.path.join(folder, 'mapping.bin')
image_transforms = []
if train:
image_transforms += [
xforms.crop(crop_type='randomside', side_ratio=0.8),
xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
stream_definitions = StreamDefs(
features=StreamDef(field='image', transforms=image_transforms),
labels=StreamDef(field='label', shape=10)
)
deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)
train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)
from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
loss = cross_entropy_with_softmax(output, targets)
metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
features: train_datasource.streams.features,
labels: train_datasource.streams.labels
}
loss.train(train_datasource,
max_epochs=10,
minibatch_size=64,
epoch_size=60000,
parameter_learners=[learner],
model_inputs_to_streams=input_map,
callbacks=[progress_writer, test_config])
Đầu ra
-------------------------------------------------------------------
average since average since examples
loss last metric last
------------------------------------------------------
Learning rate per minibatch: 0.2
142 142 0.922 0.922 64
1.35e+06 1.51e+07 0.896 0.883 192
[………]
Biến đổi hình ảnh
Như chúng ta đã thấy, rất khó để đào tạo NN được sử dụng để nhận dạng hình ảnh và chúng cũng cần rất nhiều dữ liệu để đào tạo. Một vấn đề nữa là họ có xu hướng trang bị quá nhiều hình ảnh được sử dụng trong quá trình đào tạo. Hãy để chúng tôi xem với một ví dụ, khi chúng tôi chụp ảnh khuôn mặt ở tư thế thẳng đứng, người mẫu của chúng tôi sẽ gặp khó khăn khi nhận ra khuôn mặt được xoay theo hướng khác.
Để khắc phục vấn đề này, chúng ta có thể sử dụng chức năng nâng cao hình ảnh và CNTK hỗ trợ các phép biến đổi cụ thể, khi tạo nguồn minibatch cho hình ảnh. Chúng ta có thể sử dụng một số phép biến đổi như sau:
Chúng tôi có thể cắt ngẫu nhiên hình ảnh được sử dụng để đào tạo chỉ với một vài dòng mã.
Chúng ta cũng có thể sử dụng thang đo và màu sắc.
Hãy xem với sự trợ giúp của mã Python sau, chúng ta có thể thay đổi danh sách các phép biến đổi như thế nào bằng cách bao gồm một phép chuyển đổi cắt xén trong hàm được sử dụng để tạo nguồn minibatch trước đó.
import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
mapping_file = os.path.join(folder, 'mapping.bin')
image_transforms = []
if train:
image_transforms += [
xforms.crop(crop_type='randomside', side_ratio=0.8),
xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
stream_definitions = StreamDefs(
features=StreamDef(field='image', transforms=image_transforms),
labels=StreamDef(field='label', shape=10)
)
deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)
Với sự trợ giúp của đoạn mã trên, chúng ta có thể nâng cao chức năng bao gồm một tập hợp các phép biến đổi hình ảnh, do đó, khi chúng ta đào tạo, chúng ta có thể cắt ảnh một cách ngẫu nhiên, để chúng ta có được nhiều biến thể hơn của hình ảnh.