Veblen34's picture
Upload folder using huggingface_hub
cd6775d verified
Raw
History Blame Contribute Delete
4.82 kB
# Copyright (c) 2019-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
#
from logging import getLogger
import torch
from .transformer import TransformerModel
from ..data.dictionary import Dictionary, BOS_WORD, EOS_WORD, PAD_WORD, UNK_WORD, MASK_WORD
from ..utils import AttrDict
logger = getLogger()
class SentenceEmbedder(object):
@staticmethod
def reload(path, params):
"""
Create a sentence embedder from a pretrained model.
"""
# reload model
reloaded = torch.load(path)
state_dict = reloaded['model']
# handle models from multi-GPU checkpoints
if 'checkpoint' in path:
state_dict = {(k[7:] if k.startswith('module.') else k): v for k, v in state_dict.items()}
# reload dictionary and model parameters
dico = Dictionary(reloaded['dico_id2word'], reloaded['dico_word2id'], reloaded['dico_counts'])
pretrain_params = AttrDict(reloaded['params'])
pretrain_params.n_words = len(dico)
pretrain_params.bos_index = dico.index(BOS_WORD)
pretrain_params.eos_index = dico.index(EOS_WORD)
pretrain_params.pad_index = dico.index(PAD_WORD)
pretrain_params.unk_index = dico.index(UNK_WORD)
pretrain_params.mask_index = dico.index(MASK_WORD)
# build model and reload weights
model = TransformerModel(pretrain_params, dico, True, True)
model.load_state_dict(state_dict)
model.eval()
# adding missing parameters
params.max_batch_size = 0
return SentenceEmbedder(model, dico, pretrain_params)
def __init__(self, model, dico, pretrain_params):
"""
Wrapper on top of the different sentence embedders.
Returns sequence-wise or single-vector sentence representations.
"""
self.pretrain_params = {k: v for k, v in pretrain_params.__dict__.items()}
self.model = model
self.dico = dico
self.n_layers = model.n_layers
self.out_dim = model.dim
self.n_words = model.n_words
def train(self):
self.model.train()
def eval(self):
self.model.eval()
def cuda(self):
self.model.cuda()
def get_parameters(self, layer_range):
s = layer_range.split(':')
assert len(s) == 2
i, j = int(s[0].replace('_', '-')), int(s[1].replace('_', '-'))
# negative indexing
i = self.n_layers + i + 1 if i < 0 else i
j = self.n_layers + j + 1 if j < 0 else j
# sanity check
assert 0 <= i <= self.n_layers
assert 0 <= j <= self.n_layers
if i > j:
return []
parameters = []
# embeddings
if i == 0:
# embeddings
parameters += self.model.embeddings.parameters()
logger.info("Adding embedding parameters to optimizer")
# positional embeddings
if self.pretrain_params['sinusoidal_embeddings'] is False:
parameters += self.model.position_embeddings.parameters()
logger.info("Adding positional embedding parameters to optimizer")
# language embeddings
if hasattr(self.model, 'lang_embeddings'):
parameters += self.model.lang_embeddings.parameters()
logger.info("Adding language embedding parameters to optimizer")
parameters += self.model.layer_norm_emb.parameters()
# layers
for l in range(max(i - 1, 0), j):
parameters += self.model.attentions[l].parameters()
parameters += self.model.layer_norm1[l].parameters()
parameters += self.model.ffns[l].parameters()
parameters += self.model.layer_norm2[l].parameters()
logger.info("Adding layer-%s parameters to optimizer" % (l + 1))
logger.info("Optimizing on %i Transformer elements." % sum([p.nelement() for p in parameters]))
return parameters
def get_embeddings(self, x, lengths, positions=None, langs=None):
"""
Inputs:
`x` : LongTensor of shape (slen, bs)
`lengths` : LongTensor of shape (bs,)
Outputs:
`sent_emb` : FloatTensor of shape (bs, out_dim)
With out_dim == emb_dim
"""
slen, bs = x.size()
assert lengths.size(0) == bs and lengths.max().item() == slen
# get transformer last hidden layer
tensor = self.model('fwd', x=x, lengths=lengths, positions=positions, langs=langs, causal=False)
assert tensor.size() == (slen, bs, self.out_dim)
# single-vector sentence representation (first column of last layer)
return tensor[0]