Machine Learning thật thú vị (Phần 2: ví dụ đơn giản Neuron Network)
Tôi thích học những thứ mà tôi thích chơi, và tôi thấy nó mang lại kết quả tốt. Hướng dẫn này dạy backpropagation thông qua một ví dụ trò chơi rất đơn giản, thực hiện bằng một đoạn code python ngắn, và bạn sẽ thấy nó quen quen. Bài toán Chúng ta sẽ tạo ra một Neuron Network để dự đoán kết ...
Tôi thích học những thứ mà tôi thích chơi, và tôi thấy nó mang lại kết quả tốt. Hướng dẫn này dạy backpropagation thông qua một ví dụ trò chơi rất đơn giản, thực hiện bằng một đoạn code python ngắn, và bạn sẽ thấy nó quen quen.
Bài toán
Chúng ta sẽ tạo ra một Neuron Network để dự đoán kết quả như dưới đây:
Input 1 | Input 2 | Output |
---|---|---|
0 | 0 | 0 |
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
Code
Bạn thấy nó "quen quen" chứ? Đó chính là phép XOR nhỉ? Ok, không chần chừ gì nữa, chúng ta bắt tay vào code mạng Neuron Network này nào. Tôi sẽ dùng mạng Neuron 2 layer
import numpy as np # sigmoid function def nonlin(x,deriv=False): if(deriv==True): return x*(1-x) return 1/(1+np.exp(-x)) # input dataset X = np.array([ [0,0], [1,1], [1,0], [0,1] ]) # output dataset y = np.array([[0,0,1,1]]).T # seed random numbers to make calculation # deterministic (just a good practice) np.random.seed(1) # initialize weights randomly with mean 0 syn0 = 2*np.random.random((2,1)) - 1 for iter in xrange(10000): # forward propagation l0 = X l1 = nonlin(np.dot(l0,syn0)) # how much did we miss? l1_error = y - l1 # multiply how much we missed by the # slope of the sigmoid at the values in l1 l1_delta = l1_error * nonlin(l1,True) # update weights syn0 += np.dot(l0.T,l1_delta) print "Output After Training:" print l1
Kết quả
Kết quả sau khi Training: [[ 0.00966449] [ 0.00786506] [ 0.99358898] [ 0.99211957]]
Giải thích các biến
Biến | Mô tả |
---|---|
X | Nhập dữ liệu ma trận đầu vào, nơi mỗi hàng là một ví dụ để training |
Y | Ma trận dữ liệu đầu ra, nơi mỗi hàng là một ví dụ training tương ứng |
L0 | Lớp đầu tiên của Neuron Network, được xác định bởi dữ liệu đầu vào |
L1 | Lớp thứ hai của Neuron Network, còn được gọi là lớp ẩn |
Syn0 | Lớp trọng lượng thứ nhất, Synapse 0, kết nối từ L0 đến L1. |
* | Toán tử nhân, vì vậy hai vectơ có kích thước bằng nhau nhân các giá trị tương ứng 1 đến 1 để tạo ra một vector cuối cùng có kích thước giống hệt nhau. |
- | Các phép trừ nguyên tố, vì vậy hai vectơ có kích thước bằng nhau sẽ trừ đi các giá trị tương ứng 1 đến 1 để tạo ra một vector cuối cùng có kích thước giống hệt nhau. |
x.dot(y) | Nếu x và y là vectơ, đây là một dấu chấm. Nếu cả hai đều là ma trận, đó là phép nhân ma trận. Nếu chỉ có một là một ma trận, thì đó là phép nhân ma trận vector. |
Giải thích code
Như bạn thấy trong kết quả sau khi Training, nó đã hoạt động! Trước khi tôi mô tả quá trình, tôi khuyên bạn nên "nghịch" xung quanh với mã để có được một cảm giác trực quan cho nó hoạt động như thế nào. Dưới đây là một số cách mà bạn có thể nghịch:
- So sánh l1 sau lần lặp đầu tiên và sau lần lặp cuối cùng.
- Kiểm tra function "nonlin". Đây là những gì cho chúng ta một xác suất như đầu ra.
- Kiểm tra xem l1_error thay đổi như bạn lặp lại như thế nào.
- Lấy ra dòng 36. Phần lớn của điều kỳ diệu nằm ở đây.
- Kiểm tra dòng 39. Tất cả mọi thứ trong mạng chuẩn bị cho hoạt động này.
Bây giờ chúng ta sẽ nghiên cứu từng dòng code nhé.
Khuyến nghị: bạn hãy mở 2 màn hình, 1 là của đoạn code trên, 1 là đoạn dưới đây để bạn có thể dễ dàng theo dõi.
Dòng 01: Đây là numpy, là một thư viện đại số tuyến tính. Đây là sự phụ thuộc duy nhất của chúng tôi.
Dòng 04: Đây là "phi tuyến tính" của chúng ta. Mặc dù nó có thể là một số loại function, tính không tuyến tính này mô tả một hàm gọi là "sigmoid". Một hàm sigmoid ánh xạ bất kỳ giá trị nào với một giá trị giữa 0 và 1. Chúng ta sử dụng nó để chuyển đổi các số thành xác suất. Nó cũng có một số đặc tính mong muốn khác để huấn luyện các Neuron Network.
Dòng 05: Lưu ý rằng function này cũng có thể tạo ra các dẫn xuất của một sigmaoid (khi deriv là True). Một trong những tính chất mong muốn của một hàm sigmoid là đầu ra của nó có thể được sử dụng để tạo ra các dẫn xuất của nó. Nếu đầu ra của sigmoid là một biến output, sau đó các đạo hàm chỉ đơn giản là ra * (1-out). Điều này rất hiệu quả.
Nếu bạn không quen với các dẫn xuất, chỉ cần suy nghĩ về nó như là độ dốc của hàm sigmoid tại một điểm nhất định (như bạn có thể thấy ở trên, các điểm khác nhau có độ dốc khác nhau).
Dòng 10: Điều này khởi tạo bộ dữ liệu đầu vào của chúng ta như một ma trận numpy. Mỗi hàng là một ví dụ để training. Mỗi cột tương ứng với một trong các node đầu vào của chúng ta. Vì vậy, chúng tôi có 2 node đầu vào mạng và 4 ví dụ training.
Dòng 16: Điều này khởi tạo bộ dữ liệu đầu ra của chúng tôi. Trong trường hợp này, tôi tạo ra các tập dữ liệu theo chiều ngang (với một hàng và 4 cột) cho không gian. ".T" là chức năng chuyển vị. Sau khi chuyển đổi, ma trận Y này có 4 hàng với một cột. Giống như đầu vào của chúng tôi, mỗi hàng là một ví dụ training, và mỗi cột (chỉ một) là một node đầu ra. Vì vậy, mạng của chúng tôi có 2 đầu vào và 1 đầu ra.
Dòng 20: Thực hành tốt để gieo số ngẫu nhiên của bạn. Số của bạn vẫn sẽ được phân phối ngẫu nhiên, nhưng chúng sẽ được phân phối ngẫu nhiên theo cách chính xác mỗi lần bạn đào tạo. Điều này làm cho việc xem các thay đổi của bạn ảnh hưởng đến mạng như thế nào dễ dàng hơn.
Dòng 23: Đây là ma trận trọng số của chúng ta cho Neuron Network này. Nó được gọi là "syn0" để ngụ ý "synapse zero". Vì chúng ta chỉ có 2 lớp (đầu vào và đầu ra), chúng ta chỉ cần một ma trận trọng lượng để kết nối chúng. Kích thước của nó là (2,1) bởi vì chúng ta có 2 đầu vào và 1 đầu ra. Một cách khác để nhìn vào nó là l0 có kích thước 2 và l1 có kích thước 1. Vì vậy, chúng ta muốn kết nối mọi nút trong l0 tới mỗi nút trong l1, đòi hỏi ma trận dimensionality (2,1).