38 深度学习(二):tensorflow基础介绍

news2024/11/16 9:53:28

文章目录

  • tensorflow基础介绍
    • 基础张量
    • 自定义损失函数
    • 自定义模型和激活函数
    • 图函数(略)
    • 自动求导机制
    • 自定义fit

tensorflow基础介绍

基础张量

import tensorflow as tf
import numpy as np
import pandas as pd

# constant是常量张量 不能进行再次assign改值
t = tf.constant([[1., 2., 3.], [4., 5.,6.]])

# 转换为numpy
print(t.numpy())

# 转换成列表
print(t.numpy().tolist())

# 调用加减法和numpy一样
# 数学函数就直接就是tf.math当中的函数,使用和numpy的那些一样
# 矩阵乘法用 @ 小老鼠

# 标量是没有维度的
t = tf.constant(2.718)
print(t.shape)

# ragged tensor 和 SparseTensor 个人觉得不用就行,一般来说没啥用,这边不介绍

print('-'*20)
# Variables 可变张量
v = tf.Variable([[1., 2., 3.], [4., 5.,6.]])
print(v)
print(v.value())

# 修改变量时要用assign,改变tensor内某个值,空间没有发生变化,效率高
# assign value
print(id(v))
v.assign(2*v)
print(id(v))
print(v.numpy())
print('-'*20)
v[0, 1].assign(42)  #取某个元素修改
print(v.numpy())
print('-'*20)
v[1].assign([7., 8., 9.])  #取某一行修改
print(v.numpy())
print(id(v))

输出:

[[1. 2. 3.]
 [4. 5. 6.]]
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
()
--------------------
<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=
array([[1., 2., 3.],
       [4., 5., 6.]], dtype=float32)>
tf.Tensor(
[[1. 2. 3.]
 [4. 5. 6.]], shape=(2, 3), dtype=float32)
135725893022432
135725893022432
[[ 2.  4.  6.]
 [ 8. 10. 12.]]
--------------------
[[ 2. 42.  6.]
 [ 8. 10. 12.]]
--------------------
[[ 2. 42.  6.]
 [ 7.  8.  9.]]
135725893022432

自定义损失函数

from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import numpy as np
import pandas as pd
import tensorflow as tf
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline


# 得到数据
# -----------------------------------------------------------------------------
housing = fetch_california_housing()
x_train_all, x_test, y_train_all, y_test = train_test_split(housing.data, housing.target, random_state = 7)
x_train, x_valid, y_train, y_valid = train_test_split(x_train_all, y_train_all, random_state = 11)
print(x_train.shape, y_train.shape)
print(x_valid.shape, y_valid.shape)
print(x_test.shape, y_test.shape)
scaler = StandardScaler()
x_train_scaled = scaler.fit_transform(x_train)
x_valid_scaled = scaler.transform(x_valid)
x_test_scaled = scaler.transform(x_test)
# -----------------------------------------------------------------------------

# 自定义损失函数 均方差
def customized_mse(y_true, y_pred):
    return tf.reduce_mean(tf.square(y_pred - y_true))


# m=tf.keras.losses.MeanSquaredError()  #用框架提供的对象
model = tf.keras.models.Sequential([
    tf.keras.layers.Dense(30, activation='relu',input_shape=x_train.shape[1:]),
    tf.keras.layers.Dense(1),
])

model.summary()

# 为了验证自定义损失是否正确
model.compile(loss=customized_mse, optimizer="sgd",metrics=["mean_squared_error"])
callbacks = [tf.keras.callbacks.EarlyStopping(patience=5, min_delta=1e-2)]

history = model.fit(x_train_scaled, y_train,validation_data = (x_valid_scaled, y_valid),epochs = 100,callbacks = callbacks)

def plot_learning_curves(history):
    pd.DataFrame(history.history).plot(figsize=(8, 5))
    plt.grid(True)
    plt.gca().set_ylim(0, 3)
    plt.show()
plot_learning_curves(history)

model.evaluate(x_test_scaled, y_test, verbose=0)

输出:

(11610, 8) (11610,)
(3870, 8) (3870,)
(5160, 8) (5160,)
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_2 (Dense)             (None, 30)                270       
                                                                 
 dense_3 (Dense)             (None, 1)                 31        
                                                                 
=================================================================
Total params: 301 (1.18 KB)
Trainable params: 301 (1.18 KB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________
Epoch 1/100
363/363 [==============================] - 3s 7ms/step - loss: 0.9562 - mean_squared_error: 0.9562 - val_loss: 0.7666 - val_mean_squared_error: 0.7666
Epoch 2/100
363/363 [==============================] - 2s 6ms/step - loss: 0.8993 - mean_squared_error: 0.8993 - val_loss: 0.4572 - val_mean_squared_error: 0.4572
Epoch 3/100
363/363 [==============================] - 2s 6ms/step - loss: 0.4234 - 

·······

Epoch 17/100
363/363 [==============================] - 2s 5ms/step - loss: 0.3475 - mean_squared_error: 0.3475 - val_loss: 0.3581 - val_mean_squared_error: 0.3581
Epoch 18/100
363/363 [==============================] - 2s 4ms/step - loss: 0.3458 - mean_squared_error: 0.3458 - val_loss: 0.3541 - val_mean_squared_error: 0.3541
Epoch 19/100
363/363 [==============================] - 1s 3ms/step - loss: 0.3453 - mean_squared_error: 0.3453 - val_loss: 0.3532 - val_mean_squared_error: 0.3532
图片见下
[0.35976365208625793, 0.35976365208625793]

在这里插入图片描述

自定义模型和激活函数

import tensorflow as tf
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline


# 得到数据
# -----------------------------------------------------------------------------
housing = fetch_california_housing()
x_train_all, x_test, y_train_all, y_test = train_test_split(housing.data, housing.target, random_state = 7)
x_train, x_valid, y_train, y_valid = train_test_split(x_train_all, y_train_all, random_state = 11)
print(x_train.shape, y_train.shape)
print(x_valid.shape, y_valid.shape)
print(x_test.shape, y_test.shape)
scaler = StandardScaler()
x_train_scaled = scaler.fit_transform(x_train)
x_valid_scaled = scaler.transform(x_valid)
x_test_scaled = scaler.transform(x_test)
# -----------------------------------------------------------------------------

# customized dense layer.
# -----------------------------------------------------------------------------
class CustomizedDenseLayer(keras.layers.Layer):
    def __init__(self, units, activation=None, **kwargs):
        self.units = units
        self.activation = keras.layers.Activation(activation)  #直接使用tf提供的 激活函数
        super().__init__(**kwargs)

    def build(self, input_shape):
        """构建所需要的参数,也就是kernel还有bias"""
        # x * w + b. x:[batch-size, num1] y:[batch-size, utils] 故:w:[num1,utils],b:[1,utils] 或者 使用[utils]直接和那些数组相加的效果也是一样的。
        # 使用均匀分布的方法去初始化kernel
        self.kernel = self.add_weight(name = 'kernel',shape = (input_shape[1], self.units),initializer = 'uniform',trainable = True)
        self.bias = self.add_weight(name = 'bias',shape = (self.units),initializer = 'zeros',trainable = True)

        #接着我们要继承父类的build
        super(CustomizedDenseLayer, self).build(input_shape)

    def call(self, x):
        """完成正向计算"""
        return self.activation(x @ self.kernel + self.bias)

# 自定义激活函数
customized_softplus = keras.layers.Lambda(lambda x : tf.math.log(1+tf.math.exp(x)))

#完全模仿dense来实现自定义层,因此input_shape传的和dense一致,只需要是特征数,父类Layer自动会转为
#二维的input_shape,然后再传递给build
model = keras.models.Sequential([
    CustomizedDenseLayer(30, activation='relu',input_shape=x_train.shape[1:]),  #这里传入的是特征数
    CustomizedDenseLayer(1,activation=customized_softplus),
])
# -----------------------------------------------------------------------------

model.summary()
model.compile(loss="mean_squared_error", optimizer="sgd")
callbacks = [keras.callbacks.EarlyStopping(patience=5, min_delta=1e-3)]

history = model.fit(x_train_scaled, y_train,validation_data = (x_valid_scaled, y_valid),epochs = 100,callbacks = callbacks)

def plot_learning_curves(history):
    pd.DataFrame(history.history).plot(figsize=(8, 5))
    plt.grid(True)
    plt.gca().set_ylim(0, 3)
    plt.show()
plot_learning_curves(history)

model.evaluate(x_test_scaled, y_test, verbose=0)

输出:

(11610, 8) (11610,)
(3870, 8) (3870,)
(5160, 8) (5160,)
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 customized_dense_layer_2 (  (None, 30)                270       
 CustomizedDenseLayer)                                           
                                                                 
 customized_dense_layer_3 (  (None, 1)                 31        
 CustomizedDenseLayer)                                           
                                                                 
=================================================================
Total params: 301 (1.18 KB)
Trainable params: 301 (1.18 KB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________
Epoch 1/100
363/363 [==============================] - 2s 4ms/step - loss: 1.2189 - val_loss: 0.6802
Epoch 2/100
363/363 [==============================] - 2s 4ms/step - loss: 0.5919 - val_loss: 0.5863
Epoch 3/100
363/363 [==============================] - 1s 4ms/step - loss: 0.5182 - val_loss: 0.5198

······

Epoch 33/100
363/363 [==============================] - 3s 7ms/step - loss: 0.3626 - val_loss: 0.3811
Epoch 34/100
363/363 [==============================] - 1s 4ms/step - loss: 0.3620 - val_loss: 0.3779
Epoch 35/100
363/363 [==============================] - 1s 4ms/step - loss: 0.3610 - val_loss: 0.3801
图片见下:
0.3835444152355194

在这里插入图片描述

图函数(略)

这个个人觉得好像没啥用,暂时先不介绍,后补。

自动求导机制

import tensorflow as tf


# 对常量没有办法进行求导计算
x1 = tf.constant(2.0)
x2 = tf.constant(3.0)
with tf.GradientTape() as tape:
    z1 = (x1 + 5) * (x2 ** 2)
dz1 = tape.gradient(z1, [x1, x2])
print(dz1)
print('-'*20)

# 对变量进行求导计算
x3 = tf.Variable(2.0)
x4 = tf.Variable(3.0)
with tf.GradientTape() as tape:
    z2 = (x3 + 5) * (x4 ** 2)
dz2 = tape.gradient(z2, [x3, x4])
print(dz2)
print('-'*20)

# 两个目标函数对一个变量求导数
x5 = tf.Variable(5.0)
with tf.GradientTape() as tape:
    z3 = 3 * x5
    z4 = x5 ** 2
    z5 = x5 ** 3
dz3 = tape.gradient([z3, z4, z5], x5)   #3+10+75
print(dz3)
print('-'*20)

# 求二阶导
#因为会执行多次,所以加入persistent
with tf.GradientTape(persistent=True) as outer_tape:
    with tf.GradientTape(persistent=True) as inner_tape:
        z6 = (x3 + 5) * (x4 ** 2)
    inner_grads = inner_tape.gradient(z6, [x3, x4]) # inner_grads是一个列表 
outer_grads = [outer_tape.gradient(inner_grad, [x3, x4])for inner_grad in inner_grads]
print(outer_grads)
del inner_tape
del outer_tape

输出:

[None, None]
--------------------
[<tf.Tensor: shape=(), dtype=float32, numpy=9.0>, <tf.Tensor: shape=(), dtype=float32, numpy=42.0>]
--------------------
tf.Tensor(87.99999, shape=(), dtype=float32)
--------------------
[[None, <tf.Tensor: shape=(), dtype=float32, numpy=6.0>], [<tf.Tensor: shape=(), dtype=float32, numpy=6.0>, <tf.Tensor: shape=(), dtype=float32, numpy=14.0>]]

自定义fit

import tensorflow as tf
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline


# 得到数据
# -----------------------------------------------------------------------------
housing = fetch_california_housing()
x_train_all, x_test, y_train_all, y_test = train_test_split(housing.data, housing.target, random_state = 7)
x_train, x_valid, y_train, y_valid = train_test_split(x_train_all, y_train_all, random_state = 11)
print(x_train.shape, y_train.shape)
print(x_valid.shape, y_valid.shape)
print(x_test.shape, y_test.shape)
scaler = StandardScaler()
x_train_scaled = scaler.fit_transform(x_train)
x_valid_scaled = scaler.transform(x_valid)
x_test_scaled = scaler.transform(x_test)
# -----------------------------------------------------------------------------


epochs = 100 #多少次
batch_size = 32
steps_per_epoch = len(x_train_scaled) // batch_size  # 一共要取多少次
print(steps_per_epoch)
optimizer = keras.optimizers.SGD()
metric = keras.metrics.MeanSquaredError()

#随机取数据,取出来32个样本
def random_batch(x, y, batch_size=32):
    idx = np.random.randint(0, len(x), size=batch_size)
    return x[idx], y[idx]

model = keras.models.Sequential([
    keras.layers.Dense(30, activation='relu',input_shape=x_train.shape[1:]),
    keras.layers.Dense(1),
])
print('-'*50)

#下面一部分相当于替代了fit函数

for epoch in range(epochs):#每一轮epochs训练所有的样本
    metric.reset_states()  #清空损失
    for step in range(steps_per_epoch):
        #随机取32个样本
        x_batch, y_batch = random_batch(x_train_scaled, y_train,batch_size)

        with tf.GradientTape() as tape:
            # 得到预测值 等价于model.predict 一般来说使用model的是大批量数据也就是train数据 而使用predict的是test数据,只是用于区分而已,实际上两个函数是一样的
            y_pred = model(x_batch)
            # 删减了值为1的维度,二阶张量,变为一阶张量 计算出来的y是[batch-size,1]而y_bacth是[batch-size]所以需要进行调整数据
            y_pred = tf.squeeze(y_pred, 1)
            # 计算损失
            loss = keras.losses.mean_squared_error(y_batch, y_pred)
            #计算均方误差
            metric(y_batch, y_pred)
        
        # 求梯度 即通过loss需要反向去更新参数
        grads = tape.gradient(loss, model.variables)
        # 梯度和变量绑定
        grads_and_vars = zip(grads, model.variables)
        # 更新,通过grads,去更新模型的model.variables,也就是更新了w,b
        optimizer.apply_gradients(grads_and_vars)
        # 打印,不要在循环内加print,影响\r
        p="Epoch "+str(epoch)+" train mse:"+str(metric.result().numpy())
        print(p, end='\r')
    #打换行的目的是为了新起一行显示
    print('') 
    #搞了一个epoch训练后,认为模型可以了,去验证集验证
    y_valid_pred = model(x_valid_scaled)
    y_valid_pred = tf.squeeze(y_valid_pred, 1)
    valid_loss = keras.losses.mean_squared_error(y_valid_pred, y_valid)
    print("\t", "valid mse: ", valid_loss.numpy())

输出:

(11610, 8) (11610,)
(3870, 8) (3870,)
(5160, 8) (5160,)
362
--------------------------------------------------
Epoch 0 train mse:1.3466285
	 valid mse:  0.5476390780096311
Epoch 1 train mse:0.45485455
	 valid mse:  0.4251055461379762
Epoch 2 train mse:0.412074
	 valid mse:  0.46565304912661426
Epoch 3 train mse:0.435362
	 valid mse:  0.40384912219474317

······

Epoch 97 train mse:0.32565653
	 valid mse:  0.32143461024556846
Epoch 98 train mse:0.34540302
	 valid mse:  0.3209666738097622
Epoch 99 train mse:0.3280668
	 valid mse:  0.3186309043590573

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

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

相关文章

【ETL工具】Datax-ETL-SqlServerToHDFS

&#x1f984; 个人主页——&#x1f390;个人主页 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;&#x1f341; 感谢点赞和关注 &#xff0c;每天进步一点点&#xff01;加油&#xff01;&…

lazada获得lazada商品详情 API 返回值说明

item_get-获得lazada商品详情 lazada.item_get 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;获取key和secret接入secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_sear…

德思特新闻 | 走进德思特——通过创新帮助客户成功

文章来源&#xff1a;德思特测试测量 阅读原文&#xff1a;德思特新闻 | 走进德思特——通过创新帮助客户成功 走进德思特 2023年上半年&#xff0c;ChatGPT红遍全球&#xff0c;人工智能、B5G/6G、物联网、云计算、软件自动化等新兴技术的快速发展进一步推动科技行业的复苏…

vue核心面试题汇总【查缺补漏】

给大家推荐一个实用面试题库 1、前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;web前端面试题库 很喜欢‘万变不离其宗’这句话&#xff0c;希望在不断的思考和总结中找到Vue中的宗&#xff0c;来解答面试官抛出的…

gd32部分映射1/2,完全映射,备用功能选择等

一、重映射与部分映射问题 参考相应用户手册&#xff1b; 打开&#xff1a;I/O 重映射功能和调试配置&#xff1b; AFIO 端口配置寄存器 0&#xff08;AFIO_PCF0&#xff09;&#xff1b; AFIO 端口配置寄存器 1&#xff08;AFIO_PCF1&#xff09;&#xff1b; 【e.g】以定时器…

Java练习题2021-4

"某游戏公司设计了一个奖励活动&#xff0c;给N个用户(1≤N≤10^7)连续编号为1到N&#xff0c;依据用户的编号S发放奖励。 发放奖励规则为&#xff1a; 公司随机设定三个非零正整数x&#xff0c;y&#xff0c;z。 如果S同时是x、y的倍数&#xff0c;奖励2张卡片&#xff1…

QCI利用量子计算为飞行汽车提供优化飞行路径和改进设计的功能

​&#xff08;图片来源&#xff1a;网络&#xff09; 长期以来&#xff0c;飞行汽车和量子计算机一直是“未来技术”的简写&#xff0c;它们将彻底改变交通世界。预计到2032年&#xff0c;量子计算的市场价值将达到1700亿美元&#xff0c;当前有很多实际用例已经证明了它的价…

如何用 Zabbix 监控 Radius 服务?

网管小贾 / sysadm.cc Radius 对于搞系统的小伙伴们来说应该并不陌生&#xff0c;它是提供身份认证的服务程序。 Radius 应用广泛&#xff0c;最简单的场景之一就是无线连接&#xff0c;使用用户名密码或者证书等方式通过它的验证后无线网络连接就可以建立起来。 如此重要的一…

1496. 判断路径是否相交

1496. 判断路径是否相交 java代码&#xff1a; class Solution {public boolean isPathCrossing(String path) {int x 0;int y 0;HashSet<String> hashSet new HashSet<>();hashSet.add("0-0");for (int i 0; i < path.length(); i) {switch (pa…

Vue-cli 搭建 SPA 项目,Vue 项目结构说明,开发示例,以及如何修改端口号,install 命令中的 -g,-S,-D 参数,嵌套路由,package.json 详解

目录 1. vue-cli安装 1.1 安装前提 1.2 什么是vue-cli 1.3 安装vue-cli 2. 使用vue-cli构建项目 2.1 使用脚手架创建项目骨架 2.2 到新建项目目录&#xff0c;安装需要的模块 2.3 如何修改端口号 2.4 添加element-ui模块 2.5 package.json详解 3. install命令中的-g…

FLStudio21完整版编曲软件多少钱?要不要购买

水果&#xff0c;全称Fruity Loop Studio&#xff0c;简称FL Studio。是一款全能的音乐制作软件&#xff0c;经过二十多年的演化更迭&#xff0c;其各项功能非常的先进。其开创性的Pat\song模式&#xff0c;也为初学者的学习提供了便利。那么水果音乐制作软件需要多少钱呢&…

修复VS2015没有代码提示的问题【已解决】

问题描述 在Visual Studio 中编写代码时&#xff0c;发现使用库函数的时候&#xff0c;在类对象后输入点后&#xff0c;并没有出现类对应的成员信息的提示。 解决过程 1&#xff09;方法1&#xff1a; 百度“vs 没有代码提示”&#xff0c;搜索解决方案。 方案1&#xff1…

高级路由配置

目录 路由协议认证 Ripv2的认证配置 OSPF认证 BGP认证 OSPF特殊区域 BGP的选路规则 路由策略&#xff08;route-policy和filter-policy&#xff09; IP-Prefix List:前缀列表 Filter-Policy 路由引入&#xff08;import-route&#xff09; Filter-policy和route-pol…

『 基础算法题解 』之双指针(下)

文章目录 和为S的两个数题目解析算法原理代码 三数之和题目解析算法原理代码 四数之和题目解析算法原理代码 和为S的两个数 题目解析 【题目链接】 该题目的原题为和为s的两个数: 即给定一组升序数据(数组price),并给出一个变量target,要求找出和为target的两个数; 算法原理…

第4关:书籍排序

题目&#xff1a; C&C结构体 (educoder.net) 思路&#xff1a; 1.字符串字典序排序---> 利用string.h里面的strcmp&#xff0c;由其返回值确定两字符串大小。&#xff08;pstrcmp(a,b)&#xff0c;若p>1&#xff0c;则a字典序大于b。&#xff09; 2.当不能定义字…

Java练习题2021-1

"从大于等于N的正整数里找到一个最小的数M&#xff0c;使之满足&#xff1a; M和M的逆序数&#xff08;如1230的逆序数为321&#xff09;的差的绝对值为一个[100000,200000]区间内的值。 输入说明&#xff1a;起始数字N&#xff1b; 输出说明&#xff1a;找到的第一个符合…

Java实现Excel导入和导出,看这一篇就够了(珍藏版2.0)

1. 前言 两年前&#xff0c;我发表了一篇自己基于POI实现的工具类 Java实现Excel导入和导出&#xff0c;看这一篇就够了(珍藏版)&#xff0c;也就是1.0版本&#xff0c;受到了不少粉丝和朋友喜欢&#xff0c;谢谢大家认可。在这两年多的时间里&#xff0c;经过粉丝们的建议&am…

0基础学习PyFlink——用户自定义函数之UDTAF

大纲 UDTAFTableAggregateFunction的实现累加器定义创建累加 返回类型计算 完整代码 在前面几篇文章中&#xff0c;我们分别介绍了UDF、UDTF和UDAF这三种用户自定义函数。本节我们将介绍最后一种函数&#xff1a;UDTAF——用户自定义表值聚合函数。 UDTAF UDTAF函数即具备了…

归一化一维时序信号,针对上下幅值波动不均问题

目的&#xff1a;如下图&#xff0c;信号上包络和下包络都有无规律的起伏&#xff0c;如何进行有效归一化&#xff0c;步骤如下&#xff1a; 步骤1. 信号初步归一化 data mapminmax(data,-1,1); 步骤2. 希尔伯特变换获得该时序信号的包络 z hilbert(data);figure;plot(data…

【VUE】ArcoDesign之自定义主题样式和命名空间

前言 Arco Design是什么&#xff1f; Arco Design 是由字节跳动推出的企业级产品的完整设计和开发解决方案前端组件库 官网地址&#xff1a;https://arco.design/同时也提供了一套开箱即用的中后台前端解决方案&#xff1a;Arco Design Pro(https://pro.arco.design/) Arco De…