Neural Network

#1.PLA 从新回顾一下一开始学的PLA,preceptron learning Algorithm。PLA适用于二维及高维的线性可分的状况,若是是非线性可分的数据,若是使用PLA可能会无限循环。问题的答案只有赞成或不一样意: git

PLA要作的其实就找到一个x映射到y的f,使得这个f和数据的分布一致,判断结果一致。 若是是遇到了线性不可分的状况,就不能再要求彻底正确了,因此在optimization的时候会要求只须要找到最少错误的分类就能够了,再也不要求彻底正确的分类。 #2.Combine some PLA 把PLA按照aggregation model的想法结合起来:
左边是x = {X1, X2, X3, X4......},和右边的w = {W1, W2, W3......}作內积以后就获得了n个值,就至关于PLA里面WX的部分了。把获得WX的称为是g(x),最后再乘上α,其实就是把g(x)作了一个非线性的组合,也就是aggregation的blending模型。
上图实现的是g1,g2的and。如何用感知机模型实现and逻辑?一种方法是:
g1,g2 = {-1, +1};g1 = -1, g2 = -1,那么结果是就是-3,g1 = -1, g2 = +1, 结果就是-1,若是g1 = +1, g2 = +1,那么结果就是仍是正的,符合预期。
这个例子简单说明了在通过必定的线性组合的状况下是能够作到非线性的分类的。除此以外,OR,XOR等等都是能够经过g(x)的线性组合获得的。 **因此说,Neural Network是一种很powerful同上也是complicated的模型,另外,当hidden层神经元数量大的时候计算量会很是大。**好比下面的一个例子,有一个圆形区域,里面的+!外面是-1,这种是没有办法使用一个PLA切分开的,只能使用多个PLA了,若是是8个PLA的时候,大概是能够组成一个圆形,16个PLA的时候就要更接近了,所以,使用的PLA越多,获得的结果就会和数据的分布越拟合:
以前说过,凸多边形的VC dimension是无限大的,2的n次方,因此随着PLA数量的增加vc 维是没有限制的,容易形成过拟合。可是,数目较多老是能够获得一个更加平滑更加拟合的曲线,这也是aggregation model的特色。 可是,仍是有单层preceptron线性组合作不到的事情,好比XOR操做:
由于XOR获得的是非线性可分的区域,以下图所示,没有办法由g1和g2线性组合实现。因此说linear aggregation of perceptrons模型的复杂度仍是有限制的。事实上,一层的perceptron其实就是一次transform,那么既然一次transform不行,咱们尝试一下多层的perceptron,屡次的transform。把XOR拆分开来,第一次是使用AND,第二次就是使用OR,以下:
这样就从简单的单层aggregation提高到了multi-layer的多层感知机,模型的复杂度增长以后就更能解决一些非线性的问题了。 第一层的wx处理后再接到下一层wx处理。这其实就是有点接近神经网络的模型了。 #3.Neural Network 以前已经介绍过三种线性模型:linear classification,linear regression,logistic regression。那么,对于OUTPUT层的分数s,根据具体问题,能够选择最合适的线性模型。若是是binary classification问题,能够选择linear classification模型;若是是linear regression问题,能够选择linear regression模型;若是是soft classification问题,则能够选择logistic regression模型。 若是根据上面的模型,每一层都是wx,那么不管多少层叠加起来都是www....x而已,都是线性的,因此咱们要在每一层结束的时候加上一个activity function。对于激活函数的选择有不少,sigmoid,relu,tanh等。sigmoid函数因为会出现梯度消失的现象,因此如今已经不多用了,relu函数是比较经常使用的。这里会使用tanh函数:
tanh是一个平滑函数,当|s|比较大的时候近似于阶梯函数,|s|比较小的时候会接近于线性函数。到处连续并且可导,计算也比较方便,并且求导的时候能够用上自身的值:
反向传播计算的时候是能够用上以前计算过的缓存下来的值,若是在神经元数量特别多的状况下是能够减小计算复杂度的。
那么下图更新以后的Neural Network:
指的就是第几层,再看一下权值w:
l表示第几层,ij表示前一层输出个数加上当前的项。那么对于每一层的分数:
再通过一层激活函数:
每一层的输出就是这样了。
上图中的每一层神经网络其实就是一种transform的过程,而每一层转换的关键就在于权值w,每一层网络利用输入x和权值w的乘积,在通过tanh函数以后,将获得改函数的输出,从左到右,一层一层的进行,若是乘积获得的分数越大,那么tanh(wx)就越接近于1了,代表拟合出来的分布越接近于书记分布。因此每一层的输入x和权重w具备模式上的类似性,比较接近平行,那么transform的效果就比较好。因此,神经网络的核心就是pattern extraction,从数据自己开始查找蕴含的规律,经过一层一层的找到以后再拟合结果。因此,神经网络是生成模型。 根据error function,咱们只要计算Ein = (y - score)^2就可利用知道这单个样本点的error了,因此只须要创建Ein与每个权值之间的关系就能够了,最直接的方法就是使用Gradient Descent了,不断优化w的值。
先来看一下如何计算他们之间的关系:
咱们的对象是w,天然就是对w求偏导:
这是输出层的偏导结果,也就是delta_output。 对于其余层,根据链式法则:
咱们令第j层的神经元的偏导数即为
后面的推导其实都很简单了:
依照这种往上递推的方式,能够把每一层的分数梯度算出来。
上面采用的是SGD的方法,即每次迭代更新时只取一个点,这种作法通常不够稳定。因此一般会采用mini-batch的方法,即每次选取一些数据,例如N/10,来进行训练,最后求平均值更新权重w。这种作法的实际效果会比较好一些。 #4.Optimization and Regularization 最终的目标仍是要Ein最小,采用什么error function只须要在推导上修正一下就行了。
层数越多,说明模型的复杂度就会越大,很明显,这样获得的model确定不是convex的,可能有不少的山峰,可能只是走到了其中一个而已,并无到最低的。解决这种状况首先就是对w权值就行随机选择,经过random从广泛几率上选择初始值,避免了人为干扰的因素,有更大的可能走到全局的最优。
从理论上看神经网络,dvc = O(VD)。其中,V是神经网络里面神经元的个数,D表示全部权值的数量,全部若是V很大,那么复杂度就会越大,颇有可能会overfit,因此能够经过限制模型复杂度来防止过拟合。 防止overfit还有一个方法,就是regularization,L1或L2正则化。可是使用L2正则化有一个缺点,大的权值就减少很大,小权值基本不怎么变,复杂度事实上仍是没有变。而L1正则化是可使得权值稀疏,可是在某些地方是不能够微分的,使用也不适合。使用咱们须要一个可使得大权值减少很大,小权值减少到0的一个函数:
除此以外,训练次数减小也是能够达到限制过拟合效果的。由于训练时间越长,对于寻找可能性就会越多,VC dimension就会越大,当t不大的时候是能够减低模型复杂度的。
#5.代码实现 首先是生成数据,使用的是sklearn的make_moon:

def generator():
    np.random.seed(0)
    x, y = dataTool.make_moons(200, noise=0.2)
    plt.scatter(x[:, 0], x[:, 1], s = 40, c = y, cmap=plt.cm.Spectral)
    plt.show()
    return x, y
    pass

复制代码

这是咱们生成数据的分布,能够看到线性分类器是没法区分开的。 而后就是网络生成训练的主要部分了:

class Network(object):
    def __init__(self, x, y):
        '''initialize the data'''
        self.x = x
        self.num_examples = len(x)
        self.y = y
        self.n_output = 2
        self.n_input = 2
        self.epsilon = 0.01
        self.reg_lambed = 0.01
        self.model = None
        pass
复制代码

初始化数据。github

def calculate_loss(self, model):
        '''calculate the loss function'''
        w1, b1, w2, b2 = model['w1'], model['b1'], model['w2'], model['b2']
        z1 = self.x.dot(w1) + b1
        a1 = np.tanh(z1)
        z2 = a1.dot(w2) + b2
        exp_scores = np.exp(z2)
        probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
        corect_logprobs = -np.log(probs[range(self.num_examples), self.y])
        data_loss = np.sum(corect_logprobs)
        data_loss += self.reg_lambed / 2 * (np.sum(np.square(w1)) + np.sum(np.square(w2)))
        return 1.0/self.num_examples * data_loss
复制代码

计算损失函数,最后使用的是softmax分类器,损失函数使用的是交叉熵: 缓存

在加上regularization便可。

def predict(self, x):
        '''according to the model,predict the consequence'''
        w1, b1, w2, b2 = self.model['w1'], self.model['b1'], self.model['w2'], self.model['b2']
        z1 = x.dot(w1) + b1
        a1 = np.tanh(z1)
        z2 = a1.dot(w2) + b2
        exp_scores = np.exp(z2)
        probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
        return np.argmax(probs, axis=1)
        pass
复制代码

预测,常规操做。bash

def build_Network(self, n_hinden, num_pass = 20000, print_loss = True):
        loss = []
        np.random.seed(0)
        w1 = np.random.randn(self.n_input, n_hinden) / np.sqrt(self.n_input)
        b1 = np.zeros((1, n_hinden))
        w2 = np.random.randn(n_hinden, self.n_output) / np.sqrt(n_hinden)
        b2 = np.zeros((1, self.n_output))

        self.model = {}
        for i in range(num_pass):
            z1 = self.x.dot(w1) + b1
            a1 = np.tanh(z1)
            z2 = a1.dot(w2) + b2
            exp_scores = np.exp(z2)
            probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)

            delta3 = probs
            delta3[range(self.num_examples), self.y] -= 1
            dw2 = (a1.T).dot(delta3)
            db2 = np.sum(delta3, axis=0, keepdims=True)
            delta2 = delta3.dot(w2.T)*(1 - np.power(a1, 2))
            dw1 = np.dot(self.x.T, delta2)
            db1 = np.sum(delta2, axis=0)
            dw2 += self.reg_lambed * w2
            dw1 += self.reg_lambed * w1

            w1 += -self.epsilon * dw1
            b1 += -self.epsilon * db1
            w2 += -self.epsilon * dw2
            b2 += -self.epsilon * db2

            self.model = {'w1':w1, 'b1':b1, 'w2':w2, 'b2':b2}
            if print_loss and i %200 == 0:
                print('Loss : ', (i, self.calculate_loss(model=self.model)))
                loss.append(self.calculate_loss(model=self.model))
        return loss
复制代码

有使用的是softmax损失函数,对于softmax函数求导以后就是原函数-1,求w2梯度,对w2求导就只有a2了,根据刚刚的公式: 网络

能够求出delta2,最后一次更新便可。

if __name__ == '__main__':
    Accuracy = []
    losses = []
    x, y = Tool.generator()
    for i in range(1, 13):
        mlp = Network(x, y)
        loss = mlp.build_Network(n_hinden=i)
        losses.append(loss)
        Tool.plot_decision_boundary(mlp.predict, x, y, 'Neutral Network when Hidden layer size is ' + str(i))
        predicstions = mlp.predict(x)
        a = sum(1*(predicstions == y)) / len(y)
        Accuracy.append(a)

    '''draw the accuracy picture'''
    plt.plot(range(len(Accuracy)), Accuracy, c = 'blue')
    plt.title('The Accuracy of the Neural Network')
    plt.xlabel('Hinden Layer Size')
    plt.ylabel('Accuracy')
    plt.show()


    '''draw the loss function picture'''
    for i, loss in enumerate(losses):
        plt.plot(range(len(loss)), loss, c = Tool.get_colors(i), label = 'the hindden layer size '+str(i))
    plt.title('Loss Function')
    plt.xlabel('time')
    plt.ylabel('loss score')
    plt.legend()
    plt.show()
复制代码

主要的运行函数。 还须要看一个画图函数:app

def plot_decision_boundary(pred_func, X, y, title):
    # Set min and max values and give it some padding
    x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
    h = 0.01
    # Generate a grid of points with distance h between them
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    # Predict the function value for the whole gid
    Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    # Plot the contour and training examples
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)
    plt.title(title)
    plt.show()

复制代码

接下来运行一下看效果吧(有些颜色的代码不全,GitHub上有): dom

接下来的效果应该都是相似的了。 随着神经元数量的增长:
准确率是愈来愈高的。
1个神经元和2个神经元的时候明显是欠拟合,后面的效果其实都变化不大。

符上因此GitHub代码: github.com/GreenArrow2…函数

相关文章
相关标签/搜索