MLX: Apple silicon Machine Learning - 02.Linear Regression
MLX: Linear Regression
MLX๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ Linear Regression ์์ ๋ฅผ ๋๋ ค๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์์์ ํจ์๋ฅผ ๋ง๋ค์ด ๋ฐ์ดํฐ๋ฅผ ํฉ์ฑํ๊ณ , ํด๋น ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด ์ญ์ผ๋ก ๊ทผ์ฌ์น๋ฅผ ๊ตฌํ๋ ์์ ์ ๋๋ค.
์ฐ์ ๊ด๋ จ ๋ชจ๋์ import ํ๊ณ hyperparam์ ์ธํ ํฉ๋๋ค.
import mlx.core as mx
import time
num_features = 100
num_examples = 1_000
test_examples = 100
num_iters = 10_000 # iterations of SGD
lr = 0.01 # learning rate for SGD
๋จธ์ ๋ฌ๋์์ ๋งํ๋ Batch์ ์ ์
- ๋ชจ๋ธ์ ํ์ตํ ๋ ํ iteration๋น(๋ฐ๋ณต 1ํ๋น) ์ฌ์ฉ๋๋ example์ set๋ชจ์์ ๋๋ค.
- ์ฌ๊ธฐ์ iteration์ ์ ํด์ง batch size๋ฅผ ์ด์ฉํ์ฌ ํ์ต(forward - backward)๋ฅผ ๋ฐ๋ณตํ๋ ํ์๋ฅผ ๋งํฉ๋๋ค.
- ํ ๋ฒ์ epoch๋ฅผ ์ํด ์ฌ๋ฌ๋ฒ์ iteration์ด ํ์ํฉ๋๋ค.
- training error์ validation error๊ฐ ๋์ผํ๊ฒ ๊ฐ์ํ๋ค๊ฐ validation error๊ฐ ์ฆ๊ฐํ๊ธฐ ์์ํ๋ ์ง์ ์ ์ epoch๋ฅผ ์ ํํด์ผ ํฉ๋๋ค. (overfitting ๋ฐฉ์ง)
Batch Size์ ์ ์
- Batch ํ๋์ ํฌํจ๋๋ example set์ ๊ฐฏ์์ ๋๋ค.
- Batch / Mini-Batch/ Stochastic ์ธ ๊ฐ์ง๋ก ๋๋ ์ ์์ต๋๋ค.(์๋ ๊ทธ๋ฆผ ์ฐธ๊ณ )
- SGD(Stochastic Gradient Descent)๋ ๋ฐฐ์น ํฌ๊ธฐ๊ฐ 1, Mini-Batch๋ 10 ~ 1,00 ์ฌ์ด์ง๋ง ๋ณดํต 2์ ์ง์์น(32, 64, 128โฆ)์ผ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
Batch๋ณ ํน์ง ๋ฐ ์ฅ๋จ์
Batch
- ์ฌ๋ฌ๊ฐ์ ์ํ๋ค์ด ํ๋ฒ์ ์ํฅ์ ์ฃผ์ด ํฉ์๋ ๋ฐฉํฅ์ผ๋ก smoothํ๊ฒ ์๋ ด๋ฉ๋๋ค.
- ์ํ ๊ฐฏ์๋ฅผ ์ ๋ถ ๊ณ์ฐํด์ผ ํจ์ผ๋ก ์๊ฐ์ด ๋ง์ด ์์๋ฉ๋๋ค.
- ๋ชจ๋ Training data set์ ์ฌ์ฉํฉ๋๋ค.
(SGD)Stochastic Gradient Descent
- ๋ฐ์ดํฐ๋ฅผ ํ ๊ฐ์ฉ ์ถ์ถํด์ ์ฒ๋ฆฌํ๊ณ ์ด๋ฅผ ๋ชจ๋ ๋ฐ์ดํฐ์ ๋ฐ๋ณตํ๋ ๊ฒ์ ๋๋ค.
- ์๋ ด ์๋๋ ๋น ๋ฅด์ง๋ง ์ค์ฐจ์จ์ด ํฝ๋๋ค. (global minimum์ ์ฐพ์ง ๋ชปํ ์ ์์)
- GPU ์ฑ๋ฅ์ ์ ๋๋ก ํ์ฉํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋นํจ์จ์ ์ ๋๋ค. (ํ๋์ฉ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ)
Mini-Batch
- ์ ์ฒด ํ์ต ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์น ์ฌ์ด์ฆ๋ก ๋ฑ๋ถํ์ฌ ๊ฐ ๋ฐฐ์น ์ ์ ์์ฐจ์ ์ผ๋ก ์ํํฉ๋๋ค.
- ๋ฐฐ์น๋ณด๋ค ๋น ๋ฅด๊ณ SGD๋ณด๋ค ๋ฎ์ ์ค์ฐจ์จ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์์์ ์ ํ ํจ์๋ฅผ ๋ง๋ค๊ณ , ์์์ input ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์ด์ค๋๋ค.
mx.random.normal
์ ์ด์ฉํ์ฌ ๋๋คํ๊ฒ ๋ง๋ค์ด์ค๋๋ค.
label ๊ฐ์ ๊ฒฝ์ฐ ๋ง๋ค์ด์ง input๋ฐ์ดํฐ๋ฅผ ํจ์์ ํต๊ณผ์ํค๊ณ , ์์ noise๋ฅผ ๋ถ์ฌํ์ฌ ๋ง๋ค์ด์ค๋๋ค.
# ์์์ ์ ํ ํจ์ True parameters
w_start = mx.random.normal((num_features,))
# Input examples(design matrix)
X = mx.random.normal((num_examples, num_features))
# Noisy labels
eps = 1e-2 * mx.random.normal((num_examples,))
mx.random.normal((num_examples,))
y = X @ w_start + eps
@
๋ NumPy๋ MXNet๊ณผ ๊ฐ์ ๋ฐฐ์ด ๊ณ์ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ํ๋ ฌ ๊ณฑ์ (๋๋ ํ๋ ฌ-๋ฒกํฐ ๊ณฑ์ )์ ๋ํ๋ด๋ ์ฐ์ฐ์์ ๋๋ค.X @ w_start
๋ ํ๋ ฌX
์ ๋ฒกํฐw_start
์ฌ์ด์ ํ๋ ฌ ๊ณฑ์ ์ ์๋ฏธํฉ๋๋ค.
๋ณ๋์ ํ ์คํธ ์ ๋ ๋ง๋ค์ด์ค๋๋ค.
# Test set generation
X_test = mx.random.normal((test_examples, num_features))
y_test = X_test @ w_start
๊ทธ๋ฆฌ๊ณ Loss function๊ณผ Gradient function(mx.grad ์ฌ์ฉ)์ ๋ง๋ค์ด์ค๋๋ค.
# MSE Loss function
def loss_fn(w):
return 0.5 * mx.mean(mx.square(X @ w - y))
# Gradient function
grad_fn = mx.grad(loss_fn)
์ด์ Linear regression์ ์ํ parameter๋ฅผ ์ด๊ธฐํํ๊ณ SGD(Stochastic Gradient Descent) ๋ฐฉ๋ฒ์ ์ด์ฉํด ํ์ตํฉ๋๋ค.
# Initialize random parameter
w = 1e-2 * mx.random.normal((num_features,))
# Test Error(MSE)
pred_test = X_test @ w
test_error = mx.mean(mx.square(y_test - pred_test))
print(f"Initial Test Error(MSE): {test_error.item():.6f}")
Initial Test Error(MSE): 114.406784
# Training by SGD
start = time.time()
for its in range(1,num_iters+1):
grad = grad_fn(w)
w = w - lr * grad
mx.eval(w)
end = time.time()
print(f"Training elapsed time: {end-start} seconds")
print(f"Throughput: {num_iters/(end-start):.3f} iter/s")
Training elapsed time: 0.8959159851074219 seconds Throughput: 11161.761 iter/s
# Test Error(MSE)
pred_test = X_test @ w
test_error = mx.mean(mx.square(y_test - pred_test))
print(f"Final Test Error(MSE): {test_error.item():.6f}")
Final Test Error(MSE): 0.000011
Test Set์ ์ MSE๊ฐ์ด ํฌ๊ฒ ๊ฐ์ํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.(Test Set MSE: 0.00001)
์ถ๊ฐ์ ์ผ๋ก ์ํ์๊ฐ์ ์ฝ 0.8์ด ๊ฑธ๋ฆฐ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.(M3 Macbook pro ๊ธฐ์ค)
CPU ์ฐ์ฐ๊ณผ์ ์ํ์๊ฐ ๋น๊ต
๋ง์ฝ MLX(GPU)๋์ ์ numpy array(CPU)๋ฅผ ์ฌ์ฉํ์ ๋ ๋ฐ์๋๋ ์๋ ์ฐจ์ด๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
import numpy as np
# True parameters
w_star = np.random.normal(size=(num_features,1))
# Input examples(design matrix)
X = np.random.normal(size=(num_examples, num_features))
# Noisy labels
eps = 1e-2 * np.random.normal(size=(num_examples,1))
y = np.matmul(X, w_star) + eps
# Test Set Generation
X_test = np.random.normal(size=(test_examples, num_features))
y_test = np.matmul(X_test, w_star)
def loss_fn(w):
return 0.5 * np.mean(np.square(np.matmul(X, w) - y))
def grad_fn(w):
return np.matmul(X.T, np.matmul(X, w) - y) * (1/num_examples)
w = 1e-2 * np.random.normal(size = (num_features,1))
pred_test = np.matmul(X_test, w)
test_error = np.mean(np.square(y_test - pred_test))
print(f"Initial Test Error(MSE): {test_error.item():.6f}")
Initial Test Error(MSE): 93.005015
start = time.time()
for its in range(1,num_iters+1):
grad = grad_fn(w)
w = w - lr * grad
end = time.time()
print(f"Training elapsed time: {end-start} seconds")
print(f"Throughput: {num_iters/(end-start):.3f} iter/s")
Training elapsed time: 0.8565518856048584 seconds Throughput: 11674.716 iter/s
pred_test = np.matmul(X_test, w)
test_error = np.mean(np.square(y_test - pred_test))
print(f"Final Test Error(MSE): {test_error.item():.6f}")
Final Test Error(MSE): 0.000010
๊ฐ๋จํ linear regression์์๋ ํฐ ์ฐจ์ด๊ฐ ์๋ ๊ฒ์ ํ์ธํ ์ ์์์ต๋๋ค.
multi-layer perceptron์ฒ๋ผ ํ๋ ฌ ์ฐ์ฐ์ด ๋ฌด๊ฑฐ์์ง๋ ๊ฒฝ์ฐ ์ฐจ์ด๊ฐ ๋ฐ์ํ๋์ง ๋ค์ ํฌ์คํ ์์ ํ์ธํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
References
-
MLX ํํ์ด์ง(MLX Linear Regression ์ค๋ช )
-
Tstory(Batch ์ค๋ช )
-
SKT Enterprise(MLX Linear Regression ์ค๋ช )