原型网络(Prototypical Networks) 完整流程讲解【附小样本电影分类代码】

这篇具有很好参考价值的文章主要介绍了原型网络(Prototypical Networks) 完整流程讲解【附小样本电影分类代码】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 基本介绍

1.1 本节引入

在之前的的文章中,我们介绍了关于连体网络的相关概念,并且给出了使用Pytorch实现的基于连体网络的人脸识别网络的小样本的学习过程。在接下来的内容中,我们来继续介绍另外一种小样本学习的神经网络结构——原型网络。这种网络的特点是拥有能够不仅仅应用在当前数据集的泛化分类能力。在接下来的内容中,我们将介绍以下几个内容:

  1. 原型网络的基本结构。
  2. 原型网络算法描述。
  3. 将原型网络应用于分类任务。

1.2 原型网络引入

相比于连体网络,原型网络是另外一种简单,高效的小样本的学习方式。与连体网络的学习目标类似。原型网络的目标也是学习到一个向量空间来实现文本分类任务。

原型网络的基本思路是对于每一个分类来创建一个原型表示(protoypicla representation)。并且对于一个需要分类的查询,采用计算分类的原型向量和查询点的距离来进行确定。

确定基本思路之后,下面从一个例子开始,对于原型网络进行具体描述。

2 原型网络

2.1 从一个例子开始

现在,我们拥有一个支持集(support set),内部包含狮子,大象,狗三个分类的图片。也就是说,对于分类任务,我们一共拥有三个分类:{狮子,大象,狗}。现在,我们需要对于每一个分类创建一个原型表示。建立的基本流程如下图所示:

  1. 首先,我们对于每一个样本使用编码的方式fφ (),学习到每一个样本的编码表示(信息抽取)。举个例子,我们可以使用卷积操作来实现对于图片编码信息的抽取。
    prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉
  2. 在学习到每一个样本的编码表示之后,我们对于每一个分类下的所有的样本编码进行求和求取平均的操作,将结果作为分类的原型表示。因此,一个分类的原型表示使用向量求和求平均的过程过程进行表示。
    prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉

当一个新的数据样本被输入到网络中的时候,我们需要的是对于这个样本预测出其分类情况。
3. 第一步,我对于这个新的数据样本使用 fφ(),生成其编码表示。如下图所示:
prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉
4. 接下来,我们需要做的就是计算新的样本的编码表示和每一个分类的原型表示之间的距离情况,通过最下距离来确定查询样本属于哪一个分类。对于距离计算,并没有特殊的要求,可以使用欧式距离或者Cos相似度等等计算方式。
prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉

  1. 最后在计算出所有的分类之间的距离之后,我们使用softmax的方式将距离转换成概率的形式。我们有三个分类,那么对于样本在softmax之后,获取到的就是对于这三个分类的距离情况。

在本节的最后,我们回到我们的学习过程,我们希望的是网络从小样本的数据集中进行学习。所以我们在训练的时候,我们对于每一个分类随机的生成少量的样本,我们成这些少量的样本集合为支持集,在整个的训练过程,我们只需要使用到支持集即可。而不需要所有的数据集。同理,我们随机的从数据集中抽取一个样本作为查询点并且对其进行分类的预测。这样就完成了我们从小样本学习的方式。

2.2 原型网络的整体架构

首先,我们给出原型网络的整体架构图:

prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉

我们从整体的架构上来分析一下这种网络结构:

  1. 第一步,我们对于支持集中的每一个样本点生成一个编码表示,通过通过求和平均的方式来生成每一个分类的原型表示。同时,对于我们的查询样本,我们也对其生成一个向量表示
  2. 同时,我们需要计算每一个查询点和每一个分类原型表示的距离情况。并计算softmax概率结果。生成对于各个分类的概率分布情况。

进一步,对于原型网络而言,其应用的范围不仅仅在单样本/小样本的学习过程中,同时还可以应用在零样本的学习方式。对于这种应用的思路是:尽管我们没有当前分类的数据样本,但是如果能够在更高的层次中生成分类的原型表示(元信息)。通过这种元信息,我们也可以完成和上面类似的计算,完成我们的分类任务。

2.3 算法描述

这里我们结合网络结构和数学公式来对原型网络进行算法描述:

  1. 假设我们当前的数据集为D,其内部的样本的表示形式为{ (x_1,y_1),(x_2,y_2),....,(x_n,y_n)},其中x表示的向量表示,y表示分类分类标签。
  2. 对于每一个分类,我们随机的从总的样本集中为其生成n个样本点,对于每一个分类,我们生成最后支持集为S。
  3. 同理,我们随机的从总的样本集中为每一个分类选择n个样本点来生成查询集Q。
  4. 对于支持集内部的样本点,使用编码公式fφ 来为每一个分类生成一个原型表示,这里的编码公式fφ 可以是任意的一种信息抽取的方式。例如CNN,LSTM等等。
  5. 对于每一个分类,我们生成其原型表示为 :

prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉

  1. 类似的是,我们对于查询集也生成查询集的编码。
  2. 进一步,我们需要计算的是查询集和支持集的原型表示的距离情况。
  3. 最后,需要计算的是当前样本属于每一个分类的概率 pw(y=k|x),这里使用softmax的计算方式:

prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉
9. 最终,我们计算损失函数为

prototypical networks,# NLP/文本分类,深度学习,机器学习,计算机视觉

2.4 代码描述

这里,我们选择自定义了一个简单的评论数据集,一共两个分类,每一个分类下面有5个数据,每个分类我们选择3个作为支持集,3个作为查询集,其具体的实现如下:

#encoding=utf-8

import torch
import torch.nn as nn
import torch.nn.functional as F
import jieba
import random
import torch.optim as optim


def createData():
    text_list_pos = ["电影内容很好","电影题材很好","演员演技很好","故事很感人","电影特效很好"]
    text_list_neg = ["电影内容垃圾","电影是真的垃圾","表演太僵硬了","故事又臭又长","电影太让人失望了"]
    test_pos = ["电影","很","好"]
    test_neg = ["电影","垃圾"]
    words_pos = [[item for item in jieba.cut(text)] for text in text_list_pos]  # [['电影', '内容', '很', '好'], ['电影', '题材', '很', '好'], ['演员', '演技', '很', '好'], ['故事', '很', '感人'], ['电影', '特效', '很', '好']]
    words_neg = [[item for item in jieba.cut(text)] for text in text_list_neg]  # [['电影', '内容', '垃圾'], ['电影', '是', '真的', '垃圾'], ['表演', '太', '僵硬', '了'], ['故事', '又臭又长'], ['电影', '太', '让', '人', '失望', '了']]
    words_all = []
    for item in words_pos:
        for key in item:
            words_all.append(key)
    for item in words_neg:
        for key in item:
            words_all.append(key)
    vocab = list(set(words_all))    # ['太', '故事', '垃圾', '失望', '又臭又长', '表演', '很', '内容', '题材', '让', '僵硬', '感人', '演员', '演技', '了', '真的', '特效', '好', '是', '电影', '人']
    print(vocab)
    word2idx = {w:c for c,w in enumerate(vocab)}    # {'太': 0, '故事': 1, '垃圾': 2, '失望': 3, '又臭又长': 4, '表演': 5, '很': 6, '内容': 7, '题材': 8, '让': 9, '僵硬': 10, '感人': 11, '演员': 12, '演技': 13, ...}
    idx_words_pos = [[word2idx[item] for item in text] for text in words_pos]   # [[19, 7, 6, 17], [19, 8, 6, 17], [12, 13, 6, 17], [1, 6, 11], [19, 16, 6, 17]]
    idx_words_neg = [[word2idx[item] for item in text] for text in words_neg]   # [[19, 7, 2], [19, 18, 15, 2], [5, 0, 10, 14], [1, 4], [19, 0, 9, 20, 3, 14]]
    idx_test_pos = [word2idx[item] for item in test_pos]    # [19, 6, 17]
    idx_test_neg = [word2idx[item] for item in test_neg]    # [19, 2]

    return vocab,word2idx,idx_words_pos,idx_words_neg,idx_test_pos,idx_test_neg


def createOneHot(vocab,idx_words_pos,idx_words_neg,idx_test_pos,idx_test_neg):
    input_dim = len(vocab)  # 21
    features_pos = torch.zeros(size=[len(idx_words_pos),input_dim]) # torch.Size([5, 21])
    features_neg = torch.zeros(size=[len(idx_words_neg), input_dim])    # torch.Size([5, 21])
    for i in range(len(idx_words_pos)):
        for j in idx_words_pos[i]:
            features_pos[i,j] = 1.0

    for i in range(len(idx_words_neg)):
        for j in idx_words_neg[i]:
            features_neg[i,j] = 1.0
    features = torch.cat([features_pos,features_neg],dim=0) # torch.Size([10, 21])
    labels = [1,1,1,1,1,0,0,0,0,0]
    labels = torch.LongTensor(labels)   # tensor([1, 1, 1, 1, 1, 0, 0, 0, 0, 0])
    test_x_pos = torch.zeros(size=[1,input_dim])    # torch.Size([1, 21])
    test_x_neg = torch.zeros(size=[1,input_dim])    # torch.Size([1, 21])
    for item in idx_test_pos:
        test_x_pos[0,item] = 1.0
    for item in idx_test_neg:
        test_x_neg[0,item] = 1.0
    test_x = torch.cat([test_x_pos,test_x_neg],dim=0)   # torch.Size([2, 21])
    test_labels = torch.LongTensor([1,0])
    return features,labels,test_x,test_labels

def randomGenerate(features):   # torch.Size([10, 21])
    N = features.shape[0]   # 10
    half_n = N // 2 # 5
    support_input = torch.zeros(size=[6, features.shape[1]])    # torch.Size([6, 21])
    query_input = torch.zeros(size=[4,features.shape[1]])   # torch.Size([4, 21])
    postive_list = list(range(0,half_n))    # [0, 1, 2, 3, 4]
    negtive_list = list(range(half_n,N))    # [5, 6, 7, 8, 9]
    support_list_pos = random.sample(postive_list,3)    # [0, 2, 4]
    support_list_neg = random.sample(negtive_list,3)    # [5, 7, 8]
    query_list_pos = [item for item in postive_list if item not in support_list_pos]    # [1, 3]
    query_list_neg = [item for item in negtive_list if item not in support_list_neg]    # [6, 9]
    index = 0
    for item in support_list_pos:
        support_input[index,:] = features[item,:]
        index += 1
    for item in support_list_neg:
        support_input[index,:] = features[item,:]
        index += 1
    index = 0
    for item in query_list_pos:
        query_input[index,:] = features[item,:]
        index += 1
    for item in query_list_neg:
        query_input[index,:] = features[item,:]
        index += 1
        
    query_label = torch.LongTensor([1,1,0,0])

    return support_input,query_input,query_label



class fewModel(nn.Module):
    def __init__(self,input_dim,hidden_dim,num_class):
        super(fewModel,self).__init__()
        self.input_dim = input_dim  # 21
        self.hidden_dim = hidden_dim    # 4
        self.num_class = num_class  # 2
        # 线性层进行编码
        self.linear = nn.Linear(input_dim,hidden_dim)


    def embedding(self,features):
        result = self.linear(features)
        return result

    def forward(self,support_input,query_input):

        support_embedding = self.embedding(support_input)   # torch.Size([6, 4])
        query_embedding = self.embedding(query_input)   # torch.Size([4, 4])
        support_size = support_embedding.shape[0]   # 6
        every_class_num  = support_size // self.num_class   # 3
        class_meta_dict = {}    # 存放每一个类别的所有支持集样本Embedding的平均值 {0: tensor([-0.1464, -0.2873, -0.1670,  0.3826], grad_fn=<DivBackward0>), 1: tensor([-0.0235, -0.2609, -0.1084,  0.0402], grad_fn=<DivBackward0>)}
        for i in range(0,self.num_class):
            class_meta_dict[i] = torch.sum(support_embedding[i*every_class_num:(i+1)*every_class_num,:],dim=0) / every_class_num
        class_meta_information = torch.zeros(size=[len(class_meta_dict),support_embedding.shape[1]])    # tensor([[-0.1464, -0.2873, -0.1670,  0.3826], [-0.0235, -0.2609, -0.1084,  0.0402]], grad_fn=<CopySlices>)
        for key,item in class_meta_dict.items():
            class_meta_information[key,:] = class_meta_dict[key]
        N_query = query_embedding.shape[0]  # 4
        result = torch.zeros(size=[N_query,self.num_class])
        for i in range(0,N_query):
            temp_value = query_embedding[i].repeat(self.num_class,1)    # tensor([[ 0.0120, -0.3115, -0.1872,  0.3385], [ 0.0120, -0.3115, -0.1872,  0.3385]], grad_fn=<RepeatBackward0>)
            cosine_value = torch.cosine_similarity(class_meta_information,temp_value,dim=1) # tensor([0.9483, 0.8077], grad_fn=<SumBackward1>)
            result[i] = cosine_value
        result = F.log_softmax(result,dim=1)    # tensor([[-0.6253, -0.7659], [-0.7211, -0.6660], [-0.5841, -0.8156], [-0.7082, -0.6783]], grad_fn=<LogSoftmaxBackward0>)
        return result


def train(epoch,support_input,query_input,query_label):
    optimer.zero_grad()
    output = model(support_input,query_input)   # tensor([[-0.6253, -0.7659], [-0.7211, -0.6660], [-0.5841, -0.8156], [-0.7082, -0.6783]], grad_fn=<LogSoftmaxBackward0>)
    loss = F.nll_loss(output,query_label)   # tensor([[-0.6253, -0.7659], [-0.7211, -0.6660], [-0.5841, -0.8156], [-0.7082, -0.6783]], grad_fn=<LogSoftmaxBackward0>)    tensor([1, 1, 0, 0])
    loss.backward()
    optimer.step()
    print("Epoch: {:04d}".format(epoch),"loss:{:.4f}".format(loss))

if __name__ == '__main__':
    hidden_dim = 4
    n_class = 2
    lr = 0.01
    epochs = 1000
    vocab,word2idx,idx_words_pos,idx_words_neg,idx_test_pos,idx_test_neg = createData()
    features,labels,test_x,test_labels = createOneHot(vocab,idx_words_pos,idx_words_neg,idx_test_pos,idx_test_neg)

    model = fewModel(features.shape[1],hidden_dim,n_class)
    optimer = optim.Adam(model.parameters(),lr=lr,weight_decay=5e-4)

    for i in range(epochs):
        support_input, query_input, query_label = randomGenerate(features)
        train(i,support_input,query_input,query_label)

 原型网络(Prototypical Networks) 完整流程讲解_原型网络代码讲解_root-cause的博客-CSDN博客

【Pytorch】prototypical network原型网络小样本图像分类简述及其实现_原型网络 pytorch_Jnchin的博客-CSDN博客

学习笔记--原型网络(Prototypical Network) - 知乎文章来源地址https://www.toymoban.com/news/detail-766702.html

到了这里,关于原型网络(Prototypical Networks) 完整流程讲解【附小样本电影分类代码】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 机器学习15:神经网络-Neural Networks

    神经网络是特征交叉的更复杂版本。本质上,神经网络会学习适当的特征组合。本文主要介绍神经网络的结构、隐藏层、激活函数等内容。 目录 1.神经网络:结构 2.隐藏层 3.激活函数 3.1 常用激活函数 3.2 小结 4.

    2024年02月12日
    浏览(37)
  • 神经网络:表述(Neural Networks: Representation)

    无论是线性回归还是逻辑回归,当特征太多时,计算的负荷会非常大。 案例: 假设我们有非常多的特征,例如大于 100 个变量,我们希望用这 100 个特征来构建一个非线性的多项式模型,结果将是数量非常惊人的特征组合,即便我们只采用两两特征的组合(𝑥1𝑥2 +𝑥1𝑥3

    2024年01月24日
    浏览(38)
  • 递归神经网络(Recursive Neural Networks)

    递归神经网络(Recursive Neural Networks)是一种特殊的神经网络,它们通过处理具有树形结构的数据来捕获数据的深层次关系,尤其是在自然语言处理和计算机视觉中的一些应用,如语法分析和场景理解。 1. 理解基本概念和背景 区别于循环神经网络 :首先,清楚递归神经网络(

    2024年04月13日
    浏览(35)
  • 生成对抗网络 – Generative Adversarial Networks | GAN

    目录 生成对抗网络 GAN 的基本原理 非大白话版本 第一阶段:固定「判别器D」,训练「生成器G」

    2024年04月15日
    浏览(45)
  • 28_计算机网络(Computer Networks)基础

    本篇介绍计算机网络的基础知识。 第一个计算机网络出现在1950~1960年代,通常在公司或研究室内部使用,为了方便信息交换,比把纸卡或磁带送到另一栋楼里更快速可靠,这叫 \\\"球鞋网络\\\" 第二个好处是能共享物理资源,举个例子,与其每台电脑配一台打印机,大家可以共享

    2024年02月14日
    浏览(33)
  • 神经网络的学习(Neural Networks: Learning)

    案例:假设神经网络的训练样本有𝑚个,每个包含一组输入𝑥和一组输出信号𝑦,𝐿表示神经网络层数,𝑆𝐼表示每层的 neuron 个数(𝑆𝑙表示输出层神经元个数),𝑆𝐿代表最后一层中处理单元的个数。 将神经网络的分类定义为两种情况:二类分类和多类分类, 二类分

    2024年01月24日
    浏览(39)
  • 【C++】运算符重载 ⑩ ( 下标 [] 运算符重载 | 函数原型 int& operator[](int i) | 完整代码示例 )

    在之前的博客 【C++】面向对象示例 - 数组类 ( 示例需求 | 创建封装类 | 数组类头文件 Array.h | 数组类实现 Array.cpp | 测试类 Test.cpp - 主函数入口 ) 中 , 实现了一个数组类 , 在一个类中 , 封装了一个 int 类型的指针 , 该指针指向堆内存的 内存空间 , 用于存放一个数组 ; 核心是 2

    2024年02月07日
    浏览(36)
  • 深度学习7:生成对抗网络 – Generative Adversarial Networks | GAN

    生成对抗网络 – GAN 是最近2年很热门的一种无监督算法,他能生成出非常逼真的照片,图像甚至视频。我们手机里的照片处理软件中就会使用到它。 目录 生成对抗网络 GAN 的基本原理 大白话版本 非大白话版本 第一阶段:固定「判别器D」,训练「生成器G」 第二阶段:固定

    2024年02月11日
    浏览(57)
  • 【设计模式——学习笔记】23种设计模式——原型模式Prototype(原理讲解+应用场景介绍+案例介绍+Java代码实现)

    原型模式指用通过拷贝原型实例创建新的实例,新实例和原型实例的属性完全一致 原型模式是一种创建型设计模式 工作原理是通过调用原型实例的 clone() 方法来完成克隆,原型实例需要实现Cloneable接口,并重写 clone() 方法 需要为每个类开发一个克隆方法,这对全新的类来说

    2024年02月16日
    浏览(52)
  • 物理信息神经网络PINNs : Physics Informed Neural Networks 详解

    本博客主要分为两部分: 1、PINN模型论文解读 2、PINN模型相关总结 基于物理信息的神经网络(Physics-informed Neural Network, 简称PINN),是一类用于解决有监督学习任务的神经网络,同时尊重由一般非线性偏微分方程描述的任何给定的物理规律。 原理 :它不仅能够像传统神经网

    2024年02月02日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包