Phần 3: Tạo mạng nơ-ron đầu tiên.

Mạng nơ-ron cho mọi người (\^_^). Ai cũng có thể làm được.
Từng bước từng bước, đơn giản dễ hiểu và dĩ nhiên ko có toán ở đây.

Cài đặt thư viện

Cái Spyder ở trong cái Anaconda được cài ở phần 1.

For Windows and Linux users:
In Spyder, go to Tools and Open Anaconda Prompt. Then enter the following commands:

  1. Create a new environment with Anaconda and Python 3.5:
    1
    2
    >conda create -n tensorflow python=3.5 anaconda 
    >
  1. Activate the environment:
    1
    2
    >activate tensorflow
    >
  1. After this you can install Theano, TensorFlow and Keras:
    1
    2
    3
    4
    5
    >conda install theano
    >conda install mingw libpython
    >pip install tensorflow
    >pip install keras
    >
  1. Update the packages:
    1
    2
    >conda update --all
    >
  1. Run Spyder:
    1
    2
    >spyder
    >

To install TensorFlow on your GPU (optional):

1
2
>pip install tensorflow-gpu
>

Cái đoạn hướng dẫn cài đặt này khá là … vớ vẩn. Cài các thư viện python rồi code bằng gì chả được. Một câu như dưới này là xong.
pip install numpy matplotlib pandas theano tensorflow keras

Tải cấu trúc folder các dạng mạng nơ-ron từ đường dẫn này

Tải code mẫu hôm nay ở đường dẫn này

Giải thích file mẫu ann.py

Dựng mạng nơ-ron

Khai báo thư viện

1
2
3
4
# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

numpy, matplotlib,pandas là 3 thư viện được sử dụng rất phổ biến trong Học máy.

  • numpy để làm việc với mảng.
  • matplotlib để vẽ biểu đồ.
  • pandas để làm việc với file.
    import numpy as np nghĩa là dùng thư viện numpy với tên viết tắt là np (gõ cho ngắn).

Đọc dữ liệu

1
2
3
4
#Importing the dataset
dataset = pd.read_csv('Churn_Modelling.csv')
X = dataset.iloc[:, 3:13].values
y = dataset.iloc[:, 13].values

dataset = pd.read_csv('Churn_Modelling.csv')dùng hàm read_csv() để đọc file Churn_Modelling.csv ở cùng thư mục hiện tại. Nếu ở thư mục khác thì ghi cả đường dẫn vào. Ví dụ: /123/abc/Trump.csv. Ngoài read_csv() ra, còn nhiều hàm khác nữa, dùng rất tiện lợi như read_json(), read_excel(), read_html(), … Xem thêm tại đây. Dữ liệu nhận được ở dạng DataFrame.

X = dataset.iloc[:, 3:13].values lấy dữ liệu theo toạ độ. Dữ liệu hiện tại dạng bảng có 2 chiều: tên cột và số thứ tự, nên truyền 2 tọa độ dòng đầu:dòng cuối,cột đầu:cột cuối. Như trên [:,3:13]là lấy từ dòng đầu tiên (vì ko có tọa độ dòng đầu ) đến dòng cuối cùng (vì ko có tọa độ dòng cuối) và từ cột 3 đến cột 13. Dữ liệu nhận được vẫn ở dạng DataFrame. Để chuyển thành mảng 2 chiều numpy.ndarray dùng .values. Hàng cột đếm từ 0

Tiền xử lí dữ liệu

1
2
3
4
5
6
7
8
9
# Encoding categorical data
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder_X_1 = LabelEncoder()
X[:, 1] = labelencoder_X_1.fit_transform(X[:, 1])
labelencoder_X_2 = LabelEncoder()
X[:, 2] = labelencoder_X_2.fit_transform(X[:, 2])
onehotencoder = OneHotEncoder(categorical_features = [1])
X = onehotencoder.fit_transform(X).toarray()
X = X[:, 1:]

X[:, 1] = labelencoder_X_1.fit_transform(X[:, 1])sẽ chuyển cột Quốc gia từ kí tự thành dạng số, ở đây là 0 ,1 và 2 (vì có 3 nước).

X[:, 2] = labelencoder_X_2.fit_transform(X[:, 2]) tương tự với giới tính: 0 và 1.

onehotencoder = OneHotEncoder(categorical_features = [1]) tạo OneHotEncoder theo cột 1 (tạm dịch là “bộ xử lí 1 nóng” cho dễ hình dung). OneHotEncoder để tạo OneHotVector. “OneHot” là gì? One là một. Quá dễ hiểu, ok? Hot là nóng. Nếu coi lạnh là số không thì nóng sẽ là số một. Lại chả thế :p. Vậy OneHot là chỉ có 1 số 1, còn lại là 0 hết. Hay nói cách khác là vector đơn vị. Ví dụ, hệ tọa độ 3 chiều (x,y,z) có vector đơn vị là (1,0,0), (0,1,0), (0,0,1). Cột 1 chứa 3 nước, chuyển thành vector đơn vị thì cho mỗi nước thành 1 trục của hệ tọa độ (x,y,z) là xong. Vậy 120 nước thành vector đơn vị thì dùng hệ tọa độ 120 trục. (Máy nó làm chứ có phải người làm đâu, sao phải xoắn.)
Tại sao phải chuyển các nước thành OneHotVector? Vì ở dạng số như ban đầu:0, 1, … thì các nước sẽ có quan hệ đaị số (cộng trừ nhân chia) với nhau. 1+2=3 thì Anh+Pháp=Đức à? Máy tính sẽ nhìn các số dưới dạng đó. Khi chuyển thành vector, Anh(1,0,0) thì là Anh thì không phải Pháp, không phải Đức.

X = onehotencoder.fit_transform(X).toarray() để tạo xử lí cái cột Quốc gia đó.

X = X[:, 1:] để bỏ cột 0, vì không dùng :))

Phân chia dữ liệu

1
2
3
# Splitting the dataset into the Training set and Test set
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

Chia dữ liệu thành 2 phần, phần để kiểm tra là 20%, phần để huấn luyện là 80%, có trộn ngẫu nhiên trước khi chia. Random_state =0 là khởi tạo với giá trị ngẫu nhiên với tham số bằng 0, không ngẫu nhiên thì bỏ qua tham số này: train_test_split(X, y, test_size = 0.2)

Chuẩn hóa dữ liệu

1
2
3
4
5
# Feature Scaling
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)

sc = StandardScaler() tạo 1 bộ xử lí chuẩn hóa.
Chuẩn hóa là gì? Chuẩn hóa là đưa dữ liệu về dạng phân bố chuẩn. Giá trị trung bình =0, phương sai=1. Cách tính giá trị trung bình, phương sai có thể ôn lại tại đây. Các loại chuẩn hóa có thể đọc thêm tại đây.
Tại sao lại phải chuẩn hóa? Đọc phần 2 sẽ thấy các hàm kích hoạt có giá trị đầu ra từ -1 đến 1. Ví dụ, nơ-ron dùng hàm ReLU (cho nó dễ ^^ ) : y=max(x,0) Nơ-ron này chỉ có 1 đầu vào x nên công thức của cả nơ-ron là Y= max(r*X,0). Bài toán là phân 2 nhóm lớn hơn hoặc bằng và nhỏ hơn giá trị trung bình là 5. Có nghĩa là X>=5 thì Y>0. Thế thì sẽ không tìm được r để r*X<0 .Sau khi chuẩn hóa, giá trị trung bình bằng 0, quá ngon rồi còn gì.
X_train = sc.fit_transform(X_train) tính và xử lí dữ liệu ở tập huấn luyện.
X_test = sc.transform(X_test)xử lí dữ liệu ở tập kiểm tra. Không tính lại.

Tạo mạng nơ-ron

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Importing the Keras libraries and packages
import keras
from keras.models import Sequential
from keras.layers import Dense

# Initialising the ANN
classifier = Sequential()

# Adding the input layer and the first hidden layer
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))

# Adding the second hidden layer
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))

# Adding the output layer
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))

# Compiling the ANN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])

# Fitting the ANN to the Training set
classifier.fit(X_train, y_train, batch_size = 10, epochs = 100)

classifier = Sequential()tạo ra 1 cái khung chứa các lớp nơ-ron.

classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))thêm 1 lớp mạng vào khung. Lớp này gồm 6 nơ-ron, hàm kích hoạt là ReLU, vì lớp ẩn đầu tiên nên có lớp mạng đầu vào là 11. X có 11 cột. Xem các activation tại đây.
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy']) dùng optimizer Adam, xem các optimizer tại đây, xem các hàm loss tại đây., hàm metrics tại đây.

classifier.fit(X_train, y_train, batch_size = 10, epochs = 100) huấn luyện mạng. Luyện dữ liệu 100 lần, kích thước gói là 10, sau 10 dòng dũ liệu cập nhật trọng số 1 lần.

Kiểm tra kết quả

1
2
3
4
5
6
7
8
9
10
# Part 3 - Making predictions and evaluating the model

# Predicting the Test set results
y_pred = classifier.predict(X_test)
y_pred = (y_pred > 0.5)

# Making the Confusion Matrix
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, y_pred)
print(cm)

Confusion matrix xem tại đây

Actual class Actual class
Exited No exited
Predicted class Exited 1508 True Positives 87 False Positives
Predicted class No exited 195 False Negatives 210 True Negatives

Cân bằng giữa thiên vị và biến đổi (Bias–variance tradeoff)

Để hiểu rõ ràng, thiên vị (bias) và biến đổi (variance) là gì, mình đã tìm được 1 bài viết cực kì dễ hiểu.
Theo từ điển:

Bias : Prejudice in favor of or against one thing, person, or group compared with another, usually in a way considered to be unfair.
Variance: The state or fact of disagreeing or quarreling.

Không cần hiểu tiếng anh. Mà có hiểu tiếng anh cũng chả hiểu nó nghĩa là gì. Ví dụ sau đây sẽ làm rõ cho 2 khái niệm trên.

Giả sử bạn có 2 nhà dự báo thời tiết, Mr.Bias và Mr.Variance. Mr.Bias rất thích mưa, còn Mr.Variance là 1 tên mọt sách.

Chúng ta sẽ nói về các điều kiện của mưa. Mưa chỉ xảy ra khi có 1 chút ẩm ướt, và không xảy ra khi trời nóng, trời gió, hoặc trời băng tuyết.

Bạn hỏi Mr.Bias (anh ấy quá thiên vị cho mưa)
Tôi: Hôm nay nóng quá, có mưa không nhỉ?
Mr.Bias: Mưa chứ.

Tôi: Hôm nay trời hơi gió, có mưa không ?
Mr.Bias: Có thể sẽ không mưa

Tôi: Hôm nay toàn băng tuyết, có mưa không ông?
Mr.Bias: Dĩ nhiên là mưa rồi.

Tôi: Hôm nay hơi ẩm ướt, chắc mưa nhỉ?
Mr.Bias: Chắc chắn

Có thể thấy, Mr.Bias quá thiên vị cho trời mưa. Anh ấy sai trong hầu hết trường hợp. Cái này gọi là under fitting (“dưới mức khớp”-tạm dịch thế-).
hinh1
Hình minh họa under fitting

Giờ hỏi sang Mr.Variance (người mọt sách, nhớ tất cả dữ liệu đã học)
Tôi: Hôm nay nóng quá, có mưa không nhỉ?
Mr.Variance: Không

Tôi: Hôm nay trời hơi gió, có mưa không ?
Mr.Variance: Không

Tôi: Hôm nay toàn băng tuyết, có mưa không ông?
Mr.Variance: Không

Tôi: Hôm nay hơi ẩm ướt, chắc mưa nhỉ?
Mr.Variance: Chắc chắn

Anh ấy trả lời chính xác những gì đã học. Nhưng anh là mọt sách, anh không biết gì ngoài những cái có trong sách.

Tôi: Hôm nay tôi ngồi trên ghế, thấy mây đem rất nhiều, trời có thể mưa ko?
Mr.Variance: Cái này tôi chưa gặp bao giờ, chắc là không mưa.
Cái này gọi là over fitting (“quá khớp”-tạm dịch-) và thiếu tính tổng quát.
hinh2
Hình minh họa over fitting

Vậy cần đảm bảo cân bằng giữa thiên vị (tổng quát hơn) và biến đổi (chính xác hơn).
hinh3

Biểu đồ cân bằng giữa 2 cái có dạng như sau:
hinh4

Cải thiện mạng nơ-ron

Sử dụng dropout

Dropout là bỏ qua 1 số nơ-ron khi luyện mạng nơ-ron với dữ liệu. Cấu trúc mạng nơ-ron bị thay đổi nên sẽ làm giảm khả năng over fitting.

Dùng GridSearchCV để tìm mô hình tốt nhất.

Luyện mạng nơ-ron nhiều lần với thông số khác nhau rồi chọn cái tốt nhất.

Dùng K-fold cross-validation

Chia dũ liệu làm k phần. Luyện tập cho mạng với k-1 phần, 1 phần còn lại dùng để kiểm tra mạng nơ-ron. Dữ liệu kiểm tra ko dùng để luyện nên giảm over fitting. Cái cv = 10 ở dưới nghĩa là cross-validation với k=10.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Improving the ANN
# Dropout Regularization to reduce overfitting if needed

# Tuning the ANN
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import GridSearchCV
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
def build_classifier(optimizer):
classifier = Sequential()
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu', input_dim = 11))
classifier.add(Dropout(0.1))
classifier.add(Dense(units = 6, kernel_initializer = 'uniform', activation = 'relu'))
classifier.add(Dropout(0.1))
classifier.add(Dense(units = 1, kernel_initializer = 'uniform', activation = 'sigmoid'))
classifier.compile(optimizer = optimizer, loss = 'binary_crossentropy', metrics = ['accuracy'])
return classifier
classifier = KerasClassifier(build_fn = build_classifier)
parameters = {'batch_size': [25, 32],
'epochs': [100, 500],
'optimizer': ['adam', 'rmsprop']}
grid_search = GridSearchCV(estimator = classifier,
param_grid = parameters,
scoring = 'accuracy',
cv = 10)
grid_search = grid_search.fit(X_train, y_train)
best_parameters = grid_search.best_params_
best_accuracy = grid_search.best_score_