毕设(一):正则化极限学习机(RELM)、在线学习的极限学习机(OS-ELM)、带遗忘机制的在线学习极限学习机(FOS-ELM)

本文深入探讨极限学习机(ELM)及其变种RELM、OS-ELM和FOS-ELM的原理与实现,包括算法基础、公式解析及Python代码示例,适合于单一资产交易场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

终于要毕业了,毕业设计也做完了,我的毕设是《极限学习机和强化学习在单一资产交易中的应用》,本质上用以极限学习机为值函数逼近器的一类强化学习算法去对一个资产进行交易。既然毕设也做完了,大学生涯也要结束了,那在去工作之前将毕设的东西好好总结一下,也方便以后自己看。

算法基础

ELM

极限学习机ELM是一类Single-hidden Layer Feedforward Neural Network(SLFNs)算法,由Huang等基于 Moore-Penrose 广义逆的理论提出,主要针对SLFNs中存在的学习速率慢,迭代时间长,学习参数如学习步长、学习率需要人为提前设置等问题。与传统的神经网络学习算法相比,ELM只需要设置合适的隐层节点数,随机生成隐层所需所有参数,利用最小二乘法确定输出层权值。整个学习过程只需一步而无需多次更新隐层参数。正是因为ELM算法的快速学习能力以及较强的非线性逼近能力等特点,使得ELM在实际应用中受到了研究者们的青睐。例如ELM及改进算法被广泛应用于故障检测、时间序列预测、姿态识别、化学分析、医疗诊断、智能供电等领域。
如果说ELM有什么公式比较重要的话,那应该是T=HβT=H\betaT=Hββ=H†T\beta=H^\dag Tβ=HT。这里一个用以求得预测值TTT,一个用来求解输出权重β\betaβ。需要注意H†H^\dagHHHH广义逆
而RELM则是在标准ELM在ELM的二次型指标中引入l2l_2l2正则化项。省略掉推导过程的话,β\betaβ的求解公式将变成:
β=H†T=(HTH+gI) \beta = H^\dag T=(H^TH+gI) β=HT=(HTH+gI)
其中,ggg为用于调整正则化作用的权重系数,III为单位矩阵。

OS-ELM

在线学习的极限学习机和标准ELM之间的区别在于引入在线机制,这个机制的引入涉及到输出权重的更新,省略推导过程的话,当第k批样本到达时的β\betaβ更新方式:
βk=βk−1+PkHkT(Tk−Hkβk−1) \beta^{k}=\beta^{k-1}+P_kH^{T}_k(T_k-H_k\beta^{k-1}) βk=βk1+PkHkT(TkHkβk1)
其中,命名PkP_kPk为工作矩阵,为HHH的转置与HHH乘积的逆,初始化时,P0=(H0TH0)−1P_0=(H^T_0H_0)^{-1}P0=(H0TH0)1
其更新方式为:
Pk=(Pk−1−1+HkTHk)=Pk−1−Pk−1HkT(I+HkHkT)−1HkPk−1 \begin{aligned} P_k & =(P^{-1}_{k-1}+H^T_kH_k)\\ & =P_{k-1}-P_{k-1}H^T_k(I+H_kH^T_k)^{-1}H_kP_{k-1} \end{aligned} Pk=(Pk11+HkTHk)=Pk1Pk1HkT(I+HkHkT)1HkPk1
如果用标准的ELM进行学习,除了每次需要对已有的样本进行重新学习,这浪费了很多计算资源,而且需要记录下之前的样本的特征,当样本量增加到一定程度的时候,学习机都没来得及学习更新一批样本就来了,那学习机就根本学不下去了。但OS-ELM完成学习后由于无需对已有样本做后续工作,所以不需要记录下样本的特征,可以说节省了许多内存。

FOS-ELM

带遗忘机制的OS-ELM和OS-ELM之间的区别在于引入遗忘机制,用以消除过期数据对预测的影响。遗忘机制要求我们需要记录学习机内样本。FOS-ELM要求初始化时设定一个样本量,当超过这个量,学习机就会启动遗忘机制。如果未启动遗忘机制的话,FOS-ELM的β\betaβ的更新方式和OS-ELM一样。如果启动了遗忘机制,设待删除的样本为第lll批,对工作矩阵PkP_kPk有:
Pk=(∑i=k−l+1kHiTHi+HkTHk)−1=(Pk−1−1+HkTHk−Hk−lTHk−l)−1 \begin{aligned} P_k&=(\sum\limits_{i=k-l+1}^{k}H^T_iH_i+H^T_{k}H_{k})^{-1}\\ &=(P^{-1}_{k-1}+H^T_kH_{k}-H^T_{k-l}H_{k-l})^{-1} \end{aligned} Pk=(i=kl+1kHiTHi+HkTHk)1=(Pk11+HkTHkHklTHkl)1
那么β\betaβ的更新方式为:
βk=Pk(Pk−1βk+[−Hk−lHk]T[Tk−lTk])=Pk((Pk−1−[−Hk−lHk]T[Tk−lTk])βk−1+[−Hk−lHk]T[Tk−lTk])=βk−1+Pk[−Hk−lHk]T([Tk−lTk]−[Hk−lHk]βk−1) \begin{aligned} \beta^{k} & =P_{k}(P^{-1}_k\beta^{k}+\begin{bmatrix}-H_{k-l} \\H_{k}\end{bmatrix} ^{T}\begin{bmatrix}T_{k-l} \\T_{k}\end{bmatrix})\\ &=P_k((P^{-1}_k-\begin{bmatrix}-H_{k-l} \\H_{k}\end{bmatrix} ^{T}\begin{bmatrix}T_{k-l} \\T_{k}\end{bmatrix})\beta^{k-1}+\begin{bmatrix}-H_{k-l} \\H_{k}\end{bmatrix} ^{T}\begin{bmatrix}T_{k-l} \\T_{k}\end{bmatrix})\\ &=\beta^{k-1}+P_{k}\begin{bmatrix}-H_{k-l} \\H_{k}\end{bmatrix} ^{T}(\begin{bmatrix}T_{k-l} \\T_{k}\end{bmatrix}-\begin{bmatrix}H_{k-l} \\H_{k}\end{bmatrix}\beta^{k-1}) \end{aligned} βk=Pk(Pk1βk+[HklHk]T[TklTk])=Pk((Pk1[HklHk]T[TklTk])βk1+[HklHk]T[TklTk])=βk1+Pk[HklHk]T([TklTk][HklHk]βk1)

代码

以上就是三个算法最主要的一些公式,接下来模型的实现就直接上代码吧。同时为了开发的方便,我把三个模型写成了继承关系,其中RELM为OS-ELM的父类,OS-ELM为FOS-ELM的父类。

import numpy as np
from sklearn.preprocessing import OneHotEncoder


class RELM_HiddenLayer:

    """
        正则化的极限学习机
        :param x: 初始化学习机时的训练集属性X
        :param num: 学习机隐层节点数
        :param C: 正则化系数的倒数
    """

    def __init__(self, x, num, C=10):
        row = x.shape[0]
        columns = x.shape[1]
        rnd = np.random.RandomState()
        # 权重w
        self.w = rnd.uniform(-1, 1, (columns, num))
        # 偏置b
        self.b = np.zeros([row, num], dtype=float)
        for i in range(num):
            rand_b = rnd.uniform(-0.4, 0.4)
            for j in range(row):
                self.b[j, i] = rand_b
        self.H0 = np.matrix(self.softplus(np.dot(x, self.w) + self.b))
        self.C = C
        self.P = (self.H0.H * self.H0 + len(x) / self.C).I

    @staticmethod
    def sigmoid(x):
        """
            激活函数sigmoid
            :param x: 训练集中的X
            :return: 激活值
        """
        return 1.0 / (1 + np.exp(-x))

    @staticmethod
    def softplus(x):
        """
            激活函数 softplus
            :param x: 训练集中的X
            :return: 激活值
        """
        return np.log(1 + np.exp(x))

    @staticmethod
    def tanh(x):
        """
            激活函数tanh
            :param x: 训练集中的X
            :return: 激活值
        """
        return (np.exp(x) - np.exp(-x))/(np.exp(x) + np.exp(-x))

    # 回归问题 训练
    def regressor_train(self, T):
        """
            初始化了学习机后需要传入对应标签T
            :param T: 对应属性X的标签T
            :return: 隐层输出权值beta
        """
        all_m = np.dot(self.P, self.H0.H)
        self.beta = np.dot(all_m, T)
        return self.beta

    # 回归问题 测试
    def regressor_test(self, test_x):
        """
            传入待预测的属性X并进行预测获得预测值
            :param test_x:被预测标签的属性X
            :return: 被预测标签的预测值T
        """
        b_row = test_x.shape[0]
        h = self.softplus(np.dot(test_x, self.w) + self.b[:b_row, :])
        result = np.dot(h, self.beta)
        return result

    # 分类问题 训练
    def classifisor_train(self, T):
        """
            初始化了学习机后需要传入对应标签T
            :param T: 对应属性X的标签T
            :return: 隐层输出权值beta
        """
        if len(T.shape) > 1:
            pass
        else:
            self.en_one = OneHotEncoder()
            T = self.en_one.fit_transform(T.reshape(-1, 1)).toarray()
            pass
        all_m = np.dot(self.P, self.H0.H)
        self.beta = np.dot(all_m, T)
        return self.beta
        pass

    # 分类问题 测试
    def classifisor_test(self, test_x):
        """
            传入待预测的属性X并进行预测获得预测值
            :param test_x:被预测标签的属性X
            :return: 被预测标签的预测值T
        """
        b_row = test_x.shape[0]
        h = self.softplus(np.dot(test_x, self.w) + self.b[:b_row, :])
        result = np.dot(h, self.beta)
        result = [item.tolist().index(max(item.tolist())) for item in result]
        return result
        pass


class OS_DELM_HiddenLayer(RELM_HiddenLayer):
    """
        正则化的在线学习的极限学习机
        :param x: 初始化学习机时的训练集属性X
        :param num: 学习机隐层节点数
        :param C: 正则化系数的倒数
    """

    def __init__(self, x, num, C=10):
        super(OS_DELM_HiddenLayer, self).__init__(x, num, C=C)

    # 回归问题 在线学习
    def online_regressor_study(self, x, t):
        """
            在线学习模块
            :param x: 待学习训练集的属性X
            :param t: 待学习训练集的标签Y
        """
        if len(x.shape) == 1:
            x.reshape(1, -1)
        b_row = x.shape[0]
        H_k = np.matrix(self.softplus(np.dot(x, self.w) + self.b[:b_row, :]))
        self.P = np.linalg.pinv(self.P.I + H_k.H * H_k + b_row / self.C)
        self.beta = self.beta + self.P * H_k.H * (t - H_k * self.beta)

    # 分类问题 在线学习
    def online_classifisor_study(self, x, t):
        """
            在线学习模块
            :param x: 待学习训练集的属性X
            :param t: 待学习训练集的标签Y
        """
        if len(t.shape) > 1:
            pass
        else:
            t = self.en_one.transform(t.reshape(-1, 1)).toarray()
            pass
        self.online_regressor_study(x, t)
        pass


class FOS_DELM_HiddenLayer(OS_DELM_HiddenLayer):
    """
        :param x: 初始化学习机时的训练集属性X
        :param num: 学习机隐层节点数
        :param C: 正则化系数的倒数
        带遗忘机制的正则化的在线学习极限学习机
    """

    def __init__(self, x, num, C=10):
        super(FOS_DELM_HiddenLayer, self).__init__(x, num, C=C)

    def regressor_train(self, T):
        """
            这里之所以重写train方法是因为启动遗忘机制时需要用到将要被删除的标签的值
            :param T: 对应属性X的标签T
            :return: 隐层输出权值beta
        """
        self.T = T
        return super(FOS_DELM_HiddenLayer, self).regressor_train(T)

    def online_regressor_study(self, x, t):
        """
            在线学习模块,这里在线学习直接启动了遗忘机制
            :param x: 待学习训练集的属性X
            :param t: 待学习训练集的标签Y
        """
        self.more_than_k(x, t)

    def less_than_k(self, x, t):
        """
            在线学习模块,当学习机内部样本数量还没超过阈值时,依然使用在线学习的方式
            :param x: 待学习训练集的属性X
            :param t: 待学习训练集的标签Y
        """
        super(FOS_DELM_HiddenLayer, self).online_regressor_study(x, t)

    def more_than_k(self, x, t):
        """
            在线学习模块,当学习机内部样本数量超过阈值时,启动遗忘机制
            :param x: 待学习训练集的属性X
            :param t: 待学习训练集的标签Y
        """
        b_row = x.shape[0]
        if len(x.shape) == 1:
            b_row = 1
        H_k = np.matrix(self.softplus(np.dot(x, self.w) + self.b[:b_row, :]))
        T_lost = self.T[0: b_row]
        H_lost = self.H0[0: b_row]
        P_k = np.linalg.pinv(self.P + H_k.H * H_k - H_lost.H * H_lost + b_row / self.C)
        mid2 = np.transpose(np.row_stack((-H_lost, H_k)))
        mid3 = np.row_stack((T_lost, t))
        self.beta = self.beta + P_k * mid2 * (mid3 - np.row_stack((H_lost, H_k)) * self.beta)
        self.P = P_k
        self.H0 = np.row_stack((self.H0[b_row:], H_k))
        self.T = np.row_stack((self.T[b_row:], t))
        pass

在这里我预先写了三个激活函数,通过对比发现softplus函数的精度是最高的,如果有需要其实是可以将激活函数替换成其他函数的。

总结

以上就是3个ELM的实现。说真的,一开始做这个课题的时候拼命在网上找看OS-ELM的实现一直没找到,其实是很烦的。但是烦过以后自己动手一点点实现它其实是很有成就感的。ELM做股价预测来说,预测的精度和现有的很多模型的精度是相当的,大概也是在0.55左右。ELM属于我的毕设的第一部分,它将作为我的交易Agent的值函数逼近器。下一部分将会写毕设的第二部分强化学习(RL)的一些实现,应该会尽可能在上班前完成的,加油!!!

评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值