mirror of
https://github.com/wassname/Castor.git
synced 2026-08-20 12:00:37 +08:00
* Add ReutersTrainer, ReutersEvaluator options in Factory classes * Add Reuters to Kim-CNN command line arguments * Fix SST dataset path according to changes in Kim-CNN args The dataset path in args.py was made to point at the dataset folder rather than dataset/SST folder. Hence SST folder was added to paths in the SST dataset class * Add Reuters dataset class, and support in __main__ * Add Reuters dataset trainers and evaluators * Remove debug print statement in reuters_evaluator * Fix rounding bug in reuters_trainer and reuters_evaluator * Add LSTM for baseline text classification measurements * Add eval metrics for lstm_baseline * Set batch_first param in lstm_baseline * Remove onnx args from lstm_baseline * Pack padded sequences in LSTM_baseline * Add TensorBoardX support for Reuters trainer * Add Arxiv Academic Paper Dataset (AAPD) * Add Hidden Bottleneck Layer to BiLSTM * Fix packing of padded tensors in Reuters * Add cmdline args for Hidden Bottleneck Layer for BiLSTM * Include pre-padding lengths in AAPD dataset * Remove duplication of preprocessing code in AAPD * Remove batch_size condition in ReutersTrainer * Add ignore_lengths option to ReutersTrainer and ReutersEvaluator * Add AAPDCharQuantized and ReutersCharQuantized * Rename Reuters_hierarchical to ReutersHierarchical * Add CharacterCNN for document classification * Update README.md for CharacterCNN * Fix table in README.md for CharacterCNN * Add AAPDHierarchical for HAN * Update HAN for changes in Reuters dataset endpoints * Fix bug in CharCNN when running on CPU * Add AAPD dataset support for KimCNN * Fix dataset paths for SST-1 * Fix dimensions of FC1 in CharCNN * Add model checkpointing for Reuters based on F1 * Refactor LSTM baseline __main__ * Add precision, recall and F1 to Reuters evaluator * Checkpoint only at the end of an epoch for ReutersTrainer Add detailed log printing for dev evaluations * Fix log_template and dev_log_template in ReutersTrainer * Add IMDB dataset * Fix duplicate printing of header in ReutersTrainer * Add support for single_label datasets in ReutersTrainer * Add support for IMDB dataset in lstm_baseline and lstm_reg * Fix evaluator call in main method of HAN * Add IMDB for HAN * Fix for single_label * Fix evaluate_dataset method for single_label datasets * Reduce default patience to 5 epochs before early stopping * Revert change to save_state rather than the entire model * Add Yelp 2018 dataset * Integrate Yelp2018 with LSTM baseline * Replace Yelp2018 with Yelp2014 dataset * Add Yelp2014 to LSTM Baseline * Integrate Yelp14 into LSTM Regularization * Remove dropout in HBL for LSTM Baseline and Reg * Add Yelp for HAN * Fix the saving issue for HAN * Fix loading for HAN * Fix typo in ReutersEvaluator * Print to STDOUT rather than logger * Print XML-CNN eval to STDOUT rather than logger * Update max_length for IMDB dataset * Add single_label support for char_cnn * Fix evaluation method for char_cnn * Remove unwanted parameters from ReutersTrainer and ReutersEval * Fix code formatting in lstm_reg/args * Add support for IMDB and Yelp in KimCNN * Fix single_label incorporation * Remove unnecessary conditions * Fix num_classes in Yelp2014 * Add single_label support for XML-CNN * Fix call to evaluator in XML-CNN * Address PEP8 issues * Address PEP8 issues * Address PEP8 issues * Address PEP8 issues
162 lines
6.5 KiB
Python
162 lines
6.5 KiB
Python
from copy import deepcopy
|
|
import logging
|
|
import random
|
|
|
|
import numpy as np
|
|
import torch
|
|
import torch.onnx
|
|
import torch.nn.functional as F
|
|
from sklearn import metrics
|
|
|
|
from common.evaluation import EvaluatorFactory
|
|
from common.train import TrainerFactory
|
|
from datasets.sst import SST1
|
|
from datasets.sst import SST2
|
|
from datasets.reuters import Reuters
|
|
from datasets.aapd import AAPD
|
|
from datasets.yelp2014 import Yelp2014
|
|
from datasets.imdb import IMDB
|
|
from xml_cnn.args import get_args
|
|
from xml_cnn.model import XmlCNN
|
|
|
|
|
|
class UnknownWordVecCache(object):
|
|
"""
|
|
Caches the first randomly generated word vector for a certain size to make it is reused.
|
|
"""
|
|
cache = {}
|
|
|
|
@classmethod
|
|
def unk(cls, tensor):
|
|
size_tup = tuple(tensor.size())
|
|
if size_tup not in cls.cache:
|
|
cls.cache[size_tup] = torch.Tensor(tensor.size())
|
|
# choose 0.25 so unknown vectors have approximately same variance as pre-trained ones
|
|
# same as original implementation: https://github.com/yoonkim/CNN_sentence/blob/0a626a048757d5272a7e8ccede256a434a6529be/process_data.py#L95
|
|
cls.cache[size_tup].uniform_(-0.25, 0.25)
|
|
return cls.cache[size_tup]
|
|
|
|
|
|
def get_logger():
|
|
logger = logging.getLogger(__name__)
|
|
logger.setLevel(logging.INFO)
|
|
|
|
ch = logging.StreamHandler()
|
|
ch.setLevel(logging.DEBUG)
|
|
formatter = logging.Formatter('%(levelname)s - %(message)s')
|
|
ch.setFormatter(formatter)
|
|
logger.addHandler(ch)
|
|
|
|
return logger
|
|
|
|
|
|
def evaluate_dataset(split_name, dataset_cls, model, embedding, loader, batch_size, device, single_label):
|
|
saved_model_evaluator = EvaluatorFactory.get_evaluator(dataset_cls, model, embedding, loader, batch_size, device)
|
|
saved_model_evaluator.single_label = single_label
|
|
scores, metric_names = saved_model_evaluator.get_scores()
|
|
print('Evaluation metrics for', split_name)
|
|
print(metric_names)
|
|
print(scores)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# Set default configuration in : args.py
|
|
args = get_args()
|
|
|
|
# Set random seed for reproducibility
|
|
torch.manual_seed(args.seed)
|
|
torch.backends.cudnn.deterministic = True
|
|
if not args.cuda:
|
|
args.gpu = -1
|
|
if torch.cuda.is_available() and args.cuda:
|
|
print('Note: You are using GPU for training')
|
|
torch.cuda.set_device(args.gpu)
|
|
torch.cuda.manual_seed(args.seed)
|
|
if torch.cuda.is_available() and not args.cuda:
|
|
print('Warning: You have Cuda but not use it. You are using CPU for training.')
|
|
np.random.seed(args.seed)
|
|
random.seed(args.seed)
|
|
logger = get_logger()
|
|
|
|
dataset_map = {
|
|
'SST-1': SST1,
|
|
'SST-2': SST2,
|
|
'Reuters': Reuters,
|
|
'AAPD': AAPD,
|
|
'IMDB': IMDB,
|
|
'Yelp2014':Yelp2014
|
|
}
|
|
if args.dataset not in dataset_map:
|
|
raise ValueError('Unrecognized dataset')
|
|
else:
|
|
train_iter, dev_iter, test_iter = dataset_map[args.dataset].iters(args.data_dir, args.word_vectors_file, args.word_vectors_dir, batch_size=args.batch_size, device=args.gpu, unk_init=UnknownWordVecCache.unk)
|
|
|
|
config = deepcopy(args)
|
|
config.dataset = train_iter.dataset
|
|
config.target_class = train_iter.dataset.NUM_CLASSES
|
|
config.words_num = len(train_iter.dataset.TEXT_FIELD.vocab)
|
|
|
|
print('Dataset {} Mode {}'.format(args.dataset, args.mode))
|
|
print('VOCAB num',len(train_iter.dataset.TEXT_FIELD.vocab))
|
|
print('LABEL.target_class:', train_iter.dataset.NUM_CLASSES)
|
|
print('Train instance', len(train_iter.dataset))
|
|
print('Dev instance', len(dev_iter.dataset))
|
|
print('Test instance', len(test_iter.dataset))
|
|
|
|
if args.resume_snapshot:
|
|
if args.cuda:
|
|
model = torch.load(args.resume_snapshot, map_location=lambda storage, location: storage.cuda(args.gpu))
|
|
else:
|
|
model = torch.load(args.resume_snapshot, map_location=lambda storage, location: storage)
|
|
else:
|
|
model = XmlCNN(config)
|
|
if args.cuda:
|
|
model.cuda()
|
|
print('Shift model to GPU')
|
|
|
|
parameter = filter(lambda p: p.requires_grad, model.parameters())
|
|
#optimizer = torch.optim.Adadelta(parameter, lr=args.lr, weight_decay=args.weight_decay)
|
|
optimizer = torch.optim.Adam(parameter, lr = args.lr)
|
|
|
|
if args.dataset not in dataset_map:
|
|
raise ValueError('Unrecognized dataset')
|
|
else:
|
|
train_evaluator = EvaluatorFactory.get_evaluator(dataset_map[args.dataset], model, None, train_iter, args.batch_size, args.gpu)
|
|
test_evaluator = EvaluatorFactory.get_evaluator(dataset_map[args.dataset], model, None, test_iter, args.batch_size, args.gpu)
|
|
dev_evaluator = EvaluatorFactory.get_evaluator(dataset_map[args.dataset], model, None, dev_iter, args.batch_size, args.gpu)
|
|
train_evaluator.single_label = args.single_label
|
|
test_evaluator.single_label = args.single_label
|
|
dev_evaluator.single_label = args.single_label
|
|
trainer_config = {
|
|
'optimizer': optimizer,
|
|
'batch_size': args.batch_size,
|
|
'log_interval': args.log_every,
|
|
'dev_log_interval': args.dev_every,
|
|
'patience': args.patience,
|
|
'model_outfile': args.save_path, # actually a directory, using model_outfile to conform to Trainer naming convention
|
|
'logger': logger,
|
|
'single_label': args.single_label
|
|
}
|
|
trainer = TrainerFactory.get_trainer(args.dataset, model, None, train_iter, trainer_config, train_evaluator, test_evaluator, dev_evaluator)
|
|
|
|
if not args.trained_model:
|
|
trainer.train(args.epochs)
|
|
else:
|
|
if args.cuda:
|
|
model = torch.load(args.trained_model, map_location=lambda storage, location: storage.cuda(args.gpu))
|
|
else:
|
|
model = torch.load(args.trained_model, map_location=lambda storage, location: storage)
|
|
|
|
if args.dataset not in dataset_map:
|
|
raise ValueError('Unrecognized dataset')
|
|
else:
|
|
evaluate_dataset('dev', dataset_map[args.dataset], model, None, dev_iter, args.batch_size, args.gpu, args.single_label)
|
|
evaluate_dataset('test', dataset_map[args.dataset], model, None, test_iter, args.batch_size, args.gpu, args.single_label)
|
|
|
|
if args.onnx:
|
|
device = torch.device('cuda') if torch.cuda.is_available() and args.cuda else torch.device('cpu')
|
|
dummy_input = torch.zeros(args.onnx_batch_size, args.onnx_sent_len, dtype=torch.long, device=device)
|
|
onnx_filename = 'xmlcnn_{}.onnx'.format(args.mode)
|
|
torch.onnx.export(model, dummy_input, onnx_filename)
|
|
print('Exported model in ONNX format as {}'.format(onnx_filename))
|