栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

机器学习基础备忘录

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

机器学习基础备忘录

本文侧重代码实现,不讨论原理。

文章目录
    • 距离计算
    • 模型选择
      • 留出法
      • 交叉验证法
      • 留一法
    • 性能度量
      • 均方误差MSE
      • 均方根误差RMSE
      • 平均绝对误差MAE
      • 准确率
      • 混淆矩阵
      • ROC曲线
      • 协方差Cov
    • Sklearn线性模型
      • 线性回归
      • 逻辑回归
    • Pytorch简介
      • 偏导数计算
      • 多次求导
      • 非标量输出
      • 线性回归
    • SVM
      • 基本原理
      • 重要公式
      • 代码实现
      • 指定核函数
    • 卷积神经网络
      • 图像尺寸变化
      • 代码实例
      • 代码结果分析
      • 池化层

距离计算

欧 氏 距 离 : d ( x , y ) = ∑ k = 1 N ( x k − y k ) 2 欧氏距离:d(x,y)=sqrt{sum_{k=1}^{N}(x_k-y_k)^2} 欧氏距离:d(x,y)=k=1∑N​(xk​−yk​)2 ​

曼 哈 顿 距 离 : d ( x , y ) = ∑ k = 1 N ∣ x k − y k ∣ 曼哈顿距离:d(x,y)=sum_{k=1}^N|x_k-y_k| 曼哈顿距离:d(x,y)=k=1∑N​∣xk​−yk​∣

切 比 雪 夫 距 离 : d ( x , y ) = max ⁡ ( ∣ x k − y k ∣ ) 切比雪夫距离:d(x,y)=max(|x_k-y_k|) 切比雪夫距离:d(x,y)=max(∣xk​−yk​∣)

余 弦 距 离 : c o s θ = x 1 x 2 + y 1 y 2 x 1 2 + x 2 2 y 1 2 + y 2 2 余弦距离:costheta=frac{x_1x_2+y_1y_2}{sqrt{x_1^2+x_2^2}sqrt{y_1^2+y_2^2}} 余弦距离:cosθ=x12​+x22​ ​y12​+y22​ ​x1​x2​+y1​y2​​

import numpy as np

dot1 = np.array([1,2])  # 第一个点的坐标(1,2)
dot2 = np.array([4,5])  # 第二个点的坐标(4,5)

d1 = np.sqrt(np.sum((dot1-dot2)**2))  # 欧氏距离
d2 = np.sum(np.abs(dot1-dot2))  # 曼哈顿距离
d3 = np.max(np.abs(dot1-dot2))  # 切比雪夫距离
d4 = np.dot(dot1,dot2) / np.sqrt(np.dot(dot1,dot1)*np.dot(dot2,dot2))  # 余弦距离
模型选择 留出法

将数据分为训练集和测试集,使用训练集生成模型,使用测试集检验模型准确率。

# 核心代码
train_test_split(data,data_lable,test_size=0.6)
# 完整代码
from sklearn.model_selection import train_test_split
import numpy as np

data = np.array([10,21,23,53,63])  # 需要划分的数据
data_lable = [0,1,2,3,4]  # 上述数据的标签
"""
训练集数据, 测试集数据, 训练集标签, 测试集标签 = 
train_test_split(数据列表,数据列表标签,test_size=训练集/总数)
"""
data_train, data_test, lable_train, lable_test = train_test_split(data,data_lable,test_size=0.6)

交叉验证法

相当于多次train_test_split操作。将数据集划分为k个大小相似的子集,每次选取其中一个子集作为测试集,其他数据作为训练集。如[10,20,30,40],我们设k=4,则生成如下4种数据集:

训练集:[10,20,30],测试集:[40]
训练集:[10,20,40],测试集:[30]
训练集:[10,30,40],测试集:[20]
训练集:[20,30,40],测试集:[10]

代码如下:

# 核心代码
"""
将data数组分成3折 : KFold(n_splits=3).split(data)  
train_index:训练集索引  使用data[train_index]获取训练集
test_index:测试集索引  使用data[test_index]获取测试集
"""
for train_index, test_index in KFold(n_splits=3).split(data):
  ...略...
# 完整代码
import numpy as np
from sklearn.model_selection import KFold

data = np.array([10,21,23,53,63,25])  # 需要划分的数据

for train_index, test_index in KFold(n_splits=3).split(data):
    print("————————————————————————————————")
    print("训练集索引:",train_index,"训练集:",data[train_index])
    print("测试集索引:",test_index,"测试集:",data[test_index])
# 输出
————————————————————————————————
训练集索引: [2 3 4 5] 训练集: [23 53 63 25]
测试集索引: [0 1] 测试集: [10 21]
————————————————————————————————
训练集索引: [0 1 4 5] 训练集: [10 21 63 25]
测试集索引: [2 3] 测试集: [23 53]
————————————————————————————————
训练集索引: [0 1 2 3] 训练集: [10 21 23 53]
测试集索引: [4 5] 测试集: [63 25]
留一法

交叉验证的变种,每次只留一个数据作为测试集。例如有n个数需要被划分,则留一法就相当于k=n的交叉验证。

# 核心代码
for train_index, test_index in LeaveOneOut().split(data):
  ...略...
# 完整代码
from sklearn.model_selection import LeaveOneOut
import numpy as np

data = np.array([10,20,30,40])

for train_index, test_index in LeaveOneOut().split(data):
    print("————————————————————————————————")
    print("训练集索引:",train_index,"训练集:",data[train_index])
    print("测试集索引:",test_index,"测试集:",data[test_index])
# 输出
————————————————————————————————
训练集索引: [1 2 3] 训练集: [20 30 40]
测试集索引: [0] 测试集: [10]
————————————————————————————————
训练集索引: [0 2 3] 训练集: [10 30 40]
测试集索引: [1] 测试集: [20]
————————————————————————————————
训练集索引: [0 1 3] 训练集: [10 20 40]
测试集索引: [2] 测试集: [30]
————————————————————————————————
训练集索引: [0 1 2] 训练集: [10 20 30]
测试集索引: [3] 测试集: [40]
性能度量 均方误差MSE

M S E = 1 n ∑ i = 1 n ( f ( x i ) − y i ) 2 MSE = frac{1}{n}sum_{i=1}^{n}(f(x_i)-y_i)^2 MSE=n1​i=1∑n​(f(xi​)−yi​)2

实现如下:

# 核心代码
"""
均方误差 = mean_squared_error(真值列表,预测值列表)
"""
result = mean_squared_error(y_true, y_pred)   
import numpy as np                            
from sklearn.metrics import mean_squared_error
                                              
y_true = np.array([1, 2, 3, 4, 5, 6])  # 正确数据 
y_pred = np.array([0, 2, 2, 4, 5, 7])  # 预测数据 
                                              
result = mean_squared_error(y_true, y_pred)
# result结果为0.5
均方根误差RMSE

R M S E = 1 n ∑ i = 1 n ( f ( x i ) − y i ) 2 RMSE = sqrt{frac{1}{n}sum_{i=1}^{n}(f(x_i)-y_i)^2} RMSE=n1​i=1∑n​(f(xi​)−yi​)2 ​

# 实现(MSE套一层根号即可)
result = np.sqrt( mean_squared_error(y_true, y_pred) )
平均绝对误差MAE

M A E = 1 n ∑ i = 1 m ∣ f ( x i ) − y i ∣ MAE = frac{1}{n}sum_{i=1}^{m}|f(x_i)-y_i| MAE=n1​i=1∑m​∣f(xi​)−yi​∣

实现起来非常简单,就是将MSE中的mean_squared_error替换成mean_absolute_error。

# 实现
import numpy as np                            
from sklearn.metrics import mean_absolute_erro
                                              
y_true = np.array([1, 2, 3, 4, 5, 6])  # 正确数据 
y_pred = np.array([0, 2, 2, 4, 5, 7])  # 预测数据 
                                              
result = mean_absolute_error(y_true, y_pred)  
准确率

预测对的 / 所有
a c c = 1 n ∑ i = 1 n ( f ( x i ) = y i ) acc=frac{1}{n}sum_{i=1}^{n}(f(x_i)=y_i) acc=n1​i=1∑n​(f(xi​)=yi​)

# 核心代码
"""
准确率 = accuracy_score(正确数据列表,预测数据列表)   
"""
result = accuracy_score(y_true,y_pred)    
# 完整代码
import numpy as np                         
from sklearn.metrics import accuracy_score 
                                           
y_true = np.array([1, 2, 3, 4, 5, 6])  # 正确
y_pred = np.array([0, 2, 2, 4, 5, 7])  # 预测
                                           
result = accuracy_score(y_true,y_pred)     
混淆矩阵
真实情况预测结果正例反例
正例TP(真正例)FN(假反例)
反例FP(假正例)TN(真反例)
  • 查准率:预测为正中,预测正确的概率
    P = T P T P + F P P=frac{TP}{TP+FP} P=TP+FPTP​

  • 查全率:真实情况为正中,预测正确的概率
    R = T P T P + F N R = frac{TP}{TP+FN} R=TP+FNTP​

  • 准确率
    A C C = T P + T N T P + F P + T N + F N ACC = frac{TP+TN}{TP+FP+TN+FN} ACC=TP+FP+TN+FNTP+TN​

通过生成真实数据与预测数据的混淆矩阵,可以更好的看出预测的情况。

# 核心代码
"""
混淆矩阵 = confusion_matrix(真实数据集,预测数据集,labels=标签集) 
此处的标签集不好理解,看下面的样例就懂了
"""
result = confusion_matrix(y_true,y_pred,labels=[0,1])   
# 完整代码
import numpy as np                                         
from sklearn.metrics import confusion_matrix               
                                                           
y_pred = np.array([0, 1, 0, 1])  # 预测数据                       
y_true = np.array([1, 0, 1, 1])  # 正确数据                       
                                                           
result = confusion_matrix(y_true,y_pred,labels=[0,1])      
# 输出
[[0 1]
 [2 1]]

上述输出可以用如下表格来解释

此处假设0为正例,1为反例

真实情况预测结果01
001
121

以上表格蕴含了以下信息:

真实情况预测结果预测次数结果
000真正例TP = 0
011假反例FN = 1,预测错误1次
102假正例FP = 2,预测错误2次
111真反例TN = 1,预测成功1次

查 准 率 = T P T P + F P = 0 0 + 2 = 0 查准率 = frac{TP}{TP+FP}=frac{0}{0+2}=0 查准率=TP+FPTP​=0+20​=0

查 全 率 = T P T P + F N = 0 0 + 1 = 0 查全率 = frac{TP}{TP+FN}=frac{0}{0+1}=0 查全率=TP+FNTP​=0+10​=0

准 确 率 = T P + T N T P + F P + T N + F N = 0 + 1 0 + 2 + 1 + 1 = 1 4 准确率=frac{TP+TN}{TP+FP+TN+FN}=frac{0+1}{0+2+1+1} = frac{1}{4} 准确率=TP+FP+TN+FNTP+TN​=0+2+1+10+1​=41​

实际上,sklearn也提供了直接计算查准率的函数precision_score

# 查准率
import numpy as np
from sklearn.metrics import precision_score

y_pred = np.array([0, 1, 0, 1])  # 预测数据
y_true = np.array([1, 0, 1, 1])  # 正确数据

accu = precision_score(y_true,y_pred,average='macro')
# accu结果为0.25
ROC曲线
真实情况预测结果正例反例
正例TP(真正例)FN(假反例)
反例FP(假正例)TN(真反例)

R O C 曲 线 X 轴 : f p r = F P F P + T N = 真 实 情 况 中 : 反 例 预 测 错 误 的 真 实 情 况 中 : 反 例 总 和 ROC曲线X轴:fpr=frac{FP}{FP+TN}=frac{真实情况中:反例预测错误的}{真实情况中:反例总和} ROC曲线X轴:fpr=FP+TNFP​=真实情况中:反例总和真实情况中:反例预测错误的​

R O C 曲 线 Y 轴 : t p r ( 查 全 率 ) = T P T P + F N = 真 实 情 况 中 : 正 例 中 预 测 正 确 的 真 实 情 况 中 : 正 例 总 和 ROC曲线Y轴:tpr(查全率)=frac{TP}{TP+FN}=frac{真实情况中:正例中预测正确的}{真实情况中:正例总和} ROC曲线Y轴:tpr(查全率)=TP+FNTP​=真实情况中:正例总和真实情况中:正例中预测正确的​

在ROC曲线中,AUC(曲线下的面积)值越大,说明该模型性能越好。

# 核心代码
"""
x轴列表, y轴列表, _ = roc_curve(真实数据,预测数据)
曲线下面积 = auc(x轴列表, y轴列表)
"""
fpr_x, tpr_y, _ = roc_curve(y_true, y_pred)  # 生成ROC曲线的x、y值列表
auc = auc(fpr_x, tpr_y)  # 计算曲线下的面积
# 完整代码
import numpy as np
from sklearn.metrics import roc_curve, auc

y_pred = np.array([0.1, 0.8, 0.2, 0.5, 0.5, 0.7, 0.3, 0.1])  # 预测数据
y_true = np.array([0, 1, 0, 1, 1, 1, 0, 1])  # 正确数据

fpr_x, tpr_y, _ = roc_curve(y_true, y_pred)  # 生成ROC曲线的x、y值列表
auc = auc(fpr_x, tpr_y)  # 计算曲线下的面积
# auc结果为0.8333333333333334
协方差Cov

C o v ( X , Y ) = ∑ i = 1 n ( x i − x ‾ ) ( y i − y ‾ ) n − 1 Cov(X,Y)=frac{sum_{i=1}^{n}(x_i-overline{x})(y_i-overline{y})}{n-1} Cov(X,Y)=n−1∑i=1n​(xi​−x)(yi​−y​)​

通过一个实例来计算:

  1. 为方便计算,我们只定义两个点,每个点(样本)有两个特征:x与y

d o t 1 = ( 1 , 3 ) d o t 2 = ( 5 , 7 ) ( n = 2 ) dot_1 = (1,3)\dot_2=(5,7)\(n=2) dot1​=(1,3)dot2​=(5,7)(n=2)

  1. 用两个变量空间x,y分别表示特征对应的向量
    x = [ 1 5 ] , y = [ 3 7 ] x=begin{bmatrix} 1\5 end{bmatrix} , y=begin{bmatrix} 3\7 end{bmatrix} x=[15​],y=[37​]

  2. 计算特征的均值
    x ‾ = 3 , y ‾ = 5 overline{x}=3,overline{y}=5 x=3,y​=5

  3. 计算协方差
    C o v ( x , x ) = ( 1 − 3 ) 2 + ( 5 − 3 ) 2 2 − 1 = 8 C o v ( x , y ) = ( 1 − 3 ) ( 3 − 5 ) + ( 5 − 3 ) ( 7 − 5 ) 2 − 1 = 8 C o v ( y , x ) = C o v ( x , y ) = 8 C o v ( y , y ) = ( 3 − 5 ) 2 + ( 7 − 5 ) 2 2 − 1 = 8 Cov(x,x) = frac{(1-3)^2+(5-3)^2}{2-1}=8\ Cov(x,y) = frac{(1-3)(3-5)+(5-3)(7-5)}{2-1}=8\ Cov(y,x)=Cov(x,y)=8\ Cov(y,y) = frac{(3-5)^2+(7-5)^2}{2-1}=8 Cov(x,x)=2−1(1−3)2+(5−3)2​=8Cov(x,y)=2−1(1−3)(3−5)+(5−3)(7−5)​=8Cov(y,x)=Cov(x,y)=8Cov(y,y)=2−1(3−5)2+(7−5)2​=8

  4. 生成协方差矩阵
    C o v ( z ) = [ C o v ( x , x ) C o v ( x , y ) C o v ( y , x ) C o v ( y , y ) ] = [ 8 8 8 8 ] Cov(z)= begin{bmatrix} Cov(x,x) & Cov(x,y)\ Cov(y,x) & Cov(y,y) end{bmatrix} = begin{bmatrix} 8 & 8\ 8 & 8 end{bmatrix} Cov(z)=[Cov(x,x)Cov(y,x)​Cov(x,y)Cov(y,y)​]=[88​88​]

下面用代码实现上述过程:

import numpy as np
x = np.array([1,5])
y = np.array([3,7])
z = np.stack([x,y])  # z=[[1,5],[3,7]]
result = np.cov(z)  # 生成协方差矩阵
result的值
[[8. 8.]
 [8. 8.]]

意义:协方差用来描述X和Y的相关程度

值范围意义
Cov( X , Y ) < 0X与Y负相关
Cov( X , Y ) > 0X与Y正相关
Cov( X , Y ) = 0X与Y不相关
Sklearn线性模型 线性回归

给一些点(xi,yi),用线性回归找出一条线y=wx+b,该线能够最大程度的与点拟合。

通过这条回归线,我们能根据xi预测出yi的大概值。代码实现如下:

# 核心代码
model = LinearRegression()  # 定义线性模型
model.fit(x, y)  # 根据(x,y)点集生成线性模型
x_test = [[4], [5], [6]]  # 测试数据
y_test = model.predict(x_test)  # 模型预测结果
# 完整代码
import numpy as np
from sklearn.linear_model import LinearRegression

# 准备自变量与因变量
# 这部分不用看,只知道生成了(x,y)散点即可
x = np.array([0, 1, 2, 3, 4])  # 自变量x
y = 3 * x + 2  # 因变量y: [ 2  5  8 11 14]
x = x + np.random.rand(5)  # 将点用随机数打乱
x = [[i] for i in x]  # 行变列,如[1,2,3]会变成[[1],[2],[3]]
y = [[i] for i in y]  # 行变列,这是sklearn包要求的格式

# 建立线性模型
model = LinearRegression()  # 定义线性模型
model.fit(x, y)  # 根据(x,y)点集生成线性模型

# 准备测试数据
x_test = [[4], [5], [6]]

# 打印预测结果
y_test = model.predict(x_test)
print(y_test)
print("w值:", model.coef_)
print("b截距值为:", model.intercept_)
# 输出
[[12.79914287]
 [15.74000827]
 [18.68087368]]
w值: [[2.9408654]]
b截距值为: [1.03568125]

上述代码生成了以下线性模型
y = w x + b = 2.9408654 x + 1.03568125 y=wx+b=2.9408654x+1.03568125 y=wx+b=2.9408654x+1.03568125
将测试数据x代入该公式即可得到预测值y。

后面的pytorch部分将会通过梯度下降的方法来生成线性模型。

逻辑回归

以鸢尾花数据集为例。与上述线性回归极其相似,因此不作过多解释。

# 完整代码
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 获取数据集
iris = datasets.load_iris()
iris_x = iris.data
iris_y = iris.target
# 留出法划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris_x, iris_y, test_size=0.1)
# 生成逻辑回归模型
model = LogisticRegression()
model.fit(x_train, y_train)
# 检验模型
y_pred = model.predict(x_test)
accu = accuracy_score(y_test, y_pred)
Pytorch简介 偏导数计算

计算 y = ( x + w ) ( w + 1 ) y=(x+w)(w+1) y=(x+w)(w+1)对 x x x的偏导数,公式可以分解为下图:

用pytorch构建上述公式,可以很容易的求出偏导数,代码如下:

import torch

# 生成公式 y=(x+w)*(w+1)
x = torch.tensor([2.0], requires_grad=True)  # 求x的偏导数,必须使requires_grad=True,否则报错
w = torch.tensor([1.0])
a = torch.add(x, w)  # a = x+w
b = torch.add(w, 1)  # b = w+1
y = torch.mul(a, b)  # y = a*b
# 反向传播,计算所有requires_grad=True张量(tensor)的导数
y.backward()
print(x.grad)  # x的偏导数
# 结果
tensor([2.])
多次求导

backward(retain_graph=True)可以保留计算图,再调用一次backward()即可实现二阶求导。代码修改如下:

# 核心代码
y.backward(retain_graph=True)  # 计算保留图,用于二次求导
print(x.grad)  # x的一阶导
y.backward()  # 二次求导
print(x.grad)  # x的二阶导
# 完整代码
import torch

# 构建公式 y=(x+w)*(w+1)
x = torch.tensor([2.0], requires_grad=True)  # 求x的偏导数,必须使requires_grad=True,否则报错
w = torch.tensor([1.0])
a = torch.add(x, w)  # a = x+w
b = torch.add(w, 1)  # b = w+1
y = torch.mul(a, b)  # y = a*b
# 反向传播,计算所有requires_grad=True的导数
y.backward(retain_graph=True)  # 计算保留图,用于二次求导
print(x.grad)  # x的一阶导
y.backward()
print(x.grad)  # x的二阶导
非标量输出

使用torch.cat()函数我们可以将不同的函数结合到一起,实现下图计算:

代码实现如下

# 核心代码
loss = torch.cat([y0, y1], dim=0)  # dim=0代表横向拼接
loss_w = torch.tensor([1., 2.])  # 设置权重,y0为1,y1为2
loss.backward(gradient=loss_w)  # 反向传播
# 完整代码
import torch
# 构建两个公式
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], )
a = torch.add(w, x)
b = torch.add(w, 3)
y0 = torch.mul(a, b)  # y0 = (x+w)(w+3)
y1 = torch.add(a, b)  # y1 = (x+w)+(w+3)
# 合并公式
loss = torch.cat([y0, y1], dim=0)  # dim=0代表横向拼接
loss_w = torch.tensor([1., 2.])  # 设置权重,y0为1,y1为2
loss.backward(gradient=loss_w)  # 反向传播
print(w.grad)  # w的偏导数
# 输出
tensor([11.])
线性回归

问题:给定若干(x,y)点集,找出一条直线 y = w x + b y=wx+b y=wx+b,使所有点到直线的距离之和最小。

目标:找到合适的 w w w与 b b b,使损失函数 L = 1 N ∑ i = 1 N ( w x i + b − y t r u e ) 2 L=frac{1}{N}sum_{i=1}^{N}(wx_i+b-y_{true})^2 L=N1​∑i=1N​(wxi​+b−ytrue​)2 的值最小。

方法:我们需要对损失函数关于 w w w和 b b b求导: ∂ L ∂ w frac{partial{L}}{partial{w}} ∂w∂L​, ∂ L ∂ b frac{partial{L}}{partial{b}} ∂b∂L​,然后使用公式
w t + 1 = w t − μ ∂ L ∂ w b t + 1 = b t − μ ∂ L ∂ b ( μ : 学 习 率 , 梯 度 下 降 的 跨 度 ) w_{t+1}=w_t-mufrac{partial{L}}{partial{w}} \ b_{t+1}=b_t-mufrac{partial{L}}{partial{b}} \(mu:学习率,梯度下降的跨度) wt+1​=wt​−μ∂w∂L​bt+1​=bt​−μ∂b∂L​(μ:学习率,梯度下降的跨度)
不断调整 w w w与 b b b的值,直到得到合适的线性模型。

import matplotlib.pyplot as plt
import torch

# 准备自变量与因变量
# 这部分不用看,只知道生成了(x,y)散点即可
x = torch.rand(20, 1) * 10  # [20*1]的0-1的随机数 * 10
y = 2 * x + (5 + torch.randn(20, 1))  # y = 2x + 5
# 学习率
mu = 0.05  
# 构建线性回归参数 y_pred = wx + b
w = torch.tensor(5.0, requires_grad=True)  # 初始化w
b = torch.tensor(10.0, requires_grad=True)  # 初始化b
# 迭代训练1000次
for i in range(1000):
    """向前传播,计算预测值 y_pred = wx + b"""
    wx = torch.mul(w, x)  # wx = w * x
    y_pred = torch.add(wx, b)  # y_pred = w * x + b
    # 计算MSE loss
    # 目的是为了使loss尽可能小
    loss = (0.5 * (y - y_pred) ** 2).mean()
    # 反向传播,求b与w的偏导数
    loss.backward()
    # 更新参数
    # 此处等同于 w = w.sub(w,lr*w.grad)
    # 后面带下划线的都是in-place的,会将调用者改变
    w.data.sub_(mu * w.grad)  # 调整w的值
    b.data.sub_(mu * b.grad)  # 调整b的值
    # 更新参数后一定要清零梯度
    if i != 999:
        w.grad.zero_()
        b.grad.zero_()
    # 每隔50次循环输出一次图像
    if i % 50 == 0:
        plt.scatter(x.data.numpy(), y.data.numpy())  # 散点
        plt.plot(x.data.numpy(), y_pred.data.numpy())  # 回归直线
        plt.show()
SVM 基本原理

SVM的原理非常复杂,博主的水平不足以理解透彻并输出为文章,因此引用一位大佬的教程(是我见过写的最棒的,强推)

SVM原理:https://cloud.tencent.com/developer/article/1618598

重要公式
  • 支持向量样本点到决策面方程的距离(上述文章中公式2.12)
    d = ∣ w T x i + γ ∣ ∣ ∣ w ∣ ∣ = 1 ∣ ∣ w ∣ ∣ , ( x i 为 支 持 向 量 ) d=frac{|w^Tx_i+gamma|}{||w||}=frac{1}{||w||},(x_i为支持向量) d=∣∣w∣∣∣wTxi​+γ∣​=∣∣w∣∣1​,(xi​为支持向量)

  • 线性SVM最优化问题的数学描述(2.14)
    m i n w , γ 1 2 ∣ ∣ w ∣ ∣ 2 s . t . y i ( w T x i + γ ) ≥ 1 , i = 1 , 2 , . . . , m min_{w,gamma}frac{1}{2}||w||^2\ s.t. y_i(w^Tx_i+gamma)ge1, i=1,2,...,m minw,γ​21​∣∣w∣∣2s.t.yi​(wTxi​+γ)≥1,i=1,2,...,m

代码实现

原理虽然不好理解,但是代码实现起来却非常非常简单。

import numpy as np
from sklearn.svm import SVC

x = np.array([[-1, -1], [-2, -1], [1, 1], [2, 1]])  # 自变量
y = np.array([1, 1, 2, 2])  # 因变量
model = SVC()  # 定义模型
model.fit(x, y)  # 根据数据训练模型
pred = model.predict([[-0.8, -1]])  # 预测x=[-0.8,-1]的结果
print(pred)  # 输出y=[1]
指定核函数

通过调整SVC()函数中的kernel属性可以切换所使用的核函数。

下面我们通过不同的核函数来解决经典的鸢尾花分类问题。

# 核心代码
clf_rbf = SVC(kernel='rbf')
clf_linear = SVC(kernel='linear')
clf_poly = SVC(kernel='poly')
# 完整代码
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
# 导入数据
iris = datasets.load_iris()
x = iris.data  # 自变量
y = iris.target  # 因变量
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)  # 留出法划分数据集

# kernel(核函数) = 'rbf'
clf_rbf = SVC(kernel='rbf')
clf_rbf.fit(x_train, y_train)
score_rbf = clf_rbf.score(x_test, y_test)  # 返回给定测试数据和标签的平均准确度
print("rbf准确率 : %f" % score_rbf)

# kernel = 'linear'
clf_linear = SVC(kernel='linear')
clf_linear.fit(x_train, y_train)
score_linear = clf_linear.score(x_test, y_test)
print("linear准确率 :  %f" % score_linear)

# kernel = 'poly'
clf_poly = SVC(kernel='poly')
clf_poly.fit(x_train, y_train)
score_poly = clf_poly.score(x_test, y_test)
print("poly准确率 : %f" % score_poly)
# 输出
rbf准确率 : 0.977778
linear准确率 :  1.000000
poly准确率 : 0.977778
卷积神经网络 图像尺寸变化

输入图像大小 n i n n_{in} nin​ x n i n n_{in} nin​ ,卷积核大小 k k k x k k k ,步长为 s s s,边界填充为 p p p,则输出图像的边长 n o u t n_{out} nout​为:
n o u t = ⌊ n i n − k + 2 p s + 1 ⌋ n_{out}=left lfloor frac{n_{in}-k+2p}{s}+1 right rfloor nout​=⌊snin​−k+2p​+1⌋
下面我们通过一个实例来应用此公式。

代码实例
# 完整代码
import torch
"""5x5的图像(深度1)经过4个3x3卷积核处理(步长2)"""
conv2d = torch.nn.Conv2d(
    in_channels=1,  # 输入通道数C(深度)
    out_channels=4,  # 期望输出的C,此处定义的是实际上是卷积核的数量
    kernel_size=3,  # 卷积核大小3x3,等同于(3,3)
    stride=2)  # 步长
input = torch.randn(1, 1, 5, 5)  # [N,C,H,W]:[图像数量,图像深度(通道数),图像高度,图像宽度]
print("输入数据形状[N,C,H,W]:", input.data.shape)
print("输入数据:", input.data)
output = conv2d(input)
print("输出图像形状[N,C,H,W]:", output.data.shape)
print("输出数据:", output.data)
# 输出
输入数据形状[N,C,H,W]: torch.Size([1, 1, 5, 5])
输入数据: tensor([[[[ 1.1716,  1.0910,  1.9840, -0.8604, -0.2014],
          [ 0.3645,  1.7407, -0.9170,  1.0958,  0.8324],
          [-0.0618,  0.8313, -2.6619, -0.5088, -0.9346],
          [ 0.0357, -1.5625,  1.1964, -1.6998,  0.4962],
          [ 0.9606,  0.2284, -0.5521, -1.3429,  0.4901]]]])

输出图像形状[N,C,H,W]: torch.Size([1, 4, 2, 2])
输出数据: tensor([[[[ 0.0852,  1.2326],
          [ 0.2375,  0.0811]],
         [[ 1.7314,  0.3480],
          [-0.9429, -0.8034]],
         [[-0.1069, -0.4321],
          [ 0.5028, -0.8286]],
         [[-0.8727, -0.1086],
          [ 0.4673, -0.2946]]]])
代码结果分析

Q1:5x5的图像,经过3x3大小、步长为2的卷积核处理后,为什么会变成2x2的图像呢?

5x5的图像,则 n i n = 5 n_{in}=5 nin​=5。

3x3的卷积核,则 k = 3 k=3 k=3。

步长为2,则 s = 2 s=2 s=2。

默认填充为0,则 p = 0 p=0 p=0。

最后根据公式 n o u t = ⌊ n i n − k + 2 p s + 1 ⌋ n_{out}=left lfloor frac{n_{in}-k+2p}{s}+1 right rfloor nout​=⌊snin​−k+2p​+1⌋,可以算出 n o u t = 2 n_{out}=2 nout​=2,这与上述代码的输出结果吻合。

Q2:为什么4个卷积核处理深度(通道)为1的图像,生成的是深度(通道数)为4的图像?

如果图像的通道为c,则卷积核的通道也必须为c,计算的结果为所有通道卷积结果的和,最终会生成通道为1的图像,如下图所示。

如果我用2个[C,H,W]=[3,1,1]的卷积核来对图像进行处理,则生成的图像深度为2,如下图所示。

所以,输出图像的深度与卷积核的深度、长度、高度都无关,只与卷积核的数量有关。

池化层

这里比较简单,稍微看看就明白了

import torch

# 准备一个[N,C,H,W] = [1,1,3,3]的张量
input = torch.tensor([[[1.0, 2.0, 3.0],
                       [4.0, 5.0, 6.0],
                       [7.0, 8.0, 9.0]]])
# 2x2的最大池化层
maxPool = torch.nn.MaxPool2d(
    kernel_size=2,
    stride=1)
output = maxPool(input)
# output输出:
# tensor([[[5., 6.],
#          [8., 9.]]])

# 2x2的平均池化层
avgPool = torch.nn.AvgPool2d(
    kernel_size=2,
    stride=1)
output = avgPool(input)
# output输出:
# tensor([[[3., 4.],
#          [6., 7.]]])

总结完毕,保佑大伙考试顺利

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/954747.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号