pytorch基础操作(五)多层感知机的实现

news2024/11/27 8:39:33

1、多层感知机

1、激活函数的引入

这个多层感知机有4个输⼊,3个输出,其隐藏层包含5个隐藏单元。输⼊层不涉及任何计算,因此使⽤此⽹络产⽣输出只需要实现隐藏层和输出层的计算。因此,这个多层感知机中的层数为2。注意,这两个层都是全连接的。每个输⼊都会影响隐藏层中的每个神经元,⽽隐藏层中的每个神经元⼜会影响输出层中的每个神经元。
在这里插入图片描述
形式上,我们按如下⽅式计算单隐藏层多层感知机的输出 O
在这里插入图片描述
上⾯的隐藏单元由输⼊的仿射函数给出,⽽输出(softmax操作前)只是隐藏单元的仿射函数。仿射函数的仿射函数本⾝就是仿射函数,但是我们之前的线性模型已经能够表⽰任何仿射函数。
在这里插入图片描述
为了发挥多层架构的潜⼒,我们还需要⼀个额外的关键要素:在仿射变换之后对每个隐藏单元应⽤⾮线性的激活函数(activation function)σ

激活函数的输出(例如,σ(·))被称为活性值(activations),有了激活函数,就不可能再将我们的多层感知机退化成线性模型
在这里插入图片描述

2、常见的激活函数

(1)ReLU函数

最受欢迎的激活函数是 修正线性单元 (Rectified linear unit,ReLU), 因为它实现简单,同时在各种预测任务中表现良好。

给定元素x,ReLU函数被定义为该元素与0的最大值:

通俗地说,ReLU函数通过将相应的活性值设为0(激活函数的输出被称为活性值(activations)),仅保留正元素并丢弃所有负元素。

'''
1、ReLU函数

画出函数的曲线图。 正如从图中所看到,激活函数是分段线性的。
'''
import PlotFig as pf
import torch
%matplotlib inline


x = torch.arange(-8.0, 8.0, 0.1, requires_grad=True)

y = torch.relu(x)

pf.plot(x.detach(), y.detach(),'x', 'relu(x)',figsize=(5,2.5))

在这里插入图片描述

from matplotlib import pyplot as plt
from matplotlib_inline import backend_inline


def use_svg_display():
    """使用svg格式在Jupyter中显示绘图"""
    backend_inline.set_matplotlib_formats('svg')


def set_figsize(figsize=(3.5, 2.5)):
    """设置matplotlib的图表大小"""
    use_svg_display()
    plt.rcParams['figure.figsize'] = figsize


def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
    """设置matplotlib的轴"""
    axes.set_xlabel(xlabel)
    axes.set_ylabel(ylabel)
    axes.set_xscale(xscale)
    axes.set_yscale(yscale)
    axes.set_xlim(xlim)
    axes.set_ylim(ylim)
    if legend:
        axes.legend(legend)
    axes.grid()

def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
         ylim=None, xscale='linear', yscale='linear',
         fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
    """绘制数据点"""
    if legend is None:
        legend = []

    set_figsize(figsize)
    axes = axes if axes else plt.gca()

    # 如果X有一个轴,输出True
    def has_one_axis(X):
        return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
                and not hasattr(X[0], "__len__"))

    if has_one_axis(X):
        X = [X]
    if Y is None:
        X, Y = [[]] * len(X), X
    elif has_one_axis(Y):
        Y = [Y]
    if len(X) != len(Y):
        X = X * len(Y)
    axes.cla()
    for x, y, fmt in zip(X, Y, fmts):
        if len(x):
            axes.plot(x, y, fmt)
        else:
            axes.plot(y, fmt)
    set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
# 绘制ReLU函数的导数。
'''
当输入为负时,ReLU函数的导数为0,而当输入为正时,ReLU函数的导数为1。
注意,当输入值精确等于0时,ReLU函数不可导。 在此时,我们默认使用左侧的导数,即当输入为0时导数为0。


使⽤ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。
这使得优化表现得更好,并且ReLU减轻了困扰以往神经⽹络的梯度消失问题
'''
y.backward(torch.ones_like(x), retain_graph=True)

pf.plot(x.detach(), x.grad,'x', 'grad of  relu(x)',figsize=(5,2.5))

在这里插入图片描述

(2)Sigmoid函数

sigmoid函数将输⼊变换为区间(0, 1)上的输出
在这里插入图片描述
当我们想要将输出视作⼆元分类问题的概率时,sigmoid仍然被⼴泛⽤作输出单元上的激活函数。
然⽽,sigmoid在隐藏层中已经较少使⽤,它在⼤部分时候被更简单、更容易训练的ReLU所取代。

'''
2、Sigmoid函数
'''

# 注意,当输⼊接近0时,sigmoid函数接近线性变换。
y =  torch.sigmoid(x)
pf.plot(x.detach(), y.detach(),'x', 'sigmod(x)',figsize=(5,2.5))

在这里插入图片描述
导数:
在这里插入图片描述

'''
sigmoid函数的导数为: sigmoid(x) (1 − sigmoid(x)).

sigmoid函数的导数图像如下所⽰。
注意,当输⼊为0时,sigmoid函数的导数达到最⼤值0.25;⽽输⼊在任⼀⽅向上越远离0点时,导数越接近0。
'''
# 清除以前的梯度
x.grad.data.zero_()
y.backward(torch.ones_like(x),retain_graph=True)
pf.plot(x.detach(), x.grad, 'x', 'grad of sigmoid', figsize=(5, 2.5))

在这里插入图片描述

(3)tanh函数

tanh(双曲正切)函数能将其输⼊压缩转换到区间(-1, 1)上
在这里插入图片描述

'''
3、tanh函数

tanh(双曲正切)函数能将其输⼊压缩转换到区间(-1, 1)上


'''
y =  torch.tanh(x)
pf.plot(x.detach(), y.detach(),'x', 'tanh(x)',figsize=(5,2.5))

在这里插入图片描述
导数:
在这里插入图片描述

#  导数为1 − tanh^2(x)
# 当输⼊接近0时,tanh函数的导数接近最⼤值1。
# 与我们在sigmoid函数图像中看到的类似,输⼊在任⼀⽅向上越远离0点,导数越接近0。
x.grad.data.zero_()
y.backward(torch.ones_like(x),retain_graph=True)
pf.plot(x.detach(), x.grad, 'x', 'grad of tanh', figsize=(5, 2.5))

在这里插入图片描述

2、手动实现多层感知机

1、读取数据集

'''
  1、读取服装分类数据集 Fashion-MNIST
'''
import torchvision
import torch
from torch.utils import data
from torchvision import transforms


def get_dataloader_workers():
    """使⽤4个进程来读取数据"""
    return 4



def get_mnist_data(batch_size, resize=None):
    trans = [transforms.ToTensor()]

    if resize:
        # 还接受⼀个可选参数resize,⽤来将图像⼤⼩调整为另⼀种形状
        trans.insert(0,transforms.Resize(resize))
    trans = transforms.Compose(trans)

    mnist_train = torchvision.datasets.FashionMNIST(
        root='../data',train=True,transform=trans,download=False
    )


    mnist_test = torchvision.datasets.FashionMNIST(
        root='../data',train=False,transform=trans,download=False
    )
    # 数据加载器每次都会读取⼀⼩批量数据,⼤⼩为batch_size。通过内置数据迭代器,我们可以随机打乱了所有样本,从⽽⽆偏⻅地读取⼩批量
    # 数据迭代器是获得更⾼性能的关键组件。依靠实现良好的数据迭代器,利⽤⾼性能计算来避免减慢训练过程。
    train_iter = data.DataLoader(mnist_train,batch_size=batch_size,shuffle=True,num_workers=get_dataloader_workers())
    test_iter = data.DataLoader(mnist_test,batch_size=batch_size,shuffle=True,num_workers=get_dataloader_workers())

    return (train_iter,test_iter)


batch_size = 256

train_iter,test_iter = get_mnist_data(batch_size)

2、初始化模型参数

'''
  2、初始化模型参数

  服装分类数据集中的每个样本都是28×28的图像,一共含有10个类别。
  忽略像素之间的空间结构,我们可以将每个图像视为具有784个输⼊特征和10个类的简单分类数据集。

  ⾸先,我们将实现⼀个具有单隐藏层的多层感知机,它包含256个隐藏单元。

  注意,我们可以将这两个变量都视为超参数。通常,我们选择2的若⼲次幂作为层的宽度。
  注意,对于每⼀层我们都要记录⼀个权重矩阵和⼀个偏置向量
'''
from torch import nn
num_inputs, num_hiddens, num_outputs = 784, 256, 10


 # nn.Parameter可以看作是一个类型转换函数,将一个不可训练的类型 Tensor 转换成可以训练的类型 parameter ,并将这个 parameter 绑定到这个module
# 里面(net.parameter() 中就有这个绑定的 parameter,所以在参数优化的时候可以进行优化),所以经过类型转换这个变量就变成了模型的一部分,
# 成为了模型中根据训练可以改动的参数。使用这个函数的目的也是想让某些变量在学习的过程中不断的修改其值以达到最优化。

W1 = nn.Parameter(
    torch.randn(num_inputs,num_hiddens,requires_grad=True) * 0.01
)

b1 = nn.Parameter(
    torch.zeros(num_hiddens,requires_grad=True)
)

W2 = nn.Parameter(
    torch.randn(num_hiddens,num_outputs,requires_grad=True) * 0.01
)

b2 = nn.Parameter(
    torch.zeros(num_outputs,requires_grad=True)
)

params = [W1, b1, W2, b2]

3、激活函数

'''
  3、激活函数

  实现ReLU激活函数
'''
def relu(X):
    a = torch.zeros_like(X)
    return torch.max(X,a)

4、定义模型

'''
  4、定义模型

  因为我们忽略了空间结构,所以我们使⽤reshape将每个⼆维图像转换为⼀个⻓度为num_inputs的向量。
'''
def net(X):
    X = X.reshape((-1,num_inputs))
    H = relu(X@W1 + b1)
    return (H@W2 + b2)

5、loss函数

'''
  5、loss函数

  我们直接使⽤⾼级API中的内置函数来计算softmax和交叉熵损失
'''
loss = nn.CrossEntropyLoss(reduction='none')

6、训练

'''
  6、训练
  多层感知机的训练过程与softmax回归的训练过程完全相同
'''
# 将迭代周期数设置为10,并将学习率设置为0.1
num_epochs = 10
lr = 0.1

# 梯度下降
updater = torch.optim.SGD(params,lr=lr)

# 和softmax回归一样训练过程
import EpochTrainClass as e_train

e_train.train_ch3(net,train_iter,test_iter,loss,num_epochs,updater)

在这里插入图片描述

EpochTrainClass


import torch
from AccumulatorClass import Accumulator


def accuracy(y_hat, y):
    """计算预测正确的数量"""
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
         y_hat = y_hat.argmax(axis=1)
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())



def evaluate_accuracy(net,data_iter):
    """计算在指定数据集上模型的精度"""
    if isinstance(net,torch.nn.Module):
        # 将模型设置为评估模式
        net.eval()
    metric = Accumulator(2)
    with torch.no_grad():
        for X,y in data_iter:
            metric.add(accuracy(net(X),y), y.numel())

    return metric[0] / metric[1]

def epoch_train(net,train_iter,loss,updater):
    # 将模型设置为训练模式
    if isinstance(net,torch.nn.Module):
        net.train()

    # 指标:训练损失总和,训练准确度总和,样本数
    metric = Accumulator(3)
    for X,y in train_iter:
        # 计算梯度,并更新参数
        y_hat = net(X)
        l = loss(y_hat, y)

        if isinstance(updater, torch.optim.Optimizer):
            # 使用pytorch内置的优化器和损失函数
            updater.zero_grad()
            l.mean().backward()
            updater.step()
        else:
            # 使用定制的优化器和损失函数
            l.sum().backward()
            updater(X.shape[0])

        metric.add(
            float(l.sum()),
            accuracy(y_hat,y),
            y.numel()
        )

    # 返回训练损失和训练精度
    return (metric[0] / metric[2],metric[1] / metric[2])

def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):
    for epoch in range(num_epochs):
        print(f"epoch: {epoch + 1}")
        train_metrics = epoch_train(net,train_iter,loss,updater)
        print(train_metrics[0],train_metrics[1])
        test_acc = evaluate_accuracy(net,test_iter)
        print(test_acc)

Accumulator

'''
定义⼀个实⽤程序类Accumulator,⽤于对多个变量进⾏累加
'''
class Accumulator():

    """在n个变量上累加"""
    def __init__(self, n):
        self.data = [0.0] * n


    def add(self, *args):
        self.data = [a + float(b) for a,b in zip(self.data, args)]


    def reset(self):
        self.data = [0.0] * len(self.data)

    def __getitem__(self,index):
        return self.data[index]

7、模型的预测

'''
7、模型的预测
'''
def get_fashion_mnist_labels(labels):
    """返回Fashion-MNIST数据集的⽂本标签"""
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]


def predict_ch3(net,test_iter, n=8):

    for X,y in test_iter:
        trues = get_fashion_mnist_labels(y[0:n])
        preds = get_fashion_mnist_labels(
        net(X).argmax(axis=1)[0:n]
    )

        print('trues:',trues)
        print('preds:',preds)
        break


predict_ch3(net,test_iter)

在这里插入图片描述

3、多层感知机简洁实现

'''
  1、读取服装分类数据集 Fashion-MNIST
'''
import torchvision
import torch
from torch import nn
from torch.utils import data
from torchvision import transforms


def get_dataloader_workers():
    """使⽤4个进程来读取数据"""
    return 4



def get_mnist_data(batch_size, resize=None):
    trans = [transforms.ToTensor()]

    if resize:
        # 还接受⼀个可选参数resize,⽤来将图像⼤⼩调整为另⼀种形状
        trans.insert(0,transforms.Resize(resize))
    trans = transforms.Compose(trans)

    mnist_train = torchvision.datasets.FashionMNIST(
        root='../data',train=True,transform=trans,download=False
    )


    mnist_test = torchvision.datasets.FashionMNIST(
        root='../data',train=False,transform=trans,download=False
    )
    # 数据加载器每次都会读取⼀⼩批量数据,⼤⼩为batch_size。通过内置数据迭代器,我们可以随机打乱了所有样本,从⽽⽆偏⻅地读取⼩批量
    # 数据迭代器是获得更⾼性能的关键组件。依靠实现良好的数据迭代器,利⽤⾼性能计算来避免减慢训练过程。
    train_iter = data.DataLoader(mnist_train,batch_size=batch_size,shuffle=True,num_workers=get_dataloader_workers())
    test_iter = data.DataLoader(mnist_test,batch_size=batch_size,shuffle=True,num_workers=get_dataloader_workers())

    return (train_iter,test_iter)


batch_size = 256

train_iter,test_iter = get_mnist_data(batch_size)
'''
2、初始化模型参数

与softmax回归相比,唯⼀的区别是我们添加了2个全连接层(之前我们只添加了1个全连接层)。

第⼀层是隐藏层,它包含256个隐藏单元,并使⽤了ReLU激活函数。第⼆层是输出层。
'''


# pytorch不会隐式调整输入的形状,因此在线性层前定义展平层(flatten),来调整网络输入的形状
net = nn.Sequential(
    nn.Flatten(),
    nn.Linear(784, 256),
    nn.ReLU(),
    nn.Linear(256, 10)
)


def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights)
'''
3、定义损失函数

'''

loss = nn.CrossEntropyLoss(reduction='none')
'''
4、梯度下降算法

我们使⽤学习率为0.1的⼩批量随机梯度下降作为优化算法。这与我们在线性回归例⼦中的相同,这说明了优化器的普适性
'''

trainer = torch.optim.SGD(net.parameters(), lr=0.1)
'''
5、训练
'''
import EpochTrainClass as e_train

num_epochs = 10
e_train.train_ch3(net,train_iter,test_iter,loss,num_epochs,trainer)

在这里插入图片描述

'''
6、模型的预测
'''
def get_fashion_mnist_labels(labels):
    """返回Fashion-MNIST数据集的⽂本标签"""
    text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
    return [text_labels[int(i)] for i in labels]


def predict_ch3(net,test_iter, n=8):

    for X,y in test_iter:
        trues = get_fashion_mnist_labels(y[0:n])
        preds = get_fashion_mnist_labels(
        net(X).argmax(axis=1)[0:n]
    )

        print('trues:',trues)
        print('preds:',preds)
        break


predict_ch3(net,test_iter)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/92194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小米盒子为什么搜不到电视家?电视安装包解析错误解决方案

不少的朋友在小米电视盒子上安装了美家市场软件商店后,却发现在市场里面没法安装想要的电视盒子直播软件,这是怎么回事呢?其实大部分原因是电视盒子机制的问题限制了安装,导致部分品牌电视盒子装软件时会弹出“无法安装”的提示。…

Mysql双主整理

目录 1. Mysql binlog参数配置 2. Mysql binlog查看详细内容 3. Mysql双主搭建 4. Mysql双主解决数据回环 4.1 双主同步测试一 4.1.1 测试总结 4.2 双主同步测试二 4.2.1 测试总结 4.3 双主同步测试三 4.3.1 测试总结 1. Mysql binlog参数配置 log-binmysql-bin 打…

水果FLStudio21.0.0软件最新版有哪些新增功能变化?

FL Studio(水果软件)21 引入更快、更精确的音频编辑、改进的内容发现、对 DAW 情绪的控制以及更多鼓舞人心的创意工具。FL Studio是一款功能非常强大的音乐创作编辑软件它就是FL Studio(水果软件)。使用FL Studio中文版可以轻松帮我们制作自己的音乐唱片,拥有强大且…

【ROS】HelloWord简单实现

C实现 1. 创建工作空间并初始化 创建工作目录demo01_ws,并在该文件夹下创建src文件夹 mkdir -p demo01_ws/src进入到该目录下 cd demo01_ws/初始化 catkin_make这时在demo01_ws目录下除了src文件夹外,多处了两个文件夹。 ![在这里插入图片描述](htt…

数字化门店转型| 水疗会所管理系统| 小程序搭建

水疗会所与沐足采耳、洗浴按摩等都属于休息享受型服务,是不少中年人的选择,一天的压力可以得到缓解,同时客单价一般在几百元左右,在水疗会所里可以洗澡蒸桑拿、桌游、乒乓球等,同时随着近些年来生活压力逐渐加大&#…

【C语言学习】详解二级指针

在学习数据结构时,通常会遇到调用函数无法对主函数中的全局变量进行有效的更改操作,这时我们就需要指针,但二级指针对于初学者而言有着一定的学习难度,本文通过代码结合实验调试来详细说明二级指针。 如果一个指针指向另一个指针&…

[附源码]Node.js计算机毕业设计高校图书服务系统Express

项目运行 环境配置: Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境:最好是Nodejs最新版,我…

Atcoder 前缀和优化DP Candies

Candies - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 思路: 考虑DP 状态设计: 首先,因为是线性DP,dp[i]是必不可少的 然后去考虑一下决策,看看是什么东西影响了决策 对于第 i 个位置&#xf…

stm32f767自举

仅作笔记 一,自举。 在M0,M3,M4内核中,是通过boot0和boot1两个引脚的电平组合来确定启动地址的,启动的介质可以是系统存储器,SRAM,主Flash等。 在M7内核中,是通过boot0的电平加 Fla…

Linux内核调试技术之动态调试

前言 使用printk的打印方式只能通过设置输出等级来进行控制,具备一定的局限性。在实际系统运行过程中,我们更希望能选择性地打开某些子系统或者模块的输出,为此内核提供了动态调试技术。内核中包括pr_debug、dev_dbg接口都使用了动态调试技术…

javax.crypto.BadPaddingException: Decryption error

问题描述 使用Postman调用Java api解密token时 token值为iRdLmVEYUUvoH1oDF2QhSVhJxXYMRCxzbtJsL01Iun2OLHY/FxNQOrAwF4Bj2cdp1vhsXt9BQtcxmiyuCvyi2Itl2qlvlCT6VwRM6UgQ5SBIiInGlLYCrzDfOoQ74zhxwW7M43vIuLs6W0y7Rt86uZgmAR8gYwMLfvGnRg 执行时报错如下: 原因分析…

Redis框架(十二):大众点评项目 阻塞队列+异步处理 实现秒杀优化

大众点评项目 阻塞队列异步处理 实现秒杀优化需求:阻塞队列异步处理 实现秒杀优化为什么使用异步处理?为什么使用阻塞队列?为什么使用Lua?业务逻辑及其实现原有逻辑代码 / 优化后逻辑代码完整优化业务代码原有优化业务代码总结Spr…

Traefik整理

entryPoints配置 defaultEntryPoints ["oneway"][entryPoints]# 代表traefik的监听端口为90[entryPoints.oneway]address ":90"#90端口接收到的请求先进行鉴权,traefik会先访问跳转到http://127.0.0.1:51001/t/test1进行权限验证[entryPoint…

如何使用加密sqlite数据库

如何使用加密sqlite数据库,起始有开源的sqlcipher 可以去开源网站搜索一下,如码云,github等,那么如何编译呢, 这是我的虚拟机版本和 config参数 然后就会生成Makefile 直接make即可生成 sqlcipher可执行程序&#xff…

有关Monaco的使用疑惑

前言 学习monaco editor已经有三个多月了。阅读了大部分的的文档,也看了很多相关文章,也调研了一些使用它做的大型开源项目。 一开始的疑惑已经逐渐解开,但随着学习的深入,也遇到了比较奇怪的问题。这篇文件就来聊一聊&#xff0…

软考考试多少分通过?

当然是45!45!45!而且是各科45! 初级和中级考两科 综合知识:考试时间为 150 分钟,笔试,选择题(上午 9:00-11:30)案例分析:考试时间为 90 分钟,笔…

Divide by Zero 2021 and Codeforces Round #714 (Div. 2) C. Add One

Problem - C - Codeforces 翻译: 给你一个整数𝑛。您必须对其应用𝑚操作。 在单个操作中,必须将该数字的每个数字𝑑替换为整数𝑑1的十进制表示形式。例如,在应用一次操作后,1912变…

安利一个Python大数据分析神器!

对于Pandas运行速度的提升方法,之前已经介绍过很多回了,里面经常提及Dask,很多朋友没接触过可能不太了解,今天就推荐一下这个神器。 1、什么是Dask? Pandas和Numpy大家都不陌生了,代码运行后数据都加载到…

项目里接入了MQ消息中间件以后,我摸鱼的时间更长了~

V-xin:ruyuanhadeng获得600页原创精品文章汇总PDF 一、前情回顾 之前给大家聊了一下,面试时如果遇到消息中间件这个话题,面试官上来可能问的两个问题: 你们的系统架构中为什么要引入消息中间件?系统架构中引入消息中…

零跑汽车股价终于盼来了期望

近期零跑股价上涨,给其它汽车产业带来了危机。9月29日,零跑汽车作为第四位登陆港股的新势力车企,终于胜利敲钟。但是,紧接着等待零跑的却是刷新新势力纪录的开盘破发。 继开盘首日暴跌33%之后,9月30日收盘,…