Skip to content

Commit 0a6b995

Browse files
authored
Merge pull request #1 from brightmart/master
merge
2 parents 3e7911b + e09b47e commit 0a6b995

3 files changed

Lines changed: 71 additions & 206 deletions

File tree

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
Text Classification
22
-------------------------------------------------------------------------
3-
the purpose of this repository is to explore text classification methods in NLP with deep learning.
3+
The purpose of this repository is to explore text classification methods in NLP with deep learning.
44

55
#### Update:
66

7-
try bert model for multi-label classification, please check session #Models Detail, 3) Bert.
7+
Releasing Pre-trained Model of <a href="https://github.com/brightmart/albert_zh">ALBERT_Chinese</a> Training with 30G+ Raw Chinese Corpus, xxlarge, xlarge and more, Target to match State of the Art performance in Chinese, 2019-Oct-7, During the National Day of China!
8+
9+
<a href='https://github.com/brightmart/nlp_chinese_corpus'>Large Amount of Chinese Corpus for NLP Available!</a>
810

911
Google's BERT achieved new state of art result on more than 10 tasks in NLP using pre-train in language model then
1012

@@ -52,6 +54,8 @@ question(as query), then ask the model to predict an answer; if you feed story s
5254

5355
classification task.
5456

57+
To discuss ML/DL/NLP problems and get tech support from each other, you can join QQ group: 836811304
58+
5559
Models:
5660
-------------------------------------------------------------------------
5761

@@ -135,7 +139,7 @@ if you use python3, it will be fine as long as you change print/try catch functi
135139
TextCNN model is already transfomed to python 3.6
136140

137141

138-
Sample data: <a href='https://pan.baidu.com/s/1yWZf2eAPxq15-r2hHk2M-Q'>cached file </a>
142+
Sample data: <a href='https://pan.baidu.com/s/1yWZf2eAPxq15-r2hHk2M-Q'>cached file of baidu</a> or <a href="https://drive.google.com/drive/folders/0AKEuT4gza2AlUk9PVA">Google Drive:</a>send me an email
139143
-------------------------------------------------------------------------------------------------------
140144
to help you run this repository, currently we re-generate training/validation/test data and vocabulary/labels, and saved
141145

@@ -535,7 +539,7 @@ III.Attention Mechanism:
535539

536540
1) transfer encoder input list and hidden state of decoder
537541

538-
2) calculate similiarity of hidden state with each encoder input, to get possibility distribution for each encoder input.
542+
2) calculate similarity of hidden state with each encoder input, to get possibility distribution for each encoder input.
539543

540544
3) weighted sum of encoder input based on possibility distribution.
541545

@@ -615,7 +619,7 @@ Model Structure:
615619

616620
2) Dynamic memory:
617621

618-
a. compute gate by using 'similiarity' of keys,values with input of story.
622+
a. compute gate by using 'similarity' of keys,values with input of story.
619623

620624
b. get candidate hidden state by transform each key,value and input.
621625

@@ -707,7 +711,7 @@ During the process of doing large scale of multi-label classification, serveral
707711
It depend the task you are doing. From the task we conducted here, we believe that ensemble models based on models trained from multiple features including word, character for title and description can help to reach very high accuarcy; However, in some cases,as just alphaGo Zero demonstrated, algorithm is more important then data or computational power, in fact alphaGo Zero did not use any humam data.
708712

709713
2) Is there a ceiling for any specific model or algorithm?
710-
The answer is yes. lots of different models were used here, we found many models have similiar performances, even though there are quite different in structure. In some extent, the difference of performance is not so big.
714+
The answer is yes. lots of different models were used here, we found many models have similar performances, even though there are quite different in structure. In some extent, the difference of performance is not so big.
711715

712716
3) Is case study of error useful?
713717
I think it is quite useful especially when you have done many different things, but reached a limit. For example, by doing case study, you can find labels that models can make correct prediction, and where they make mistakes. And to imporove performance by increasing weights of these wrong predicted labels or finding potential errors from data.

a02_TextCNN/p7_TextCNN_train.py

Lines changed: 60 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import h5py
1616
import os
1717
import random
18+
from numba import jit
1819
#configuration
1920
FLAGS=tf.app.flags.FLAGS
2021

@@ -54,8 +55,7 @@ def main(_):
5455
#print some message for debug purpose
5556
print("trainX[0:10]:", trainX[0:10])
5657
print("trainY[0]:", trainY[0:10])
57-
train_y_short = get_target_label_short(trainY[0])
58-
print("train_y_short:", train_y_short)
58+
print("train_y_short:", trainY[0])
5959

6060
#2.create session.
6161
config=tf.ConfigProto()
@@ -128,203 +128,64 @@ def main(_):
128128

129129

130130
# 在验证集上做验证,报告损失、精确度
131-
def do_eval(sess,textCNN,evalX,evalY,num_classes):
132-
evalX=evalX[0:3000]
133-
evalY=evalY[0:3000]
134-
number_examples=len(evalX)
135-
eval_loss,eval_counter,eval_f1_score,eval_p,eval_r=0.0,0,0.0,0.0,0.0
136-
batch_size=1
137-
label_dict_confuse_matrix=init_label_dict(num_classes)
138-
for start,end in zip(range(0,number_examples,batch_size),range(batch_size,number_examples,batch_size)):
139-
feed_dict = {textCNN.input_x: evalX[start:end], textCNN.input_y_multilabel:evalY[start:end],textCNN.dropout_keep_prob: 1.0,
131+
def do_eval(sess, textCNN, evalX, evalY, num_classes):
132+
evalX = evalX[0:3000]
133+
evalY = evalY[0:3000]
134+
number_examples = len(evalX)
135+
eval_loss, eval_counter, eval_f1_score, eval_p, eval_r = 0.0, 0, 0.0, 0.0, 0.0
136+
batch_size = 1
137+
predict = []
138+
139+
for start, end in zip(range(0, number_examples, batch_size), range(batch_size, number_examples + batch_size, batch_size)):
140+
''' evaluation in one batch '''
141+
feed_dict = {textCNN.input_x: evalX[start:end],
142+
textCNN.input_y_multilabel: evalY[start:end],
143+
textCNN.dropout_keep_prob: 1.0,
140144
textCNN.is_training_flag: False}
141-
curr_eval_loss, logits= sess.run([textCNN.loss_val,textCNN.logits],feed_dict)#curr_eval_acc--->textCNN.accuracy
142-
predict_y = get_label_using_logits(logits[0])
143-
target_y= get_target_label_short(evalY[start:end][0])
144-
#f1_score,p,r=compute_f1_score(list(label_list_top5), evalY[start:end][0])
145-
label_dict_confuse_matrix=compute_confuse_matrix(target_y, predict_y, label_dict_confuse_matrix)
146-
eval_loss,eval_counter=eval_loss+curr_eval_loss,eval_counter+1
147-
148-
f1_micro,f1_macro=compute_micro_macro(label_dict_confuse_matrix) #label_dict_accusation is a dict, key is: accusation,value is: (TP,FP,FN). where TP is number of True Positive
149-
f1_score=(f1_micro+f1_macro)/2.0
150-
return eval_loss/float(eval_counter),f1_score,f1_micro,f1_macro
151-
152-
#######################################
153-
def compute_f1_score(predict_y,eval_y):
154-
"""
155-
compoute f1_score.
156-
:param logits: [batch_size,label_size]
157-
:param evalY: [batch_size,label_size]
158-
:return:
159-
"""
160-
f1_score=0.0
161-
p_5=0.0
162-
r_5=0.0
163-
return f1_score,p_5,r_5
164-
165-
def compute_f1_score_removed(label_list_top5,eval_y):
166-
"""
167-
compoute f1_score.
168-
:param logits: [batch_size,label_size]
169-
:param evalY: [batch_size,label_size]
170-
:return:
171-
"""
172-
num_correct_label=0
173-
eval_y_short=get_target_label_short(eval_y)
174-
for label_predict in label_list_top5:
175-
if label_predict in eval_y_short:
176-
num_correct_label=num_correct_label+1
177-
#P@5=Precision@5
178-
num_labels_predicted=len(label_list_top5)
179-
all_real_labels=len(eval_y_short)
180-
p_5=num_correct_label/num_labels_predicted
181-
#R@5=Recall@5
182-
r_5=num_correct_label/all_real_labels
183-
f1_score=2.0*p_5*r_5/(p_5+r_5+0.000001)
184-
return f1_score,p_5,r_5
185-
186-
random_number=1000
187-
def compute_confuse_matrix(target_y,predict_y,label_dict,name='default'):
188-
"""
189-
compute true postive(TP), false postive(FP), false negative(FN) given target lable and predict label
190-
:param target_y:
191-
:param predict_y:
192-
:param label_dict {label:(TP,FP,FN)}
193-
:return: macro_f1(a scalar),micro_f1(a scalar)
194-
"""
195-
#1.get target label and predict label
196-
if random.choice([x for x in range(random_number)]) ==1:
197-
print(name+".target_y:",target_y,";predict_y:",predict_y) #debug purpose
198-
199-
#2.count number of TP,FP,FN for each class
200-
y_labels_unique=[]
201-
y_labels_unique.extend(target_y)
202-
y_labels_unique.extend(predict_y)
203-
y_labels_unique=list(set(y_labels_unique))
204-
for i,label in enumerate(y_labels_unique): #e.g. label=2
205-
TP, FP, FN = label_dict[label]
206-
if label in predict_y and label in target_y:#predict=1,truth=1 (TP)
207-
TP=TP+1
208-
elif label in predict_y and label not in target_y:#predict=1,truth=0(FP)
209-
FP=FP+1
210-
elif label not in predict_y and label in target_y:#predict=0,truth=1(FN)
211-
FN=FN+1
212-
label_dict[label] = (TP, FP, FN)
213-
return label_dict
214-
215-
def compute_micro_macro(label_dict):
216-
"""
217-
compute f1 of micro and macro
218-
:param label_dict:
219-
:return: f1_micro,f1_macro: scalar, scalar
220-
"""
221-
f1_micro = compute_f1_micro_use_TFFPFN(label_dict)
222-
f1_macro= compute_f1_macro_use_TFFPFN(label_dict)
223-
return f1_micro,f1_macro
224-
225-
def compute_TF_FP_FN_micro(label_dict):
226-
"""
227-
compute micro FP,FP,FN
228-
:param label_dict_accusation: a dict. {label:(TP, FP, FN)}
229-
:return:TP_micro,FP_micro,FN_micro
230-
"""
231-
TP_micro,FP_micro,FN_micro=0.0,0.0,0.0
232-
for label,tuplee in label_dict.items():
233-
TP,FP,FN=tuplee
234-
TP_micro=TP_micro+TP
235-
FP_micro=FP_micro+FP
236-
FN_micro=FN_micro+FN
237-
return TP_micro,FP_micro,FN_micro
238-
def compute_f1_micro_use_TFFPFN(label_dict):
239-
"""
240-
compute f1_micro
241-
:param label_dict: {label:(TP,FP,FN)}
242-
:return: f1_micro: a scalar
243-
"""
244-
TF_micro_accusation, FP_micro_accusation, FN_micro_accusation =compute_TF_FP_FN_micro(label_dict)
245-
f1_micro_accusation = compute_f1(TF_micro_accusation, FP_micro_accusation, FN_micro_accusation,'micro')
246-
return f1_micro_accusation
247-
248-
def compute_f1_macro_use_TFFPFN(label_dict):
249-
"""
250-
compute f1_macro
251-
:param label_dict: {label:(TP,FP,FN)}
252-
:return: f1_macro
253-
"""
254-
f1_dict= {}
255-
num_classes=len(label_dict)
256-
for label, tuplee in label_dict.items():
257-
TP,FP,FN=tuplee
258-
f1_score_onelabel=compute_f1(TP,FP,FN,'macro')
259-
f1_dict[label]=f1_score_onelabel
260-
f1_score_sum=0.0
261-
for label,f1_score in f1_dict.items():
262-
f1_score_sum=f1_score_sum+f1_score
263-
f1_score=f1_score_sum/float(num_classes)
264-
return f1_score
265-
266-
small_value=0.00001
267-
def compute_f1(TP,FP,FN,compute_type):
268-
"""
269-
compute f1
270-
:param TP_micro: number.e.g. 200
271-
:param FP_micro: number.e.g. 200
272-
:param FN_micro: number.e.g. 200
273-
:return: f1_score: a scalar
274-
"""
275-
precison=TP/(TP+FP+small_value)
276-
recall=TP/(TP+FN+small_value)
277-
f1_score=(2*precison*recall)/(precison+recall+small_value)
278-
279-
if random.choice([x for x in range(500)]) == 1:print(compute_type,"precison:",str(precison),";recall:",str(recall),";f1_score:",f1_score)
280-
281-
return f1_score
282-
def init_label_dict(num_classes):
283-
"""
284-
init label dict. this dict will be used to save TP,FP,FN
285-
:param num_classes:
286-
:return: label_dict: a dict. {label_index:(0,0,0)}
287-
"""
288-
label_dict={}
289-
for i in range(num_classes):
290-
label_dict[i]=(0,0,0)
291-
return label_dict
292-
293-
def get_target_label_short(eval_y):
294-
eval_y_short=[] #will be like:[22,642,1391]
295-
for index,label in enumerate(eval_y):
296-
if label>0:
297-
eval_y_short.append(index)
298-
return eval_y_short
299-
300-
#get top5 predicted labels
301-
def get_label_using_logits(logits,top_number=5):
302-
# index_list=np.argsort(logits)[-top_number:]
303-
#vindex_list=index_list[::-1]
304-
y_predict_labels = [i for i in range(len(logits)) if logits[i] >= 0.50] # TODO 0.5PW e.g.[2,12,13,10]
305-
if len(y_predict_labels) < 1: y_predict_labels = [np.argmax(logits)]
306-
307-
return y_predict_labels
308-
309-
#统计预测的准确率
310-
def calculate_accuracy(labels_predicted, labels,eval_counter):
311-
label_nozero=[]
312-
#print("labels:",labels)
313-
labels=list(labels)
314-
for index,label in enumerate(labels):
315-
if label>0:
316-
label_nozero.append(index)
317-
if eval_counter<2:
318-
print("labels_predicted:",labels_predicted," ;labels_nozero:",label_nozero)
319-
count = 0
320-
label_dict = {x: x for x in label_nozero}
321-
for label_predict in labels_predicted:
322-
flag = label_dict.get(label_predict, None)
323-
if flag is not None:
324-
count = count + 1
325-
return count / len(labels)
326-
327-
##################################################
145+
current_eval_loss, logits = sess.run(
146+
[textCNN.loss_val, textCNN.logits], feed_dict)
147+
predict = [*predict, np.argmax(np.array(logits[0]))]
148+
eval_loss += current_eval_loss
149+
eval_counter += 1
150+
evalY = [np.argmax(ii) for ii in evalY]
151+
152+
if not FLAGS.multi_label_flag:
153+
predict = [int(ii > 0.5) for ii in predict]
154+
_, _, f1_macro, f1_micro, _ = fastF1(predict, evalY, num_classes)
155+
f1_score = (f1_micro + f1_macro) / 2.0
156+
return eval_loss / float(eval_counter), f1_score, f1_micro, f1_macro
157+
158+
@jit
159+
def fastF1(result: list, predict: list, num_classes: int):
160+
''' f1 score '''
161+
true_total, r_total, p_total, p, r = 0, 0, 0, 0, 0
162+
total_list = []
163+
for trueValue in range(num_classes):
164+
trueNum, recallNum, precisionNum = 0, 0, 0
165+
for index, values in enumerate(result):
166+
if values == trueValue:
167+
recallNum += 1
168+
if values == predict[index]:
169+
trueNum += 1
170+
if predict[index] == trueValue:
171+
precisionNum += 1
172+
R = trueNum / recallNum if recallNum else 0
173+
P = trueNum / precisionNum if precisionNum else 0
174+
true_total += trueNum
175+
r_total += recallNum
176+
p_total += precisionNum
177+
p += P
178+
r += R
179+
f1 = (2 * P * R) / (P + R) if (P + R) else 0
180+
total_list.append([P, R, f1])
181+
p, r = np.array([p, r]) / num_classes
182+
micro_r, micro_p = true_total / np.array([r_total, p_total])
183+
macro_f1 = (2 * p * r) / (p + r) if (p + r) else 0
184+
micro_f1 = (2 * micro_p * micro_r) / (micro_p + micro_r) if (micro_p + micro_r) else 0
185+
accuracy = true_total / len(result)
186+
print('P: {:.2f}%, R: {:.2f}%, Micro_f1: {:.2f}%, Macro_f1: {:.2f}%, Accuracy: {:.2f}'.format(
187+
p * 100, r * 100, micro_f1 * 100, macro_f1 * 100, accuracy * 100))
188+
return p, r, macro_f1, micro_f1, total_list
328189

329190
def assign_pretrained_word_embedding(sess,vocabulary_index2word,vocab_size,textCNN,word2vec_model_path):
330191
import word2vec # we put import here so that many people who do not use word2vec do not need to install this package. you can move import to the beginning of this file.
@@ -390,4 +251,4 @@ def load_data(cache_file_h5py,cache_file_pickle):
390251
print("INFO. cache file load successful...")
391252
return word2index, label2index,train_X,train_Y,vaild_X,valid_Y,test_X,test_Y
392253
if __name__ == "__main__":
393-
tf.app.run()
254+
tf.app.run()

a05_HierarchicalAttentionNetwork/p1_HierarchicalAttention_model_transformer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,4 +472,4 @@ def get_input_y(i,input_x,batch_size):
472472
input_y = np.array(input_y)
473473
return input_y
474474

475-
test()
475+
#test()

0 commit comments

Comments
 (0)