mirror of
https://github.com/storytold/storyteller-ml.git
synced 2026-10-23 08:26:06 +00:00
Introduce code from Rust monorepo. This is a mess
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
name: AttentionIsAllYouNeed
|
||||
do_training: True # set to False if only preprocessing data
|
||||
do_testing: False # set to True to run evaluation on test data after training
|
||||
|
||||
model:
|
||||
beam_size: 4
|
||||
len_pen: 0.6
|
||||
multilingual: False
|
||||
max_generation_delta: 5
|
||||
label_smoothing: 0.1
|
||||
shared_tokenizer: True # train tokenizer model across src and tgt train data
|
||||
preproc_out_dir: null # path to store data preprocessing outputs
|
||||
src_language: 'en'
|
||||
tgt_language: 'de'
|
||||
|
||||
train_ds:
|
||||
src_file_name: null
|
||||
tgt_file_name: null
|
||||
use_tarred_dataset: False # if true tar_file_name and meta_file_name will be used (or created automatically)
|
||||
# config for preprocessing training data and creating a tarred datset automatically
|
||||
tar_file_prefix: parallel # prefix for tar file names
|
||||
tar_files: null # if data has already been preprocessed (rest of config ignored)
|
||||
metadata_file: null # metadata for tarred dataset
|
||||
lines_per_dataset_fragment: 1000000 # Number of lines to consider for bucketing and padding
|
||||
num_batches_per_tarfile: 100 # Number of batches (pickle files) within each tarfile
|
||||
tar_shuffle_n: 100 # How many samples to look ahead and load to be shuffled
|
||||
shard_strategy: scatter # tarred dataset shard distribution strategy
|
||||
n_preproc_jobs: -2 # number of processes to use for data preprocessing (-2 means all but 2)
|
||||
tokens_in_batch: 512
|
||||
clean: true
|
||||
max_seq_length: 512
|
||||
shuffle: true
|
||||
num_samples: -1
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
num_workers: 8
|
||||
concat_sampling_technique: temperature # only used with ConcatTranslationDataset
|
||||
concat_sampling_temperature: 5 # only used with ConcatTranslationDataset
|
||||
concat_sampling_probabilities: null # only used with ConcatTranslationDataset
|
||||
|
||||
validation_ds:
|
||||
src_file_name: ???
|
||||
tgt_file_name: ???
|
||||
tokens_in_batch: 512
|
||||
clean: false
|
||||
max_seq_length: 512
|
||||
shuffle: false
|
||||
num_samples: -1
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
num_workers: 8
|
||||
|
||||
test_ds:
|
||||
src_file_name: ???
|
||||
tgt_file_name: ???
|
||||
tokens_in_batch: 512
|
||||
clean: false
|
||||
max_seq_length: 512
|
||||
shuffle: false
|
||||
num_samples: -1
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
num_workers: 8
|
||||
|
||||
optim:
|
||||
name: adam
|
||||
lr: 0.001
|
||||
betas:
|
||||
- 0.9
|
||||
- 0.98
|
||||
weight_decay: 0.0
|
||||
sched:
|
||||
name: InverseSquareRootAnnealing
|
||||
min_lr: 0.0
|
||||
last_epoch: -1
|
||||
warmup_ratio: 0.1
|
||||
|
||||
encoder_tokenizer:
|
||||
library: yttm
|
||||
tokenizer_model: null
|
||||
vocab_size: null # vocab size for training bpe
|
||||
bpe_dropout: null
|
||||
vocab_file: null
|
||||
special_tokens: null
|
||||
training_sample_size: null # valid for sentencepiece tokenizer
|
||||
|
||||
decoder_tokenizer:
|
||||
library: yttm
|
||||
tokenizer_model: null
|
||||
vocab_size: null # vocab size for training bpe
|
||||
bpe_dropout: null
|
||||
vocab_file: null
|
||||
special_tokens: null
|
||||
training_sample_size: null # valid for sentencepiece tokenizer
|
||||
|
||||
encoder:
|
||||
library: nemo
|
||||
model_name: null
|
||||
pretrained: false
|
||||
max_sequence_length: 512
|
||||
num_token_types: 0
|
||||
embedding_dropout: 0.1
|
||||
learn_positional_encodings: false
|
||||
hidden_size: 512
|
||||
num_layers: 6
|
||||
inner_size: 2048
|
||||
num_attention_heads: 8
|
||||
ffn_dropout: 0.1
|
||||
attn_score_dropout: 0.1
|
||||
attn_layer_dropout: 0.1
|
||||
hidden_act: relu
|
||||
mask_future: false
|
||||
pre_ln: false
|
||||
pre_ln_final_layer_norm: true
|
||||
|
||||
decoder:
|
||||
library: nemo
|
||||
model_name: null
|
||||
pretrained: false
|
||||
max_sequence_length: 512
|
||||
num_token_types: 0
|
||||
embedding_dropout: 0.1
|
||||
learn_positional_encodings: false
|
||||
hidden_size: 512
|
||||
inner_size: 2048
|
||||
num_layers: 6
|
||||
num_attention_heads: 8
|
||||
ffn_dropout: 0.1
|
||||
attn_score_dropout: 0.1
|
||||
attn_layer_dropout: 0.1
|
||||
hidden_act: relu
|
||||
pre_ln: false
|
||||
pre_ln_final_layer_norm: true
|
||||
|
||||
head:
|
||||
num_layers: 1
|
||||
activation: relu
|
||||
log_softmax: true
|
||||
dropout: 0.0
|
||||
use_transformer_init: true
|
||||
|
||||
trainer:
|
||||
gpus: 4
|
||||
num_nodes: 1
|
||||
max_epochs: 200
|
||||
amp_level: O2 # O1/O2 for mixed precision
|
||||
precision: 16 # Should be set to 16 for O1 and O2, default is 16 as PT ignores it when am_level is O0
|
||||
accelerator: ddp
|
||||
checkpoint_callback: False
|
||||
logger: False
|
||||
log_every_n_steps: 50 # Interval of logging.
|
||||
check_val_every_n_epoch: 1
|
||||
|
||||
exp_manager:
|
||||
name: AAYNBase
|
||||
files_to_copy: []
|
||||
@@ -0,0 +1,132 @@
|
||||
name: HuggingFaceEncoder
|
||||
do_training: True # set to False if only preprocessing data
|
||||
do_testing: False # set to True to run evaluation on test data after training
|
||||
|
||||
model:
|
||||
beam_size: 4
|
||||
len_pen: 0.6
|
||||
max_generation_delta: 5
|
||||
label_smoothing: 0.1
|
||||
shared_tokenizer: false
|
||||
preproc_out_dir: null
|
||||
src_language: 'en'
|
||||
tgt_language: 'de'
|
||||
|
||||
train_ds:
|
||||
src_file_name: null
|
||||
tgt_file_name: null
|
||||
use_tarred_dataset: False # if true tar_file_name and meta_file_name will be used (or created automatically)
|
||||
# config for preprocessing training data and creating a tarred datset automatically
|
||||
tar_file_prefix: parallel # prefix for tar file names
|
||||
tar_files: null # if data has already been preprocessed (rest of config ignored)
|
||||
metadata_file: null # metadata for tarred dataset
|
||||
lines_per_dataset_fragment: 1000000 # Number of lines to consider for bucketing and padding
|
||||
num_batches_per_tarfile: 100 # Number of batches (pickle files) within each tarfile
|
||||
tar_shuffle_n: 100 # How many samples to look ahead and load to be shuffled
|
||||
shard_strategy: scatter # tarred dataset shard distribution strategy
|
||||
n_preproc_jobs: -2 # number of processes to use for data preprocessing (-2 means all but 2)
|
||||
tokens_in_batch: 512
|
||||
clean: true
|
||||
max_seq_length: 512
|
||||
shuffle: true
|
||||
num_samples: -1
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
num_workers: 8
|
||||
|
||||
validation_ds:
|
||||
src_file_name: null
|
||||
tgt_file_name: null
|
||||
tokens_in_batch: 512
|
||||
clean: false
|
||||
max_seq_length: 512
|
||||
shuffle: false
|
||||
num_samples: -1
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
num_workers: 8
|
||||
|
||||
test_ds:
|
||||
src_file_name: null
|
||||
tgt_file_name: null
|
||||
tokens_in_batch: 512
|
||||
clean: false
|
||||
max_seq_length: 512
|
||||
shuffle: false
|
||||
num_samples: -1
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
num_workers: 8
|
||||
|
||||
optim:
|
||||
name: adam
|
||||
lr: 0.001
|
||||
betas:
|
||||
- 0.9
|
||||
- 0.98
|
||||
weight_decay: 0.0
|
||||
sched:
|
||||
name: InverseSquareRootAnnealing
|
||||
min_lr: 0.0
|
||||
last_epoch: -1
|
||||
warmup_ratio: 0.1
|
||||
|
||||
encoder_tokenizer:
|
||||
library: huggingface
|
||||
tokenizer_model: null
|
||||
vocab_file: null
|
||||
special_tokens: null
|
||||
vocab_size: null
|
||||
|
||||
decoder_tokenizer:
|
||||
library: yttm
|
||||
tokenizer_model: null
|
||||
vocab_file: null
|
||||
special_tokens: null
|
||||
vocab_size: null
|
||||
|
||||
encoder:
|
||||
library: huggingface
|
||||
model_name: bert-base-uncased
|
||||
pretrained: false
|
||||
|
||||
decoder:
|
||||
library: nemo
|
||||
model_name: null
|
||||
pretrained: false
|
||||
max_sequence_length: 512
|
||||
num_token_types: 2
|
||||
embedding_dropout: 0.1
|
||||
learn_positional_encodings: false
|
||||
hidden_size: 512
|
||||
inner_size: 2048
|
||||
num_layers: 6
|
||||
num_attention_heads: 8
|
||||
ffn_dropout: 0.1
|
||||
attn_score_dropout: 0.1
|
||||
attn_layer_dropout: 0.1
|
||||
hidden_act: relu
|
||||
pre_ln: false
|
||||
|
||||
head:
|
||||
num_layers: 1
|
||||
activation: relu
|
||||
log_softmax: true
|
||||
dropout: 0.0
|
||||
use_transformer_init: true
|
||||
|
||||
trainer:
|
||||
gpus: 4
|
||||
num_nodes: 1
|
||||
max_epochs: 200
|
||||
amp_level: O2 # O1/O2 for mixed precision
|
||||
precision: 16 # Should be set to 16 for O1 and O2, default is 16 as PT ignores it when am_level is O0
|
||||
accelerator: ddp
|
||||
checkpoint_callback: False
|
||||
logger: False
|
||||
log_every_n_steps: 50 # Interval of logging.
|
||||
check_val_every_n_epoch: 1
|
||||
|
||||
exp_manager:
|
||||
name: HuggingFaceEncoder
|
||||
files_to_copy: []
|
||||
@@ -0,0 +1,68 @@
|
||||
# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
from nemo.collections.nlp.data.machine_translation.preproc_mt_data import MTDataPreproc
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='NMT dataset pre-processing')
|
||||
parser.add_argument('--tokenizer_model', type=str, required=True, help='Path to tokenizer model')
|
||||
parser.add_argument('--tokenizer_name', type=str, default='yttm', help='BPE Tokenizer Name, Options: [yttm]')
|
||||
parser.add_argument('--bpe_droput', type=float, default=0.0, help='BPE dropout to use')
|
||||
parser.add_argument('--clean', action="store_true", help='Whether to clean dataset based on length diff')
|
||||
parser.add_argument('--pkl_file_prefix', type=str, default='parallel', help='Prefix for tar and pickle files')
|
||||
parser.add_argument('--fname', type=str, required=True, help='Path to monolingual data file')
|
||||
parser.add_argument('--out_dir', type=str, required=True, help='Path to store dataloader and tokenizer models')
|
||||
parser.add_argument('--max_seq_length', type=int, default=512, help='Max Sequence Length')
|
||||
parser.add_argument('--min_seq_length', type=int, default=1, help='Min Sequence Length')
|
||||
parser.add_argument('--tokens_in_batch', type=int, default=16000, help='# Tokens per batch per GPU')
|
||||
parser.add_argument(
|
||||
'--lines_per_dataset_fragment',
|
||||
type=int,
|
||||
default=1000000,
|
||||
help='Number of lines to consider for bucketing and padding',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--num_batches_per_tarfile',
|
||||
type=int,
|
||||
default=1000,
|
||||
help='Number of batches (pickle files) within each tarfile',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
if not os.path.exists(args.out_dir):
|
||||
os.mkdir(args.out_dir)
|
||||
if not os.path.exists(args.tokenizer_model):
|
||||
assert FileNotFoundError("Could not find tokenizer model %s" % (args.tokenizer))
|
||||
|
||||
tokenizer_model = MTDataPreproc.get_monolingual_tokenizer(
|
||||
tokenizer_name=args.tokenizer_name, tokenizer_model=args.tokenizer_model, bpe_dropout=args.bpe_droput
|
||||
)
|
||||
|
||||
MTDataPreproc.preprocess_monolingual_dataset(
|
||||
clean=args.clean,
|
||||
fname=args.fname,
|
||||
out_dir=args.out_dir,
|
||||
tokenizer=tokenizer_model,
|
||||
max_seq_length=args.max_seq_length,
|
||||
min_seq_length=args.min_seq_length,
|
||||
tokens_in_batch=args.tokens_in_batch,
|
||||
lines_per_dataset_fragment=args.lines_per_dataset_fragment,
|
||||
num_batches_per_tarfile=args.num_batches_per_tarfile,
|
||||
pkl_file_prefix=args.pkl_file_prefix,
|
||||
global_rank=0,
|
||||
world_size=1,
|
||||
)
|
||||
@@ -0,0 +1,143 @@
|
||||
# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
from nemo.collections.nlp.data.machine_translation.preproc_mt_data import MTDataPreproc
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='NMT dataset pre-processing')
|
||||
parser.add_argument('--shared_tokenizer', action="store_true", help='Whether to share encoder/decoder tokenizers')
|
||||
parser.add_argument('--clean', action="store_true", help='Whether to clean dataset based on length diff')
|
||||
parser.add_argument('--tar_file_prefix', type=str, default='parallel', help='Prefix for tar files')
|
||||
parser.add_argument('--bpe_dropout', type=float, default=0.1, help='Whether to share encoder/decoder tokenizers')
|
||||
parser.add_argument('--src_fname', type=str, required=True, help='Path to the source file')
|
||||
parser.add_argument('--tgt_fname', type=str, required=True, help='Path to the target file')
|
||||
parser.add_argument('--out_dir', type=str, required=True, help='Path to store dataloader and tokenizer models')
|
||||
parser.add_argument('--encoder_model_name', type=str, default=None, help='For use with pretrained encoders')
|
||||
parser.add_argument(
|
||||
'--decoder_model_name', type=str, default=None, help='For use with pretrained decoders (not yet supported)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--encoder_tokenizer_model', type=str, default='None', help='Path to pre-trained encoder tokenizer model'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--encoder_tokenizer_name', type=str, default='yttm', help='Encoder BPE Tokenizer Name, Options: [yttm]'
|
||||
)
|
||||
parser.add_argument('--encoder_tokenizer_vocab_size', type=int, default=32000, help='Encoder Vocab size after BPE')
|
||||
parser.add_argument(
|
||||
'--encoder_tokenizer_coverage', type=float, default=0.999, help='Encoder Character coverage for BPE'
|
||||
)
|
||||
parser.add_argument('--encoder_tokenizer_bpe_dropout', type=float, default=0.1, help='Encoder BPE dropout prob')
|
||||
parser.add_argument(
|
||||
'--decoder_tokenizer_model', type=str, default='None', help='Path to pre-trained decoder tokenizer model'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--decoder_tokenizer_name', type=str, default='yttm', help='Encoder BPE Tokenizer Name, Options: [yttm]'
|
||||
)
|
||||
parser.add_argument('--decoder_tokenizer_vocab_size', type=int, default=32000, help='Encoder Vocab size after BPE')
|
||||
parser.add_argument(
|
||||
'--decoder_tokenizer_coverage', type=float, default=0.999, help='Encoder Character coverage for BPE'
|
||||
)
|
||||
parser.add_argument('--decoder_tokenizer_bpe_dropout', type=float, default=0.1, help='Encoder BPE dropout prob')
|
||||
parser.add_argument('--max_seq_length', type=int, default=512, help='Max Sequence Length')
|
||||
parser.add_argument('--min_seq_length', type=int, default=1, help='Min Sequence Length')
|
||||
parser.add_argument('--tokens_in_batch', type=int, default=16000, help='# Tokens per batch per GPU')
|
||||
parser.add_argument('--coverage', type=float, default=0.999, help='BPE character coverage [0-1]')
|
||||
parser.add_argument(
|
||||
'--lines_per_dataset_fragment',
|
||||
type=int,
|
||||
default=1000000,
|
||||
help='Number of lines to consider for bucketing and padding',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--num_batches_per_tarfile',
|
||||
type=int,
|
||||
default=1000,
|
||||
help='Number of batches (pickle files) within each tarfile',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--n_preproc_jobs', type=int, default=-2, help='Number of processes to use for creating the tarred dataset.',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
if not os.path.exists(args.out_dir):
|
||||
os.mkdir(args.out_dir)
|
||||
|
||||
if (
|
||||
args.encoder_tokenizer_model != 'None'
|
||||
and args.decoder_tokenizer_model == 'None'
|
||||
or args.decoder_tokenizer_model != 'None'
|
||||
and args.encoder_tokenizer_model == 'None'
|
||||
):
|
||||
if args.shared_tokenizer:
|
||||
raise ValueError(
|
||||
'''
|
||||
If using a pre-trained shared tokenizer,
|
||||
both encoder and decoder tokenizers must be the same
|
||||
'''
|
||||
)
|
||||
else:
|
||||
raise ValueError('Both encoder and decoder pre-trained tokenizer models must be specified')
|
||||
|
||||
if args.encoder_tokenizer_model == 'None' and args.decoder_tokenizer_model == 'None':
|
||||
encoder_tokenizer_model, decoder_tokenizer_model = MTDataPreproc.train_tokenizers(
|
||||
out_dir=args.out_dir,
|
||||
src_fname=args.src_fname,
|
||||
tgt_fname=args.tgt_fname,
|
||||
shared_tokenizer=args.shared_tokenizer,
|
||||
encoder_tokenizer_name=args.encoder_tokenizer_name,
|
||||
encoder_tokenizer_vocab_size=args.encoder_tokenizer_vocab_size,
|
||||
encoder_tokenizer_coverage=args.encoder_tokenizer_coverage,
|
||||
decoder_tokenizer_name=args.decoder_tokenizer_name,
|
||||
decoder_tokenizer_vocab_size=args.decoder_tokenizer_vocab_size,
|
||||
decoder_tokenizer_coverage=args.decoder_tokenizer_coverage,
|
||||
global_rank=0,
|
||||
)
|
||||
else:
|
||||
encoder_tokenizer_model, decoder_tokenizer_model = args.encoder_tokenizer_model, args.decoder_tokenizer_model
|
||||
|
||||
encoder_tokenizer, decoder_tokenizer = MTDataPreproc.get_enc_dec_tokenizers(
|
||||
encoder_tokenizer_name=args.encoder_tokenizer_name,
|
||||
encoder_tokenizer_model=encoder_tokenizer_model,
|
||||
encoder_bpe_dropout=args.encoder_tokenizer_bpe_dropout,
|
||||
decoder_tokenizer_name=args.decoder_tokenizer_name,
|
||||
decoder_tokenizer_model=decoder_tokenizer_model,
|
||||
decoder_bpe_dropout=args.decoder_tokenizer_bpe_dropout,
|
||||
)
|
||||
|
||||
_, _ = MTDataPreproc.preprocess_parallel_dataset(
|
||||
clean=args.clean,
|
||||
src_fname=args.src_fname,
|
||||
tgt_fname=args.tgt_fname,
|
||||
out_dir=args.out_dir,
|
||||
encoder_tokenizer_name=args.encoder_tokenizer_name,
|
||||
encoder_model_name=args.encoder_model_name,
|
||||
encoder_tokenizer_model=encoder_tokenizer_model,
|
||||
encoder_bpe_dropout=args.encoder_tokenizer_bpe_dropout,
|
||||
decoder_tokenizer_name=args.decoder_tokenizer_name,
|
||||
decoder_model_name=args.decoder_model_name,
|
||||
decoder_tokenizer_model=decoder_tokenizer_model,
|
||||
decoder_bpe_dropout=args.decoder_tokenizer_bpe_dropout,
|
||||
max_seq_length=args.max_seq_length,
|
||||
min_seq_length=args.min_seq_length,
|
||||
tokens_in_batch=args.tokens_in_batch,
|
||||
lines_per_dataset_fragment=args.lines_per_dataset_fragment,
|
||||
num_batches_per_tarfile=args.num_batches_per_tarfile,
|
||||
tar_file_prefix=args.tar_file_prefix,
|
||||
global_rank=0,
|
||||
world_size=1,
|
||||
n_jobs=args.n_preproc_jobs,
|
||||
)
|
||||
@@ -0,0 +1,137 @@
|
||||
# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from omegaconf import OmegaConf
|
||||
from pytorch_lightning import Trainer
|
||||
|
||||
from nemo.collections.nlp.data.machine_translation.preproc_mt_data import MTDataPreproc
|
||||
from nemo.collections.nlp.models.machine_translation.mt_enc_dec_config import MTEncDecModelConfig
|
||||
from nemo.collections.nlp.models.machine_translation.mt_enc_dec_model import MTEncDecModel
|
||||
from nemo.core.config import hydra_runner
|
||||
from nemo.core.config.modelPT import NemoConfig
|
||||
from nemo.core.config.pytorch_lightning import TrainerConfig
|
||||
from nemo.utils import logging
|
||||
from nemo.utils.config_utils import update_model_config
|
||||
from nemo.utils.exp_manager import ExpManagerConfig, exp_manager
|
||||
|
||||
|
||||
"""
|
||||
Usage:
|
||||
1. If you need to start docker and install NeMo, otherwise skip this step:
|
||||
|
||||
a. ```docker run --gpus all -it --rm -v /home/okuchaiev/repos/NeMo/:/NeMo -p 6006:6006 -v /mnt:/mnt --shm-size=16g --ulimit memlock=-1 --ulimit stack=67108864 --device=/dev/snd nvcr.io/nvidia/pytorch:20.11-py3```
|
||||
b. ```cd /NeMo```
|
||||
c. ```./reinstall.sh```
|
||||
|
||||
2. Train a new tokenizer (or use pre-trained one):
|
||||
```yttm bpe --data /mnt/D1/Data/NMT/wmt16_de_en/train.clean.en-de.shuffled.common --model tokenizer.BPE.8192.model --vocab_size 8192```
|
||||
|
||||
(To use WANDB, optionally, do login first)
|
||||
``wandb login [YOUR WANDB login]``
|
||||
|
||||
3. Start training:
|
||||
|
||||
|
||||
(This example for "base" model on 2 GPUs for 150000 steps with batch size of 12500 tokens per GPU)
|
||||
|
||||
python enc_dec_nmt.py \
|
||||
--config-path=conf \
|
||||
--config-name=aayn_base \
|
||||
trainer.gpus=[0,1] \
|
||||
~trainer.max_epochs \
|
||||
+trainer.max_steps=150000 \
|
||||
model.beam_size=4 \
|
||||
model.max_generation_delta=5 \
|
||||
model.label_smoothing=0.1 \
|
||||
model.encoder_tokenizer.tokenizer_model=tokenizer.BPE.8192.model \
|
||||
model.decoder_tokenizer.tokenizer_model=tokenizer.BPE.8192.model \
|
||||
model.encoder.num_layers=6 \
|
||||
model.encoder.hidden_size=512 \
|
||||
model.encoder.inner_size=2048 \
|
||||
model.encoder.num_attention_heads=8 \
|
||||
model.encoder.ffn_dropout=0.1 \
|
||||
model.decoder.num_layers=6 \
|
||||
model.decoder.hidden_size=512 \
|
||||
model.decoder.inner_size=2048 \
|
||||
model.decoder.num_attention_heads=8 \
|
||||
model.decoder.ffn_dropout=0.1 \
|
||||
model.train_ds.src_file_name=/mnt/D1/Data/NMT/wmt16_de_en/train.clean.de.shuffled \
|
||||
model.train_ds.tgt_file_name=/mnt/D1/Data/NMT/wmt16_de_en/train.clean.en.shuffled \
|
||||
model.train_ds.tokens_in_batch=12500 \
|
||||
model.validation_ds.src_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.ref \
|
||||
model.validation_ds.tgt_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.src \
|
||||
model.validation_ds.tokens_in_batch=8192 \
|
||||
model.test_ds.src_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.ref \
|
||||
model.test_ds.tgt_file_name=/mnt/D1/Data/NMT/wmt16_de_en/wmt14-en-de.src \
|
||||
model.optim.lr=0.001 \
|
||||
model.optim.sched.warmup_ratio=0.05 \
|
||||
+exp_manager.create_wandb_logger=True \
|
||||
+exp_manager.wandb_logger_kwargs.name=TEST-nmt-base \
|
||||
+exp_manager.wandb_logger_kwargs.project=nmt-de-en \
|
||||
+exp_manager.create_checkpoint_callback=True \
|
||||
+exp_manager.checkpoint_callback_params.monitor=val_sacreBLEU \
|
||||
+exp_manager.exp_dir=nmt_base \
|
||||
+exp_manager.checkpoint_callback_params.mode=max
|
||||
"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class MTEncDecConfig(NemoConfig):
|
||||
name: Optional[str] = 'MTEncDec'
|
||||
do_training: bool = True
|
||||
do_testing: bool = False
|
||||
model: MTEncDecModelConfig = MTEncDecModelConfig()
|
||||
trainer: Optional[TrainerConfig] = TrainerConfig()
|
||||
exp_manager: Optional[ExpManagerConfig] = ExpManagerConfig(name='MTEncDec', files_to_copy=[])
|
||||
|
||||
|
||||
@hydra_runner(config_path="conf", config_name="aayn_base")
|
||||
def main(cfg: MTEncDecConfig) -> None:
|
||||
# merge default config with user specified config
|
||||
default_cfg = MTEncDecConfig()
|
||||
cfg = update_model_config(default_cfg, cfg)
|
||||
logging.info("\n\n************** Experiment configuration ***********")
|
||||
logging.info(f'Config: {OmegaConf.to_yaml(cfg)}')
|
||||
|
||||
# training is managed by PyTorch Lightning
|
||||
trainer = Trainer(**cfg.trainer)
|
||||
|
||||
# tokenizers will be trained and and tarred training data will be created if needed
|
||||
# model config is then updated
|
||||
if cfg.model.preproc_out_dir is not None:
|
||||
MTDataPreproc(cfg=cfg.model, trainer=trainer)
|
||||
|
||||
# experiment logs, checkpoints, and auto-resume are managed by exp_manager and PyTorch Lightning
|
||||
exp_manager(trainer, cfg.exp_manager)
|
||||
|
||||
# everything needed to train translation models is encapsulated in the NeMo MTEncdDecModel
|
||||
mt_model = MTEncDecModel(cfg.model, trainer=trainer)
|
||||
|
||||
logging.info("\n\n************** Model parameters and their sizes ***********")
|
||||
for name, param in mt_model.named_parameters():
|
||||
print(name, param.size())
|
||||
logging.info("***********************************************************\n\n")
|
||||
|
||||
if cfg.do_training:
|
||||
trainer.fit(mt_model)
|
||||
|
||||
if cfg.do_testing:
|
||||
trainer.test(mt_model)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,122 @@
|
||||
# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""
|
||||
Given NMT model's .nemo file, this script can be used to translate text.
|
||||
USAGE Example:
|
||||
1. Obtain text file in src language. You can use sacrebleu to obtain standard test sets like so:
|
||||
sacrebleu -t wmt14 -l de-en --echo src > wmt14-de-en.src
|
||||
2. Translate:
|
||||
python nmt_transformer_infer.py --model=[Path to .nemo file] --srctext=wmt14-de-en.src --tgtout=wmt14-de-en.pre
|
||||
"""
|
||||
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import torch
|
||||
|
||||
import nemo.collections.nlp as nemo_nlp
|
||||
from nemo.collections.nlp.modules.common.transformer import (
|
||||
BeamSearchSequenceGenerator,
|
||||
BeamSearchSequenceGeneratorWithLanguageModel,
|
||||
)
|
||||
from nemo.utils import logging
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("--model", type=str, required=True, help="")
|
||||
parser.add_argument("--srctext", type=str, required=True, help="")
|
||||
parser.add_argument("--tgtout", type=str, required=True, help="")
|
||||
parser.add_argument("--batch_size", type=int, default=256, help="")
|
||||
parser.add_argument("--beam_size", type=int, default=4, help="")
|
||||
parser.add_argument("--len_pen", type=float, default=0.6, help="")
|
||||
parser.add_argument("--max_delta_length", type=int, default=5, help="")
|
||||
parser.add_argument("--target_lang", type=str, default=None, help="")
|
||||
parser.add_argument("--source_lang", type=str, default=None, help="")
|
||||
# shallow fusion specific parameters
|
||||
parser.add_argument("--lm_model", type=str, default=None, help="")
|
||||
parser.add_argument("--fusion_coef", type=float, default=0.0, help="")
|
||||
|
||||
args = parser.parse_args()
|
||||
torch.set_grad_enabled(False)
|
||||
if args.model.endswith(".nemo"):
|
||||
logging.info("Attempting to initialize from .nemo file")
|
||||
model = nemo_nlp.models.machine_translation.MTEncDecModel.restore_from(restore_path=args.model)
|
||||
src_text = []
|
||||
tgt_text = []
|
||||
else:
|
||||
raise NotImplemented(f"Only support .nemo files, but got: {args.model}")
|
||||
|
||||
if torch.cuda.is_available():
|
||||
model = model.cuda()
|
||||
|
||||
if args.lm_model is not None:
|
||||
lm_model = nemo_nlp.models.language_modeling.TransformerLMModel.restore_from(restore_path=args.lm_model).eval()
|
||||
model.beam_search = BeamSearchSequenceGeneratorWithLanguageModel(
|
||||
embedding=model.decoder.embedding,
|
||||
decoder=model.decoder.decoder,
|
||||
log_softmax=model.log_softmax,
|
||||
bos=model.decoder_tokenizer.bos_id,
|
||||
pad=model.decoder_tokenizer.pad_id,
|
||||
eos=model.decoder_tokenizer.eos_id,
|
||||
language_model=lm_model,
|
||||
fusion_coef=args.fusion_coef,
|
||||
max_sequence_length=model.decoder.max_sequence_length,
|
||||
beam_size=args.beam_size,
|
||||
len_pen=args.len_pen,
|
||||
max_delta_length=args.max_delta_length,
|
||||
)
|
||||
else:
|
||||
model.beam_search = BeamSearchSequenceGenerator(
|
||||
embedding=model.decoder.embedding,
|
||||
decoder=model.decoder.decoder,
|
||||
log_softmax=model.log_softmax,
|
||||
bos=model.decoder_tokenizer.bos_id,
|
||||
pad=model.decoder_tokenizer.pad_id,
|
||||
eos=model.decoder_tokenizer.eos_id,
|
||||
max_sequence_length=model.decoder.max_sequence_length,
|
||||
beam_size=args.beam_size,
|
||||
len_pen=args.len_pen,
|
||||
max_delta_length=args.max_delta_length,
|
||||
)
|
||||
|
||||
logging.info(f"Translating: {args.srctext}")
|
||||
|
||||
count = 0
|
||||
with open(args.srctext, 'r') as src_f:
|
||||
for line in src_f:
|
||||
src_text.append(line.strip())
|
||||
if len(src_text) == args.batch_size:
|
||||
res = model.translate(text=src_text, source_lang=args.source_lang, target_lang=args.target_lang)
|
||||
if len(res) != len(src_text):
|
||||
print(len(res))
|
||||
print(len(src_text))
|
||||
print(res)
|
||||
print(src_text)
|
||||
tgt_text += res
|
||||
src_text = []
|
||||
count += 1
|
||||
# if count % 300 == 0:
|
||||
# print(f"Translated {count} sentences")
|
||||
if len(src_text) > 0:
|
||||
tgt_text += model.translate(text=src_text, source_lang=args.source_lang, target_lang=args.target_lang)
|
||||
|
||||
with open(args.tgtout, 'w') as tgt_f:
|
||||
for line in tgt_text:
|
||||
tgt_f.write(line + "\n")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main() # noqa pylint: disable=no-value-for-parameter
|
||||
@@ -0,0 +1,7 @@
|
||||
**STEPS 2 RUN**
|
||||
===============
|
||||
0. (Make sure you have Flask installed - ``pip install -r requirements.txt``)
|
||||
1. Edit "config.json" file to only contain models you need. If model's location starts with "NGC/" - it will load this model from NVIDIA's NGC. Otherwise, specify full path to .nemo file.
|
||||
4. To run: ``python nmt_service.py``
|
||||
5. To translate: ``http://127.0.0.1:5000/translate?text=Frohe%20Weihnachten`` (here %20 means space)
|
||||
6. Run web UI: ``python -m http.server``
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"en-de": "NGC/nmt_en_de_transformer12x2",
|
||||
"de-en": "NGC/nmt_de_en_transformer12x2",
|
||||
"en-es": "NGC/nmt_en_es_transformer12x2",
|
||||
"es-en": "NGC/nmt_es_en_transformer12x2",
|
||||
"en-ru": "NGC/nmt_en_ru_transformer6x6",
|
||||
"ru-en": "NGC/nmt_ru_en_transformer6x6",
|
||||
"en-fr": "NGC/nmt_en_fr_transformer12x2",
|
||||
"fr-en": "NGC/nmt_fr_en_transformer12x2",
|
||||
"en-zh": "NGC/nmt_en_zh_transformer6x6",
|
||||
"zh-en": "NGC/nmt_zh_en_transformer6x6"
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Neural Machine Translation Demo App</title>
|
||||
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
||||
<link rel="stylesheet" href="/resources/demos/style.css">
|
||||
<style>
|
||||
.ui-resizable-se {
|
||||
bottom: 17px;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||
<script>
|
||||
$( function() {
|
||||
$( "#tgt_text" ).resizable({
|
||||
handles: "se"
|
||||
});
|
||||
} );
|
||||
$( function() {
|
||||
$( "#src_text" ).resizable({
|
||||
handles: "se"
|
||||
});
|
||||
} );
|
||||
$( function() {
|
||||
$( "#translate_button" ).button();
|
||||
$( "#translate_button" ).click( function( event ) {
|
||||
$.ajax({
|
||||
url: "http://10.110.40.187:5000/translate",
|
||||
type: "GET",
|
||||
data: {
|
||||
text: $( "#src_text" ).val(),
|
||||
langpair: $('input[type=radio][name=langpair]:checked').attr('id'),
|
||||
do_moses: true
|
||||
},
|
||||
success: function (result) {
|
||||
$( "#tgt_text" ).val(result.translation);
|
||||
},
|
||||
error: function (err) {
|
||||
alert('Sorry, can not reach translation service');
|
||||
},
|
||||
})
|
||||
} );
|
||||
} );
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="contact-us">
|
||||
<h1>Neural Machine Translation Demo</h1>
|
||||
<p>
|
||||
<br/>
|
||||
<h4>Running NeMo commit id: v1.0.2 </h4>
|
||||
<br/>
|
||||
</p>
|
||||
<p>
|
||||
<fieldset>
|
||||
<legend>Select translation direction: </legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="en-de">English to German</label>
|
||||
<input type="radio" name="langpair" id="en-de">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="de-en">German to English</label>
|
||||
<input type="radio" name="langpair" id="de-en">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="es-en">Spanish to English</label>
|
||||
<input type="radio" name="langpair" id="es-en">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="en-es" selected="selected">English to Spanish</label>
|
||||
<input type="radio" name="langpair" id="en-es" checked>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="en-ru">English to Russian</label>
|
||||
<input type="radio" name="langpair" id="en-ru">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="ru-en">Russian to English</label>
|
||||
<input type="radio" name="langpair" id="ru-en">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="en-fr">English to French</label>
|
||||
<input type="radio" name="langpair" id="en-fr">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="fr-en">French to English</label>
|
||||
<input type="radio" name="langpair" id="fr-en">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="en-zh">English to Chinese</label>
|
||||
<input type="radio" name="langpair" id="en-zh">
|
||||
</td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<label for="zh-en">Chinese to English</label>
|
||||
<input type="radio" name="langpair" id="zh-en">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<textarea id="src_text" rows="12" cols="60">Type something here, chose language pair and click "Translate" button.</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button id="translate_button">Translate !</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<textarea id="tgt_text" rows="12" cols="60" readonly></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,100 @@
|
||||
# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import json
|
||||
import time
|
||||
|
||||
import flask
|
||||
import torch
|
||||
from flask import Flask, json, request
|
||||
from flask_cors import CORS
|
||||
|
||||
import nemo.collections.nlp as nemo_nlp
|
||||
from nemo.utils import logging
|
||||
|
||||
MODELS_DICT = {}
|
||||
|
||||
model = None
|
||||
api = Flask(__name__)
|
||||
CORS(api)
|
||||
|
||||
|
||||
def initialize(config_file_path: str):
|
||||
"""
|
||||
Loads 'language-pair to NMT model mapping'
|
||||
"""
|
||||
__MODELS_DICT = None
|
||||
|
||||
logging.info("Starting NMT service")
|
||||
logging.info(f"I will attempt to load all the models listed in {config_file_path}.")
|
||||
logging.info(f"Edit {config_file_path} to disable models you don't need.")
|
||||
if torch.cuda.is_available():
|
||||
logging.info("CUDA is available. Running on GPU")
|
||||
else:
|
||||
logging.info("CUDA is not available. Defaulting to CPUs")
|
||||
|
||||
# read config
|
||||
with open(config_file_path) as f:
|
||||
__MODELS_DICT = json.load(f)
|
||||
|
||||
if __MODELS_DICT is not None:
|
||||
for key, value in __MODELS_DICT.items():
|
||||
logging.info(f"Loading model for {key} from file: {value}")
|
||||
if value.startswith("NGC/"):
|
||||
model = nemo_nlp.models.machine_translation.MTEncDecModel.from_pretrained(model_name=value[4:])
|
||||
else:
|
||||
model = nemo_nlp.models.machine_translation.MTEncDecModel.restore_from(restore_path=value)
|
||||
if torch.cuda.is_available():
|
||||
model = model.cuda()
|
||||
MODELS_DICT[key] = model
|
||||
else:
|
||||
raise ValueError("Did not find the config.json or it was empty")
|
||||
logging.info("NMT service started")
|
||||
|
||||
|
||||
@api.route('/translate', methods=['GET', 'POST', 'OPTIONS'])
|
||||
def get_translation():
|
||||
try:
|
||||
time_s = time.time()
|
||||
langpair = request.args["langpair"]
|
||||
src = request.args["text"]
|
||||
do_moses = request.args.get('do_moses', False)
|
||||
if langpair in MODELS_DICT:
|
||||
if do_moses:
|
||||
result = MODELS_DICT[langpair].translate(
|
||||
[src], source_lang=langpair.split('-')[0], target_lang=langpair.split('-')[1]
|
||||
)
|
||||
else:
|
||||
result = MODELS_DICT[langpair].translate([src])
|
||||
|
||||
duration = time.time() - time_s
|
||||
logging.info(
|
||||
f"Translated in {duration}. Input was: {request.args['text']} <############> Translation was: {result[0]}"
|
||||
)
|
||||
res = {'translation': result[0]}
|
||||
response = flask.jsonify(res)
|
||||
response.headers.add('Access-Control-Allow-Origin', '*')
|
||||
return response
|
||||
|
||||
else:
|
||||
logging.error(f"Got the following langpair: {langpair} which was not found")
|
||||
except Exception as ex:
|
||||
res = {'translation': str(ex)}
|
||||
response = flask.jsonify(res)
|
||||
response.headers.add('Access-Control-Allow-Origin', '*')
|
||||
return res
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
initialize('config.json')
|
||||
api.run(host='0.0.0.0')
|
||||
@@ -0,0 +1,3 @@
|
||||
nemo_toolkit[all]>=1.0.0rc1
|
||||
flask
|
||||
flask_cors
|
||||
@@ -0,0 +1,111 @@
|
||||
@import url("https://fonts.googleapis.com/css?family=Spartan&display=swap");
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
/*background: url("https://img.wallpapersafari.com/desktop/1680/1050/65/18/8AYkSt.jpg") center center;*/
|
||||
background: url("https://images5.alphacoders.com/550/550948.jpg") center center;
|
||||
background-size: cover;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
font-size: 12pt;
|
||||
font-family: "Spartan";
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.contact-us {
|
||||
/*background: #1f1d1d;*/
|
||||
padding: 50px 100px;
|
||||
border-top: 10px solid #229955;
|
||||
}
|
||||
|
||||
label, input, textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-size: 12pt;
|
||||
line-height: 24pt;
|
||||
font-family: "Spartan";
|
||||
}
|
||||
|
||||
input {
|
||||
margin-bottom: 24pt;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
font-size: 22pt;
|
||||
line-height: 24pt;
|
||||
font-style: italic;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
em {
|
||||
color: #229955;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
border: none;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 2px;
|
||||
background: #f8f4e5;
|
||||
padding-left: 5px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input:focus, textarea:focus {
|
||||
border: 1px solid #6bd4b1;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
button {
|
||||
display: block;
|
||||
float: left;
|
||||
line-height: 24pt;
|
||||
padding: 0 20px;
|
||||
border: none;
|
||||
background: #f45702;
|
||||
color: white;
|
||||
letter-spacing: 2px;
|
||||
transition: 0.2s all ease-in-out;
|
||||
border-bottom: 2px solid transparent;
|
||||
outline: none;
|
||||
}
|
||||
button:hover {
|
||||
background: inherit;
|
||||
color: #ea6153;
|
||||
border-bottom: 2px solid #f45702;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: #ffc7b8;
|
||||
}
|
||||
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
textarea:-webkit-autofill,
|
||||
textarea:-webkit-autofill:hover,
|
||||
textarea:-webkit-autofill:focus {
|
||||
border: 1px solid #6bd4b1;
|
||||
-webkit-text-fill-color: #2A293E;
|
||||
-webkit-box-shadow: 0 0 0px 1000px #f8f4e5 inset;
|
||||
transition: background-color 5000s ease-in-out 0s;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
# Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
import os
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import torch
|
||||
import torch.multiprocessing as mp
|
||||
from torch.utils.data import DataLoader
|
||||
|
||||
from nemo.collections.nlp.data.language_modeling import TarredSentenceDataset
|
||||
from nemo.collections.nlp.data.machine_translation import TarredTranslationDataset
|
||||
from nemo.collections.nlp.models.machine_translation.mt_enc_dec_model import MTEncDecModel
|
||||
from nemo.utils import logging
|
||||
|
||||
|
||||
def get_args():
|
||||
parser = ArgumentParser(description='Batch translation of sentences from a pre-trained model on multiple GPUs')
|
||||
parser.add_argument("--model", type=str, required=True, help="Path to the .nemo translation model file")
|
||||
parser.add_argument(
|
||||
"--text2translate", type=str, required=True, help="Path to the pre-processed tarfiles for translation"
|
||||
)
|
||||
parser.add_argument("--result_dir", type=str, required=True, help="Folder to write translation results")
|
||||
parser.add_argument(
|
||||
"--twoside", action="store_true", help="Set flag when translating the source side of a parallel dataset"
|
||||
)
|
||||
parser.add_argument(
|
||||
'--metadata_path', type=str, required=True, help="Path to the JSON file that contains dataset info"
|
||||
)
|
||||
parser.add_argument('--topk', type=int, default=500, help="Value of k for topk sampling")
|
||||
parser.add_argument('--src_language', type=str, required=True, help="Source lang ID for detokenization")
|
||||
parser.add_argument('--tgt_language', type=str, required=True, help="Target lang ID for detokenization")
|
||||
parser.add_argument(
|
||||
'--reverse_lang_direction',
|
||||
action="store_true",
|
||||
help="Reverse source and target language direction for parallel dataset",
|
||||
)
|
||||
parser.add_argument('--n_gpus', type=int, default=-1, help="Number of GPUs to use")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def translate(rank, world_size, args):
|
||||
if args.model.endswith(".nemo"):
|
||||
logging.info("Attempting to initialize from .nemo file")
|
||||
model = MTEncDecModel.restore_from(restore_path=args.model, map_location=f"cuda:{rank}")
|
||||
elif args.model.endswith(".ckpt"):
|
||||
logging.info("Attempting to initialize from .ckpt file")
|
||||
model = MTEncDecModel.load_from_checkpoint(checkpoint_path=args.model, map_location=f"cuda:{rank}")
|
||||
model.replace_beam_with_sampling(topk=args.topk)
|
||||
model.eval()
|
||||
if args.twoside:
|
||||
dataset = TarredTranslationDataset(
|
||||
text_tar_filepaths=args.text2translate,
|
||||
metadata_path=args.metadata_path,
|
||||
encoder_tokenizer=model.encoder_tokenizer,
|
||||
decoder_tokenizer=model.decoder_tokenizer,
|
||||
shuffle_n=100,
|
||||
shard_strategy="scatter",
|
||||
world_size=world_size,
|
||||
global_rank=rank,
|
||||
reverse_lang_direction=args.reverse_lang_direction,
|
||||
)
|
||||
else:
|
||||
dataset = TarredSentenceDataset(
|
||||
text_tar_filepaths=args.text2translate,
|
||||
metadata_path=args.metadata_path,
|
||||
tokenizer=model.encoder_tokenizer,
|
||||
shuffle_n=100,
|
||||
shard_strategy="scatter",
|
||||
world_size=world_size,
|
||||
global_rank=rank,
|
||||
)
|
||||
loader = DataLoader(dataset, batch_size=1)
|
||||
result_dir = os.path.join(args.result_dir, f'rank{rank}')
|
||||
os.makedirs(result_dir, exist_ok=True)
|
||||
originals_file_name = os.path.join(result_dir, 'originals.txt')
|
||||
translations_file_name = os.path.join(result_dir, 'translations.txt')
|
||||
num_translated_sentences = 0
|
||||
|
||||
with open(originals_file_name, 'w') as of, open(translations_file_name, 'w') as tf:
|
||||
for batch_idx, batch in enumerate(loader):
|
||||
for i in range(len(batch)):
|
||||
if batch[i].ndim == 3:
|
||||
batch[i] = batch[i].squeeze(dim=0)
|
||||
batch[i] = batch[i].to(rank)
|
||||
if args.twoside:
|
||||
src_ids, src_mask, _, _, _ = batch
|
||||
else:
|
||||
src_ids, src_mask = batch
|
||||
if batch_idx % 100 == 0:
|
||||
logging.info(
|
||||
f"{batch_idx} batches ({num_translated_sentences} sentences) were translated by process with "
|
||||
f"rank {rank}"
|
||||
)
|
||||
num_translated_sentences += len(src_ids)
|
||||
inputs, translations = model.batch_translate(src=src_ids, src_mask=src_mask)
|
||||
for src, translation in zip(inputs, translations):
|
||||
of.write(src + '\n')
|
||||
tf.write(translation + '\n')
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = get_args()
|
||||
world_size = torch.cuda.device_count() if args.n_gpus == -1 else args.n_gpus
|
||||
mp.spawn(translate, args=(world_size, args), nprocs=world_size, join=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user