人类本身能够通过极少量的样本识别一个新物体,即使是一个小孩也能凭借动物图册上的几张小小的插画记住不同的动物。在人类的快速学习能力的启发下,研究人员希望机器学习模型在学习了一定类别的大量数据后,对于新的类别,只需要少量的样本就能快速学习,这就是 Few-shot Learning 要解决的问题。它可以用先验知识,从受监督的经验有限的新任务中,快速得出结论。可以给小样本学习这样定义:它是一种机器学习问题,经验E在任务T上有少量的监督信息的样本情况下来获得。典型的应用有字符生成,机器人技术(一键模仿,视觉导航,连续控制),药物发现,FSL翻译,冷启动项目推荐等等。另外,FSL还可以减少标签数据的收集和减少数据密集型应用的数据收集。比如:图像分类、图像检索、目标跟踪、手势识别、图像理解、视觉问题回答、视频时间检测、语言建模和神经结构搜索等等。
最初的 few-shot learning 研究领域主要集中在图像 领域,大致可分为三类:Mode Based、Metric Based 和 Optimization Based。
一、小样本学习概述
1、Model Based 方法
Model Based 方法旨在通过模型结构的设计快速在少量样本上更新参数,直接建立输入 x 和预测值 P 的映射函数;
Santoro 等人 [5] 提出使用记忆增强的方法来解决 Few-shot Learning 任务。基于记忆的神经网络方法早在 2001 年被证明可以用于 meta-learning。他们通过权重更新来调节 bias,并且通过学习将表达快速缓存到记忆中来调节输出。然而,利用循环神经网络的内部记忆单元无法扩展到需要对大量新信息进行编码的新任务上。因此,需要让存储在记忆中的表达既要稳定又要是元素粒度访问的,前者是说当需要时就能可靠地访问,后者是说可选择性地访问相关的信息;另外,参数数量不能被内存的大小束缚。神经图灵机(NTMs)和记忆网络就符合这种必要条件。
文章基于神经网络图灵机(NTMs)的思想,因为 NTMs 能通过外部存储(external memory)进行短时记忆,并能通过缓慢权值更新来进行长时记忆,NTMs 可以学习将表达存入记忆的策略,并如何用这些表达来进行预测。由此,文章方法可以快速准确地预测那些只出现过一次的数据[6]。
基于 LSTM 等 RNN 的模型,将数据看成序列来训练,在测试时输入新的类的样本进行分类。具体地,在当前时刻预测输入样本的类别,并在下一时刻给出真实的 label,并且添加了 external memory 存储上一次的 x 输入,这使得下一次输入后进行反向传播时,可以让 y( label)和 x 建立联系,使得之后的 x 能够通过外部记忆获取相关图像进行比对来实现更好的预测。
2、Metric Based 方法
Metric Based 方法通过度量 batch 集中的样本和 support 集中样本的距离,借助最近邻的思想完成分类[7];
Few-shot Learning 最大的问题就是过拟合。如果在 Few-shot Learning 的任务中去训练普通的基于 cross-entropy 的神经网络分类器,那么几乎肯定是会过拟合,因为神经网络分类器中有数以万计的参数需要优化。
相反,很多非参数化的方法(最近邻、K-NN、Kmeans)是不需要优化参数的,因此可以在 Meta-learning 的框架下构造一种可以端到端训练的 few-shot 分类器。该方法是对样本间距离分布进行建模,使得同类样本靠近,异类样本远离。
3、Optimization Based 方法
它认为普通的梯度下降方法难以在 few-shot 场景 下拟合,因此通过调整优化方法来完成小样本分类的任务 [8]。
上述方法是 Few-shot Learning 的一些初始应用,由于这个理论相对比较新,应用暂时集中在图像分类、图像识别、文本分类等领域,应用还比较窄,这些方法只是简单介绍,事实上后面还有许多进一步的优化和更复杂的网络构建。
二、Metric Based 方法 代码实现
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
from collections import Counter
from scipy import stats
import os
import faiss
import time
class FaissKNNImpl:
def __init__(self,k,faiss):
self.k = k # k nearest neighbor value
self.faiss = faiss # FAISS instance
self.index = 0
self.gpu_index_flat = 0
self.train_labels = []
self.test_label_faiss_output = []
def fitModel(self,train_features,train_labels):
self.train_labels = train_labels # 将train_labels赋值给self
num_dim = train_features.shape[1] # 获取数据的维度
self.index = self.faiss.IndexFlatL2(num_dim) # 为向量集构建IndexFlatL2索引,它是最简单的索引类型,只执行强力L2距离搜索
self.index.add(train_features) # add vectors to the index
def fitModel_GPU(self,train_features,train_labels):
no_of_gpus = self.faiss.get_num_gpus()
self.train_labels = train_labels
self.gpu_index_flat = self.index = self.faiss.IndexFlatL2(train_features.shape[1]) # build the index
if no_of_gpus > 0:
self.gpu_index_flat = self.faiss.index_cpu_to_all_gpus(self.index)
self.gpu_index_flat.add(train_features) # add vectors to the index
return no_of_gpus
def predict(self,test_features):
distance, test_features_faiss_Index = self.index.search(test_features, self.k)
self.test_label_faiss_output = stats.mode(self.train_labels[test_features_faiss_Index],axis=1)[0]
self.test_label_faiss_output = np.array(self.test_label_faiss_output.ravel())
#for test_index in range(0,test_features.shape[0]):
# self.test_label_faiss_output[test_index] = stats.mode(self.train_labels[test_features_faiss_Index[test_index]])[0][0] #Counter(self.train_labels[test_features_faiss_Index[test_index]]).most_common(1)[0][0]
return self.test_label_faiss_output
def predict_GPU(self,test_features):
distance, test_features_faiss_Index = self.gpu_index_flat.search(test_features, self.k)
self.test_label_faiss_output = stats.mode(self.train_labels[test_features_faiss_Index],axis=1)[0]
self.test_label_faiss_output = np.array(self.test_label_faiss_output.ravel())
return self.test_label_faiss_output
def getAccuracy(self,test_labels):
accuracy = (self.test_label_faiss_output == test_labels).mean()
accuracy = round(accuracy,2)
return accuracy
if __name__=="__main__":
data_dir = "raw"
raw_data_file = os.path.join(data_dir, "covtype.data.gz")
print("Reading raw data from {}".format(raw_data_file))
raw_data = np.loadtxt(raw_data_file, delimiter=',', dtype=int)
# 一、数据准备【Prepare Training and Test Data using 58k datapoints and 54 features】
# 原始数据的维度为:55维,其中最后一维是分类标签
np.random.seed(0)
np.random.shuffle(raw_data)
train_size = int(0.9 * raw_data.shape[0])
train_features = raw_data[:train_size, :-1].astype('float32')
train_labels = raw_data[:train_size, -1].astype('float32')
test_features = raw_data[train_size:, :-1].astype('float32')
test_labels = raw_data[train_size:, -1].astype('float32')
# 二、Train FAISS KNN model with k = 5, 10
k_list = [5, 10]
for k in k_list:
print("Training FAISS KNN model with k = {}".format(k))
start_time = time.time()
faissobj = FaissKNNImpl(k,faiss)
faissobj.fitModel_GPU(train_features,train_labels)
run_time = time.time() - start_time
print('time required for training %d data points at k = %d: %.2f seconds' % (train_features.shape[0], k , run_time))
start_time = time.time()
predictions = faissobj.predict_GPU(test_features)
run_time = time.time() - start_time
print('time required for predicting %d data point at k = %d: %.2f seconds【平均每条数据预测用时:%.2fμs】' % (test_features.shape[0], k, run_time, run_time*1000000/test_features.shape[0]))
accuracy = faissobj.getAccuracy(test_labels)
print('Accuracy for K = %d : %d' % (k, accuracy*100),'%')
from sklearn.metrics import classification_report
y_true = test_labels
y_pred = predictions
target_names = ['class 1', 'class 2', 'class 3','class 4', 'class 5', 'class 6','class 7']
print(classification_report(y_true, y_pred, target_names=target_names))
https://www.cnblogs.com/huadongw/p/17032810.html
Facebook: 亿级向量相似度检索库Faiss 原理+应用_kaiyuan_sjtu的博客-CSDN博客
软件测试 | 测试开发 | 高性能高维向量的KNN搜索方案_faiss 精确 knn 检索xingn_霍格沃兹-慕漓的博客-CSDN博客
相似向量检索库-Faiss-简介及原理_金色麦田~的博客-CSDN博客
在点云中构建KNN近邻图(使用faiss库实现GPU快速计算KNN)_点云knn_Tinet-的博客-CSDN博客
Faiss - Kmeans及KNN使用示例 - AI备忘录
https://towardsdatascience.com/make-knn-300-times-faster-than-scikit-learns-in-20-lines-5e29d74e76bb