梯度下降、随机梯度下降算法 (手写)【实战案例】

梯度下降、随机梯度下降算法 (手写)【实战案例】

这份作业提供了一个很好的实战案例,在此将其转为博客。作为学习笔记
若想了解该作业得更多信息,或者算法的其他内容欢迎私信博主。或添加博主VX: 1178623893

COMP9417 - Machine Learning

Homework 1: Gradient Descent & Friends

Introduction

In this homework, you will be required to manually implement (Stochastic) Gradient Descent
in Python to learn the parameters of a linear regression model.

# Import Packages
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Load Data
df = pd.read_csv(r'real_estate(1).csv')
df
transactiondateagenearestMRTnConveniencelatitudelongitudeprice
02012.91732.084.8788210.024.98298121.5402437.9
12012.91719.5306.594709.024.98034121.5395142.2
22013.58313.3561.984505.024.98746121.5439147.3
32013.50013.3561.984505.024.98746121.5439154.8
42012.8335.0390.568405.024.97937121.5424543.1
........................
4092013.00013.74082.015000.024.94155121.5038115.4
4102012.6675.690.456069.024.97433121.5431050.0
4112013.25018.8390.969607.024.97923121.5398640.6
4122013.0008.1104.810105.024.96674121.5406752.5
4132013.5006.590.456069.024.97433121.5431063.9

414 rows × 7 columns

### Question 1. (Pre-processing)
#  Question 1. (Pre-processing)
# Q1(a)  Remove any rows of the data that contain a missing (‘NA’) value. List the indices of the removed
# data points. Then, delete all features from the dataset apart from: age, nearestMRT and nConvenience.

df1 = df.dropna(axis = 0,how='any')  # df1: remove 'NA'
df2 = df1.reset_index(drop = True)   # Set a new index for df1

df3 = df2[['price','age','nearestMRT','nConvenience']]  # Delete all features from the dataset apart from: age, nearestMRT and nConvenience.

# Q1(b) feature normalisation
df_data = (df3 - df3.min()) / (df3.max() - df3.min())
print('----------------------the cleaned data----------------------')
print(df_data)
print('-----------------the mean value over your dataset.-------------------')
print(df_data.mean())

----------------------the cleaned data----------------------
        price       age  nearestMRT  nConvenience
0    0.275705  0.730594    0.009513           1.0
1    0.314832  0.445205    0.043809           0.9
2    0.361237  0.303653    0.083315           0.5
3    0.429481  0.303653    0.083315           0.5
4    0.323021  0.114155    0.056799           0.5
..        ...       ...         ...           ...
403  0.070974  0.312785    0.627820           0.0
404  0.385805  0.127854    0.010375           0.9
405  0.300273  0.429224    0.056861           0.7
406  0.408553  0.184932    0.012596           0.5
407  0.512284  0.148402    0.010375           0.9

[408 rows x 4 columns]
-----------------the mean value over your dataset.-------------------
price           0.277240
age             0.406079
nearestMRT      0.162643
nConvenience    0.412010
dtype: float64

Question 2. (Train and Test sets)

# Question 2. (Train and Test sets)
# 
train_df = df_data.iloc[:int(.5 * len(df_data)),:]
test_df  = df_data.iloc[int(.5 * len(df_data)):,:]
print('----------------------the Train Set----------------------')
print(train_df)
print('----------------------the Test Set----------------------')
print(test_df)
print('---------------------------------------------------------')
print('Print out the first and last rows of both your training and test sets.')
print('---------------------------------------------------------')
print(train_df.iloc[1,:])
print(train_df.iloc[-1,:])
print(test_df.iloc[1,:])
print(test_df.iloc[-1,:])

----------------------the Train Set----------------------
        price       age  nearestMRT  nConvenience
0    0.275705  0.730594    0.009513           1.0
1    0.314832  0.445205    0.043809           0.9
2    0.361237  0.303653    0.083315           0.5
3    0.429481  0.303653    0.083315           0.5
4    0.323021  0.114155    0.056799           0.5
..        ...       ...         ...           ...
199  0.350318  0.356164    0.041138           0.5
200  0.172884  0.410959    0.215241           0.1
201  0.125569  0.292237    0.220637           0.3
202  0.331210  0.506849    0.055096           1.0
203  0.242038  0.878995    0.099260           0.3

[204 rows x 4 columns]
----------------------the Test Set----------------------
        price       age  nearestMRT  nConvenience
204  0.169245  0.262557    0.206780           0.1
205  0.303003  0.794521    0.023551           0.8
206  0.405823  0.118721    0.056799           0.5
207  0.326661  0.000000    0.038770           0.1
208  0.213831  0.401826    0.275697           0.2
..        ...       ...         ...           ...
403  0.070974  0.312785    0.627820           0.0
404  0.385805  0.127854    0.010375           0.9
405  0.300273  0.429224    0.056861           0.7
406  0.408553  0.184932    0.012596           0.5
407  0.512284  0.148402    0.010375           0.9

[204 rows x 4 columns]
---------------------------------------------------------
Print out the first and last rows of both your training and test sets.
---------------------------------------------------------
price           0.314832
age             0.445205
nearestMRT      0.043809
nConvenience    0.900000
Name: 1, dtype: float64
price           0.242038
age             0.878995
nearestMRT      0.099260
nConvenience    0.300000
Name: 203, dtype: float64
price           0.303003
age             0.794521
nearestMRT      0.023551
nConvenience    0.800000
Name: 205, dtype: float64
price           0.512284
age             0.148402
nearestMRT      0.010375
nConvenience    0.900000
Name: 407, dtype: float64

Question 3. (Loss Function)

Consider the loss function
L c ( x , y ) = 1 c 2 ( x − y ) 2 + 1 − 1 \mathcal{L}_{c}(x, y)=\sqrt{\frac{1}{c^{2}}(x-y)^{2}+1}-1 Lc(x,y)=c21(xy)2+1 1
where c ∈ R c \in \mathbb{R} cR is a hyper-parameter. Consider the (simple) linear model
We can write this more succintly by letting w = ( w 0 , w 1 , w 2 , w 3 ) T w=\left(w_{0}, w_{1}, w_{2}, w_{3}\right)^{T} w=(w0,w1,w2,w3)T and X ( i ) = ( 1 , x 1 ( i ) , x 2 ( i ) , x 3 ( i ) ) T \boldsymbol{X}^{(i)}=\left(1, x_{1}^{(i)}, x_{2}^{(i)}, x_{3}^{(i)}\right)^{T} X(i)=(1,x1(i),x2(i),x3(i))T
,so that y ^ ( i ) = w T X ( i ) \hat{y}^{(i)}=w^{T} X^{(i)} y^(i)=wTX(i). The mean-loss achieved by our model (w) on a given dataset of n observations is then
L c ( y , y ^ ) = 1 n ∑ i = 1 n L c ( y ( i ) , y ^ ( i ) ) = 1 n ∑ i = 1 n [ 1 c 2 ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) 2 + 1 − 1 ] \mathcal{L}_{c}(y, \hat{y})=\frac{1}{n} \sum_{i=1}^{n} \mathcal{L}_{c}\left(y^{(i)}, \hat{y}^{(i)}\right)= \\ \frac{1}{n} \sum_{i=1}^{n}\left[\sqrt{\frac{1}{c^{2}}\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)^{2}+1}-1\right] Lc(y,y^)=n1i=1nLc(y(i),y^(i))=n1i=1n[c21(y(i)w(t),X(i))2+1 1]
Compute the following derivatives:
∂ L c ( y ( i ) y ^ ( i ) ) ∂ w k , k = 0 , 1 , 2 , 3 \frac{\partial \mathcal{L}_{c}\left(y^{(i)} \hat{y}^{(i)}\right)}{\partial w_{k}}, \quad k=0,1,2,3 wkLc(y(i)y^(i)),k=0,1,2,3
You must show your working for full marks.

Answer to Question 3.
∂ L c ( y ( i ) y ^ ( i ) ) ∂ w k = ∂ ∂ w k ( 1 c 2 ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) 2 + 1 − 1 ) = 1 2 ( 1 c 2 ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) 2 + 1 ) − 1 2 ∂ ∂ w k ( 1 c 2 ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) 2 + 1 ) = 1 2 ( 1 c 2 ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) 2 + 1 ) − 1 2 1 c 2 ∂ ∂ w k ( ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) 2 ) = ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) x k ( i ) c 2 ( y ( i ) − ⟨ w ( t ) , X ( i ) ⟩ ) 2 + c 4 \begin{aligned} \frac{\partial \mathcal{L}_{c}\left(y^{(i)} \hat{y}^{(i)}\right)}{\partial w_{k}} &= \frac{\partial}{\partial w_k}\left({\sqrt{\frac{1}{c^{2}}\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)^{2}+1}-1} \right) \\ &= \frac{1}{2}\left(\frac{1}{c^{2}}\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)^{2}+1\right)^{-\frac{1}{2}}\frac{\partial}{ \partial w_k}\left( \frac{1}{c^{2}}\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)^{2}+1 \right) \\ &= \frac{1}{2}\left(\frac{1}{c^{2}}\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)^{2}+1\right)^{-\frac{1}{2}}\frac{1}{c^2}\frac{\partial }{\partial w_k}\left(\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)^{2}\right) \\ &= \frac{\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)x_{k}^{(i)}}{\sqrt{c^2\left(y^{(i)}-\left\langle w^{(t)}, X^{(i)}\right\rangle\right)^{2}+c^4}} \end{aligned} wkLc(y(i)y^(i))=wk(c21(y(i)w(t),X(i))2+1 1)=21(c21(y(i)w(t),X(i))2+1)21wk(c21(y(i)w(t),X(i))2+1)=21(c21(y(i)w(t),X(i))2+1)21c21wk((y(i)w(t),X(i))2)=c2(y(i)w(t),X(i))2+c4 (y(i)w(t),X(i))xk(i)

Question 4. (Gradient Descent Psuedocode)

The pseudocode for gradient descent updates
for i in range ( max_iterations):   
	params_grad = evaluate_gradient ( loss_function , training_data , params )
	params = params - learning_rate * params_grad 

The pseudocode for stochastic gradient descent updates
for i in range ( nb_epochs ):             # loop Epochs
	np. random . shuffle ( training_data  )    #  random
	for batch in get_batches (training_data , batch_size =50):
       params_grad = evaluate_gradient ( loss_function , batch , params )
       params = params - learning_rate * params_grad

Question 5. (Gradient Descent Implementation)

# Question 5. (Gradient Descent Implementation)
# Q5. (a)
#  -------------------- Gradient_Descent --------------------
def loss(w,x,y):
        c = 0.5
        temp = pow((y-x@w),2)
        num = np.sqrt(temp/c/c+1)-1
        return np.mean(num)
    
def Gradient_Descent(w,x,y,eta):
    max_iter = 400
    i = 0
    Loss = []
    w_all = w
    while i < max_iter:
        i += 1
        w0 = w[0] - eta * np.mean( 0.5 * (x[:,0].reshape([-1,1])) * (x@w-y) / (np.sqrt(pow((x@w-y),2)+4)))
        w1 = w[1] - eta * np.mean( 0.5 * (x[:,1].reshape([-1,1])) * (x@w-y) / (np.sqrt(pow((x@w-y),2)+4)))
        w2 = w[2] - eta * np.mean( 0.5 * (x[:,2].reshape([-1,1])) * (x@w-y) / (np.sqrt(pow((x@w-y),2)+4)))
        w3 = w[3] - eta * np.mean( 0.5 * (x[:,3].reshape([-1,1])) * (x@w-y) / (np.sqrt(pow((x@w-y),2)+4)))
        w = np.array([w0,w1,w2,w3]).reshape([-1,1])
        w_all = np.hstack([w_all,w])
        loss_fun = loss(w,x,y)
        Loss.append(loss(w,x,y))
    return Loss,w_all

#  -------------------- Main Function --------------------
df_x = train_df[['age','nearestMRT','nConvenience']]
df_y = train_df['price']
x = np.hstack([np.ones([len(train_df),1]),df_x.values])
y = df_y.values.reshape([-1,1])
ww = np.array([1,1,1,1]).reshape([-1,1])


## 
alphas = [10,5,2, 1,0.5, 0.25,0.1, 0.05, 0.01]
num = 0
for eta in alphas:
    Loss_temp,w_all  = Gradient_Descent(ww,x,y,eta)
    Loss_temp = np.array(Loss_temp).reshape([-1,1])
    if num == 0:
        Loss_all = Loss_temp
        num  = 1
    else:
        Loss_all = np.hstack([Loss_all,Loss_temp])
##  plot
fig, ax = plt.subplots(3,3, figsize=(10,10))
ax.flat
for i, ax in enumerate(ax.flat):
# losses is a list of 9 elements. Each element is an array of length nIter storing the loss at each iteration for
# that particular step size
    ax.plot(Loss_all[:,i])
    ax.set_title(f"step size: {alphas[i]}") # plot titles
    plt.tight_layout() # plot formatting

在这里插入图片描述

Q5. (b)

From your results in the previous part, choose an appropriate step size (and state your choice), and
explain why you made this choice

Answer to Question 5.(b).

In my opinion, after many tests, the step size of 1 is an appropriate choice.
If the step size is too large, the iteration will be too fast, and even the optimal solution may be missed.The step size is too small, the iteration speed is too slow, and the algorithm cannot finish for a long time.However, when the step size is 1, the algorithm uses fewer times to reach the optimal value.

# Q5. (c)
# 取 eta = 0.3 画出所有的权重迭代图
#  -------------------- Main Function --------------------
df_x = df_data[['age','nearestMRT','nConvenience']]
df_y = df_data['price']
x = np.hstack([np.ones([len(df_data),1]),df_x.values])
y = df_y.values.reshape([-1,1])
ww = np.array([1,1,1,1]).reshape([-1,1])
eta = 0.3 
Loss_temp,w_all  = Gradient_Descent(ww,x,y,eta)

plt.plot(w_all.T)
plt.title('The progression of each of the four weights over the iterations.')
plt.ylabel('Weights')
plt.xlabel('Iterations')
plt.legend(['w0','w_1','w_2','w_3','w_3'])
plt.show()
print('The final weight vector is :',w_all[:,-1]) # Print out the final weight vector.

# Finally, run your model on the train and test set, and print the achieved losses.
# Train Set
df_train_x = train_df[['age','nearestMRT','nConvenience']]
df_train_y = train_df['price']
train_x = np.hstack([np.ones([len(df_train_x),1]),df_train_x.values])
train_y = df_train_y.values.reshape([-1,1])
loss_train = loss(w_all[:,-1].reshape([-1,1]),train_x,train_y)
print('Loss for Train Set :',loss_train)

# Test Set
df_test_x = test_df[['age','nearestMRT','nConvenience']]
df_test_y = test_df['price']
test_x = np.hstack([np.ones([len(df_test_x),1]),df_test_x.values])
test_y = df_test_y.values.reshape([-1,1])
loss_test = loss(w_all[:,-1].reshape([-1,1]),test_x,test_y)
print('Loss for Test Set :',loss_test)

在这里插入图片描述

The final weight vector is : [ 0.04394919 -0.01285655  0.29836987  0.44517113]
Loss for Train Set : 0.030617652935386656
Loss for Test Set : 0.035002153888240746

Question 6. (Stochastic Gradient Descent Implementation)

# Q6. (a)
#  -------------------- Stochastic_Gradient_Descent --------------------
def Stochastic_Gradient_Descent(w,x,y,eta):
    def loss(w,x,y):
        c = 0.5
        temp = pow((y-x@w),2)
        num = np.sqrt(temp/c/c+1)-1
        return np.mean(num)
    Loss_all = []
    data = np.hstack([y,x])
    w_all    = w
    n_Epochs = 6
    for i in range(n_Epochs):
        rand_data = np.random.permutation(data)
        yy = rand_data[:,0]
        xx = rand_data[:,1:]
        for j in range(len(yy)):
            w0 = w[0] - eta *  0.5 * (xx[j,0]) * (xx[j,:]@w-yy[j]) / (np.sqrt(pow((xx[j,:]@w-yy[j]),2)+4))
            w1 = w[1] - eta *  0.5 * (xx[j,1]) * (xx[j,:]@w-yy[j]) / (np.sqrt(pow((xx[j,:]@w-yy[j]),2)+4))
            w2 = w[2] - eta *  0.5 * (xx[j,2]) * (xx[j,:]@w-yy[j]) / (np.sqrt(pow((xx[j,:]@w-yy[j]),2)+4))
            w3 = w[3] - eta *  0.5 * (xx[j,3]) * (xx[j,:]@w-yy[j]) / (np.sqrt(pow((xx[j,:]@w-yy[j]),2)+4))
            w = np.array([w0,w1,w2,w3]).reshape([-1,1])
            w_all = np.hstack([w_all,w])
            loss_fun = loss(w,x,y)
            Loss_all.append(loss(w,x,y))
    return w_all,Loss_all
#  -------------------- Main Function --------------------
df_x = train_df[['age','nearestMRT','nConvenience']]
df_y = train_df['price']
x = np.hstack([np.ones([len(train_df),1]),df_x.values])
y = df_y.values.reshape([-1,1])
ww = np.array([1,1,1,1]).reshape([-1,1])

eta = 0.4
w_all,loss_all = Stochastic_Gradient_Descent(ww,x,y,eta)


alphas = [10,5,2, 1,0.5, 0.25,0.1, 0.05, 0.01]
num = 0
for eta in alphas:
    w_temp, Loss_temp  = Stochastic_Gradient_Descent(ww,x,y,eta)
    Loss_temp1 = np.array(Loss_temp).reshape([-1,1])
    if num == 0:
        Loss_all = Loss_temp1
        num  = 1
    else:
        Loss_all = np.hstack([Loss_all,Loss_temp1])

##  plot
fig, ax = plt.subplots(3,3, figsize=(10,10))
ax.flat

for i, ax in enumerate(ax.flat):
# losses is a list of 9 elements. Each element is an array of length nIter storing the loss at each iteration for
# that particular step size
    ax.plot(Loss_all[:,i])
    ax.set_title(f"step size: {alphas[i]}") # plot titles
    plt.tight_layout() # plot formatting

在这里插入图片描述

Q6. (b)

From your results in the previous part, choose an appropriate step size (and state your choice), and
explain why you made this choice

Answer to Question 6.(b).

In my opinion, after many tests, the step size of 0.5 is an appropriate choice.
If the step size is too large, the iteration will be too fast, and even the optimal solution may be missed.The step size is too small, the iteration speed is too slow, and the algorithm cannot finish for a long time.However, when the step size is 0.5, the algorithm uses fewer times to reach the optimal value.

# Q6. (c)
# 取 eta = 0.4 画出所有的权重迭代图
#  -------------------- Main Function --------------------
df_x = train_df[['age','nearestMRT','nConvenience']]
df_y = train_df['price']
x = np.hstack([np.ones([len(train_df),1]),df_x.values])
y = df_y.values.reshape([-1,1])
ww = np.array([1,1,1,1]).reshape([-1,1])

eta = 0.4
w_all,Loss_temp  = Stochastic_Gradient_Descent(ww,x,y,eta)

plt.plot(w_all.T)
plt.title('The progression of each of the four weights over the iterations.')
plt.ylabel('Weights')
plt.xlabel('Iterations')
plt.legend(['w0','w_1','w_2','w_3','w_3'])
plt.show()
print('The final weight vector is :',w_all[:,-1]) # Print out the final weight vector.

# Finally, run your model on the train and test set, and print the achieved losses.
# Train Set
df_train_x = train_df[['age','nearestMRT','nConvenience']]
df_train_y = train_df['price']
train_x = np.hstack([np.ones([len(df_train_x),1]),df_train_x.values])
train_y = df_train_y.values.reshape([-1,1])
loss_train = loss(w_all[:,-1].reshape([-1,1]),train_x,train_y)
print('Loss for Train Set :',loss_train)

# Test Set
df_test_x = test_df[['age','nearestMRT','nConvenience']]
df_test_y = test_df['price']
test_x = np.hstack([np.ones([len(df_test_x),1]),df_test_x.values])
test_y = df_test_y.values.reshape([-1,1])
loss_test = loss(w_all[:,-1].reshape([-1,1]),test_x,test_y)
print('Loss for Test Set :',loss_test)

在这里插入图片描述

The final weight vector is : [ 0.27166775 -0.12645567 -0.17158891  0.20079968]
Loss for Train Set : 0.012240492047852287
Loss for Test Set : 0.01614156189305504

Question 7. Results Analysis

In a few lines, comment on your results in Questions 5 and 6.

Ansewr:

Both Gradient Descent and Stochastic Gradient Descent performed well in the tests, he said, meaning that they both used fewer iterations to reach the optimal value.However, in general, stochastic gradient descent is better than gradient descent.

Explain the importance of the step-size in both GD and SGD.

Ansewr:

Step size determines the length of each step in the gradient descent iteration along the negative direction of the gradient.It is important to set a proper step size.This is because the step size is too large, which will lead to too fast iteration and may even miss the optimal solution.The step size is too small, the iteration speed is too slow, and the algorithm cannot finish for a long time.

Explain why one might have a preference for GD or SGD.

Ansewr:

Gradient Descent and Stochastic Gradient Descent are two important optimization algorithms, and each of them has its own disadvantages and advantages.In general, gradient descent can be more accurate in the direction of the extreme value, but the gradient descent algorithm cannot guarantee that the optimized function can reach the global optimal solution.The worst part is that gradient descent takes too long to compute.For stochastic gradient descent, the convergence rate is generally much faster, but the error function is not
minimized as in Gd.

Explain why the GD paths look much smoother than the SGD paths.

Ansewr:

BGD always synthesizes the gradient of all data, so its iteration process is always smooth, while SGD randomly selects a piece of data as a parameter, so its iteration process is very unstable.

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春风惹人醉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值