IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 多分类任务ovo、ovr及softmax回归 -> 正文阅读

[人工智能]多分类任务ovo、ovr及softmax回归

多分类任务OVO、OVR及softmax回归 – 潘登同学的Machine Learning笔记

简单回顾Logistic回归

  • 总目标:分类

逻辑回归就是在多元线性回归基础上把结果缩放到 0 到 1 之间。 h θ ( x ) h_{\theta}(x) hθ?(x) 越接近1 越是正例, h θ ( x ) h_{\theta}(x) hθ?(x) 越接近 0 越是负例,根据中间 0.5 分为二类;

  • 模型:
    y ^ = h θ ( x ) = g ( θ T x ) = 1 1 + e ? θ T x \hat{y} = h_{\theta}(x)= g(\theta^Tx) = \frac{1}{1+e^{-\theta^Tx}} y^?=hθ?(x)=g(θTx)=1+e?θTx1?

y ^ \hat{y} y^?值: 概率含义( y ^ \hat{y} y^?越大说明分成正例的概率越大)

  • 优化目标:分类的越精确越好, 分对的越多越好

  • Loss函数:

L ( θ ) = ? ∑ i = 1 m ( y i log ? h θ ( x i ) + ( 1 ? y i ) log ? ( 1 ? h θ ( x i ) ) L(\theta) = -\sum_{i=1}^{m}(y_{i}\log h_{\theta}(x_{i}) + (1-y_{i})\log (1-h_{\theta}(x_{i})) L(θ)=?i=1m?(yi?loghθ?(xi?)+(1?yi?)log(1?hθ?(xi?))

Logistic回归实现多分类问题

  • Logistic回归就是二分类器, 那应该怎么做多分类呢?

我们想到 y ^ \hat{y} y^?的值不是有概率含义嘛, 把多分类任务转换成很多个二分类任务, 然后根据概率的大小分类;

考察如下分类任务:

多分类问题

One-vs-all(one-vs-rest)

OVR的思想就是用一个类别去与其他类别进行二分类, 然后进行多次这样的分类, 选择概率值最大的那个类别;

OVR的一个核心是生成假数据集;

当对红色做二分类时, 就要将其他两个变成同一类别:

ovr1

ovr2

ovr3

  • 将其表示为数学形式

h θ ( 1 ) ( x ) = P ( y = 1 ∣ x ; θ ) h θ ( 2 ) ( x ) = P ( y = 2 ∣ x ; θ ) h θ ( 3 ) ( x ) = P ( y = 3 ∣ x ; θ ) h_{\theta}^{(1)}(x) = P(y=1|x;\theta) \\ h_{\theta}^{(2)}(x) = P(y=2|x;\theta) \\ h_{\theta}^{(3)}(x) = P(y=3|x;\theta) \\ hθ(1)?(x)=P(y=1x;θ)hθ(2)?(x)=P(y=2x;θ)hθ(3)?(x)=P(y=3x;θ)

  • 总的来说
    h θ ( i ) ( x ) = P ( y = i ∣ x ; θ ) h_{\theta}^{(i)}(x) = P(y=i|x;\theta) \\ hθ(i)?(x)=P(y=ix;θ)
  • 根据概率最大选择类别
    max ? i h θ ( i ) ( x ) \max_i h_{\theta}^{(i)}(x) imax?hθ(i)?(x)

实战OVR对上次的鸢尾花数据进行多分类

上次我们对鸢尾花数据分类只是分为属于setosa和不属于setosa;

其实这不就是OVR的一部分嘛, 我们这次把3个类别setosa,versicolor,virginica都实现分类;

话不多说, 上代码!!!

#%%多分类任务
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import seaborn as sns
path = 'iris.csv'
data = pd.read_csv(path)

np.random.seed(2)
x = data.iloc[:,2:4]
y = data.iloc[:,4]
y.replace(['setosa','versicolor','virginica'],[0,1,2],inplace = True)#把品种转化为0 1 2

sns.set()
sns.scatterplot(data['petal_length'],data['petal_width'],hue = data['species'])
#划分训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3)

log_reg = LogisticRegression(solver='sag',max_iter=100000,multi_class='ovr')  #ovr表示one-vs-rest 
#公式中默认自带penalty L2正则项   和  L2 前面的系数1/C  C 默认是1
log_reg.fit(x_train,y_train)
log_reg.coef_

y_hat = log_reg.predict_proba(x_test)
#这个第一列表示是零这一类的的概率
#将概率转化为预测结果
idx = np.argmax(y_hat, axis=1)

#比较预测结果与实际值
print(idx == y_test) 
#发现结果中有一个错误

OVO(One vs One)

另外一个做多分类的思想就是把所有类别的数据, 每个分类器只挑两个类别做二分类, 得出属于哪一类; 最后把所有分类器的结果放在一起, 选择最多的那个类别;

以三分类为例
A与B进行二分类
分为A类
A与C进行二分类
B与C进行二分类
分为C类
投票选出A类

这也属于机器学习的经典范式, 就是自下而上的决策, 根据所有分类器对结果进行投票, 票数高者就是最终结果;

实战OVO对鸢尾花数据进行多分类

在sklearn中, OVO的参数是’multinomial’,

话不多说, 上代码!!!

#%%多分类任务OVO
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import seaborn as sns
path = 'iris.csv'
data = pd.read_csv(path)

np.random.seed(2)
x = data.iloc[:,2:4]
y = data.iloc[:,4]
y.replace(['setosa','versicolor','virginica'],[0,1,2],inplace = True)#把品种转化为0 1 2

sns.set()
sns.scatterplot(data['petal_length'],data['petal_width'],hue = data['species'])
#划分训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3)

log_reg = LogisticRegression(solver='sag',max_iter=100000,multi_class='multinomial')  #multinomial表示OVO 
#公式中默认自带penalty L2正则项   和  L2 前面的系数1/C  C 默认是1
log_reg.fit(x_train,y_train)
log_reg.coef_

y_hat = log_reg.predict_proba(x_test)
#这个第一列表示是零这一类的的概率
#将概率转化为预测结果
idx = np.argmax(y_hat, axis=1)

#比较预测结果与实际值
print(idx == y_test) 
#发现结果中有一个错误
  • 而不论是OVO还是OVR, 本质上都是二分类, 那么有没有直接多分类的算法呢?

那就是Softmax!!!

Softmax回归

  • 总目标:多分类

Softmax也是在多元线性回归基础上把结果缩放到 0 到 1 之间。 然后依据属于哪一类的概率最高, 选择该类;

  • 模型:
    y i ^ = h θ ( x i ) = [ P ( y i = 1 ∣ x i ; θ ) P ( y i = 2 ∣ x i ; θ ) ? P ( y i = k ∣ x i ; θ ) ] = 1 ∑ j = 1 k e ? θ j T x i [ e ? θ 1 T x i e ? θ 2 T x i ? e ? θ k T x i ] \hat{y^i} = h_{\theta}(x^i) = {\begin{bmatrix} P(y^i=1|x^i;\theta) \\ P(y^i=2|x^i;\theta) \\ \vdots \\ P(y^i=k|x^i;\theta) \\ \end{bmatrix}} = \frac{1}{\sum_{j=1}^{k}e^{-\theta_j^Tx^i}} {\begin{bmatrix} e^{-\theta_1^Tx^i} \\ e^{-\theta_2^Tx^i} \\ \vdots \\ e^{-\theta_k^Tx^i} \\ \end{bmatrix}} yi^?=hθ?(xi)=??????P(yi=1xi;θ)P(yi=2xi;θ)?P(yi=kxi;θ)???????=j=1k?e?θjT?xi1????????e?θ1T?xie?θ2T?xi?e?θkT?xi????????

y ^ \hat{y} y^?值: 概率含义( y ^ \hat{y} y^?越大说明分成该例的概率越大)

上面的角标解释: 头上顶着i表示第i条样本, 下标是j表示第j组参数;

模型参数比较复杂, 不像之前的多元线性回归的参数基本上是一个行向量 [ θ 1 , θ 2 , ? ? , θ n ] [\theta_1, \theta_2, \cdots, \theta_n] [θ1?,θ2?,?,θn?]

而softmax模型的参数为 θ k × n \theta_{k \times n} θk×n?, 将其按行分块:
[ θ 1 θ 2 ? θ k ] k × n \begin{bmatrix} \theta_1 \\ \theta_2 \\ \vdots \\ \theta_k \\ \end{bmatrix}_{k \times n} ??????θ1?θ2??θk????????k×n?
举个栗子:
θ 1 × x 1 \theta_1 \times x_1 θ1?×x1?
这个结果进行非线性变换后就表示第一个样本属于第一类的概率;

所以结果矩阵 X m × n ? θ k × n T X_{m \times n} \cdot \theta_{k \times n}^T Xm×n??θk×nT?

  • 优化目标:分类的越精确越好, 分对的越多越好

根据Logistic回归的Loss函数也可以想到loss函数大概就是: 分对的概率取个负数(loss越小越好)
L ( θ ) = ? ∑ i = 1 m ∑ j = 1 k y j i log ? p j i L(\theta) = -\sum_{i=1}^{m}\sum_{j=1}^{k}y_{j}^{i} \log p_{j}^{i} L(θ)=?i=1m?j=1k?yji?logpji?

其中 y j i y_{j}^{i} yji?表示第i样本是否属于第j个类别(如果属于是则为1, 不是则为0); p j i p_{j}^{i} pji?为预测值(表示第i样本是否属于第j个类别的预测概率)

后面还会详细讲loss函数, 先有初步感知即可;

从广义线性回归推导出 softmax

像Logistic回归假设服从二项分布;
像多元线性回归假设服从高斯分布;

softmax回归假设服从多项分布的, 可以理解为二项分布的推广, 也契合了做多分类的特点;

推导说明多项分布是指数族分布

  • 多项式分布的目标值 y ∈ { 1 , 2 , 3 , … , k } y\in \{1,2,3,\ldots,k\} y{1,2,3,,k};(其中是类别种数)其概率分布为:
    I { y = i } = φ i , 且 ∑ i = 1 k φ i = 1 I\{y=i\}=\varphi_i , 且\sum_{i=1}^{k}\varphi_i = 1\\ I{y=i}=φi?,i=1k?φi?=1

  • 其联合分布的概率密度函数为:

P ( y ; φ ) = φ 1 I { y = 1 } φ 2 I { y = 2 } … φ k ? 1 I { y = k ? 1 } φ k I { y = k } = φ 1 I { y = 1 } φ 2 I { y = 2 } … φ k ? 1 I { y = k ? 1 } φ k 1 ? ∑ i = 1 k ? 1 I { y = i } = e log ? ( φ 1 I { y = 1 } φ 2 I { y = 2 } … φ k ? 1 I { y = k ? 1 } φ k 1 ? ∑ i = 1 k ? 1 I { y = i } ) = e ( ∑ i = 1 k ? 1 I { y = i } log ? φ i + ( 1 ? ∑ i = 1 k ? 1 I { y = i } ) log ? φ k ) = e ( ∑ i = 1 k ? 1 I { y = i } log ? φ i φ k + log ? φ k ) = e ( ∑ i = 1 k ? 1 log ? φ i φ k T ( y ) i + log ? φ k ) = e ( ∑ i = 1 k log ? φ i φ k T ( y ) i + log ? φ k ) ( 因 为 log ? φ k φ k 为 0 , 所 以 加 上 之 后 不 影 响 ) = e ( η T T ( y ) ? a ( η ) ) \begin{aligned} P(y;\varphi) &= \varphi_1^{I\{y=1\}}\varphi_2^{I\{y=2\}}\ldots\varphi_{k-1}^{I\{y=k-1\}}\varphi_k^{I\{y=k\}} \\ &= \varphi_1^{I\{y=1\}}\varphi_2^{I\{y=2\}}\ldots\varphi_{k-1}^{I\{y=k-1\}}\varphi_k^{1-\sum_{i=1}^{k-1}I\{y=i\}} \\ &= e^{\log (\varphi_1^{I\{y=1\}}\varphi_2^{I\{y=2\}}\ldots\varphi_{k-1}^{I\{y=k-1\}}\varphi_k^{1-\sum_{i=1}^{k-1}I\{y=i\}})} \\ &= e^{(\sum_{i=1}^{k-1}I\{y=i\}\log\varphi_i + (1-\sum_{i=1}^{k-1}I\{y=i\})\log\varphi_k)} \\ &= e^{(\sum_{i=1}^{k-1}I\{y=i\}\log\frac{\varphi_i}{\varphi_k} + \log\varphi_k)} \\ &= e^{(\sum_{i=1}^{k-1}\log\frac{\varphi_i}{\varphi_k}T(y)_i + \log\varphi_k)} \\ &= e^{(\sum_{i=1}^{k}\log\frac{\varphi_i}{\varphi_k}T(y)_i + \log\varphi_k)} (因为\log\frac{\varphi_k}{\varphi_k}为0,所以加上之后不影响)\\ &= e^{(\eta^TT(y)-a(\eta))}\\ \end{aligned} P(y;φ)?=φ1I{y=1}?φ2I{y=2}?φk?1I{y=k?1}?φkI{y=k}?=φ1I{y=1}?φ2I{y=2}?φk?1I{y=k?1}?φk1?i=1k?1?I{y=i}?=elog(φ1I{y=1}?φ2I{y=2}?φk?1I{y=k?1}?φk1?i=1k?1?I{y=i}?)=e(i=1k?1?I{y=i}logφi?+(1?i=1k?1?I{y=i})logφk?)=e(i=1k?1?I{y=i}logφk?φi??+logφk?)=e(i=1k?1?logφk?φi??T(y)i?+logφk?)=e(i=1k?logφk?φi??T(y)i?+logφk?)(logφk?φk??0,)=e(ηTT(y)?a(η))?
注意:上面是把求和写成了内积形式, 什么是内积

这样我们就把多项式分布写成了指数族分布, 而有了指数族分布, 就能推导出softmax回归的公式;

由指数族分布推导softmax回归

  • 由上面的式子, 有:

η = [ log ? φ 1 φ k log ? φ 2 φ k ? log ? φ k ? 1 φ k log ? φ k φ k ] \eta = {\begin{bmatrix} \log\frac{\varphi_1}{\varphi_k} \\ \log\frac{\varphi_2}{\varphi_k} \\ \vdots \\ \log\frac{\varphi_{k-1}}{\varphi_k} \\ \log\frac{\varphi_{k}}{\varphi_k} \\ \end{bmatrix}} η=?????????logφk?φ1??logφk?φ2???logφk?φk?1??logφk?φk????????????

  • 由单个 η i \eta_i ηi? 推导 φ i \varphi_i φi?

η i = φ i φ k ? φ i = φ k e η i 又 ∵ ∑ i = 1 k φ i = ∑ i = 1 k φ k e η i = 1 ∴ φ k = 1 ∑ i = 1 k e η i ∴ φ i = e η i ∑ i = 1 k e η i {\eta_i = \frac{\varphi_i}{\varphi_k}} \Rightarrow {\varphi_i = \varphi_k e^{\eta_i}} \\ 又 \because \sum_{i=1}^{k}\varphi_i = \sum_{i=1}^{k}\varphi_k e^{\eta_i} = 1 \\ \therefore \varphi_k = \frac{1}{\sum_{i=1}^{k}e^{\eta_i}}\\ \therefore \varphi_i = \frac{e^{\eta_i}}{\sum_{i=1}^{k}e^{\eta_i}}\\ ηi?=φk?φi???φi?=φk?eηi?i=1k?φi?=i=1k?φk?eηi?=1φk?=i=1k?eηi?1?φi?=i=1k?eηi?eηi??

回想: φ i \varphi_i φi?的含义:就是y属于i类的概率;

  • 至此, 我们就得到了softmax回归的公式

softmax回归公式

y i ^ = h θ ( x i ) = [ P ( y i = 1 ∣ x i ; θ ) P ( y i = 2 ∣ x i ; θ ) ? P ( y i = k ∣ x i ; θ ) ] = 1 ∑ j = 1 k e θ j T x i [ e θ 1 T x i e θ 2 T x i ? e θ k T x i ] \hat{y^i} = h_{\theta}(x^i) = {\begin{bmatrix} P(y^i=1|x^i;\theta) \\ P(y^i=2|x^i;\theta) \\ \vdots \\ P(y^i=k|x^i;\theta) \\ \end{bmatrix}} = \frac{1}{\sum_{j=1}^{k}e^{\theta_j^Tx^i}} {\begin{bmatrix} e^{\theta_1^Tx^i} \\ e^{\theta_2^Tx^i} \\ \vdots \\ e^{\theta_k^Tx^i} \\ \end{bmatrix}} yi^?=hθ?(xi)=??????P(yi=1xi;θ)P(yi=2xi;θ)?P(yi=kxi;θ)???????=j=1k?eθjT?xi1????????eθ1T?xieθ2T?xi?eθkT?xi????????

图示softmax回归模型

图示softmax回归模型

softmax回归的Loss函数

推导的流程基本上与Logistic回归的推导类似:

取对数
取负号
最大似然估计构造损失函数
最大化正确分类的概率
将连乘变为连加
将取最大变成Loss取最小
  • 最大似然估计构造损失函数
    L ( θ ) = ∏ i = 1 m P ( y i ∣ x i ; θ ) = ∏ i = 1 m ∏ j = 1 k φ j I { y i = j } \begin{aligned} {\Bbb{L}(\theta)} &= \prod_{i=1}^{m} P(y^i|x^i;\theta)\\ &= \prod_{i=1}^{m}\prod_{j=1}^{k}\varphi_j^{I\{y^i=j\}}\\ \end{aligned} L(θ)?=i=1m?P(yixi;θ)=i=1m?j=1k?φjI{yi=j}??
    注意:上面这个式子看上去会有点懵, 但是根据最大化分对的概率, 写成连乘就是这样;

    i还是表示第i个样本, j表示第j个类别, 如: I { y i = j } I\{y^i=j\} I{yi=j}则表示第i个样本属于j类的标签(属于为1, 不属于为0)

  • 取对数

log ? L ( θ ) = ∑ i = 1 m log ? P ( y i ∣ x i ; θ ) = ∑ i = 1 m log ? ∏ j = 1 k ( θ j T x i ∑ l = 1 k θ l T x i ) I { y i = j } \begin{aligned} \log {\Bbb{L}(\theta)} &= \sum_{i=1}^{m}\log P(y^i|x^i;\theta) \\ &= \sum_{i=1}^{m}\log \prod_{j=1}^{k} (\frac{\theta_j^Tx^i}{\sum_{l=1}^{k}\theta_l^Tx^i})^{I\{y^i=j\}} \\ \end{aligned} logL(θ)?=i=1m?logP(yixi;θ)=i=1m?logj=1k?(l=1k?θlT?xiθjT?xi?)I{yi=j}?

  • 稍微改写取负数
    L o s s = ? ∑ i = 1 m ∑ j = 1 k I { y i = j } log ? ( θ j T x i ∑ l = 1 k θ l T x i ) \begin{aligned} Loss &= -\sum_{i=1}^{m}\sum_{j=1}^{k} {I\{y^i=j\}} \log (\frac{\theta_j^Tx^i}{\sum_{l=1}^{k}\theta_l^Tx^i}) \\ \end{aligned} Loss?=?i=1m?j=1k?I{yi=j}log(l=1k?θlT?xiθjT?xi?)?

注意: log ? 后 面 就 是 预 测 值 y ^ , log ? 前 面 就 是 实 际 值 y \log后面就是预测值\hat{y}, \log前面就是实际值y logy^?,logy

逻辑回归和 Softmax 回归的关系

逻辑回归可以看成是 Softmax 回归的特例,就是 k=2 时候的 softmax 回归,因为当 我们把 softmax 回归公式 k=2 带入的话

h θ ( x ) = 1 e θ 1 T x + θ 2 T x [ e θ 1 T x i e θ 2 T x i ] = 1 e 0 ? T x + ( θ 2 ? θ 1 ) T x [ e 0 ? T x i e ( θ 2 ? θ 1 ) T x i ] = [ 1 1 + e ( θ 2 ? θ 1 ) T x i 1 ? 1 1 + e ( θ 2 ? θ 1 ) T x i ] \begin{aligned} h_{\theta}(x) &= \frac{1}{e^{\theta_1^Tx + \theta_2^Tx}} {\begin{bmatrix} e^{\theta_1^Tx^i} \\ e^{\theta_2^Tx^i} \\ \end{bmatrix}} \\ &= \frac{1}{e^{\vec{0}^Tx + (\theta_2-\theta_1)^Tx}} {\begin{bmatrix} e^{\vec{0}^Tx^i} \\ e^{(\theta_2-\theta_1)^Tx^i} \\ \end{bmatrix}} \\ &= {\begin{bmatrix} \frac{1}{1 + e^{(\theta_2-\theta_1)^Tx^i}} \\ 1-\frac{1}{1 + e^{(\theta_2-\theta_1)^Tx^i}} \\ \end{bmatrix}} \\ \end{aligned} hθ?(x)?=eθ1T?x+θ2T?x1?[eθ1T?xieθ2T?xi?]=e0 Tx+(θ2??θ1?)Tx1?[e0 Txie(θ2??θ1?)Txi?]=[1+e(θ2??θ1?)Txi1?1?1+e(θ2??θ1?)Txi1??]?

此时softmax回归就是参数为 ( θ 2 ? θ 1 ) (\theta_2-\theta_1) (θ2??θ1?)的逻辑回归

实战softmax回归

因为sklearn没有封装专门的softmax回归, 而是把他放进了LogisticRegression里面, 还记得前面的OVR和OVO嘛? LogisticRegression的OVO就是softmax(网上说的), 但是根据前面的原理, 他俩显然不一样, 所以这里有待考证…

关键是知道直接多分类的算法就是softmax; 算法实现好处理

就把他当作softmax吧, 话不多说, 上代码!!!

#%%softmax回归实现多分类
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import seaborn as sns
path = 'iris.csv'
data = pd.read_csv(path)

np.random.seed(2)
x = data.iloc[:,2:4]
y = data.iloc[:,4]
y.replace(['setosa','versicolor','virginica'],[0,1,2],inplace = True)#把品种转化为0 1 2

sns.set()
sns.scatterplot(data['petal_length'],data['petal_width'],hue = data['species'])
#划分训练集和测试集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size = 0.3)

log_reg = LogisticRegression(solver='sag',max_iter=100000,multi_class='multinomial')  #multinomial表示softmax 回归
#公式中默认自带penalty L2正则项   和  L2 前面的系数1/C  C 默认是1
log_reg.fit(x_train,y_train)
log_reg.coef_

y_hat = log_reg.predict_proba(x_test)
#这个第一列表示是零这一类的的概率
#将概率转化为预测结果
idx = np.argmax(y_hat, axis=1)

#比较预测结果与实际值
print(idx == y_test) 
#发现结果中有一个错误

softmax回归就是这样了, 继续下一章吧!pd的Machine Learning

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 14:56:26  更:2021-10-24 14:58:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 8:39:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码