【嵌入式】智能系统优化:【C++】驱动的【机器学习】与【数据挖掘】技术

ecde6503e5cb4996a0ff258b3d1ffc28.png

目录

一、嵌入式系统简介

二、C++在嵌入式系统中的优势

三、机器学习在嵌入式系统中的挑战

四、C++实现机器学习模型的基本步骤

五、实例分析:使用C++在嵌入式系统中实现手写数字识别

1. 数据准备

2. 模型训练与压缩

3. 模型部署

六、优化与分析

1. 模型优化

模型量化

模型剪枝

2. 系统优化

内存管理

计算资源分配

电源管理

七、性能评估与优化策略

1. 性能评估指标

2. 性能优化策略

八、实际应用案例 -嵌入式图像分类系统

概述

步骤

1. 数据准备

2. 模型部署

3. 实时推理

九、总结与展望


63748e72dc314943857316f3b1f6a386.gif#pic_center

随着物联网(IoT)和智能设备的普及,嵌入式系统变得越来越重要。而随着人工智能(AI)和机器学习(ML)技术的发展,将这些技术应用于嵌入式系统中可以实现许多智能应用,如智能家居、自动驾驶和工业自动化等。然而,由于嵌入式系统的资源有限,将AI和ML应用到嵌入式系统中面临许多挑战。

一、嵌入式系统简介

a75256bf614b4ba68d12d5f6ad533168.png

嵌入式系统是一种专用计算机系统,通常嵌入到大型系统中,执行特定任务。典型的嵌入式系统包括微控制器(MCU)、单板计算机(SBC)和专用AI加速器。嵌入式系统的主要特点包括:

  • 资源受限:CPU、内存和存储资源较少。
  • 实时性要求:需要在严格的时间限制内完成任务。
  • 专用性强:专为特定任务或设备设计。

二、C++在嵌入式系统中的优势

C++因其高效性和面向对象的特性,在嵌入式系统中得到了广泛应用。其优势包括:

  • 高性能:C++的编译后代码执行效率高,适合资源受限的嵌入式系统。
  • 面向对象:便于代码模块化和重用。
  • 丰富的库支持:标准库和第三方库丰富,便于实现复杂功能。

三、机器学习在嵌入式系统中的挑战

将机器学习模型部署到嵌入式系统中需要克服多种挑战:

  • 模型压缩:减少模型的大小和计算复杂度。
  • 实时性:确保模型推理的实时响应。
  • 资源管理:优化内存和计算资源的使用。

四、C++实现机器学习模型的基本步骤

  1. 数据准备:获取并预处理数据。
  2. 模型训练:在PC或服务器上训练模型。
  3. 模型压缩:使用量化、剪枝等技术压缩模型。
  4. 模型部署:将模型移植到嵌入式系统中。
  5. 实时推理:在嵌入式设备上进行实时推理。

五、实例分析:使用C++在嵌入式系统中实现手写数字识别

以下实例将展示如何在嵌入式系统中使用C++和TensorFlow Lite实现手写数字识别。

c1e2a01d6f8549498683cd2f261d7e47.png

1. 数据准备

我们使用MNIST数据集进行手写数字识别。首先,需要将数据集转换为适合嵌入式系统使用的格式。

#include <fstream>
#include <vector>
#include <iostream>void read_mnist(const std::string &filename, std::vector<std::vector<uint8_t>> &images) {std::ifstream file(filename, std::ios::binary);if (file.is_open()) {int magic_number = 0;int number_of_images = 0;int rows = 0;int cols = 0;file.read((char*)&magic_number, sizeof(magic_number));magic_number = __builtin_bswap32(magic_number);file.read((char*)&number_of_images, sizeof(number_of_images));number_of_images = __builtin_bswap32(number_of_images);file.read((char*)&rows, sizeof(rows));rows = __builtin_bswap32(rows);file.read((char*)&cols, sizeof(cols));cols = __builtin_bswap32(cols);for (int i = 0; i < number_of_images; ++i) {std::vector<uint8_t> image(rows * cols);file.read((char*)image.data(), rows * cols);images.push_back(image);}}
}

2. 模型训练与压缩

在PC上使用Python和TensorFlow训练一个简单的卷积神经网络(CNN)模型,并将其转换为适合嵌入式系统的格式。

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten
import numpy as np# 加载数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0# 构建模型
model = Sequential([Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)),Flatten(),Dense(128, activation='relu'),Dense(10, activation='softmax')
])# 编译和训练模型
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)# 模型量化
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()# 保存模型
with open('model.tflite', 'wb') as f:f.write(tflite_model)

3. 模型部署

使用TensorFlow Lite将模型部署到嵌入式系统中,并进行推理。

#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/kernels/register_ref.h"
#include <vector>
#include <iostream>void run_inference(const std::vector<uint8_t> &input_image) {// 加载模型const char* model_path = "model.tflite";auto model = tflite::FlatBufferModel::BuildFromFile(model_path);tflite::ops::builtin::BuiltinOpResolver resolver;std::unique_ptr<tflite::Interpreter> interpreter;tflite::InterpreterBuilder(*model, resolver)(&interpreter);// 分配张量interpreter->AllocateTensors();int input = interpreter->inputs()[0];uint8_t* input_data = interpreter->typed_tensor<uint8_t>(input);// 将图像数据复制到输入张量std::copy(input_image.begin(), input_image.end(), input_data);// 运行推理interpreter->Invoke();// 获取输出int output = interpreter->outputs()[0];float* output_data = interpreter->typed_tensor<float>(output);// 打印结果for (int i = 0; i < 10; ++i) {std::cout << "Probability of " << i << ": " << output_data[i] << std::endl;}
}

六、优化与分析

在实际应用中,我们需要不断优化模型和系统,以满足嵌入式设备的资源限制和性能需求。以下是一些常见的优化策略和分析方法。

1. 模型优化

模型优化可以通过多种方式进行,包括量化、剪枝和知识蒸馏。

模型量化

模型量化可以显著减少模型的大小和计算量,提高推理速度。

# 模型量化
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
quantized_model = converter.convert()# 保存量化后的模型
with open('quantized_model.tflite', 'wb') as f:f.write(quantized_model)

模型剪枝

模型剪枝可以通过删除不重要的权重来减少模型的大小。

import tensorflow_model_optimization as tfmot# 定义剪枝参数
pruning_params = {'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(initial_sparsity=0.50,final_sparsity=0.90,begin_step=0,end_step=1000)
}# 使用剪枝API
model_for_pruning = tfmot.sparsity.keras.prune_low_magnitude(model, **pruning_params)# 编译模型
model_for_pruning.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])# 训练模型
model_for_pruning.fit(x_train, y_train, epochs=2, validation_data=(x_test, y_test))# 删除剪枝标记并保存模型
model_for_export = tfmot.sparsity.keras.strip_pruning(model_for_pruning)
model_for_export.save('pruned_model.h5')

2. 系统优化

在嵌入式系统中,除了优化模型外,还需要优化系统的各个方面,包括内存管理、计算资源分配和电源管理。

内存管理

在嵌入式系统中,内存资源通常非常有限,因此高效的内存管理是至关重要的。

// 示例代码:高效内存管理
#include <vector>
#include <iostream>// 使用内存池管理动态内存分配
class MemoryPool {
public:MemoryPool(size_t size) : size_(size), memory_(new char[size]), offset_(0) {}~MemoryPool() {delete[] memory_;}void* allocate(size_t size) {if (offset_ + size > size_) {throw std::bad_alloc();}void* ptr = memory_ + offset_;offset_ += size;return ptr;}void deallocate(void* ptr, size_t size) {// 简单实现,不做实际操作}private:size_t size_;char* memory_;size_t offset_;
};// 示例使用
int main() {MemoryPool pool(1024);int* a = static_cast<int*>(pool.allocate(sizeof(int) * 10));for (int i = 0; i < 10; ++i) {a[i] = i;std::cout << a[i] << " ";}std::cout << std::endl;pool.deallocate(a, sizeof(int) * 10);return 0;
}

计算资源分配

在多核嵌入式系统中,可以使用并行计算来提高模型推理的速度。

// 示例代码:多线程并行计算
#include <thread>
#include <vector>
#include <iostream>void process_data(int id, const std::vector<int>& data) {for (auto val : data) {std::cout << "Thread " << id << ": " << val << std::endl;}
}int main() {std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};std::thread t1(process_data, 1, std::ref(data));std::thread t2(process_data, 2, std::ref(data));t1.join();t2.join();return 0;
}

电源管理

在电池供电的嵌入式系统中,电源管理至关重要。可以通过动态电压和频率调节(DVFS)来降低功耗。

// 示例代码:电源管理(伪代码)
#include <iostream>void adjust_frequency(int level) {// 根据需要调整CPU频率std::cout << "Adjusting CPU frequency to level: " << level << std::endl;
}int main() {int workload = 50; // 示例工作负载if (workload < 20) {adjust_frequency(1); // 低频率} else if (workload < 70) {adjust_frequency(2); // 中等频率} else {adjust_frequency(3); // 高频率}return 0;
}

七、性能评估与优化策略

评估和优化模型在嵌入式系统上的性能是确保系统能够满足实际应用需求的重要步骤。

1. 性能评估指标

  • 推理时间:模型从输入到输出的时间。
  • 内存使用:模型运行时的内存占用。
  • 能耗:模型运行时的功耗。

2. 性能优化策略

  • 使用硬件加速:利用硬件平台的AI加速器。
  • 优化编译器:使用针对特定硬件优化的编译器和库,如TensorFlow Lite Micro。
  • 并行处理:在多核系统中使用并行计算提高推理速度。

八、实际应用案例 -嵌入式图像分类系统

4df95d93e16647e78fff05e95b201ece.png

构建一个嵌入式图像分类系统,使用Raspberry Pi和TensorFlow Lite进行实时图像分类。

概述

在本案例中,我们将使用Raspberry Pi和TensorFlow Lite部署一个手写数字识别模型。本文将详细展示如何在嵌入式系统中实现图像分类的每一步,包括数据准备、模型部署和实时推理。

步骤

  1. 数据准备:获取MNIST数据集并转换为适合嵌入式系统使用的格式。
  2. 模型训练与量化:使用预训练的TensorFlow Lite模型。
  3. 模型部署:将模型部署到Raspberry Pi上。
  4. 实时推理:在Raspberry Pi上进行实时图像分类。

1. 数据准备

在C++中读取MNIST数据集,并将其格式化为适合模型输入的形式。

#include <iostream>
#include <fstream>
#include <vector>void read_mnist(const std::string &filename, std::vector<std::vector<uint8_t>> &images) {std::ifstream file(filename, std::ios::binary);if (file.is_open()) {int magic_number = 0;int number_of_images = 0;int rows = 0;int cols = 0;file.read((char*)&magic_number, sizeof(magic_number));magic_number = __builtin_bswap32(magic_number);file.read((char*)&number_of_images, sizeof(number_of_images));number_of_images = __builtin_bswap32(number_of_images);file.read((char*)&rows, sizeof(rows));rows = __builtin_bswap32(rows);file.read((char*)&cols, sizeof(cols));cols = __builtin_bswap32(cols);for (int i = 0; i < number_of_images; ++i) {std::vector<uint8_t> image(rows * cols);file.read((char*)image.data(), rows * cols);images.push_back(image);}}
}int main() {std::vector<std::vector<uint8_t>> images;read_mnist("train-images-idx3-ubyte", images);std::cout << "Read " << images.size() << " images." << std::endl;return 0;
}

2. 模型部署

使用TensorFlow Lite的C++ API将量化后的模型部署到Raspberry Pi上。

#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/interpreter.h"
#include <vector>
#include <iostream>
#include <memory>void run_inference(const std::vector<uint8_t> &input_image) {// 加载模型const char* model_path = "model.tflite";auto model = tflite::FlatBufferModel::BuildFromFile(model_path);tflite::ops::builtin::BuiltinOpResolver resolver;std::unique_ptr<tflite::Interpreter> interpreter;tflite::InterpreterBuilder(*model, resolver)(&interpreter);// 分配张量interpreter->AllocateTensors();int input = interpreter->inputs()[0];uint8_t* input_data = interpreter->typed_tensor<uint8_t>(input);// 将图像数据复制到输入张量std::copy(input_image.begin(), input_image.end(), input_data);// 运行推理interpreter->Invoke();// 获取输出int output = interpreter->outputs()[0];float* output_data = interpreter->typed_tensor<float>(output);// 打印结果for (int i = 0; i < 10; ++i) {std::cout << "Probability of " << i << ": " << output_data[i] << std::endl;}
}int main() {std::vector<uint8_t> image_data(28 * 28); // 假设我们有一个28x28的灰度图像数据// 在此处加载图像数据run_inference(image_data);return 0;
}

 

3. 实时推理

在Raspberry Pi上进行实时推理,需要处理实时获取的图像数据并进行推理。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model.h"void preprocess_image(const cv::Mat &image, std::vector<uint8_t> &output_image) {cv::Mat resized_image;cv::resize(image, resized_image, cv::Size(28, 28));cv::cvtColor(resized_image, resized_image, cv::COLOR_BGR2GRAY);output_image.assign(resized_image.data, resized_image.data + resized_image.total());
}void classify_image(const std::vector<uint8_t> &image_data) {const char* model_path = "model.tflite";auto model = tflite::FlatBufferModel::BuildFromFile(model_path);tflite::ops::builtin::BuiltinOpResolver resolver;std::unique_ptr<tflite::Interpreter> interpreter;tflite::InterpreterBuilder(*model, resolver)(&interpreter);interpreter->AllocateTensors();int input_index = interpreter->inputs()[0];uint8_t* input_data = interpreter->typed_tensor<uint8_t>(input_index);std::copy(image_data.begin(), image_data.end(), input_data);interpreter->Invoke();int output_index = interpreter->outputs()[0];float* output_data = interpreter->typed_tensor<float>(output_index);for (int i = 0; i < 10; ++i) {std::cout << "Class " << i << ": " << output_data[i] << std::endl;}
}int main() {cv::VideoCapture cap(0);if (!cap.isOpened()) {std::cerr << "Error opening video stream" << std::endl;return -1;}while (true) {cv::Mat frame;cap >> frame;if (frame.empty()) {break;}std::vector<uint8_t> image_data;preprocess_image(frame, image_data);classify_image(image_data);cv::imshow("Frame", frame);if (cv::waitKey(10) == 27) {break;}}cap.release();cv::destroyAllWindows();return 0;
}

九、总结与展望

在嵌入式系统中使用C++进行机器学习和数据挖掘,包括数据准备、模型训练与压缩、模型部署以及实时推理。未来,随着硬件和算法的不断进步,嵌入式机器学习将会有更加广阔的应用前景,推动物联网、智能制造和智能家居等领域的创新发展。

d6f8de9bc53d443f9b9584c9760c1871.png

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生成式人工智能如何运作?

一、简述 生成式人工智能是一种可用于创建内容&#xff08;包括对话、故事、图像、视频和音乐&#xff09;的人工智能。人工智能技术试图在图像识别、自然语言处理&#xff08;NLP&#xff09;和翻译等非传统计算任务中模仿人类智能。生成式人工智能是人工智能的发展方向。您可…

使用python绘制桑基图

使用python绘制桑基图 桑基图效果代码 桑基图 桑基图&#xff08;Sankey Diagram&#xff09;是一种用来表示流动&#xff08;如能源、资金、材料等&#xff09;在不同实体之间转移的图表。 每个流的宽度与流量成正比&#xff0c;通常用于显示能量或成本流动的分布情况。 桑基…

RocketMQ教程(三):RocketMQ的核心组件

四个核心组件 RocketMQ 的架构采用了典型的分布式系统设计理念,以确保高性能、高可用和可扩展性。RocketMQ 主要由四个核心组件构成:NameServer、Broker、Producer 和 Consumer。下面是对这些组件以及它们在 RocketMQ 中的角色和功能的概述: 1. NameServer 角色和功能:Name…

Linux安装RocketMQ教程【带图文命令巨详细】

巨详细Linux安装Nacos教程RocketMQ教程 1、检查残留版本2、上传压缩包至服务器2.1压缩包获取2.2创建相关目录 3、安装RocketMQ4、配置RocketMQ4.1修改runserver.sh和runbroker.sh启动脚本4.2新增broker.conf配置信息4.3启动关闭rocketmq4.4配置开机自启动&#xff08;扩展项&am…

【设计模式深度剖析】【5】【行为型】【迭代器模式】

&#x1f448;️上一篇:策略模式 设计模式-专栏&#x1f448;️ 文章目录 迭代器模式定义英文原话直译如何理解呢&#xff1f; 迭代器模式的角色1. Iterator&#xff08;迭代器&#xff09;2. ConcreteIterator&#xff08;具体迭代器&#xff09;3. Aggregate&#xff08;聚…

排序算法之快速排序

排序算法之快速排序 简介算法解析双循环单循环 代码实现测试调用 简介 快速排序是由冒泡排序演变而来&#xff0c;比冒泡排序更快的排序算法。之所以快&#xff0c;是因为快速排序用了分治法。 相同的是&#xff0c;与冒泡排序一样&#xff0c;快速排序也属于交换排序&#x…

使用Ollama+OpenWebUI本地部署Gemma谷歌AI开放大模型完整指南

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;AI大模型部署与应用专栏&#xff1a;点击&#xff01; &#x1f916;Ollama部署LLM专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月4日10点50分 &#x1f004;️文章质量&#xff1…

google keybox.xml格式 内容有哪些 Keybox数量、设备ID、算法的 私钥 公钥 证书链 (ECDSA即ECC, RSA)

根据您提供的文件内容&#xff0c;keybox.xml 文件包含以下主要信息&#xff1a; Keybox数量 ([NumberOfKeyboxes](file:///d%3A/010F200/svn/ProduceToolMfc/FtSmartPos/FtSmartPos/ToolBydMes/httpclient/e%3A%5CGoogleKey%5CLinux_AttestationKeyboxPack_Tool%5CLinux_Atte…

微服务架构-正向治理与治理效果

目录 一、正向治理 1.1 概述 1.2 效率治理 1.2.1 概述 1.2.2 基于流量录制和回放的测试 1.2.3 基于仿真环境的测试 1.3 稳定性治理 1.3.1 概述 1.3.2 稳定性治理模型 1.3.3 基于容器化的稳定性治理 1.3.3.1 概述 1.3.3.2 测试 1.3.3.3 部署 1.3.3.3.1 概述 1.3.3…

matlab 计算三维空间点到直线的距离

目录 一、算法原理二、代码实现三、结果展示四、参考链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 直线的点向式方程为: x − x 0 m = y

IEDA 默认集成依赖概述

IEDA 默认集成依赖概述 目录概述需求&#xff1a; 设计思路实现思路分析 1.Developer Tools:GraalVM Native supportGraphQL DGs Code GenerationSpring Boot DevToolsLombokSpring Configuration ProcessorDocker Compose supportSpring Modulith 2.WebWebSpring WebSpring Re…

应用层——HTTP协议(自己实现一个http协议)——客户端(浏览器)的请求做反序列化和请求分析,然后创建http向响应结构

应用层&#xff1a;之前我们写的创建套接字&#xff0c;发送数据&#xff0c;序列化反序列化这些都是在写应用层 我们程序员写的一个个解决我们实际问题, 满足我们日常需求的网络程序, 都是在应用层 之前的网络计算机是我们自定义的协议&#xff1a;传输的数据最终是什么样的结…

【NetTopologySuite类库】C#生成带约束(线、面)的Delaunay三角网

介绍 API地址&#xff1a;https://nettopologysuite.github.io/NetTopologySuite/api/NetTopologySuite.Triangulate.ConformingDelaunayTriangulationBuilder.html#NetTopologySuite_Triangulate_ConformingDelaunayTriangulationBuilder_Constraints 约束为线 效果图 红色…

基于SSM+Jsp的高校信息资源共享平台

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

海康威视综合安防管理平台 多处 FastJson反序列化RCE漏洞复现

0x01 产品简介 海康威视综合安防管理平台是一套“集成化”、“智能化”的平台,通过接入视频监控、一卡通、停车场、报警检测等系统的设备。海康威视集成化综合管理软件平台,可以对接入的视频监控点集中管理,实现统一部署、统一配置、统一管理和统一调度。 0x02 漏洞概述 由于…

【Redis】 Redis 集成到 Spring Boot上面

文章目录 &#x1f343;前言&#x1f384;Spring Boot连接redis客户端&#x1f6a9;项目的创建&#x1f6a9;配置端⼝转发&#x1f6a9;配置 redis 服务地址&#x1f6a9;更改 Redis 配置文件&#x1f6a9;使用 StringRedisTemplate 类操作 &#x1f38d;Spring Boot操作Redis客…

JAVA网络编程,反射及注解知识总结

文章目录 网络编程软件架构三要素IP端口号协议UDP协议发送数据接收数据三种通信方式 TCP协议客户端服务器端三次握手四次挥手 反射获取字节码文件获取构造方法获取成员变量获取成员方法反射的作用 动态代理注解作用格式使用位置注解的原理常见注解元注解自定义注解解析注解 网络…

安装windows11系统跳过微软账号登录,使用本地账号登录方法

在安装win11系统&#xff0c;进行到如图下所示界面的时候&#xff0c;暂停下 我们可以按下键盘的ShiftF10按键&#xff08;部分电脑是FnShiftF10&#xff09;&#xff0c;这时屏幕会出现命令行窗口&#xff0c;如图下所示 我们需要在命令行内输入代码oobe\bypassnro.cmd然后回车…

[AI Google] 双子座模型家族迎来新突破:更快的模型、更长的上下文、AI代理等更多功能

Google发布了Gemini模型家族的更新&#xff0c;包括新的1.5 Flash模型&#xff0c;该模型旨在提高速度和效率&#xff0c;以及Project Astra&#xff0c;这是对未来AI助手愿景的展示。1.5 Flash是专为大规模高频任务优化的轻量级模型&#xff0c;具有突破性的长上下文窗口。同时…

积累常用css

1、封面文字&#xff0c;垂直居中&#xff0c;可以两列并排 font-size: 20px;font-weight: 600;color: #333;line-height: 20px;display: block;word-wrap: break-word;writing-mode: vertical-lr;height: 160px;margin: 0 auto; 2、宽border效果 .dashed-box { margin: 80px…