2017-06-18 22 views
0

我週二向我的同學們的web開發人員簡單介紹了神經網絡。我希望將this code(根據第1部分,一個微小的玩具神經網絡:2層網絡)翻譯成JavaScript,以便讓我的觀衆更容易辨認。將11行玩具神經網絡代碼翻譯爲JavaScript時遇到麻煩

import numpy as np 

# sigmoid function 
def nonlin(x,deriv=False): 
    if(deriv==True): 
     return x*(1-x) 
    return 1/(1+np.exp(-x)) 

# input dataset 
X = np.array([ [0,0,1], 
       [0,1,1], 
       [1,0,1], 
       [1,1,1] ]) 

# output dataset    
y = np.array([[0,0,1,1]]).T 

# seed random numbers to make calculation 
# deterministic (just a good practice) 
np.random.seed(1) 

# initialize weights randomly with mean 0 
syn0 = 2*np.random.random((3,1)) - 1 

for iter in xrange(10000): 

    # forward propagation 
    l0 = X 
    l1 = nonlin(np.dot(l0,syn0)) 

    # how much did we miss? 
    l1_error = y - l1 

    # multiply how much we missed by the 
    # slope of the sigmoid at the values in l1 
    l1_delta = l1_error * nonlin(l1,True) 

    # update weights 
    syn0 += np.dot(l0.T,l1_delta) 

print "Output After Training:" 
print l1 

這是我的JavaScript代碼,因爲它現在。我只是去ES6ified它得到它在我的IDE中運行:

const _ = require('lodash') 
const m = require('mathjs') 

const sigmoid = function(z) { return 1.0/(1.0 + Math.exp(-z)) } 

const sigmoid_prime = function(z) { return sigmoid(z) * (1 - sigmoid(z)) } 

var X = m.matrix([ [0,0,1],[0,1,1],[1,0,1],[1,1,1] ]) 
var y = m.transpose(m.matrix(([[0,1,1,0]]))) 

var syn0 = m.random([3, 1], -1, 1) 

var l0, l1, l1_delta, l1_error 

_.range(10000).forEach(function() { 

    l0 = X; 
    l1 = m.map(m.multiply(l0, syn0), sigmoid) 
    l1_error = m.subtract(y, l1) 
    l1_delta = m.dotMultiply(l1_error, m.map(l1, sigmoid_prime)) 
    syn0 = m.multiply(m.transpose(l0),l1_delta) 
}) 

console.log("Output After Training:") 
console.log(l1) 

正如你可以看到我使用mathjs作爲numpy的替代品。我試圖仔細查看mathjs和numpy的文檔,而不是混淆我的矩陣乘法和我的元素乘法,但是有些東西非常壞,每個輸出都得到.5。我已經在調試器中逐步完成了我的程序,並在python臨時文件中並行比較了值,並將python與JavaScript程序生成的syn0的值一起啓動,看起來好像它在這裏,反向傳播行,它們略有分歧(並且可能會在迭代中分歧更大):l1_delta = m.dotMultiply(l1_error, m.map(l1, sigmoid_prime))。但我看不出爲什麼。

編輯:我應該更新我的代碼之前,我發佈反映,在上一個版本中,我改變了y定義var y = m.matrix([ [0], [0], [1], [1]]),它稍微修改了問題,因爲輸出切換從全部.5's稍微浮動.5。

第二次編輯:布倫特正確地指出,我有一個bug,因爲模仿我從我的sigmoid素函數移植的代碼只需要z *(1-z)。我錯過了那個皺紋。可悲的是,這並沒有什麼區別。控制檯登錄字符串化的功能和syn0在最後一次迭代的值:

sigmoid prime is function (z) {return sigmoid(z) * (1 - sigmoid(z))} 
syn0 is Matrix { 
    _data: 
    [ [ 0.21089543115482337 ], 
    [ -0.010100491415226356 ], 
    [ -0.021376195229226028 ] ], 
    _size: [ 3, 1 ], 
    _datatype: undefined } 

現在改變功能:

sigmoid prime is function (z) { return z * (1 - (z)) } 
syn0 is Matrix { 
    _data: 
    [ [ 0.2235282818415481 ], 
    [ -0.010714305064562765 ], 
    [ -0.022890185954402634 ] ], 
    _size: [ 3, 1 ], 
    _datatype: undefined } 
+0

我要在這裏猜測 - 你的權重是否正確地輸入到浮動/雙打而不是整數等? – Monza

+0

如果我在'syn0 = m.multiply(m.transpose(l0),l1_delta)之後加上'm.map(syn0,function(w){console.log(typeof w)})''it console log '數'。我不認爲他們可以是整數,他們有很多小數位(除非我不知不覺地說出一些關於數據類型的簡單描述,我不知道)。 – Katie

回答

0

看起來你很接近,這是一個很好的端口。

認爲這是您的翻譯nonlin函數的一個小錯誤。在deriv參數爲真的情況下,等式是x * (1 - x)。在你的版本中,你使用的是sigmoid(x) * (1 - sigmoid(x))。我不認爲你需要從sigmoid_prime內撥打sigmoid

我希望有幫助!

+0

你是對的,謝謝你指出,但它實際上似乎沒有什麼區別。我不知道爲什麼會有這樣的數學直覺,但似乎是這樣。我將把一些控制檯日誌顯示在對問題的編輯中;它有點過於參與評論。我還應該注意,原始問題中的「權重趨於零」是錯誤的,也許考慮到錯誤會幫助我弄清楚發生了什麼。最後兩個收斂到零,但第一個大於後兩個,因爲它應該是,但仍然太小。 – Katie

+0

(我編輯了「權重收斂到零」我決定最容易混淆的事情是在原始問題中完全擺脫它,但我很抱歉,如果它是誤導!) – Katie