使用BERT生成句向量
轉載請註明出處,原文地址
在閱讀本文之前如果您對BERT並不瞭解,請參閱我的其他博文BERT完全指南
簡介
之前的文章介紹了BERT的原理、並用BERT做了文字分類與相似度計算,本文將會教大家用BERT來生成句向量,核心邏輯程式碼參考了hanxiao大神的bert-as-service,我的程式碼地址如下:
程式碼地址:BERT句向量
傳統的句向量
對於傳統的句向量生成方式,更多的是採用word embedding的方式取加權平均,該方法有一個最大的弊端,那就是無法理解上下文的語義,同一個詞在不同的語境意思可能不一樣,但是卻會被表示成同樣的word embedding,BERT生成句向量的優點在於可理解句意,並且排除了詞向量加權引起的誤差。
BERT句向量
BERT的包括兩個版本,12層的transformer與24層的transformer,官方提供了12層的中文模型,下文也將會基於12層的模型來講解。
每一層transformer的輸出值,理論上來說都可以作為句向量,但是到底應該取哪一層呢,根據hanxiao大神的實驗資料,最佳結果是取倒數第二層,最後一層的值太接近於目標,前面幾層的值可能語義還未充分的學習到。
接下來我們從程式碼的角度來進詳細講解。
先看下args.py檔案,該檔案有幾個句向量的重要引數,前幾個都是路徑,這裡不再詳細解釋,這裡主要說一下layer_indexes引數與max_seq_len引數,layer_indexes表示的是使用第幾層的輸出作為句向量,-2表示的是倒數第二層,max_seq_len表示的是序列的最大長度,因為輸入的長度是不固定的,所以我們需要設定一個最大長度才能確保輸出的維度是一樣的,如果最大長度是20,當輸入的序列長度小於20的時候,就會補0,如果大於20則會擷取前面的部分 ,通常該值會取語料的長度的平均值+2,加2的原因是因為需要拼接兩個佔位符[CLS](表示序列的開始)與[SEP](表示序列的結束)
model_dir = os.path.join(file_path, 'chinese_L-12_H-768_A-12/')
config_name = os.path.join(model_dir, 'bert_config.json')
ckpt_name = os.path.join(model_dir, 'bert_model.ckpt')
output_dir = os.path.join(model_dir, '../tmp/result/')
vocab_file = os.path.join(model_dir, 'vocab.txt')
data_dir = os.path.join(model_dir, '../data/')
num_train_epochs = 10
batch_size = 32
learning_rate = 0.00005
# gpu使用率
gpu_memory_fraction = 0.8
# 預設取倒數第二層的輸出值作為句向量
layer_indexes = [-2]
# 序列的最大程度,單文字建議把該值調小
max_seq_len = 20
再來看graph.py檔案,該程式碼的主要目的是把預訓練好的模型載入進來,並修改輸出層,我們一步一步來看。
首先建立一個目錄,該目錄用於存放待輸出的檔案,定義bert的配置資訊路徑,根據路徑讀取配置資訊轉化為bert_config物件。
tensorflow.python.tools.optimize_for_inference_lib import optimize_for_inference
tf.gfile.MakeDirs(args.output_dir)
config_fp = args.config_name
logger.info('model config: %s' % config_fp)
# 載入bert配置檔案 with tf.gfile.GFile(config_fp, 'r') as f:
bert_config = modeling.BertConfig.from_dict(json.load(f))
定義三個佔位符,分別表示的是對應文字的index,mask與type_index,其中index表示的是在詞典中的index,mask表示的是該位置是否有內容,舉個例子,例如序列的最大長度是20,有效的字元只有10個字,加上[CLS]與[SEP]兩個佔位符,那有8個字元是空的,該8個位置設定為0其他位置設定為1,type_index表示的是是否是第一個句子,是第一個句子則設定為1,因為該專案只有一個句子,所以均為1。
logger.info('build graph...')
input_ids = tf.placeholder(tf.int32, (None, args.max_seq_len), 'input_ids')
input_mask = tf.placeholder(tf.int32, (None, args.max_seq_len), 'input_mask')
input_type_ids = tf.placeholder(tf.int32, (None, args.max_seq_len), 'input_type_ids')
根據上面定義的三個佔位符,定義好輸入的張量,例項化一個model物件,該物件就是預訓練好的bert模型,然後從check_point檔案中初始化權重
input_tensors = [input_ids, input_mask, input_type_ids]
model = modeling.BertModel(
config=bert_config,
is_training=False,
input_ids=input_ids,
input_mask=input_mask,
token_type_ids=input_type_ids,
use_one_hot_embeddings=False)
tvars = tf.trainable_variables()
init_checkpoint = args.ckpt_name
(assignment_map, initialized_variable_names) = modeling.get_assignment_map_from_checkpoint(tvars, init_checkpoint)
tf.train.init_from_checkpoint(init_checkpoint, assignment_map)
接下來判斷一下args.index_layeres引數的長度,如果長度為1,則只取改層的輸出,否則遍歷需要取的層,把所有層的weight取出來並拼接成一個768*層數的張量
with tf.variable_scope("pooling"):
if len(args.layer_indexes) == 1:
encoder_layer = model.all_encoder_layers[args.layer_indexes[0]]
else:
all_layers = [model.all_encoder_layers[l] for l in args.layer_indexes]
encoder_layer = tf.concat(all_layers, -1)
接下來是句向量生成的核心程式碼,這裡定義了兩個方法,一個mul_mask 和一個masked_reduce_mean,我們先看masked_reduce_mean(encoder_layer, input_mask)
這裡呼叫方法時傳入的是encoder_layer即輸出值,與input_mask即是否有有效文字,masked_reduce_mean
方法中又呼叫了mul_mask
方法,即先把input_mask進行了一個維度擴充套件,然後與encoder_layer相乘,為什麼要維度擴充套件呢,我們看下兩個值的維度,我們還是假設序列的最大長度是20,那麼encoder_layer的維度為[20,768]
,為了把無效的位置的內容置為0,input_mask的維度為[20]
,擴充之後變成了[20,1]
,兩個值相乘,便把input_mask為0的位置的encoder_layer的值改為了0, 然後把相乘得到的值在axis=1的位置進行相加最後除以input_mask在axis=1的維度的和,然後把得到的結果新增一個別名final_encodes
mul_mask = lambda x, m: x * tf.expand_dims(m, axis=-1)
masked_reduce_mean = lambda x, m: tf.reduce_sum(mul_mask(x, m), axis=1) / (
tf.reduce_sum(m, axis=1, keepdims=True) + 1e-10)
input_mask = tf.cast(input_mask, tf.float32)
pooled = masked_reduce_mean(encoder_layer, input_mask)
pooled = tf.identity(pooled, 'final_encodes')
output_tensors = [pooled]
tmp_g = tf.get_default_graph().as_graph_def()
最後把得到的句向量重新新增進graph中,並返回graph的路徑。
config = tf.ConfigProto(allow_soft_placement=True)
with tf.Session(config=config) as sess:
logger.info('load parameters from checkpoint...')
sess.run(tf.global_variables_initializer())
logger.info('freeze...')
tmp_g = tf.graph_util.convert_variables_to_constants(sess, tmp_g, [n.name[:-2] for n in output_tensors])
dtypes = [n.dtype for n in input_tensors]
logger.info('optimize...')
tmp_g = optimize_for_inference(
tmp_g,
[n.name[:-2] for n in input_tensors],
[n.name[:-2] for n in output_tensors],
[dtype.as_datatype_enum for dtype in dtypes],
False)
tmp_file = tempfile.NamedTemporaryFile('w', delete=False, dir=args.output_dir).name
logger.info('write graph to a tmp file: %s' % tmp_file)
with tf.gfile.GFile(tmp_file, 'wb') as f:
f.write(tmp_g.SerializeToString())
return tmp_file
實際的使用和BERT做文字分類的方法類似,只是在返回的EstimatorSpec
不太一樣,具體細節不在詳解,可參考我的具體程式碼。
with tf.gfile.GFile(self.graph_path, 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
input_names = ['input_ids', 'input_mask', 'input_type_ids']
output = tf.import_graph_def(graph_def,
input_map={k + ':0': features[k] for k in input_names},
return_elements=['final_encodes:0'])
return EstimatorSpec(mode=mode, predictions={
'encodes': output[0]
})
最後再貼一下程式碼地址
BERT生成句向量
相關文章
- 如何使用 resnet 生成圖片向量?
- NLP ——句向量表示
- jsqlparser使用記錄---生成sql語句JSSQL
- 以圖搜圖如何生成向量?
- Bert下載和使用(以bert-base-uncased為例)
- dotnet 簡單控制檯使用 KernelMemory 向量化文字嵌入生成和查詢
- 【BERT】詳解BERT
- 怎樣生成一個好的詞向量
- 使用 numpy 的 savez_compressed 儲存深度學習模型生成的向量資料深度學習模型
- 向量圖SVG的使用SVG
- Java中如何解析SQL語句、格式化SQL語句、生成SQL語句?JavaSQL
- excel表結構生成powerDesigner模型,生成建表語句sqlExcel模型SQL
- c++ 一維向量,和二維向量的基本使用C++
- 【詞向量表示】Item2Vec、DeepWalk、Node2vec、EGES詞向量生成演算法演算法
- DBeaver如何生成select,update,delete,insert語句delete
- python中for語句讀取生成器Python
- 定時生成分月表sql語句SQL
- mysql資料庫語句自動生成MySql資料庫
- NLP與深度學習(六)BERT模型的使用深度學習模型
- NLP生成任務超越BERT、GPT!微軟提出通用預訓練模型MASSGPT微軟模型
- Chroma向量資料庫使用案例資料庫
- MATLAB中如何生成指定範圍的隨機整數向量Matlab隨機
- pytorch中:使用bert預訓練模型進行中文語料任務,bert-base-chinese下載。PyTorch模型
- transformers(1) 、bertORM
- 透過ModelScope開源多模態Embedding模型進行向量生成模型
- OSM地圖本地釋出-如何生成各省市向量地圖地圖
- EFCore常規操作生成的SQL語句一覽SQL
- AutoGPT放棄使用向量資料庫GPT資料庫
- 使用withopen語句(未完)
- Python基於Excel生成向量圖層及屬性表資訊:ArcPyPythonExcel
- 使用sql語句查詢平均值,使用sql語句查詢資料總條數, not in 篩選語句的使用SQL
- 從RNN到BERTRNN
- Roberta: Bert調優
- 只要一句話,為你生成創意畫作
- 通過實體類生成 mysql 的建表語句MySql
- 自定義註解例項實現SQL語句生成SQL
- CCF 202006-2 稀疏向量【map的使用】
- 【BERT】你儲存的BERT模型為什麼那麼大?模型