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. Show
Trong trang này:
1. Giới thiệuKể 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). 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:
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. Số lượng 'stars' trên GitHub repo.
(Xem thêm: Machine Learning Frameworks Comparison)
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)
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?)
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:
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:
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 KerasViệ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:
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 regressionTa 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 regressionQuay 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 perceptronChú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-MNISTCơ 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. 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ì:
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ánTa đã 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:
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
4. Kết luận
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 |