手把手教你自制編程AI:訓練2小時,RNN就能寫本身的代碼

咱們都知道,神經網絡下圍棋能贏柯潔、讀X光照片好過醫生、就連文本翻譯上也快超過人類了……其實在寫代碼方面,神經網絡也絲絕不落下風……用Linux源代碼訓練2小時,一個遞歸神經網絡就能重寫好它本身的代碼,這是否是比程序員學得還快?
git

爲了幫你們一窺究竟,AI100(rgznai100)編譯了開發者Thibault Neveu的這篇文章,手把手教你作一個這樣的神經網絡。程序員

做者 | Thibault Neveugithub

我認這很瘋狂。開發者讓神經網絡學會了本身編程來重寫它本身代碼!好吧,我們也試。數據庫

預備條件編程

  1. Tensorflow + 基本的深度學習技能數組

  2. 該項目的github代碼庫 - https://github.com/thibo73800/deep_generation/tree/master/c_code網絡

  3. 我會在本文中快速回顧一下遞歸神經網絡。可是,若是你對這個課題不甚瞭解,我相信如下兩個資源能讓你弄懂遞歸神經網絡:app

視頻 - https://www.youtube.com/watch?v=iX5V1WpxxkY&t=2652s

文章 - http://colah.github.io/posts/2015-08-Understanding-LSTMs/函數

我不會在本文中詳解本項目的全部環節。但我會仔細闡述其中的基本要點來讓你理解整個項目。花點時間,親手運行下文中給出的每一段代碼,理解其中的邏輯。這很重要,畢竟,實踐出真知。post

接下來是正題,讓咱們開始吧!

數據庫

跟其餘監督訓練同樣,咱們須要爲神經網絡提供一個數據集。這裏咱們使用C語言(若是用太簡單的語言,就很差玩了)。咱們直接用Linux github代碼庫中的c語言腳本做爲訓練數據。我已經把咱們會用到的.c代碼提取到本項目中。

代碼地址-https://github.com/thibo73800/deep_generation/tree/master/c_code/dataset

首要問題:如何表示數據?

神經網絡只能用於處理數字。對於其餘形式的數據,它就無能爲力了。所以,數據集中的每一個字符都須要被翻譯成這種形式(每一個數字對應一個字符)。

示例:把字符轉換爲整數(int)

舉例來講,這裏用數字7表示字符「=」。爲了在反向傳播期間得到更好的收斂性,咱們稍後會在獨熱編碼(One-Hot Encoding)編碼中表示每一個數字。

# List all file in the dataset directory

all_file = os.listdir("dataset")

# Filter : Select only c file

all_file_name = np.array([f for f in all_file if f.find(".c") != -1])


content = ""

for name in all_file_name:

      with open(os.path.join("dataset", name), "r") as f:

            content += f.read() + "\n"


# Convert the string into a list of interger

vocab = set(content)

vocab_to_int = {c: i for i, c in enumerate(vocab)}

int_to_vocab = dict(enumerate(vocab))

encoded = np.array([vocab_to_int[c] for c in content], dtype=np.int32)

這裏,須要記住的三個重要變量是:vocab_to_int、int_to_vocab和encoded。前兩個變量是讓咱們可以字符和整數間隨意轉換。最後的變量是用編碼器的形式來表示全部數據。(均已轉換爲數字)

第一個批函數

首先建立一個簡單的批處理:由兩個輸入序列構成,每一個序列10個數字。這一批處理將做爲下文字符處理的一個示例。

batch = {

    "x" : [

        encoded[:10],

         encoded[20:30]

],

"y" : [

      encoded[1:11],

      encoded[21:31]

   ]

      }

Batch Inputs :

[20 6 58 27 6 27 97 86 56 49]

[ 36 32 32 37 27 12 94 60 89 101]

Batch Targets :

[ 6 58 27 6 27 97 86 56 49 57]

[ 32 32 37 27 12 94 60 89 101 77]

這就是批函數所處理的內容,翻譯成字符以下:

['/', '*', '\n', ' ', '*', ' ', 'C', 'o', 'p', 'y']

['2', '0', '0', '4', ' ', 'E', 'v', 'g', 'e', 'n']

如今,咱們須要來處理一些數值。咱們但願神經網絡可以在上一個字符"n"已知的條件下預測出下一個字符。並且,不僅是上一個字符。若是我告訴神經網絡上一個字符是「e」 ,下一個字符的可能性空間會很是大。但若是我能告訴神經網絡前幾個字符分別是 「w」 、「h」、 「i」 、「l」 和 「e」 ,下一個要輸入的字符很顯然就是「(「。

所以,咱們必須構建一個可以考慮字符時間間隔的神經網絡。這就是遞歸神經網絡。

遞歸神經網絡?

爲說明上述實例,咱們用一個典型的分類器(上圖左側)來處理上一個字符;它被傳遞出藍色的隱含層後,分類器就能推斷出結果。遞歸神經網絡在結構上則不一樣。每一個紅色的隱含層「細胞」不只與輸入相連,還與前一個「細胞」(instant t-1)相連。爲了解決這裏的問題,咱們的「細胞」內部使用長短時間記憶(LSTM)網絡。

請花點時間來理解遞歸神經網絡的原理,這樣才能充分理解接下來的代碼。

構建模型!

Tensorboard圖

接下來的內容,咱們將詳述這一神經網絡的5大部分。佔位符在這裏用做模型的一個入口。LSTM神經元初始化後用於生成遞歸神經網絡。

輸出層各自相連,用於估量模型的偏差。最後,咱們會定義訓練內容。

1)圖形輸入

with tf.name_scope("graph_inputs"):

     inputs = tf.placeholder(tf.int32, [2, 10], name='placeholder_inputs')

     targets = tf.placeholder(tf.int32, [2, 10], name='placeholder_targets')

     keep_prob = tf.placeholder(tf.float32, name='placeholder_keep_prob')

這個批處理由兩個大小爲10的輸入序列構成,所以輸入的預期特徵是[2, 10],批處理的每一個入口都與單一輸出相關聯,目標的特徵定義與此相同。最後,咱們定義了一個用做機率值的佔位符,用以表示後面的退出率(dropout)。

2)LSTM

with tf.name_scope("LSTM"):


     def create_cell():

         lstm = tf.contrib.rnn.BasicLSTMCell(4)

         drop = tf.contrib.rnn.DropoutWrapper(lstm, output_keep_prob=keep_prob)

         return drop


cell = tf.contrib.rnn.MultiRNNCell([create_cell() for _ in range(3)])

initial_state = cell.zero_state(2, tf.float32)


io_size = len(vocab)

x_one_hot = tf.one_hot(inputs, io_size)

cell_outputs, final_state = tf.nn.dynamic_rnn(cell, x_one_hot, initial_state=initial_state)

讓咱們來學習這份代碼的每一部分:

  • create_cell() 用於生成由4個隱神經元所構成的LSTM神經元。在返回結果前,該函數還在cell輸出中添加了一個退出項(dropout)。

  • tf.contrib.rnn.MultiRNNCell用於實例化遞歸神經網絡。咱們把給出的create_cell()數組做爲參數,是由於咱們但願獲得由多層網絡構成的遞歸神經網絡。本例爲三層。

  • initial_state:已知遞歸神經網絡的每一個神經元都依賴於先前的狀態,所以咱們必須實例化一個全是零的初始狀態,它將做爲批處理首批入口的輸入。

  • x_one_hot將batch轉化爲獨熱編碼。

  • cell_outputs給出遞歸神經網絡每一個細胞的輸出。在本例中,每一個輸出由4個數值(隱神經元個數)構成。

  • final_state返回最後一個細胞的狀態,在訓練期間可用做下一批處理的最新初始狀態(假設下一個批處理是上一個批處理的邏輯延續)。

3)圖形輸出

with tf.name_scope("graph_outputs"):

     seq_output_reshape = tf.reshape(cell_outputs, [-1, 4], name="reshape_x") 


     with tf.name_scope('output_layer'):

           w = tf.Variable(tf.truncated_normal((4, io_size), stddev=0.1), name="weights")

           b = tf.Variable(tf.zeros(io_size), name="bias")


logits = tf.add(tf.matmul(seq_output_reshape , w), b, name= "logits")

softmax = tf.nn.softmax(logits, name='predictions')

細胞的輸出值被儲存在一個三維特徵表內[序列數,序列大小,神經元數],或爲 [2, 10, 4]。咱們無需按序列來分離輸出。而後,改變輸出值的維度以儲存在seq_out_reshape的數組[20, 4]內。

最後,使用一個簡單的線性運算:tf.matmul (..) + b。最後以softmax結尾,爲的是用機率形式來表示輸出。

4)損失

with tf.name_scope("Loss"):

        y_one_hot = tf.one_hot(targets, io_size, name="y_to_one_hot")

        y_reshaped = tf.reshape(y_one_hot, logits.get_shape(), name="reshape_one_hot")


loss = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y_reshaped)

loss = tf.reduce_mean(loss)

爲進行偏差運算,咱們的批處理目標必需要表示成跟模型輸出值相同的方法和維度。使用與輸入相同的編碼方式,咱們用tf.one_hot來表示輸出值。而後將數組tf.reshape ()的維度重寫爲與tf.matmul (..) + b的線性輸出同樣。然後,咱們就能夠用該函數來計算模型的偏差。

5)訓練

with tf.name_scope("train"):

    adam = tf.train.AdamOptimizer(0.0001)

    optimizer = adam.minimize(loss)

咱們簡單用AdamOptimize來最小化偏差。

結果!

這是最值得慶祝的環節:訓練結果。我所用到的參數以下:

  • 序列大小:100

  • 批處理大小:200

  • 每一個細胞的神經元數: 512

  • 遞歸神經網絡深度:2

  • 學習速度:0.0005

  • Dropout:0.5

在個人GPU(GeForce GTX 1060)上訓練大約兩小時後,所得結果以下圖所示:

咱們先來觀察偏差的變化:

最後,咱們來閱讀模型所生成的代碼:

static int super_fold(struct mddev *mddev, void __user * *rd)

{

     struct md_rdev *rdev;


     if (!tryet & gcov_ntreef(*stint)) {

          if (gc_th->max_sectors)

          if (task)

         goto next_start;

    if (!list_empty(&mddev->disks) {

        if (mddev->dev_sectors == 0 ||

          mddev->chunk_sectors == 0 && mddev->minor_version !=

           mddev->max_disks && mddev->dev_sectors

         rdev2->rescan_recovnr != 0)

rdev->recovery_offset = mddev->curr_resync_completed;

           }

     }

}

從結果上看,模型清楚地理解了該程序的通常結構,很是酷:一個函數、參數、變量初始化……條件,等等。

咱們注意到,所用數據集中絕對沒有那個名爲「super_fold」的函數。所以,我很難理解這個函數的具體做用,一個較爲合理的解釋,是該模型要比我聰明……天哪!!

原文地址:

https://becominghuman.ai/how-to-train-a-neural-network-to-code-by-itself-a432e8a120df

相關文章
相關標籤/搜索