• [学习笔记] RBF神经网络初探


    RBF神经网络初探

    径向基函数

    径向基函数是一种函数的取值仅仅与输入的中心点有关的函数,具有这种性质的函数就称为径向基函数。

    比如,高斯函数是一种径向基函数,其输出值的大小与距离中心点的距离有关,距离中心点越远,函数值越小,距离中心点越近,函数值越大。

    RBF神经网络的结构

    RBF神经网络一般具有两层结构,是一种前向神经网络。第一层的作用是将输入由非线性可分转变为线性可分,第二层一般是感知机类型的神经元层或ADALINE类型的神经元层。

    第一层计算

    计算过程

    对于只有一个两维的输入(p1, p2)而言,假定函数的中心点C1和C2已知(同样假设只有两个中心),利用高斯函数作为径向基函数,如果高斯函数的标准差σ1和σ2已知,那么第一层的输出即为:

    计算过程为:

    1. 计算由样本(p1,p2)组成的点到中心C1的距离r1,通过高斯径向基函数投影为Φ1
    2. 同理计算到到C2的距离投影到Φ2.

    中心C和标准差σ的确定

    上述过程假定中心C和标准差σ是已知的,实际上很多任务中是需要学习这两个量的,对于中心C,我们一般采用kmeans聚类算法来确定,因此聚类的中心点数量k也是一个超参。而σ的确定也非常简单,即以到聚类中心点的距离(平方根距离)最近的前k个样本的聚类的均值为σ,之后每个σ就都确定了。

    还有一种方法来确定C和σ,就是认为C和σ是可学习的参数,利用梯度下降来更新学习C和σ。后面的代码例子中将利用梯度来学习C和σ。

    第二层计算

    感知机和ADALINE

    对于第一层输出p(假设为5维向量),其输出为线性映射:

    [a = hardlim(Wp + b) ]

    其中W为1x5矩阵,b为1x1常量,harddim为sgn函数:

    [egin{equation} sgn(x) = egin{cases} 1,& x>0 \ 0,& x=0\ -1,& x<0 end{cases} end{equation} ]

    其中感知机和ADALINE其实有一些不同点,虽然前向过程的purelin恒等函数看起来没啥用(只是形式上要走个激活函数),但两者在更新参数时使用的标签是不同的,感知机是用离散的标签作为gt来更新前面的参数,而ADALINE则是直接根据加权求和的结果,也就是连续值来更新前面的参数,具体可以见下图:

    Coding

    本文仅以高斯径向基函数,第二层为感知机模型,利用梯度下降算法更新参数为例来写一个RBF神经网络的Demo。(求梯度的公式感觉自己推就太麻烦了,有自动求导为啥不用.)

    Loss:

    测试拟合情况:

    import torch
    import torch.nn as nn
    import numpy as np
    import torch.optim as optim
    from matplotlib import pyplot as plt
    class RBF(nn.Module):
        def __init__(self,input_dim = 5,k = 3):
            super(RBF,self).__init__()
            self.k = k
            self.C = nn.Parameter(torch.randn(1,k,input_dim)) # (n,k,5)
            self.sigma = nn.Parameter(torch.randn(1,k)) # (n,k)
            self.w = nn.Parameter(torch.randn(1,1,k)) # (n,1,k)
            self.b = nn.Parameter(torch.randn(1,1,1)) # (n,1,1)
            self.tanh = nn.Tanh()
        def forward(self,x):#(n,5)
            r = torch.sqrt(torch.sum((x.view(-1,1,5) - self.C)**2,dim = -1)) # (n,k)
            phi = torch.exp(-r**2/(2*self.sigma**2)).unsqueeze(-1) # (n,k,1)
            return self.tanh(self.w @ phi + self.b).squeeze(-1)
    
    
    
    if __name__ == "__main__":
        batch_size = 4
        k = 70
        input_dim = 5
        num_epochs = 300
        x_train = torch.rand(batch_size * 160,input_dim) * 2
        y_train = torch.FloatTensor(torch.sin(torch.sum(x_train,dim = -1,keepdim=True)))
        #y_train[(x_train[:,0] > 0.5) & (x_train[:,2] < 0.5)] = 0
        
        model = RBF(input_dim,k)
        optimizer = optim.Adam(model.parameters(),lr = 1e-3)
        criterion = nn.MSELoss()
        
        loss_curve = []
        for epoch in range(num_epochs):
            running_loss = 0.
            for i in range(160):
                x = x_train[i*batch_size:(i+1)*batch_size]
                y = y_train[i*batch_size:(i+1)*batch_size]
                
                pred = model(x)
                loss = criterion(pred,y)
    
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
    
                running_loss += loss
            print("loss: {}".format(running_loss / 160))
            loss_curve.append(running_loss / 160)
        x_test = torch.rand(160,input_dim)*2
        
        y_test = torch.FloatTensor(torch.sin(torch.sum(x_test,dim = -1,keepdim=True)))
        
        model.eval()
        with torch.no_grad():
            y_pred = model(x_test)
        y_test = y_test[indices]
        y_pred = y_pred[indices]
        plt.plot(y_test.squeeze(1).numpy())
        plt.plot(y_pred.squeeze(1).numpy())
        #plt.plot(loss_curve, label='train_loss')
        plt.show()
    
  • 相关阅读:
    python isinstance函数 判断元素是否是字符串、int型、float型
    Day04 list(列表)
    Day 05 Dict字典
    Python的简介
    DAY7 字符编码和文件操作
    DAY6 元组、字典与集合
    DAY5 基本数据类型及内置方法
    DAY4 if、while和for
    DAY3 数据类型与运算符
    DAY2 初识python
  • 原文地址:https://www.cnblogs.com/aoru45/p/12410545.html
Copyright © 2020-2023  润新知