Powered by Blogger.

Bài 5 – Xây dựng mô hình Neural Network

Chào tất cả các bạn, trong bài viết này Nguyễn Văn Hiếu blog tiếp tục trình bày series về khóa học Tensorflow. Nếu bạn chưa nắm được thông tin tutorial này, bạn hãy xem bài viết giới thiệu trước tiên nhé. Bài đầu tiên sẽ mô tả chi tiết thông tin về khóa học này, các yêu cầu với người học, cài đặt môi trường và danh sách các bài học từ đầu đến cuối.
Trong bài viết này, chúng ta sẽ cùng đi xây dựng một model neural network đơn giản sử dụng bộ dữ liệu MNIST và cùng bàn luận về các vấn đề xung quanh. Toàn bộ source code của bài này các bạn có thể xem tại đây
Kể từ bài này, tôi sẽ dùng jupyter notebook để viết code. Nếu bạn chưa quen, hãy để lại bình luận. Nếu cần thiết, tôi sẽ viết riêng 1 bài hướng dẫn.

Mô tả bài toán và bộ dữ liệu MNIST

MNIST là bộ dữ liệu là các con số viết tay từ 0 đến 9. Bộ dữ liệu này bao gồm 60.000 mẫu cho huấn luyện và 10.000 mẫu để kiểm thử. Các mẫu dữ liệu trong bộ MNIST đã được chuẩn hóa về kích thước: căn chỉnh chính giữa dữ liệu, và mỗi mẫu sẽ là một ảnh có kích thước(shape) 28×28 pixel có nhãn là giá trị số của nó(0 đến 9).
mnist data
Trong bài toán ví dụ này, để đơn giản hóa thì mỗi mẫu dữ liệu(ảnh) sẽ được đưa về 1-D numpy array có 784 chiều(28*28 = 784).
Thông tin chi tiết về dữ liệu: http://yann.lecun.com/exdb/mnist/
Còn đây là hình ảnh về mạng neural network mà chúng ta sẽ cài đặt với tensorflow
mạng neural network với 2 hidden layer
Đây là một mạng neural network rất đơn giản có 2 hidden layer fully connected. Chúng ta sẽ sử dụng mạng này để huấn luyện trên bộ dữ liệu mnist. Bạn không cần lo lắng nếu chưa thực sự hiểu rõ về mạng neural network này. Tôi sẽ giải thích cho bạn rõ hơn ở phần cài đặt nó.
Vẫn như thường lệ, một chương trình TF sẽ gồm 2 bước: xây dựng graph và thực thi tính toán trên graph đã xây dựng.

Xây dựng graph cho mạng neural network phía trên

Việc đầu tiên vẫn là import các thư viện cần thiết cho bài toán của chúng ta
Sau khi chạy secsion này, dữ liệu mnist sẽ được tải về, chương trình sẽ đọc và lưu trong biến mnist
Tiếp theo, chúng ta khai báo một số tham số cho model.
Trong đó:
n_hidden_1n_hidden_2 là số noron của mỗi layer do chúng ta định nghĩa và cũng không cần phải giống nhau. Số 256 ở đây có thể thay bằng số khác nhé.
input_shape là kích thước của 1 điểm dữ liệu. Do chúng ta đã đưa ảnh 28×28 về vector 1 chiều.
num_class là kích thước của vector nhãn sử dụng one-hot vector. Bài trước mình đã giải thích kỹ phần này rồi nên xin phép không nói lại.
X có shape là [None, input_class] có nghĩa là chúng ta có thể truyền vào số lượng điểm dữ liệu tùy ý, nhưng mỗi điểm dữ liệu phải là 1 tensor(trường hợp này là 1 vector) có input_shape chiều.
Y có shape là [None, num_class] có nghĩa là chúng ta có thể truyền vào số lượng điểm dữ liệu tùy ý, nhưng mỗi điểm dữ liệu phải là 1 tensor(trường hợp này là 1 vector) có num_class chiều.
Tiếp theo, chúng ta cần cung cấp cho chương trình các tham số của từng layer. Cụ thể ở đây là weights và bias.
Chắc không cần nói các bạn cũng hình dung được weights['h1']biases['b1'] lần lượt là weights, bias của layer 1; weights['h2']biases['b2'] là weights và bias của layer 2. Còn weights và bias của layer output là weights['out']biases['out'].

Giải thích shape của weights và bias

Vậy thì từ đâu sinh ra shape của weigts['h1']weigts['h2']weigts['out'] như trên?
Hiển nhiên số cột n_hidden_1n_hidden_2 ở weigts['h1']weigts['h2']là các con số chúng ta mong muốn nên không giải thích gì rồi. Còn số cột num_classes là hiển nhiên vì chúng ta muốn output giống với label của dữ liệu.
Phần này có liên quan tới điều kiện nhân 2 mảng(n-D array) – hoặc gọi là tensor trong TF, mình sẽ giải thích thật dễ hiểu cho các bạn.
Giải thích cho weights['h1'] có shape = [input_shape, n_hidden_1]:
Bạn xem đoạn code tiếp theo(đoạn code kết nối các layer), chúng ta đang cần tính toán phép nhân ma trận giữa x và weights['h1'].
tf.matmul(x, y) trả về kết quả của phép nhân 2 tensor x và y.
x ở đây là một input, do đó shape(x) = [1, 784]. Do 1 điểm dữ liệu là 1 vector 784 chiều tôi đã nói ở trên.
Mà để có thể nhân hai ma trận này, thì chiều cuối của ma trận x phải bằng với chiều đầu tiên của ma trận weights['h1']. Trong trường hợp này, cả x và weights['h1'] đều là ma trận(2-D tensor) cho nên ta có thể nói đơn giản là: số cột của ma trận x phải bằng số hàng của ma trận weights['h1'].
Nếu A là một ma trận m x n và B là ma trận n x p thì phép nhân 2 ma trận A và B có kết quả là một ma trận có kích thước m x p
Như vậy, tf.matmul(x, weights['h1'])trong phép toán dưới đây(đoạn code kết nối các layer) sẽ là một 2-D array có số hàng bằng số hàng của x, có số cột bằng số cột của weights['h1']. Tức shape= [1, n_hidden_1].
Lưu ý: tf.add(x, y) thực hiện phép cộng 2 tensor có cùng kích thước. Hiển nhiên đúng, vì tensor kết quả của tf.matmul(x, weights['h1']) và tensor biases['b1'] là như nhau.
Cuối cùng, shape(layer_1) = [1, n_hidden_1].
Tương tự, bạn có thể giải thích cho shape của weights['h2'] như sau:
Đoạn code tạo model nối các layer có dòng sau:
Như vậy, để đảm bảo có thể thực hiện phép nhân, số cột của layer_1  và số hàng của weights['h2'] phải bằng nhau. Còn phép cộng 2 tensor cho ra kích thước không đổi.
Với weights['out'] và các biases['h1'],  biases['h2']biases['out'] bạn đọc tự giải thích theo cách tương tự.

Nối các layer lại

Việc tiếp theo chúng ta cần thực hiện là kết nối các layer lại. Chúng ta sẽ định nghĩa một hàm như sau:
Việc kết nối các layer khá đơn giản, layer sau sẽ dùng kết quả của layer trước.
Tiếp theo, chúng ta sẽ xây dựng các op dự đoán, tính toán lỗi và optimizer.
Ở đây, các bạn có thể thấy logits chính là output bước đầu của chúng ta khi truyền vào input(ở đây là X). loss_op cho ra trung bình(tf.reduce_mean) mất mát sử dụng tf.nn.softmax_cross_entropy_with_logits của tf.
tf.argmax(logits, 1) trả về giá trị max trong tensor logits theo chiều thứ 2(cột) – chiều được đánh chỉ số từ 0.
Ví dụ:
tf.equal(x, y) trả về tensor có cùng kích thước với x và y. Trả về so sánh của từng phần tử tương ứng giữa x và y.
Ví dụ:
tf.cast(correct_pred, tf.float32) vonvert correct_pred về kiểu tf.float32. Do đang là boolean nên True = 1 và False = 0.
Op init được khai báo và lát nữa chúng ta sẽ run đầu tiên trong session để khởi tạo tất cả các Variable chúng ta đã định nghĩa.

Thực thi và đánh giá model

Giờ thì tạo session và chạy thôi chứ còn gì nữa.
Và log của quá trình huấn luyện như sau:
Độ chính xác là 86% cho bộ dữ liệu MNIST. Đây là 1 kết quả thấp do model của chúng ta quá đơn giản mà.
Các bạn có thể xem model vừa triển khai trên tensorboard.
Tensorboard neural network model
Bài tiếp theo: #
    Blogger Comment
    Facebook Comment