国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量

這篇具有很好參考價值的文章主要介紹了人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

人工智能專欄文章匯總:人工智能學習專欄文章匯總-CSDN博客

本篇目錄

四、自然語言處理

4.1 詞向量 (Word Embedding)

4.1.1 詞向量的生成過程

4.1.2 word2vec介紹

4.1.3 word2vec:skip-gram算法的實現

4.2 句向量 - 情感分析

4.2.1 LSTM (Long Short-Term Memory)介紹

4.2.2 基于飛槳實現的情感分析模型

4.3?BERT模型


四、自然語言處理

計算機如何理解并處理人類語言?答案是通過詞向量。

4.1 詞向量 (Word Embedding)

在自然語言處理任務中,詞向量(Word Embedding)是表示自然語言里單詞的一種方法,即把每個詞都表示為一個N維空間內的點,即一個高維空間內的向量。通過這種方法,實現把自然語言計算轉換為向量計算。

具體來說,詞向量(其實對于中文來說是字向量)是基于語料通過某種算法(比如word2vec),使得語料中的每個詞對應一個N維向量,這個向量就是詞向量,如 “我” 這個詞可以用 [0.1, 2.0, 1.6, ...] 這個向量來表示,這個向量是結合該詞在語料中的上下文的詞語通過計算得來,能反應上下文的關系。詞向量技術將自然語言中的詞轉化為稠密向量(減少計算維度),并且使得相近的詞有相似的向量表示,方便后續(xù)在向量的基礎上做運算,進一步挖掘文本之間的潛在關系。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

4.1.1 詞向量的生成過程

詞向量一般按如下過程生成:

1. 將詞變成數字(這樣計算機才能處理):將詞表(語料)中的詞轉換成id(id從0到N),一般id 0給出現頻率最高的詞,之后根據詞的出現頻率從高到低,id從小到大。詞表的長度為M

2. 將詞表中所有的詞變成用id來表示,這樣一段話就變成了一串連續(xù)的數字

3. 將這一串數字作為輸入,通過詞向量算法(比如word2vec),來計算出詞向量網絡參數(Embedded lookup),這個詞向量網絡參數的維度是 M?x L,M是詞表長度,L是自定義的詞向量維度(這個維度可以是任意大小,但實際應用中會定義成比輸入維度小很多,方便后續(xù)運算。根據大量經驗值,這個值一般設為300效果最好)。

4. 利用訓練好的詞向量網絡參數來獲取詞的詞向量,詞的數量為N(比如對于,我,愛,人工,智能,這4個詞,N為4)

  • 詞向量網絡的輸入端:輸入數據是以one-hot向量方式表示的某個詞活多個詞,如[1,0,0,0...],[0,0,1,0...],因此輸入端向量的維度 N x M,N是詞的數量,M是詞表的長度。
  • [N, M] x [M, L] = [N, L]
  • 詞向量網絡的輸出端:輸出端得到的即為這些詞的詞向量,維度為 N x L。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

那么要如何得到詞向量網絡參數(Embdded lookup)?就是通過不同的詞向量算法來訓練網絡并獲取。

獲得詞向量的經典算法包括LSA, word2vec, Glove等等. 關于word2vec的可以參考這篇文章(其中對詞向量也有比較好的說明):詞向量:word2vec - 簡書

4.1.2 word2vec介紹

?2013年,Mikolov提出的經典word2vec算法就是通過上下文來學習語義信息。word2vec包含兩個經典模型:CBOW(Continuous Bag-of-Words)和Skip-gram,如圖所示。?

  • CBOW:通過上下文的詞向量推理中心詞。
  • Skip-gram:根據中心詞推理上下文。

假設有一個句子“Pineapples are spiked and yellow”,兩個模型的推理方式如下:

  • CBOW中,先在句子中選定一個中心詞,并把其它詞作為這個中心詞的上下文。如?所示,把“Spiked”作為中心詞,把“Pineapples、are、and、yellow”作為中心詞的上下文。在學習過程中,使用上下文的詞向量推理中心詞,這樣中心詞的語義就被傳遞到上下文的詞向量中,如“Spiked → pineapple”,從而達到學習語義信息的目的。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

  • Skip-gram中,同樣先選定一個中心詞,并把其他詞作為這個中心詞的上下文。如?所示,把“Spiked”作為中心詞,把“Pineapples、are、and、yellow”作為中心詞的上下文。不同的是,在學習過程中,使用中心詞的詞向量去推理上下文,這樣上下文定義的語義被傳入中心詞的表示中,如“pineapple → Spiked”, 從而達到學習語義信息的目的。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

一般來說,CBOW比Skip-gram訓練速度快,訓練過程更加穩(wěn)定,原因是CBOW使用上下文average的方式進行訓練,每個訓練step會見到更多樣本。而在生僻字(出現頻率低的字)處理上,skip-gram比CBOW效果更好,原因是skip-gram不會刻意回避生僻字(CBOW結構中輸入中存在生僻字時,生僻字會被其它非生僻字的權重沖淡)。

4.1.3 word2vec:skip-gram算法的實現

實際情況中,vocab_size通常很大(幾十萬甚至幾百萬),要處理一個非常大的矩陣運算(計算過程非常緩慢,需要消耗大量的內存)。為了緩解這個問題,通常采取負采樣(negative_sampling) 的方式來近似模擬多分類任務。就是隨機從詞表中選擇幾個代表詞,通過最小化這幾個代表詞的概率,去近似最小化整體的預測概率。比如,先指定一個中心詞(如“人工”)和一個目標詞正樣本(如“智能”),再隨機在詞表中采樣幾個目標詞負樣本(如“日本”,“喝茶”等)。有了這些內容,我們的skip-gram模型就變成了一個二分類任務。對于目標詞正樣本,我們需要最大化它的預測概率;對于目標詞負樣本,我們需要最小化它的預測概率。通過這種方式,我們就可以完成計算加速。上述做法,我們稱之為負采樣。

使用飛槳實現Skip-gram

流程如下:

  1. 數據處理:選擇需要使用的數據,并做好必要的預處理工作。

  2. 網絡定義:使用飛槳定義好網絡結構,包括輸入層,中間層,輸出層,損失函數和優(yōu)化算法。

  3. 網絡訓練:將準備好的數據送入神經網絡進行學習,并觀察學習的過程是否正常,如損失函數值是否在降低,也可以打印一些中間步驟的結果出來等。

  4. 網絡評估:使用測試集合測試訓練好的神經網絡,看看訓練效果如何。

在實現的過程中,通常會讓模型接收3個tensor輸入:

  • 代表中心詞的tensor:假設我們稱之為center_words?V,一般來說,這個tensor是一個形狀為[batch_size, vocab_size]的one-hot tensor,表示在一個mini-batch中每個中心詞具體的ID。

  • 代表目標詞的tensor:假設我們稱之為target_words?T,一般來說,這個tensor同樣是一個形狀為[batch_size, vocab_size]的one-hot tensor,表示在一個mini-batch中每個目標詞具體的ID。

  • 代表目標詞標簽的tensor:假設我們稱之為labels?L,一般來說,這個tensor是一個形狀為[batch_size, 1]的tensor,每個元素不是0就是1(0:負樣本,1:正樣本)。

模型訓練過程如下:

  1. 用V去查詢W0?的到H1(用中心詞正向算出的詞向量),用T去查詢W1得到H2?(用目標詞反向算出的詞向量),分別得到兩個形狀為[batch_size, embedding_size]的tensor?。
  2. 將H1, H2這兩個tensor進行點積運算,最終得到一個形狀為[batch_size]的tensor?
  3. 使用sigmoid函數作用在O上,將上述點積的結果歸一化為一個0-1的概率值,作為預測概率,根據標簽信息L訓練這個模型即可。

在結束模型訓練之后,一般使用W0?作為最終要使用的詞向量,用W0?的向量表示。通過向量點乘的方式,計算不同詞之間的相似度。

Skip-gram模型構建和訓練完整代碼如下:

# 下載語料用來訓練word2vec
def download():
    # 可以從百度云服務器下載一些開源數據集(dataset.bj.bcebos.com)
    corpus_url = "https://dataset.bj.bcebos.com/word2vec/text8.txt"
    # 使用python的requests包下載數據集到本地
    web_request = requests.get(corpus_url)
    corpus = web_request.content
    # 把下載后的文件存儲在當前目錄的text8.txt文件內
    with open("./text8.txt", "wb") as f:
        f.write(corpus)
    f.close()
download()




# 讀取text8數據
def load_text8():
    with open("./text8.txt", "r") as f:
        corpus = f.read().strip("\n")
    f.close()

    return corpus

corpus = load_text8()




# 對語料進行預處理(分詞)
def data_preprocess(corpus):
    # 由于英文單詞出現在句首的時候經常要大寫,所以我們把所有英文字符都轉換為小寫,
    # 以便對語料進行歸一化處理(Apple vs apple等)
    corpus = corpus.strip().lower()
    corpus = corpus.split(" ")
    return corpus

corpus = data_preprocess(corpus)
print(corpus[:50])




# 構造詞典,統計每個詞的頻率,并根據頻率將每個詞轉換為一個整數id
def build_dict(corpus):
    # 首先統計每個不同詞的頻率(出現的次數),使用一個詞典記錄
    word_freq_dict = dict()
    for word in corpus:
        if word not in word_freq_dict:
            word_freq_dict[word] = 0
        word_freq_dict[word] += 1

    # 將這個詞典中的詞,按照出現次數排序,出現次數越高,排序越靠前
    # 一般來說,出現頻率高的高頻詞往往是:I,the,you這種代詞,而出現頻率低的詞,往往是一些名詞,如:nlp
    word_freq_dict = sorted(word_freq_dict.items(), key = lambda x:x[1], reverse = True)
    
    # 構造3個不同的詞典,分別存儲,
    # 每個詞到id的映射關系:word2id_dict
    # 每個id出現的頻率:word2id_freq
    # 每個id到詞的映射關系:id2word_dict
    word2id_dict = dict()
    word2id_freq = dict()
    id2word_dict = dict()

    # 按照頻率,從高到低,開始遍歷每個單詞,并為這個單詞構造一個獨一無二的id
    for word, freq in word_freq_dict:
        curr_id = len(word2id_dict)
        word2id_dict[word] = curr_id
        word2id_freq[word2id_dict[word]] = freq
        id2word_dict[curr_id] = word

    return word2id_freq, word2id_dict, id2word_dict

word2id_freq, word2id_dict, id2word_dict = build_dict(corpus)
vocab_size = len(word2id_freq)
print("there are totoally %d different words in the corpus" % vocab_size)
for _, (word, word_id) in zip(range(50), word2id_dict.items()):
    print("word %s, its id %d, its word freq %d" % (word, word_id, word2id_freq[word_id]))
---------------------------------------------------------------
there are totoally 253854 different words in the corpus
word the, its id 0, its word freq 1061396
word of, its id 1, its word freq 593677
word and, its id 2, its word freq 416629
word one, its id 3, its word freq 411764




# 把語料轉換為id序列
def convert_corpus_to_id(corpus, word2id_dict):
    # 使用一個循環(huán),將語料中的每個詞替換成對應的id,以便于神經網絡進行處理
    corpus = [word2id_dict[word] for word in corpus]
    return corpus

corpus = convert_corpus_to_id(corpus, word2id_dict)
print("%d tokens in the corpus" % len(corpus))
print(corpus[:50])
---------------------------------------------------------------
17005207 tokens in the corpus
[5233, 3080, 11, 5, 194, 1, 3133, 45, 58, 155, 127, 741, 476, 10571, 133, 0, 27349, 1, 0, 




# 使用二次采樣算法(subsampling)處理語料,強化訓練效果
def subsampling(corpus, word2id_freq):
    
    # 這個discard函數決定了一個詞會不會被替換,這個函數是具有隨機性的,每次調用結果不同
    # 如果一個詞的頻率很大,那么它被遺棄的概率就很大
    def discard(word_id):
        return random.uniform(0, 1) < 1 - math.sqrt(
            1e-4 / word2id_freq[word_id] * len(corpus))

    corpus = [word for word in corpus if not discard(word)]
    return corpus

corpus = subsampling(corpus, word2id_freq)
print("%d tokens in the corpus" % len(corpus))
print(corpus[:50])




# 構造數據,準備模型訓練
# max_window_size代表了最大的window_size的大小,程序會根據max_window_size從左到右掃描整個語料
# negative_sample_num代表了對于每個正樣本,我們需要隨機采樣多少負樣本用于訓練,
# 一般來說,negative_sample_num的值越大,訓練效果越穩(wěn)定,但是訓練速度越慢。 
def build_data(corpus, word2id_dict, word2id_freq, max_window_size = 3, negative_sample_num = 4):
    
    # 使用一個list存儲處理好的數據
    dataset = []

    # 從左到右,開始枚舉每個中心點的位置
    for center_word_idx in range(len(corpus)):
        # 以max_window_size為上限,隨機采樣一個window_size,這樣會使得訓練更加穩(wěn)定
        window_size = random.randint(1, max_window_size)
        # 當前的中心詞就是center_word_idx所指向的詞
        center_word = corpus[center_word_idx]

        # 以當前中心詞為中心,左右兩側在window_size內的詞都可以看成是正樣本
        positive_word_range = (max(0, center_word_idx - window_size), min(len(corpus) - 1, center_word_idx + window_size))
        positive_word_candidates = [corpus[idx] for idx in range(positive_word_range[0], positive_word_range[1]+1) if idx != center_word_idx]

        # 對于每個正樣本來說,隨機采樣negative_sample_num個負樣本,用于訓練
        for positive_word in positive_word_candidates:
            # 首先把(中心詞,正樣本,label=1)的三元組數據放入dataset中,
            # 這里label=1表示這個樣本是個正樣本
            dataset.append((center_word, positive_word, 1))

            # 開始負采樣
            i = 0
            while i < negative_sample_num:
                negative_word_candidate = random.randint(0, vocab_size-1)

                if negative_word_candidate not in positive_word_candidates:
                    # 把(中心詞,正樣本,label=0)的三元組數據放入dataset中,
                    # 這里label=0表示這個樣本是個負樣本
                    dataset.append((center_word, negative_word_candidate, 0))
                    i += 1
    return dataset
corpus_light = corpus[:int(len(corpus)*0.2)]
dataset = build_data(corpus_light, word2id_dict, word2id_freq)
for _, (center_word, target_word, label) in zip(range(50), dataset):
    print("center_word %s, target %s, label %d" % (id2word_dict[center_word],
                                                   id2word_dict[target_word], label))
-----------------------------------------------------------------------
center_word anarchism, target originated, label 1
center_word anarchism, target kdepim, label 0
center_word anarchism, target mahoney, label 0




#訓練數據準備好后,把訓練數據都組裝成mini-batch,并準備輸入到網絡中進行訓練,代碼如下
# 構造mini-batch,準備對模型進行訓練
# 我們將不同類型的數據放到不同的tensor里,便于神經網絡進行處理
# 并通過numpy的array函數,構造出不同的tensor來,并把這些tensor送入神經網絡中進行訓練
def build_batch(dataset, batch_size, epoch_num):
    
    # center_word_batch緩存batch_size個中心詞
    center_word_batch = []
    # target_word_batch緩存batch_size個目標詞(可以是正樣本或者負樣本)
    target_word_batch = []
    # label_batch緩存了batch_size個0或1的標簽,用于模型訓練
    label_batch = []

    for epoch in range(epoch_num):
        # 每次開啟一個新epoch之前,都對數據進行一次隨機打亂,提高訓練效果
        random.shuffle(dataset)
        
        for center_word, target_word, label in dataset:
            # 遍歷dataset中的每個樣本,并將這些數據送到不同的tensor里
            center_word_batch.append([center_word])
            target_word_batch.append([target_word])
            label_batch.append(label)

            # 當樣本積攢到一個batch_size后,我們把數據都返回回來
            # 在這里我們使用numpy的array函數把list封裝成tensor
            # 并使用python的迭代器機制,將數據yield出來
            # 使用迭代器的好處是可以節(jié)省內存
            if len(center_word_batch) == batch_size:
                yield np.array(center_word_batch).astype("int64"), \
                    np.array(target_word_batch).astype("int64"), \
                    np.array(label_batch).astype("float32")
                center_word_batch = []
                target_word_batch = []
                label_batch = []

    if len(center_word_batch) > 0:
        yield np.array(center_word_batch).astype("int64"), \
            np.array(target_word_batch).astype("int64"), \
            np.array(label_batch).astype("float32")

for _, batch in zip(range(10), build_batch(dataset, 128, 3)):
    print(batch)
    break




#定義skip-gram訓練網絡結構
#使用paddlepaddle的2.0.0版本
#一般來說,在使用paddle訓練的時候,我們需要通過一個類來定義網絡結構,這個類繼承了paddle.nn.layer
class SkipGram(nn.Layer):
    def __init__(self, vocab_size, embedding_size, init_scale=0.1):
        # vocab_size定義了這個skipgram這個模型的詞表大小
        # embedding_size定義了詞向量的維度是多少
        # init_scale定義了詞向量初始化的范圍,一般來說,比較小的初始化范圍有助于模型訓練
        super(SkipGram, self).__init__()
        self.vocab_size = vocab_size
        self.embedding_size = embedding_size

        # 使用Embedding函數構造一個詞向量參數
        # 這個參數的大小為:[self.vocab_size, self.embedding_size]
        # 數據類型為:float32
        # 這個參數的初始化方式為在[-init_scale, init_scale]區(qū)間進行均勻采樣
        self.embedding = Embedding( 
            num_embeddings = self.vocab_size,
            embedding_dim = self.embedding_size,
            weight_attr=paddle.ParamAttr(
                initializer=paddle.nn.initializer.Uniform( 
                    low=-init_scale, high=init_scale)))

        # 使用Embedding函數構造另外一個詞向量參數
        # 這個參數的大小為:[self.vocab_size, self.embedding_size]
        # 這個參數的初始化方式為在[-init_scale, init_scale]區(qū)間進行均勻采樣
        self.embedding_out = Embedding(
            num_embeddings = self.vocab_size,
            embedding_dim = self.embedding_size,
            weight_attr=paddle.ParamAttr(
                initializer=paddle.nn.initializer.Uniform(
                    low=-init_scale, high=init_scale)))

    # 定義網絡的前向計算邏輯
    # center_words是一個tensor(mini-batch),表示中心詞
    # target_words是一個tensor(mini-batch),表示目標詞
    # label是一個tensor(mini-batch),表示這個詞是正樣本還是負樣本(用0或1表示)
    # 用于在訓練中計算這個tensor中對應詞的同義詞,用于觀察模型的訓練效果
    def forward(self, center_words, target_words, label):
        # 首先,通過self.embedding參數,將mini-batch中的詞轉換為詞向量
        # 這里center_words和eval_words_emb查詢的是一個相同的參數
        # 而target_words_emb查詢的是另一個參數
        center_words_emb = self.embedding(center_words)
        target_words_emb = self.embedding_out(target_words)

        # 我們通過點乘的方式計算中心詞到目標詞的輸出概率,并通過sigmoid函數估計這個詞是正樣本還是負樣本的概率。
        word_sim = paddle.multiply(center_words_emb, target_words_emb)
        word_sim = paddle.sum(word_sim, axis=-1)
        word_sim = paddle.reshape(word_sim, shape=[-1])
        pred = F.sigmoid(word_sim)

        # 通過估計的輸出概率定義損失函數,注意我們使用的是binary_cross_entropy_with_logits函數
        # 將sigmoid計算和cross entropy合并成一步計算可以更好的優(yōu)化,所以輸入的是word_sim,而不是pred
        loss = F.binary_cross_entropy_with_logits(word_sim, label)
        loss = paddle.mean(loss)

        # 返回前向計算的結果,飛槳會通過backward函數自動計算出反向結果。
        return pred, loss




# 開始訓練,定義一些訓練過程中需要使用的超參數
batch_size = 512
epoch_num = 3
embedding_size = 200
step = 0
learning_rate = 0.001

#定義一個使用word-embedding查詢同義詞的函數
#這個函數query_token是要查詢的詞,k表示要返回多少個最相似的詞,embed是我們學習到的word-embedding參數
#我們通過計算不同詞之間的cosine距離,來衡量詞和詞的相似度
#具體實現如下,x代表要查詢詞的Embedding,Embedding參數矩陣W代表所有詞的Embedding
#兩者計算Cos得出所有詞對查詢詞的相似度得分向量,排序取top_k放入indices列表
def get_similar_tokens(query_token, k, embed):
    W = embed.numpy()
    x = W[word2id_dict[query_token]]
    cos = np.dot(W, x) / np.sqrt(np.sum(W * W, axis=1) * np.sum(x * x) + 1e-9)
    flat = cos.flatten()
    indices = np.argpartition(flat, -k)[-k:]
    indices = indices[np.argsort(-flat[indices])]
    for i in indices:
        print('for word %s, the similar word is %s' % (query_token, str(id2word_dict[i])))


# 通過我們定義的SkipGram類,來構造一個Skip-gram模型網絡
skip_gram_model = SkipGram(vocab_size, embedding_size)

# 構造訓練這個網絡的優(yōu)化器
adam = paddle.optimizer.Adam(learning_rate=learning_rate, parameters = skip_gram_model.parameters())

# 使用build_batch函數,以mini-batch為單位,遍歷訓練數據,并訓練網絡
for center_words, target_words, label in build_batch(
    dataset, batch_size, epoch_num):
    # 使用paddle.to_tensor,將一個numpy的tensor,轉換為飛槳可計算的tensor
    center_words_var = paddle.to_tensor(center_words)
    target_words_var = paddle.to_tensor(target_words)
    label_var = paddle.to_tensor(label)
    
    # 將轉換后的tensor送入飛槳中,進行一次前向計算,并得到計算結果
    pred, loss = skip_gram_model(
        center_words_var, target_words_var, label_var)

    # 程序自動完成反向計算
    loss.backward()
    # 程序根據loss,完成一步對參數的優(yōu)化更新
    adam.step()
    # 清空模型中的梯度,以便于下一個mini-batch進行更新
    adam.clear_grad()

    # 每經過100個mini-batch,打印一次當前的loss,看看loss是否在穩(wěn)定下降
    step += 1
    if step % 1000 == 0:
        print("step %d, loss %.3f" % (step, loss.numpy()[0]))

    # 每隔10000步,打印一次模型對以下查詢詞的相似詞,這里我們使用詞和詞之間的向量點積作為衡量相似度的方法,只打印了5個最相似的詞
    if step % 10000 ==0:
        get_similar_tokens('movie', 5, skip_gram_model.embedding.weight)
        get_similar_tokens('one', 5, skip_gram_model.embedding.weight)
        get_similar_tokens('chip', 5, skip_gram_model.embedding.weight)
----------------------------------------------------------------------------
step 9000, loss 0.241
step 10000, loss 0.244
for word movie, the similar word is movie
for word movie, the similar word is amigaos

step 19000, loss 0.181
step 20000, loss 0.137
for word movie, the similar word is movie
for word movie, the similar word is rosenberg

step 29000, loss 0.229
step 30000, loss 0.276
for word movie, the similar word is movie
for word movie, the similar word is canals

step 199000, loss 0.163
step 200000, loss 0.091
for word movie, the similar word is movie
for word movie, the similar word is watching


4.2 句向量 - 情感分析

人類自然語言具有高度的復雜性,相同的對話在不同的情景,不同的情感,不同的人演繹,表達的效果往往也會迥然不同。例如"你真的太瘦了",當你聊天的對象是一位身材苗條的人,這是一句贊美的話;當你聊天的對象是一位肥胖的人時,這就變成了一句嘲諷。

簡單的說,我們可以將情感分析(sentiment classification)任務定義為一個分類問題,即指定一個文本輸入,機器通過對文本進行分析、處理、歸納和推理后自動輸出結論,如圖1所示。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

通常情況下,人們把情感分析任務看成一個三分類問題

  • 正向:?表示正面積極的情感,如高興,幸福,驚喜,期待等。

  • 負向:?表示負面消極的情感,如難過,傷心,憤怒,驚恐等。

  • 其他:?其他類型的情感。

上面我們剛學習了通過把每個單詞轉換成向量的方式,可以完成單詞語義計算任務。那么我們自然會聯想到,是否可以把每個自然語言句子也轉換成一個向量表示,并使用這個向量表示完成情感分析任務呢?

在日常工作中有一個非常簡單粗暴的解決方式:就是先把一個句子中所有詞的embedding進行加權平均,再用得到的平均embedding作為整個句子的向量表示。然而由于自然語言變幻莫測,我們在使用神經網絡處理句子的時候,往往會遇到如下兩類問題:

  • 變長的句子:?自然語言句子往往是變長的,不同的句子長度可能差別很大。然而大部分神經網絡接受的輸入都是張量,長度是固定的,那么如何讓神經網絡處理變長數據成為了一大挑戰(zhàn)。

  • 組合的語義:?自然語言句子往往對結構非常敏感,有時稍微顛倒單詞的順序都可能改變這句話的意思,比如:

    你等一下我做完作業(yè)就走。

    我等一下你做完工作就走。

    我不愛吃你做的飯。

    你不愛吃我做的飯。

    我瞅你咋地。

    你瞅我咋地。

因此,我們需要找到一個可以考慮詞和詞之間順序(關系)的神經網絡,用于更好地實現自然語言句子建模。目前大多數成功的自然語言模型都建立在對句子的序列化建模上。兩個經典的序列化建模模型是:

  • 循環(huán)神經網絡(Recurrent Neural Network,RNN)
  • 長短時記憶網絡(Long Short-Term Memory,LSTM)

RNN相當于將神經網絡單元進行了橫向連接,處理前一部分輸入的RNN單元不僅有正常的模型輸出,還會輸出“記憶”傳遞到下一個RNN單元。而處于后一部分的RNN單元,不僅僅有來自于任務數據的輸入,同時會接收從前一個RNN單元傳遞過來的記憶輸入,這樣就使得整個神經網絡具備了“記憶”能力。但RNN對“記憶”能力的設計是比較粗糙的,當網絡處理的序列數據過長時,累積的內部信息就會越來越復雜,直到超過網絡的承載能力,通俗的說“事無巨細的記錄,總有一天大腦會崩潰”。

為了解決這個問題,科學家巧妙的設計了一種記憶單元,稱之為“長短時記憶網絡(Long Short-Term Memory,LSTM)”。利用LSTM我可以把詞向量進一步提煉為句向量,步驟是先獲取一段文本的詞向量,再將詞向量按順序輸入給LSTM,最終LSTM會輸出一個向量,即為這段文本的句向量。

4.2.1 LSTM (Long Short-Term Memory)介紹

短期記憶網絡(LSTM,Long Short-Term Memory)是一種時間循環(huán)神經網絡,是為了解決一般的RNN(循環(huán)神經網絡)存在的長期依賴問題而專門設計出來的,所有的RNN都具有一種重復神經網絡模塊的鏈式形式。在標準RNN中,這個重復的結構模塊只有一個非常簡單的結構。LSTM則更復雜,它是由一系列LSTM單元(LSTM Unit)組成,其鏈式結構如下圖。每個網絡模塊中都含一線(記憶線)三門(遺忘門,輸入門,輸出門)。每個模塊代表一個時刻。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

LSTM在每個處理單元內部,加入了輸入門、輸出門和遺忘門的設計,三者有明確的任務分工:

  • 輸入門:控制有多少輸入信號會被融合;
  • 遺忘門:控制有多少過去的記憶會被遺忘;
  • 輸出門:控制多少處理后的信息會被輸出;

三者的作用與人類的記憶方式有異曲同工之處,即:

  • 與當前任務無關的信息會直接過濾掉,如非常專注的開車時,人們幾乎不注意沿途的風景;
  • 過去記錄的事情不一定都要永遠記住,如令人傷心或者不重要的事,通常會很快被淡忘;
  • 根據記憶和現實觀察進行決策,如開車時會結合記憶中的路線和當前看到的路標,決策轉彎或不做任何動作。?

下面對模塊內部分別介紹。

記憶線(Ct):相當于一條記憶傳送帶,上面放置了從 0 到 t 時刻的語言輸入的信息

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

??

遺忘門(ft): 用來決定把記憶傳送帶上哪些信息給剔除掉,用來確保記憶線上的信息不會過于冗余和復雜。遺忘門的輸入是當前時刻的輸入和上一時刻的輸出。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

輸入門(it):輸入門是來決定將哪些新的信息放到記憶線上,它的輸入也是當前時刻的輸入和上一時刻的輸出。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

?輸出門(Ot):輸出門決定本時刻的輸出,它的輸入也是當前時刻的輸入和上一時刻的輸出。最終它會和記憶線進行運算得到當前時刻的輸出ht。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

4.2.2 基于飛槳實現的情感分析模型

首先,需要下載語料用于模型訓練和評估效果。我們使用的是IMDB的電影評論數據,這個數據集是一個開源的英文數據集,由訓練數據和測試數據組成。每個數據都分別由若干小文件組成,每個小文件內部都是一段用戶關于某個電影的真實評價,以及觀眾對這個電影的情感傾向(是正向還是負向),數據集下載的代碼如下:

def download():
    # 通過python的requests類,下載存儲在
    # https://dataset.bj.bcebos.com/imdb%2FaclImdb_v1.tar.gz的文件
    corpus_url = "https://dataset.bj.bcebos.com/imdb%2FaclImdb_v1.tar.gz"
    web_request = requests.get(corpus_url)
    corpus = web_request.content

    # 將下載的文件寫在當前目錄的aclImdb_v1.tar.gz文件內
    with open("./aclImdb_v1.tar.gz", "wb") as f:
        f.write(corpus)
    f.close()

download()



#將數據集加載到程序中,并打印一小部分數據觀察一下數據集的特點,代碼如下
def load_imdb(is_training):
    data_set = []

    # aclImdb_v1.tar.gz解壓后是一個目錄
    # 我們可以使用python的rarfile庫進行解壓
    # 訓練數據和測試數據已經經過切分,其中訓練數據的地址為:
    # ./aclImdb/train/pos/ 和 ./aclImdb/train/neg/,分別存儲著正向情感的數據和負向情感的數據
    # 我們把數據依次讀取出來,并放到data_set里
    # data_set中每個元素都是一個二元組,(句子,label),其中l(wèi)abel=0表示負向情感,label=1表示正向情感
    
    for label in ["pos", "neg"]:
        with tarfile.open("./aclImdb_v1.tar.gz") as tarf:
            path_pattern = "aclImdb/train/" + label + "/.*\\.txt$" if is_training \
                else "aclImdb/test/" + label + "/.*\\.txt$"
            path_pattern = re.compile(path_pattern)
            tf = tarf.next()
            while tf != None:
                if bool(path_pattern.match(tf.name)):
                    sentence = tarf.extractfile(tf).read().decode()
                    sentence_label = 0 if label == 'neg' else 1
                    data_set.append((sentence, sentence_label)) 
                tf = tarf.next()

    return data_set

train_corpus = load_imdb(True)
test_corpus = load_imdb(False)

for i in range(5):
    print("sentence %d, %s" % (i, train_corpus[i][0]))    
    print("sentence %d, label %d" % (i, train_corpus[i][1]))
-----------------------------------------------------------------------------
sentence 0, Zentropa has much in common with The Third Man, another noir-like film set among the rubble of postwar Europe.
sentence 0, label 1
sentence 1, Zentropa is the most original movie
sentence 1, label 1




#在自然語言處理中,需要先對語料進行切詞,這里我們可以使用空格把每個句子切成若干詞的序列
def data_preprocess(corpus):
    data_set = []
    for sentence, sentence_label in corpus:
        # 這里有一個小trick是把所有的句子轉換為小寫,從而減小詞表的大小
        # 一般來說這樣的做法有助于效果提升
        sentence = sentence.strip().lower()
        sentence = sentence.split(" ")
        
        data_set.append((sentence, sentence_label))

    return data_set

train_corpus = data_preprocess(train_corpus)
test_corpus = data_preprocess(test_corpus)
print(train_corpus[:5])
print(test_corpus[:5])
-------------------------------------------------------------------------------------
[(['zentropa', 'has', 'much', 'in', 'common', 'with', 'the', 
[(['previous', 'reviewer', 'claudio', 'carvalho', 'gave', 




#在經過切詞后,需要構造一個詞典,把每個詞都轉化成一個ID,以便于神經網絡訓練
# 構造詞典,統計每個詞的頻率,并根據頻率將每個詞轉換為一個整數id
def build_dict(corpus):
    word_freq_dict = dict()
    for sentence, _ in corpus:
        for word in sentence:
            if word not in word_freq_dict:
                word_freq_dict[word] = 0
            word_freq_dict[word] += 1

    word_freq_dict = sorted(word_freq_dict.items(), key = lambda x:x[1], reverse = True)
    
    word2id_dict = dict()
    word2id_freq = dict()

    # 一般來說,我們把oov和pad放在詞典前面,給他們一個比較小的id,這樣比較方便記憶,并且易于后續(xù)擴展詞表
    word2id_dict['[oov]'] = 0
    word2id_freq[0] = 1e10

    word2id_dict['[pad]'] = 1
    word2id_freq[1] = 1e10

    for word, freq in word_freq_dict:
        word2id_dict[word] = len(word2id_dict)
        word2id_freq[word2id_dict[word]] = freq

    return word2id_freq, word2id_dict




# 把語料轉換為id序列
def convert_corpus_to_id(corpus, word2id_dict):
    data_set = []
    for sentence, sentence_label in corpus:
        # 將句子中的詞逐個替換成id,如果句子中的詞不在詞表內,則替換成oov
        # 這里需要注意,一般來說我們可能需要查看一下test-set中,句子oov的比例,
        # 如果存在過多oov的情況,那就說明我們的訓練數據不足或者切分存在巨大偏差,需要調整
        sentence = [word2id_dict[word] if word in word2id_dict \
                    else word2id_dict['[oov]'] for word in sentence]    
        data_set.append((sentence, sentence_label))
    return data_set

train_corpus = convert_corpus_to_id(train_corpus, word2id_dict)
test_corpus = convert_corpus_to_id(test_corpus, word2id_dict)
print("%d tokens in the corpus" % len(train_corpus))
print(train_corpus[:5])
print(test_corpus[:5])
-------------------------------------------------------------------------------
25000 tokens in the corpus
[([22216, 41, 76, 8, 1136, 17, 2, 874, 979, 167,
[([868, 2313, 29392, 0, 442, 3, 76, 138, 20739, 5,




#把原始語料中的每個句子通過截斷和填充,轉換成一個固定長度的句子,并將所有數據整理成mini-batch,用于訓練模型
# 編寫一個迭代器,每次調用這個迭代器都會返回一個新的batch,用于訓練或者預測
def build_batch(word2id_dict, corpus, batch_size, epoch_num, max_seq_len, shuffle = True, drop_last = True):

    # 模型將會接受的兩個輸入:
    # 1. 一個形狀為[batch_size, max_seq_len]的張量,sentence_batch,代表了一個mini-batch的句子。
    # 2. 一個形狀為[batch_size, 1]的張量,sentence_label_batch,每個元素都是非0即1,代表了每個句子的情感類別(正向或者負向)
    sentence_batch = []
    sentence_label_batch = []

    for _ in range(epoch_num): 

        #每個epoch前都shuffle一下數據,有助于提高模型訓練的效果
        #但是對于預測任務,不要做數據shuffle
        if shuffle:
            random.shuffle(corpus)

        for sentence, sentence_label in corpus:
            sentence_sample = sentence[:min(max_seq_len, len(sentence))]
            if len(sentence_sample) < max_seq_len:
                for _ in range(max_seq_len - len(sentence_sample)):
                    sentence_sample.append(word2id_dict['[pad]'])
            
            
            sentence_sample = [[word_id] for word_id in sentence_sample]

            sentence_batch.append(sentence_sample)
            sentence_label_batch.append([sentence_label])

            if len(sentence_batch) == batch_size:
                yield np.array(sentence_batch).astype("int64"), np.array(sentence_label_batch).astype("int64")
                sentence_batch = []
                sentence_label_batch = []
    if not drop_last and len(sentence_batch) > 0:
        yield np.array(sentence_batch).astype("int64"), np.array(sentence_label_batch).astype("int64")

for batch_id, batch in enumerate(build_batch(word2id_dict, train_corpus, batch_size=3, epoch_num=3, max_seq_len=30)):
    print(batch)
    break
-----------------------------------------------------------------------------
(array([[[  3589],
        [   161],
        [     7],
        [     3],
        [    56],
        [   139],
        [    18],
        [     6],




# 定義一個用于情感分類的網絡實例,SentimentClassifier
class SentimentClassifier(paddle.nn.Layer):
    
    def __init__(self, hidden_size, vocab_size, embedding_size, class_num=2, num_steps=128, num_layers=1, init_scale=0.1, dropout_rate=None):
        
        # 參數含義如下:
        # 1.hidden_size,表示embedding-size,hidden和cell向量的維度
        # 2.vocab_size,模型可以考慮的詞表大小
        # 3.embedding_size,表示詞向量的維度
        # 4.class_num,情感類型個數,可以是2分類,也可以是多分類
        # 5.num_steps,表示這個情感分析模型最大可以考慮的句子長度
        # 6.num_layers,表示網絡的層數
        # 7.dropout_rate,表示使用dropout過程中失活的神經元比例
        # 8.init_scale,表示網絡內部的參數的初始化范圍,長短時記憶網絡內部用了很多Tanh,Sigmoid等激活函數,\
        # 這些函數對數值精度非常敏感,因此我們一般只使用比較小的初始化范圍,以保證效果
        super(SentimentClassifier, self).__init__()
        self.hidden_size = hidden_size
        self.vocab_size = vocab_size
        self.embedding_size = embedding_size
        self.class_num = class_num
        self.num_steps = num_steps
        self.num_layers = num_layers
        self.dropout_rate = dropout_rate
        self.init_scale = init_scale
       
        # 聲明一個LSTM模型,用來把每個句子抽象成向量
        self.simple_lstm_rnn = paddle.nn.LSTM(input_size=hidden_size, hidden_size=hidden_size, num_layers=num_layers)

        # 聲明一個embedding層,用來把句子中的每個詞轉換為向量
        self.embedding = paddle.nn.Embedding(num_embeddings=vocab_size, embedding_dim=embedding_size, sparse=False, 
                                    weight_attr=paddle.ParamAttr(initializer=paddle.nn.initializer.Uniform(low=-init_scale, high=init_scale)))
        
        # 聲明使用上述語義向量映射到具體情感類別時所需要使用的線性層
        self.cls_fc = paddle.nn.Linear(in_features=self.hidden_size, out_features=self.class_num, 
                             weight_attr=None, bias_attr=None)
        
        # 一般在獲取單詞的embedding后,會使用dropout層,防止過擬合,提升模型泛化能力
        self.dropout_layer = paddle.nn.Dropout(p=self.dropout_rate, mode='upscale_in_train')

    # forwad函數即為模型前向計算的函數,它有兩個輸入,分別為:
    # input為輸入的訓練文本,其shape為[batch_size, max_seq_len]
    # label訓練文本對應的情感標簽,其shape維[batch_size, 1]
    def forward(self, inputs):
        # 獲取輸入數據的batch_size
        batch_size = inputs.shape[0]

        # 本實驗默認使用1層的LSTM,首先我們需要定義LSTM的初始hidden和cell,這里我們使用0來初始化這個序列的記憶
        init_hidden_data = np.zeros(
            (self.num_layers, batch_size, self.hidden_size), dtype='float32')
        init_cell_data = np.zeros(
            (self.num_layers, batch_size, self.hidden_size), dtype='float32')

        # 將這些初始記憶轉換為飛槳可計算的向量,并且設置stop_gradient=True,避免這些向量被更新,從而影響訓練效果
        init_hidden = paddle.to_tensor(init_hidden_data)
        init_hidden.stop_gradient = True
        init_cell = paddle.to_tensor(init_cell_data)
        init_cell.stop_gradient = True

        # 對應以上第2步,將輸入的句子的mini-batch轉換為詞向量表示,轉換后輸入數據shape為[batch_size, max_seq_len, embedding_size]
        x_emb = self.embedding(inputs)
        x_emb = paddle.reshape(x_emb, shape=[-1, self.num_steps, self.embedding_size])
        # 在獲取的詞向量后添加dropout層
        if self.dropout_rate is not None and self.dropout_rate > 0.0:
            x_emb = self.dropout_layer(x_emb)
        
        # 對應以上第3步,使用LSTM網絡,把每個句子轉換為語義向量
        # 返回的last_hidden即為最后一個時間步的輸出,其shape為[self.num_layers, batch_size, hidden_size]
        rnn_out, (last_hidden, last_cell) = self.simple_lstm_rnn(x_emb, (init_hidden, init_cell))
        # 提取最后一層隱狀態(tài)作為文本的語義向量,其shape為[batch_size, hidden_size]
        last_hidden = paddle.reshape(last_hidden[-1], shape=[-1, self.hidden_size])

        # 對應以上第4步,將每個句子的向量表示映射到具體的情感類別上, logits的維度為[batch_size, 2]
        logits = self.cls_fc(last_hidden)
        
        return logits




#模型訓練
paddle.seed(0)
random.seed(0)
np.random.seed(0)

# 定義訓練參數
epoch_num = 5
batch_size = 128

learning_rate = 0.0001
dropout_rate = 0.2
num_layers = 1
hidden_size = 256
embedding_size = 256
max_seq_len = 128
vocab_size = len(word2id_freq)

# 實例化模型
sentiment_classifier = SentimentClassifier(hidden_size, vocab_size, embedding_size,  num_steps=max_seq_len, num_layers=num_layers, dropout_rate=dropout_rate)

# 指定優(yōu)化策略,更新模型參數
optimizer = paddle.optimizer.Adam(learning_rate=learning_rate, beta1=0.9, beta2=0.999, parameters= sentiment_classifier.parameters()) 

# 定義訓練函數
# 記錄訓練過程中的損失變化情況,可用于后續(xù)畫圖查看訓練情況
losses = []
steps = []

def train(model):
    # 開啟模型訓練模式
    model.train()
    
    # 建立訓練數據生成器,每次迭代生成一個batch,每個batch包含訓練文本和文本對應的情感標簽
    train_loader = build_batch(word2id_dict, train_corpus, batch_size, epoch_num, max_seq_len)
    
    for step, (sentences, labels) in enumerate(train_loader):
        # 獲取數據,并將張量轉換為Tensor類型
        sentences = paddle.to_tensor(sentences)
        labels = paddle.to_tensor(labels)
        
        # 前向計算,將數據feed進模型,并得到預測的情感標簽和損失
        logits = model(sentences)

        # 計算損失
        loss = F.cross_entropy(input=logits, label=labels, soft_label=False)
        loss = paddle.mean(loss)

        # 后向傳播
        loss.backward()
        # 更新參數
        optimizer.step()
        # 清除梯度
        optimizer.clear_grad()

        if step % 100 == 0:
            # 記錄當前步驟的loss變化情況
            losses.append(loss.numpy()[0])
            steps.append(step)
            # 打印當前l(fā)oss數值
            print("step %d, loss %.3f" % (step, loss.numpy()[0]))

#訓練模型
train(sentiment_classifier)

# 保存模型,包含兩部分:模型參數和優(yōu)化器參數
model_name = "sentiment_classifier"
# 保存訓練好的模型參數
paddle.save(sentiment_classifier.state_dict(), "{}.pdparams".format(model_name))
# 保存優(yōu)化器參數,方便后續(xù)模型繼續(xù)訓練
paddle.save(optimizer.state_dict(), "{}.pdopt".format(model_name))




#模型評估
def evaluate(model):
    # 開啟模型測試模式,在該模式下,網絡不會進行梯度更新
    model.eval()

    # 定義以上幾個統計指標
    tp, tn, fp, fn = 0, 0, 0, 0

    # 構造測試數據生成器
    test_loader = build_batch(word2id_dict, test_corpus, batch_size, 1, max_seq_len)
    
    for sentences, labels in test_loader:
        # 將張量轉換為Tensor類型
        sentences = paddle.to_tensor(sentences)
        labels = paddle.to_tensor(labels)
        
        # 獲取模型對當前batch的輸出結果
        logits = model(sentences)
        
        # 使用softmax進行歸一化
        probs = F.softmax(logits)

        # 把輸出結果轉換為numpy array數組,比較預測結果和對應label之間的關系,并更新tp,tn,fp和fn
        probs = probs.numpy()
        for i in range(len(probs)):
            # 當樣本是的真實標簽是正例
            if labels[i][0] == 1:
                # 模型預測是正例
                if probs[i][1] > probs[i][0]:
                    tp += 1
                # 模型預測是負例
                else:
                    fn += 1
            # 當樣本的真實標簽是負例
            else:
                # 模型預測是正例
                if probs[i][1] > probs[i][0]:
                    fp += 1
                # 模型預測是負例
                else:
                    tn += 1

    # 整體準確率
    accuracy = (tp + tn) / (tp + tn + fp + fn)
    
    # 輸出最終評估的模型效果
    print("TP: {}\nFP: {}\nTN: {}\nFN: {}\n".format(tp, fp, tn, fn))
    print("Accuracy: %.4f" % accuracy)

# 加載訓練好的模型進行預測,重新實例化一個模型,然后將訓練好的模型參數加載到新模型里面
saved_state = paddle.load("./sentiment_classifier.pdparams")
sentiment_classifier = SentimentClassifier(hidden_size, vocab_size, embedding_size,  num_steps=max_seq_len, num_layers=num_layers, dropout_rate=dropout_rate)
sentiment_classifier.load_dict(saved_state)

# 評估模型
evaluate(sentiment_classifier)

借助相同的思路,我們可以很輕易的解決文本相似度計算問題,假設給定兩個句子:

句子1:我不愛吃烤冷面,但是我愛吃冷面

句子2:我愛吃菠蘿,但是不愛吃地瓜

同樣使用LSTM網絡,把每個句子抽象成一個向量表示,通過計算這兩個向量之間的相似度,就可以快速完成文本相似度計算任務。在實際場景里,我們也通常使用LSTM網絡的最后一步hidden結果,將一個句子抽象成一個向量,然后通過向量點積,或者cosine相似度的方式,去衡量兩個句子的相似度。

4.3?BERT模型

大名鼎鼎的BERT,全稱為Bidirectional Encoder Representation from Transformers,是一個預訓練的語言表征模型。BERT論文發(fā)表時提及在11個NLP(Natural Language Processing,自然語言處理)任務中獲得了新的state-of-the-art的結果,表現非常驚艷。

BERT在訓練過程中,不再像以往一樣采用傳統的單向語言模型或者把兩個單向語言模型進行淺層拼接的方法進行預訓練,而是使用了基于掩蓋的語言模型(Masked Language Model, MLM),即隨機對輸入序列中的某些位置進行遮蔽,然后通過模型來對其進行預測,以生成深度的雙向語言表征。

BERT在預訓練時使用的是大量的無標注的語料(比如隨手可見的一些文本,它是沒有標注的)。所以它在預訓練任務設計的時候,一定是要考慮無監(jiān)督來做,因為是沒有標簽的。

對于無監(jiān)督的目標函數來講,有兩組目標函數比較受到重視,
第一種是?AR模型,auto regressive,自回歸模型。只能考慮單側信息,典型的就是GPT。

另一種是AE模型,auto encoding,自編碼模型。從損壞的輸入數據中預測重建原始數據,可以使用上下文的信息。BERT使用的就是AE。這種方式可以讓模型根據上下文充分的預測缺失信息。

人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量,人工智能技術學習,人工智能,學習,筆記

如上圖所示便是ML和NSP這兩個任務在BERT預訓練時的輸入輸出示意圖,其中最上層輸出的在預訓練時用于NSP中的分類任務;其它位置上的,則用于預測被掩蓋的Token。

對于BERT來說,如果單從網絡結構上來說的話,感覺并沒有太大的創(chuàng)新,這也正如作者所說“BERT整體上就是由多層的Transformer Encoder堆疊所形成”,并且所謂的“Bidirectional”其實指的也就是Transformer中的self-attention機制。真正讓BERT表現出色的應該是基于MLM和NSP這兩種任務的預訓練過程,使得訓練得到的模型具有強大的表征能力。

輔助閱讀:BERT原理與NSP和MLM - 知乎文章來源地址http://www.zghlxwxcb.cn/news/detail-829673.html

到了這里,關于人工智能學習與實訓筆記(四):神經網絡之NLP基礎—詞向量的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 人工智能學習與實訓筆記(九):Langchain + 百度大模型實戰(zhàn)案例

    人工智能學習與實訓筆記(九):Langchain + 百度大模型實戰(zhàn)案例

    人工智能專欄文章匯總:人工智能學習專欄文章匯總-CSDN博客 本篇目錄 1. LLMChain 2.?Sequential Chains SimpleSequentialChain SequentialChain 3. Router Chain 4. Documents Chain 5. Document?Loaders(文檔加載器) 6. Text Splitter(文本分割器) 7.?Vectorstores(向量存儲器) 8.?Retriever(檢索器) 9. Agent(代

    2024年04月13日
    瀏覽(26)
  • 人工智能學習與實訓筆記(十):百度對話大模型ERNIE調用實操

    人工智能學習與實訓筆記(十):百度對話大模型ERNIE調用實操

    人工智能專欄文章匯總:人工智能學習專欄文章匯總-CSDN博客 本篇目錄 一、直接基于ERNIE Bot Sdk調用 1. SDK基礎 1.1 安裝EB SDK 1.2 認證鑒權 1.3 EB SDK Hello-World 1.4 多輪對話 1.5 語義向量 1.6?文生圖 2.?SDK進階 - 對話補全(Chat Completion) 2.1 通過參數調節(jié)響應結果多樣性 2.2 流式傳輸

    2024年02月20日
    瀏覽(26)
  • 深度學習2.神經網絡、機器學習、人工智能

    深度學習2.神經網絡、機器學習、人工智能

    目錄 深度學習、神經網絡、機器學習、人工智能的關系 大白話解釋深度學習 傳統機器學習 VS 深度學習 深度學習的優(yōu)缺點 4種典型的深度學習算法 卷積神經網絡 – CNN 循環(huán)神經網絡 – RNN 生成對抗網絡 – GANs 深度強化學習 – RL 總結 深度學習 深度學習、機器學習、人工智能

    2024年02月11日
    瀏覽(142)
  • 【AI】了解人工智能、機器學習、神經網絡、深度學習

    【AI】了解人工智能、機器學習、神經網絡、深度學習

    一、深度學習、神經網絡的原理是什么? 深度學習和神經網絡都是基于對人腦神經系統的模擬。下面將分別解釋深度學習和神經網絡的原理。 深度學習的原理: 深度學習是一種特殊的機器學習,其模型結構更為復雜,通常包括很多隱藏層。它依賴于神經網絡進行模型訓練和

    2024年02月06日
    瀏覽(104)
  • 人工智能|機器學習——循環(huán)神經網絡的簡潔實現

    人工智能|機器學習——循環(huán)神經網絡的簡潔實現

    循環(huán)神經網絡的簡潔實現 如何使用深度學習框架的高級API提供的函數更有效地實現相同的語言模型。 我們仍然從讀取時光機器數據集開始。 定義模型 高級API提供了循環(huán)神經網絡的實現。 我們構造一個具有256個隱藏單元的單隱藏層的循環(huán)神經網絡層 rnn_layer 。 事實上,我們

    2024年02月04日
    瀏覽(20)
  • 頭歌平臺-人工智能技術應用-實踐學習與答案2(補充實訓部分)

    注:這一題的輸出沒有很符合我的預期,所以我干脆直接改了他的print輸出,用自己更喜歡的方式輸出 注: 這里對字典的統計我引入了defaultdict函數(這個函數是用來新建一個鍵值對的),算是額外引入了一個算法庫使用 測試用例: 一、 針對集體宿舍人員如何科學防控的問

    2024年02月07日
    瀏覽(30)
  • AI學術交流——“人工智能”和“神經網絡學習”

    AI學術交流——“人工智能”和“神經網絡學習”

    作者簡介:一名云計算網絡運維人員、每天分享網絡與運維的技術與干貨。? ?座右銘:低頭趕路,敬事如儀 個人主頁:網絡豆的主頁????? 目錄 前言 一.人工智能 1.“人工智能之父” 2.達特茅斯會議(人工智能起源) 3.人工智能重要節(jié)點 二.神經網絡 1.什么是神經網絡

    2024年02月09日
    瀏覽(99)
  • 魚類識別Python+深度學習人工智能+TensorFlow+卷積神經網絡算法

    魚類識別Python+深度學習人工智能+TensorFlow+卷積神經網絡算法

    魚類識別系統。使用Python作為主要編程語言開發(fā),通過收集常見的30種魚類(‘墨魚’, ‘多寶魚’, ‘帶魚’, ‘石斑魚’, ‘秋刀魚’, ‘章魚’, ‘紅魚’, ‘羅非魚’, ‘胖頭魚’, ‘草魚’, ‘銀魚’, ‘青魚’, ‘馬頭魚’, ‘魷魚’, ‘鲇魚’, ‘鱸魚’, ‘鮑魚’, ‘鮭

    2024年02月02日
    瀏覽(113)
  • 【人工智能】圖文詳解深度學習中的卷積神經網絡(CNN)
  • 【人工智能與機器學習】基于卷積神經網絡CNN的貓狗識別

    【人工智能與機器學習】基于卷積神經網絡CNN的貓狗識別

    很巧,筆者在幾月前的計算機設計大賽作品設計中也采用了貓狗識別,目前已推國賽評選中 但當時所使用的方法與本次作業(yè)要求不太一致,又重新做了一遍,下文將以本次作業(yè)要求為主,介紹CNN卷積神經網絡實現貓狗識別 貓狗識別和狗品種識別是計算機視覺領域中一個重要

    2024年02月13日
    瀏覽(45)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包