Upload 3 files
Browse filesUpdate 3 Project Files: Conventional_Neural_Network , Single_Layer_Perceptron , Multi_Layer_Perceptron
- Multi_Layer_Perceptron.py +129 -0
- Single_Layer_Perceptron.py +141 -0
- conventional_neural_network.py +103 -0
Multi_Layer_Perceptron.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
# --- 1. Dữ liệu XOR gate ---
|
| 4 |
+
X = np.array([[0, 0],
|
| 5 |
+
[0, 1],
|
| 6 |
+
[1, 0],
|
| 7 |
+
[1, 1]])
|
| 8 |
+
y = np.array([[0], [1], [1], [0]]) # output XOR
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
# --- 2. Hàm sigmoid & derivative ---
|
| 12 |
+
def sigmoid(x):
|
| 13 |
+
return 1 / (1 + np.exp(-x))
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def sigmoid_derivative(x):
|
| 17 |
+
return x * (1 - x)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
# --- 3. Khởi tạo weights & bias ---
|
| 21 |
+
np.random.seed(42)
|
| 22 |
+
input_dim = 2
|
| 23 |
+
hidden_dim = 2 # thử đổi thành 3, 4, 5...
|
| 24 |
+
'''
|
| 25 |
+
Ảnh hưởng:
|
| 26 |
+
2 neurons: học XOR ổn
|
| 27 |
+
1 neuron: không học được
|
| 28 |
+
2 neurons: học nhanh hơn, loss giảm mạnh 👉 Đây là chỗ dễ thấy sự thay đổi nhất.
|
| 29 |
+
'''
|
| 30 |
+
output_dim = 1
|
| 31 |
+
lr = 0.5 # thử 0.1, 1.0, 2.0
|
| 32 |
+
'''
|
| 33 |
+
Ảnh hưởng:
|
| 34 |
+
lr nhỏ → học chậm, mượt
|
| 35 |
+
lr lớn → lúc học rất nhanh, lúc bị “nhảy loạn”, dễ diverge 👉 Thay đổi learning rate luôn thấy kết quả khác.
|
| 36 |
+
'''
|
| 37 |
+
epochs = 10000 # thử 3000, 50000
|
| 38 |
+
'''
|
| 39 |
+
Ảnh hưởng:
|
| 40 |
+
ít epoch → chưa học hết, dự đoán sai
|
| 41 |
+
nhiều epoch → XOR học hoàn hảo hơn
|
| 42 |
+
'''
|
| 43 |
+
|
| 44 |
+
# weights: input -> hidden
|
| 45 |
+
w1 = np.random.randn(input_dim, hidden_dim) # Có thể thử nhân thêm weight với 0.1 hoặc 0.001
|
| 46 |
+
'''
|
| 47 |
+
Hiệu ứng: khi nhân với 0.1
|
| 48 |
+
Train rất mượt
|
| 49 |
+
Loss giảm đều
|
| 50 |
+
Tốc độ học nhanh
|
| 51 |
+
Đây là “sweet spot”.
|
| 52 |
+
|
| 53 |
+
Hiệu ứng: khi nhân với 0.001
|
| 54 |
+
Activation gần 0 → mô hình học chậm
|
| 55 |
+
Loss giảm nhưng rất từ từ
|
| 56 |
+
'''
|
| 57 |
+
b1 = np.zeros((1, hidden_dim))
|
| 58 |
+
|
| 59 |
+
# weights: hidden -> output
|
| 60 |
+
w2 = np.random.randn(hidden_dim, output_dim)
|
| 61 |
+
b2 = np.zeros((1, output_dim)) # Có thể thử Bias random: b1 = np.random.randn((1, output_dim))
|
| 62 |
+
'''
|
| 63 |
+
Hiệu ứng CÓ THỂ THẤY RÕ:
|
| 64 |
+
Decision boundary bắt đầu lệch → học XOR nhanh hơn
|
| 65 |
+
Loss giảm nhanh từ những bước đầu tiên
|
| 66 |
+
Output có thể ra đúng từ rất sớm (epoch 10–20)
|
| 67 |
+
'''
|
| 68 |
+
|
| 69 |
+
# --- 4. Huấn luyện bằng Backpropagation ---
|
| 70 |
+
for epoch in range(epochs):
|
| 71 |
+
# Forward pass
|
| 72 |
+
z1 = np.dot(X, w1) + b1
|
| 73 |
+
h = sigmoid(z1)
|
| 74 |
+
z2 = np.dot(h, w2) + b2
|
| 75 |
+
y_pred = sigmoid(z2)
|
| 76 |
+
|
| 77 |
+
# Tính lỗi
|
| 78 |
+
error = y - y_pred
|
| 79 |
+
|
| 80 |
+
# Backward pass
|
| 81 |
+
d_y_pred = error * sigmoid_derivative(y_pred)
|
| 82 |
+
d_h = d_y_pred.dot(w2.T) * sigmoid_derivative(h)
|
| 83 |
+
|
| 84 |
+
# Cập nhật weights & bias
|
| 85 |
+
w2 += h.T.dot(d_y_pred) * lr
|
| 86 |
+
b2 += np.sum(d_y_pred, axis=0, keepdims=True) * lr
|
| 87 |
+
w1 += X.T.dot(d_h) * lr
|
| 88 |
+
b1 += np.sum(d_h, axis=0, keepdims=True) * lr
|
| 89 |
+
|
| 90 |
+
# --- 5. Test MLP ---
|
| 91 |
+
print("Testing trained MLP:")
|
| 92 |
+
z1 = np.dot(X, w1) + b1
|
| 93 |
+
h = sigmoid(z1)
|
| 94 |
+
z2 = np.dot(h, w2) + b2
|
| 95 |
+
y_pred = sigmoid(z2)
|
| 96 |
+
print(np.round(y_pred))
|
| 97 |
+
|
| 98 |
+
'''
|
| 99 |
+
✅ Tóm tắt học thuật:
|
| 100 |
+
| Tiêu chí | Single Layer Perceptron (SLP) | Multi-Layer Perceptron (MLP) |
|
| 101 |
+
| ------------------------- | ------------------------------------- | ---------------------------------------------------------------------- |
|
| 102 |
+
| **Số lớp** | 1 lớp (input → output) | Nhiều lớp (input → hidden → output) |
|
| 103 |
+
| **Hàm học** | Tuyến tính | Phi tuyến tính (nhờ lớp ẩn và activation) |
|
| 104 |
+
| **Hàm kích hoạt** | Step function | Sigmoid, ReLU, Tanh hoặc các hàm phi tuyến khác |
|
| 105 |
+
| **Khả năng học XOR** | Không | Có |
|
| 106 |
+
| **Thuật toán huấn luyện** | Perceptron learning rule | Backpropagation + gradient descent |
|
| 107 |
+
| **Ứng dụng** | Phân loại tuyến tính cơ bản (AND, OR) | Classification, regression, nhận dạng hình ảnh, NLP, dữ liệu phi tuyến |
|
| 108 |
+
| **Ưu điểm** | Đơn giản, dễ hiểu | Học được phi tuyến, khả năng biểu diễn cao |
|
| 109 |
+
| **Hạn chế** | Chỉ học tuyến tính | Dễ overfitting, cần tuning hyperparameters, tốn tài nguyên |
|
| 110 |
+
'''
|
| 111 |
+
|
| 112 |
+
'''
|
| 113 |
+
Epoch không phải là weight hay bias, nhưng về thuật toán học, nó được coi là hyperparameter.
|
| 114 |
+
Hyperparameter = tham số do người đặt trước khi huấn luyện (khác với parameter là giá trị học được từ dữ liệu).
|
| 115 |
+
Các hyperparameters phổ biến:
|
| 116 |
+
Learning rate (𝜂)
|
| 117 |
+
Batch size
|
| 118 |
+
Số epoch
|
| 119 |
+
Số lớp ẩn, số neuron
|
| 120 |
+
Hàm kích hoạt
|
| 121 |
+
Như vậy: Epoch → hyperparameter, ảnh hưởng trực tiếp đến quá trình huấn luyện.
|
| 122 |
+
3. Epoch ảnh hưởng đến quá trình học như thế nào
|
| 123 |
+
Quá ít epoch → underfitting, model chưa học đủ.
|
| 124 |
+
Quá nhiều epoch → overfitting, model nhớ dữ liệu training quá mức, generalization kém.
|
| 125 |
+
Kết hợp với learning rate → số epoch quyết định model có hội tụ hay không.
|
| 126 |
+
4. Kết luận
|
| 127 |
+
Epoch là hyperparameter, nhưng nó không phải parameter học được từ dữ liệu.
|
| 128 |
+
Chọn epoch phù hợp = một phần quan trọng trong tuning hyperparameters để đạt hiệu quả tối ưu.
|
| 129 |
+
'''
|
Single_Layer_Perceptron.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
# --- 1. Dữ liệu AND gate ---
|
| 4 |
+
X = np.array([[0,0],
|
| 5 |
+
[0,1],
|
| 6 |
+
[1,0],
|
| 7 |
+
[1,1]])
|
| 8 |
+
y = np.array([0, 0, 0, 1]) # output AND
|
| 9 |
+
|
| 10 |
+
# --- 2. Hàm kích hoạt step function ---
|
| 11 |
+
def step(x):
|
| 12 |
+
return 1 if x > 0 else 0
|
| 13 |
+
|
| 14 |
+
# --- 3. Khởi tạo weights và bias ---
|
| 15 |
+
np.random.seed(42)
|
| 16 |
+
weights = np.random.randn(2)
|
| 17 |
+
bias = np.random.randn()
|
| 18 |
+
learning_rate = 0.1
|
| 19 |
+
epochs = 10
|
| 20 |
+
|
| 21 |
+
# --- 4. Huấn luyện Perceptron ---
|
| 22 |
+
for epoch in range(epochs):
|
| 23 |
+
print(f"Epoch {epoch+1}")
|
| 24 |
+
for xi, yi in zip(X, y):
|
| 25 |
+
z = np.dot(xi, weights) + bias
|
| 26 |
+
y_pred = step(z)
|
| 27 |
+
error = yi - y_pred
|
| 28 |
+
weights += learning_rate * error * xi
|
| 29 |
+
bias += learning_rate * error
|
| 30 |
+
print(f"Input: {xi}, Pred: {y_pred}, Error: {error}, Weights: {weights}, Bias: {bias}")
|
| 31 |
+
print("-"*50)
|
| 32 |
+
|
| 33 |
+
# --- 5. Test Perceptron ---
|
| 34 |
+
print("Testing trained perceptron (AND):")
|
| 35 |
+
for xi in X:
|
| 36 |
+
z = np.dot(xi, weights) + bias
|
| 37 |
+
y_pred = step(z)
|
| 38 |
+
print(f"Input: {xi}, Predicted: {y_pred}")
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# ===============================================================
|
| 42 |
+
# ===============================================================
|
| 43 |
+
# THÊM CHO OR GATE
|
| 44 |
+
# ===============================================================
|
| 45 |
+
# ===============================================================
|
| 46 |
+
|
| 47 |
+
print("\n\n===== OR GATE =====")
|
| 48 |
+
|
| 49 |
+
# Dữ liệu OR gate
|
| 50 |
+
X_or = np.array([[0,0],
|
| 51 |
+
[0,1],
|
| 52 |
+
[1,0],
|
| 53 |
+
[1,1]])
|
| 54 |
+
y_or = np.array([0, 1, 1, 1]) # output OR
|
| 55 |
+
|
| 56 |
+
# Khởi tạo mới weights, bias
|
| 57 |
+
weights = np.random.randn(2)
|
| 58 |
+
bias = np.random.randn()
|
| 59 |
+
|
| 60 |
+
# Huấn luyện OR
|
| 61 |
+
for epoch in range(epochs):
|
| 62 |
+
for xi, yi in zip(X_or, y_or):
|
| 63 |
+
z = np.dot(xi, weights) + bias
|
| 64 |
+
y_pred = step(z)
|
| 65 |
+
error = yi - y_pred
|
| 66 |
+
weights += learning_rate * error * xi
|
| 67 |
+
bias += learning_rate * error
|
| 68 |
+
|
| 69 |
+
# Test OR
|
| 70 |
+
print("Testing trained perceptron (OR):")
|
| 71 |
+
for xi in X_or:
|
| 72 |
+
z = np.dot(xi, weights) + bias
|
| 73 |
+
y_pred = step(z)
|
| 74 |
+
print(f"Input: {xi}, Predicted: {y_pred}")
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
# ===============================================================
|
| 78 |
+
# ===============================================================
|
| 79 |
+
# THÊM CHO NOT GATE
|
| 80 |
+
# ===============================================================
|
| 81 |
+
# ===============================================================
|
| 82 |
+
|
| 83 |
+
print("\n\n===== NOT GATE =====")
|
| 84 |
+
|
| 85 |
+
# Dữ liệu NOT gate (1 input → output đảo)
|
| 86 |
+
X_not = np.array([[0],
|
| 87 |
+
[1]])
|
| 88 |
+
y_not = np.array([1, 0]) # NOT
|
| 89 |
+
|
| 90 |
+
# Khởi tạo weight, bias (1 chiều)
|
| 91 |
+
weight = np.random.randn(1)
|
| 92 |
+
bias = np.random.randn()
|
| 93 |
+
|
| 94 |
+
# Huấn luyện NOT
|
| 95 |
+
for epoch in range(epochs):
|
| 96 |
+
for xi, yi in zip(X_not, y_not):
|
| 97 |
+
z = np.dot(xi, weight) + bias
|
| 98 |
+
y_pred = step(z)
|
| 99 |
+
error = yi - y_pred
|
| 100 |
+
weight += learning_rate * error * xi
|
| 101 |
+
bias += learning_rate * error
|
| 102 |
+
|
| 103 |
+
# Test NOT
|
| 104 |
+
print("Testing trained perceptron (NOT):")
|
| 105 |
+
for xi in X_not:
|
| 106 |
+
z = np.dot(xi, weight) + bias
|
| 107 |
+
y_pred = step(z)
|
| 108 |
+
print(f"Input: {xi}, Predicted: {y_pred}")
|
| 109 |
+
|
| 110 |
+
'''
|
| 111 |
+
✅ Tóm tắt học thuật:
|
| 112 |
+
| Tiêu chí | Single Layer Perceptron (SLP) | Multi-Layer Perceptron (MLP) |
|
| 113 |
+
| ------------------------- | ------------------------------------- | ---------------------------------------------------------------------- |
|
| 114 |
+
| **Số lớp** | 1 lớp (input → output) | Nhiều lớp (input → hidden → output) |
|
| 115 |
+
| **Hàm học** | Tuyến tính | Phi tuyến tính (nhờ lớp ẩn và activation) |
|
| 116 |
+
| **Hàm kích hoạt** | Step function | Sigmoid, ReLU, Tanh hoặc các hàm phi tuyến khác |
|
| 117 |
+
| **Khả năng học XOR** | Không | Có |
|
| 118 |
+
| **Thuật toán huấn luyện** | Perceptron learning rule | Backpropagation + gradient descent |
|
| 119 |
+
| **Ứng dụng** | Phân loại tuyến tính cơ bản (AND, OR, Not) | Classification, regression, nhận dạng hình ảnh, NLP, dữ liệu phi tuyến |
|
| 120 |
+
| **Ưu điểm** | Đơn giản, dễ hiểu | Học được phi tuyến, khả năng biểu diễn cao |
|
| 121 |
+
| **Hạn chế** | Chỉ học tuyến tính | Dễ overfitting, cần tuning hyperparameters, tốn tài nguyên |
|
| 122 |
+
'''
|
| 123 |
+
|
| 124 |
+
'''
|
| 125 |
+
Epoch không phải là weight hay bias, nhưng về thuật toán học, nó được coi là hyperparameter.
|
| 126 |
+
Hyperparameter = tham số do con người đặt trước trước khi huấn luy��n (khác với parameter là giá trị học được từ dữ liệu).
|
| 127 |
+
Các hyperparameters phổ biến:
|
| 128 |
+
Learning rate (𝜂)
|
| 129 |
+
Batch size
|
| 130 |
+
Số epoch
|
| 131 |
+
Số lớp ẩn, số neuron
|
| 132 |
+
Hàm kích hoạt
|
| 133 |
+
Như vậy: Epoch → hyperparameter, ảnh hưởng trực tiếp đến quá trình huấn luyện.
|
| 134 |
+
3. Epoch ảnh hưởng đến quá trình học như thế nào
|
| 135 |
+
Quá ít epoch → underfitting, model chưa học đủ.
|
| 136 |
+
Quá nhiều epoch → overfitting, model nhớ dữ liệu training quá mức, generalization kém.
|
| 137 |
+
Kết hợp với learning rate → số epoch quyết định model có hội tụ hay không.
|
| 138 |
+
4. Kết luận
|
| 139 |
+
Epoch là hyperparameter, nhưng nó không phải parameter học được từ dữ liệu.
|
| 140 |
+
Chọn epoch phù hợp = một phần quan trọng trong tuning hyperparameters để đạt hiệu quả tối ưu.
|
| 141 |
+
'''
|
conventional_neural_network.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Contain the implementation of a simple neural network
|
| 3 |
+
Author: Son Phat Tran
|
| 4 |
+
"""
|
| 5 |
+
import numpy as np
|
| 6 |
+
from utils import sigmoid, sigmoid_derivative
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class ConventionalNeuralNetwork:
|
| 10 |
+
def __init__(self, input_size, hidden_size):
|
| 11 |
+
"""
|
| 12 |
+
Create a two-layer neural network
|
| 13 |
+
NOTE:
|
| 14 |
+
- The network does not include any bias b
|
| 15 |
+
- The network uses the sigmoid activation function
|
| 16 |
+
:param input_size: size of the input vector
|
| 17 |
+
:param hidden_size: size of the hidden layer
|
| 18 |
+
:return:
|
| 19 |
+
"""
|
| 20 |
+
# Cache the size
|
| 21 |
+
self.input_size = input_size
|
| 22 |
+
self.hidden_size = hidden_size
|
| 23 |
+
|
| 24 |
+
# Create the layer
|
| 25 |
+
self.W1 = np.random.normal(size=(self.input_size, self.hidden_size))
|
| 26 |
+
self.W2 = np.random.normal(size=(self.hidden_size, 1))
|
| 27 |
+
|
| 28 |
+
# Create a cache
|
| 29 |
+
self.cache = {}
|
| 30 |
+
|
| 31 |
+
def forward(self, x_train, y_train):
|
| 32 |
+
"""
|
| 33 |
+
Perform the forward pass of the neural network
|
| 34 |
+
:param x_train: the training input of the neural network
|
| 35 |
+
:param y_train: the training
|
| 36 |
+
:return: the output of the neural network
|
| 37 |
+
"""
|
| 38 |
+
# Calculate the output of the first layer
|
| 39 |
+
a1 = x_train @ self.W1
|
| 40 |
+
z1 = sigmoid(a1)
|
| 41 |
+
|
| 42 |
+
# Calculate the output of the second layer
|
| 43 |
+
a2 = z1 @ self.W2
|
| 44 |
+
|
| 45 |
+
# Cache the values
|
| 46 |
+
self.cache = {
|
| 47 |
+
"x_train": x_train,
|
| 48 |
+
"y_train": y_train,
|
| 49 |
+
"a1": a1,
|
| 50 |
+
"z1": z1,
|
| 51 |
+
"a2": a2
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
# Calculate the error function
|
| 55 |
+
score = (1 / 2) * np.sum((y_train.reshape(-1) - a2.reshape(-1)) ** 2) / y_train.shape[0]
|
| 56 |
+
return a2, score
|
| 57 |
+
|
| 58 |
+
def predict(self, x_test):
|
| 59 |
+
"""
|
| 60 |
+
Perform the prediction
|
| 61 |
+
:param x_test: the test points
|
| 62 |
+
:return: the output prediction
|
| 63 |
+
"""
|
| 64 |
+
# Calculate the output of the first layer
|
| 65 |
+
a1 = x_test @ self.W1
|
| 66 |
+
z1 = sigmoid(a1)
|
| 67 |
+
|
| 68 |
+
# Calculate the output of the second layer
|
| 69 |
+
a2 = z1 @ self.W2
|
| 70 |
+
return a2
|
| 71 |
+
|
| 72 |
+
def backward(self, learning_rate):
|
| 73 |
+
"""
|
| 74 |
+
Perform back-propagation
|
| 75 |
+
:param learning_rate: Learning rate of back-propagation
|
| 76 |
+
:return: None
|
| 77 |
+
"""
|
| 78 |
+
# Get cached values
|
| 79 |
+
x_train, y_train, a1, z1, a2 = self.cache["x_train"], self.cache["y_train"], \
|
| 80 |
+
self.cache["a1"], self.cache["z1"], self.cache["a2"]
|
| 81 |
+
|
| 82 |
+
# Calculate the gradient w.r.t a2
|
| 83 |
+
d_a2 = (a2 - y_train.reshape(-1, 1)).reshape(-1, 1)
|
| 84 |
+
|
| 85 |
+
# Calculate the gradient w.r.t z1
|
| 86 |
+
d_z1 = d_a2 @ self.W2.T
|
| 87 |
+
|
| 88 |
+
# Calculate the gradient w.r.t W2
|
| 89 |
+
d_W2 = z1.T @ d_a2
|
| 90 |
+
|
| 91 |
+
# Calculate the gradient w.r.t a1
|
| 92 |
+
d_a1 = d_z1 * sigmoid_derivative(a1)
|
| 93 |
+
|
| 94 |
+
# Calculate the gradient w.r.t W1
|
| 95 |
+
d_W1 = x_train.T @ d_a1
|
| 96 |
+
|
| 97 |
+
# Perform back-prop
|
| 98 |
+
self.W1 -= learning_rate * d_W1
|
| 99 |
+
self.W2 -= learning_rate * d_W2
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
|