BP 神经网络算法

神经网络模型之BP算法及实例分析 神经网络BP算法及预测实例 阅读详情

BP神经网络算法

  简介:BP(Back Propagation)网络是1986年由Rumelhart和McCelland为首的科学家小组提出,是一种按误差逆传播算法训练的多层前馈网络,是目前应用最广泛的神经网络模型之一。BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。它的学习规则是使用最速下降法,通过反向传播来不断调整网络的权值和阈值,使网络的误差平方和最小。BP神经网络模型拓扑结构包括输入层(input)、隐层(hide layer)和输出层(output layer)
  摘 要:BP神经网络算法是在BP神经网络现有算法的基础上提出的,是通过任意选定一组权值,将给定的目标输出直接作为线性方程的代数和来建立线性方程组,解得待求权,不存在传统方法的局部极小及收敛速度慢的问题,且更易理解。
  关键词:固定权值;gauss消元法;BP算法
  人工神经网络(artificial neural networks,ANN)系统是20世纪40年代后出现的,它是由众多的神经元可调的连接权值连接而成,具有大规模并行处理、分布式信息存储、良好的自组织自学习能力等特点,在信息处理、模式识别、智能控制及系统建模等领域得到越来越广泛的应用。尤其误差反向传播算法(Error Back-propagation Training,简称BP网络)可以逼近任意连续函数,具有很强的非线性映射能力,而且网络的中间层数、各层的处理单元数及网络的学习系数等参数可根据具体情况设定,灵活性很大,所以它在许多应用领域中起到重要作用。近年来,为了解决BP神经网络收敛速度慢、不能保证收敛到全局最小点,网络的中间层及它的单元数选取无理论指导及网络学习和记忆的不稳定性等缺陷,提出了许多改进算法。
  1 传统的BP算法简述
  BP算法是一种有监督式的学习算法,其主要思想是:输入学习样本,使用反向传播算法对网络的权值和偏差进行反复的调整训练,使输出的向量与期望向量尽可能地接近,当网络输出层的误差平方和小于指定的误差时训练完成,保存网络的权值和偏差。具体步骤如下:
  (1)初始化,随机给定各连接权[w],[v]及阀值θi,rt。
  (2)由给定的输入输出模式对计算隐层、输出层各单元输出
  bj=f(■wijai-θj) ct=f(■vjtbj-rt)
  式中:bj为隐层第j个神经元实际输出;ct为输出层第t个神经元的实际输出;wij为输入层至隐层的连接权;vjt为隐层至输出层的连接权。
  dtk=(ytk-ct)ct(1-ct) ejk=[■dtvjt] bj(1-bj)
  式中:dtk为输出层的校正误差;ejk为隐层的校正误差。
  (3)计算新的连接权及阀值,计算公式如下:
  vjt(n+1)=vjt(n)+?琢dtkbj wij(n+1)=wij(n)+?茁ejkaik
  rt(n+1)=rt(n)+?琢dtk θj(n+1)=θj(n)+?茁ejk
  式中:?琢,?茁为学习系数(0<?琢<1,0<?茁<1)。
  (4)选取下一个输入模式对返回第2步反复训练直到网络设输出误差达到要求结束训练。
  传统的BP算法,实质上是把一组样本输入/输出问题转化为一个非线性优化问题,并通过负梯度下降算法,利用迭代运算求解权值问题的一种学习方法,但其收敛速度慢且容易陷入局部极小,为此提出了一种新的算法,即高斯消元法。
  2 改进的BP网络算法
  2.1 改进算法概述
  此前有人提出:任意选定一组自由权,通过对传递函数建立线性方程组,解得待求权。本文在此基础上将给定的目标输出直接作为线性方程等式代数和来建立线性方程组,不再通过对传递函数求逆来计算神经元的净输出,简化了运算步骤。没有采用误差反馈原理,因此用此法训练出来的神经网络结果与传统算法是等效的。其基本思想是:由所给的输入、输出模式对通过作用于神经网络来建立线性方程组,运用高斯消元法解线性方程组来求得未知权值,而未采用传统BP网络的非线性函数误差反馈寻优的思想。
  2.2 改进算法的具体步骤
  对给定的样本模式对,随机选定一组自由权,作为输出层和隐含层之间固定权值,通过传递函数计算隐层的实际输出,再将输出层与隐层间的权值作为待求量,直接将目标输出作为等式的右边建立方程组来求解。
  现定义如下符号(见图1):x (p)输入层的输入矢量;y (p)输入层输入为x (p)时输出层的实际输出矢量;t (p)目标输出矢量;n,m,r分别为输入层、隐层和输出层神经元个数;W为隐层与输入层间的权矩阵;V为输出层与隐层间的权矩阵。具体步骤如下:
  (1)随机给定隐层和输入层间神经元的初始权值wij。
  (2)由给定的样本输入xi(p)计算出隐层的实际输出aj(p)。为方便起见将图1网络中的阀值写入连接权中去,令:隐层阀值θj=wnj,x(n)=-1,则:
  aj(p)=f(■wijxi(p)) (j=1,2…m-1)。
  (3)计算输出层与隐层间的权值vjr。以输出层的第r个神经元为对象,由给定的输出目标值tr(p)作为等式的多项式值建立方程,用线性方程组表示为:
  a0(1)v1r+a1(1)v2r+…+am(1)vmr=tr(1)a0(2)v1r+a1(2)v2r+…+am(2)vmr=tr(2) ……a0(p)v1r+a1(p)v2r+…+am(p)vmr=tr(p) 简写为: Av=T
  为了使该方程组有唯一解,方程矩阵A为非奇异矩阵,其秩等于其增广矩阵的秩,即:r(A)=r(A┊B),且方程的个数等于未知数的个数,故取m=p,此时方程组的唯一解为: Vr=[v0r,v2r,…vmr](r=0,1,2…m-1)
  (4)重复第三步就可以求出输出层m个神经元的权值,以求的输出层的权矩阵加上随机固定的隐层与输入层的权值就等于神经网络最后训练的权矩阵。
  3 计算机运算实例
  现以神经网络最简单的XOR问题用VC编程运算进行比较(取神经网络结构为2-4-1型),传统算法和改进BP算法的误差(取动量因子α=0.001 5,步长η=1.653)
算法C++版代码:
#ifndef BP_H
#define BP_H
class BpNet
{
private:
    int _nInput;            //输入层节点个数
    int _nHide;             //隐含层节点个数
    int _nOutput;           //输出层节点个数
   
    double **_pplfWeight1;  //输入层-隐含层权系数
    double **_pplfWeight2;  //隐含层-输出层权系数
   
    double *_plfHideIn, *_plfHideOut;       //隐含层的网络输入和输出
    double *_plfOutputIn, *_plfOutputOut;   //输出层的网络输入和输出
   
private:
    double (*f)(double);    //激活函数
   
public:
    /**
    构造函数,创建一个未经训练的Bp网络
    param nInput 输入层节点个数
    param nHide 隐含层节点个数
    param nOutput 输出层节点个数
    */
    BpNet(int nInput, int nHide, int nOutput);
   
    /**
    析构函数,销毁已有的Bp网络
    */
    virtual ~BpNet();
   
    /**
    通过多组正例,对Bp网络进行训练
    param pplfInput 正例的输入
    param pplfDesire 正例的理想输出
    返回值 训练是否收敛
    */
    bool Train(int n, double **pplfInput, double **pplfDesire);
   
    /**
    使用当前的Bp网络对指定模式进行分类,分类的结果存储到plfOutput中
    param plfInput 待分类的模式
    param plfOutput 分类的输出
    */
    void Classify(double plfInput[], double plfOutput[]);
};
#endif
#include "bp.h"
#include "memory.h"
#include "math.h"
#include "time.h"
#include "stdlib.h"
#include "stdio.h"
double sigmoid(double x)
{
    return 1 / (1 + exp(- x));
}
BpNet::BpNet(int nInput, int nHide, int nOutput)
{
    _nInput = nInput;
    _nHide = nHide;
    _nOutput = nOutput;
   
    srand((unsigned)time(NULL));
   
    _pplfWeight1 = new double *[_nInput];
    for (int i = 0; i < _nInput; i++)
    {
        _pplfWeight1[i] = new double [_nHide];
        for (int j = 0; j < _nHide; j++) _pplfWeight1[i][j] = rand() / (double)(RAND_MAX);
    }
   
    _pplfWeight2 = new double *[_nHide];
    for (int i = 0; i < _nHide; i++)
    {
        _pplfWeight2[i] = new double [_nOutput];
        for (int j = 0; j < _nOutput; j++) _pplfWeight2[i][j] = rand() / (double)(RAND_MAX);
    }
   
    _plfHideIn = new double[_nHide];
    _plfHideOut = new double[_nHide];
    _plfOutputIn = new double[_nOutput];
    _plfOutputOut = new double[_nOutput];
    f = sigmoid;    //使用sigmoid激活函数
}
BpNet::~BpNet()
{
    delete []_plfHideIn;
    delete []_plfHideOut;
    delete []_plfOutputIn;
    delete []_plfOutputOut;
    for (int i = 0; i < _nInput; i++) delete []_pplfWeight1[i];
    for (int i = 0; i < _nHide; i++) delete []_pplfWeight2[i];
    delete []_pplfWeight1;
    delete []_pplfWeight2;
}
void BpNet::Classify(double plfInput[], double plfOutput[])
{
    memset(_plfHideIn, 0, sizeof(double) * _nHide);
    memset(_plfHideOut, 0, sizeof(double) * _nHide);
    memset(_plfOutputIn, 0, sizeof(double) * _nOutput);
    memset(_plfOutputOut, 0, sizeof(double) * _nOutput);
   
    //输入层到隐含层的正向传播
    for (int i = 0; i < _nInput; i++)
        for (int j = 0; j < _nHide; j++)
            _plfHideIn[j] += plfInput[i] * _pplfWeight1[i][j];
    for (int j = 0; j < _nHide; j++) _plfHideOut[j] = (*f)(_plfHideIn[j]);
   
    //隐含层到输出层的正向传播
    for (int j = 0; j < _nHide; j++)
        for (int k = 0; k < _nOutput; k++)
            _plfOutputIn[k] += _plfHideOut[j] * _pplfWeight2[j][k];
    for (int k = 0; k < _nOutput; k++) _plfOutputOut[k] = (*f)(_plfOutputIn[k]);
   
    if (plfOutput != NULL)
        memcpy(plfOutput, _plfOutputOut, sizeof(double) * _nOutput);
}
bool BpNet::Train(int n, double **pplfInput, double **pplfDesire)
{
    const double a = 0.1;
    const double E = 0.01;
    double lfE = E + 1;
   
    //输入层-隐含层权系数增量
    double **pplfDeltaWeight1 = new double *[_nInput];
    for (int i = 0; i < _nInput; i++)
    {
        pplfDeltaWeight1[i] = new double [_nHide];
        memset(pplfDeltaWeight1[i], 0, sizeof(double) * _nHide);
    }
   
    //隐含层-输出层权系数增量
    double **pplfDeltaWeight2 = new double *[_nHide];
    for (int i = 0; i < _nHide; i++)
    {
        pplfDeltaWeight2[i] = new double[_nOutput];
        memset(pplfDeltaWeight2[i], 0, sizeof(double) * _nOutput);
    }
       
    int nCount = 0;
    while (lfE > E)
    {
        lfE = 0;
        //对每一个样本进行处理
        for (int i = 0; i < n; i++)
        {
            double *plfInput = pplfInput[i];        //样本输入
            double *plfDesire = pplfDesire[i];      //样本期望输出
       
            //计算样本实际输出plfOutput
            Classify(plfInput, NULL);
       
            //计算误差测度
            double lfEp = 0;
            for (int j = 0; j < _nOutput; j++)
                lfEp += (plfDesire[j] - _plfOutputOut[j]) * (plfDesire[j] - _plfOutputOut[j]);
            lfE += lfEp;
       
            //计算隐含层-输出层权系数增量
            double *plfChange2 = new double[_nOutput];
       
            for (int j = 0; j < _nOutput; j++)
                plfChange2[j] = _plfOutputOut[j] * (1 - _plfOutputOut[j]) * (plfDesire[j] - _plfOutputOut[j]);
            for (int j = 0; j < _nHide; j++)
                for (int k = 0; k < _nOutput; k++)
                    pplfDeltaWeight2[j][k] = a * _plfHideOut[j] * plfChange2[k];
            //计算输入层-隐含层权系数增量
            double *plfChange1 = new double[_nHide];
            memset(plfChange1, 0, sizeof(double) * _nHide);
            for (int j = 0; j < _nHide; j++)
            {
                for (int k = 0; k < _nOutput; k++)
                    plfChange1[j] += _pplfWeight2[j][k] * plfChange2[k];
                plfChange1[j] *= _plfHideOut[j] * (1 - _plfHideOut[j]);
            }
            for (int j = 0; j < _nInput; j++)
                for (int k = 0; k < _nHide; k++)
                    pplfDeltaWeight1[j][k] = a * plfInput[j] * plfChange1[k];
               
            delete []plfChange1;
            delete []plfChange2;
       
            //更新Bp网络权值
            for (int i = 0; i < _nInput; i++)
                for (int j = 0; j < _nHide; j++)
                    _pplfWeight1[i][j] += pplfDeltaWeight1[i][j];
            for (int i = 0; i < _nHide; i++)
                for (int j = 0; j < _nOutput; j++)
                    _pplfWeight2[i][j] += pplfDeltaWeight2[i][j];
        }
        nCount++;
        if (nCount % 10 == 0) printf("%d%8.5lf/n", nCount, lfE);
    }
           
    for (int i = 0; i < _nInput; i++) delete []pplfDeltaWeight1[i];
    for (int i = 0; i < _nHide; i++) delete []pplfDeltaWeight2[i];
    delete [] pplfDeltaWeight1;
    delete [] pplfDeltaWeight2;
    return true;
}
西瓜书5.5 编程实现BP神经网络——标准BP算法、累积BP算法 这里照着书上的公式,实现了一下标准BP算法,和累积BP算法,BP是error Back Propagation的意思,误差逆传播。BP网络通常是指用BP算法训练的多层前馈神经网络。代码是照着书本公式自己写的,没有参考网上的其他版本。 数据和代码地址:https://github.com/qdbszsj/BP 具体的理论证明和公式推导,见西瓜书P101-104。这里重点说一下我的数据处理和一些代 阅读详情

相关推荐

神经网络中BP算法的原理与用Python实现源码

(1)什么是梯度下降和链式求导法则 1.梯度下降 假设我们有一个函数J(w),如下图所示。 现在,我们要求当w等于什么的时候,J(w)能够取到最小值。从图中我们知道最小值在初始位置的左边,也就意味着如果想要使J(w)最小,w的值需要减小。而初始位置的切线斜率a>0(也是该位置对应的导数大于0),w=w-eta*a(eta是学习率)就能让w的值减小,循环求导更新w直到J(w)取到最

Microstrong 1万+

神经网络入门

启发式算法,和图论还没有更新,我又来写神经网络了。以我浅薄的理解,简单介绍下,神经网络的入门。   神经网络的构成:从层级结构上讲,分为输入层,隐藏层和输出层。 细化结构:包含了神经元,神经元之间连接方式。 神经元结构:   在神经网络中,神经元接受输入并通过加权求和,经过激活函数得到输出。神经网络是要找到合适的权值,使得预测结果和真实结果之间的误差最小。权重矩阵,在网络训练的过程中是可学习的,也就是可以不断更改的。激活函数有:sgn,sigmoid,relu等。   另一种比较特殊的节点是—偏置节点。它

Pbw_666的博客 598

深入浅出BP神经网络算法的原理

深入浅出BP神经网络算法的原理

qq_45252766的博客 1万+

深度学习之径向基函数神经网络RBFNN

  径向基函数(Radial Basis Function)神经网络是具有唯一最佳逼近(克服局部极小值问题)、训练简洁、学习收敛速度快等良好性能的前馈型神经网络,目前已证明RBFNN能够以任意精度逼近任意连续的非线性网络,被广泛用于函数逼近、语音识别、模式识别、图像处理、自动控制和故障诊断等领域。 全局逼近网络:网络的一个或多个权值对任一输出都有影响。由于每次输入都要对所有权值进行修正,因此这...

liuy9803的博客 3万+

人工神经网络算法-BP算法原理

人工神经网络是由大量的神经元按照大规模并行的方式通过一定的拓扑结构连接而成的。按照一定的规则将神经元连接成神经网络,并使网络中各神经元的连接权按一定的规则变化,这样一来也就产生了各式各样的神经网络模型。 从几个方面进行分类: (1)按神经网络的拓扑结构可以分为反馈神经网络模型和前向神经网络模型; (2)按照神经网络模型的性能可分为连续型与离散型神经网络模型,确定型与随机型神经网络模型 (3

wj176623的专栏 1万+

mlp神经网络和bp神经网络,bp神经网络lm算法原理

1.初始权值不一样,如果一样,每次训练结果是相同的2.是3.在train之前修改权值,IW,LW,b,使之相同4.取多次实验的均值一点浅见,仅供参考训练误差是否降到一定范围内,比如1e-3,将训练样本回代结果如何,训练样本进行了预处理,比如归一化,而测试样本未进行同样的处理这样的归一化似有问题,我也认为“测试数据的归一化也用训练数据归一化时得出的min和max值”,请参考这个帖子测试数据带入训练好的神经网络误差当然不会达到1e-5,这是预测啊。若干次后,再给新的输入,神经网络就能正确的预测对于的输出。...

kfc67269的博客 2939

B站韩顺平java学习笔记(二十五)-- 正则表达式章节

正则表达式

LW_20180806的博客 6万+

bp神经网络优化算法对比,bp神经网络的优化算法

5.优化网络结构 ————————拓扑结构中网络层数、各层节点数、节点连接方式的不确定性——————————————构造法和剪枝法(权衰减法、灵敏度计算方法等)——————————————网络结构随样本空间进行变换,简化网络结构6混合智能算法————————与遗传算法、进化计算、人工免疫算法、蚁群算法、微粒群算法、————————模糊数学、小波理论、混沌理论。反向传播借助 链式法则 ,计算两个或两个以上复合函数的导数,将输出单元的梯度反向传播回输入单元,根据计算出的梯度,调整网络的可学习参数。

Supermen333的博客 1179

RNN:循环神经网络的基本知识

RNN(Recurrent Neural Network),又称循环神经网络。RNN是一类用于处理序列数据的神经网络,所谓的序列数据就是指这一些列的数据其前后的输入数据是有关联的,序列前面的数据特征有可能影响到序列后面的数据。如文字数据“我喜欢吃苹果”,在“我喜欢”的后面最有可能加的是名词或者动词,这就是所谓的序列数据中序列数据之间的影响作用。根据序列数据的特征,产生了RNN神经网络,RNN能处理序列的输入,发现前后输入的关系,对比起其它神经网络如CNN只能接受独立的输入,这是RNN与CNN...

qq_43160049的博客 4240

基于遗传算法的BP神经网络

基于遗传算法的BP神经网络 源码地址:https://github.com/Grootzz/GA-BP 介绍: 利用遗传算法并行地优化BP网络的权值和阈值,从而避免了BP网络在优化权值和阈值时陷入局部最优的缺点 背景: 这个项目的背景为客运量和货运量的预测 文件介绍: freightFlow.xlsx : 货运量数据集,前7列为影响货运量的因素,第8列为货运量 passengerFlow.xl...

Grootz的博客 7652

bp神经网络算法matlab程序,bp神经网络的matlab实现

trainlm训练函数最有效%net=newff(P,T,31,{'tansig','purelin'},'trainlm');%创建一个新的前向神经网络net_1=newff(minmax(P),[10,1],{'tansig','purelin'},'traingdm')%当前输入层权值和阈值{1,1}inputbias=net_1.b{1}%当前网络层权值和阈值{2,1}layerbias=net_1.b{2}%设置训练参数=50;这就是p到t的映射关系。...

shirley67269的博客 5065

神经网络浅讲:从神经元到深度学习

  神经网络是一门重要的机器学习技术。它是目前最为火热的研究方向--深度学习的基础。学习神经网络不仅可以让你掌握一门强大的机器学习方法,同时也可以更好地帮助你理解深度学习技术。   本文以一种简单的,循序的方式讲解神经网络。适合对神经网络了解不多的同学。本文对阅读没有一定的前提要求,但是懂一些机器学习基础会更好地帮助理解本文。   神经网络是一种模拟人脑的神经网络以期能够实现类人工智能的机器学...

weixin_30271335的博客 1万+

bp神经网络优化算法对比,提高bp神经网络精度

但当时并没有找到同样有技的含隐层的同培的学习规则。在BP 网络中,隐层节点数的选择非常重要,它不仅对建立的神经网络模型的性能影响很大,而且是训练时出现“过拟合”的直接原因,但是目前理论上还没有一种科学的和普遍的确定方法。神经网络不但具有处理数值数据的一般计算能力,而且还具有处理知识的思维、学习、记忆能力,它采用类似于“黑箱”的方法,通过学习和记忆,找出输入、输出变量之间的非线性关系(映射),在执行问题和求解时,将所获取的数据输入到已经训练好的网络,依据网络学到的知识进行网络推理,得出合理的答案与结果。

aifans_bert的博客 3669

基于遗传算法优化的BP神经网络

基于遗传算法的GA-BP神经网络(附matlab源码)

Lov1_BYS的博客 5335

CT图像重建SART算法matlab代码

CT图像重建经典SART算法,可以用于学习图像重建,适用于新手

5分钟搞懂双目相机标定:从棋盘格到3D点云的完整流程(附Python代码)

本文详细介绍了双目相机标定的完整流程,从棋盘格准备到3D点云生成,涵盖单目标定、双目标定、立体校正、视差计算等关键步骤。通过Python代码示例,帮助读者快速掌握双目立体视觉技术,实现高精度的3D重建。特别适合机器人导航、工业检测等应用场景。

weixin_29100399的博客 588

神经网络的BP算法推导详解

神经网络的BP算法推导详解一.BP算法的提出及其算法思想二.BP算法三.前馈计算的过程四.反向传播的计算 一.BP算法的提出及其算法思想 神经网络主要是由三个部分组成的,分别是:1) 网络架构 2) 激活函数 3) 找出最优权重值的参数学习算法. BP(back propagation)神经网络是1986年由Rumelhart和McClelland为首的科学家提出的概念,是一种按照误差逆向传播算法训练的多层前馈神经网络。 既然我们无法直接得到隐层的权值,能否先通过输出层得到输出结果和期望输出的误差来间接调

qq_43232556的博客 5174

用Verilog在FPGA上做个电子琴:从矩阵键盘到蜂鸣器的完整实现(附代码)

本文详细介绍了如何使用Verilog在FPGA上实现一个完整的电子琴系统,涵盖矩阵键盘扫描、音调生成和蜂鸣器驱动等核心模块。通过模块化设计和PWM调制技术,开发者可以构建一个可交互的音乐播放器,项目代码完整且易于扩展,适合FPGA初学者和数字逻辑设计爱好者实践。

weixin_29191669的博客 403

BP 神经网络算法原理

本篇文章主要根据《神经网络与机器学习》和《人工神经网络原理》两本书,对 BP 神经网络的数学推导过程做了一个总结,为自己进入深度学习打...

小糖同学的专栏 2426

本地部署gradle

在部署CAS构建执行包时,如果按照CAS的官方命令gradlew clean build,如果系统没安装过gradle,这个步骤将会从网上下载gradle,但是进度非常慢,耗时很长。为了更快地完成项目构建,我们可以直接在本地部署好gradle,节省一点时间。

益添的博客 780

肖特基二极管选型参数,结构原理,工艺与注意问题总结

肖特基二极管(Schottky Diode)是一种特殊的二极管,也被称为肖特基势垒二极管。它是利用金属与半导体接触形成的金属-半导体结原理制成的。与传统的PN结二极管相比,肖特基二极管具有更低的正向压降、更高的开关速度、更高的反向恢复时间以及更好的温度稳定性等特点。本文对肖特基二极管的工作原理,结构特点,工艺流程,选型参数及设计注意事项进行总结。

fydar的博客 812
上一篇: EAI_基础概念
下一篇: BPEL-基础概念
Debug_Today
博客等级 码龄19年 31粉丝 64原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值