KNN识别:一眼认出你喜欢的明星!

全文共7985字,预计学习时长20分钟

你能从下图中认出自己最喜爱的名人吗?当然可以啦。而计算机会如何完成这项任务呢?接下来的几分钟里,让我们来训练一个用来识别名人人脸的模型!完成这项任务,我们要用到同种算法!

该数据集来源于Pinterest,而后经过精心策划——裁剪和标记。其中,从Adriana Lima到Tom Ellis,包含105位名人及17534张人脸。通过Kaggle临时令牌导入Kaggle数据集(在Google Colab上):

from google.colab import files

"""upload your Kaggle temporary token downloaded from yourKaggle account onto your local device"""

files.upload() Out:

Saving kaggle.json to kaggle.json

{'kaggle.json': b'{"username":"xxx","key":"yyy"}'}

下载数据集:

!mkdir -p ~/.kaggle

!cp kaggle.json ~/.kaggle/

!chmod 600 ~/.kaggle/kaggle.json!kaggle datasets download -dhereisburak/pins-face-recognitionOut:

Downloading pins-face-recognition.zip to /content

97% 361M/372M [00:13<00:00, 20.9MB/s]

100% 372M/372M [00:14<00:00, 27.8MB/s]

检查文件是否下载成功:

!lsOut:

kaggle.json pins-face-recognition.zip sample_data

解压文件:

!unzip "pins-face-recognition.zip" -d /tmp

检查每个目录下的文件数量:

import os

print(len(os.listdir('/tmp')))

print(len(os.listdir('/tmp/105_classes_pins_dataset/')))

print(len(os.listdir('/tmp/105_classes_pins_dataset/pins_tom ellis/')))

print(len(os.listdir('/tmp/105_classes_pins_dataset/pins_margot robbie/')))Out:

1

105

180

221

随机选取一系列图像并打印它们的形状:

import cv2

a = 60

b = 3241

for i in range(8):

im =cv2.imread('/tmp/105_classes_pins_dataset/pins_margot robbie/

margotrobbie'+str(a+i)+'_'+str(b+i)+'.jpg')

print(im.shape)Out:

(320, 302, 3)

(221, 209, 3)

(225, 209, 3)

(221, 209, 3)

(387, 365, 3)

(266, 251, 3)

(225, 209, 3)

(185, 175, 3)

这些都是不同维度的形状。尝试在Margot Robbie的目录下绘制一系列图像:

from matplotlib import pyplot

from matplotlib.image import imread

folder = '/tmp/105_classes_pins_dataset/pins_margot robbie/'

for i in range(8):

pyplot.subplot(330 + 1 + i)

filename = folder+'margotrobbie'+str(a+i)+'_'+str(b+i)+'.jpg'

image = imread(filename)

pyplot.imshow(image)

pyplot.show()

尝试对2020年一月份的世界首富Elon Musk的目录做同样的工作:

from matplotlib import pyplot

from matplotlib.image import imread

folder = '/tmp/105_classes_pins_dataset/pins_elon musk/'

a = 191

b = 1575

for i in range(7):

pyplot.subplot(330 + 1 + i)

filename = folder+'elonmusk'+str(a+i)+'_'+str(b+i)+'.jpg'

image = imread(filename)

pyplot.imshow(image)

pyplot.show()

看!价值连城的微笑!我们需要的一些库:

import numpy as np

from PIL import Image

import operator

from operator import itemgetter

尝试重设图像大小——以Talor Swift为例(更改为128*128*3):

from PIL import Image

img = Image.open('/tmp/105_classes_pins_dataset/pins_Taylor Swift/TaylorSwift4_4643.jpg')

img = img.resize((128,128))

img

np.asarray(img) #display the pixel arrayOut:

array([[[187, 191, 202],

[187, 191, 202],

[187, 191, 202],

...,

[ 94, 85, 78],

[104, 95, 87],

[ 98, 89, 80]],

[[187, 191, 202],

[188, 192, 203],

[188, 192, 203],

...,

[ 82, 72, 66],

[ 95, 84, 77],

[ 92, 82, 73]],

[[187, 191, 202],

[187, 191, 202],

[187, 191, 202],

...,

[107, 96, 91],

[105, 94, 87],

[100, 90, 81]],

...,

[[244, 143, 171],

[243, 143, 171],

[242, 145, 172],

...,

[186, 135, 105],

[190, 137, 109],

[193, 138, 111]],

[[236, 144, 169],

[234, 144, 169],

[234, 149, 172],

...,

[187, 147, 117],

[191, 148, 121],

[184, 140, 114]],

[[232, 142, 167],

[230, 143, 167],

[232, 150, 172],

...,

[170, 137, 107],

[152, 116, 89],

[143, 104, 78]]], dtype=uint8)

检查重设后图像的宽度和高度:

width, height = img.size

print(width, height)Out:

128 128

现在,麻烦的部分来了:逐个目录进行迭代,而后遍历其中的图像——直接将它们的大小重设为(128*128),并将每张图像的像素矩阵附加到X上,对应的名人标签附加到y上——跟踪我们的计数:

X = []

y = []

count = 0

dir="/tmp/105_classes_pins_dataset/"

for i in os.listdir(dir):

print(i,":",len(os.listdir(dir+"/"+i)))

count+=len(os.listdir(dir+"/"+i))

for j inos.listdir(dir+"/"+i):

img =Image.open(dir+"/"+i+"/"+j)

img = img.resize((128,128))

X.append(np.asarray(img))

y.append(i)

print(count)

X = np.asarray(X)

y = np.asarray(y)

print(X.shape, y.shape)Out:

pins_ellen page : 188

pins_Avril Lavigne : 162

pins_Marie Avgeropoulos : 161

pins_Rebecca Ferguson : 178

pins_Robert De Niro : 156

pins_Emilia Clarke : 210

pins_Dwayne Johnson : 141

pins_Josh Radnor : 117

pins_Ben Affleck : 126

pins_Zoe Saldana : 186

pins_camila mendes : 162

pins_Morgan Freeman : 105

pins_Alvaro Morte : 139

pins_Pedro Alonso : 125

pins_Taylor Swift : 131

pins_Natalie Dormer : 198

pins_Andy Samberg : 196

pins_grant gustin : 183

pins_Brie Larson : 169

pins_Lindsey Morgan : 169

pins_Lionel Messi : 86

pins_kiernen shipka : 203

pins_Mark Ruffalo : 178

pins_Gwyneth Paltrow : 187

pins_tom ellis : 180

pins_Tuppence Middleton : 133

pins_Tom Hardy : 198

pins_Wentworth Miller : 179

pins_Amanda Crew : 117

pins_Nadia Hilker : 133

pins_Jason Momoa : 184

pins_Megan Fox : 209

pins_Rami Malek : 160

pins_Zendaya : 138

pins_Stephen Amell : 159

pins_Elizabeth Lail : 158

pins_gal gadot : 199

pins_margot robbie : 221

pins_Dominic Purcell : 146

pins_Leonardo DiCaprio : 237

pins_Tom Holland : 189

pins_Jessica Barden : 141

pins_Penn Badgley : 171

pins_Sarah Wayne Callies : 159

pins_Bill Gates : 122

pins_Johnny Depp : 182

pins_Jimmy Fallon : 113

pins_Chris Evans : 166

pins_Jennifer Lawrence : 180

pins_Richard Harmon : 148

pins_scarlett johansson : 201

pins_Brenton Thwaites : 209

pins_elizabeth olsen : 221

pins_elon musk : 135

pins_Irina Shayk : 156

pins_Henry Cavil : 195

pins_Inbar Lavi : 127

pins_Sophie Turner : 204

pins_Shakira Isabel Mebarak : 154

pins_Jeremy Renner : 167

pins_barack obama : 119

pins_Chris Pratt : 176

pins_amber heard : 218

pins_Madelaine Petsch : 192

pins_Lili Reinhart : 150

pins_Ursula Corbero : 167

pins_Alex Lawther : 152

pins_Zac Efron : 191

pins_Selena Gomez : 186

pins_alycia dabnem carey : 211

pins_Morena Baccarin : 175

pins_Danielle Panabaker : 181

pins_Emma Watson : 211

pins_Katharine Mcphee : 177

pins_Logan Lerman : 212

pins_Anne Hathaway : 203

pins_Rihanna : 133

pins_jeff bezos : 106

pins_Jake Mcdorman : 159

pins_Mark Zuckerberg : 95

pins_Adriana Lima : 213

pins_Brian J. Smith : 102

pins_barbara palvin : 197

pins_Robert Downey Jr : 233

pins_Emma Stone : 139

pins_Tom Cruise : 192

pins_Eliza Taylor : 162

pins_Cristiano Ronaldo : 98

pins_Maisie Williams : 193

pins_Miley Cyrus : 178

pins_Millie Bobby Brown : 191

pins_Alexandra Daddario : 225

pins_Christian Bale : 154

pins_melissa fumero : 154

pins_Natalie Portman : 166

pins_Neil Patrick Harris : 116

pins_Anthony Mackie : 124

pins_Bobby Morley : 138

pins_Krysten Ritter : 171

pins_Hugh Jackman : 179

pins_Katherine Langford : 226

pins_Chris Hemsworth : 159

pins_Tom Hiddleston : 181

pins_Maria Pedraza : 122

pins_Keanu Reeves : 160

17534

(17534, 128, 128, 3) (17534,)

注意:可以优化的地方——在重设大小的同时,可以将这些图像直接转换成灰阶——因为颜色在此没什么意义,处理灰阶图像的计算成本更低。

重设X (17534, 128, 128, 3)为(17534, 128*128*3):

X = X.reshape(17534, 49152).astype('float32')

对0至1之间的像素进行标准化:

X/=255

X.shapeOut:

(17534, 49152)

从零开始实现

先定义一个返回两点之间欧氏距离的函数:

def euc_dist(x1, x2):

return np.sqrt(np.sum((x1-x2)**2))

注意:可以优化的地方——可以用曼哈顿距离替代欧氏距离,因为平方计算成本较高,尤其是在处理这样的多维像素矩阵的时候!

现在,编写一个名为“KNN”的类,并为“K”值初始化一个实例:

class KNN:

def __init__(self, K=3):

self.K = K

将一个用于初始化实例的函数添加到类,以与训练集匹配——X-train和y-train:

class KNN:

def __init__(self, K=3):

self.K = K

def fit(self, x_train, y_train):

self.X_train = x_train

self.Y_train = y_train

将预测函数添加到类:

def predict(self, X_test):

predictions = []

for i in range(len(X_test)):

dist =np.array([euc_dist(X_test[i], x_t) for x_t in

self.X_train])

dist_sorted =dist.argsort()[:self.K]

neigh_count = {}

for idx in dist_sorted:

if self.Y_train[idx] inneigh_count:

neigh_count[self.Y_train[idx]] += 1

else:

neigh_count[self.Y_train[idx]]= 1

sorted_neigh_count =sorted(neigh_count.items(),

key=operator.itemgetter(1),reverse=True)

predictions.append(sorted_neigh_count[0][0])

return predictions

我们来一行一行理解——

首先初始化了一个用于存储预测结果的列表,然后运行一个循环来计算每个测试示例与相应训练示例之间的欧式距离,并将这些距离存储在NumPy数组中,之后返回这些距离的第一个K排序值的索引,然后创建一个字典,其中类标签为键,它们的事件为值。

接着,将每个键值对的计数添加到neigh_count字典中,之后,根据出现次数,将键值对降序排列,其中,出现最多的值将是对每个训练示例的预测结果。然后,返回预测结果。

最终代码——

def euc_dist(x1, x2):

returnnp.sqrt(np.sum((x1-x2)**2))

class KNN:

def __init__(self, K=3):

self.K = K

def fit(self, x_train,y_train):

self.X_train = x_train

self.Y_train = y_train

def predict(self, X_test):

predictions = []

count = 0

for i inrange(len(X_test)):

count = count + 1

dist =np.array([euc_dist(X_test[i], x_t) for x_t in self.X_train])

dist_sorted =dist.argsort()[:self.K]

neigh_count = {}

for idx indist_sorted:

ifself.Y_train[idx] in neigh_count:

neigh_count[self.Y_train[idx]] += 1

else:

neigh_count[self.Y_train[idx]] = 1

sorted_neigh_count = sorted(neigh_count.items(),key=operator.itemgetter(1), reverse=True)

print(str(count)+''+str(sorted_neigh_count[0][0]))

predictions.append(sorted_neigh_count[0][0])

return predictions

以上就是从零开始实现KNN的内容,现在,在处理过的数据集上测试一下这个模型吧!如果你是在Google Colob上做的——使用GPU运行速度会更快!

from sklearn.metrics importaccuracy_score

model = KNN(K = k) #experiment with different k values

model.fit(X_test, y_test)

pred = model.predict(X_test)

""" You can now test your model on different classificationmetrics! Good Luck!"""

留言点赞关注

我们一起分享AI学习与发展的干货

如转载,请后台留言,遵守转载规范

打开APP阅读更多精彩内容