上文链接:
Deep learning for Computer Vision with Python(1)从零开始入门计算机视觉
Deep learning for Computer Vision with Python 笔记(2)图像基础_冰淇淋2333的博客-CSDN博客
Deep learning for Computer Vision with Python笔记(3)图像数据集介绍_冰淇淋2333的博客-CSDN博客
Deep learning for Computer Vision with Python笔记(4)构建KNN图像分类器_冰淇淋2333的博客-CSDN博客
什么是参数学习?
对于一个给定的模型,对于必要的参数进行定义。
这里的参数是广义的定义,包括所有影响模型训练的因素:数据,评分函数,损失函数,权重,以及偏差。
1. 线性分类器的介绍:从图像到标签
整个线性分类器 的过程可以用下图来表示。图像矩阵×权重矩阵+b,得到最终的y是一个n维向量,n是标签的个数。w的大小是由图像大小决定的。
线性分类器的好处有:1. 一旦数据和标签定下来,我们只需要考虑w和b对于模型的影响。2. 预测的效率非常高。
2. python实现线性分类器的图像分类
1. 构建图像
初始化W,b;加载图片并展平为3×3072维度;
import numpy as np
import cv2
labels = ["dog", "cat", "panda"]
np.random.seed(1)
W = np.random.randn(3, 3072) # 3072 = 3 * 32 * 32
b = np.random.rand(3)
# 加载图像,调整大小,转成numpy,展平
orig = cv2.imread("test.jpg")
image = cv2.resize(orig, (32, 32)).flatten()
W:(3*3072), image:(3072*1), 所以相乘后结果为(3*1). 目标有多少类,W的行就取多少。
2. 线性计算,并计算精度
# 线性计算
scores = W.dot(image) + b
for (label, score) in zip(labels, scores): # 同时迭代两个数组:zip合并
print("[INFO] {}: {:.2f}".format(label, score))
cv2.putText(orig, "Label: {}".format(labels[np.argmax(scores)]), (10,30), cv2.FONT_HERSHEY_SIMPLEX,
0.9, (0, 255, 0), 2)
cv2.imshow("Image", orig)
cv2.waitKey(0)
获得结果:
以上的例子是我们通过随机方式手动初始化W和b,接下来我们将介绍优化和梯度下降,通过优化的方式学习到最优的W和b。
3. 优化策略:梯度下降法
如图所示,梯度下降法是当权重不断增大时,损失函数的图像有波峰和波谷。每个波峰是局部最大值,每个波谷是局部最小值。局部最小值中损失最小的是全局最小值,我们的理想状态就是找到这个全局最小值时参数的取值。
然而,在真正的学习过程中,这张图是不可见的,无法可视化,也就很难找到这个全局最小值。实际上,我们可以把学习过程比作一个碗,机器人在碗里行走,试图找到碗的最低点(碗是三维的,而实际问题可能有几万维)。机器人的初始位置是随机的,他需要通过调整自己的方向,每一步都朝着下坡的方向走,直到达到碗底。他并不知道哪个方向离碗底最近,只能计算出损失最小的方向,尝试优化参数。
这个理论成立的前提是:损失函数是一个凸函数,也就是说它只要有局部最小值,那么局部最小值就是全局最小值。但是,大多数处理的问题几乎都不是平整的凸函数,而是有多个波峰和波谷。但是,我们仍然使用梯度下降法,是因为这个方法已经足够好了,尽管不是全局最小,但是结果的实践是足够的。
在python中应用梯度下降法训练线性分类器并评估结果:
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import numpy as np
import argparse
def sigmoid_activation(x):
# sigmod 激活函数
return 1.0 / (1 + np.exp(-x))
def predict(X, W):
preds = sigmoid_activation(X.dot(W))
preds[preds <= 0.5] = 0
preds[preds > 0] = 1
return preds
# 输入参数:epochs和学习率
ap = argparse.ArgumentParser()
ap.add_argument("-e","--epochs", type=float, default=100, help="# of epochs")
ap.add_argument("-a", "--alpha", type=float, default=0.01, help="learning rate") # 梯度下降的学习率
args = vars(ap.parse_args())
# 聚类,生成1000个数据点,两类数据,特征维度为2
(X, y) = make_blobs(n_samples=1000, n_features=2, centers=2, cluster_std=1.5, random_state=1)
# 插入一个常数列作为偏置(b)
y = y.reshape((y.shape[0], 1))
# np.c_:左右连接两个矩阵
X = np.c_[X, np.ones((X.shape[0]))]
(trainX, testX, trainY, testY) = train_test_split(X, y, test_size=0.5, random_state=42)
# 初始化权重矩阵:
print("[INFO] training...")
W = np.random.randn(X.shape[1], 1)
losses = []
# 训练:梯度下降
for epoch in np.arange(0, args["epochs"]):
preds = sigmoid_activation(trainX.dot(W))
error = preds - trainY
loss = np.sum(error ** 2)
losses.append(loss) # 最小二乘误差
# 计算梯度,更新权重矩阵
gradient = trainX.T.dot(error)
W += -args["alpha"] * gradient
if epoch == 0 or (epoch + 1) % 5 == 0:
print("[INFO] epoch={}, losses={:.7f}".format(int(epoch + 1), loss))
# 测试结果
print("[INFO] evaluating...")
preds = predict(testX, W)
print(classification_report(testY, preds))
# 绘制测试数据
plt.style.use("ggplot")
plt.figure()
plt.title("Data")
plt.scatter(testX[:, 0], testX[:, 1], marker="o", c=testY, s=30)
# 损失数据可视化
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, args["epochs"]), losses)
plt.title("Training loss")
plt.xlabel("Epoch #")
plt.ylabel("Loss")
plt.show()
结果: