0.导航
项目 | 内容 |
---|---|
这个作业属于哪个课程 | 人工智能实战 |
这个作业的要求在哪里 | 第三次作业:使用minibatch的方式进行梯度下降 |
我在这个课程的目标是 | 开拓视野,积累AI实战经验 |
这个作业在哪个具体方面帮助我 | 了解单变量线性回归的几种方法,掌握Mini-Batch梯度下降的具体实现过程 |
1.具体作业内容
(1)使用minibatch的方式进行梯度下降
-采用随机选取数据的方式
-batch size分别选择5,10,15进行运行
-示例代码位置:Here
(2)复习讲过的课程(链接),并回答关于损失函数的 2D 示意图的问题:
-问题2:为什么是椭圆而不是圆?如何把这个图变成一个圆?
-问题3:为什么中心是个椭圆区域而不是一个点?
2.代码部分(作业1)
改写读取数据集的函数ReadData(),使得可以随机选取数据
def ReadData():
Xfile = Path(x_data_name)
Yfile = Path(y_data_name)
if Xfile.exists() & Yfile.exists():
X = np.load(Xfile)
Y = np.load(Yfile)
idx = np.arange(X.size)
np.random.shuffle(idx)
X = X[idx]
Y = Y[idx]
return X.reshape(1,-1),Y.reshape(1,-1)
else:
return None,None
改写InitializeHyperParameters(method)函数
def InitializeHyperParameters(method):
if method=="MiniBatch_BatchSize_5":
eta = 0.1
max_epoch = 50
batch_size = 5
elif method=="MiniBatch_BatchSize_10":
eta = 0.1
max_epoch = 50
batch_size = 10
elif method=="MiniBatch_BatchSize_15":
eta = 0.1
max_epoch = 50
batch_size = 15
return eta, max_epoch, batch_size
然后对主函数稍作包装修改
def main(method):
eta, max_epoch,batch_size = InitializeHyperParameters(method)
W, B = InitialWeights(1,1,0)
# calculate loss to decide the stop condition
loss = 5
dict_loss = {}
# read data
X, Y = ReadData()
# count of samples
num_example = X.shape[1]
num_feature = X.shape[0]
# if num_example=200, batch_size=10, then iteration=200/10=20
max_iteration = (int)(num_example / batch_size)
for epoch in range(max_epoch):
print("epoch=%d" %epoch)
for iteration in range(max_iteration):
# get x and y value for one sample
batch_x, batch_y = GetBatchSamples(X,Y,batch_size,iteration)
# get z from x,y
batch_z = ForwardCalculationBatch(W, B, batch_x)
# calculate gradient of w and b
dW, dB = BackPropagationBatch(batch_x, batch_y, batch_z)
# update w,b
W, B = UpdateWeights(W, B, dW, dB, eta)
# calculate loss for this batch
loss = CheckLoss(W,B,X,Y)
print(epoch,iteration,loss,W,B)
prev_loss = loss
dict_loss[loss] = CData(loss, W, B, epoch, iteration)
# end for
# end for
ShowLossHistory(dict_loss, method)
w,b,cdata = GetMinimalLossData(dict_loss)
print(cdata.w, cdata.b)
print("epoch=%d, iteration=%d, loss=%f" %(cdata.epoch, cdata.iteration, cdata.loss))
#ShowResult(X, Y, W, B, epoch)
print(w,b)
x = 346/1000
result = ForwardCalculationBatch(w, b, x)
print(result)
loss_2d(X,Y,200,dict_loss,method,cdata)
if __name__ == '__main__':
main("MiniBatch_BatchSize_5");
main("MiniBatch_BatchSize_10");
main("MiniBatch_BatchSize_15");
运行得到结果进行对比
可以看到随着batch_size的增大,曲线变得平滑,个体样本的噪声被显著降低
再来看看Loss_2D生成的图像
也是随着batch_size的增大,曲线变得更加平滑,但是与此同时生成图片(即运行速度)显著变慢,说明计算量明显上升,所以当曲线平滑到一定程度,即batch_size达到较大的某个值以后,再增大batc_size对结果误差减小带来的优势会小于因此消耗更多性能和时间带来的不足,因此当batch_size取到最合适的值时,有最佳效果。这也是介于SGD和BGD两者之间的Mini-Batch方法的优势所在。
3.问题回答(作业2)
问题2:为什么是椭圆而不是圆?如何把这个图变成一个圆?
-答:损失函数如下
可以想见,因为w和b对J的贡献的系数不等,因此图像是一个椭圆而非一个圆,变成圆 只需要使其贡献相等即可,但此时w和b就没有什么区别了,因此没有实际意义。
问题3:为什么中心是个椭圆区域而不是一个点?
-答:我个人的理解是:中心部分和全局最优的差距非常小,因为中心部分那块区域的导数接近于0,且由于计算精度有限,计算的结果(每个点)又是离散而非连续的一条曲线,因此反映到图像上一块区域而不是一个点,而那一块区域就是表示实验中允许的误差范围。