02-27 周一 图解机器学习SVM-人脸识别之PCA降维

news2025/1/16 5:47:13
02-27 周一 图解机器学习SVM分类
时间版本修改人描述
2023年2月27日09:48:38V0.1宋全恒新建文档

简介

 本文主要是在试图代码分析图解机器学习这本书中5.5人脸识别分类(p60),主要的过程是使用PCA技术和SVM技术进行人脸的分类工作。

准备

数据集

 数据集下载,使用的是英国剑桥大学的AT&T人脸数据。程序采用的数据集下载地址为 csdn下载地址,著名人脸识别数据库ORL,已经为大家分类打包好,一共40个人每人10张脸,有正脸、左右侧脸、正脸表情变化等,包括jpg以及pgm格式,保证全面无删减哦。程序使用的是pgm格式,对应的图片如下所示:

注: 核心信息一共有40类样本,每个类中包含包含同一个人的10张图像(112*92)

 可以下载pgm格式pgmviewer,但是由于笔者的电脑是win10,无法运行,然后也可以使用线上转换器,查看每个pgm图片的具体图像。

 从s1到s40,一共40个文件夹,每个文件夹表示1个人,每个文件夹中一共有10个该人的人脸图片。

环境搭建

 由于运行环境使用Linux,并且,需要使用到opencv图像识别库,需要使用python扩展包。

root@9296ffc57f68:/workspace# pip install opencv_python
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting opencv_python
  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/29/35/a791b550cdeb4efd8b66e921748f2aff938868a29794489d93575d604a02/opencv_python-4.7.0.72-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (61.8 MB)
Requirement already satisfied: numpy>=1.17.0 in /opt/conda/lib/python3.7/site-packages (from opencv_python) (1.21.2)
Installing collected packages: opencv_python
Successfully installed opencv_python-4.7.0.72
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

[notice] A new release of pip available: 22.2.1 -> 23.0.1


root@9296ffc57f68:/workspace# pip install opencv-python-headless
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting opencv-python-headless
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/3f/45/21fc904365f9cea3559e0192349bfe3ea2dce52672c1d9127c3b59711804/opencv_python_headless-4.7.0.72-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (49.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.2/49.2 MB 506.4 kB/s eta 0:00:00
Requirement already satisfied: numpy>=1.17.0 in /opt/conda/lib/python3.7/site-packages (from opencv-python-headless) (1.21.2)
Installing collected packages: opencv-python-headless
Successfully installed opencv-python-headless-4.7.0.72
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

[notice] A new release of pip available: 22.2.1 -> 23.0.1

程序调整

 程序主要调整了PICTURE_PATH参数的初始值,并且使用os.path.join构造了每个图像的值。

# PICTURE_PATH为图像存放目录位置,注意读者需要修改为自己电脑存放图像的目录
PICTURE_PATH = "/workspace/att_faces" 
def get_Image(): #读取图像程序
    for i in range(1,41):  #循环读取所以图片文件
        for j in range(1,11):
            path =os.path.join(PICTURE_PATH, "s"+str(i), str(j)+".pgm")   #路径
            img = cv2.imread(path)                                  #使用imread函数读取图像
#生活中大多数看到的彩色图像都是RGB类型,但是图像处理时,需要用到灰度图、二值图、HSV、HSI等颜色制式,opencv的cvtColor()函数来实现这些功能
            img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            h,w = img_gray.shape           #图像的尺寸信息赋值给变量h和w
            img_col = img_gray.reshape(h*w) #使用reshape函数对图像进行处理
            all_data_set.append(img_col)     #将图像添加到数据集all_data_set中
            all_data_label.append(i)         #确定图像对应的标签值
    return h,w 

程序理解

全部程序

#%程序5-3 人脸识别程序,名称:facerecognizition.py
#导入相关支持库
from time import time
import logging
import matplotlib.pyplot as plt
import cv2 
#从sklearn导入相关模型和svm算法
from numpy import *
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC
# PICTURE_PATH为图像存放目录位置,注意读者需要修改为自己电脑存放图像的目录
PICTURE_PATH = "/workspace/att_faces" 
def get_Image(): #读取图像程序
    for i in range(1,41):  #循环读取所以图片文件
        for j in range(1,11):
            path =os.path.join(PICTURE_PATH, "s"+str(i), str(j)+".pgm")   #路径
            img = cv2.imread(path)                                  #使用imread函数读取图像
#生活中大多数看到的彩色图像都是RGB类型,但是图像处理时,需要用到灰度图、二值图、HSV、HSI等颜色制式,opencv的cvtColor()函数来实现这些功能
            img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            h,w = img_gray.shape           #图像的尺寸信息赋值给变量h和w
            img_col = img_gray.reshape(h*w) #使用reshape函数对图像进行处理
            all_data_set.append(img_col)     #将图像添加到数据集all_data_set中
            all_data_label.append(i)         #确定图像对应的标签值
    return h,w 

all_data_set = []         #变量all_data_set初始化为空
all_data_label = []       # 变量all_data_label初始化为空
h,w = get_Image()       #调用定义的get_Image()函数获取图像
X =array(all_data_set)    #使用all_data_set作为参数定义数组赋值给变量X
y = array(all_data_label)  #使用all_data_ label作为参数定义数组赋值给变量y
n_samples,n_features = X.shape   #X数组中的图像信息赋值给变量n_samples,n_features
n_classes = len(unique(y))        #得到变量y的长度赋值给n_classes
target_names = []               #变量target_names初始化为空
for i in range(1,41):             #循环读取
    names = "person" + str(i)    #定义变量names,并赋值
target_names.append(names) #变量target_names不断添加信息的names
#打印输出:数据集总规模,n_samples和n_features
print("Total dataset size:")
print("n_samples: %d" % n_samples)
print("n_features: %d" % n_features)
#程序划分,一部分用于训练集,另一部分用于测试集,这里使用3/4数据用于训练,1/4数据用于测试
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42)  
n_components = 20
#打印输出信息
print("Extracting the top %d eigenfaces from %d faces"
      % (n_components, X_train.shape[0])) 
t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized', #选择一种svd方式
          whiten=True).fit(X_train)    #whiten是一种数据预处理方式,会损失一些数据信息,但可获得更好的预测结果
print("done in %0.3fs" % (time() - t0)) 
eigenfaces = pca.components_.reshape((n_components, h, w))    #特征脸 
print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)      #得到训练集投影系数
X_test_pca = pca.transform(X_test)        #得到测试集投影系数
print("done in %0.3fs" % (time() - t0))      #打印出来时间

程序理解

函数定义-实现图像数据和标签

def get_Image(): #读取图像程序
    for i in range(1,41):  #循环读取所以图片文件
        for j in range(1,11):
            path =os.path.join(PICTURE_PATH, "s"+str(i), str(j)+".pgm")   #路径
            img = cv2.imread(path)                                  #使用imread函数读取图像
#生活中大多数看到的彩色图像都是RGB类型,但是图像处理时,需要用到灰度图、二值图、HSV、HSI等颜色制式,opencv的cvtColor()函数来实现这些功能
            img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            h,w = img_gray.shape           #图像的尺寸信息赋值给变量h和w
            img_col = img_gray.reshape(h*w) #使用reshape函数对图像进行处理
            all_data_set.append(img_col)     #将图像添加到数据集all_data_set中
            all_data_label.append(i)         #确定图像对应的标签值
    return h,w 

 上述主要是进行数据的加载,而且是加载了所有的图像,两个没有用过的函数,1个是cv2.imread,一个是reshape。

cv2.imread

 具体可参见 cv2.imread,用于将磁盘上的图像文件加载到内存中,读取之后的效果如下:

cv2.imread()有两个参数,第一个参数filename是图片路径,第二个参数flag表示图片读取模式,共有三种:

cv2.IMREAD_COLOR:加载彩色图片,这个是默认参数,可以直接写1。
cv2.IMREAD_GRAYSCALE:以灰度模式加载图片,可以直接写0。
cv2.IMREAD_UNCHANGED:包括alpha(包括透明度通道),可以直接写-1

 cv2.imread()读取图片后以多维数组的形式保存图片信息,前两维表示图片的像素坐标,最后一维表示图片的通道索引,具体图像的通道数由图片的格式来决定。

cvtCololr

 接下来是把三通道的图像转化为灰度图。cv2.cvtColor(p1,p2) 是颜色空间转换函数,p1是需要转换的图片,p2是转换成何种格式。

 上述代码涉及了颜色空间的转换,具体可以参见 cv2.imread()和cv2.cvtColor() 的使用。灰度图的理解如下:

数据概览

all_data_set = []         #变量all_data_set初始化为空
all_data_label = []       # 变量all_data_label初始化为空
h,w = get_Image()       #调用定义的get_Image()函数获取图像
X =array(all_data_set)    #使用all_data_set作为参数定义数组赋值给变量X
y = array(all_data_label)  #使用all_data_ label作为参数定义数组赋值给变量y
n_samples,n_features = X.shape   #X数组中的图像信息赋值给变量n_samples,n_features
n_classes = len(unique(y))        #得到变量y的长度赋值给n_classes
target_names = []               #变量target_names初始化为空
for i in range(1,41):             #循环读取
    names = "person" + str(i)    #定义变量names,并赋值
    target_names.append(names) #变量target_names不断添加信息的names
#打印输出:数据集总规模,n_samples和n_features
print("Total dataset size:")
print("    n_samples: %d" % n_samples)
print("    n_features: %d" % n_features)

 range(1, 41)返回的数据是1到40的序列,左包含,右不包含。

 此时X,y,target_names的结果如下:

train_test_split进行训练和测试数据划分

 从上可以看出当前样本数一共有400个数据,特征为10304维度。

 程序使用train_test_split来进行训练和测试数据的拆分。

 train_test_split方法能够将数据集按照用户的需要指定划分为训练集和测试集。一组用来进行训练,而另外一组用来进行测试。

#程序划分,一部分用于训练集,另一部分用于测试集,这里使用3/4数据用于训练,1/4数据用于测试
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42)  

 函数参数含义如下:

X_train,X_test, y_train, y_test =train_test_split(train_data,train_target,test_size=0.25, random_state=0,stratify=y)
# train_data:所要划分的样本特征集
# train_target:所要划分的样本结果
# test_size:样本占比,如果是整数的话就是样本的数量
# random_state:是随机数的种子。
# 随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。

 划分结果为:

PCA主成分获取


n_components = 20
#打印输出信息
print("Extracting the top %d eigenfaces from %d faces"
      % (n_components, X_train.shape[0])) 
t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized', #选择一种svd方式
          whiten=True).fit(X_train)    #whiten是一种数据预处理方式,会损失一些数据信息,但可获得更好的预测结果
print("done in %0.3fs" % (time() - t0)) 
eigenfaces = pca.components_.reshape((n_components, h, w))    #特征脸 
print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)      #得到训练集投影系数
X_test_pca = pca.transform(X_test)        #得到测试集投影系数
print("done in %0.3fs" % (time() - t0))      #打印出来时间

 通过PCA,实现降维,然后使用pca转化了训练数据和测试数据,上述代码也打印了降维的耗时。

 最后一段,主要是要理解PCA主成分分析。


n_components = 20
#打印输出信息
print("Extracting the top %d eigenfaces from %d faces"
      % (n_components, X_train.shape[0])) 
t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized', #选择一种svd方式
          whiten=True).fit(X_train)    #whiten是一种数据预处理方式,会损失一些数据信息,但可获得更好的预测结果
print("done in %0.3fs" % (time() - t0)) 

 通过主成分分析,通过指定鬼脸数(Eigenfaces for Recognition)为20,获取pca。

 主成分分析方法主要用来降维,因为我们无法直接使用10304维的特征进行SVM,或者说进行协方差矩阵的特征值和特征向量分解,因此通过PCA选择最重要的特征或者说特征向量进行降维,一方面能够保证计算的精(一般PCA的主成分占据95%的特征。)度,同时大大降低计算量。从得到的pca.components_,可以看出得到的特征向量一共20个,在论文中有如下的陈述:

Each individual face can be represented exactly in terms of a linear combination of eigenfaces. Eache face can also be approximated using only the “best” eigenfaces----those that have the largest eigenvalues, and which therefore account for the most variance within the set of face images.The Best M eigenfaces span an M-dimensional subspace—“face space”----of all possible images.

获取投影

 最后这部分的代码,主要是使用pca来转化训练数据集和测试数据集,由输出的两个shape可以看出,可以看到300个人脸的特征维度从10304,降维到了20个主成分上了。

关键

特征脸

 特征量的提出是由

一组特征脸可以通过在一大组描述不同人脸的图像上进行主成分分析(PCA)获得。任意一张人脸图像都可以被认为是这些标准脸的组合。例如,**一张人脸图像可能是特征脸1的10%,加上特征脸2的55%,在减去特征脸3的3%。**值得注意的是,它不需要太多的特征脸来获得大多数脸的近似组合。另外,由于人脸是通过一系列向量(每个特征脸一个比例值)而不是数字图像进行保存,可以节省很多存储空间。百度百科。

 基本过程是把所有图像组成单一矩阵T,然后计算其协方差矩阵S,计算协方差矩阵S的特征值和特征向量。

 这些特征脸可以用于标识已有的和新的人脸:我们可以将一个新的人脸图像(先要减去均值图像)投影到特征脸上,以此来记录这个图像与平均图像的偏差。每一个特征向量的特征值代表了训练集合的图像与均值图像在该方向上的偏差有多大。将图像投影到特征向量的子集上可能丢失信息,但是通过保留那些具有较大特征值的特征向量的方法可以减少这个损失。例如,如果当前处理一个100 x 100的图像,就会得到10000个特征向量。在实际使用中,大多数的图像可以投影到100到150个特征向量上进行识别,因此,10000个特征向量的绝大多数可以丢弃。

感觉这个在读书时,线性代数中是很重要的思想。

 特征脸可以参考 特征脸思想。

 协方差矩阵的计算过程:

 在B站上出了一个特征脸计算的up主分享。

PCA降维

 PCA降维可以参考博客 主成分分析(PCA)原理详解

 PCA的思想是将n维特征映射到k维上(k<n),这k维是全新的正交特征。这k维特征称为主成分,是重新构造出来的k维特征,而不是简单地从n维特征中去除其余n-k维特征。

注: 例子表明是将2维特征降低到1维特征。

总结

 本文记录了通过PCA降维将原理的(112*92)降维到20个维度的向量的过程。主要是通过该程序串联起了PCA、方差、协方差、标准差,特征值分析和特征值等线性代数,需要恶补。在B站上可以刷到 人脸识别的课程非常的好,一共323分钟。抽时间要好好看一下。

 机器学习是一门处理数据的艺术,这个文章简要的描述了由400个样本,通过预处理,得到其协方差矩阵,进而得到协方差矩阵的特征值和特征向量,由这些特征获取主要成分(Principal component)。进而根据主成分得到所有训练样本在主成分即特征向量上的投影。利用降维后的数据进行SVM分类。再保证精度的同时,大大降低了计算的耗时,也算是模糊数学的一种思想实践。

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

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

相关文章

JavaScript中单例模式这样用

如果希望自己的代码更优雅、可维护性更高以及更简洁&#xff0c;往往离不开设计模式这一解决方案。 在JS设计模式中&#xff0c;最核心的思想&#xff1a;封装变化&#xff08;将变与不变分离&#xff0c;确保变化的部分灵活&#xff0c;不变的部分稳定&#xff09;。 单例模式…

Spring Batch 综合案例实战中

目录 需求一 需求二 转视频版 需求一 需求&#xff1a;先动态生成50w条员工数据&#xff0c;存放再employee.csv文件中 步骤1&#xff1a;定义&#xff1a;DataInitController RestController public class DataInitController {Autowiredprivate IEmployeeService emplo…

arduino-sentry2之卡片篇

欧克,今天在学生的强烈要求下 我又重启arduino的sentry2调试篇 目前实验结果,可以检测到10张交通卡片 也就是如图所示十张 具体视频如下: https://live.csdn.net/v/279170 具体代码如下: #include <Arduino.h> #include <

什么是千年虫?计算机如何开始处理日期?都有哪些时间日期格式化?

目录 “千年虫”漏洞&#xff08;Year 2000 Problem&#xff0c;简称“Y2K”&#xff09; 计算机是怎么开始处理日期的么&#xff1f; 举例1&#xff1a;时间格式化举例( 过滤器) 举例2&#xff1a;时间格式化 自定义私有过滤器(日期格式化) 高性能计数器演示 OLE时间对象…

Vue的组件(注册、局部、组件复用、props、emit、生命周期)全解

文章目录前言知识点组件注册局部组件组件复用组件间通信props 类型检测子父组件通信之 emit动态组件生命周期函数前言 Vue 支持模块化和组件化开发&#xff0c;可以将整个页面进行模块化分割&#xff0c;低耦合高内聚&#xff0c;使得代码可以在各个地方使用。 知识点 组件注册…

python自学之《21天学通Python》(15)——第18章 数据结构基础

数据结构是用来描述一种或多种数据元素之间的特定关系&#xff0c;算法是程序设计中对数据操作的描述&#xff0c;数据结构和算法组成了程序。对于简单的任务&#xff0c;只要使用编程语言提供的基本数据类型就足够了。而对于较复杂的任务&#xff0c;就需要使用比基本的数据类…

华三OSPF 综合实验

OSPF 实验 实验拓扑 实验需求 按照图示配置 IP 地址按照图示分区域配置 OSPF &#xff0c;实现全网互通为了路由结构稳定&#xff0c;要求路由器使用环回口作为 Router-id&#xff0c;ABR 的环回口宣告进骨干区域 实验解法 1.配置 IP 地址部分 2.按照图示分区域配置 OS…

FFmpeg从入门到入魔(1):初探FFmpeg框架

1. FFmpeg介绍与裁剪1.1 FFmpeg简介FFmpeg&#xff08;Fast forword mpeg&#xff0c;音视频转换器&#xff09;是一个开源免费跨平台的视频和音频流方案&#xff0c;它提供了录制/音视频编解码、转换以及流化音视频的完整解决方案。ffmpeg4.0.2源码目录结构如下&#xff1a;目…

为什么IBDP的文凭更受美国大学的青睐?

家长们可以看到&#xff0c;不管是AP还是A-LEVEL这样的课程&#xff0c;都只是单科的课程&#xff08;A-LEVEL也是英国发展出来&#xff0c;AP是针对美国大学设计的&#xff09;&#xff0c;学生是可以针对他们的强项去做选修&#xff0c;比如我的化学很强&#xff0c;那我可以…

第十节 集合

集合 什么是集合 集合就是能储存一批元素的容器。 特征&#xff1a; 集合类型可以不固定&#xff0c;大小也是可变的。 ArrayList集合 ArrayList是集合中的一种&#xff0c;它支持索引。 ArrayList集合的对象获取 public ArrayList()创建一个空的集合对象 ArrayList集合的添加…

Hive 一文读懂

Hive 简介1.1 什么是Hive1&#xff09;hive简介Hive&#xff1a;由Facebook开源用于解决海量结构化日志的数据统计。Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能。2&#xff09;Hive本质&#xff1a;将…

Goframe快速创建项目,并使用Cli工具创建dao、service、logic

GoFrame项目创建与Cli工具创建1.项目创建2.Mysql数据库配置3.Cli工具dao自动生成4.业务模型须知5.Cli工具service/logic自动生成 - 接口6.Controller/Api创建1.项目创建 官网 - 项目创建-init 开发文档 - 目录介绍 官网 - 示例项目 1.gf init 项目名 &#xff08;创建项目…

无法定位程序输入点kernel32.dll,如何修复kernel32.dll

kernel32.dll是Windows操作系统中非常重要的一个系统文件&#xff0c;如果它丢失或损坏可能会导致许多应用程序无法正常运行。今天小编就来给大家详细的讲解一下无法定位程序输入点kernel32.dll&#xff0c;我们要怎么修复这个kernel32.dll缺失的问题。 一.kernel32.dll时候什么…

前端开发环境配置,浏览器跨域配置,代码提交配置git等

这是我目前公司的开发配置文档大家可以参考&#xff1a; 前端文档 1 搭建前端环境 1.1 安装nodejs 1.1.1 nodejs下载地址 https://nodejs.org/dist/v10.15.3/node-v10.15.3-x64.msi&#xff08;win64&#xff09; https://nodejs.org/dist/v10.15.3/node-v10.15.3.pkg&…

查询性能较 Trino/Presto 3-10 倍提升!Apache Doris 极速数据湖分析深度解读

从上世纪 90 年代初 Bill Inmon 在《building the Data Warehouse》一书中正式提出数据仓库这一概念&#xff0c;至今已有超过三十年的时间。在最初的概念里&#xff0c;数据仓库被定义为「一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合&#xff0c;用于支持管理…

Python排序 -- 内附蓝桥题:错误票据,奖学金

排序 ~~不定时更新&#x1f383;&#xff0c;上次更新&#xff1a;2023/02/28 &#x1f5e1;常用函数&#xff08;方法&#xff09; 1. list.sort() --> sort 是 list 的方法&#xff0c;会直接修改 list 举个栗子&#x1f330; li [2,3,1,5,4] li.sort() print(li) …

New Bing怼人、说谎、PUA,ChatGPT已经开始胡言乱语了

最近&#xff0c;来自大洋彼岸那头的ChatGPT科技浪潮席卷而来&#xff0c;微软将chatGPT整合搜索引擎Bing开启内测后&#xff0c;数百万用户蜂拥而至&#xff0c;都想试试这个「百事通」。 赶鸭子上架&#xff0c;“翻车”了&#xff1f; 但短短上线十几天&#xff0c;嵌入了…

5个开源的Java项目快速开发脚手架

概览 &#xff1a; GunspigRuoYiJeecg-bootiBase4J 一、Guns 推荐指数 &#xff1a;⭐⭐⭐⭐⭐ 简介 采用主流框架 &#xff1a; 基于 Spring Boot2.0版本开发&#xff0c;并且支持 Spring Cloud Alibaba 微服务。功能齐全 &#xff1a;包含系统管理&#xff0c;代码生成&a…

python线程池【ThreadPoolExecutor()】批量获取博客园标题数据

转载&#xff1a;蚂蚁学python 网址&#xff1a;【【2021最新版】Python 并发编程实战&#xff0c;用多线程、多进程、多协程加速程序运行】 https://www.bilibili.com/video/BV1bK411A7tV/?p8&share_sourcecopy_web&vd_sourced0ef3d08fdeef1740bab49cdb3e96467实战案…

SpringMVC 面试题

1、什么是SpringMVC&#xff1f; SpringMVC是一个基于Java的实现了MVC设计模式的“请求驱动型”的轻量级WEB框架&#xff0c;通过把model&#xff0c;view&#xff0c;controller 分离&#xff0c;将web层进行职责的解耦&#xff0c;把复杂的web应用分成逻辑清晰的几个部分&am…