nlp研究方向的修正

給你一篇文章或者一個句子,人們在理解這些句子時,頭腦中會進行上下文的搜索和知識聯想。對於一篇有思想的文章,作者的創作構思以及核心思想,我們人腦基本的處理邏輯都是結合過去學習過的規則和概念進行抽象總結。作者的創作過程可以形成一個圖模型,清晰地展示出路徑。目前的nlp根本達不到,都是淺層次的操作,因爲目前的nlp基本上借鑑了圖像處理機制,根本沒有觸及nlp的本質。nlp的進展將會十分艱難,因爲機器永遠不能理解字符串背後的涵義以及說話者到底發生了什麼。目前來看,只有知識圖譜算是當今Ai最有前景,道路最正確的一個研究方向。邏輯推理還有很長的路,吳文俊公式在理論上已經給出了支持,但是應用在計算機中困難重重。
  通常情況下,人在理解語義時頭腦會搜尋與之相關的知識。知識圖譜的創始人人爲,構成這個世界的是實體,而不是字符串,這從根本上改變了過去的搜索體系。語義理解其實是基於知識、概念以及這些概念間的關係。人們在解答問題時,往往會講述與這個問題相關的知識,這是語義理解的過程。這種機制完全不同於人對圖像或者語音的認識。CNN在圖像或者語音領域取得成果是不足爲奇的,因爲生物學家已經對人腦神經元在圖像識別過程中的機制非常熟悉,但是對於人腦如何理解文字的神經元機制卻知之甚少,所以導致了目前nlp語義理解方面進展非常緩慢。然而有的學者研究規則專家系統已經長達20多年,本人堅信這是正確的方向,最起碼比單純研究深度學習更有實際意義。研究nlp,語言邏輯,語言學是必修課,目前深度學習的瓶頸早就已經顯現出來了,而且門檻兒遠低於知識圖譜,規則專家系統。
  單就深度學習來看的話,學院派的人花費大量精力在NLG,seq2seq,多任務自然語言生成等等上面。這些在知識圖譜專家或者語言學家眼中就是學術界的玩票兒。本人在剛開始介入nlp學習的過程中,對深度學習很瘋狂,尤其是seq2seq,後來請教王昊奮專家,王就很坦白地跟我說seq2seq是玩票兒,坑了很多人,包括在校研究生。所以本人從那以後重新反思之前的學習,重新確立方向,先把數學專業的數學進修好,包括6本數學著作涵蓋泛函數,微積分,線代,統計學,矩陣論,凸優化。然後重點轉向圖模型推理,知識圖譜的研究學習。在學習的過程中,前期走了很多彎路,幸虧及時修正了方向,要不然將會陷入深度學習的陷阱之中。當然深度學習並不是一無是處,最起碼在圖像中取得了非常好的效果,是成功的。在nlp中,深度學習與圖模型結合初步解決推理問題也是成功的,谷歌大腦和DeepMind在18年已經做了嘗試並且開源了代碼。也就說深度學習引入到nlp中需要改進,一方面要改進自身的算法,比如CNN的動態池化層改進,輸入層embedding的知識圖譜嵌入擴展,另一方面又要與圖模型,統計學進行融合。現在Ai界比較熱的兩大研究方向:一是AutoML,二是神經規則推理。在神經網絡參數優化方面,遺傳算法是重點。在聯結主義和符號主義融合方面,國內的呂正東博士是先鋒,他的深度好奇公司已經邁出來第一步。   
  之前在網上看到很多介紹word2vector的博客,本人發現其中有很多錯誤。論述很多篇幅並沒有抓住他的本質。還有一部分人質疑word2vector不是深度學習,說層數太淺達不到深度的級別,這是一種誤解。word2vector是地地道道的深度學習,能夠抽取出詞的高階特徵。他的成功,關鍵是基於他的核心思想:相同語境出現的詞語義相近。這在nlp中是非常重要的一個思想,利用上下文。除去上下文的影響因素,單純從數學公式來看,w2v的skip_gram是logistic regression的升級版。所以w2v其實是很簡單的,但是背後的想法不簡單。這也是國內的研究人員與美國的研究人員的差距,國內人員習慣於複雜的公式推導,但是想法很low,美國正好相反。這一點從數學教育就可以看出來,國內熱衷於感知層面的數學學習,和機器差不多。而國外主要從認知層面來學習數學。物理學,數學,神經生物學,生活常識都可以是想法的來源,比如上個世紀的pagerank好像很簡單,但是歐洲的學者利用隨機遊走模型能夠模擬出成功和運氣之間存在很強的相關性。即使是簡單的算法,國內的人也想不出來,原因是人天性裏的好奇心和創造力從小被解題和刷題給滅掉了。
  再比如,給你一篇文章,抽取出其中的中心句或者總結出中心思想(當然了,只有中國的語文教學這樣教學生,把學生教傻了,當前的在線教育利用Ai助紂爲虐就是個妖魔化方向)。首先你得研究作爲一個人本身的處理邏輯,然後從中抽象出數學模型然後再與Ai結合。

Ai的研究本質上就是對人腦邏輯的研究

這就是上層的靈感,尤其是幼兒時期的非經驗主義的學習,不需要海量數據的灌輸。這一點國內非常落伍,基本都是從google扒美國的論文,拿過來研究一下改改。去年百度副總閉關幾個月閱讀《腦科學導論》反思當下的深度學習,請問AI創業公司有幾個能做到?除了吹牛還有別的本事嗎?更進一步說,人本身就是十分複雜精密的機器,從DNA指導蛋白質合成過程就可以看出,人一定是上帝造出來的機器,不可能是隨機組合,概率真的真的太太太低了。只有修正了認知纔會進步。回到剛提出的問題,抽出中心句的過程,人腦邏輯是衡量上下文和假設中心句的語義相似度。所以纔會有另一篇本人寫的博客。
  目前來看,LSTM以及Attention Model是比較成功的,但是仍然基於形式化的,對於深層語義仍然沒有解決,必須依靠規則專家系統!目前來看,深度學習算法LSTM,Attention Model等在nlp中的應用,僅限於上下文和詞,句子向量。計算一下句子相似度,聚類之類的,要想真正讓機器理解文字,還達不到。也就是說只在語義表示層做文章是遠遠不夠的,底層的知識圖譜是關鍵。Google提出的知識圖譜是一種變革,nlp是一個完整的生態圈,從最底層的存儲,GDB三元組(entry,relation,entry),到上層的語義表示(這個階段可以藉助深度學習直接在語義層進行訓練),比如(head,relation,tail)三元組表示的圖結構,表達了實體與實體間的關係,可以用深度學習訓練出一個模型:h + r = t,獲取語義表示。這樣在預測時,得到了兩個實體的語義表示,進行減法運算就可以知道兩者的關係。這個不同於word2vector,但是還是有共性的。word2vector的模型訓練和kg的向量化,兩者其實存在一定的關聯。前者可以看成是kg圖結構碾平之後的序列化的向量表示。目前trans系列和基於語義相似度模型都可以解決kg的向量化。
  實體,關係和規則是深度學習引入到nlp中必須考慮的,也是邏輯推理的基本要素。深度學習獲取語義表示(不僅限於文字,也可是一個有多維度的圖節點),必須與規則交互,規則表明了實體之間如何交互。語義表示和規則是深度學習兩大構成要素,二者相互交互。  
  語義表示是深度學習在nlp文字應用中的方向。之前在詞embedding上word2vector獲取了巨大成功,現在主要方向是由詞embedding遷移到句子或者文章embedding。獲取句子的embedding,之前的博客,siamese lstm已經有論述了,在2014~2015年間,國外的學者探索了各種方法,比如tree-lstm,convnet,skip-thougt,基於ma機構的siamese lstm來計算句子或者文章的相似度。目前從數據來看,基於ma結構的siamese lstm效果最好,最適應nlp的規律。在github上已經有了siamese lstm的實驗,進一步改進是基於BiLSTM+self_attention(本人提出),至於增加層數是否能夠帶來準確率的提升,有待於進一步論證,個人持中立態度。現在上傳用tensorflow實現的word2vector代碼(negative sampleing)作爲結尾:

data-helper.py:	
import collections
import os
import random
import zipfile
import numpy as np
import urllib.request as request
import tensorflow as tf
 
url = 'http://mattmahoney.net/dc/'
 
def maybe_download(filename,expected_bytes):
    if not os.path.exists(filename):
        filename,_ = request.urlretrieve(url+filename,filename)
    statinfo = os.stat(filename)
    if statinfo.st_size == expected_bytes:
        print('Found and verified',filename)
    else:
        print(statinfo.st_size)
        raise Exception('Failed to verify' + filename + '.Can you get to it with a browser?')
    return filename
 
def read_data(filename):
    with zipfile.ZipFile(filename) as f:
        data = tf.compat.as_str(f.read(f.namelist()[0])).split()
    return data
 
vocabulary_size = 50000
def build_dataset(words):
    count = [['UNK',-1]]
    count.extend(collections.Counter(words).most_common(vocabulary_size - 1))
    dictionary = dict(zip(list(zip(*count))[0],range(len(list(zip(*count))[0]))))
    data = list()
    un_count = 0
 
    for word in words:
        if word in dictionary:
            index = dictionary[word]
        else:
            index = 0
            un_count += 1
        data.append(index)
    count[0][1] = un_count
    reverse_dictionary = dict(zip(dictionary.values(),dictionary.keys()))
    return data,reverse_dictionary,dictionary,count
 
data_index = 0
def generate_batch(data,batch_size,num_skips,skip_window):
    filename = maybe_download('text8.zip', 31344016)
    words = read_data(filename)
    global data_index
    assert num_skips <= 2 * skip_window
    assert batch_size % num_skips == 0
    span = 2 * skip_window + 1
    batch = np.ndarray(shape=[batch_size],dtype=np.int32)
    labels = np.ndarray(shape=[batch_size,1],dtype=np.int32)
    buffer = collections.deque(maxlen=span)
    #初始化
    for i in range(span):
        buffer.append(data[data_index])
        data_index = (data_index + 1) % len(data)
    #移動窗口,獲取批量數據
    for i in range(batch_size // num_skips):
        target = skip_window
        avoid_target = [skip_window]
        for j in range(num_skips):
            while target in avoid_target:
                target = np.random.randint(0,span - 1)
            avoid_target.append(target)
            batch[i * num_skips + j] = buffer[skip_window]
            labels[i * num_skips + j,0] = buffer[target]
 
        buffer.append(data[data_index])
        data_index = (data_index + 1) % len(data)
    return batch,labels

 w2vModel.py
	
import tensorflow as tf
import w2v.data_helper as da
import numpy as np
import math
#filename = da.maybe_download('text8.zip', 31344016)
words = da.read_data("text8.zip")
assert  words is not None
data,reverse_dictionary,dictionary,count = da.build_dataset(words)
 
class config(object):
    batch_size = 128
    embedding_size = 128
    skip_window = 1
    num_skips = 2
 
    valid_size = 16
    valid_window = 100
    valid_examples = np.random.choice(valid_window, valid_size, replace=False)
    num_sampled = 64
    vocabulary_size = 50000
    num_steps = 10001
 
class w2vModel(object):
    def __init__(self,config):
        self.train_inputs = train_inputs = tf.placeholder(tf.int32, shape=[config.batch_size])
        self.train_labels = train_labels = tf.placeholder(tf.int32, shape=[config.batch_size, 1])
        self.valid_dataset = valid_dataset = tf.constant(config.valid_examples, dtype=tf.int32)
 
        with tf.device('/cpu:0'):
            embeddings = tf.Variable(
                tf.random_uniform(shape=[config.vocabulary_size, config.embedding_size], minval=-1.0, maxval=1.0))
            embed = tf.nn.embedding_lookup(embeddings, train_inputs)
            nce_weights = tf.Variable(
                tf.truncated_normal([config.vocabulary_size, config.embedding_size], stddev=1.0 / math.sqrt(config.embedding_size)))
            nce_bias = tf.Variable(tf.zeros([config.vocabulary_size]))
 
            loss = tf.reduce_mean(
                tf.nn.nce_loss(weights=nce_weights, biases=nce_bias, labels=train_labels, inputs=embed,
                               num_sampled=config.num_sampled, num_classes=config.vocabulary_size))
            optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)
            norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))
            normalized_embeddings = embeddings / norm
            valid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, valid_dataset)
            similarity = tf.matmul(valid_embeddings, normalized_embeddings, transpose_b=True)
            tf.add_to_collection("embedding",embeddings)
            self.saver = saver = tf.train.Saver(tf.global_variables())

 train.py:
	
import tensorflow as tf
import w2v.w2vmodel as model
import w2v.data_helper as da
 
config = model.config()
 
with tf.Graph().as_default() as g:
    Model = model.w2vModel(config)
    with tf.Session(graph=g) as session:
        tf.global_variables_initializer().run()
        print("initialized")
 
        average_loss = 0.0
        for step in range(config.num_steps):
            batch_inputs,batch_labels = da.generate_batch(model.data,config.batch_size,config.num_skips,config.skip_window)
            feed_dict = {Model.train_inputs:batch_inputs,Model.train_labels:batch_labels}
 
            _,loss_val = session.run([Model.optimizer,Model.loss],feed_dict=feed_dict)
            average_loss += loss_val
            if step % 2000 == 0:
                if step > 0:
                    average_loss /= 2000
                print("Average loss at step",step,":",average_loss)
                average_loss = 0
            if step % 10000 == 0:
                sim = Model.similarity.eval()
                for i in range(config.valid_size):
                    valid_word = model.reverse_dictionary[config.valid_examples[i]]
                    top_k = 8
                    nearest = (-sim[i,:]).argsort()[1:top_k+1]
                    log_str = "Nearest to %s:" % valid_word
                    for k in range(top_k):
                        close_word = model.reverse_dictionary[nearest[k]]
                        log_str = "%s %s," % (log_str,close_word)
                    print(log_str)
        Model.saver.save(session, "E:/word2vector/models/model.ckpt")
        #final_embeddings = model.normalized_embeddings.eval()



期待nlp語義理解出現變革……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章