元学习—关系网络pytorch实现

元学习—关系网络实现

原理部分已经在元学习—关系网络和匹配网络中讲述,这里不再赘述,实验包括了one-shot学习,few-shot(few=5)学习的两种学习过程。原始样本通过随机产生,类别一个有两个,损失函数使用的是均方误差的方式。具体的代码如下:

1 One-Shot学习

#encoding=utf-8
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import time
import random

def createData():
    '''
    随机创建两类数据,每一类数据的数量为10,维度为32
    :return:
    '''
    classA = torch.rand(size=[10,32])
    classB = torch.rand(size=[10,32])
    # 将两类数据进行按行拼接
    data = torch.cat([classA,classB],dim=0)
    # 分别给两类数据构造标签,其中A类数据集的标签为1,B类数据的标签为0
    labelA = torch.ones(10)
    labelB = torch.zeros(10)
    label = torch.cat([labelA,labelB])
    return data,label

def createSQ(data,label):
    '''
    :param data: 总体数据
    :param label:总体标签
    :return:
    '''
    indexA = random.randint(0,data.shape[0]/2-1)
    indexB = random.randint(data.shape[0]/2,data.shape[0]-1)
    A_data = data[indexA,:].reshape(1,-1)
    B_data = data[indexB,:].reshape(1,-1)
    support_set = torch.cat([A_data,B_data],dim=0)
    indexQ = random.randint(0,data.shape[0]-1)
    while indexQ == indexA or indexQ == indexB:
        indexQ = random.randint(0,data.shape[0]-1)
    query_set = data[indexQ,:]
    query_label = label[indexQ]
    return support_set,query_set,query_label

class RelationWork(nn.Module):
    def __init__(self,input_dim,hidden_dim,num_class):
        super(RelationWork, self).__init__()
        self.hidden_dim = hidden_dim
        self.input_dim = input_dim
        self.num_class = num_class
        self.weight = nn.Parameter(torch.zeros(size=[input_dim,hidden_dim]))
        nn.init.xavier_uniform_(self.weight.data,gain=1.414)
        self.bias = nn.Parameter(torch.zeros(hidden_dim))
        nn.init.uniform_(self.bias.data,a=0,b=1)

        # 下面,定义一个单层的神经网络来实现Z函数
        self.W = nn.Parameter(torch.zeros(size=[2 * hidden_dim,num_class]))
        nn.init.xavier_uniform_(self.W.data,gain=1.414)
        self.Bias = nn.Parameter(torch.zeros(num_class))
        nn.init.uniform_(self.Bias.data,a=0,b=1)


    def f(self,x):
        '''
        定义编码函数
        :param x: 需要编码的数据
        :return:  编码之后的结果
        '''
        embeddings = torch.matmul(x,self.weight) + self.bias
        embeddings = F.relu(embeddings)
        return embeddings
    def Z(self,x_i,x_j):
        '''
        :param x_i: Support Set中的编码数据
        :param x_j: Query Set中编码数据
        :return:
        '''
        rows = x_i.shape[0]
        x_j = x_j.repeat((rows,1))
        x = torch.cat([x_i,x_j],dim=1)
        result = torch.matmul(x,self.W) + self.Bias
        result = F.relu(result)
        return result
    def g(self,x):
        '''
        定义g函数,这里使用softmax函数 转换成score
        :param x: 通过Z计算出来的相关性结果
        :return: 当前样本属于各个分类的概率
        '''
        return F.softmax(x,dim=1)
    def forward(self,x_i,x_j):
        '''
        基本过程:
        1. 编码
        2. 相似性计算
        3. 转换成分值
        :param x_i: 支持集中的原始数据
        :param x_j: 查询集中的原始数据
        :return:
        '''
        fxi = self.f(x_i)
        fxj = self.f(x_j)
        similar = self.Z(fxi,fxj)
        return self.g(similar)

model = RelationWork(32,8,2)
optimer = optim.Adam(model.parameters(),lr=0.01)
loss = nn.MSELoss(reduction="sum")
data,label = createData()

def train(epoch,support_set,query_set,query_label):
    time.time()
    optimer.zero_grad()
    out = model(support_set,query_set)
    out = torch.max(out,dim=1).indices.reshape(-1,1)
    query_label = query_label.repeat(2,1)
    loss_train = loss(out,query_label)
    loss_train = loss_train.requires_grad_()
    loss_train.backward()
    optimer.step()
    print("Epoch: {:04d}".format(epoch+1),"loss_train: {:.4f}".format(loss_train.data.item()))
if __name__ == "__main__":
    for epoch in range(1000):
        support_set,query_set,query_label = createSQ(data,label)
        train(epoch,support_set,query_set,query_label)

2 few-shot

在few-shot中,需要生成各个类别的向量表示,然后在进行各个类别和查询样本的相似性计算。这里我们选择的类别向量的计算采用求和的方式进行计算。具体代码如下:

#encoding=utf-8
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import time
import random

def createData():
    '''
    随机创建两类数据,每一类数据的数量为10,维度为32
    :return:
    '''
    classA = torch.rand(size=[10,32])
    classB = torch.rand(size=[10,32])
    # 将两类数据进行按行拼接
    data = torch.cat([classA,classB],dim=0)
    # 分别给两类数据构造标签,其中A类数据集的标签为1,B类数据的标签为0
    labelA = torch.ones(10)
    labelB = torch.zeros(10)
    label = torch.cat([labelA,labelB])
    return data,label

def createFSQ(data,label):
    '''
    :param data: 总体数据
    :param label:总体标签
    :return:
    '''
    indexA = random.sample(list(range(data.shape[0]//2)),k=5)
    indexB = random.sample(list(range(data.shape[0]//2,data.shape[0])),k=5)
    A_data = data[indexA,:].reshape(5,-1)
    B_data = data[indexB,:].reshape(5,-1)
    support_set = torch.cat([A_data,B_data],dim=0)
    indexQ = random.randint(0,data.shape[0]-1)
    while indexQ in indexA or indexQ in indexB:
        indexQ = random.randint(0,data.shape[0]-1)
    query_set = data[indexQ,:]
    query_label = label[indexQ]
    return support_set,query_set,query_label



class RelationWork(nn.Module):
    def __init__(self,input_dim,hidden_dim,num_class):
        super(RelationWork, self).__init__()
        self.hidden_dim = hidden_dim
        self.input_dim = input_dim
        self.num_class = num_class
        self.weight = nn.Parameter(torch.zeros(size=[input_dim,hidden_dim]))
        nn.init.xavier_uniform_(self.weight.data,gain=1.414)
        self.bias = nn.Parameter(torch.zeros(hidden_dim))
        nn.init.uniform_(self.bias.data,a=0,b=1)

        # 下面,定义一个单层的神经网络来实现Z函数
        self.W = nn.Parameter(torch.zeros(size=[2 * hidden_dim,num_class]))
        nn.init.xavier_uniform_(self.W.data,gain=1.414)
        self.Bias = nn.Parameter(torch.zeros(num_class))
        nn.init.uniform_(self.Bias.data,a=0,b=1)


    def f(self,x):
        '''
        定义编码函数
        :param x: 需要编码的数据
        :return:  编码之后的结果
        '''
        embeddings = torch.matmul(x,self.weight) + self.bias
        embeddings = F.relu(embeddings)
        return embeddings
    def Z(self,x_i,x_j):
        '''
        :param x_i: Support Set中的编码数据
        :param x_j: Query Set中编码数据
        :return:
        '''
        rows = x_i.shape[0]
        x_j = x_j.repeat((rows,1))
        x = torch.cat([x_i,x_j],dim=1)
        result = torch.matmul(x,self.W) + self.Bias
        result = F.relu(result)
        return result
    def makeClassVector(self,inputs):
        '''
        生成类别的向量信息,前5个是A类,后五个是B类
        :param inputs: 支持集的编码结果
        :return:
        '''
        classA = inputs[:5,:]
        classB = inputs[5:,:]
        classA = torch.sum(classA,dim=0).reshape(1,-1)
        classB = torch.sum(classB,dim=0).reshape(1,-1)
        classAll = torch.cat([classA,classB],dim=0)

        return classAll


    def g(self,x):
        '''
        定义g函数,这里使用softmax函数 转换成score
        :param x: 通过Z计算出来的相关性结果
        :return: 当前样本属于各个分类的概率
        '''
        return F.softmax(x,dim=1)
    def forward(self,x_i,x_j):
        '''
        基本过程:
        1. 编码
        2. 相似性计算
        3. 转换成分值
        :param x_i: 支持集中的原始数据
        :param x_j: 查询集中的原始数据
        :return:
        '''
        fxi = self.f(x_i)
        fxj = self.f(x_j)
        classi = self.makeClassVector(fxi)
        similar = self.Z(classi,fxj)
        return self.g(similar)

model = RelationWork(32,8,2)
optimer = optim.Adam(model.parameters(),lr=0.01)
loss = nn.MSELoss(reduction="sum")
data,label = createData()

def train(epoch,support_set,query_set,query_label):
    time.time()
    optimer.zero_grad()
    out = model(support_set,query_set)
    out = torch.max(out,dim=1).indices.reshape(-1,1)
    query_label = query_label.repeat(2,1)
    loss_train = loss(out,query_label)
    loss_train = loss_train.requires_grad_()
    loss_train.backward()
    optimer.step()
    print("Epoch: {:04d}".format(epoch+1),"loss_train: {:.4f}".format(loss_train.data.item()))
if __name__ == "__main__":
    for epoch in range(1000):
        support_set,query_set,query_label = createFSQ(data,label)
        train(epoch,support_set,query_set,query_label)
    print(support_set.shape)
   

3 总结

上述可以进行改进的部分包括对于损失函数的选择,以及few-shot中对于类别向量生成方式的选择。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值