MNIST数据集:利用numpy编写第一个训练代码——SVM分类器

支持向量机(Support Vector Machine,简称SVM)是一种监督学习算法,主要用于分类和回归问题,但在实际应用中更常用于分类问题。SVM的基本原理是找到一个超平面,将数据集中的不同类别尽可能地分开,同时保持超平面与最近的数据点(即支持向量)之间的间隔最大化。

以下是SVM的关键概念和步骤:

  1. 线性可分性:SVM最初是为线性可分数据设计的,即数据可以通过一个线性超平面完全分开。

  2. 超平面:在N维空间中,超平面是一个N-1维的线性子空间,可以由一个权重向量w和一个偏置项b定义,形式为w^T * x + b = 0,其中x是数据点,w^T表示权重向量的转置。

  3. 间隔:间隔是数据点到超平面的最短距离。在SVM中,我们希望找到这样一个超平面,使得不同类别的数据点到这个超平面的距离(即间隔)最大化。

  4. 支持向量:支持向量是最靠近超平面的数据点,它们决定了超平面的位置和方向。

  5. 优化问题:SVM的训练过程可以转化为一个凸优化问题。目标是最大化间隔,同时确保所有数据点都在正确的一侧,并且违反间隔的数据点尽可能少。

  6. 软间隔和正则化:在现实世界的数据中,数据往往是非线性可分的。软间隔SVM允许一些数据点违反间隔,以获得更好的泛化能力。正则化项用于控制模型的复杂度,防止过拟合。

  7. 核函数:为了处理非线性问题,SVM引入了核函数,它可以将原始数据映射到更高维的空间中,在这个新的空间中寻找线性可分的超平面。常用的核函数包括线性核、多项式核、径向基函数(RBF)核等。

  8. SVM的实现:SVM的实现通常包括选择合适的核函数、设置正则化参数和误差项的惩罚系数,然后通过求解优化问题来训练模型。

  9. 多类分类:对于多类分类问题,SVM可以采用一对一或一对其余等策略,将多类问题转化为多个二类问题来解决。

  10. SVM的优缺点:SVM在许多基准数据集上表现出色,特别是在高维数据上。它的优点包括内存效率高、分类精度高、对非线性问题有很好的处理能力。但缺点是对于大规模数据集的训练可能比较慢,对核函数和参数的选择敏感,且在某些噪声较大的数据集上可能表现不佳。

SVM是一种强大的分类算法,广泛应用于生物信息学、图像识别、文本分类等领域。

代码解释:

这段代码是一个使用支持向量机(SVM)进行图像分类的示例,主要分为以下几个部分:

  1. 导入必要的库:代码开始处导入了numpysklearn中的一些模块、timeoperatorosPIL等库。

  2. 图像数据加载imagedata函数用于加载图像文件夹中的所有图像,将它们转换为灰度,并调整为28x28像素的尺寸,然后归一化并返回图像数据数组。

  3. 标签数据加载labeldata函数用于从MNIST数据集的标签文件中读取标签数据。注意这里有一个逻辑错误,for循环的范围应该是基于文件的实际大小,而不是固定的21。

  4. 数据归一化:将图像数据X的像素值从[0, 255]缩放到[0, 1]。

  5. 数据类型转换:将标签数据y转换为整数类型。

  6. 添加偏置项X_train_bias通过在每个特征向量的末尾添加一个值为1的列来添加偏置项,这对于线性模型是必要的。

  7. 损失函数L_i_vectorizedL函数分别计算了单个样本和整个训练集的损失。

  8. SVM训练函数train_svm函数实现了SVM的训练过程。它使用随机梯度下降优化权重矩阵W,并通过正则化防止过拟合。

  9. 模型训练:使用train_svm函数和添加了偏置项的训练数据X_train_bias以及标签y_train来训练SVM模型。

  10. 预测:使用训练好的权重矩阵W对第一个训练样本进行预测,计算得分,并找到得分最高的类别作为预测结果。

  11. 计算准确率:这部分代码被注释掉了,如果取消注释,它将计算模型在整个测试集上的准确率。

代码中有几个需要注意的地方:

  • labeldata函数的实现可能不正确,因为它假设标签文件的大小是固定的,而实际上应该根据文件的实际大小来读取。
  • train_svm函数中的y_batch应该从标签到索引的映射,但在代码中没有看到相应的转换。
  • 代码中的注释和打印语句有助于理解每个步骤的作用,但在实际使用中可能需要根据具体情况进行调整。

整体来看,这段代码展示了如何使用SVM对图像数据进行分类,包括数据预处理、模型训练和预测等步骤。

import numpy as np
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
import numpy as np
import time
import operator
import os
from PIL import Image
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 加载MNIST数据集


def imagedata(image_folder):
    image_files = os.listdir(image_folder)
    image_list = []
    for image_file in image_files:
        file_path = os.path.join(image_folder, image_file)
        with Image.open(file_path) as img:
            img_gray = img.convert('L')
            img_resized = img_gray.resize((28, 28))
            image_arry = np.array(img_resized)
            image_list.append(image_arry)
    mnist_images = np.stack(image_list)
    train_image = mnist_images.reshape(mnist_images.shape[0], -1)
    return train_image


def labeldata(MNIST_labels_path):
    with open(MNIST_labels_path, 'rb') as f:
        file_labels = f.read()
    train_label = []
    for i in range(1, 21):
        label = int.from_bytes(file_labels[i + 8 - 1:8 + i], 'big')
        train_label.append(label)
    return train_label
image_folder = "D:\\MNIST_data\\train1"
MNIST_labels_path = 'D:\\MNIST_data\\train-labels-idx1-ubyte\\train-labels.idx1-ubyte'
X = imagedata(image_folder)
y = labeldata(MNIST_labels_path)
test_image_folder = "D:\\MNIST_data\\test"
test_image = imagedata(test_image_folder)


X = X / 255.0  # 将像素值缩放到0到1之间

y = np.array(y)
y = y.astype(int)
X_train=X
y_train=y
# 将数据分割为训练集和测试集
# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 添加偏置项到特征向量中
X_train_bias = np.c_[X_train, np.ones((X_train.shape[0], 1))]
# X_test_bias = np.c_[X_test, np.ones((X_test.shape[0], 1))]

def L_i_vectorized(x, y, W):
    delta = 1.0
    scores = W.dot(x)
    margins = np.maximum(0, scores - scores[y] + delta)
    margins[y] = 0
    loss_i = np.sum(margins)
    return loss_i

def L(X, y, W):
    num_train = X.shape[1]
    scores = W.dot(X)
    margins = np.maximum(0, scores - scores[y] + 1.0)
    margins[y, np.arange(num_train)] = 0
    loss = np.sum(margins) / num_train
    return loss


def train_svm(X, y, learning_rate=1e-7, reg=5e4, num_iters=1000, batch_size=20):
    num_train = X.shape[0]
    dim = X.shape[1]
    num_classes = len(np.unique(y))
    W = np.zeros((num_classes, dim+1))  # 初始化权重矩阵,包含偏置项

    for it in range(num_iters):
        batch_size = min(batch_size, num_train)
        idx = np.random.choice(num_train, batch_size, replace=False)
        X_batch = X[idx]
        y_batch = y[idx]   # 将类别标签转换为从0开始的索引

        loss = 0
        dW = np.zeros_like(W)
        for i in range(batch_size):
            xi = X_batch[i]
            yi = y_batch[i]
            scores = W[:, :-1].dot(xi) + W[:, -1]  # 计算得分,包括偏置项
            correct_class_score = scores[yi]
            margins = np.maximum(0, scores - correct_class_score + 1)
            margins[yi] = 0  # 忽略正确类别的边界违反
            loss_i = np.sum(margins)
            loss += loss_i

            # 计算梯度
            for j in range(num_classes):
                if j == yi:
                    # 仅对正确类别计算梯度
                    dW[j, :-1] -= learning_rate * (xi * (margins[j] > 0) - reg * W[j, :-1])
                    dW[j, -1] -= learning_rate * (1 * (margins[j] > 0) - reg * W[j, -1])
                else:
                    # 对其他类别,如果违反了边界,则更新梯度
                    if margins[j] > 0:
                        dW[j, :-1] -= learning_rate * (xi * 1 - reg * W[j, :-1])
                        dW[j, -1] -= learning_rate * (1 * 1 - reg * W[j, -1])

        W += dW
        loss /= batch_size

        if it % 10 == 0:
            print(f"Iteration {it}: loss {loss}")
    return W


# 训练模型
W = train_svm(X_train_bias, y_train , learning_rate=1e-8, reg=5e4, num_iters=1000, batch_size=5)

# # 预测
scores = W.dot(X_train_bias[0].T)
y_pred = np.argmax(scores, axis=0)
#
# # 计算准确率
# accuracy = np.mean(y_pred == y_test)
# print(f"Accuracy: {accuracy}")

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值