全文共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学习与发展的干货
如转载,请后台留言,遵守转载规范