AutoCV第九课:ML基础

2023-10-11 10:30
文章标签 基础 ml 第九课 autocv

本文主要是介绍AutoCV第九课:ML基础,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • ML基础
    • 注意事项
    • 一、2023/6/28更新
    • 前言
    • 1. 矩阵乘法和求导
    • 2. 多元线性回归
    • 3. 多模型线性回归
    • 4. 多分类逻辑回归
    • 总结

ML基础

注意事项

一、2023/6/28更新

新增多元和多模型线性回归的矩阵表达,即第 2、3 小节内容
新增逻辑回归多分类 mnist 模型,即第 4 小节内容

前言

手写AI推出的全新保姆级从零手写自动驾驶CV课程,链接。记录下个人学习笔记,仅供自己参考。

本次课程主要学习矩阵运算的基础,考虑使用矩阵来表达多个线性回归模型。

课程大纲可看下面的思维导图。

在这里插入图片描述

1. 矩阵乘法和求导

先回忆下矩阵相关知识

定义矩阵乘法
{ a b d e } × { 1 3 2 4 } = { a 1 + b 2 a 3 + b 4 d 1 + e 2 d 3 + e 4 } \left\{\begin{array}{cc}a&b\\ d&e\end{array}\right\}\times\left\{\begin{array}{cc}1&3\\ 2&4\end{array}\right\}=\left\{\begin{array}{cc}a1+b2&a3+b4\\ d1+e2&d3+e4\end{array}\right\} {adbe}×{1234}={a1+b2d1+e2a3+b4d3+e4}
记法:C[r][c] = 乘加(A中取 r 行,B中取 c 列)

在这里插入图片描述

图1 矩阵乘法示例

参考:https://www.cnblogs.com/ljy-endl/p/11411665.html

矩阵求导

对于 A ⋅ B = C A\cdot B = C AB=C 定义 L L L 是关于 C C C 的损失函数

G = ∂ L ∂ C G = \dfrac{\partial L}{\partial C} G=CL 若直接 C C C A A A 求导,则 G G G 定义为 C C C 大小的全 1 矩阵,则有:
∂ L ∂ A = G ⋅ B T ∂ L ∂ B = A T ⋅ G \dfrac{\partial L}{\partial A}=G\cdot B^T \ \ \ \ \ \dfrac{\partial L}{\partial B}=A^T \cdot G AL=GBT     BL=ATG
矩阵求导推导

  1. 考虑矩阵乘法 A ⋅ B = C A \cdot B = C AB=C

  2. 考虑 Loss 函数 L = ∑ i m ∑ j n ( C i j − p ) 2 L = \sum^m_{i}\sum^n_{j}{(C_{ij} - p)^2} L=imjn(Cijp)2

  3. 考虑 C C C 的每一项导数 ▽ C i j = ∂ L ∂ C i j \triangledown C_{ij} = \frac{\partial L}{\partial C_{ij}} Cij=CijL

  4. 考虑 A B C ABC ABC 都为 2x2 矩阵时,定义 G G G L L L C C C 的导数
    A = [ a b c d ] B = [ e f g h ] C = [ i j k l ] G = ∂ L ∂ C = [ ∂ L ∂ i ∂ L ∂ j ∂ L ∂ k ∂ L ∂ l ] = [ w x y z ] A = \begin{bmatrix} a & b\\ c & d \end{bmatrix} \quad B = \begin{bmatrix} e & f \\ g & h \end{bmatrix} \quad C = \begin{bmatrix} i & j \\ k & l \end{bmatrix} \quad G = \frac{\partial L}{\partial C} = \begin{bmatrix} \frac{\partial L}{\partial i} & \frac{\partial L}{\partial j} \\ \frac{\partial L}{\partial k} & \frac{\partial L}{\partial l} \end{bmatrix} = \begin{bmatrix} w & x \\ y & z \end{bmatrix} A=[acbd]B=[egfh]C=[ikjl]G=CL=[iLkLjLlL]=[wyxz]

  5. 展开左边 A ⋅ B A \cdot B AB

C = [ i = a e + b g j = a f + b h k = c e + d g l = c f + d h ] C = \begin{bmatrix} i = ae + bg & j = af + bh\\ k = ce + dg & l = cf + dh \end{bmatrix} C=[i=ae+bgk=ce+dgj=af+bhl=cf+dh]

  1. L L L 对于每一个 A A A 的导数
    ▽ A i j = ∂ L ∂ A i j \triangledown A_{ij} = \frac{\partial L}{\partial A_{ij}} Aij=AijL

    ∂ L ∂ a = ∂ L ∂ i ∗ ∂ i ∂ a + ∂ L ∂ j ∗ ∂ j ∂ a ∂ L ∂ b = ∂ L ∂ i ∗ ∂ i ∂ b + ∂ L ∂ j ∗ ∂ j ∂ b ∂ L ∂ c = ∂ L ∂ k ∗ ∂ k ∂ c + ∂ L ∂ l ∗ ∂ l ∂ c ∂ L ∂ d = ∂ L ∂ k ∗ ∂ k ∂ d + ∂ L ∂ l ∗ ∂ l ∂ d \begin{aligned} \frac{\partial L}{\partial a} &= \frac{\partial L}{\partial i} * \frac{\partial i}{\partial a} + \frac{\partial L}{\partial j} * \frac{\partial j}{\partial a} \\ \frac{\partial L}{\partial b} &= \frac{\partial L}{\partial i} * \frac{\partial i}{\partial b} + \frac{\partial L}{\partial j} * \frac{\partial j}{\partial b} \\ \frac{\partial L}{\partial c} &= \frac{\partial L}{\partial k} * \frac{\partial k}{\partial c} + \frac{\partial L}{\partial l} * \frac{\partial l}{\partial c} \\ \frac{\partial L}{\partial d} &= \frac{\partial L}{\partial k} * \frac{\partial k}{\partial d} + \frac{\partial L}{\partial l} * \frac{\partial l}{\partial d} \end{aligned} aLbLcLdL=iLai+jLaj=iLbi+jLbj=kLck+lLcl=kLdk+lLdl

    ∂ L ∂ a = w e + x f ∂ L ∂ b = w g + x h ∂ L ∂ c = y e + z f ∂ L ∂ d = y g + z h \begin{aligned} \frac{\partial L}{\partial a} &= we + xf \\ \frac{\partial L}{\partial b} &= wg + xh \\ \frac{\partial L}{\partial c} &= ye + zf \\ \frac{\partial L}{\partial d} &= yg + zh \end{aligned} aLbLcLdL=we+xf=wg+xh=ye+zf=yg+zh

  2. 因此 A A A 的导数为

    ∂ L ∂ A = [ w e + x f w g + x h y e + z f y g + z h ] ∂ L ∂ A = [ w x y z ] [ e g f h ] \frac{\partial L}{\partial A} = \begin{bmatrix} we + xf & wg + xh\\ ye + zf & yg + zh \end{bmatrix} \quad \frac{\partial L}{\partial A} = \begin{bmatrix} w & x\\ y & z \end{bmatrix} \begin{bmatrix} e & g\\ f & h \end{bmatrix} AL=[we+xfye+zfwg+xhyg+zh]AL=[wyxz][efgh]

    ∂ L ∂ A = G ⋅ B T \frac{\partial L}{\partial A} = G \cdot B^T AL=GBT

  3. 同理 B B B 的导数为
    ∂ L ∂ e = w a + y c ∂ L ∂ f = x a + z c ∂ L ∂ g = w b + y d ∂ L ∂ h = x b + z d \begin{aligned} \frac{\partial L}{\partial e} &= wa + yc \\ \frac{\partial L}{\partial f} &= xa + zc \\ \frac{\partial L}{\partial g} &= wb + yd \\ \frac{\partial L}{\partial h} &= xb + zd \end{aligned} eLfLgLhL=wa+yc=xa+zc=wb+yd=xb+zd

    ∂ L ∂ B = [ w a + y c x a + z c w b + y d x b + z d ] ∂ L ∂ B = [ a c b d ] [ w x y z ] \frac{\partial L}{\partial B} = \begin{bmatrix} wa + yc & xa + zc\\ wb + yd & xb + zd \end{bmatrix} \quad \frac{\partial L}{\partial B} = \begin{bmatrix} a & c\\ b & d \end{bmatrix} \begin{bmatrix} w & x\\ y & z \end{bmatrix} BL=[wa+ycwb+ydxa+zcxb+zd]BL=[abcd][wyxz]

    ∂ L ∂ B = A T ⋅ G \frac{\partial L}{\partial B} = A^T \cdot G BL=ATG

2. 多元线性回归

之前我们是通过房价预测的案例来讲解线性回归的,在前面的分析中我们假设房价只与房屋面积一个自变量相关,因此可以将其视为一元线性回归模型处理,其对应的房价计算公式如下:

房价 = 房屋面积 * 系数 + 偏置

而实际情况下,房价应该与多个自变量相关,比如房屋的面积(m2)、距离地铁的远近(km)、装修的程度(0-1)等等,因此需要将其视为多元线性回归模型处理,其对应的房价计算公式如下:

房价 = 房屋面积 * 系数1 + 距离 * 系数2 + 装修 * 系数3 + 偏置

我们先初步写个 demo 确保各部分的维度是正确的,示例代码如下:

import numpy as np# 定义变量
# 面积,距离,装修
x = np.array([[80, 3, 1],[100, 5, 0.3],[130, 2, 0.1],[300, 20, 1],[60, 1, 0.8]
])# 定义输出
# 房价
y = np.array([50000,60000,50000,30000,70000,
]).reshape(-1, 1)k = np.random.randn(3).reshape(1, 3)
b = 0# x(5x3), k(1x3), b(1,)
predict = (x * k + b).sum(axis=1, keepdims=True)# predict(5x1) y(5x1)
loss = 0.5 * ((predict - y) ** 2).sum()
print(loss)

在上面的示例代码中,我们使用 numpy 来进行数值计算和对应的矩阵操作。首先定义了一个自变量 x(5,3),表示 5 个样本的特征值,每行包含房屋面积、距离和装修情况三个特征,并定义了因变量房价 y(5,1);接下来初始化权重参数 k(1,3) 和偏置 b(1,);然后利用矩阵运算的方式得出了每个样本的房价预测结果;最后根据预测结果和实际房价 y 之间的差异来计算 loss,使用的是均方差损失函数,最终得出的 loss 是一个标量,符合我们的预期。

我们确保了最终输出 loss 的 shape 是正确的,接下来我们来对其进行优化,包括对数据进行正则化、循环迭代更新参数以及验证

优化后的示例代码如下:

import numpy as np# 定义变量
# 面积,距离,装修
x = np.array([[80, 3, 1],[100, 5, 0.3],[130, 2, 0.1],[300, 20, 1],[60, 1, 0.8]
])# 定义输出
# 房价
y = np.array([50000,60000,50000,30000,70000,
]).reshape(-1, 1)k = np.random.randn(3).reshape(1, 3)
b = 0# 数据正则化
def normalize(x):x_std  = x.std(axis=0, keepdims=True)x_mean = x.mean(axis=0, keepdims=True)norm_x = (x - x_mean) / x_stdreturn norm_x, x_std, x_meannorm_x, x_std, x_mean = normalize(x)
norm_y, y_std, y_mean = normalize(y)
lr = 1e-2for iter in range(1000):# x(5x3), k(1x3), b(1,)predict = (norm_x * k + b).sum(axis=1, keepdims=True)# predict(5x1) y(5x1)loss = 0.5 * ((predict - norm_y) ** 2).sum()if iter % 100 == 0:print(f"Iter {iter}, Loss: {loss:.3f}")delta_k = ((predict - norm_y) * norm_x).sum(axis=0, keepdims=True)delta_b = (predict - norm_y).sum()# 参数更新k = k - lr * delta_kb = b - lr * delta_b# 验证
while True:text = input("请输入你想预测的房子的相关信息[面积,距离,装修]:")feature = list(map(float, text.strip().split(" ")))if len(feature) != 3:print(f"输入有误,请重新输入")continuefeature = np.array([feature])norm_feature = (feature - x_mean) / x_stdpredict = (norm_feature * k + b).sum()real_predict = predict * y_std + y_meanprint(real_predict)

上述示例代码是完整的多元线性回归的房价预测案例。通过给定的房屋特征(面积、距离、装修),使用梯度下降法不断调整权重系数和偏置,以最小化预测值与实际房价之间的损失。通过数据正则化和参数更新,预测新房屋的房价。值得一提的是,模型最终的效果似乎并没有我们想象的那么好😂,这并不重要,我们主要通过这个案例来学习多元线性回归模型。

运行效果如下:

在这里插入图片描述

图2-1 多元线性回归房价预测(单输出)

3. 多模型线性回归

在上面的分析中,我们考虑的是多变量单输出的情况,也就是最终我们只需要预测房价,如果是多变量多输出的情况又该如何考虑呢?🤔

假设目前我们根据面积、距离和装修程度三个特征不仅要预测房价还需要预测租金,也就是有两个输出,其实对应的就是两个模型,此时我们可以使用上节课学习到的矩阵知识来处理多个模型的问题。

具体的实现代码如下,与上述单输出的情况并没有太大的差异,只是需要从矩阵的角度来考虑这个问题

import numpy as np# 定义变量
# 面积,距离,装修
x = np.array([[80, 3, 1],[100, 5, 0.3],[130, 2, 0.1],[300, 20, 1],[60, 1, 0.8]
])# 定义输出
# 房价,租金
y = np.array([50000, 3000,50000, 6000,60000, 8000,30000, 9000,70000, 3000
]).reshape(-1, 2)# 权重系数和偏置
# 看作两个模型,每个模型包含3个权重和一个偏置
k = np.random.randn(3, 2)
b = np.zeros((1, 2))# 数据正则化
def normalize(x):x_std  = x.std(axis=0, keepdims=True)x_mean = x.mean(axis=0, keepdims=True)norm_x = (x - x_mean) / x_stdreturn norm_x, x_std, x_meannorm_x, x_std, x_mean = normalize(x)
norm_y, y_std, y_mean = normalize(y)
lr = 1e-3for iter in range(1000):# norm_x(5x3), k(3x2), b(1x2)# predict(5x2)predict = norm_x @ k + b# predict(5x2) y(5x2)loss = 0.5 * ((predict - norm_y) ** 2).sum()if iter % 100 == 0:print(f"Iter {iter}, Loss: {loss:.3f}")# predict(5x2), norm_y(5x2)# C = AB# dA = G @ B.T# dB = A.T @ GG = predict - norm_ydelta_k = norm_x.T @ Gdelta_b = G.sum(axis=0, keepdims=True)# 参数更新k = k - lr * delta_kb = b - lr * delta_b# 验证
while True:text = input("请输入你想预测的房子的相关信息[面积,距离,装修]:")feature = list(map(float, text.strip().split(" ")))if len(feature) != 3:print(f"输入有误,请重新输入")continuefeature = np.array([feature])norm_feature = (feature - x_mean) / x_std# 1x2predict = norm_feature @ k + breal_predict = predict * y_std + y_meanprice1, price2 = real_predict[0]print(f"对于房价的预测为:{price1:.3f},对于租金预测为:{price2:.3f}")

上述示例代码是一个多输出多元线性回归的示例,旨在通过给定的房屋特征(面积、距离、装修)同时预测房价和租金。这种多输出的线性回归模型适用于需要同时预测多个相关输出的场景。

运行效果如下:

在这里插入图片描述

图3-1 多元线性回归房价预测(多输出)

我们再来回顾下其中使用到的矩阵求导的相关知识

对于 A ⋅ B = C A \cdot B = C AB=C 定义 L L L 是关于 C C C 的损失函数

G = ∂ L ∂ C G = \dfrac{\partial L}{\partial C} G=CL,则有
∂ L ∂ A = G ⋅ B T ∂ L ∂ B = A T ⋅ G \dfrac{\partial L}{\partial A}=G\cdot B^T \ \ \ \ \dfrac{\partial L}{\partial B}=A^T \cdot G AL=GBT    BL=ATG
回到代码中,我们需要求 ∂ L ∂ k \dfrac{\partial L}{\partial k} kLdelta_k,其中 G = ∂ L ∂ C = p r e d i c t − n o r m _ y G = \dfrac{\partial L}{\partial C} = predict-norm\_y G=CL=predictnorm_y C = A ⋅ B = n o r m _ x ⋅ k C = A \cdot B = norm\_x \cdot k C=AB=norm_xk,因此最终的 ∂ L ∂ k = n o r m _ x . T ⋅ G \dfrac{\partial L}{\partial k} = norm\_x.T \cdot G kL=norm_x.TG

我们也可以从 shape 维度来验证下,norm_x(5x3) G(5x2) => norm_x.T(3x5) => delta_k(3x2)

4. 多分类逻辑回归

之前我们是通过苹果分类案例来讲解逻辑回归问题的,可以将其视为一个二分类问题,为此我们引入了 sigmoid 函数并定义了逻辑回归模型的损失函数即二元交叉熵损失函数。

这节课我们来学习多分类逻辑回归,对 mnist 手写识别数据集中的 10 个类别进行分类。

在正式开始之前,我们需要考虑如下问题:

  1. 由于是 10 个数字的分类任务,所以可以将其视为 10 个逻辑回归模型

  2. 关于正则化的考虑

  • 我们是否应该参考线性回归的正则化,对每个 pixel 都统计其 mean 和 std 呢?🤔
  • 如果每个数据都是独立分布,则需要独立统计 mean 和 std,而对于 2d 图像,每个 pixel 并不是独立分布的,它们是存在空间相关性的,因此需要统一考虑 mean 和 std。对于训练集,需要统计 mean 和 std,对于测试集,使用训练集统计的 mean 和 std 即可
  1. 我们之前使用 sigmoid 处理二分类问题,即 sigmoid(predict)->logits(0-1),在这里是多分类问题,我们考虑使用 softmax(predict)->logits(0-1)

我们先把前面写过的 mnist 的 dataset 和 dataloader 的示例代码 copy 过来,如下所示:

import numpy as np
import matplotlib.pyplot as pltclass MNISTDataset:def __init__(self, images_path, labels_path):self.images_path = images_pathself.labels_path = labels_pathself.images, self.labels = self.load_mnist_data()def __len__(self):return len(self.images)def __getitem__(self, index):image, label = self.images[index], self.labels[index]return image, labeldef load_mnist_data(self):# load labelswith open(self.labels_path, "rb") as f:magic_number, num_of_items = np.frombuffer(f.read(8), dtype=">i", count=2, offset=0)labels = np.frombuffer(f.read(), dtype=np.uint8, count=-1, offset=0)# load imageswith open(self.images_path, "rb") as f:magic_number, num_of_images, rows, cols = np.frombuffer(f.read(16), dtype=">i", count=4, offset=0)pixels = np.frombuffer(f.read(), dtype=np.uint8, count=-1, offset=0)images_matrix = pixels.reshape(num_of_images, rows, cols)return images_matrix, labelsclass MNISTDataLoader:def __init__(self, dataset, batch_size, shuffle=True):self.dataset = datasetself.batch_size = batch_sizeself.shuffle = shuffledef __iter__(self):self.indexs = np.arange(len(self.dataset))if self.shuffle:np.random.shuffle(self.indexs)self.cursor = 0return selfdef __next__(self):begin = self.cursorend   = self.cursor + self.batch_sizeif end > len(self.dataset):raise StopIteration()self.cursor = endbatched_data = []for index in self.indexs[begin:end]:item = self.dataset[index]batched_data.append(item)return batched_datadef show_mnist_image(images, labels, n=1):for i in range(n):image = images[i]label = labels[i]plt.title(f"label is {label}")plt.imshow(image)plt.show()# example usage
dataset = MNISTDataset("mnist/t10k-images-idx3-ubyte", "mnist/t10k-labels-idx1-ubyte")
loader  = MNISTDataLoader(dataset, batch_size=32, shuffle=True)
for i, batched_data in enumerate(loader):if i == 0:images, labels = list(zip(*batched_data))print(len(batched_data))show_mnist_image(images, labels)        

首先是正则化的考虑,计算 mean 和 std

class MNISTDataset:def __init__(self, images_path, labels_path, train, mean=None, std=None):self.images_path = images_pathself.labels_path = labels_pathself.images, self.labels = self.load_mnist_data()# flatten Nx28x28 -> Nx784self.images =  self.images.reshape(len(self.images), -1)if train:self.images, self.mean, self.std = self.normalize(self.images)else:self.images, self.mean, self.std = self.normalize(self.images, mean, std)@staticmethoddef normalize(x, mean=None, std=None):if mean is None:mean = x.mean()if std is None:std = x.std()x = (x - mean) / stdreturn x, mean, std...

然后是考虑 softmax 来处理多分类问题,其计算公式如下:
σ ( z ) j = e z j ∑ k = 1 K e z k f o r j = 1 , . . . , K . \sigma(\mathbf{z})_{j}={\frac{e^{z_{j}}}{\sum_{k=1}^{K}e^{z_{k}}}}\quad{\mathrm{for}}\ \ j=1,...,K. σ(z)j=k=1Kezkezjfor  j=1,...,K.
假设当前输入 x = [x0, x1, x2],经过 softmax 后的输出是怎样的呢?

我们定义 esum = exp(x0) + exp(x1) + exp(x2)

故最终的输出为 output = [exp(x0)/esum,exp(x1)/esum,exp(x2)/esum]

我们还需要考虑一个溢出问题, 假设当前的输入 x = [100, 500, 1000],exp(1000)会导致溢出,而我们常见的解决手段是将输入中的每个值减去其中的最大值即 x-x.max()

对应的 softmax crossentropy loss 的计算如下:
l o s s = − [ y ∗ ln ⁡ ( p ) ] loss = -[y * \ln(p)] loss=[yln(p)]
关于 loss 的导数推导具体可参考 一文详解Softmax函数

还有一点值得注意的是对于 softmax 而言,labels 需要转换为 onehot 编码的格式

通过上述分析,循环更新迭代的示例代码如下所示:

# 定义k和b
num_classes = 10
k = np.random.randn(784, num_classes)
b = np.zeros((1, num_classes))def softmax(x, dim):x = np.exp(x - x.max())return x / x.sum(axis=dim, keepdims=True)def crossentropy_loss(logits, onehot_labels):batch = logits.shape[0]return -(onehot_labels * np.log(logits)).sum() / batchlr = 1e-2
niter = 0for epoch in range(10):for images, labels in train_loader:niter += 1# 32x784 @ 784x10predict = images @ k + b# predict -> logitslogits = softmax(predict, dim=1)# softmax crossentropy loss# loss = -(y * ln(p))batch = logits.shape[0]onehot_labels = np.zeros_like(logits)# labels(32,) -> onehot(32,10)onehot_labels[np.arange(batch), labels] = 1loss = crossentropy_loss(logits, onehot_labels)if niter % 100 == 0:print(f"Epoch: {epoch}, Iter: {niter}, Loss: {loss:.3f}")G = (logits - onehot_labels) / batch# C = AB# dA = G @ B.T# dB = A.T @ Gdelta_k = images.T @ Gdelta_b = G.sum(axis=0, keepdims=True)k = k - lr * delta_kb = b - lr * delta_b# evaluateall_predict = []for images, labels in test_loader:predict = images @ k + blogits = softmax(predict, dim=1)predict_labels = logits.argmax(axis=1)all_predict.extend(predict_labels == labels)accuracy = np.sum(all_predict) / len(all_predict) * 100print(f"Epoch: {epoch}, Evaluate Test Set, Accuracy: {accuracy:.3f} %")

上述示例代码展示了 MNIST 数据集上使用逻辑回归进行多分类的示例。它使用 softmax 函数将模型输出转换为概率分布,并使用交叉熵损失函数衡量模型输出与真实标签之间的差异。通过梯度下降法更新权重和偏置,以最小化损失函数。我们还使用测试集计算模型的准确率,并通过迭代训练和评估,可以逐步优化模型,并得到在 MNIST 数据集上分类准确的结果。

运行效果如下:

在这里插入图片描述

图4-1 逻辑回归多分类

为了更好的查看结果,我们可以对其进行可视化操作,具体实现代码如下:

for images, labels in test_loader:predict = images @ k + blogits = softmax(predict, dim=1)predict_labels = logits.argmax(axis=1)pixels = (images * train_dataset.std + train_dataset.mean).astype(np.uint8).reshape(-1, 28, 28)for image, predict, gt in zip(pixels, predict_labels, labels):plt.imshow(image)plt.title(f"Predict: {predict}, GT: {gt}")plt.show()

需要注意的是,在可视化时需要将对应图片的像素值通过 mean 和 std 恢复到原始范围,并将其 reshape 为 28x28 的大小,方便可视化。

模型预测的部分结果如下所示:

在这里插入图片描述

图4-2 预测结果1

在这里插入图片描述

图4-3 预测结果2

可以看到模型预测的部分结果还是有误的,这也很正常,毕竟分类识别准确率在 86.6% 左右。

完整的示例代码如下所示:

import numpy as np
import matplotlib.pyplot as pltclass MNISTDataset:def __init__(self, images_path, labels_path, train, mean=None, std=None):self.images_path = images_pathself.labels_path = labels_pathself.images, self.labels = self.load_mnist_data()# flatten Nx28x28 -> Nx784self.images =  self.images.reshape(len(self.images), -1)if train:self.images, self.mean, self.std = self.normalize(self.images)else:self.images, self.mean, self.std = self.normalize(self.images, mean, std)@staticmethoddef normalize(x, mean=None, std=None):if mean is None:mean = x.mean()if std is None:std = x.std()x = (x - mean) / stdreturn x, mean, stddef __len__(self):return len(self.images)def __getitem__(self, index):image, label = self.images[index], self.labels[index]return image, labeldef load_mnist_data(self):# load labelswith open(self.labels_path, "rb") as f:magic_number, num_of_items = np.frombuffer(f.read(8), dtype=">i", count=2, offset=0)labels = np.frombuffer(f.read(), dtype=np.uint8, count=-1, offset=0)# load imageswith open(self.images_path, "rb") as f:magic_number, num_of_images, rows, cols = np.frombuffer(f.read(16), dtype=">i", count=4, offset=0)pixels = np.frombuffer(f.read(), dtype=np.uint8, count=-1, offset=0)images_matrix = pixels.reshape(num_of_images, rows, cols)return images_matrix, labelsclass MNISTDataLoader:def __init__(self, dataset, batch_size, shuffle=True):self.dataset = datasetself.batch_size = batch_sizeself.shuffle = shuffledef __iter__(self):self.indexs = np.arange(len(self.dataset))if self.shuffle:np.random.shuffle(self.indexs)self.cursor = 0return selfdef __next__(self):begin = self.cursorend   = self.cursor + self.batch_sizeif end > len(self.dataset):raise StopIteration()self.cursor = endbatched_data = []for index in self.indexs[begin:end]:item = self.dataset[index]batched_data.append(item)# return batched_datareturn [np.stack(item, axis=0) for item in list(zip(*batched_data))]      # 训练集
train_dataset = MNISTDataset("mnist/train-images-idx3-ubyte", "mnist/train-labels-idx1-ubyte", train=True)
train_loader  = MNISTDataLoader(train_dataset, batch_size=32, shuffle=True)# 测试集
test_dataset = MNISTDataset("mnist/t10k-images-idx3-ubyte", "mnist/t10k-labels-idx1-ubyte",train=False,mean=train_dataset.mean,std=train_dataset.std
)
test_loader = MNISTDataLoader(test_dataset, 10)# 定义k和b
num_classes = 10
k = np.random.randn(784, num_classes)
b = np.zeros((1, num_classes))def softmax(x, dim):x = np.exp(x - x.max())return x / x.sum(axis=dim, keepdims=True)def crossentropy_loss(logits, onehot_labels):batch = logits.shape[0]return -(onehot_labels * np.log(logits)).sum() / batchlr = 1e-2
niter = 0for epoch in range(10):for images, labels in train_loader:niter += 1# 32x784 @ 784x10predict = images @ k + b# predict -> logitslogits = softmax(predict, dim=1)# softmax crossentropy loss# loss = -(y * ln(p))batch = logits.shape[0]onehot_labels = np.zeros_like(logits)# labels(32,) -> onehot(32,10)onehot_labels[np.arange(batch), labels] = 1loss = crossentropy_loss(logits, onehot_labels)if niter % 100 == 0:print(f"Epoch: {epoch}, Iter: {niter}, Loss: {loss:.3f}")G = (logits - onehot_labels) / batch# C = AB# dA = G @ B.T# dB = A.T @ Gdelta_k = images.T @ Gdelta_b = G.sum(axis=0, keepdims=True)k = k - lr * delta_kb = b - lr * delta_b# evaluateall_predict = []for images, labels in test_loader:predict = images @ k + blogits = softmax(predict, dim=1)predict_labels = logits.argmax(axis=1)all_predict.extend(predict_labels == labels)accuracy = np.sum(all_predict) / len(all_predict) * 100print(f"Epoch: {epoch}, Evaluate Test Set, Accuracy: {accuracy:.3f} %")for images, labels in test_loader:predict = images @ k + blogits = softmax(predict, dim=1)predict_labels = logits.argmax(axis=1)pixels = (images * train_dataset.std + train_dataset.mean).astype(np.uint8).reshape(-1, 28, 28)for image, predict, gt in zip(pixels, predict_labels, labels):plt.imshow(image)plt.title(f"Predict: {predict}, GT: {gt}")plt.show()

总结

本次课程学习了矩阵求导相关知识,后续实现多个线性回归或者逻辑逻辑回归模型可以考虑使用矩阵方式来表达

本次课程主要学习了多元和多模型线性回归,还是从房价预测的案例出发,考虑多个变量影响房价,从而引出多元线性回归模型;考虑多个输出即多个模型,不仅预测房价还预测租金,引出多模型线性回归,从矩阵角度对其进行分析,重新回顾并学习了矩阵求导的相关知识。

本次课程主要学习了多分类逻辑回归模型,对手写识别数据集进行分类。我们对于正则化的考虑是对训练集只使用一个 mean 和 std,因为我们认为每个 pixel 之间并不是相互独立的,而需要将其视为一个整体,而对于测试集的 mean 和 std 我们直接使用训练集的即可。此外,与二分类不同的是我们使用 softmax 函数将模型的输出转换为概率分布,并使用 softmax crossentropy loss 作为该多分类逻辑回归模型的损失函数。

这篇关于AutoCV第九课:ML基础的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/187412

相关文章

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

c++基础版

c++基础版 Windows环境搭建第一个C++程序c++程序运行原理注释常亮字面常亮符号常亮 变量数据类型整型实型常量类型确定char类型字符串布尔类型 控制台输入随机数产生枚举定义数组数组便利 指针基础野指针空指针指针运算动态内存分配 结构体结构体默认值结构体数组结构体指针结构体指针数组函数无返回值函数和void类型地址传递函数传递数组 引用函数引用传参返回指针的正确写法函数返回数组

【QT】基础入门学习

文章目录 浅析Qt应用程序的主函数使用qDebug()函数常用快捷键Qt 编码风格信号槽连接模型实现方案 信号和槽的工作机制Qt对象树机制 浅析Qt应用程序的主函数 #include "mywindow.h"#include <QApplication>// 程序的入口int main(int argc, char *argv[]){// argc是命令行参数个数,argv是

【MRI基础】TR 和 TE 时间概念

重复时间 (TR) 磁共振成像 (MRI) 中的 TR(重复时间,repetition time)是施加于同一切片的连续脉冲序列之间的时间间隔。具体而言,TR 是施加一个 RF(射频)脉冲与施加下一个 RF 脉冲之间的持续时间。TR 以毫秒 (ms) 为单位,主要控制后续脉冲之前的纵向弛豫程度(T1 弛豫),使其成为显著影响 MRI 中的图像对比度和信号特性的重要参数。 回声时间 (TE)

Java基础回顾系列-第七天-高级编程之IO

Java基础回顾系列-第七天-高级编程之IO 文件操作字节流与字符流OutputStream字节输出流FileOutputStream InputStream字节输入流FileInputStream Writer字符输出流FileWriter Reader字符输入流字节流与字符流的区别转换流InputStreamReaderOutputStreamWriter 文件复制 字符编码内存操作流(

Java基础回顾系列-第五天-高级编程之API类库

Java基础回顾系列-第五天-高级编程之API类库 Java基础类库StringBufferStringBuilderStringCharSequence接口AutoCloseable接口RuntimeSystemCleaner对象克隆 数字操作类Math数学计算类Random随机数生成类BigInteger/BigDecimal大数字操作类 日期操作类DateSimpleDateForma