目录

1--前言

2--路径总览

3--划分数据集

3.1--数据集介绍:

3.2--代码:

3.3--运行及结果:

4--主函数

4.1--原理分析:

4.2--源码:

4.3--运行及结果:

5--参考

6--问题补充


1--前言

①sysu模式识别作业

②数据集:ORL Database of Faces

③原理: wk_NNC算法

2--路径总览

机器学习笔记--改进KNN算法实现人脸识别-LMLPHP

3--划分数据集

3.1--数据集介绍:

①ORL数据集采用P5类型的PGM格式进行存储,下图以记事本打开一个样本为例进行说明:

机器学习笔记--改进KNN算法实现人脸识别-LMLPHP

分析:第一行说明图片为P5格式;第二行为图片的宽高数据;第三行为数据的最大值;第四行及之后存储了图片的像素值

注:需要说明的是,在划分数据集中用到了图片的宽高(H, W)数值,即(92,112),同时使用了min = 0max = 255进行归一化;

3.2--代码:

import os
from PIL import Image
import numpy as np
import random

def split_dataset(data_path, proportion):

    # 初始化训练集、验证集及其标签
    train_dataset = []
    test_dataset = []
    train_labels = []
    test_labels = []

    for i in range(40): # 遍历40类
        sample_list = os.listdir(data_path + '/s' + str(i + 1)) # 10个样本名
        random.shuffle(sample_list) # 随机打乱10个样本
        for j in range(len(sample_list)): # 遍历打乱后的10个样本
            img = Image.open(data_path + '/s' + str(i + 1) + '/' + sample_list[j]) # 读取第j个样本
            if j < (proportion * len(sample_list)): # 前7个划分到训练集
                train_dataset.append(np.array(img, dtype=np.uint8)) # 存储训练数据
                train_labels.append(i) # 存储训练标签
            else:
                test_dataset.append(np.array(img, dtype=np.uint8))  # 存储验证数据
                test_labels.append(i)  # 存储验证标签
    return train_dataset, train_labels, test_dataset, test_labels

def process_data(train_dataset, train_labels, test_dataset, test_labels):

    # 计算训练集和验证集的数目
    train_sum = len(train_dataset) # 等于 40 * 10 * proportion
    test_sum = len(test_dataset) # 等于 40 * 10 * (1-proportion)

    # 初始化处理后的训练集和验证集
    train_data = np.zeros((train_sum, H * W))
    test_data = np.zeros((test_sum, H * W))
    train_label = np.array(train_labels)
    test_label = np.array(test_labels)

    for i in range(train_sum): # 遍历每一个样本
        temp = train_dataset[i].reshape(-1) # reshape成单维向量
        train_data[i] = (temp - 0) / (255 - 0) # 归一化
    for j in range(test_sum):
        temp = test_dataset[j].reshape(-1)
        test_data[j] = (temp - 0) / (255 - 0) # 归一化

    return train_data, train_label, test_data, test_label

if __name__ == "__main__":

    # 参数
    data_path = './dataset/ORL/att_faces/orl_faces'  # 数据集路径
    proportion = 0.7  # 划分比例 0.7训练 0.3验证
    H = 92
    W = 112

    # 划分数据集
    train_dataset, train_labels, test_dataset, test_labels = split_dataset(data_path = data_path, proportion = proportion)

    # 数据集预处理
    train_data, train_label, test_data, test_label = process_data(train_dataset, train_labels, test_dataset, test_labels)

    save_name = './dataset/dataset.npz'
    np.savez(save_name, x_train=train_data, y_train=train_label, x_test=test_data, y_test=test_label)

3.3--运行及结果:

python gen_dataset.py

4--主函数

4.1--原理分析:

(具体公式参考链接,这里只做原理简述)

①首先计算当前分类样本与训练样本的距离(常用欧式距离),让k个距离最小的训练样本拥有投票权;

②初始化所有类别的概率均为1,即初始化权重得分均为1;

③根据公式计算前k个训练样本的权重得分,并让投票样本的类别作为分类样本的预测类别;

④分类样本被预测为投票样本的概率由投票样本的权重得分决定

⑤最终权重得分和最高的类别为分类样本的预测类别。

4.2--源码:

import numpy as np

# KNN classifier
def kNNClassify(test_x, train_x, train_y, k=4):

    # 计算与训练集样本的距离(280个),这里用欧几里得距离表示
    distance = np.sum(np.power((train_x - test_x), 2), axis=1) # 280
    sort_inx = np.argsort(distance, kind="quicksort")[:k] # 取前k个最小距离对应的索引,即训练集样本的索引

    w = [] # 初始化距离权重
    for i in range(k): # 利用 wk-NNC 算法公式计算k个近邻的权重
        w.append((distance[sort_inx[k - 1]] - distance[sort_inx[i]]) / (distance[sort_inx[k - 1]] - distance[sort_inx[0]]))

    score = np.ones(40) # 40个类别的得分
    for inx, data in enumerate(sort_inx):
        vote_label = train_y[data]  # 投票类别,即当前邻居k对应的类别 (取值为0~39)
        score[vote_label] += w[inx]  # 投票类别的得分 = 原始得分(初始化全为1) + 权重得分

    pre_label = np.argmax(score)  # 取得分最高的类别作为预测类别
    return pre_label

if __name__ == "__main__":

    # 读取数据集
    dataset_path = './dataset/dataset.npz'
    dataset = np.load(dataset_path)
    train_dataset = dataset['x_train']
    train_labels = dataset['y_train']
    test_dataset = dataset['x_test']
    test_labels = dataset['y_test']

    # 邻居数
    k = 4

    correct_sum = 0 # 预测正确的样本数
    test_sum = test_dataset.shape[0] # 验证集样本数
    string = "test_number: {0}, true_label: {1}, pre_label: {2}------>correct?: {3}" # 定义打印格式
    for i in np.arange(test_sum):
        # 利用KNN进行分类
        label = kNNClassify(test_x = test_dataset[i], train_x = train_dataset, train_y = train_labels, k=k)

        if label == test_labels[i]: # 分类正确
            correct_sum = correct_sum + 1

        print(string.format(i + 1, test_labels[i], label, label == test_labels[i])) # 打印当前样本分类结果

    print("Accuracy: {}%".format((correct_sum / test_sum) * 100)) # 打印最终准确率

4.3--运行及结果:

python knn.py

机器学习笔记--改进KNN算法实现人脸识别-LMLPHP

5--参考

参考1

参考2

6--问题补充

未完待续!

11-09 06:50