├── .gitignore ├── README.md ├── config.py ├── layers ├── __init__.py ├── attention.py ├── folding.py └── kmaxpooling.py ├── models ├── __init__.py ├── base_model.py ├── keras_base_model.py ├── keras_bilstm_model.py ├── keras_cnnrnn_model.py ├── keras_dcnn_model.py ├── keras_dpcnn_model.py ├── keras_han_model.py ├── keras_multi_text_cnn_model.py ├── keras_rcnn_model.py ├── keras_rnncnn_model.py ├── keras_text_cnn_model.py └── keras_vdcnn_model.py └── utils ├── __init__.py └── metrics.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | .idea/ 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Text Classification 2 | 3 | All kinds of neural text classififers implemented by Keras (tensorflow backend). 4 | 5 | ### Models 6 | 7 | - [TextCNN, EMNLP2014](https://www.aclweb.org/anthology/D14-1181) 8 | Kim et al. Convolutional Neural Networks for Sentence Classification. 9 | 10 | - [DCNN, ACL2014](http://www.aclweb.org/anthology/P14-1062) 11 | Kalchbrenner et al. A Convolutional Neural Network for Modelling Sentences 12 | 13 | - [RCNN, AAAI2015](https://www.aaai.org/ocs/index.php/AAAI/AAAI15/paper/download/9745/9552) 14 | Lai et al. Recurrent Convolutional Neural Networks for Text Classification. 15 | 16 | - [HAN, NAACL-HLT2016](http://www.aclweb.org/anthology/N16-1174) 17 | Yang et al. Hierarchical Attention Networks for Document Classification. 18 | 19 | - [DPCNN, ACL2017](https://ai.tencent.com/ailab/media/publications/ACL3-Brady.pdf) 20 | Johnson et al. Deep Pyramid Convolutional Neural Networks for Text Categorization. 21 | 22 | - [VDCNN, EACL2017](http://www.aclweb.org/anthology/E17-1104) 23 | Conneau et al. Very Deep Convolutional Networks for Text Classification. 24 | 25 | - MultiTextCNN 26 | Extension of textcnn, stacking multiple cnns with the same filter size. 27 | 28 | - BiLSTM 29 | Bidirectional lstm + max pooling over time. 30 | 31 | - RNNCNN 32 | Bidirectional gru + conv + max pooling & avg pooling. 33 | 34 | - CNNRNN 35 | conv + max pooling + Bidirectional gru + max pooling over time. 36 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: config.py 10 | 11 | @time: 2019/2/8 8:44 12 | 13 | @desc: 14 | 15 | """ 16 | from keras.optimizers import Adam 17 | 18 | 19 | class Config(object): 20 | def __init__(self): 21 | # input configuration 22 | self.input_level = 'word' 23 | self.word_max_len = 128 24 | self.char_max_len = 200 25 | self.max_len = {'word': self.word_max_len, 26 | 'char': self.char_max_len 27 | } 28 | self.han_max_sent = 10 29 | self.word_embed_dim = 300 30 | self.word_embed_type = 'glove' 31 | self.word_embed_trainable = False 32 | self.word_embeddings = None 33 | 34 | # model structure configuration 35 | self.exp_name = None 36 | self.model_name = None 37 | self.rnn_units = 300 38 | self.dense_units = 512 39 | 40 | # model training configuration 41 | self.batch_size = 128 42 | self.n_epoch = 50 43 | self.learning_rate = 0.001 44 | self.optimizer = Adam(self.learning_rate) 45 | self.dropout = 0.5 46 | self.l2_reg = 0.001 47 | 48 | # output configuration 49 | self.n_class = 3 50 | 51 | # checkpoint configuration 52 | self.checkpoint_dir = 'ckpt' 53 | self.checkpoint_monitor = 'val_acc' 54 | self.checkpoint_save_best_only = True 55 | self.checkpoint_save_weights_only = True 56 | self.checkpoint_save_weights_mode = 'max' 57 | self.checkpoint_verbose = 1 58 | 59 | # early_stopping configuration 60 | self.early_stopping_monitor = 'val_acc' 61 | self.early_stopping_mode = 'max' 62 | self.early_stopping_patience = 5 63 | self.early_stopping_verbose = 1 64 | 65 | -------------------------------------------------------------------------------- /layers/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: __init__.py.py 10 | 11 | @time: 2019/2/8 8:41 12 | 13 | @desc: 14 | 15 | """ -------------------------------------------------------------------------------- /layers/attention.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: attention.py 10 | 11 | @time: 2019/2/8 13:36 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | from keras import backend as K, initializers, regularizers, constraints 18 | from keras.engine.topology import Layer 19 | 20 | 21 | class SelfAttention(Layer): 22 | """ 23 | Attention operation, with a context/query vector, for temporal data. 24 | Supports Masking. 25 | Follows the work of Yang et al. [https://www.cs.cmu.edu/~diyiy/docs/naacl16.pdf] 26 | "Hierarchical Attention Networks for Document Classification" 27 | by using a context vector to assist the attention 28 | # Input shape 29 | 3D tensor with shape: `(samples, steps, features)`. 30 | # Output shape 31 | 2D tensor with shape: `(samples, features)`. 32 | How to use: 33 | Just put it on top of an RNN Layer (GRU/LSTM/SimpleRNN) with return_sequences=True. 34 | The dimensions are inferred based on the output shape of the RNN. 35 | e: The layer has been tested with Keras 2.0.6 36 | Example: 37 | model.add(LSTM(64, return_sequences=True)) 38 | model.add(AttentionWithContext()) 39 | # next add a Dense layer (for classification/regression) or whatever... 40 | """ 41 | 42 | def __init__(self, W_regularizer=None, u_regularizer=None, b_regularizer=None, W_constraint=None, 43 | u_constraint=None, b_constraint=None, bias=False, return_score=False, **kwargs): 44 | self.supports_masking = True 45 | self.return_score = return_score 46 | 47 | self.init = initializers.get('glorot_uniform') 48 | 49 | self.W_regularizer = regularizers.get(W_regularizer) 50 | self.u_regularizer = regularizers.get(u_regularizer) 51 | self.b_regularizer = regularizers.get(b_regularizer) 52 | 53 | self.W_constraint = constraints.get(W_constraint) 54 | self.u_constraint = constraints.get(u_constraint) 55 | self.b_constraint = constraints.get(b_constraint) 56 | 57 | self.bias = bias 58 | super(SelfAttention, self).__init__(**kwargs) 59 | 60 | def build(self, input_shape): 61 | assert len(input_shape) == 3 62 | 63 | self.W = self.add_weight((input_shape[-1], input_shape[-1],), 64 | initializer=self.init, 65 | name='{}_W'.format(self.name), 66 | regularizer=self.W_regularizer, 67 | constraint=self.W_constraint) 68 | if self.bias: 69 | self.b = self.add_weight((input_shape[-1],), 70 | initializer='zero', 71 | name='{}_b'.format(self.name), 72 | regularizer=self.b_regularizer, 73 | constraint=self.b_constraint) 74 | 75 | self.u = self.add_weight((input_shape[-1],), 76 | initializer=self.init, 77 | name='{}_u'.format(self.name), 78 | regularizer=self.u_regularizer, 79 | constraint=self.u_constraint) 80 | 81 | super(SelfAttention, self).build(input_shape) 82 | 83 | def compute_mask(self, input, input_mask=None): 84 | # do not pass the mask to the next layers 85 | return None 86 | 87 | def call(self, x, mask=None): 88 | uit = K.dot(x, self.W) 89 | 90 | if self.bias: 91 | uit += self.b 92 | 93 | uit = K.tanh(uit) 94 | ait = SelfAttention.dot_product(uit, self.u) 95 | 96 | a = K.exp(ait) 97 | 98 | # apply mask after the exp. will be re-normalized next 99 | if mask is not None: 100 | # Cast the mask to floatX to avoid float64 upcasting in theano 101 | a *= K.cast(mask, K.floatx()) 102 | 103 | # in some cases especially in the early stages of training the sum may be almost zero 104 | # and this results in NaN's. A workaround is to add a very small positive number ε to the sum. 105 | # a /= K.cast(K.sum(a, axis=1, keepdims=True), K.floatx()) 106 | a /= K.cast(K.sum(a, axis=1, keepdims=True) + K.epsilon(), K.floatx()) 107 | 108 | a = K.expand_dims(a) 109 | weighted_input = x * a 110 | 111 | if self.return_score: 112 | return K.sum(weighted_input, axis=1), a 113 | else: 114 | return K.sum(weighted_input, axis=1) 115 | 116 | def compute_output_shape(self, input_shape): 117 | if self.return_score: 118 | return [(input_shape[0], input_shape[-1]), (input_shape[0], input_shape[1])] 119 | return input_shape[0], input_shape[-1] 120 | 121 | @staticmethod 122 | def dot_product(x, kernel): 123 | """ 124 | Wrapper for dot product operation, in order to be compatible with both 125 | Theano and Tensorflow 126 | Args: 127 | x (): input 128 | kernel (): weights 129 | Returns: 130 | """ 131 | if K.backend() == 'tensorflow': 132 | return K.squeeze(K.dot(x, K.expand_dims(kernel)), axis=-1) 133 | else: 134 | return K.dot(x, kernel) 135 | -------------------------------------------------------------------------------- /layers/folding.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: folding.py 10 | 11 | @time: 2019/2/9 20:48 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | import tensorflow as tf 18 | from keras import backend as K 19 | from keras.engine.topology import Layer 20 | 21 | 22 | class Folding(Layer): 23 | def __init__(self, **kwargs): 24 | super(Folding, self).__init__(**kwargs) 25 | 26 | def build(self, input_shape): 27 | if len(input_shape) != 3: 28 | raise ValueError('Input into Folding Layer must be a 3D tensor!') 29 | super(Folding, self).build(input_shape) 30 | 31 | def call(self, inputs): 32 | # split the tensor along dimension 2 into dimension_axis_size/2 33 | # which will give us 2 tensors. 34 | # will raise ValueError if K.int_shape(inputs) is odd 35 | splits = tf.split(inputs, int(K.int_shape(inputs)[-1] / 2), axis=-1) 36 | 37 | # reduce sums of the pair of rows we have split onto 38 | reduce_sums = [tf.reduce_sum(split, axis=-1) for split in splits] 39 | 40 | # stack them up along the same axis we have reduced 41 | row_reduced = tf.stack(reduce_sums, axis=-1) 42 | return row_reduced 43 | 44 | def compute_output_shape(self, input_shape): 45 | return input_shape[0], input_shape[1], int(input_shape[2] / 2) 46 | -------------------------------------------------------------------------------- /layers/kmaxpooling.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: kmaxpooling.py 10 | 11 | @time: 2019/2/8 13:08 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | import tensorflow as tf 18 | from keras import backend as K 19 | from keras.engine.topology import Layer 20 | from tensorflow.contrib.framework import sort 21 | 22 | 23 | class KMaxPooling(Layer): 24 | """ 25 | Implemetation of temporal k-max pooling layer, which was first proposed in Kalchbrenner et al. 26 | [http://www.aclweb.org/anthology/P14-1062] 27 | "A Convolutional Neural Network for Modelling Sentences" 28 | This layer allows to detect the k most important features in a sentence, independent of their 29 | specific position, preserving their relative order. 30 | """ 31 | def __init__(self, k=1, **kwargs): 32 | self.k = k 33 | 34 | super(KMaxPooling, self).__init__(**kwargs) 35 | 36 | def build(self, input_shape): 37 | if len(input_shape) != 3: 38 | raise ValueError('Input into KMaxPooling muse be a 3D tensor!') 39 | if self.k > input_shape[1]: 40 | raise ValueError('detect `%d` most important features from `%d` timesteps is not allowed' % 41 | (self.k, input_shape[1])) 42 | super(KMaxPooling, self).build(input_shape) 43 | 44 | def call(self, inputs): 45 | """ 46 | Reference: https://stackoverflow.com/questions/51299181/how-to-implement-k-max-pooling-in-tensorflow-or-keras 47 | The key point is preserving the relative order 48 | """ 49 | permute_inputs = K.permute_dimensions(inputs, (0, 2, 1)) 50 | flat_permute_inputs = tf.reshape(permute_inputs, (-1,)) 51 | topk_indices = sort(tf.nn.top_k(permute_inputs, k=self.k)[1]) 52 | 53 | all_indices = tf.reshape(tf.range(K.shape(flat_permute_inputs)[0]), K.shape(permute_inputs)) 54 | to_sum_indices = tf.expand_dims(tf.gather(all_indices, 0, axis=-1), axis=-1) 55 | topk_indices += to_sum_indices 56 | 57 | flat_topk_indices = tf.reshape(topk_indices, (-1, )) 58 | topk_output = tf.reshape(tf.gather(flat_permute_inputs, flat_topk_indices), K.shape(topk_indices)) 59 | 60 | return K.permute_dimensions(topk_output, (0, 2, 1)) 61 | 62 | def compute_output_shape(self, input_shape): 63 | return input_shape[0], self.k, input_shape[-1] -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: __init__.py.py 10 | 11 | @time: 2019/2/8 8:41 12 | 13 | @desc: 14 | 15 | """ -------------------------------------------------------------------------------- /models/base_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: base_model.py 10 | 11 | @time: 2019/2/1 14:03 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | import abc 18 | 19 | 20 | class BaseModel(object): 21 | def __init__(self): 22 | super(BaseModel, self).__init__() 23 | 24 | self.model = None 25 | 26 | @abc.abstractmethod 27 | def build(self): 28 | """Build the model""" 29 | 30 | @abc.abstractmethod 31 | def train(self, data_train, data_dev): 32 | """Train the model""" 33 | 34 | @abc.abstractmethod 35 | def load_weights(self, filename): 36 | """Load weights from the `filename`""" 37 | 38 | @abc.abstractmethod 39 | def evaluate(self, data): 40 | """Evaluate the model on the provided data""" 41 | 42 | @abc.abstractmethod 43 | def predict(self, data): 44 | """Predict for the provided data""" 45 | -------------------------------------------------------------------------------- /models/keras_base_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_base_model.py 10 | 11 | @time: 2019/2/3 17:14 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | import os 18 | import abc 19 | import logging 20 | 21 | from keras.callbacks import ModelCheckpoint, EarlyStopping 22 | from models.base_model import BaseModel 23 | from utils.metrics import eval_acc 24 | 25 | 26 | class KerasBaseModel(BaseModel): 27 | def __init__(self, config, **kwargs): 28 | super(KerasBaseModel, self).__init__() 29 | self.config = config 30 | self.level = self.config.input_level 31 | self.max_len = self.config.max_len[self.config.input_level] 32 | self.word_embeddings = config.word_embeddings 33 | self.n_class = config.n_class 34 | 35 | self.callbacks = [] 36 | self.init_callbacks() 37 | 38 | self.model = self.build(**kwargs) 39 | 40 | def init_callbacks(self): 41 | self.callbacks.append(ModelCheckpoint( 42 | filepath=os.path.join(self.config.checkpoint_dir, '%s.hdf5' % self.config.exp_name), 43 | monitor=self.config.checkpoint_monitor, 44 | save_best_only=self.config.checkpoint_save_best_only, 45 | save_weights_only=self.config.checkpoint_save_weights_only, 46 | mode=self.config.checkpoint_save_weights_mode, 47 | verbose=self.config.checkpoint_verbose 48 | )) 49 | 50 | self.callbacks.append(EarlyStopping( 51 | monitor=self.config.early_stopping_monitor, 52 | mode=self.config.early_stopping_mode, 53 | patience=self.config.early_stopping_patience, 54 | verbose=self.config.early_stopping_verbose 55 | )) 56 | 57 | def load_weights(self, filename): 58 | self.model.load_weights(filename) 59 | 60 | def load_best_model(self): 61 | logging.info('loading model checkpoint: %s.hdf5\n' % self.config.exp_name) 62 | self.load_weights(os.path.join(self.config.checkpoint_dir, '%s.hdf5' % self.config.exp_name)) 63 | logging.info('Model loaded') 64 | 65 | @abc.abstractmethod 66 | def build(self): 67 | """Build the model""" 68 | 69 | def train(self, data_train, data_dev=None): 70 | x_train, y_train = data_train 71 | 72 | logging.info('start training...') 73 | self.model.fit(x=x_train, y=y_train, batch_size=self.config.batch_size, epochs=self.config.n_epoch, 74 | validation_split=0.1, validation_data=data_dev, callbacks=self.callbacks) 75 | logging.info('training end...') 76 | 77 | def evaluate(self, data): 78 | input_data, label = data 79 | prediction = self.predict(input_data) 80 | acc = eval_acc(label, prediction) 81 | logging.info('acc : %f', acc) 82 | return acc 83 | 84 | def predict(self, data): 85 | return self.model.predict(data) 86 | -------------------------------------------------------------------------------- /models/keras_bilstm_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_bilstm_model.py 10 | 11 | @time: 2019/2/8 11:00 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | from keras.models import Model 18 | from keras.layers import Input, Embedding, SpatialDropout1D, Dense, LSTM, Bidirectional, Lambda 19 | import keras.backend as K 20 | 21 | from models.keras_base_model import KerasBaseModel 22 | 23 | 24 | class BiLSTM(KerasBaseModel): 25 | def __init__(self, config, **kwargs): 26 | super(BiLSTM, self).__init__(config, **kwargs) 27 | 28 | def build(self): 29 | input_text = Input(shape=(self.max_len,)) 30 | 31 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 32 | weights=[self.word_embeddings], 33 | trainable=self.config.word_embed_trainable, mask_zero=True)(input_text) 34 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 35 | 36 | hidden_states = Bidirectional(LSTM(units=self.config.rnn_units, return_sequences=True))(text_embed) 37 | global_max_pooling = Lambda(lambda x: K.max(x, axis=1)) # GlobalMaxPooling1D didn't support masking 38 | sentence_embed = global_max_pooling(hidden_states) 39 | 40 | dense_layer = Dense(256, activation='relu')(sentence_embed) 41 | output = Dense(self.n_class, activation='softmax')(dense_layer) 42 | 43 | model = Model(input_text, output) 44 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 45 | return model 46 | -------------------------------------------------------------------------------- /models/keras_cnnrnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_cnnrnn_model.py 10 | 11 | @time: 2019/2/11 19:19 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | 18 | from keras.models import Model 19 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, GRU, concatenate, Dense, Bidirectional, \ 20 | MaxPooling1D, GlobalMaxPooling1D 21 | 22 | from models.keras_base_model import KerasBaseModel 23 | 24 | 25 | class CNNRNN(KerasBaseModel): 26 | def __init__(self, config): 27 | super(CNNRNN, self).__init__(config) 28 | 29 | def build(self): 30 | input_text = Input(shape=(self.max_len,)) 31 | 32 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 33 | weights=[self.word_embeddings], 34 | trainable=self.config.word_embed_trainable)(input_text) 35 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 36 | 37 | conv_layer = Conv1D(300, kernel_size=3, padding="valid", activation='relu')(text_embed) 38 | conv_max_pool = MaxPooling1D(pool_size=2)(conv_layer) 39 | 40 | gru_layer = Bidirectional(GRU(self.config.rnn_units, return_sequences=True))(conv_max_pool) 41 | sentence_embed = GlobalMaxPooling1D()(gru_layer) 42 | 43 | dense_layer = Dense(256, activation='relu')(sentence_embed) 44 | if self.config.loss_function == 'binary_crossentropy': 45 | output = Dense(1, activation='sigmoid')(dense_layer) 46 | else: 47 | output = Dense(self.n_class, activation='softmax')(dense_layer) 48 | 49 | model = Model(input_text, output) 50 | model.compile(loss=self.config.loss_function, metrics=['acc'], optimizer=self.config.optimizer) 51 | return model 52 | -------------------------------------------------------------------------------- /models/keras_dcnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_dcnn_model.py 10 | 11 | @time: 2019/2/8 13:03 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | from keras.models import Model 18 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, Flatten, Dense, ZeroPadding1D, ReLU 19 | 20 | from models.keras_base_model import KerasBaseModel 21 | from layers.kmaxpooling import KMaxPooling 22 | from layers.folding import Folding 23 | 24 | 25 | class DCNN(KerasBaseModel): 26 | def __init__(self, config, **kwargs): 27 | super(DCNN, self).__init__(config, **kwargs) 28 | 29 | def build(self): 30 | input_text = Input(shape=(self.max_len,)) 31 | 32 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 33 | weights=[self.word_embeddings], 34 | trainable=self.config.word_embed_trainable)(input_text) 35 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 36 | 37 | # wide convolution 38 | zero_padded_1 = ZeroPadding1D((6, 6))(text_embed) 39 | conv_1 = Conv1D(filters=128, kernel_size=7, strides=1, padding='valid')(zero_padded_1) 40 | # dynamic k-max pooling 41 | k_maxpool_1 = KMaxPooling(int(self.max_len / 3 * 2))(conv_1) 42 | # non-linear feature function 43 | non_linear_1 = ReLU()(k_maxpool_1) 44 | 45 | # wide convolution 46 | zero_padded_2 = ZeroPadding1D((4, 4))(non_linear_1) 47 | conv_2 = Conv1D(filters=128, kernel_size=5, strides=1, padding='valid')(zero_padded_2) 48 | # dynamic k-max pooling 49 | k_maxpool_2 = KMaxPooling(int(self.max_len / 3 * 1))(conv_2) 50 | # non-linear feature function 51 | non_linear_2 = ReLU()(k_maxpool_2) 52 | 53 | # wide convolution 54 | zero_padded_3 = ZeroPadding1D((2, 2))(non_linear_2) 55 | conv_3 = Conv1D(filters=128, kernel_size=5, strides=1, padding='valid')(zero_padded_3) 56 | # folding 57 | folded = Folding()(conv_3) 58 | # dynamic k-max pooling 59 | k_maxpool_3 = KMaxPooling(k=10)(folded) 60 | # non-linear feature function 61 | non_linear_3 = ReLU()(k_maxpool_3) 62 | 63 | sentence_embed = Flatten()(non_linear_3) 64 | 65 | dense_layer = Dense(256, activation='relu')(sentence_embed) 66 | output = Dense(self.n_class, activation='softmax')(dense_layer) 67 | 68 | model = Model(input_text, output) 69 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 70 | return model 71 | -------------------------------------------------------------------------------- /models/keras_dpcnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_dpcnn_model.py 10 | 11 | @time: 2019/2/8 12:51 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | 18 | from keras.models import Model 19 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, Flatten, Dense, Activation, Add, MaxPooling1D 20 | 21 | from models.keras_base_model import KerasBaseModel 22 | 23 | 24 | class DPCNN(KerasBaseModel): 25 | def __init__(self, config, **kwargs): 26 | super(DPCNN, self).__init__(config, **kwargs) 27 | 28 | def build(self): 29 | input_text = Input(shape=(self.max_len,)) 30 | 31 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 32 | weights=[self.word_embeddings], 33 | trainable=self.config.word_embed_trainable)(input_text) 34 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 35 | 36 | repeat = 3 37 | size = self.max_len 38 | region_x = Conv1D(filters=250, kernel_size=3, padding='same', strides=1)(text_embed) 39 | x = Activation(activation='relu')(region_x) 40 | x = Conv1D(filters=250, kernel_size=3, padding='same', strides=1)(x) 41 | x = Activation(activation='relu')(x) 42 | x = Conv1D(filters=250, kernel_size=3, padding='same', strides=1)(x) 43 | x = Add()([x, region_x]) 44 | 45 | for _ in range(repeat): 46 | px = MaxPooling1D(pool_size=3, strides=2, padding='same')(x) 47 | size = int((size + 1) / 2) 48 | x = Activation(activation='relu')(px) 49 | x = Conv1D(filters=250, kernel_size=3, padding='same', strides=1)(x) 50 | x = Activation(activation='relu')(x) 51 | x = Conv1D(filters=250, kernel_size=3, padding='same', strides=1)(x) 52 | x = Add()([x, px]) 53 | 54 | x = MaxPooling1D(pool_size=size)(x) 55 | sentence_embed = Flatten()(x) 56 | 57 | dense_layer = Dense(256, activation='relu')(sentence_embed) 58 | output = Dense(self.n_class, activation='softmax')(dense_layer) 59 | 60 | model = Model(input_text, output) 61 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 62 | return model 63 | -------------------------------------------------------------------------------- /models/keras_han_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_han_model.py 10 | 11 | @time: 2019/2/8 13:22 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | 18 | from keras.models import Model 19 | from keras.layers import Input, Embedding, Dense, Bidirectional, GRU, Masking, TimeDistributed 20 | 21 | from models.keras_base_model import KerasBaseModel 22 | from layers.attention import SelfAttention 23 | 24 | 25 | class HAN(KerasBaseModel): 26 | def __init__(self, config, **kwargs): 27 | super(HAN, self).__init__(config, **kwargs) 28 | 29 | def build(self): 30 | input_text = Input(shape=(self.config.han_max_sent, self.max_len)) 31 | 32 | sent_encoded = TimeDistributed(self.word_encoder())(input_text) # word encoder 33 | sent_vectors = TimeDistributed(SelfAttention(bias=True))(sent_encoded) # word attention 34 | 35 | doc_encoded = self.sentence_encoder()(sent_vectors) # sentence encoder 36 | doc_vector = SelfAttention(bias=True)(doc_encoded) # sentence attention 37 | 38 | dense_layer = Dense(256, activation='relu')(doc_vector) 39 | output = Dense(self.n_class, activation='softmax')(dense_layer) 40 | 41 | model = Model(input_text, output) 42 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 43 | return model 44 | 45 | def word_encoder(self): 46 | input_words = Input(shape=(self.max_len,)) 47 | word_vectors = Embedding(input_dim=self.word_embeddings.shape[0], output_dim=self.word_embeddings.shape[1], 48 | weights=[self.word_embeddings], mask_zero=True, 49 | trainable=self.config.word_embed_trainable)(input_words) 50 | sent_encoded = Bidirectional(GRU(self.config.rnn_units, return_sequences=True))(word_vectors) 51 | return Model(input_words, sent_encoded) 52 | 53 | def sentence_encoder(self): 54 | input_sents = Input(shape=(self.config.han_max_sent, self.config.rnn_units * 2)) 55 | sents_masked = Masking()(input_sents) # support masking 56 | doc_encoded = Bidirectional(GRU(self.config.rnn_units, return_sequences=True))(sents_masked) 57 | return Model(input_sents, doc_encoded) 58 | -------------------------------------------------------------------------------- /models/keras_multi_text_cnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_multi_text_cnn_model.py 10 | 11 | @time: 2019/2/8 10:55 12 | 13 | @desc: 14 | 15 | """ 16 | from keras.models import Model 17 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, Flatten, concatenate, Dense, MaxPooling1D, \ 18 | BatchNormalization 19 | 20 | from models.keras_base_model import KerasBaseModel 21 | 22 | 23 | class MultiTextCNN(KerasBaseModel): 24 | def __init__(self, config, **kwargs): 25 | super(MultiTextCNN, self).__init__(config, **kwargs) 26 | 27 | def build(self): 28 | input_text = Input(shape=(self.max_len,)) 29 | 30 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 31 | weights=[self.word_embeddings], 32 | trainable=self.config.word_embed_trainable)(input_text) 33 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 34 | 35 | filter_lengths = [2, 3, 4, 5] 36 | conv_layers = [] 37 | for filter_length in filter_lengths: 38 | conv_layer_1 = Conv1D(filters=300, kernel_size=filter_length, strides=1, 39 | padding='valid', activation='relu')(text_embed) 40 | bn_layer_1 = BatchNormalization()(conv_layer_1) 41 | conv_layer_2 = Conv1D(filters=300, kernel_size=filter_length, strides=1, 42 | padding='valid', activation='relu')(bn_layer_1) 43 | bn_layer_2 = BatchNormalization()(conv_layer_2) 44 | maxpooling = MaxPooling1D(pool_size=self.max_len - 2 * filter_length + 2)(bn_layer_2) 45 | flatten = Flatten()(maxpooling) 46 | conv_layers.append(flatten) 47 | sentence_embed = concatenate(inputs=conv_layers) 48 | 49 | dense_layer = Dense(256, activation='relu')(sentence_embed) 50 | output = Dense(self.n_class, activation='softmax')(dense_layer) 51 | 52 | model = Model(input_text, output) 53 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 54 | return model 55 | -------------------------------------------------------------------------------- /models/keras_rcnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_rcnn_model.py 10 | 11 | @time: 2019/2/8 12:57 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | from keras.models import Model 18 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, Flatten, Dense, Lambda, LSTM, concatenate 19 | import keras.backend as K 20 | 21 | from models.keras_base_model import KerasBaseModel 22 | 23 | 24 | class RCNN(KerasBaseModel): 25 | def __init__(self, config, **kwargs): 26 | super(RCNN, self).__init__(config, **kwargs) 27 | 28 | def build(self): 29 | input_text = Input(shape=(self.max_len,)) 30 | 31 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 32 | weights=[self.word_embeddings], 33 | trainable=self.config.word_embed_trainable)(input_text) 34 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 35 | 36 | # We shift the document to the right to obtain the left-side contexts 37 | l_embedding = Lambda(lambda x: K.concatenate([K.zeros(shape=(K.shape(x)[0], 1, K.shape(x)[-1])), 38 | x[:, :-1]], axis=1))(text_embed) 39 | # We shift the document to the left to obtain the right-side contexts 40 | r_embedding = Lambda(lambda x: K.concatenate([K.zeros(shape=(K.shape(x)[0], 1, K.shape(x)[-1])), 41 | x[:, 1:]], axis=1))(text_embed) 42 | # use LSTM RNNs instead of vanilla RNNs as described in the paper. 43 | forward = LSTM(self.config.rnn_units, return_sequences=True)(l_embedding) # See equation (1) 44 | backward = LSTM(self.config.rnn_units, return_sequences=True, go_backwards=True)(r_embedding) # See equation (2) 45 | # Keras returns the output sequences in reverse order. 46 | backward = Lambda(lambda x: K.reverse(x, axes=1))(backward) 47 | together = concatenate([forward, text_embed, backward], axis=2) # See equation (3). 48 | 49 | # use conv1D instead of TimeDistributed and Dense 50 | semantic = Conv1D(self.config.rnn_units, kernel_size=1, activation="tanh")(together) # See equation (4). 51 | sentence_embed = Lambda(lambda x: K.max(x, axis=1))(semantic) # See equation (5). 52 | 53 | dense_layer = Dense(256, activation='relu')(sentence_embed) 54 | output = Dense(self.n_class, activation='softmax')(dense_layer) 55 | 56 | model = Model(input_text, output) 57 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 58 | return model 59 | -------------------------------------------------------------------------------- /models/keras_rnncnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_rnncnn_model.py 10 | 11 | @time: 2019/2/8 11:05 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | from keras.models import Model 18 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, GRU, concatenate, Dense, Bidirectional, \ 19 | GlobalAveragePooling1D, GlobalMaxPooling1D 20 | 21 | from models.keras_base_model import KerasBaseModel 22 | 23 | 24 | class RNNCNN(KerasBaseModel): 25 | def __init__(self, config, **kwargs): 26 | super(RNNCNN, self).__init__(config, **kwargs) 27 | 28 | def build(self): 29 | input_text = Input(shape=(self.max_len,)) 30 | 31 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 32 | weights=[self.word_embeddings], 33 | trainable=self.config.word_embed_trainable)(input_text) 34 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 35 | 36 | gru_layer = Bidirectional(GRU(self.config.rnn_units, return_sequences=True))(text_embed) 37 | 38 | conv_layer = Conv1D(64, kernel_size=2, padding="valid", kernel_initializer="he_uniform")(gru_layer) 39 | 40 | avg_pool = GlobalAveragePooling1D()(conv_layer) 41 | max_pool = GlobalMaxPooling1D()(conv_layer) 42 | sentence_embed = concatenate([avg_pool, max_pool]) 43 | 44 | dense_layer = Dense(256, activation='relu')(sentence_embed) 45 | output = Dense(self.n_class, activation='softmax')(dense_layer) 46 | 47 | model = Model(input_text, output) 48 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 49 | return model 50 | -------------------------------------------------------------------------------- /models/keras_text_cnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_text_cnn_model.py 10 | 11 | @time: 2019/2/8 10:35 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | from keras.models import Model 18 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, MaxPool1D, Flatten, concatenate, Dense 19 | 20 | from models.keras_base_model import KerasBaseModel 21 | 22 | 23 | class TextCNN(KerasBaseModel): 24 | def __init__(self, config, **kwargs): 25 | super(TextCNN, self).__init__(config, **kwargs) 26 | 27 | def build(self): 28 | input_text = Input(shape=(self.max_len,)) 29 | 30 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 31 | weights=[self.word_embeddings], 32 | trainable=self.config.word_embed_trainable)(input_text) 33 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 34 | 35 | filter_lengths = [2, 3, 4, 5] 36 | conv_layers = [] 37 | for filter_length in filter_lengths: 38 | conv_layer = Conv1D(filters=300, kernel_size=filter_length, padding='valid', 39 | strides=1, activation='relu')(text_embed) 40 | maxpooling = MaxPool1D(pool_size=self.max_len - filter_length + 1)(conv_layer) 41 | flatten = Flatten()(maxpooling) 42 | conv_layers.append(flatten) 43 | sentence_embed = concatenate(inputs=conv_layers) 44 | 45 | dense_layer = Dense(256, activation='relu')(sentence_embed) 46 | output = Dense(self.n_class, activation='softmax')(dense_layer) 47 | 48 | model = Model(input_text, output) 49 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 50 | return model 51 | -------------------------------------------------------------------------------- /models/keras_vdcnn_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: keras_vdcnn_model.py 10 | 11 | @time: 2019/2/8 13:01 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | import math 18 | from keras.models import Model 19 | from keras.layers import Input, Embedding, SpatialDropout1D, Conv1D, Flatten, Dense, BatchNormalization, ReLU, Add, \ 20 | MaxPooling1D 21 | from keras import backend as K 22 | 23 | from models.keras_base_model import KerasBaseModel 24 | from layers.kmaxpooling import KMaxPooling 25 | 26 | 27 | class VDCNN(KerasBaseModel): 28 | def __init__(self, config, **kwargs): 29 | super(VDCNN, self).__init__(config, **kwargs) 30 | 31 | def build(self, depth=[4, 4, 10, 10], pooling_type='maxpool', use_shortcut = False): 32 | input_text = Input(shape=(self.max_len,)) 33 | 34 | embedding_layer = Embedding(self.word_embeddings.shape[0], self.word_embeddings.shape[1], 35 | weights=[self.word_embeddings], 36 | trainable=self.config.word_embed_trainable)(input_text) 37 | text_embed = SpatialDropout1D(0.2)(embedding_layer) 38 | 39 | # first temporal conv layer 40 | conv_out = Conv1D(filters=64, kernel_size=3, kernel_initializer='he_uniform', padding='same')(text_embed) 41 | shortcut = conv_out 42 | 43 | # temporal conv block: 64 44 | for i in range(depth[0]): 45 | if i < depth[0] - 1: 46 | shortcut = conv_out 47 | conv_out = self.conv_block(inputs=conv_out, filters=64, use_shortcut=use_shortcut, shortcut=shortcut) 48 | else: 49 | # shortcut is not used at the last conv block 50 | conv_out = self.conv_block(inputs=conv_out, filters=64, use_shortcut=use_shortcut, shortcut=None) 51 | 52 | # down-sampling 53 | # shortcut is the second last conv block output 54 | conv_out = self.dowm_sampling(inputs=conv_out, pooling_type=pooling_type, use_shortcut=use_shortcut, 55 | shortcut=shortcut) 56 | shortcut = conv_out 57 | 58 | # temporal conv block: 128 59 | for i in range(depth[1]): 60 | if i < depth[1] - 1: 61 | shortcut = conv_out 62 | conv_out = self.conv_block(inputs=conv_out, filters=128, use_shortcut=use_shortcut, shortcut=shortcut) 63 | else: 64 | # shortcut is not used at the last conv block 65 | conv_out = self.conv_block(inputs=conv_out, filters=128, use_shortcut=use_shortcut, shortcut=None) 66 | 67 | # down-sampling 68 | conv_out = self.dowm_sampling(inputs=conv_out, pooling_type=pooling_type, use_shortcut=use_shortcut, 69 | shortcut=shortcut) 70 | shortcut = conv_out 71 | 72 | # temporal conv block: 256 73 | for i in range(depth[2]): 74 | if i < depth[1] - 1: 75 | shortcut = conv_out 76 | conv_out = self.conv_block(inputs=conv_out, filters=256, use_shortcut=use_shortcut, shortcut=shortcut) 77 | else: 78 | # shortcut is not used at the last conv block 79 | conv_out = self.conv_block(inputs=conv_out, filters=256, use_shortcut=use_shortcut, shortcut=None) 80 | 81 | # down-sampling 82 | conv_out = self.dowm_sampling(inputs=conv_out, pooling_type=pooling_type, use_shortcut=use_shortcut, 83 | shortcut=shortcut) 84 | 85 | # temporal conv block: 512 86 | for i in range(depth[3]): 87 | if i < depth[1] - 1: 88 | shortcut = conv_out 89 | conv_out = self.conv_block(inputs=conv_out, filters=128, use_shortcut=use_shortcut, shortcut=shortcut) 90 | else: 91 | # shortcut is not used at the last conv block 92 | conv_out = self.conv_block(inputs=conv_out, filters=128, use_shortcut=use_shortcut, shortcut=None) 93 | 94 | # 8-max pooling 95 | conv_out = KMaxPooling(k=8)(conv_out) 96 | flatten = Flatten()(conv_out) 97 | 98 | fc1 = Dense(2048, activation='relu')(flatten) 99 | sentence_embed = Dense(2048, activation='relu')(fc1) 100 | 101 | dense_layer = Dense(256, activation='relu')(sentence_embed) 102 | output = Dense(self.n_class, activation='softmax')(dense_layer) 103 | 104 | model = Model(input_text, output) 105 | model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=self.config.optimizer) 106 | return model 107 | 108 | def conv_block(self, inputs, filters, use_shortcut, shortcut): 109 | conv_1 = Conv1D(filters=filters, kernel_size=3, kernel_initializer='he_uniform', padding='same')(inputs) 110 | bn_1 = BatchNormalization()(conv_1) 111 | relu_1 = ReLU()(bn_1) 112 | conv_2 = Conv1D(filters=filters, kernel_size=3, kernel_initializer='he_uniform', padding='same')(relu_1) 113 | bn_2 = BatchNormalization()(conv_2) 114 | relu_2 = ReLU()(bn_2) 115 | 116 | if shortcut is not None and use_shortcut: 117 | return Add()([inputs, shortcut]) 118 | else: 119 | return relu_2 120 | 121 | def dowm_sampling(self, inputs, pooling_type, use_shortcut, shortcut): 122 | if pooling_type == 'kmaxpool': 123 | k = math.ceil(K.int_shape(inputs)[1] / 2) 124 | pool = KMaxPooling(k)(inputs) 125 | elif pooling_type == 'maxpool': 126 | pool = MaxPooling1D(pool_size=3, strides=2, padding='same')(inputs) 127 | elif pooling_type == 'conv': 128 | pool = Conv1D(filters=K.int_shape(inputs)[-1], kernel_size=3, strides=2, 129 | kernel_initializer='he_uniform', padding='same')(inputs) 130 | else: 131 | raise ValueError('pooling_type `{}` not understood'.format(pooling_type)) 132 | if shortcut is not None and use_shortcut: 133 | shortcut = Conv1D(filters=K.int_shape(inputs)[-1], kernel_size=3, strides=2, 134 | kernel_initializer='he_uniform', padding='same')(shortcut) 135 | return Add()([pool, shortcut]) 136 | else: 137 | return pool 138 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: __init__.py.py 10 | 11 | @time: 2019/2/8 10:23 12 | 13 | @desc: 14 | 15 | """ -------------------------------------------------------------------------------- /utils/metrics.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 5 | @author: alexyang 6 | 7 | @contact: alex.yang0326@gmail.com 8 | 9 | @file: metrics.py 10 | 11 | @time: 2019/2/8 10:24 12 | 13 | @desc: 14 | 15 | """ 16 | 17 | import numpy as np 18 | from sklearn.metrics import accuracy_score 19 | 20 | 21 | def eval_acc(y_true, y_pred): 22 | y_true = np.argmax(y_true, axis=-1) 23 | y_pred = np.argmax(y_pred, axis=-1) 24 | 25 | acc = accuracy_score(y_true, y_pred) 26 | return acc --------------------------------------------------------------------------------