[Khóa học tensorflow] Bài 5 – Xây dựng mô hình Neural Network

This entry is part 6 of 6 in the series Thư viện Tensorflow

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.

Bài học trước: Xây dựng mô hình logistic regression sử dụng Tensorflow

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

Mình xin 5 phút quảng cáo nha =))

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
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
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_1, n_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']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 xweights['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ả xweights['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
Tensorboard neural network model

Bài tiếp theo: #

Series Navigation<< [Khóa học tensorflow] Bài 4 – Xây dựng mô hình logistic regression
avatar
4 Comment threads
5 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
Nguyễn Văn HiếuKhoaThanhLong LươngHiếu Nguyễn Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
ThanhLong Lương
Guest
ThanhLong Lương

em không thấy có bước thực hiện hàm phi tuyến trong 1 layer , dữ liệu này là tuyến tính hết ạ ? Và nếu như output layer là 1 hàm softmax thì ta sẽ viết ntn trong tensorflow ?

Hiếu Nguyễn
Guest
Hiếu Nguyễn

Có thể mình chưa trả lời chính xác nhất nên rất hi vọng có sự thảo luận từ nhiều bạn khác về câu hỏi này.
Do đây là một mô hình mạng đơn giản nên sẽ thiếu đi một số layer.
Nếu bạn muốn biết cách dùng softmax trong tensorflow thì có thể xem ví dụ này: https://github.com/aymericdamien/TensorFlow-Examples/blob/master/notebooks/3_NeuralNetworks/convolutional_network_raw.ipynb

Hiếu Nguyễn
Guest
Hiếu Nguyễn

Bổ sung: Mình mới đọc về softmax và có nhận xét thế này. Đây chỉ là 1 cách để đưa output về dạng kết quả cho tổng xác xuất = 1. Như vậy thì cũng đơn giản và có thể tự viết được. Hoặc dùng hàm của TF: tf.nn.softmax. Ở trên cũng có dùng 1 hàm softmax đó bạn

ThanhLong Lương
Guest
ThanhLong Lương

vì em nghĩ mục đích sử dụng mạng neural chỉ là để xử lý dữ liệu phi tuyến , nếu dữ liệu đã tuyến tính thì ta hoàn toàn có thể chỉ cần 1 lớp softmax là có được kết quả khá khả quan , nên em nghĩ nên bổ sung các hàm xử lý phi tuyến trong 1 layer

Khoa
Guest
Khoa

Bạn Hiếu ơi, cho mình hỏi: Mình có thể lấy dữ liệu chữ số của riêng mình để test trên model này được không? Và nếu được thì sẽ viết như thế nào?

Khoa
Guest
Khoa

Mình cảm ơn bạn Hiếu rất nhiều nhe.

Khoa
Guest
Khoa

Bạn Hiếu ơi, mình có thử chạy đoạn code của bạn và đã thêm một số thư viện cũng như sửa một số lỗi sau khi xem link, nhưng có 1 lỗi mình không có cách nào sửa được, mong bạn trả lời giúp. Lỗi đó là

File “E:\Anaconda3\lib\site-packages\tensorflow\python\client\session.py”, line 1425, in __init__
session._session, options_ptr, status)
File “E:\Anaconda3\lib\site-packages\tensorflow\python\framework\errors_impl.py”, line 528, in __exit__
c_api.TF_GetCode(self.status.status))
InvalidArgumentError: sequential_1_input:0 is both fed and fetched.