loop_class / train.py
vitiugin's picture
documented scripts
182b923 verified
Raw
History Blame Contribute Delete
5.67 kB
import sys
import numpy as np
import pandas as pd
import tensorflow as tf
from datasets import Dataset
from sentence_transformers import SentenceTransformer
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense, LSTM, Dropout, Input, Concatenate, BatchNormalization
# arguments
# example: python train.py data.csv feedback_type
df_path = sys.argv[1] # path to data file
train_mode = sys.argv[2] # type of model: feedback_type or thematic_area only
def process(examples):
'''
process(pd.DataFrame) -> Union[List[torch.Tensor], numpy.ndarray, torch.Tensor]
Function encodes texts from dataframe columns "text" and "org" to embeddings.
'''
tokenized_text = model.encode(examples["text"])
tokenized_org = model.encode(examples["org"])
return tokenized_text, tokenized_org
def get_feedback_data(f):
'''
get_feedback_data(pd.DataFrame) -> pd.DataFrame, List[str]
Function for one hot encoding of feedback types
'''
f_types = []
f = f.dropna(subset=['feedback_type'])
for row in f.feedback_type:
f_types += row.split(' | ')
types_list = list(set(f_types))
for t in types_list:
t_list = []
for row in f.feedback_type:
if t in row:
t_list.append(1)
else:
t_list.append(0)
f['feedback_' + str(t)] = t_list
label_list = ['feedback_Request', 'feedback_Thanks', 'feedback_Question', 'feedback_Opinion', 'feedback_Concern']
return f, label_list
def get_area_data(f):
'''
get_feedback_data(pd.DataFrame) -> pd.DataFrame, List[str]
Function for one hot encoding of thematic area categories
'''
f_types = []
f = f.dropna(subset=['thematic_area'])
for row in f.thematic_area:
f_types += row.split(' | ')
types_list = list(set(f_types))
for t in types_list:
t_list = []
for row in f.thematic_area:
if t in row:
t_list.append(1)
else:
t_list.append(0)
f['area_' + str(t)] = t_list
label_list = ['area_cross-cutting', 'area_education', 'area_food security', 'area_governance',
'area_health', 'area_protection', 'area_shelter', 'area_wash']
return f, label_list
df = pd.read_csv(df_path) #reading data
# check the training mode type
if train_mode == 'feedback_type':
df, label_list = get_feedback_data(df)
elif train_mode == 'thematic_area':
df, label_list = get_feedback_data(df)
else:
print('The script supports "feedback_type" or "thematic_area" modes only.')
# parameters for reproducibility
SEED_VALUE = 13
tf.random.set_seed(SEED_VALUE)
tf.keras.utils.set_random_seed(SEED_VALUE)
tf.config.experimental.enable_op_determinism()
LABELS_NUM = len(label_list) # detect number of classes
model = SentenceTransformer('distiluse-base-multilingual-cased-v2') # define pretrained model
EMB_DIM = 512 # vector dimensionality
df = df.dropna(subset=['feedback_content', 'organisation']) # drop duplicated texts AND organizations
# dataset processing part
new_df = pd.DataFrame(data=df, columns=label_list) # new dataset with content and classes only
dataset = Dataset.from_dict({"text": df['feedback_content'], "org": df['organisation'], "label": new_df.to_numpy()}) # preparing data columns
# train-validation splitting
dataset = dataset.shuffle(seed=SEED_VALUE)
train, val = dataset.train_test_split(test_size=0.2, seed=SEED_VALUE).values()
# tokenization
train_text, train_org = process(train)
val_text, val_org = process(val)
# training data format preparation
X1_text = tf.reshape(train_text, [-1, 1, EMB_DIM])
X1_org = tf.reshape(train_org, [-1, 1, EMB_DIM])
Y1 = tf.reshape(np.array(train['label']), [-1, 1, LABELS_NUM])
# validation data format preparation
X2_text = tf.reshape(val_text, [-1, 1, EMB_DIM])
X2_org = tf.reshape(val_org, [-1, 1, EMB_DIM])
Y2 = tf.reshape(np.array(val['label']), [-1, 1, LABELS_NUM])
# Defining the model paramaters.
inputA = Input(shape=(1, EMB_DIM, ))
inputB = Input(shape=(1, EMB_DIM, ))
# the first branch operates on the transformer embeddings
x = LSTM(EMB_DIM, input_shape=(1, EMB_DIM), return_sequences=True, dropout=0.1, recurrent_dropout=0.1)(inputA)
x = Dense(EMB_DIM,activation='relu')(x)
x = Dense(256, activation="sigmoid")(x)
x = Dropout(0.5)(x)
x = Dense(128,activation='sigmoid')(x)
x_model = Model(inputs=inputA, outputs=x)
# the first branch operates on the transformer embeddings
y = LSTM(EMB_DIM, input_shape=(1, EMB_DIM), return_sequences=True, dropout=0.1, recurrent_dropout=0.1)(inputB)
y = Dense(EMB_DIM,activation='relu')(y)
y = Dense(256, activation="sigmoid")(y)
y = Dropout(0.5)(y)
y = Dense(128,activation='sigmoid')(y)
y_model = Model(inputs=inputB, outputs=y)
# combine the output of the three branches
combined = Concatenate()([x_model.output, y_model.output])
# apply a FC layer and then a regression prediction on the combined outputs
combo = BatchNormalization()(combined)
combo1 = Dense(LABELS_NUM, activation="sigmoid")(combo)
# our model will accept the inputs of the two branches and then output a single value
model = Model(inputs=[x_model.inputs, y_model.inputs], outputs=combo1)
# summary of model
model.compile(optimizer='adam', loss='binary_crossentropy',
metrics=[tf.keras.metrics.BinaryAccuracy(name='Acc'), tf.keras.metrics.Precision(name='Prec'),
tf.keras.metrics.Recall(name='Rec'), tf.keras.metrics.AUC(name='AUC')])
# model training
model.fit([X1_text, X1_org], Y1, validation_data=([X2_text, X2_org], Y2), epochs=20)
# saving of trained model
model.save('models/' + str(train_mode))