MAML——模型无关元学习(reptile) & Pytorch实现
MAML, Model-Agnostic Meta-Learning, 模型无关元学习 MAML其实做的就是学一个更好的模型参数初始化 为什么说meta learning能达到怎样的效果,多么有用,但是最后只是落脚在了一个初始化上呢。因为你像预训练pretrain model,也就是一个初始化,如果初始化很好的话,那么模型可能不需要怎么学就能performance很高了 MAML中的不同任务,指的是例如都是分类任务,但是任务a是分类鸟牛马,而任务b是分类车船飞机,这就是MAML中的不同任务。也就是说,这里的所谓不同任务,其用的模型都是同一个,但是更新过后的参数可能梯度下降会往不同的方向走 MAML并不是一个深度学习模型,倒是更像一种训练技巧 meta-learning主要分为两个阶段 meta-train:用来训练模型参数,使得模型能够学到不同任务中的共同参数 meta-test:类似于fine-tuneing阶段,用来微调下游任务。 首先假设我们首先有数据集D,这个数据集有10个类别,每个类别有100个样本,共1000个样本数据集。 我们把数据集进行分割,把100个样本分成3份,比例是1:4:5。这三份的样本数量为10,40,50。 N-way K-shot:在meta-train阶段,假设实验中设置5-way 10-shot,也就是在每个任务task中抽样5个类别,每个类别10份数据,构成一个support set,用在meta-train阶段。这5个类别中,另外的40份数据为query set,可以用在meta-test阶段;而还剩10个类别的50份数据,用来进行微调任务。 MAML的种类 回归 分类 强化学习 不同点只在于loss函数的不同。 Pytorch代码 只是为了理解,实际使用还是要用官方的代码 代码中没有体现下游微调任务 这里为了能和输出结果过sigmoid匹配上,所以classes都是0.几的 import numpy as np classes = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] way = 5 shot = 10 def sample_points(k): c = np.random.choice(classes, size=way, replace=False) x = np.random.rand(k*way, 16) #16是每一个数据的自身的维度 y = np.random.choice(c, size=k*way).reshape([-1,1]) return x,y class MAML(object): def __init__(self): """ 定义参数,实验中用到10-way,10-shot """ # 共有10个任务 self.num_tasks = 10 # 每个任务的数据量:10-shot self.num_samples = shot # 训练的迭代次数 self.epochs = 20000 #lr self.alpha = 0.0001 # 外循环的学习率,用来更新meta模型的 heta self.beta = 0.0001 # meta模型初始化的参数 self.theta = np.random.normal(size=16).reshape(-1, 1) # sigmoid函数 def sigmoid(self,a): return 1.0 / (1 + np.exp(-a)) #now let us get to the interesting part i.e training :P def train(self): # 循环epoch次数 for e in range(self.epochs): self.theta_ = [] # meta-train # 利用support set for i in range(self.num_tasks): #每次循环都是一次新的任务 # 抽样k个样本出来,k-shot XTrain, YTrain = sample_points(self.num_samples) # 前馈神经网络 a = np.matmul(XTrain, self.theta) YHat = self.sigmoid(a) # 计算交叉熵loss loss = ((np.matmul(-YTrain.T, np.log(YHat)) - np.matmul((1 -YTrain.T), np.log(1 - YHat)))/self.num_samples)[0][0] # 梯度计算,更新每个任务的theta_,不需要更新meta模型的参数theta gradient = np.matmul(XTrain.T, (YHat - YTrain)) / self.num_samples self.theta_.append(self.theta - self.alpha*gradient) # 初始化meta模型的梯度 meta_gradient = np.zeros(self.theta.shape) # meta-test # 利用query set for i in range(self.num_tasks): # 在meta-test阶段,每个任务抽取40个样本出来进行 XTest, YTest = sample_points(40) # 前馈神经网络 a = np.matmul(XTest, self.theta_[i])#这里用的是刚才meta-train更新过的参数 YPred = self.sigmoid(a) # 这里需要叠加每个任务的loss meta_gradient += np.matmul(XTest.T, (YPred - YTest)) / self.num_samples # 更新meat模型的参数theta self.theta = self.theta - (self.beta * meta_gradient / self.num_tasks) if e % 1000==0: print("Epoch {}: Loss {} ".format(e,loss)) print(Updated Model Parameter Theta ) print(Sampling Next Batch of Tasks ) print(--------------------------------- ) if __name__ == __main__: x, y = sample_points(10) print(x[0]) print(y[0]) model = MAML() model.train() #self.meta是最终学得的值
reptile是MAML的变形