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).
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
Đâ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
0
1
2
3
4
5
6
7
8
9
10
|
# Import các thư viện cần thiết
from __future__ import print_function
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# Import MNIST data
# TF có hỗ trợ giúp chúng ta đọc dữ liệu mnist
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
import tensorflow as tf
|
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.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# Khai báo các tham số của mô hình
learning_rate = 0.1 # tốc độ học
num_steps = 500 # tổng số lần học/huấn luyện
batch_size = 128 # Số điểm dữ liệu đưa vào học mỗi lần huấn luyến
display_step = 100 # Cứ sau 100 lần học, hiện thị các thay đổi thông số của mô hình
# Các tham số của mạng
n_hidden_1 = 256 # 1st layer number of neurons - số nơ ron của layer 1
n_hidden_2 = 256 # 2nd layer number of neurons - số nơ ron của layer 2
input_shapre = 784 # MNIST data input (img shape: 28*28) kích thước của 1 input(vector 784 chiều).
num_classes = 10 # MNIST total classes (0-9 digits) - label vector dạng one-hot
# tf Graph input
X = tf.placeholder("float", [None, input_shape])
Y = tf.placeholder("float", [None, num_classes])
|
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.
0
1
2
3
4
5
6
7
8
9
10
11
12
|
# Khai báo weights và bias cho từng layer
weights = {
'h1': tf.Variable(tf.random_normal([input_shape, n_hidden_1])),
'h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
'out': tf.Variable(tf.random_normal([n_hidden_2, num_classes]))
}
biases = {
'b1': tf.Variable(tf.random_normal([n_hidden_1])),
'b2': tf.Variable(tf.random_normal([n_hidden_2])),
'out': tf.Variable(tf.random_normal([num_classes]))
}
|
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_1
, n_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']
.
0
1
2
|
tf.matmul(x, 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]
.
0
1
2
|
layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
|
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:
0
1
2
|
layer_2 = tf.add(tf.matmul(layer_1, weights['h2']), biases['b2'])
|
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:
0
1
2
3
4
5
6
7
8
9
10
|
# Tạo model nối các layer
def neural_net(x):
# Hidden fully connected layer with 256 neurons
layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
# Hidden fully connected layer with 256 neurons
layer_2 = tf.add(tf.matmul(layer_1, weights['h2']), biases['b2'])
# Output fully connected layer with a neuron for each class
out_layer = tf.matmul(layer_2, weights['out']) + biases['out']
return out_layer
|
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.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
logits = neural_net(X)
# Khởi tạo loss và optimizer
loss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
logits=logits, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss_op)
# Đánh giá model
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
# ops khởi tạo các biến của graph
init = tf.global_variables_initializer()
|
Ở đâ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ụ:
0
1
2
3
|
logits = [1;2;3;4;-1]
tf.argmax(logits, 1) = 4
|
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ụ:
0
1
2
3
4
|
x = [1 2 3]
y = [1 3 3]
tf.equal(x, y) = [True False True]
|
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.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
with tf.Session() as sess:
# Chạy op khởi tạo
sess.run(init)
for step in range(1, num_steps+1):
batch_x, batch_y = mnist.train.next_batch(batch_size)
# Run optimization op (backprop)
sess.run(train_op, feed_dict={X: batch_x, Y: batch_y})
if step % display_step == 0 or step == 1:
# Calculate batch loss and accuracy
loss, acc = sess.run([loss_op, accuracy], feed_dict={X: batch_x,
Y: batch_y})
print("Step " + str(step) + ", Minibatch Loss= " + \
"{:.4f}".format(loss) + ", Training Accuracy= " + \
"{:.3f}".format(acc))
print("Optimization Finished!")
# Tính toán độ chính xác của model dựa trên tập MNIST test
print("Testing Accuracy:", \
sess.run(accuracy, feed_dict={X: mnist.test.images,
Y: mnist.test.labels}))
|
Và log của quá trình huấn luyện như sau:
0
1
2
3
4
5
6
7
8
9
|
Step 1, Minibatch Loss= 11165.8379, Training Accuracy= 0.266
Step 100, Minibatch Loss= 406.9644, Training Accuracy= 0.852
Step 200, Minibatch Loss= 175.5160, Training Accuracy= 0.898
Step 300, Minibatch Loss= 65.0292, Training Accuracy= 0.875
Step 400, Minibatch Loss= 37.5970, Training Accuracy= 0.906
Step 500, Minibatch Loss= 62.5484, Training Accuracy= 0.859
Optimization Finished!
Testing Accuracy: 0.862
|
Độ 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.
Bài tiếp theo: #
Blogger Comment
Facebook Comment