混合前端seq2seq模型部署

本文介绍了如何将基于PyTorch的seq2seq模型转换为适用于前端部署的混合Torch脚本。通过追踪和脚本化技术,将即时模式的模型转换为静态的Torch脚本,以优化模型并支持生产环境的部署。内容涵盖了编码器、解码器的实现,以及数据预处理和模型评估方法。
摘要由CSDN通过智能技术生成

混合前端seq2seq模型部署
本文介绍,如何将seq2seq模型转换为PyTorch可用的前端混合Torch脚本。要转换的模型来自于聊天机器人教程Chatbot tutorial。
1.混合前端
在一个基于深度学习项目的研发阶段, 使用像PyTorch这样即时eager、命令式的界面进行交互能带来很大便利。这使用户能够在使用Python数据结构、控制流操作、打印语句和调试实用程序时,通过熟悉的、惯用的Python脚本编写。
尽管即时性界面,对于研究和试验应用程序是一个有用的工具,但是对于生产环境中部署模型时,使用基于图形graph-based的模型表示将更加适用的。 一个延迟的图型展示,意味着可以优化,比如无序执行操作,以及针对高度优化的硬件架构的能力。 此外,基于图形的表示支持框架无关的模型导出。PyTorch提供了将即时模式的代码增量,转换为Torch脚本的机制,Torch脚本是一个在Python中的静态可分析和可优化的子集,Torch使用它来在Python运行时,独立进行深度学习。
在Torch中的torch.jit模块可以找到,将即时模式的PyTorch程序转换为Torch脚本的API。 这个模块有两个核心模式用于将即时模式模型转换为Torch脚本图形表示: 跟踪tracing 以及 脚本化scripting。
torch.jit.trace 函数接受一个模块或者一个函数和一组示例的输入,然后通过函数或模块运行输入示例,同时跟跟踪遇到的计算步骤,然后输出一个可以展示跟踪流程的基于图形的函数。跟踪Tracing对于不涉及依赖于数据的控制流的直接的模块和函数非常有用,就比如标准的卷积神经网络。
然而,如果一个有数据依赖的if语句和循环的函数被跟踪,则只记录示例输入沿执行路径调用的操作。换句话说,控制流本身并没有被捕获。要将带有数据依赖控制流的模块和函数进行转化,已提供了一个脚本化机制。脚本显式地将模块或函数代码转换为Torch脚本,包括所有可能的控制流路径。如需使用脚本模式script mode, 要确定继承了 torch.jit.ScriptModule基本类 (取代torch.nn.Module) ,并且增加 torch.jit.script 装饰器到你的Python函数或者 torch.jit.script_method 装饰器到你的模块方法。
使用脚本化的一个警告是,它只支持Python的一个受限子集。要获取与支持的特性相关的所有详细信息,参考 Torch Script language reference。为了达到最大的灵活性,可以组合Torch脚本的模式来表示整个程序,并且可以增量地应用这些技术。
在这里插入图片描述

2.预备环境
首先,导入所需的模块以及设置一些常量。如果想使用自己的模型,需要保证MAX_LENGTH常量设置正确。 提醒:这个常量定义了在训练过程中允许的最大句子长度,以及模型能够产生的最大句子长度输出。
source-python
from future import absolute_import
from future import division
from future import print_function
from future import unicode_literals

import torch
import torch.nn as nn
import torch.nn.functional as F
import re
import os
import unicodedata
import numpy as np

device = torch.device(“cpu”)

MAX_LENGTH = 10 # Maximum sentence length

默认的词向量

PAD_token = 0 # Used for padding short sentences
SOS_token = 1 # Start-of-sentence token
EOS_token = 2 # End-of-sentence token
3.模型概述
正如前文所言,使用的sequence-to-sequence (seq2seq) 模型。这种类型的模型用于输入,是可变长度序列的情况,输出也是一个可变长度序列,不一定是一对一输入映射。seq2seq 模型由两个递归神经网络(RNNs)组成:编码器 encoder和解码器decoder.
在这里插入图片描述

(1)编码器(Encoder)
编码器RNN在输入语句中每次迭代一个标记(例如单词),每次步骤输出一个“输出”向量和一个“隐藏状态”向量。”隐藏状态“向量在之后,则传递到下一个步骤,同时记录输出向量。编码器将序列中每个坐标代表的文本,转换为高维空间中的一组坐标,解码器将使用这些坐标,为给定的任务生成有意义的输出。
(2)解码器(Decoder)
解码器RNN以逐个令牌的方式生成响应语句。使用来自于编码器的文本向量和内部隐藏状态,来生成序列中的下一个单词。继续生成单词,直到输出表示句子结束的EOS语句。在解码器中使用专注机制attention mechanism,帮助在输入的某些部分生成输出时"保持专注"。对于的模型,实现了 Luong et al等人的“全局关注Global attention”模块,并将其作为解码模型中的子模块。
4.数据处理
尽管的模型在概念上处理标记序列,但在现实中,与所有机器学习模型一样处理数字。在这种情况下,在训练之前建立的模型词汇表中的每个单词都映射到一个整数索引。使用Voc对象来包含从单词到索引的映射,以及词汇表中的单词总数。将在运行模型之前加载对象。
此外,为了能够进行评估,必须提供一个处理字符串输入的工具。normalizeString函数将字符串中的所有字符转换为小写,并删除所有非字母字符。indexesFromSentence函数接受一个单词的句子,并返回相应的单词索引序列。
class Voc:
def init(self, name):
self.name = name
self.trimmed = False
self.word2index = {}
self.word2count = {}
self.index2word = {PAD_token: “PAD”, SOS_token: “SOS”, EOS_token: “EOS”}
self.num_words = 3 # 统计SOS, EOS, PAD

def addSentence(self, sentence):
    for word in sentence.split(' '):
        self.addWord(word)

def addWord(self, word):
    if word not in self.word2index:
        self.word2index[word] = self.num_words
        self.word2count[word] = 1
        self.index2word[self.num_words] = word
        self.num_words += 1
    else:
        self.word2count[word] += 1

# Remove words below a certain count threshold
def trim(self, min_count):
    if self.trimmed:
        return
    self.trimmed = True
    keep_words = []
    for k, v in self.word2count.items():
        if v >= min_count:
            keep_words.append(k)

    print('keep_words {} / {} = {:.4f}'.format(
        len(keep_words), len(self.word2index), len(keep_words) / len(self.word2index)
    ))
    # Reinitialize dictionaries
    self.word2index = {}
    self.word2count = {}
    self.index2word = {PAD_token: "PAD", SOS_token: "SOS", EOS_token: "EOS"}
    self.num_words = 3 # 统计默认的令牌
    for word in keep_words:
        self.addWord(word)

小写并删除非字母字符

def normalizeString(s):
s = s.lower()
s = re.sub(r"([.!?])", r" \1", s)
s = re.sub(r"[^a-zA-Z.!?]+", r" ", s)
return s

使用字符串句子,返回单词索引的句子

def indexesFromSentence(voc, sentence):
return [voc.word2index[word] for word in sentence.split(’ ')] + [EOS_token]
5.定义编码器
通过torch.nn.GRU模块实现编码器的RNN。本模块接受一批语句(嵌入单词的向量)的输入,它在内部遍历这些句子,每次一个标记,计算隐藏状态。将这个模块初始化为双向的,这意味着有两个独立的GRUs: 一个按时间顺序遍历序列,另一个按相反顺序遍历序列。 最终返回这两个GRUs输出和。由于模型是使用批处理进行训练的,所以,EncoderRNN模型的forward函数需要一个填充的输入批处理。为了批量处理可变长度的句子,通过MAX_LENGTH令牌允许一个句子中支持的最大长度,并且批处理中所有小于MAX_LENGTH 令牌的句子,都使用专用的PAD_token令牌填充在最后。要使用带有PyTorch RNN模块的批量填充,必须把转发forward密令,在调用torch.nn.utils.rnn.pack_padded_sequence和torch.nn.utils.rnn.pad_packed_sequence数据转换时进行打包。注意,forward 函数还接受一个input_length列表,其中包含批处理中每个句子的长度。该输入在填充时通过torch.nn.utils.rnn.pack_padded_sequence使用。
• 混合前端笔记 由于编码器的转发函数forward不包含任何依赖于数据的控制流,因此将使用跟踪tracing,转换为脚本模式script mode。在跟踪模块时, 可以保持模块定义不

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值