Thứ Hai, 31 tháng 12, 2018

[Machine Learning][Deep Learning] Kiến trúc Gated Recurrent Unit (GRU) trong RNN

Kiến trúc của 1 unit trong 1 RNN như ta đã đề cập trước đó có mô hình như dưới đây:
Lúc này, a<t> sẽ phụ thuộc vào chuỗi dữ liệu trước đó bên cạnh tác động của exploding/vanishing gradient.
Ví dụ trong câu: The cat, which already ate two big fishes and three apples ..., was full.
Lúc này The cat là số ít sẽ đi kèm với động từ tobe was, tuy nhiên ở giữa lại là 1 chuỗi dài, và trong RNN thường, ta không thể sử dụng feature The cat do chủ ngữ The cat và động từ was cách xa nhau trong chuỗi.

Một kiến trúc mới của RNN là GRU sẽ giải quyết vấn đề này.
Trong GRU, ta định nghĩa c là 1 memory cell, và c<t> = a<t> (a<t> trong RNN thường, nhưng trong GRU, ta dùng c<t> thay vì a<t>). Γu là hàm gate được tính bởi sigmoid function sẽ có giá trị xấp xỉ 0 hoặc 1. Với mỗi thời điểm t, Γu sẽ quyết định việc update c<t> = č<t> bằng biểu thức sau đây:

Nghĩa là nếu Γu = 1, ta sẽ update, nếu Γu=0, giá trị c<t> = c<t-1>, không có sự biến đổi trong mạng RNN. Do vậy trong chuỗi đã cho ở phần đầu, ta sẽ xác định được những step nào nên có sự biến đổi và những step nào nên được giữ nguyên.
Ở đây ta thấy chỉ có cat và was sẽ được update, những step t giữa chúng sẽ có giá trị  Γu=0 ứng với việc giữ nguyên. Do đó, ta có thể coi như trong câu chỉ còn The cat was full vì các step t có giá trị Γu=0 sẽ không đóng vai trò trong việc tính toán output. Thực ra vai trò của chúng là rất nhỏ vì Γu là xấp xỉ bằng 0, nhưng do đi qua nhiều step t, nên giá trị này trở nên nhỏ vô cùng gần 0, do đó ta vừa có thể tính toán output từ 1 step t rất ra trước đó, vừa có thể khắc phục vanishing hoặc exploding gradient khi mà ta bỏ qua hầu hết những thành phần không quan trọng trong sequence.

Mô hình đơn giản của 1 GRU unit sẽ như sau:

Thực tế trong mô hình GRU, ta có thêm 1 gate nữa là Γr trong đó gate này thể hiện sự giống nhau giữa c<t-1> và č<t>.
Mô hình GRU lúc này sẽ gồm 2 gate được biểu diễn như sau:


[Machine Learning] Vanishing và exploding gradient trong Neural Network

Thuật toán Gradient Descent dùng để để tìm cực tiểu của hàm cost ứng với các parameter của 1 NN. Trong NN, thông tin được tính toán từ trái qua phải, bắt đầu với input và kết thúc bởi output, trong khi đó, loss được tính và back propagation được tính theo chiểu ngược lại để ta có thể update các parameter trong mỗi qua mỗi iteration.
RNN cũng hoạt động tương tự, nhưng vì dữ liệu trong RNN là sequence nên sẽ có 2 điểm khác biệt.
- Dữ liệu đầu vào ở trạng thái hiện tại chính là đầu ra của trạng thái trước đó.
- Với mỗi thời điểm t nhất định, ta có thể tính toán cost function một cách độc lập.
Trong hình trên, với mỗi thời điểm t ta đều có thể tính toán error εt. Để tính toán và update các parameter, ta phải thực hiện back propagation từ chiều output quay ngược lại. Mỗi 1 neuron trong mạng đều tham gia vào quá trình tính toán ra output cuối cùng cũng như cost function, thông số của các neuron này cần tìm là các giá trị để cost function đạt cực tiểu. Tuy nhiên, trong RNN, mọi neuron từ neuron đầu tiên tới neuron cuối cùng đều tham gia vào quá trình này, do vậy, ta sẽ phải thực hiện back proapgate through time cho tất cả các neuron.
Vấn đề sẽ nằm ở việc update ma trận trọng số wrec.
Để tính toán xt-2 ta sẽ cần nhân xt-3 với wrec hoặc muốn tính xt-1 ta sẽ cần nhân xt-2 với wrec . Ma trận trọng số wrec là giống nhau trong toàn mạng RNN, dó vậy, nếu wrec nhỏ, giá trị gradient sẽ nhỏ, và nhỏ dần khi số lượng layer trong RNN là lớn, và giá trị này giảm theo hàm mũ.

Ta đã biết rằng ma trận này được khởi tạo lúc ban đầu với các giá trị mặc định xấp xỉ 0 và từ đó ta thực hiện train mạng NN. Tuy nhiên, nếu ra khởi tạo ma trận trọng số theo cách này và nhân với các giá trị xtxt-1xt-2xt-3, … gradient sẽ giảm nhanh sau mỗi phép nhân - vanishing gradient. Tương tự nếu giá trị này là lớn, khi đó gradient tăng nhanh và sẽ xảy ra hiện tượng tràn số, lúc này giá trị gradient ta nhận được sẽ là NaN, đây là hiện tượng exploding gradient.

Giá trị gradient càng nhỏ, NN sẽ khó để update các parameter và tốc độ converge của cost function sẽ chậm hơn rất nhiều. Ví dụ ta chỉ cần 1000 epochs để có thể tìm được giá trị tối ưu cho parameter tại thời điểm t, tuy nhiên 1000 epochs sẽ không đủ cho thời điểm t-3 do lúc này gradient đã bị giảm đi rất nhiều.
Ta có thể nghĩ rằng vậy ta có thể train đúng cho nửa mạng, nghĩa là từ t trở đi là đúng, còn t quay lại là sai, tuy nhiên tất cả mạng NN của ta sẽ bị train sai. Giải thích đơn giản là vì output của layer trước là input của layer sau, nếu ta train tại thời điểm t mà input lấy tại layer chưa được train trước đó, lúc này việc training ở thời điểm t sẽ trả về giá trị sai.

Kiến trúc Gated Recurrent Unit (GRU) hoặc Long Short Term Memory (LSTM) sẽ giải quyết vấn đề này.

Chủ Nhật, 30 tháng 12, 2018

[Machine Learning][Deep Learning] Recurrent Neural Network


  • Sequence data
Sequence data hay dữ liệu tuần tự là loại dữ liệu mà các thành phần phụ thuộc lẫn nhau về mặt thời gian hay ngữ nghĩa, ví dụ: 1 đoạn audio, 1 câu nói, hoặc 1 chuỗi DNA ...
  • Tại sao không dùng Neural Network thường (Standard Neural Network) như hình dưới.
Với các dữ liệu dạng tuần tự, khi ta dùng NN thường (có input, hidden layer và output) sẽ có 2 hai vấn đề:
- Các dữ liệu đầu vào là không cùng length, mà với NN thường, các thông số này phải được xác định trước ví dụ như số units của input layer, output layer.
- Các dữ liệu xử lý trong NN thường là các dữ liệu độc lập nghĩa là chúng không liên quan tới nhau, mà trong dữ liệu tuần tự, ta muốn quan sát các dữ liệu xung quanh để tính toán đầu ra một cách chính xác. Ví dụ như trong câu: The president of US is George Bush, khi này nếu ta đang xây dựng 1 mô hình Name Entity Recognition (NER), để phát hiện George Bush là tên người, nếu mạng NN biết được president là 1 danh từ chỉ người có trong câu khi đó đầu ra sẽ chính xác hơn (confidence score sẽ cao hơn).
  • Kiến trúc RNN
RNN được cho bởi kiến trúc như hình sau:
Các đầu ra ŷ<t> sẽ phụ thuộc vào đầu vào x<t> cũng như các dữ liệu trước đó được cho bởi a<t-1>. Lúc này, ta có thể tận dụng các feature của các sample xuất hiện trước đó trong 1 chuỗi.
Tuy nhiên, mô hình RNN lại có 1 nhược điểm đó là nó chỉ có thể tận dụng các feature của các sample xuất hiện trước đó mà không thể tận dụng các sample ở phía sau. Khi này, một mô hình mới là Bidirectional RNN được đề xuất để giải quyết vấn đề này.
Ngoài ra, trong RNN, ta vẫn phải thực hiện forward và back propagation. Khi thực hiện back propagation, t sẽ giảm dần nghĩa là ta quay ngược lại thời gian theo ngược chiều của chuỗi được cho, lúc này thuật toán được gọi là back propagation through time (BPTT)

Thứ Bảy, 29 tháng 12, 2018

Host load prediction with long short-term memory in cloud computing - Binbin Song· Yao Yu· Yu Zhou· Ziqiang Wang· Sidan Du


  • RNN

Thông số tải là một vector 1 chiều dạng time series (one-dimensional time series). Giả sử giá trị lịch sử tải trước đó là x = (xt-1, xt-2, . . . , xt-n) với n thường là rất lớn. Ta muốn dự đáon giá trị tải 
o = (xˆt+1, xˆt+2, . . . , xˆt+m)  trong đó m là số steps ở sau thời điểm hiện tại hoặc giá trị tải trung bình  o = (xˆt+1, xˆt+2, . . . , xˆt+m)/m của m steps. cạc đơn giản nhất là ta tìm 1 hàm ánh xạ (map function) f giữa lịch sử tải trước đó và giá trị trong tương lai (giá trị ta cần dự đoán):
(xˆt+1, xˆt+2, . . . , xˆt+m) = f (xt-1, xt-2, . . . , xt-n) 
Khi các giá trị lịch sử tải gần với giá trị hiện tại, mối quan hệ giữa các giá trị này sẽ lớn hơn, trong khi các giá trị lịch sử tải xa với giá trị hiện tại sẽ thường biểu diễn xu hướng và yếu tố này sẽ giúp cho việc dữ đoán. Do đó, để thiết lập 1 mapping function chính xác, ta phải cân nhắc đến cả hai yếu tố này. Ta gọi g1 là mapping function của các giá trị lịch sử tải gần và g2 là các giá trị lịch sử tải xa, gộp hai hàm này ta có hàm f' như dưới đây:
f (x; n) = f (g1(xt-1, xt-2, . . . , xt-k), g2(xt-(k+1), . . . , xt-n))  
Cách xây dựng mô hình này gần như tương đương với RNN khi mà các thông số U và W được sử dụng.
RNN lưu các trạng thái trước đó cho phép ta có thể sử dụng trong việc dự đoán tải. 
Tại mỗi thời điểm, mạng sẽ nhận input xt với khung cửa sổ cố định và tính toán hidden state st và output ot sử dụng biểu thức sau:
với U, W và V là các ma trận trọng số và σ là một activation function phi tuyến.

  • LSTM
Trong bài báo này, ta thay thế các hidden layer của RNN bằng các LSTM bkock để có thể học được long-term dependencies.

Thứ Năm, 27 tháng 12, 2018

[Machine learning] Hyperparameters vs parameters

Trong một mạng NN, ta có các thông số cần phải tìm để tối ưu mạng đó là W và b cho các layers.

Các thông số (paramters) mà tác động đến W và b được gọi là các hyperparameters, có thể liệt kê:
+ Learning rate alpha
+ Số lần iterations
+ Số hidden layers
+ Số units trong hidden layers
+ Hàm activation nào được chọn v.v.

Applied deep learning is a very empirical process - Andrew Ng

Nghĩa là trong các ứng dụng về DL, công việc chủ yếu của ta là đi tìm các hyper parameters, và tìm các tham số này phải giải quyết bằng thực nghiệm theo như sơ đồ dưới đây.
Ví dụ ta muốn tìm hyperparameter learning rate, khi đó ta phải thử với rất nhiều các giá trị alpha khác nhau và có thể cần vẽ hàm cost để thấy được tác động của learning rate lên quá trình convergence.

[Machine Learning] Deep neural network vs shallow neural network

Trong bài trước, khi ta nhắc đến shallow neural network, ta hiểu rằng đây là mạng nơ ron mà chỉ có một hoặc hai hidden layer, thực ra con số này là không định lượng, việc ta nói shallow và deep chỉ để phân biệt rằng hai kiến trúc mạng một kiến trúc sử dụng số lượng nhỏ và mạng còn lại sử dụng số lượng lớn hidden layer. Trái lại, trong deep neural network, số lượng hidden layer lớn hơn nhiều. Như đã nói ở trước, khi nói về số lớp của 1 mạng, ta sẽ bỏ qua input layer, do đó với hình dưới đây, logistic regression cũng có thể coi là một mạng neuron với chỉ 1 lớp.

Khi thực hiện tính toán forward propagation và back propagation trong Deep NN, ta cũng phải thực hiện tuần tự qua từng layer, ví dụ như với hình trên là 2 hidden layer, khi này ta sẽ phải lần lượt tính z1, a1, z2, a2 tương ứng với 2 hidden layer. 
Ta nên để ý và phân biệt rõ 2 khái niệm: hidden layer và layer của 1 mạng khi layer của 1 mạng được hiểu như là số lượng hidden layer cộng với 1 output layer.
Ngoài ta, ta sẽ có 1 vòng loop trong việc thực hiện FP và BP, ví dụ ta có n hidden layers, khi đó vòng loop của ta sẽ phải chạy qua n layer. Trái với việc tính toán trước đó ta có thể dùng vectorization, việc tính toán BP và FP không thể áp dụng vectorization và ta phải lặp qua từng layer để tính toán các giá trị W, b hay a, z.

Ngoài ra, ở layer input, ta nên chú ý rằng x1,x2,x3 chỉ là input feature của 1 sample, do đó khi có m samples, thì input vector sẽ là [mx3] với 3 là số feature của 1 input, mỗi hàng là 1 sample trong input vector.

Tiếp theo ta nói về size của các tham số trong 1 mạng Deep NN.
Giả sử ta có một Deep NN như hình dưới đây, khi đó, với mỗi layer, ta kí hiện n^[k] là số unit của layer đó, ví dụ với input layer, mỗi sample được biểu diễn bởi 2 feature, do đó n^[0] = 2, tương tự n^[1] = 3.
Các w và b của các layer có số chiều tổng quát là:
W[L] = n^[L]xn^[L-1].
Ví dụ W[2] = n^[2] x n^[1] = [5x3]
b là bias của các unit trong 1 layer, do đó nếu 1 layer có n^[L] units, thì chiều của b[L] = [n^[L] x 1]
Để tính BP, dw và db có cùng số chiều với w và b

Khi ta có 1 sample, chiều của z[L] hay a[L] là [n^[L] x 1]
Khi có m sample, chiều của z[L] hay a[L] là [n^[L] x m]

Thứ Tư, 26 tháng 12, 2018

[Machine Learning] Tại sao ta thường nên dùng tanh thay vì sigmoid khi chọn activation function?

Hai hàm sigmoid và tanh có cùng trend, tuy nhiên chúng lại có đặc tính khác nhau do đặc tính đồ thị, ta quan sát đồ thị hai hàm dưới đây.


Lí do hàm tanh tốt hơn hàm sigmoid đặc biệt là trong các ứng dụng về Big data bởi vì đạo hàm của hàm tanh thường luôn có giá trị lớn hơn đạo hàm của hàm sigmoid, do đó độ dốc của hàm tanh là lớn hơn, do đó hàm lost sẽ converge nhanh hơn. Sử dụng toán học, ta có thể chứng minh rằng.
tanhx=2σ(2x)1
Và trong hầu hết các trường hợp, ta có thể chứng minh rằng.

Trong một số trường hợp đặc biệt, ta sẽ dùng sigmoid function thay vì hàm tanh, 
ví dụ như trong bàitoán binary classification, đầu ra chỉ là 0 và 1, khi này sigmoid 
sẽ là một lựa chọn hợp lý thay vì sử dụng tanh.

Thứ Ba, 25 tháng 12, 2018

[Machine Learning] Khởi tạo các thông số weights và bias trong Shallow Neural Network

Một mạng nơ ron nông (shallow) là một mạng có số hiddens layers là nhỏ.
Khi xây dựng một NN, một trong những điều đầu tiên ta cần làm là khởi tạo các giá trị w và b cho mạng. Ví dụ mạng dưới đây có 1 hidden layer, khi này, mỗi sample sẽ được biểu diễn bởi 2 features. Ví dụ x1 = [1x2], mà ta có z = x.wT + b và ta có 2 units ở hidden layer, do đó w1 = [2x2], và a = [1x2].[2x2] = [1x2]. Từ đó, w2 = [2x1] vì ta chỉ có 1 đầu ra [1x2].[2x1] = [1x1].
w1 = [2x2] : cột của ma trận là số unit trong hidden layer, hàng là số feature của input.
b1 = [2x1], vì ta muốn thêm bias vào các unit trong hidden layer, do đó ma trận này phải là cột.

w2 = [2x1]
b2 = [1x1]

Trong logistic regression, các tham số w và b ta có thể khởi tạo bằng 0, nhưng với neural network, việc khởi tạo các giá trị bằng 0 sẽ không hợp lý. Nếu ta thực hiện back-propagation, ta sẽ update các w như sau:
w = w - alpha.dJ/dw
dJ/dw đươc tính trong các bài trước là:
dJ/dw = x.(a-y) mà a = g(z) = g(wx + b) = g(b) vì w bằng 0 trên toàn mạng. Khi này dJ/dw = x(g(b) - y) sẽ giống nhau trên toàn mạng, khi thực hiện back-propagation, các unit là giống nhau do đó ta sẽ không thể thực hiện được deep learning khi mà ta muốn thực hiện rất nhiều hàm trên mạng.

Khi này, ta phải khởi tạo giá trị w một cách mặc định như hình dưới đây.


Lí do ta phải nhân giá trị sau khởi tạo với hằng số 0.01 mà không phải 10 hay 100, -100 ... là bởi vì nếu giá trị |w| lớn, khi đó giá trị z lớn, mà theo đồ thị hàm tanh như trên, nếu giá trị z lớn, slope của nó sẽ rất nhỏ do đó việc learning sẽ tốn rất nhiều thời gian, việc khởi tạo w này gọi là zero-centric initialization nghĩa là các giá trị w sẽ gần với giá trị 0 để đảm bảo slope lớn và việc thực hiện GD sẽ diễn ra nhanh hơn.

b và các thông số thêm vào các unit phản ảnh bias, do đó ta có thể khởi tạo các giá trị này là 0 mà không ảnh hưởng tới hoạt động của NN.

[Machine Learning] Đạo hàm của các activation functions

Như ta đã nhắc đến lúc trước, đạo hàm của 1 hàm tại một điểm là độ dốc (slope) của hàm đó tại điểm đó. Ví dụ với hàm sigmoid.
Với giá trị lớn (z = 10) hoặc z nhỏ (-10), ta có thể thấy giá trị đạo hàm tính theo công thức = 0 ứng với các vùng bão hòa của sigmoid function.
Với giá trị z - 0, g(z) = 1/2 và g'(z) = 1/4 nghĩ là độ dốc của sigmoid tại điểm z = 0 là lớn.

Ngoài ra với hàm tanh, đạo hàm là tương đương với sigmoid ngoại trừ các điểm ở chính giữa đồ thị.



Cuối cùng là hàm RELU và Leaky RELU.

Thứ Hai, 24 tháng 12, 2018

[Machine Learning] Activation functions trong Neural Networks

Mô hình của 1 mạng nơ ron có cấu trúc như sau:
Ở đây, mỗi node trong hidden layer sẽ thực hiện 2 công việc.
1. Thực hiện a = X.wT + b
2. Thực hiện z = g(a)

Trong đó g là activation function. 
Cho đến nay, ta đã nhắc tới sigmoid function như là 1 activation function có biểu thức:

Ngoài ra, còn có một số activation function khác (các activation functions đều là các hàm phi tuyến) như hình dưới đây:
Trong thực tế, ta sẽ chỉ dùng các hàm sigmoid và tanh cho output layer khi mà đầu ra cần các giá trị nằm trong khoảng (0,1) hoặc (-1,1) còn các hàm như ReLU and Leaky ReLU được sử dụng ở trong các node của hidden layers. Lý do ta không sử dụng các hàm sigmoid hay tanh trong hidden layers là khi ta thực hiện back propagation, các giá trị đạo hàm sẽ nhỏ dần khi ta đi từ phải sang trái của 1 mạng NN, đo đó Gradient Descent sẽ không thể áp dụng.

Ngoài ra, tại sao ta lại cần các activation function. Ví dụ gán trực tiếp z = a và ta không hề sử dụng hàm g. Lúc này, output và input sẽ quan hệ với nhau bởi 1 hàm tuyến tính, do đó, ta sẽ không thể có nhiều lớp.

Ta sử dụng activation functions là các hàm tuyến tính thì có được không? Hay việc sử dụng hàm phi tuyến sẽ đem lại kết quả tốt hơn?

Và tại sao ta lại cần nhiều lớp trong Neural Network?

Chủ Nhật, 23 tháng 12, 2018

[Python Programming] Numpy experiences

1. Numpy arrays are element wise by default
2. Recall that "np.dot(a,b)" performs a matrix multiplication on a and b, whereas "a*b" performs an element-wise multiplication.

[Python Programming] Câu lệnh assert và cách dùng

Câu lệnh assert có trong hầu hết các ngôn ngữ lập trình, chúng giúp cho việc phát hiện sớm các lỗi trong chương trình, ví dụ như ta muốn kiểm tra đầu vào của một chương trình được nhập từ bán phím chẳng hạn.

Khi ta sử dụng:

assert condition
lúc này ta đang yêu cầu chương trình kiểm tra điều kiện condition và gửi về lỗi nếu điều kiện là False. Trong Python, câu lệnh này tương đương với.

if not condition:
    raise AssertionError()
Ví dụ ta thử trong Python sẽ thấy:
>>> assert False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
 Assertions có thể bao gồm cả log để debug và ta có thể tắt các assertions khi chạy với trình thông dịch - interpreter.
Để in ra log đi cùng với assertions nếu điều kiện sai xảy ra:

assert False, "Oh no! This assertion failed!"
Khi chạy python để bỏ qua các lệnh assert, ta có thể thêm option -O ví dụ:


python -O script.py