人工智能-KNN

461次阅读
没有评论

共计 9478 个字符,预计需要花费 24 分钟才能阅读完成。

提醒:本文最后更新于 2024-08-28 15:03,文中所关联的信息可能已发生改变,请知悉!

双十一憋在寝室炼丹

在这次作业中,我们将尝试提取基本的图像特征并使用提取的特征进行图像分类。

你需要在 TODO 模块的 """ 你的代码 """ 中填写相应的代码。

你也可以添加任意数量的 cell 来辅助你完成实验。

import random
import numpy as np
import matplotlib.pyplot as plt
from past.builtins import xrange
%matplotlib inline
plt.rcParams['figure.figsize'] = (15., 12.) # 设置默认大小
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'

%load_ext autoreload
%autoreload 2
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

数据加载

理解该数据集的类型以及访问方式

# 读取提供的 cifar10-mini 数据集,data = np.load('cifar10-mini.npz')

X_train= data['X_train']
X_val= data['X_val']
X_test= data['X_test']
y_train= data['y_train']
y_val= data['y_val']
y_test= data['y_test']

# 打印数据 shape
print(X_train.shape)
print(X_val.shape)
print(X_test.shape)
(5000, 32, 32, 3)
(500, 32, 32, 3)
(500, 32, 32, 3)

提取图像特征

方向梯度直方图 HOG (Histogram of Oriented Gridients)特征检测算法,最早是由法国研究员 Dalal 等在 CVPR-2005 上提出来的,一种解决人体目标检测的图像描述子,是一种用于表征图像局部梯度方向和梯度强度分布特性的描述符。其主要思想是:在边缘具体位置未知的情况下,边缘方向的分布也可以很好的表示图像中物体的外形轮廓,但会忽略掉颜色信息。特征维度是 144 维

颜色直方图 (color histogram)特征则是提取图像的颜色信息并忽略掉纹理信息。因此同时使用这两种特征的分类效果会好于仅使用单一特征,【加分项】你可以尝试进行对比实验验证这一假设

hog_featurecolor_histogram_hsv 两个函数都是接收一张图像然后返回这张图像的特征向量。你可以使用这两个函数中的一个提取所有图像的特征并将其存入 X_train_feats, X_val_feats, X_test_feats 这三个变量中(他们分别代表训练集、验证集和测试集的特征)。

如果你遇到了错误 ImportError: No module named past.builtins,可以在终端中执行 pip install future

from features import *

################################################################################
# TODO:                                                                        #
# 你需要使用 hog_feature, color_histogram_hsv 两个函数完成特征的提取           #
# 你可以在 features.py 中查看这两个函数的代码                                  #
################################################################################
""" 你的代码 """

feature_fns = [hog_feature, lambda img: hog_feature(img)]
# feature_fns = [hog_feature, lambda img: color_histogram_hsv(img)]

X_train_feats = extract_features(X_train, feature_fns, verbose=True)
X_val_feats = extract_features(X_val, feature_fns)
X_test_feats = extract_features(X_test, feature_fns)

################################################################################
#                                 END OF YOUR CODE                             #
################################################################################

# 预处理: 减去均值
mean_feat = np.mean(X_train_feats, axis=0, keepdims=True)
X_train_feats -= mean_feat

mean_feat = np.mean(X_val_feats, axis=0, keepdims=True)
X_val_feats -= mean_feat

mean_feat = np.mean(X_test_feats, axis=0, keepdims=True)
X_test_feats -= mean_feat

# 预处理: 除以标准差,这能保证所有的值在 0~1 之间
std_feat = np.std(X_train_feats, axis=0, keepdims=True)
X_train_feats /= std_feat

std_feat = np.std(X_val_feats, axis=0, keepdims=True)
X_val_feats /= std_feat

std_feat = np.std(X_test_feats, axis=0, keepdims=True)
X_test_feats /= std_feat

# 预处理: 增加一个偏置值,在 K-NN 中,该步操作并无必要,但增加偏置值对其他分类器如 SVM 等有帮助。X_train_feats = np.hstack([X_train_feats, np.ones((X_train_feats.shape[0], 1))])
X_val_feats = np.hstack([X_val_feats, np.ones((X_val_feats.shape[0], 1))])
X_test_feats = np.hstack([X_test_feats, np.ones((X_test_feats.shape[0], 1))])
Done extracting features for 1000 / 5000 images
Done extracting features for 2000 / 5000 images
Done extracting features for 3000 / 5000 images
Done extracting features for 4000 / 5000 images

使用 k-NN 算法对图像进行分类

使用上面提取的特征执行 k-NN 算法对图像分类,在这里,【加分项】你也可以实验对比使用 HOG 特征、颜色直方图特征与使用图像原始特征(像素)哪个好。或者尝试特征拼接。

这里你需要补全 KNearestNeighbor 类中的部分关键函数的代码,包括compute_distances_one_loop,compute_distances_two_loop,compute_distances_no_loop

你可能需要认真阅读玩下面两篇文章后才能完成这部分作业:

class KNearestNeighbor(object):
    """ 使用 L2 距离的 kNN 分类器 """
    def __init__(self):
        pass

    def train(self, X, y):
        """ 
        训练分类器 

        输入:- X: 一个形状为 (num_train, D) 的 numpy 数组,包含训练数据。- y: 一个形状为 (num_train,) 的 numpy 数组,包含训练标签,其中 y[i]是 X[i]的标签。"""
        self.X_train = X
        self.y_train = y

    def predict(self, X, k=1, num_loops=0):
        """
        使用该分类器预测测试数据的标签。输入:- X: 一个形状为 (num_test, D) 的 numpy 数组,包含测试数据。- k: 为预测标签投票的近邻的数量。- num_loops: 决定使用哪种方法来计算训练点和测试点之间的距离。训练点和测试点之间的距离。输出:- y: 一个形状为 (num_test,) 的 numpy 数组,包含测试数据的预测标签。测试数据的预测标签,其中 y[i]是测试点 X[i]的预测标签。"""
        if num_loops == 0:
            dists = self.compute_distances_no_loops(X)
        elif num_loops == 1:
            dists = self.compute_distances_one_loop(X)
        elif num_loops == 2:
            dists = self.compute_distances_two_loops(X)
        else:
            raise ValueError('Invalid value %d for num_loops' % num_loops)

        return self.predict_labels(dists, k=k)

    def compute_distances_two_loops(self, X):
        """
        计算 X 中每个测试点和 self.X_train 中每个训练点之间的距离。需要使用一个嵌套循环。输入:
        - X:一个形状为 (num_test, D) 的 numpy 数组,包含测试数据。输出:
        - dists: 一个形状为 (num_test, num_train) 的 numpy 数组,其中 dists[i, j] 是第 i 个测试点和第 j 个训练点之间的欧几里得距离。"""
        num_test = X.shape[0]
        num_train = self.X_train.shape[0]
        dists = np.zeros((num_test, num_train))
        for i in xrange(num_test):
            for j in xrange(num_train):
                #####################################################################
                # TODO:                                                             #
                # 计算第 i 个测试点和第 j 个训练点之间的 l2 距离,并将结果存入 dists[i, j]中
                #####################################################################
                """ 你的代码 """

                dists[i, j] = np.linalg.norm(X[i] - self.X_train[j])

                #####################################################################
                #                       END OF YOUR CODE                            #
                #####################################################################
        return dists

    def compute_distances_one_loop(self, X):
        """
        计算 X 中每个测试点和 self.X_train 中每个训练点之间的距离。只需在测试数据上进行一次循环。输入 / 输出。与 compute_distances_two_loops 相同
        """
        num_test = X.shape[0]
        num_train = self.X_train.shape[0]
        dists = np.zeros((num_test, num_train))
        for i in xrange(num_test):
            #######################################################################
            # TODO:                                                               #
            # 计算第 i 个测试点和所有训练点之间的 l2 距离,并将结果存入 dists[i, :]中。#
            #######################################################################
            """ 你的代码 """

            dists[i] = np.linalg.norm(X[i]-self.X_train, axis=1)

            #######################################################################
            #                         END OF YOUR CODE                            #
            #######################################################################
        return dists

    def compute_distances_no_loops(self, X):
        """
        计算 X 中每个测试点和 self.X_train 中每个训练点之间的距离,不使用显式循环。输入 / 输出。与 compute_distances_two_loops 相同
        """
        num_test = X.shape[0]
        num_train = self.X_train.shape[0]
        dists = np.zeros((num_test, num_train)) 
        ##########################################################################
        # TODO:                                                                  #
        # 计算所有测试点和所有训练点之间的 l2 距离,不使用任何显式循环             #
        # 并将结果存储在 dists 中                                                  #
        ##########################################################################
        """ 你的代码 """

        x2 = np.sum(X**2, axis=1).reshape((num_test, 1))
        y2 = np.sum(self.X_train**2, axis=1).reshape((1, num_train))
        xy = -2 * np.matmul(X, self.X_train.T)
        dists = np.sqrt(x2 + xy + y2)

        ##########################################################################
        #                         END OF YOUR CODE                               #
        ##########################################################################
        return dists

    def predict_labels(self, dists, k=1):
        """
        给出一个测试点和训练点之间距离的矩阵。为每个测试点预测一个标签。输入:
        - dists: 一个形状为 (num_test, num_train) 的 numpy 数组,其中 dists[i, j] ... 表示第 i 个测试点和第 j 个训练点之间的距离。输出:
        - y: 一个形状为 (num_test,) 的 numpy 数组,包含测试数据的预测标签。其中 y[i]是测试点 X[i]的预测标签。"""
        num_test = dists.shape[0]
        y_pred = np.zeros(num_test)
        for i in xrange(num_test):
            # 一个长度为 k 的列表,存储第 i 个测试点的 k 个最近的邻居的标签。closest_y = []

            # 使用距离矩阵找到第 1 个测试点的 k 个最近的邻居,并使用 self.y_train 来找到这些邻居的标签。#
            # 将这些标签存储在 closest_y 中。#
            k_nearest_idxs = np.argsort(dists[i, :])[:k]
            closest_y = self.y_train[k_nearest_idxs]

            # 找到标签列表 closest_y 中最常见的标签,将这个标签存入 y_pred[i]。#
            y_pred[i] = np.argmax(np.bincount(closest_y))

        return y_pred
# 实例化
classifier = KNearestNeighbor()
# 训练 KNN 分类器
classifier.train(X_train_feats, y_train)

# 使用验证集调整 k 的值
k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]
k_to_accuracies = {} # 用来存储结果

##########################################################################################
# TODO:                                                                                  #
# 你需要从 k_choice 中找出最好的 k                                                       #
# 如果 accuracy <= 0.1,说明结果不对,随机猜的准确率是 0.1,需要修改 k_nearest_neighbor.py #
##########################################################################################

#遍历所有的 k,在验证集上进行结果测试分类的准确性
for k in k_choices:
    """ 你的代码 """

    k_to_accuracies[k] = []

    num_folds = 5
    X_train_folds = np.array_split(X_train_feats, num_folds)
    y_train_folds = np.array_split(y_train, num_folds)  # 不均等分割

    accuracies = []
    for i in range(num_folds):
        X_train_cv = np.vstack(X_train_folds[0:i] + X_train_folds[i+1:])
        y_train_cv = np.hstack(y_train_folds[0:i] + y_train_folds[i+1:])
        X_valid_cv = X_train_folds[i]
        y_valid_cv = y_train_folds[i]

        classifier.train(X_train_cv, y_train_cv)
        dists = classifier.compute_distances_no_loops(X_valid_cv)
        y_valid_pred = classifier.predict_labels(dists, k)
        num_correct = np.sum(y_valid_pred == y_valid_cv)
        accuracy = float(num_correct) / y_valid_cv.shape[0]
        accuracies.append(accuracy)

    k_to_accuracies[k] = accuracies

for k in k_choices:
    accuracies = k_to_accuracies[k]
    print('k = %d, average accuracy = %f' % (k, np.average(accuracies)))
    plt.scatter([k] * len(accuracies), accuracies)

accuracies_mean = np.array([np.mean(v) for k,v in sorted(k_to_accuracies.items())])
accuracies_std = np.array([np.std(v) for k,v in sorted(k_to_accuracies.items())])
plt.errorbar(k_choices, accuracies_mean, yerr=accuracies_std)
plt.title('accuracy-k')
plt.xlabel('k')
plt.ylabel('accuracy')
plt.show()

##########################################################################################
#                                 END OF YOUR CODE                                       #
##########################################################################################

print(k_to_accuracies)
k = 1, average accuracy = 0.304400
k = 3, average accuracy = 0.297800
k = 5, average accuracy = 0.311400
k = 8, average accuracy = 0.317200
k = 10, average accuracy = 0.326200
k = 12, average accuracy = 0.321400
k = 15, average accuracy = 0.314200
k = 20, average accuracy = 0.316600
k = 50, average accuracy = 0.289600
k = 100, average accuracy = 0.265600

人工智能 -KNN

{1: [0.292, 0.29, 0.287, 0.325, 0.328], 3: [0.289, 0.296, 0.296, 0.29, 0.318], 5: [0.315, 0.297, 0.314, 0.3, 0.331], 8: [0.32, 0.308, 0.327, 0.303, 0.328], 10: [0.328, 0.309, 0.334, 0.319, 0.341], 12: [0.312, 0.315, 0.321, 0.332, 0.327], 15: [0.315, 0.304, 0.319, 0.32, 0.313], 20: [0.334, 0.312, 0.3, 0.326, 0.311], 50: [0.295, 0.282, 0.292, 0.298, 0.281], 100: [0.285, 0.276, 0.251, 0.27, 0.246]}
# 评估你的算法
##########################################################################################
# TODO:                                                                                  #
# 根据验证集的结果,选择合适的 K 值,并在测试集上测试结果                                  #
""" 你的代码 """
best_k = 10  # 填你上面选出的 K 值 
##########################################################################################
#                                 END OF YOUR CODE                                       #
##########################################################################################

# 计算测试集上准确率
y_test_pred = classifier.predict(X_test_feats, k=best_k)
test_accuracy = np.mean(y_test == y_test_pred)
print(test_accuracy)
0.302
正文完
 0
icvuln
版权声明:本站原创文章,由 icvuln 于2021-11-11发表,共计9478字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)