Chỉ có một sự khác biệt nhỏ giữa độ dốc gốc và độ dốc dốc ngẫu nhiên. Độ dốc độ dốc tính toán độ dốc dựa trên hàm mất mát được tính trên tất cả các trường hợp đào tạo, trong khi độ dốc độ dốc ngẫu nhiên tính toán độ dốc dựa trên tổn thất theo lô. Cả hai kỹ thuật này được sử dụng để tìm các tham số tối ưu cho một mô hình.
Hãy để chúng tôi thử triển khai SGD trên bộ dữ liệu 2D này.
Thuật toán
Bộ dữ liệu có 2 tính năng, tuy nhiên chúng tôi sẽ muốn thêm một thuật ngữ thiên vị để chúng tôi nối một cột của các tính năng vào cuối ma trận dữ liệu.
shape = x.shape
x = np.insert(x, 0, 1, axis=1)
Sau đó, chúng tôi khởi tạo trọng lượng của chúng tôi, có nhiều chiến lược để làm điều này. Để đơn giản, tôi sẽ đặt tất cả chúng thành 1 tuy nhiên việc đặt ngẫu nhiên các trọng số ban đầu có lẽ tốt hơn để có thể sử dụng nhiều lần khởi động lại.
w = np.ones((shape[1]+1,))
Dòng ban đầu của chúng tôi trông như thế này
Bây giờ chúng tôi sẽ lặp lại cập nhật các trọng số của mô hình nếu nó phân loại nhầm một ví dụ.
for ix, i in enumerate(x):
pred = np.dot(i,w)
if pred > 0: pred = 1
elif pred < 0: pred = -1
if pred != y[ix]:
w = w - learning_rate * pred * i
Dòng này là cập nhật trọng lượng w = w - learning_rate * pred * i
.
Chúng ta có thể thấy rằng làm quá trình này liên tục sẽ dẫn đến sự hội tụ.
Sau 10 kỷ nguyên
Sau 20 kỷ nguyên
Sau 50 kỷ nguyên
Sau 100 kỷ nguyên
Và cuối cùng,
Mật mã
Bộ dữ liệu cho mã này có thể được tìm thấy ở đây .
Hàm sẽ huấn luyện các trọng số trong ma trận tính năng x và các mục tiêu y. Nó trả về trọng lượng được đào tạow và một danh sách các trọng lượng lịch sử gặp phải trong suốt quá trình đào tạo.
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
def get_weights(x, y, verbose = 0):
shape = x.shape
x = np.insert(x, 0, 1, axis=1)
w = np.ones((shape[1]+1,))
weights = []
learning_rate = 10
iteration = 0
loss = None
while iteration <= 1000 and loss != 0:
for ix, i in enumerate(x):
pred = np.dot(i,w)
if pred > 0: pred = 1
elif pred < 0: pred = -1
if pred != y[ix]:
w = w - learning_rate * pred * i
weights.append(w)
if verbose == 1:
print('X_i = ', i, ' y = ', y[ix])
print('Pred: ', pred )
print('Weights', w)
print('------------------------------------------')
loss = np.dot(x, w)
loss[loss<0] = -1
loss[loss>0] = 1
loss = np.sum(loss - y )
if verbose == 1:
print('------------------------------------------')
print(np.sum(loss - y ))
print('------------------------------------------')
if iteration%10 == 0: learning_rate = learning_rate / 2
iteration += 1
print('Weights: ', w)
print('Loss: ', loss)
return w, weights
Chúng tôi sẽ áp dụng SGD này cho dữ liệu của chúng tôi trong perceptron.csv .
df = np.loadtxt("perceptron.csv", delimiter = ',')
x = df[:,0:-1]
y = df[:,-1]
print('Dataset')
print(df, '\n')
w, all_weights = get_weights(x, y)
x = np.insert(x, 0, 1, axis=1)
pred = np.dot(x, w)
pred[pred > 0] = 1
pred[pred < 0] = -1
print('Predictions', pred)
Hãy vẽ ranh giới quyết định
x1 = np.linspace(np.amin(x[:,1]),np.amax(x[:,2]),2)
x2 = np.zeros((2,))
for ix, i in enumerate(x1):
x2[ix] = (-w[0] - w[1]*i) / w[2]
plt.scatter(x[y>0][:,1], x[y>0][:,2], marker = 'x')
plt.scatter(x[y<0][:,1], x[y<0][:,2], marker = 'o')
plt.plot(x1,x2)
plt.title('Perceptron Seperator', fontsize=20)
plt.xlabel('Feature 1 ($x_1$)', fontsize=16)
plt.ylabel('Feature 2 ($x_2$)', fontsize=16)
plt.show()
Để xem quy trình đào tạo, bạn có thể in các trọng số khi chúng thay đổi thông qua các kỷ nguyên.
for ix, w in enumerate(all_weights):
if ix % 10 == 0:
print('Weights:', w)
x1 = np.linspace(np.amin(x[:,1]),np.amax(x[:,2]),2)
x2 = np.zeros((2,))
for ix, i in enumerate(x1):
x2[ix] = (-w[0] - w[1]*i) / w[2]
print('$0 = ' + str(-w[0]) + ' - ' + str(w[1]) + 'x_1'+ ' - ' + str(w[2]) + 'x_2$')
plt.scatter(x[y>0][:,1], x[y>0][:,2], marker = 'x')
plt.scatter(x[y<0][:,1], x[y<0][:,2], marker = 'o')
plt.plot(x1,x2)
plt.title('Perceptron Seperator', fontsize=20)
plt.xlabel('Feature 1 ($x_1$)', fontsize=16)
plt.ylabel('Feature 2 ($x_2$)', fontsize=16)
plt.show()