Dense layer là gì

Bài viết này được thực hiện với sự đóng góp của Nguyễn Tiến Cường, Cao Thanh Hà, Đinh Duy Khánh, và Nguyễn Văn Tài. Các bạn này cũng sẽ giúp tôi trong các bài về deep learning tiếp theo.

Trong trang này:

  • 1. Giới thiệu
  • 2. Linear regression và logistic regression với Keras
    • 2.1. Keras với linear regression
    • 2.1. Keras với logistic regression
  • 3. Keras cho multi-layer perceptron
    • 3.1. Giới thiệu về Fashion-MNIST
    • 3.2. Xây dựng một multi-layer perceptron để giải quyết bài toán
    • 3.3. Nhận xét
  • 4. Kết luận
  • 5. Tài liệu tham khảo

1. Giới thiệu

Kể từ 2012 khi deep learning có bước đột phá lớn, hàng loạt các thư viện hỗ trợ deep learning ra đời. Cùng với đó, ngày càng nhiều kiến trúc deep learning ra đời, khiến cho số lượng ứng dụng và các bài báo liên quan tới deep learning tăng lên chóng mặt.

Các thư viện deep learning thường được chống lưng bởi những hãng công nghệ lớn: Google (Keras, TensorFlow), Facebook (Caffe2, Pytorch), Microsoft (CNTK), Amazon (Mxnet), Microsoft và Amazon cũng đang bắt tay xây dựng Gluon (phiên bản tương tự như Keras). (Các hãng này đều có các dịch vụ cloud computing và muốn thu hút người dùng).


Dense layer là gì
Các thư viện deep learning và các hãng công nghệ lớn.
(Nguồn: Battle of the Deep Learning frameworks  Part I: 2017, even more frameworks and interfaces)

Vậy thư viện nào là tốt nhất? Câu trả lời tuỳ thuộc vào việc bạn quen với hệ điều hành, ngôn ngữ lập trình nào, bạn sử dụng deep learning vào mục đích nghiên cứu hay ra sản phẩm, bạn sử dụng trên nền tảng phần cứng nào, v.v.

Nhìn chung, một thư viện deep learning tốt cần có các đặc điểm sau:

  1. Hỗ trợ tính toán với GPU và các hệ thống phân tán. Điều này là tối quan trọng vì việc huấn luyện các mô hình deep learning yêu cầu khả năng tính toán rất mạnh.

  2. Hỗ trợ các ngôn ngữ lập trình phổ biến: C/C++, Python, Java, R,

  3. Có thể chạy được trên nhiều hệ điều hành.

  4. Thời gian từ ý tưởng tới xây dựng và huấn luyện mô hình ngắn.

  5. Có thể chạy trên trình duyệt và các thiết bị di động.

  6. Có khả năng giúp người lập trình can thiệp sâu vào mô hình và tạo ra các mô hình phức tạp.

  7. Chứa nhiều model zoo, tức các mô hình deep learning thông dụng đã được huấn luyện.

  8. Hỗ trợ tính toán backpropagation tự động.

  9. Có cộng đồng hỏi đáp lớn.

Thật khó có thể chỉ ra một thư viện đáp ứng tốt tất cả các yêu cầu phía trên. Các bạn có thể xem các bài so sánh các thư viện này ở phần Tài liệu tham khảo. Tôi chỉ xin giới thiệu một vài thống kê giúp các bạn có cái nhìn nhanh nhất về thư viện nào được sử dụng nhiều nhất.


Dense layer là gì
Số lượng 'stars' trên GitHub repo.
(Xem thêm: Machine Learning Frameworks Comparison)
  1. TensorFlow, 2. Caffe (năm 2015-2016).


Dense layer là gì
Số lượng 'stars' trên GitHub repo, số lượng 'contributors', và 'tuổi' của thư viện.
(Xem thêm: Top 16 Open Source Deep Learning Libraries and Platforms)
  1. TensorFlow, 2. Keras, 3. Caffe


Dense layer là gì
Số lượng các bài báo trên arxiv có đề cập đến mỗi thư viện.
(Xem thêm: Why use Keras?)
  1. TensorFlow, 2. Keras, 3. Caffe

Những so sánh trên đây chỉ ra rằng TensorFlow, Keras và Caffe là các thư viện được sử dụng nhiều nhất (gần đây có thêm PyTorch rất dễ sử dụng và đang thu hút thêm nhiều người dùng).

Keras được coi là một thư viện high-level với phần low-level (còn được gọi là backend) có thể là TensorFlow, CNTK, hoặc Theano (sắp tới Theano sẽ không được duy trì nâng cấp nữa). Keras có cú pháp đơn giản hơn TensorFlow rất nhiều. Với mục đích giới thiệu về các mô hình nhiều hơn là các sử dụng các thư viện deep learning, tôi sẽ chọn Keras với TensorFlow là backend.

(Bản thân tôi khi làm nghiên cứu thường dùng TensorFlow và Pytorch.)

Các bạn có thể đọc thêm bài Why use Keras? trên trang chủ của Keras (Tất nhiên trên trang chủ của thư viện nào cũng sẽ có một bài tương tự kiểu Why use ?). Tôi xin nêu lại một vài gạch đầu dòng:

  • Keras ưu tiên trải nghiệm của người lập trình

  • Keras đã được sử dụng rộng rãi trong doanh nghiệp và cộng đồng nghiên cứu

  • Keras giúp dễ dàng biến các thiết kế thành sản phẩm

  • Keras hỗ trợ huấn luyện trên nhiều GPU phân tán

  • Keras hỗ trợ đa backend engines và không giới hạn bạn vào một hệ sinh thái

Amazon hiện cũng đang làm việc để phát triển MXNet backend cho Keras. Mô hình Keras có thể được huấn luyện trên một số nền tảng phần cứng khác nhau ngoài CPU:

  • NVIDIA GPU
  • Google TPUs, thông qua TensorFlow backend và Google Cloud
  • Các OpenCL GPU, chẳng hạn như các sảm phầm từ AMD, thông qua PlaidML Keras backend.

Hy vọng chừng đó đã đủ để chúng ta cùng bắt đầu với Keras. Cách cài đặt Keras có thể được tìm thấy trên trang chủ của nó.

Tiếp theo, chúng ta sẽ làm quen với Keras qua ba ví dụ đơn giản: linear regression, logistic regression, và multi-layer perceptron.

2. Linear regression và logistic regression với Keras


Việc huấn luyện một mô hình deep learning hay neural network nói chung bao gồm các bước:

  1. Chuẩn bị dữ liệu
  2. Xây dựng network
  3. Chọn thuật toán cập nhật nghiệm, xây dựng loss và phương pháp đánh giá mô hình
  4. Huấn luyện mô hình.
  5. Đánh giá mô hình

Chúng ta cùng xem Keras thực hiện các bước này thông qua hai ví dụ dưới đây.

2.1. Keras với linear regression

Ta cùng làm một ví dụ đơn giản. Dữ liệu đầu X vào có số chiều là 2, đầu ra y = 2*X[0] + 3*X[1] + 4 + e với e là nhiễu tuân theo một phân phối chuẩn có kỳ vọng bằng 0, phương sai bằng 0.2.

Dưới đây là đoạn code ví dụ về huấn luyện mô hình linear regression bằng Keras:

import numpy as np from keras.models import Sequential from keras.layers.core import Dense, Activation from keras import optimizers # 1. create pseudo data y = 2*x0 + 3*x1 + 4 X = np.random.rand(100, 2) y = 2* X[:,0] + 3 * X[:,1] + 4 + .2*np.random.randn(100) # noise added # 2. Build model model = Sequential([Dense(1, input_shape = (2,), activation='linear')]) # 3. gradient descent optimizer and loss function sgd = optimizers.SGD(lr=0.1) model.compile(loss='mse', optimizer=sgd) # 4. Train the model model.fit(X, y, epochs=100, batch_size=2)

Kết quả:

Epoch 1/100 100/100 [==============================] - 0s 5ms/step - loss: 1.7199 Epoch 2/100 100/100 [==============================] - 0s 709us/step - loss: 0.0388 Epoch 3/100 100/100 [==============================] - 0s 675us/step - loss: 0.0415 Epoch 4/100 100/100 [==============================] - 0s 774us/step - loss: 0.0392 Epoch 5/100 ..... Epoch 100/100 100/100 [==============================] - 0s 823us/step - loss: 0.0393

Ta thấy răng thuật toán hội tụ khá nhanh và MSE loss khá nhỏ sau khi huấn luyện xong.

Chúng ta cùng xem xét từng bước:

# 2. Build model model = Sequential([Dense(1, input_shape = (2,), activation='linear')])

Sequantial([<a list>]) là thể hiện việc các layer được xây dựng theo đúng thứ tự trong [<a list>]. Phần tử đầu tiên của list thể hiện kết nối giưa input layer và layer tiếp theo, các phần tử tiếp theo của list thể hiện kết nối của các layer tiếp theo.

Dense thể hiện một fully connected layer, tức toàn bộ các unit của layer trước đó được nối với toàn bộ các unit của layer hiện tại. Giá trị đầu tiên trong Dense bằng 1 thể hiện việc chỉ có 1 unit ở layer này (đầu ra của linear regression trong trường hợp này bằng 1). input_shape = (2,) chính là kích thước của dữ liệu đầu vào. Kích thước này là một tuple nên ta cần viết dưới dạng (2,). Về sau, khi làm việc với dữ liệu nhiều chiều, ta sẽ có các tuple nhiều chiều. Ví dụ, nếu input là ảnh RGB với kích thước 224x224x3 pixel thì input_shape = (224, 224, 3).

Các layer cũng có thể được thêm lần lượt vào model bằng cách sử dụng hàm .add(). Đoạn code phía trên và đoạn code ngay dưới đây là tương đương.

model = Sequential() model.add(Dense(1, input_shape=(2,), activation='linear'))

Activation cũng có thể được tách ra thành riêng một layer như sau:

# 2. Build model model = Sequential() model.add(Dense(1, input_shape=(2,))) model.add(Activation('linear'))

Bạn đọc có thể đọc về các activation của Keras tại đây.

Đoạn code tiếp theo:

# 3. gradient descent optimizer and loss function sgd = optimizers.SGD(lr=0.1) model.compile(loss='mse', optimizer=sgd)

Thể hiện việc chọn phương pháp cập nhật nghiệm, ở đâu ta sử dụng Stochastic Gradient Descent (SGD) với learning rate lr=0.1. Các phương pháp cập nhật nghiệm khác có thể được tìm thấy tại Keras-Usage of optimizers. loss='mse' chính là mean squared error, là hàm mất mát của linear regression.

Sau khi xây dựng được mô hình và chỉ ra phương pháp cập nhật cũng như hàm mất mát, ta huấn luyện mô hình bằng:

model.fit(X, y, epochs=100, batch_size=2)

(Keras khá giống với scikit-learn ở chỗ cùng huấn luyện các mô hình bằng phương thức .fit()). Ở đây, epochs chính là số lượng epoch và batch_size chính là kích thước của một mini-batch.

Để xem hệ số tìm được của linear regression, ta sử dụng:

model.get_weights()

Kết quả:

[array([[1.996118 ], [3.0239758]], dtype=float32), array([3.963116], dtype=float32)]

ở đó, phần tử thứ nhất của list này chính là hệ số tìm được, phẩn tử thứ hai chính là bias. Kết quả này gần với nghiệm mong đợi của bài toán (y = 2*X[0] + 3*X[1] + 4).

Tương đối đơn giản.

2.1. Keras với logistic regression

Quay lại ví dụ về mối liên hệ giữa số giờ ôn tập và kết quả thi trong bài logistic regression, bài toán có thể được giải quyết bằng keras như sau:

import numpy as np from keras.models import Sequential from keras.layers.core import Dense, Activation from keras import losses from keras import optimizers # 1. Prepare data X = np.array([0.50, 0.75, 1.00, 1.25, 1.50, 1.75, 1.75, 2.00, 2.25, 2.50, 2.75, 3.00, 3.25, 3.50, 4.00, 4.25, 4.50, 4.75, 5.00, 5.50]) y = np.array([0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1]) # 2. Build model model = Sequential() model.add(Dense(1, input_shape=(1,))) model.add(Activation('sigmoid')) # 3. gradient descent optimizer and loss function sgd = optimizers.SGD(lr=0.05) model.compile(loss=losses.binary_crossentropy, optimizer=sgd) # 4. Train the model model.fit(X, y, epochs=3000, batch_size=1)

Có hai sự khác biệt ở Activation và loss vì logistic regression sử dụng hàm activation là sigmoid, hàm mất mát là trường hợp đặc biệt của cross entropy với hai class.

Kết quả tìm được tương đối giống với kết quả tìm được trước đó với numpy.

model.get_weights()
[array([[1.5141923]], dtype=float32), array([-4.1248693], dtype=float32)]

và ta có y ~ 1.51*x - 4.12.

3. Keras cho multi-layer perceptron

Chúng ta cùng xây dựng một mạng MLP đơn giản với Keras để giải quyết một bài toán phân loại ảnh.

3.1. Giới thiệu về Fashion-MNIST

Cơ sở dữ liệu ảnh được dùng là Fashion-MNIST.

Chúng ta đã quá quen với việc sử dụng MNIST. MNIST là cơ sở dữ liệu về chữ số viết tay, được sử dụng rất rộng rãi trong cồng đồng AI/ML. MNIST thường được thử đầu tiên khi có một thuật toán phân loại ảnh mới. Một số người nói If it doesnt work on MNIST, it wont work at all. Nhưng đồng thời, Well, if it does work on MNIST, it may still fail on others.

Fashion-MNIST được tạo ra gần đây với kích thước tương tự như MNIST nhưng các ảnh là các ảnh xám của trang phục với các nhãn: (0) T-shirt/top, (1) Trouser, (2) Pullover, (3) Dress, (4) Coat, (5) Sandal, (6) Shirt, (7) Sneaker, (8) Bag, (9) Ankle boot. Fashion-MNIST cũng có 10 class, 60000 ảnh cho training, 10000 ảnh cho test, mỗi ảnh có kích thước 28x28 pixel và là các ảnh xám với chỉ một channel. Dưới đây là một ví dụ về ảnh của class (2) Pullover.


Dense layer là gì
Hình ảnh một mẫu dữ liệu đầu vào với kích thước 28x28, tương ứng với nhãn "pullover" - áo len chui đầu

Tác giả của Fashion-MNIST cho rằng cần phải thay thế MNIST vì:

  • MNIST đã trở nên quá dễ. Rất nhiều thuật toán deep learning đã đạt được độ chính xác lên tới 99.7%, ngay cả KNN cũng đạt được trên 96%. Rất khó để đánh bại con số 99.7%, và nếu mô hình của bạn đạt được con số này, ta vẫn khó có thể kết luận ngay đó là một mô hình tốt.

  • MNIST được sử dụng quá nhiều đến mức nhàm chán.

  • MNIST không đại diện cho các bài toán computer vision hiện đại.

Cơ sở dữ liệu Fashion-MNIST có thể được tải về thông qua keras.datasets

# 1. prepare data from __future__ import print_function from keras.datasets import fashion_mnist (x_train, y_train), (x_test, y_test) = fashion_mnist.load_data() print('x_train shape:\t', x_train.shape) print('x_test shape:\t', x_test.shape) print('y_train shape:\t', y_train.shape) print('y_test shape:\t', y_test.shape)
x_train shape: (60000, 28, 28) x_test shape: (10000, 28, 28) y_train shape: (60000,) y_test shape: (10000,)

Ở đây, x_train, x_test mang các giá trị nguyên từ 0 đến 255, y_train, y_test chứa các số nguyên từ 0 đến 9 thể hiện class của x tương ứng. Nếu sử dụng một neural network với softmax layer ở cuối, ta cần chuẩn hoá dữ liệu đầu vào x_train, x_test về đoạn [0, 1] và chuyển y_train, y_test về dạng one-hot coding.

Việc này có thể được thực hiện như sau:

# data normalization x_train = x_train/255. x_test = x_test/255. num_classes = 10 # convert class vectors to binary class matrices y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes)

3.2. Xây dựng một multi-layer perceptron để giải quyết bài toán

Ta đã thực hiện bước đầu tiên trong bài toán xây dựng mô hình neural network cho bài toán classification bước chuẩn bị dữ liệu.

Trong mục này, chúng ta sẽ đi xây dựng một neural network đơn giản. Một mô hình đủ đơn giản giúp chúng ta tiếp tục làm quen với Keras là multi-layer perceptron.

Ta sẽ xây dựng một MLP với 3 hidden layers. Các layer cụ thể như sau:

  1. Input layer với số units là \(28\times 28 = 784\). Mỗi input là một bức ảnh của Fashion-MNIST được kéo dài ra thành một vector.
  2. Hidden layer thứ nhất với 128 units, activation là ReLU.
  3. Hidden layer thứ hai với 256 units, activation là ReLU.
  4. Hidden layer thứ ba với 512 units, activation là ReLU.
  5. Output layer là một softmax layer với 10 units.

Hàm mất mát là cross entropy, ta tạm thời chưa quan tâm đến regularization (ở đây là weight decay).

Phương pháp đánh giá hệ thống phân lớp này là 'accuracy', tức số lượng điểm được phân loại đúng trong toàn bộ số điểm.

Network đơn giản này được thực hiện trên Keras như sau:

from keras.layers import Dense, Flatten from keras.models import Sequential from keras import metrics # 2. buid model model = Sequential() model.add(Flatten(input_shape=(28, 28))) model.add(Dense(128, activation='relu')) model.add(Dense(256, activation='relu')) model.add(Dense(512, activation='relu')) model.add(Dense(num_classes, activation='softmax')) # 3. loss, metrics model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.SGD(lr=0.1), metrics=['accuracy'])

Ở đây có một hàm mới là Flatten(), hàm này biến mỗi điểm dữ liểu ở dạng một mảng nhiều chiều thành một mảng một chiều. Vì ta đang sử dụng MLP nên ta cần làm công việc này. Về sau, khi sử dụng CNN, việc giữ nguyên mảng hai chiều sẽ cho kết quả tốt hơn.

Kết quả sau khi thực hiện đoạn code trên

Epoch 1/20 60000/60000 [==============================] - 3s 47us/step - loss: 0.6784 - acc: 0.7582 .... Epoch 20/20 60000/60000 [==============================] - 3s 54us/step - loss: 0.2140 - acc: 0.9192

Sau 20 epochs, mô hình cho độ chính xác trên tập huấn luyện x_train khá cao.

Nếu chúng ta muốn đánh giá mô hình trên tập x_test, ta có thể thực hiện như sau:

from keras import metrics score = model.evaluate(x_test, y_test, verbose=0) print('Test loss: %.4f'% score[0]) print('Test accuracy %.4f'% score[1])
Test loss: 0.3312 Test accuracy 0.8840

Như vậy, độ chính xác của mô hình trên tập kiểm thử đạt 88.4%.

Bạn đọc có thể thử giải quyết bài toán này bằng các thuật toán phân loại khác và so sánh kết quả.

3.3. Nhận xét

  • Dữ liệu đầu vào chỉ là 784 chiều và đặc trưng cho dữ liệu thời trang cũng không quá phức tạp trên nền là một màu đen và ảnh đã được căn chỉnh đúng tâm, đúng kích thước. MLP mặc dù cho kết quả tương đối tốt trong bài toán này, nó không phải là một mô hình tối ưu cho dữ liệu dạng ảnh vì ít nhất, dữ liệu ảnh hai chiều ban đầu đã được dàn phẳng ra thành dữ liệu một chiều, làm mất đi những thông tin về không gian trong ảnh (spatial information). Convolutional neural network thông thường sẽ cho kết quả tốt hơn. Tôi sẽ sớm giới thiệu với bạn đọc về kiến trúc này.

  • Mạng MLP đơn giản này chưa dùng nhiều kỹ thuật của deep learning, chúng ta sẽ dần làm quen với các kỹ thuật giúp tăng độ chính xác và giảm thời gian huấn luyện trong các bài sau.

4. Kết luận

  • Keras là một thư viện tương đối dễ sử dụng đối với người mới bắt đầu. Nó cung cấp các hàm số cần thiết với cú pháp đơn giản.

  • Khi đi sâu hơn vào deep learning trong các bài sau, chúng ta sẽ dần làm quen với các kỹ thuật lập trình với Keras. Mời các bạn đón đọc.

  • Source code trong bài này có thể được tìm thấy tại đây.

5. Tài liệu tham khảo

[1] Battle of the Deep Learning frameworks  Part I: 2017, even more frameworks and interfaces

[2] Keras hompage

[3] Comparison of deep learning software Wikipedia