2020研究生数学建模E题--AlexNet深度网络解法(大雾能见度估计与预测)(含代码)

本文介绍了2020研究生数学建模E题,通过AlexNet深度网络解决大雾能见度估计问题。利用视频数据,经过数据预处理,构建并实现AlexNet模型,通过ReLU激活函数、局部响应归一化、Dropout和层叠池化等技术提高模型性能。实验结果显示模型准确率高,避免了过拟合。附有代码和模型评估。

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

一、E题赛题

2020研究生数学建模赛题链接:https://download.csdn.net/download/qq_35759272/13028941
第二题问题:
在这里插入图片描述

二、赛题分析

第二题的目的是让我们根据视频分析能见度大小。
大部分想到的是方法一
方法一:提取视频中的特征学习,将其与能见度数据简历关系即可。
如果仅采用单张图像,利用雾提取方法(其实就是分类方法,将雾分类出来,常用的包括决策数、支持向量机、神经网络等等),这类算法能够提取出雾的面积,但得不到厚度信息。
弊端:但是这种分析思路正如题目所说的问题:只选取少量视频、截取图像中的某些固有特征,未能有效利用图像的连续信息估计是不准的。
再分析:所以这里需要加入视频数据的连续信息,连续信息相对于单项图像而言能够反映变化的信息——雾霾浓度。
方法二:因此用非监督分类的方法进行雾浓度的划分,得出更为细致的特征信息,这样就能得出一系列图像信息。又因为视频设置是在固定位置进行的,因此整个场景中变化最大的应该是雾,将图像的变化信息进行提取,然后找到对应的能见度差距也是一种对应关系。

三、解题

3.1 数据预处理

和题目给个截图保持一致,用视频播放软件PotPlayer每15秒截图一次。雾霾浓度随时间短变化越来越高,可以分时间段,将图片雾霾浓度分为超大雾、大雾、中雾、小雾、消散五类,作为训练集和验证集的数据。
在这里插入图片描述

3.2 AlexNet深度网络

(1)AlexNet结构图:

在这里插入图片描述
简单解释:网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布。
要想知道每一层的大小怎么计算得到的,推荐看一下:卷积神经网络之AlexNet

(2)AlexNet结构细分图:

在这里插入图片描述

(4)各层的作用

<1>卷积层:获取图片特征值,主要获取图片的低频成分,也就是大雾浓度的变化值;
<2>全连接层:(fully connected layers,FC)在整个卷积神经网络中起到“分类器”的作用;
<3>池化层:降维、去除冗余信息、对特征进行压缩、简化网络复杂度、减小计算量、减小内存消耗;
<4>激活层:加入非线性因素的,将特征映射到高维的非线性区间进行解释,解决线性模型所不能解决的问题。

(5)Python+Tensorflow程序实现AlexNet网络
# -*- coding=UTF-8 -*-  
import tensorflow as tf  
# 输入数据  
import input_data  
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)  
# 定义网络超参数  
learning_rate = 0.001  
training_iters = 200000  
batch_size = 64  
display_step = 20  
# 定义网络参数  
n_input = 784  # 输入的维度  
n_classes = 10 # 标签的维度  
dropout = 0.8  # Dropout 的概率  
# 占位符输入  
x = tf.placeholder(tf.types.float32, [None, n_input])  
y = tf.placeholder(tf.types.float32, [None, n_classes])  
keep_prob = tf.placeholder(tf.types.float32)  
# 卷积操作  
def conv2d(name, l_input, w, b):  
    return tf.nn.relu(tf.nn.bias_add( \  
    tf.nn.conv2d(l_input, w, strides=[1, 1, 1, 1], padding='SAME'),b) \  
    , name=name)  
# 最大下采样操作  
def max_pool(name, l_input, k):  
    return tf.nn.max_pool(l_input, ksize=[1, k, k, 1], \  
    strides=[1, k, k, 1], padding='SAME', name=name)  
# 归一化操作  
def norm(name, l_input, lsize=4):  
    return tf.nn.lrn(l_input, lsize, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name=name)  
# 定义整个网络   
def alex_net(_X, _weights, _biases, _dropout):  
    _X = tf.reshape(_X, shape=[-1, 28, 28, 1]) # 向量转为矩阵  
    # 卷积层  
    conv1 = conv2d('conv1', _X, _weights['wc1'], _biases['bc1'])  
    # 下采样层  
    pool1 = max_pool('pool1', conv1, k=2)  
    # 归一化层  
    norm1 = norm('norm1', pool1, lsize=4)  
    # Dropout  
    norm1 = tf.nn.dropout(norm1, _dropout)  
   
    # 卷积  
    conv2 = conv2d('conv2', norm1, _weights['wc2'], _biases['bc2'])  
    # 下采样  
    pool2 = max_pool('pool2', conv2, k=2)  
    # 归一化  
    norm2 = norm('norm2', pool2, lsize=4)  
    # Dropout  
    norm2 = tf.nn.dropout(norm2, _dropout)  
   
    # 卷积  
    conv3 = conv2d('conv3', norm2, _weights['wc3'], _biases['bc3'])  
    # 下采样  
    pool3 = max_pool('pool3', conv3, k=2)  
    # 归一化  
    norm3 = norm('norm3', pool3, lsize=4)  
    # Dropout  
    norm3 = tf.nn.dropout(norm3, _dropout)  
   
    # 全连接层,先把特征图转为向量  
    dense1 = tf.reshape(norm3, [-1, _weights['wd1'].get_shape().as_list()[0]])   
    dense1 = tf.nn.relu(tf.matmul(dense1, _weights['wd1']) + _biases['bd1'], name='fc1')   
    # 全连接层  
    dense2 = tf.nn.relu(tf.matmul(dense1, _weights['wd2']) + _biases['bd2'], name='fc2') 
    # Relu activation  
    # 网络输出层  
    out = tf.matmul(dense2, _weights['out']) + _biases['out']  
    return out  
   
# 存储所有的网络参数  
weights = {  
    'wc1': tf.Variable(tf.random_normal([3, 3, 1, 64])),  
    'wc2': tf.Variable(tf.random_normal([3, 3, 64, 128])),  
    'wc3': tf.Variable(tf.random_normal([3, 3, 128, 256])),  
    'wd1': tf.Variable(tf.random_normal([4*4*256, 1024])),  
    'wd2': tf.Variable(tf.random_normal([1024, 1024])),  
    'out': tf.Variable(tf.random_normal([1024, 10]))  
}  
biases = {  
    'bc1': tf.Variable(tf.random_normal([64])),  
    'bc2': tf.Variable(tf.random_normal([128])),  
    'bc3': tf.Variable(tf.random_normal([256])),  
    'bd1': tf.Variable(tf.random_normal([1024])),  
    'bd2': tf.Variable(tf.random_normal([1024])),  
    'out': tf.Variable(tf.random_normal([n_classes]))  
}  
# 构建模型  
pred = alex_net(x, weights, biases, keep_prob)  
# 定义损失函数和学习步骤  
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))  
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)  
# 测试网络  
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))  
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))  
# 初始化所有的共享变量  
init = tf.initialize_all_variables()  
# 开启一个训练  
with tf.Session() as sess:  
    sess.run(init)  
    step = 1  
    # Keep training until reach max iterations  
    while step * batch_size < training_iters:  
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)  
        # 获取批数据  
        sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys, keep_prob: dropout})  
        if step % display_step == 0:  
            # 计算精度  
            acc = sess.run(accuracy, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})  
            # 计算损失值  
            loss = sess.run(cost, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 1.})  
            print "Iter " + str(step*batch_size) + ", Minibatch Loss= " + "{:.6f}".format(loss) + ", Training Accuracy= " + "{:.5f}".format(acc)  
        step += 1  
    print "Optimization Finished!"  
    # 计算测试精度  
    print "Testing Accuracy:", sess.run(accuracy, feed_dict={x: mnist.test.images[:256], y: mnist.test.labels[:256], keep_prob: 1.})  
(6)AlexNet网络解题(MATLAB)
%% 本程序由博客凌青羽:https://blog.csdn.net/qq_35759272/article/details/109252165改写
%% 加载数据集
unzip('MerchData.zip')
%unzip 提取zip文件的内容
%Location = 'E:\Image_Set';%使用自己的数据集进行训练
imds = imageDatastore('MerchData', ...%若使用自己的数据集,将其改为Location
    'IncludeSubfolders',true, ...
    'LabelSource','foldernames');
%imageDatastore 图像数据的数据存储   /...续行
%   imds = imageDatastore(location,Name,Value)
%   location-要包括在数据存储中的文件或文件夹
%   Name-相对组参数
%     'IncludeSubfolders'-子文件夹包含标记
%          ture or false  | 0 or 1  (逗号隔开)
%          ————指定ture可包含每个文件夹中的所有文件和子文件夹,指定false则仅包含每个文件夹中的文件
%      'FileExtensions'-图像文件扩展名
%      'AlternateFileSystemRoots'-备用文件系统根路径
%       'LabelSource'-提供标签数据的源
%             指定为以逗号分隔的对组,如果指定了'none',则Labels属性为空。如果指定了'foldernames',将根据文件夹名称分配标签并
%              存储在Labels属性中 

[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7,'randomized');%随机拆分imds中的文件,前70%放入imdsTrain中,剩余30%翻入imdsValidation中
%  splitEachLabel-按比例拆分ImageDatastor标签
%  [imds1,imds2] = splitEachLabel(imds,p)
%       可将imds中的图像文件拆分为两个新的数据存储,imds1和imds2.新的数据存储imds1包含每个标签前百分之p个文件,imds2中包含剩余的文件
 
numTrainImages = numel(imdsTrain.Labels);%numel数组中的元素数目

%随机显示数据集中的图像
% idx = randperm(numTrainImages,16);
% % randperm——随机置换
% %   p = randperm(n,k)返回行向量,其中包含1到n自检随机选择的k个唯一整数
% figure
% for i = 1:16
%     subplot(4,4,i)
%     I = readimage(imdsTrain,idx(i));
% %     img = readimage(imds,i)——从数据存储imds中读取地i个图像文件并返回图像数据img
%     imshow(I)
% end

%% 加载预训练网络
Alexnet_Train = alexnet;
%net.Layers   %展示这个网络架构,这个网络有5个卷积层和3个全连接层
inputSize = Alexnet_Train.Layers(1).InputSize;  
%  第一层是图像输入层,要求输入图像的尺寸为227*227*3 这里的3是颜色通道的数字

%% 替换最后三层
layersTransfer = Alexnet_Train.Layers(1:end-3);
% Extract all layers, exceptthe last three ,from the pretrained network
% 预处理网络的最后三层被配置为1000个类。这三层必须针对新的分类问题进行调整
numClasses = numel(categories(imdsTrain.Labels));%数据集中类的数目
layers = [
    layersTransfer
    fullyConnectedLayer(numClasses,'WeightLearnRateFactor',20,'BiasLearnRateFactor',20)
    softmaxLayer
    classificationLayer];
%    Transfer the layers to the new classification task by replacing the last three layers with a fully connected layer,
%a softmax layer, and a classification output layer. Specify the options of the new fully connected layer according 
%to the new data. Set the fully connected layer to have the same size as the number of classes in the new data. 
%To learn faster in the new layers than in the transferred layers, increase the WeightLearnRateFactor and 
%BiasLearnRateFactor values of the fully connected layer.
%     通过将最后三个图层替换为完全连接图层,softmax图层和分类输出图层,将图层转移到新的分类任务。根据新的数据指定新的完全连接层的
% 选项。将完全连接层设置为与新数据中的类数大小相同。要在新层中比传输层更快的学习,增加完全连接层的WeightLearnRateFactor 和 
% BiasLearnRateFactor的值

%% 本程序由博客凌青羽:https://blog.csdn.net/qq_35759272/article/details/109252165改写
%% 训练网络

%用于数据增强,增加数据量
%    The network requires input images of size 227-by-227-by-3, but the images in the image datastores have different sizes. 
% Use an augmented image datastore to automatically resize the training images. Specify additional augmentation operations 
% to perform on the training images: randomly flip the training images along the vertical axis, and randomly translate them up 
% to 30 pixels horizontally and vertically. Data augmentation helps prevent the network from overfitting and memorizing the exact details of the training images.  
%   这个网络要求的尺寸是227*227*3,但是在图像存储中的图像有不同的尺寸,使用增强数据存储自动调整训练图像大小。在训练图像中指定
% 额外的增强操作:沿着垂直轴随机翻转训练图像,水平和垂直随机移动30个像素单位
pixelRange = [-30 30];
imageAugmenter = imageDataAugmenter( ...
    'RandXReflection',true, ...
    'RandXTranslation',pixelRange, ...
    'RandYTranslation',pixelRange);
% imageDataAugmenter——配置图像数据扩充
% aug = imageDataAugmenter(Name,Value)
%  RandXReflection——左右方向的随机反射,当为真(ture/1)时每个图像都以50%的概率随机反射,当为假(falsw/0)时,不会反射图像
%  RandYReflection——上下方向的随机反射,当为真(ture/1)时每个图像都以50%的概率随机反射,当为假(falsw/0)时,不会反射图像
%  RandRotation——随机旋转
%       'RandRotation',[num1 num2]第二个元素必须大于等于第一个元素,角度从指定间隔内的连续均匀分布中随机选取
%  RandScale——均匀标度范围(应用于输入图像的均匀(各向同性)缩放范围)
%       'RandScale',[num1 num2]第二个元素必须大于等于第一个元素,比例因子从指定间隔内的连续均匀分布中随机选取
%  RandXScale——均匀标度范围(应用于输入图像的水平缩放范围)
%       'RandXScale',[num1 num2]第二个元素必须大于等于第一个元素,比例因子从指定间隔内的连续均匀分布中随机选取
%  RandYScale——均匀标度范围(应用于输入图像的垂直缩放范围)
%       'RandYScale',[num1 num2]第二个元素必须大于等于第一个元素,比例因子从指定间隔内的连续均匀分布中随机选取
%  RandXShear——水平剪切范围
%       'RandXShear',[num1 num2]第二个元素必须大于等于第一个元素,水平剪切角从指定间隔内的连续均匀分布中随机选取
%  RandYShear——垂直剪切范围
%       'RandYShear',[num1 num2]第二个元素必须大于等于第一个元素,垂直剪切角从指定间隔内的连续均匀分布中随机选取
%  RandXTranslation——水平转换范围
%       'RandXTranslation',[num1 num2]第二个元素必须大于等于第一个元素,水平平移距离从指定间隔内的连续均匀分布中随机选取
%  RandYTranslation——垂直转换范围
%       'RandYTranslation',[num1 num2]第二个元素必须大于等于第一个元素,垂直平移距离从指定间隔内的连续均匀分布中随机选取


augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain, ...
    'DataAugmentation',imageAugmenter);
% augmentedImageDatastore——将批处理转化为增强图像数据
% DataAugmentation——图像数据扩充

% To automatically resize the validation images without performing further data augmentation, use an augmented image datastore 
%without specifying any additional preprocessing operations.
%  自动调整验证图像大小而不进行其他数据增强。使用扩充图像数据存储而不指定其他预处理操作。
augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);


%   Specify the training options. For transfer learning, keep the features from the early layers of the pretrained network (the transferred layer weights). 
%To slow down learning in the transferred layers, set the initial learning rate to a small value. In the previous step, you increased the learning rate factors 
%for the fully connected layer to speed up learning in the new final layers. This combination of learning rate settings results in fast learning only in the new 
%layers and slower learning in the other layers. When performing transfer learning, you do not need to train for as many epochs. An epoch is a full training cycle 
%on the entire training data set. Specify the mini-batch size and validation data. The software validates the network every ValidationFrequency iterations during training.
%     指定训练选项,对于传输学习保留来自预训练网络早期层中的特征。为了延缓在传输层中的学习,将初始学习速率设置为一个小值。在前一步中
% 增加了完全连接层的学习因子去加速新的最终层中的学习。这种学习速率的结合会导致新层中学习速度加快,其他层中学习速度变慢。在进行转换学习时
% 你不需要这么多的时间段进行训练。一个时间段是整个训练数据集上的完全训练循环。指定最小批量和验证数据。软件在训练期间每次验证迭代都会验证网络
options = trainingOptions('sgdm', ...
    'MiniBatchSize',10, ...
    'MaxEpochs',6, ...
    'InitialLearnRate',1e-4, ...
    'ValidationData',augimdsValidation, ...
    'ValidationFrequency',3, ...
    'ValidationPatience',Inf, ...
    'Verbose',true,...
    'Plots','training-progress');
% trainingOptions——深度学习神经网络训练选项
% 语法——options = trainingOptions(solverName,Name,Value)
%      solverName——训练网络检算器
%            'sgdm'——使用随机梯度下降动量(SGDM)优化器。
%            'rmsprop'——使用RMSProp优化器
%             'adam'——使用adam优化器
%    绘图和显示
%       'plots'——在网络训练时显示的图
%           'none'or'default'    在训练时期不显示图
%           'taining-progress'    显示训练过程。这个图显示了最小批量损失和准确性,验证损失和准确性,和训练过程中的额外信息。对训练过程的更多信息,查看Monitor Deep Learning Training Progress.            
% Verbose——显示训练过程信息指示器
% MaxEpochs——最大训练周期数
%        用于训练的最大周期数,   'MaxEpochs',正整数             
% MiniBatchSize——最小批量的大小
%        用于每个训练迭代的小批量大小   'MiniBatchSize',正整数    小批量是训练集的一个子集,用于评估损失函数的梯度并更新权重
% ValidationData——训练期间用于验证的数据
% ValidationFrequency——网络验证频率
%        以迭代次数表示网络验证频率     'ValidationFrequency',正整数
% ValidationPatience——停止验证的patience
%          'ValidationPatience',inf or 正整数      若使用默认inf训练将在最大的epoch数后停止
% InitialLearnRate——初始学习率
%          'InitialLearnRate',正数    'sgdm'解算器的默认值为0.01'rmsprop' 'adam' 解算器的默认值为0.001.
%            如果学习率太低,那么培训需要很长时间,如果学习率太高那么训练可能达不到最佳结果或出现分歧



Train = trainNetwork(augimdsTrain,layers,options);
% trainNetwork——训练神经网络进行深度学习、

%% 本程序由博客凌青羽:https://blog.csdn.net/qq_35759272改写
%% 验证训练好的模型
[YPred,scores] = classify(Train,augimdsValidation);
% classify——使用经过训练的神经网络对数据进行分类
idx = randperm(numel(imdsValidation.Files),6);
% randperm——随机置换
%      p = randperm (n,k) 返回行向量,其中包含1到n之间随机选择k个唯一整数

%随机显示使用训练好的模型进行分类的图片及其标签和概率
figure
for i = 1:6
    subplot(2,3,i)
    I = readimage(imdsValidation,idx(i));
    imshow(I)
    label = YPred(idx(i));
    title(string(label) + "," + num2str(100*max(scores(idx(i),:)),3) + "%");
end


YValidation = imdsValidation.Labels;
accuracy = mean(YPred == YValidation);
disp(['accuracy:',num2str(accuracy)]); % 输出预测精度结果

%% 保存训练好的模型
save Alexnet_01 Train;


完整MATLAB程序和采集数据以及AlexNet工具包最终以链接形式上传,见评论区!!!

3.3 运行结果

(1)训练结果图
在这里插入图片描述
损失函数loss呈现递减趋势,最后接近于0;验证准确率呈现上升趋势,最后接近100%。
<1>训练周期
轮次:第6轮
历时:28秒
迭代:30次(每轮的迭代次数:5)
<2>验证:
频率:3次迭代
<3> 其他信息:
硬件资源:单GPU
学习率调度:常数
学习率:0.0001

(2)分类结果图
在这里插入图片描述
与测试集的分类完全符合,每一分类准确率都接近100%,效果很好,其实并不意外,因为数据集还没有过万,很容易达到高准确率。
:由于图片过大,截图不清楚,我尽力了,你们自己运行程序放到Word里面,会是清晰的图片的,单独截图看中间的两张图片是这样:
在这里插入图片描述

“中雾”,“大雾”是对图片预测的结果,“100%”、“91.9%”代表预测准确率。

四 模型评估/AlexNet网络优点

4.1 使用Relu作为激活函数

AlexNet成功使用ReLU作为CNN的激活函数,并验证其效果在较深的网络超过了Sigmoid函数(ReLU之前已经提出,在AlexNet才大放异彩),成功解决了Sigmoid在网络较深时的梯度弥散(消失)现象。
在这里插入图片描述

在这里插入图片描述

4.2 局部相应归一化(Local corresponding normalization)

ReLU具有的特性是,它不需要通过输入归一化来防止饱和。如果至少一些训练样本对ReLU产生了正输入,那么那个神经元上将发生学习。而局部响应归一化有助于泛化。

4.3 Dropout

训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。在AlexNet中主要是最后的几个全连接层使用了Dropout。
在这里插入图片描述

4.4 层叠池化

在LeNet中池化是不重叠的,即池化的窗口的大小和步长是相等的,如下
在这里插入图片描述
在AlexNet中使用的池化(Pooling)却是可重叠的,也就是说,在池化的时候,每次移动的步长小于池化的窗口长度。AlexNet池化的大小为3×3的正方形,每次池化移动步长为2,这样就会出现重叠。重叠池化可以避免过拟合,这个策略贡献了0.3%的Top-5错误率。与非重叠方案s=2,z=2相比,输出的维度是相等的,并且能在一定程度上抑制过拟合。

五 上传文件使用说明

评论区(全部文件)上传的文件如下:
在这里插入图片描述

(1)首先安装文件alexnet.mlpkginstall,安装文件如果失效,可以去官网下载。alexnet.mlpkginstall安装文件双击是运行不了的,要放到MATLAB软件里面,在软件里面双击打开:在这里插入图片描述
安装完成即可
(2)MerchData.zip是比赛的视频截图分类文件,不需要解压,博主已经在程序里面写了解压程序。
截图文件也可以单独在https://download.csdn.net/download/qq_35759272/13070685链接下载。
(3)运行AlexNet_test.m程序即可,结果类似上面图片。

附:

第三题解题——基于辅助车道线的大雾能见度估计模型
(1)对于机场视频可以采用——基于暗通道优先算法的能见度估计模型
文章链接:2020华为杯E题–基于暗通道优先算法的能见度估计模型(附代码)
(2)对于高速公路视频截图数据采用——基于辅助车道线的大雾能见度估计与预测模型
文章链接:2020华为杯E题–基于辅助车道线的大雾能见度估计与预测(附代码)
第四题解题——基于灰色预测的大雾能见度预测模型
解题文章链接:2020华为杯E题——基于灰色预测的大雾能见度预测模型(附代码)

!!!!!第一次参加数学建模的朋友,推荐浏览博客文章如何在数学建模比赛中稳拿奖——个人100%获奖经历分享

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌青羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值