mirror of
https://github.com/storytold/storyteller-ml.git
synced 2026-10-20 08:04:35 +00:00
Introduce code from Rust monorepo. This is a mess
This commit is contained in:
+111
@@ -0,0 +1,111 @@
|
||||
# Intent and Slot classification with pretrained BERT models
|
||||
|
||||
trainer:
|
||||
gpus: 1 # the number of gpus, 0 for CPU
|
||||
num_nodes: 1
|
||||
max_epochs: 50
|
||||
max_steps: null # precedence over max_epochs
|
||||
accumulate_grad_batches: 1 # accumulates grads every k batches
|
||||
amp_level: O0 # O1/O2 for mixed precision
|
||||
precision: 32 # Should be set to 16 for O1 and O2 amp_level to enable the AMP.
|
||||
accelerator: ddp
|
||||
log_every_n_steps: 1 # Interval of logging.
|
||||
val_check_interval: 1.0 # Set to 0.25 to check 4 times per epoch, or an int for number of iterations
|
||||
resume_from_checkpoint: null # The path to a checkpoint file to continue the training, restores the whole state including the epoch, step, LR schedulers, apex, etc.
|
||||
|
||||
checkpoint_callback: false # Provided by exp_manager
|
||||
logger: false # Provided by exp_manager
|
||||
|
||||
model:
|
||||
nemo_path: null # filename to save the model and associated artifacts to .nemo file
|
||||
data_dir: ??? # /path/to/data
|
||||
class_labels:
|
||||
intent_labels_file: intent_labels.csv
|
||||
slot_labels_file: slot_labels.csv
|
||||
class_balancing: null # or weighted_loss
|
||||
intent_loss_weight: 0.6 # relation of intent to slot loss in total loss (between 0 to 1)
|
||||
pad_label: -1 # if -1 not slot token will be used
|
||||
ignore_extra_tokens: false
|
||||
ignore_start_end: true # do not use first and last token for slot training
|
||||
|
||||
train_ds:
|
||||
prefix: train
|
||||
batch_size: 32
|
||||
shuffle: true
|
||||
num_samples: -1
|
||||
num_workers: 2
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
|
||||
validation_ds:
|
||||
prefix: test
|
||||
batch_size: 32
|
||||
shuffle: false
|
||||
num_samples: -1
|
||||
num_workers: 2
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
|
||||
test_ds:
|
||||
prefix: test
|
||||
batch_size: 32
|
||||
shuffle: false
|
||||
num_samples: -1
|
||||
num_workers: 2
|
||||
drop_last: false
|
||||
pin_memory: false
|
||||
|
||||
tokenizer:
|
||||
tokenizer_name: ${model.language_model.pretrained_model_name} # or sentencepiece
|
||||
vocab_file: null # path to vocab file
|
||||
tokenizer_model: null # only used if tokenizer is sentencepiece
|
||||
special_tokens: null
|
||||
|
||||
language_model:
|
||||
max_seq_length: 50
|
||||
pretrained_model_name: bert-base-uncased
|
||||
lm_checkpoint: null
|
||||
config_file: null # json file, precedence over config
|
||||
config: null
|
||||
|
||||
head:
|
||||
num_output_layers: 2
|
||||
fc_dropout: 0.1
|
||||
|
||||
optim:
|
||||
name: adam
|
||||
lr: 2e-5
|
||||
args:
|
||||
name: auto
|
||||
params:
|
||||
weight_decay: 0.01
|
||||
|
||||
sched:
|
||||
name: WarmupAnnealing
|
||||
iters_per_batch: null # computed at runtime
|
||||
max_steps: null # computed at runtime or explicitly set here
|
||||
|
||||
# pytorch lightning args
|
||||
monitor: val_loss
|
||||
reduce_on_plateau: false
|
||||
|
||||
# scheduler config override
|
||||
args:
|
||||
name: auto
|
||||
params:
|
||||
warmup_steps: null
|
||||
warmup_ratio: 0.1
|
||||
last_epoch: -1
|
||||
|
||||
exp_manager:
|
||||
exp_dir: null # exp_dir for your experiment, if None, defaults to "./nemo_experiments"
|
||||
name: "IntentSlot" # The name of your model
|
||||
create_tensorboard_logger: true # Whether you want exp_manger to create a tb logger
|
||||
create_checkpoint_callback: true # Whether you want exp_manager to create a modelcheckpoint callback
|
||||
|
||||
hydra:
|
||||
run:
|
||||
dir: .
|
||||
job_logging:
|
||||
root:
|
||||
handlers: null
|
||||
@@ -0,0 +1,151 @@
|
||||
# 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
|
||||
import re
|
||||
import shutil
|
||||
|
||||
from nemo.collections.nlp.data.data_utils.data_preprocessing import DATABASE_EXISTS_TMP, if_exist, write_files
|
||||
from nemo.utils import logging
|
||||
|
||||
|
||||
def copy_input_files(infold):
|
||||
""" Put training files in convenient place for conversion to our format. """
|
||||
our_infold = infold + "/dataset"
|
||||
|
||||
if os.path.exists(our_infold + "/trainset") and os.path.exists(our_infold + "/testset"):
|
||||
logging.info("Input folders exists")
|
||||
return
|
||||
|
||||
logging.info(f"Copying files to input folder: {our_infold}")
|
||||
os.makedirs(infold, exist_ok=True)
|
||||
|
||||
old_infold = (
|
||||
infold + '/CrossValidation/autoGeneFromRealAnno/autoGene_2018_03_22-13_01_25_169/CrossValidation/KFold_1'
|
||||
)
|
||||
if not os.path.exists(our_infold + "/trainset"):
|
||||
shutil.copytree(old_infold + '/trainset', our_infold + '/trainset')
|
||||
|
||||
if not os.path.exists(our_infold + "/testset"):
|
||||
shutil.copytree(old_infold + '/testset/csv', our_infold + '/testset')
|
||||
|
||||
|
||||
def get_intents(infold):
|
||||
""" Get list of intents from file names. """
|
||||
intents = [f[:-4] for f in os.listdir(infold)]
|
||||
intents.sort()
|
||||
print(f'Found {len(intents)} intents')
|
||||
return intents
|
||||
|
||||
|
||||
def get_intent_queries(infold, intent_names, mode):
|
||||
""" Get list of queries with their corresponding intent number. """
|
||||
intent_queries = ['sentence\tlabel\n']
|
||||
|
||||
for index, intent in enumerate(intent_names):
|
||||
queries = open(f'{infold}/{mode}set/{intent}.csv', 'r').readlines()
|
||||
for query in queries[1:]:
|
||||
phrases = query.split(";")
|
||||
intent_query = phrases[4][1:-1] + "\t" + str(index)
|
||||
intent_queries.append(intent_query)
|
||||
|
||||
return intent_queries
|
||||
|
||||
|
||||
def get_slots(infold, modes):
|
||||
"""
|
||||
Find a lost of unique slot types in training and testing data.
|
||||
We use a single slot type name both for starting and continuation tokes (not using B-, I- notation).
|
||||
"""
|
||||
slots = set()
|
||||
|
||||
for mode in modes:
|
||||
path = f'{infold}/{mode}set'
|
||||
for filename in os.listdir(path):
|
||||
lines = open(f'{path}/{filename}', 'r').readlines()
|
||||
for line in lines[1:]:
|
||||
query = line.split(";")[3]
|
||||
slot_phrases = re.findall('\[.*?\]', query)
|
||||
for slot_phrase in slot_phrases:
|
||||
slot = slot_phrase.split(" : ")[0][1:]
|
||||
slots.add(slot)
|
||||
|
||||
slots = sorted(slots)
|
||||
slots.append("O")
|
||||
print(f'Found {len(slots)} slot types')
|
||||
return slots
|
||||
|
||||
|
||||
def get_slot_queries(infold, slot_dict, mode, intent_names):
|
||||
""" Convert each word in a query to corresponding slot number. """
|
||||
slot_queries = []
|
||||
outside_slot = len(slot_dict) - 1
|
||||
|
||||
# keep the same order of files/queries as for intents
|
||||
for intent in intent_names:
|
||||
lines = open(f'{infold}/{mode}set/{intent}.csv', 'r').readlines()
|
||||
for line in lines[1:]:
|
||||
slot_query = ""
|
||||
query = line.split(";")[3]
|
||||
words = query.split(" ")
|
||||
current_slot = outside_slot
|
||||
for word in words:
|
||||
if word[0] == "[":
|
||||
current_slot = slot_dict[word[1:]]
|
||||
elif word[0] == ":":
|
||||
continue
|
||||
else:
|
||||
slot_query += str(current_slot) + " "
|
||||
if word[-1] == ']':
|
||||
current_slot = outside_slot
|
||||
|
||||
slot_queries.append(slot_query.strip())
|
||||
|
||||
return slot_queries
|
||||
|
||||
|
||||
def process_assistant(infold, outfold, modes=['train', 'test']):
|
||||
"""
|
||||
https://github.com/xliuhw/NLU-Evaluation-Data - this dataset includes
|
||||
about 25 thousand examples with 66 various multi-domain intents and 57 entity types.
|
||||
"""
|
||||
if if_exist(outfold, [f'{mode}_slots.tsv' for mode in modes]):
|
||||
logging.info(DATABASE_EXISTS_TMP.format('robot', outfold))
|
||||
return outfold
|
||||
|
||||
logging.info(f'Processing assistant commands dataset and store at {outfold}')
|
||||
os.makedirs(outfold, exist_ok=True)
|
||||
|
||||
# copy train/test files to the convenient directory to work with
|
||||
copy_input_files(infold)
|
||||
infold += "/dataset"
|
||||
|
||||
# get list of intents from train folder (test folder supposed to be the same)
|
||||
intent_names = get_intents(infold + "/trainset")
|
||||
write_files(intent_names, f'{outfold}/dict.intents.csv')
|
||||
|
||||
# get all train and test queries with their intent
|
||||
for mode in modes:
|
||||
intent_queries = get_intent_queries(infold, intent_names, mode)
|
||||
write_files(intent_queries, f'{outfold}/{mode}.tsv')
|
||||
|
||||
# get list of all unique slots in training and testing files
|
||||
slot_types = get_slots(infold, modes)
|
||||
write_files(slot_types, f'{outfold}/dict.slots.csv')
|
||||
|
||||
# create files of slot queries
|
||||
slot_dict = {k: v for v, k in enumerate(slot_types)}
|
||||
for mode in modes:
|
||||
slot_queries = get_slot_queries(infold, slot_dict, mode, intent_names)
|
||||
write_files(slot_queries, f'{outfold}/{mode}_slots.tsv')
|
||||
@@ -0,0 +1,265 @@
|
||||
# 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
|
||||
import shutil
|
||||
from os.path import exists
|
||||
|
||||
from assistant_utils import process_assistant
|
||||
|
||||
from nemo.collections.nlp.data.data_utils.data_preprocessing import (
|
||||
DATABASE_EXISTS_TMP,
|
||||
MODE_EXISTS_TMP,
|
||||
create_dataset,
|
||||
get_dataset,
|
||||
get_vocab,
|
||||
if_exist,
|
||||
)
|
||||
from nemo.utils import logging
|
||||
|
||||
|
||||
def ids2text(ids, vocab):
|
||||
return ' '.join([vocab[int(id_)] for id_ in ids])
|
||||
|
||||
|
||||
def process_atis(infold, outfold, modes=['train', 'test'], do_lower_case=False):
|
||||
""" MSFT's dataset, processed by Kaggle
|
||||
https://www.kaggle.com/siddhadev/atis-dataset-from-ms-cntk
|
||||
"""
|
||||
vocab = get_vocab(f'{infold}/atis.dict.vocab.csv')
|
||||
|
||||
if if_exist(outfold, [f'{mode}.tsv' for mode in modes]):
|
||||
logging.info(DATABASE_EXISTS_TMP.format('ATIS', outfold))
|
||||
return outfold
|
||||
logging.info(f'Processing ATIS dataset and storing at {outfold}.')
|
||||
|
||||
os.makedirs(outfold, exist_ok=True)
|
||||
|
||||
outfiles = {}
|
||||
for mode in modes:
|
||||
outfiles[mode] = open(os.path.join(outfold, mode + '.tsv'), 'w')
|
||||
outfiles[mode].write('sentence\tlabel\n')
|
||||
outfiles[mode + '_slots'] = open(f'{outfold}/{mode}_slots.tsv', 'w')
|
||||
|
||||
queries = open(f'{infold}/atis.{mode}.query.csv', 'r').readlines()
|
||||
intents = open(f'{infold}/atis.{mode}.intent.csv', 'r').readlines()
|
||||
slots = open(f'{infold}/atis.{mode}.slots.csv', 'r').readlines()
|
||||
|
||||
for i, query in enumerate(queries):
|
||||
sentence = ids2text(query.strip().split()[1:-1], vocab)
|
||||
if do_lower_case:
|
||||
sentence = sentence.lower()
|
||||
outfiles[mode].write(f'{sentence}\t{intents[i].strip()}\n')
|
||||
slot = ' '.join(slots[i].strip().split()[1:-1])
|
||||
outfiles[mode + '_slots'].write(slot + '\n')
|
||||
|
||||
shutil.copyfile(f'{infold}/atis.dict.intent.csv', f'{outfold}/dict.intents.csv')
|
||||
shutil.copyfile(f'{infold}/atis.dict.slots.csv', f'{outfold}/dict.slots.csv')
|
||||
for mode in modes:
|
||||
outfiles[mode].close()
|
||||
|
||||
|
||||
def process_snips(infold, outfold, do_lower_case, modes=['train', 'test'], dev_split=0.1):
|
||||
if not os.path.exists(infold):
|
||||
link = 'https://github.com/snipsco/spoken-language-understanding-research-datasets'
|
||||
raise ValueError(f'Data not found at {infold}. ' f'You may request to download the SNIPS dataset from {link}.')
|
||||
|
||||
exist = True
|
||||
for dataset in ['light', 'speak', 'all']:
|
||||
if if_exist(f'{outfold}/{dataset}', [f'{mode}.tsv' for mode in modes]):
|
||||
logging.info(DATABASE_EXISTS_TMP.format('SNIPS-' + dataset, outfold))
|
||||
else:
|
||||
exist = False
|
||||
if exist:
|
||||
return outfold
|
||||
|
||||
logging.info(f'Processing SNIPS dataset and storing at folders "speak", "light" and "all" under {outfold}.')
|
||||
logging.info(
|
||||
f'Processing and importing "smart-speaker-en-close-field" -> "speak" and "smart-speaker-en-close-field" -> "light".'
|
||||
)
|
||||
|
||||
os.makedirs(outfold, exist_ok=True)
|
||||
|
||||
speak_dir = 'smart-speaker-en-close-field'
|
||||
light_dir = 'smart-lights-en-close-field'
|
||||
|
||||
light_files = [f'{infold}/{light_dir}/dataset.json']
|
||||
speak_files = [f'{infold}/{speak_dir}/training_dataset.json']
|
||||
speak_files.append(f'{infold}/{speak_dir}/test_dataset.json')
|
||||
|
||||
light_train, light_dev, light_slots, light_intents = get_dataset(light_files, dev_split)
|
||||
speak_train, speak_dev, speak_slots, speak_intents = get_dataset(speak_files)
|
||||
|
||||
create_dataset(light_train, light_dev, light_slots, light_intents, do_lower_case, f'{outfold}/light')
|
||||
create_dataset(speak_train, speak_dev, speak_slots, speak_intents, do_lower_case, f'{outfold}/speak')
|
||||
create_dataset(
|
||||
light_train + speak_train,
|
||||
light_dev + speak_dev,
|
||||
light_slots | speak_slots,
|
||||
light_intents | speak_intents,
|
||||
do_lower_case,
|
||||
f'{outfold}/all',
|
||||
)
|
||||
|
||||
|
||||
def process_jarvis_datasets(
|
||||
infold, outfold, modes=['train', 'test', 'dev'], do_lower_case=False, ignore_prev_intent=False
|
||||
):
|
||||
""" process and convert Jarvis datasets into NeMo's BIO format
|
||||
"""
|
||||
dataset_name = "jarvis"
|
||||
if if_exist(outfold, ['dict.intents.csv', 'dict.slots.csv']):
|
||||
logging.info(DATABASE_EXISTS_TMP.format(dataset_name, outfold))
|
||||
return outfold
|
||||
|
||||
logging.info(f'Processing {dataset_name} dataset and storing at {outfold}')
|
||||
|
||||
os.makedirs(outfold, exist_ok=True)
|
||||
|
||||
outfiles = {}
|
||||
intents_list = {}
|
||||
slots_list = {}
|
||||
slots_list_all = {}
|
||||
|
||||
outfiles['dict_intents'] = open(f'{outfold}/dict.intents.csv', 'w')
|
||||
outfiles['dict_slots'] = open(f'{outfold}/dict.slots.csv', 'w')
|
||||
|
||||
outfiles['dict_slots'].write('O\n')
|
||||
slots_list["O"] = 0
|
||||
slots_list_all["O"] = 0
|
||||
|
||||
for mode in modes:
|
||||
if if_exist(outfold, [f'{mode}.tsv']):
|
||||
logging.info(MODE_EXISTS_TMP.format(mode, dataset_name, outfold, mode))
|
||||
continue
|
||||
|
||||
if not if_exist(infold, [f'{mode}.tsv']):
|
||||
logging.info(f'{mode} mode of {dataset_name}' f' is skipped as it was not found.')
|
||||
continue
|
||||
|
||||
outfiles[mode] = open(os.path.join(outfold, mode + '.tsv'), 'w')
|
||||
outfiles[mode].write('sentence\tlabel\n')
|
||||
outfiles[mode + '_slots'] = open(f'{outfold}/{mode}_slots.tsv', 'w')
|
||||
|
||||
queries = open(f'{infold}/{mode}.tsv', 'r').readlines()
|
||||
|
||||
for i, query in enumerate(queries):
|
||||
line_splits = query.strip().split("\t")
|
||||
if len(line_splits) == 3:
|
||||
intent_str, slot_tags_str, sentence = line_splits
|
||||
else:
|
||||
intent_str, sentence = line_splits
|
||||
slot_tags_str = ""
|
||||
|
||||
if intent_str not in intents_list:
|
||||
intents_list[intent_str] = len(intents_list)
|
||||
outfiles['dict_intents'].write(f'{intent_str}\n')
|
||||
|
||||
if ignore_prev_intent:
|
||||
start_token = 2
|
||||
else:
|
||||
start_token = 1
|
||||
|
||||
if do_lower_case:
|
||||
sentence = sentence.lower()
|
||||
sentence_cld = " ".join(sentence.strip().split()[start_token:-1])
|
||||
outfiles[mode].write(f'{sentence_cld}\t' f'{str(intents_list[intent_str])}\n')
|
||||
|
||||
slot_tags_list = []
|
||||
if slot_tags_str.strip():
|
||||
slot_tags = slot_tags_str.strip().split(",")
|
||||
for st in slot_tags:
|
||||
if not st.strip():
|
||||
continue
|
||||
[start_i, end_i, slot_name] = st.strip().split(":")
|
||||
slot_tags_list.append([int(start_i), int(end_i), slot_name])
|
||||
if slot_name not in slots_list:
|
||||
slots_list[slot_name] = len(slots_list)
|
||||
slots_list_all[f'B-{slot_name}'] = len(slots_list_all)
|
||||
slots_list_all[f'I-{slot_name}'] = len(slots_list_all)
|
||||
outfiles['dict_slots'].write(f'B-{slot_name}\n')
|
||||
outfiles['dict_slots'].write(f'I-{slot_name}\n')
|
||||
|
||||
slot_tags_list.sort(key=lambda x: x[0])
|
||||
slots = []
|
||||
processed_index = 0
|
||||
for tag_start, tag_end, tag_str in slot_tags_list:
|
||||
if tag_start > processed_index:
|
||||
words_list = sentence[processed_index:tag_start].strip().split()
|
||||
slots.extend([str(slots_list_all['O'])] * len(words_list))
|
||||
words_list = sentence[tag_start:tag_end].strip().split()
|
||||
slots.append(str(slots_list_all[f'B-{tag_str}']))
|
||||
slots.extend([str(slots_list_all[f'I-{tag_str}'])] * (len(words_list) - 1))
|
||||
processed_index = tag_end
|
||||
|
||||
if processed_index < len(sentence):
|
||||
words_list = sentence[processed_index:].strip().split()
|
||||
slots.extend([str(slots_list_all['O'])] * len(words_list))
|
||||
|
||||
slots = slots[1:-1]
|
||||
slot = ' '.join(slots)
|
||||
outfiles[mode + '_slots'].write(slot + '\n')
|
||||
|
||||
outfiles[mode + '_slots'].close()
|
||||
outfiles[mode].close()
|
||||
|
||||
outfiles['dict_slots'].close()
|
||||
outfiles['dict_intents'].close()
|
||||
|
||||
return outfold
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Parse the command-line arguments.
|
||||
parser = argparse.ArgumentParser(description="Process and convert datasets into NeMo\'s format.")
|
||||
parser.add_argument(
|
||||
"--dataset_name", required=True, type=str, choices=['atis', 'snips', 'jarvis', 'assistant'],
|
||||
)
|
||||
parser.add_argument(
|
||||
"--source_data_dir", required=True, type=str, help='path to the folder containing the dataset files'
|
||||
)
|
||||
parser.add_argument("--target_data_dir", required=True, type=str, help='path to save the processed dataset')
|
||||
parser.add_argument("--do_lower_case", action='store_true')
|
||||
parser.add_argument(
|
||||
"--ignore_prev_intent",
|
||||
action='store_true',
|
||||
help='ignores previous intent while importing datasets in jarvis\'s format',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
dataset_name = args.dataset_name
|
||||
source_dir = args.source_data_dir
|
||||
target_dir = args.target_data_dir
|
||||
|
||||
if not exists(source_dir):
|
||||
raise FileNotFoundError(f"{source_dir} does not exist.")
|
||||
|
||||
if dataset_name == 'atis':
|
||||
process_atis(infold=source_dir, outfold=target_dir, do_lower_case=args.do_lower_case)
|
||||
elif dataset_name == 'snips':
|
||||
process_snips(infold=source_dir, outfold=target_dir, do_lower_case=args.do_lower_case)
|
||||
elif dataset_name == 'jarvis':
|
||||
process_jarvis_datasets(
|
||||
infold=source_dir,
|
||||
outfold=target_dir,
|
||||
modes=["train", "test", "dev"],
|
||||
do_lower_case=args.do_lower_case,
|
||||
ignore_prev_intent=args.ignore_prev_intent,
|
||||
)
|
||||
elif dataset_name == 'assistant':
|
||||
process_assistant(infold=source_dir, outfold=target_dir)
|
||||
else:
|
||||
raise ValueError(f'Dataset {dataset_name} is not supported.')
|
||||
@@ -0,0 +1,85 @@
|
||||
# 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 pytorch_lightning as pl
|
||||
from omegaconf import DictConfig, OmegaConf
|
||||
|
||||
from nemo.collections.nlp.models import IntentSlotClassificationModel
|
||||
from nemo.core.config import hydra_runner
|
||||
from nemo.utils import logging
|
||||
from nemo.utils.exp_manager import exp_manager
|
||||
|
||||
|
||||
@hydra_runner(config_path="conf", config_name="intent_slot_classification_config")
|
||||
def main(cfg: DictConfig) -> None:
|
||||
logging.info(f'Config Params:\n {OmegaConf.to_yaml(cfg)}')
|
||||
trainer = pl.Trainer(**cfg.trainer)
|
||||
exp_manager(trainer, cfg.get("exp_manager", None))
|
||||
|
||||
# initialize the model using the config file
|
||||
model = IntentSlotClassificationModel(cfg.model, trainer=trainer)
|
||||
|
||||
# training
|
||||
logging.info("================================================================================================")
|
||||
logging.info('Starting training...')
|
||||
trainer.fit(model)
|
||||
logging.info('Training finished!')
|
||||
|
||||
# Stop further testing as fast_dev_run does not save checkpoints
|
||||
if trainer.fast_dev_run:
|
||||
return
|
||||
|
||||
# after model training is done, you can load the model from the saved checkpoint
|
||||
# and evaluate it on a data file or on given queries.
|
||||
logging.info("================================================================================================")
|
||||
logging.info("Starting the testing of the trained model on test set...")
|
||||
logging.info("We will load the latest model saved checkpoint from the training...")
|
||||
|
||||
# for evaluation and inference you can load the previously trained model saved in .nemo file
|
||||
# like this in your code, but we will just reuse the trained model here
|
||||
# eval_model = IntentSlotClassificationModel.restore_from(restore_path=checkpoint_path)
|
||||
eval_model = model
|
||||
|
||||
# we will setup testing data reusing the same config (test section)
|
||||
eval_model.update_data_dir_for_testing(data_dir=cfg.model.data_dir)
|
||||
eval_model.setup_test_data(test_data_config=cfg.model.test_ds)
|
||||
|
||||
trainer.test(model=eval_model, ckpt_path=None, verbose=False)
|
||||
logging.info("Testing finished!")
|
||||
|
||||
# run an inference on a few examples
|
||||
logging.info("======================================================================================")
|
||||
logging.info("Evaluate the model on the given queries...")
|
||||
|
||||
# this will work well if you train the model on Assistant dataset
|
||||
# for your own dataset change the examples appropriately
|
||||
queries = [
|
||||
'set alarm for seven thirty am',
|
||||
'lower volume by fifty percent',
|
||||
'what is my schedule for tomorrow',
|
||||
]
|
||||
|
||||
pred_intents, pred_slots = eval_model.predict_from_examples(queries, cfg.model.test_ds)
|
||||
|
||||
logging.info('The prediction results of some sample queries with the trained model:')
|
||||
for query, intent, slots in zip(queries, pred_intents, pred_slots):
|
||||
logging.info(f'Query : {query}')
|
||||
logging.info(f'Predicted Intent: {intent}')
|
||||
logging.info(f'Predicted Slots: {slots}')
|
||||
|
||||
logging.info("Inference finished!")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user