对构建波士顿房价预测任务的神经网络模型的学习

**

对构建波士顿房价预测任务的神经网络模型的学习(笔记)

**

  1. 数据集划分

将数据集划分成训练集和测试集,其中训练集用于确定模型的参数,测试集用于评判模型的效果。为什么要对数据集进行拆分,这与学生时代的授课和考试关系比较类似,如图所示。
对构建波士顿房价预测任务的神经网络模型的学习_第1张图片
2. 数据归一化处理

对每个特征进行归一化处理,使得每个特征的取值缩放到0~1之间。这样做有两个好处:一是模型训练更高效;二是特征前的权重大小可以代表该变量对预测结果的贡献度
再者就是,在后续的确定损失函数更小的点的过程中,所有参数的移动步长可以统一(学习率可以设置成统一的值);特征输入未归一化时,不同特征对应的参数所需的步长不一致,尺度较大的参数需要大步长,尺寸较小的参数需要小步长,导致无法设置统一的学习率。

  1. 均方误差

均方误差表现的“圆滑”的坡度有两个好处:
1)曲线的最低点是可导的。
2)越接近最低点,曲线的坡度逐渐放缓,有助于通过当前的梯度来判断接近最低点的程度(是否逐渐减少步长,以免错过最低点)。
而这两个特性绝对值误差是不具备的,这也是损失函数的设计不仅仅要考虑“合理性”,还要追求“易解性”的原因。

  1. np.newaxis

print('gradient_w ', gradient_w.shape)
gradient_w = gradient_w[:, np.newaxis]
print('gradient_w ', gradient_w.shape)

gradient_w (13,)
gradient_w (13,1)

print('gradient_w ', gradient_w.shape)
gradient_w = gradient_w[np.newaxis,:]
print('gradient_w ', gradient_w.shape)

gradient_w (13,)
gradient_w (1,13)

  1. 随机梯度下降法

在实际问题中,数据集往往非常大,如果每次都使用全量数据进行计算,效率非常低,通俗地说就是“杀鸡焉用牛刀”。由于参数每次只沿着梯度反方向更新一点点,因此方向并不需要那么精确。一个合理的解决方案是每次从总的数据集中随机抽取出小部分数据来代表整体,基于这部分数据计算梯度和损失来更新参数,这种方法被称作随机梯度下降法。
通过大量实验发现,模型对最后出现的数据印象更加深刻。训练数据导入后,越接近模型训练结束,最后几个批次数据对模型参数的影响越大。为了避免模型记忆影响训练效果,需要进行样本乱序操作。

采用随机梯度下降法代码:

import numpy as np

class Network(object):
    def __init__(self, num_of_weights):
        # 随机产生w的初始值
        # 为了保持程序每次运行结果的一致性,此处设置固定的随机数种子
        #np.random.seed(0)
        self.w = np.random.randn(num_of_weights, 1)
        self.b = 0.
	#正向运算        
    def forward(self, x):
    	#产生预测值z
        z = np.dot(x, self.w) + self.b
        return z
	#损失函数    
    def loss(self, z, y):
        error = z - y
        num_samples = error.shape[0]
        #均方误差
        cost = error * error
        cost = np.sum(cost) / num_samples
        return cost
    #损失函数在w,b处的梯度
    def gradient(self, x, y):
        z = self.forward(x)
        N = x.shape[0]
        #求导后所得
        gradient_w = 1. / N * np.sum((z-y) * x, axis=0)
        gradient_w = gradient_w[:, np.newaxis]
        gradient_b = 1. / N * np.sum(z-y)
        return gradient_w, gradient_b
	#eta_步长    
    def update(self, gradient_w, gradient_b, eta = 0.01):
    	#优化w,b
        self.w = self.w - eta * gradient_w
        self.b = self.b - eta * gradient_b
            
    #min-batch:每次迭代时抽取出来的一批数据被称为一个min-batch。
	#batch_size:一个mini-batch所包含的样本数目称为batch_size。
	#epoch:当程序迭代的时候,按mini-batch逐渐抽取出样本,当把整个数据集都遍历到了的时候,则完成了一轮训练,也叫一个epoch。  
    def train(self, training_data, num_epoches, batch_size=10, eta=0.01):
        n = len(training_data)
        losses = []
        for epoch_id in range(num_epoches):
            # 在每轮迭代开始之前,将训练数据的顺序随机打乱
            # 然后再按每次取batch_size条数据的方式取出
            np.random.shuffle(training_data)
            # 将训练数据进行拆分,每个mini_batch包含batch_size条的数据
            mini_batches = [training_data[k:k+batch_size] for k in range(0, n, batch_size)]
            for iter_id, mini_batch in enumerate(mini_batches):
                #print(self.w.shape)
                #print(self.b)
                x = mini_batch[:, :-1]
                y = mini_batch[:, -1:]
                a = self.forward(x)
                loss = self.loss(a, y)
                gradient_w, gradient_b = self.gradient(x, y)
                self.update(gradient_w, gradient_b, eta)
                losses.append(loss)
                print('Epoch {:3d} / iter {:3d}, loss = {:.4f}'.
                                 format(epoch_id, iter_id, loss))
        
        return losses

# 获取数据
train_data, test_data = load_data()

# 创建网络
net = Network(13)
# 启动训练
losses = net.train(train_data, num_epoches=50, batch_size=100, eta=0.1)

# 画出损失函数的变化趋势
plot_x = np.arange(len(losses))
plot_y = np.array(losses)
plt.plot(plot_x, plot_y)
plt.show()

你可能感兴趣的:(python,深度学习,人工智能)