秒懂神經網絡---震驚!!!神經網絡原來可以這么簡單!


秒懂神經網絡---震驚!!!神經網絡原來可以這么簡單!

一、總結

一句話總結:

神經網絡代碼編寫很容易:class+方法
神經網絡的思路也很容易:由輸入到輸出,只不過這個過程經過了一些優化

 

1、神經網絡解決實際問題步驟?

1、【搭建】神經網絡模型:比如搭建神經網絡基礎模塊 神經元
2、【訓練(優化)】神經網絡模型:用大量數據訓練,減少神經網絡損失,提高精確度

 

2、神經網絡中的 基本模塊 神經元是什么?

類似生物神經元:接受外來刺激(信號),再由細胞體傳出刺激(信號)
權重輸入+激活函數=輸出:1、輸入乘以權重; 2、加偏置; 3、經過激活函數處理;

 

3、神經網絡中神經元中的 激活函數 的作用是什么?

格式化輸出:輸出介於0和1:將無限制的輸入轉換為可預測形式的輸出
例如sigmoid:f(x)=e^x/(1+e^x):把 (−∞,+∞) 范圍內的數壓縮到 (0, 1)以內

 

4、神經網絡最簡單的神經元中,總共經過了哪三步計算?

1、輸入乘以權重
2、加偏置
3、經過激活函數處理
先將兩個輸入乘以權重(weight):

x1→x1 × w1
x2→x2 × w2

把兩個結果想加,再加上一個偏置(bias):

(x1 × w1)+(x2 × w2)+ b

最后將它們經過激活函數(activation function)處理得到輸出:

y = f(x1 × w1 + x2 × w2 + b)

 

 

5、神經網絡最簡單的神經元中,對於每個輸入信號,它的格式是怎樣的?

由輸入屬性構成:每個輸入信號由多個輸入的屬性構成,比如輸入為圖片時:圖片像素集,圖片大小信息,圖片時間信息 等
屬性有自己的權重和偏移:信號輸入中的每個屬性,有自己的權重和偏移
實例:比如辨別圖片中動物名字:圖片像素集,圖片大小信息,圖片時間信息 等圖片屬性可以構成一個圖片輸入

 

6、Python數學函數庫NumPy構建簡單神經網絡代碼注意?

引入Numpy庫:import numpy as np
構建神經元類:class Neuron:,里面有__init__()方法和正反饋feedforward()方法
輸入數據:weights = np.array([0, 1]) # w1 = 0, w2 = 1 ; x = np.array([2, 3]) # x1 = 2, x2 = 3
feedforward
英 ['fiːdfɔːwəd]  美 
n. 前饋(控制);正反饋

import numpy as np

def sigmoid(x):
  # Our activation function: f(x) = 1 / (1 + e^(-x))
  return 1 / (1 + np.exp(-x))

class Neuron:
  def __init__(self, weights, bias):
    self.weights = weights
    self.bias = bias

  def feedforward(self, inputs):
    # Weight inputs, add bias, then use the activation function
    total = np.dot(self.weights, inputs) + self.bias
    return sigmoid(total)

weights = np.array([0, 1]) # w1 = 0, w2 = 1
bias = 4                   # b = 4
n = Neuron(weights, bias)

x = np.array([2, 3])       # x1 = 2, x2 = 3
print(n.feedforward(x))    # 0.9990889488055994

 

 

7、一個神經網絡由哪大的三層構成?

輸入層:Input Layer:
隱藏層:Hidden Layer:
輸出層:Output Layer:

 

8、神經網絡中的前饋(正反饋)是什么?

向前傳遞的過程:把神經元的輸入向前傳遞獲得輸出的過程

 

9、神經網絡的隱藏層可能有多層,那么 神經元的正反饋函數應該怎么寫?

遞歸:其實神經網絡的代碼相對還是比較簡單的
class OurNeuralNetwork:
  def feedforward(self, x):
    out_h1 = self.h1.feedforward(x)
    out_h2 = self.h2.feedforward(x)

    # The inputs for o1 are the outputs from h1 and h2
    out_o1 = self.o1.feedforward(np.array([out_h1, out_h2]))

    return out_o1

 

 

10、我們怎么才算把我們的神經網絡模型設計好了?

測試結果小於 設定的誤差值:我們設定了一個設定的誤差值,如果測試結果的數據小於設定的誤差值,我們可以看做神經網絡模型搭建好了

 

11、訓練神經網絡的過程的 實質 是什么?

優化模型的過程:其實也就是讓損失函數的結果最小

 

 

12、如果我們用神經網絡根據某人的身高和體重來推測其性別,那么輸入是什么?

一個人的信息即為一條輸入信號
每個輸入信號分為多個屬性:比如a的身高,a的體重就是a這個人對應的輸入信號的兩個屬性(或者叫分支)

 

13、我們如何衡量一個神經網絡模型的好壞?

用Loss Function(損失函數):最簡單的損失函數比如 均方誤差(MSE)
import numpy as np

def mse_loss(y_true, y_pred):
  # y_true and y_pred are numpy arrays of the same length.
  return ((y_true - y_pred) ** 2).mean()

y_true = np.array([1, 0, 0, 1])
y_pred = np.array([0, 0, 0, 0])

print(mse_loss(y_true, y_pred)) # 0.5

 

 

14、我們比如用 均方誤差 來衡量一個神經網絡模型的好壞,那么 均方誤差 是什么?

所有數據方差的平均值:我們不妨就把它定義為損失函數。預測結果越好,損失就越低,訓練神經網絡就是將損失最小化。

 

15、神經網絡中那種錯綜復雜的上傳到下層的線如何實現?

屬性的權重和:因為每一個下層節點得到的是一整套的輸入,而不是某個輸入的屬性

 

16、如果調整一下w1,損失函數是會變大還是變小?

偏導數∂L/∂w1:偏導數∂L/∂w1是正是負能回答這個問題:當∂L/∂w1是正數時,w1會變小;當∂L/∂w1是負數 時,w1會變大。

 

17、如何求一個函數的導數,比如 偏導數∂L/∂w1?

自變量降次:在函數中,把∂w1看成自變量,然后對∂w1進行降次處理,相當於一次函數求斜率

 

18、神經網絡中,如何求 輸出結果對某一個權重的偏倒數,比如Ypred(最終結果)對w1(輸入信號的屬性第一個的權重)?

鏈式展開:Ypred對w1的偏導=Ypred對h1的偏導 * h1對w1的偏導

 

 

19、神經網絡中的優化神經網絡中的 隨機梯度下降 是干嘛的?

優化神經網絡:無非就是優化【權重 和 偏移】
優化權重:隨機梯度下降是用來優化權重的
w1=w1-η·∂L/∂w1:看這個函數就特別清晰隨機梯度下降是干嘛的以及它的特性有哪些

 

20、隨機梯度下降(w1=w1-η·∂L/∂w1)中的η是干嘛的?

學習率:訓練網絡快慢:η是一個常數,稱為學習率(learning rate),它決定了我們訓練網絡速率的快慢。

 

21、隨機梯度下降(w1=w1-η·∂L/∂w1)的特性是什么?

將w1減去η·∂L/∂w1,就等到了新的權重w1。
當∂L/∂w1是正數時,w1會變小;當∂L/∂w1是負數 時,w1會變大。

 

 

22、神經網絡的 偽代碼 如何書寫?

類+方法:就是一個神經網絡的類,里面有【初始化,正反饋,負反饋等】幾個方法

 

23、神經網絡的學習進階?

1、強大的庫:用更大更好的機器學習庫搭建神經網絡,如Tensorflow、Keras、PyTorch
2、可視化:在瀏覽器中的直觀理解神經網絡:https://playground.tensorflow.org/
3、激活函數:學習sigmoid以外的其他激活函數:https://keras.io/activations/
4、優化器:學習SGD以外的其他優化器:https://keras.io/optimizers/
1、用更大更好的機器學習庫搭建神經網絡,如Tensorflow、Keras、PyTorch
2、在瀏覽器中的直觀理解神經網絡:https://playground.tensorflow.org/
3、學習sigmoid以外的其他激活函數:https://keras.io/activations/
4、學習SGD以外的其他優化器:https://keras.io/optimizers/
5、學習卷積神經網絡(CNN)
6、學習遞歸神經網絡(RNN)

 

 

二、非常簡單清晰的神經網絡教程(轉)

轉自:AI之城
https://mp.weixin.qq.com/s/GQyXEdURHixd8jrf9A197A

 

“我在網上看到過很多神經網絡的實現方法,但這一篇是最簡單、最清晰的。”

一位來自普林斯頓的華人小哥Victor Zhou,寫了篇神經網絡入門教程,在線代碼網站Repl.it聯合創始人Amjad Masad看完以后,給予如是評價。

 

這篇教程發布僅天時間,就在Hacker News論壇上收獲了574贊。程序員們紛紛誇贊這篇文章的代碼寫得很好,變量名很規范,讓人一目了然。

下面就讓我們一起從零開始學習神經網絡吧。

實現方法

搭建基本模塊——神經元

在說神經網絡之前,我們討論一下神經元(Neurons),它是神經網絡的基本單元。神經元先獲得輸入,然后執行某些數學運算后,再產生一個輸出。比如一個2輸入神經元的例子:

 

 

在這個神經元中,輸入總共經歷了3步數學運算,

先將兩個輸入乘以權重(weight):

x1→x1 × w1
x2→x2 × w2

把兩個結果想加,再加上一個偏置(bias):

(x1 × w1)+(x2 × w2)+ b

最后將它們經過激活函數(activation function)處理得到輸出:

y = f(x1 × w+ x2 × w+ b)

激活函數的作用是將無限制的輸入轉換為可預測形式的輸出。一種常用的激活函數是sigmoid函數:

 

sigmoid函數的輸出介於0和1,我們可以理解為它把 (−∞,+∞) 范圍內的數壓縮到 (0, 1)以內。正值越大輸出越接近1,負向數值越大輸出越接近0。

舉個例子,上面神經元里的權重和偏置取如下數值:

w=[0,1]
b = 4

w=[0,1]是w1=0、w2=1的向量形式寫法。給神經元一個輸入x=[2,3],可以用向量點積的形式把神經元的輸出計算出來:

w·x+b =(x1 × w1)+(x2 × w2)+ b = 0×2+1×3+4=7
y=f(w⋅X+b)=f(7)=0.999

以上步驟的Python代碼是:

import numpy as np

def sigmoid(x):
  # Our activation function: f(x) = 1 / (1 + e^(-x))
  return 1 / (1 + np.exp(-x))

class Neuron:
  def __init__(self, weights, bias):
    self.weights = weights
    self.bias = bias

  def feedforward(self, inputs):
    # Weight inputs, add bias, then use the activation function
    total = np.dot(self.weights, inputs) + self.bias
    return sigmoid(total)

weights = np.array([0, 1]) # w1 = 0, w2 = 1
bias = 4                   # b = 4
n = Neuron(weights, bias)

x = np.array([2, 3])       # x1 = 2, x2 = 3
print(n.feedforward(x))    # 0.9990889488055994

我們在代碼中調用了一個強大的Python數學函數庫NumPy

搭建神經網絡

神經網絡就是把一堆神經元連接在一起,下面是一個神經網絡的簡單舉例:

 

 

這個網絡有2個輸入、一個包含2個神經元的隱藏層(h1和h2)、包含1個神經元的輸出層o1

隱藏層是夾在輸入輸入層和輸出層之間的部分,一個神經網絡可以有多個隱藏層。

把神經元的輸入向前傳遞獲得輸出的過程稱為前饋(feedforward)。

我們假設上面的網絡里所有神經元都具有相同的權重w=[0,1]和偏置b=0,激活函數都是sigmoid,那么我們會得到什么輸出呢?

h1=h2=f(w⋅x+b)=f((0×2)+(1×3)+0)
=f(3)
=0.9526

o1=f(w⋅[h1,h2]+b)=f((0∗h1)+(1∗h2)+0)
=f(0.9526)
=0.7216

以下是實現代碼:

import numpy as np

# ... code from previous section here

class OurNeuralNetwork:
  '''
  A neural network with:
    - 2 inputs
    - a hidden layer with 2 neurons (h1, h2)
    - an output layer with 1 neuron (o1)
  Each neuron has the same weights and bias:
    - w = [0, 1]
    - b = 0
  '''
  def __init__(self):
    weights = np.array([0, 1])
    bias = 0

    # The Neuron class here is from the previous section
    self.h1 = Neuron(weights, bias)
    self.h2 = Neuron(weights, bias)
    self.o1 = Neuron(weights, bias)

  def feedforward(self, x):
    out_h1 = self.h1.feedforward(x)
    out_h2 = self.h2.feedforward(x)

    # The inputs for o1 are the outputs from h1 and h2
    out_o1 = self.o1.feedforward(np.array([out_h1, out_h2]))

    return out_o1

network = OurNeuralNetwork()
x = np.array([2, 3])
print(network.feedforward(x)) # 0.7216325609518421

訓練神經網絡

現在我們已經學會了如何搭建神經網絡,現在我們來學習如何訓練它,其實這就是一個優化的過程。

假設有一個數據集,包含4個人的身高、體重和性別:

 

現在我們的目標是訓練一個網絡,根據體重和身高來推測某人的性別。

 

 

為了簡便起見,我們將每個人的身高、體重減去一個固定數值,把性別男定義為1、性別女定義為0。

 

在訓練神經網絡之前,我們需要有一個標准定義它到底好不好,以便我們進行改進,這就是損失(loss)。

比如用均方誤差(MSE)來定義損失:

 

n是樣本的數量,在上面的數據集中是4;
y代表人的性別,男性是1,女性是0;
ytrue是變量的真實值,ypred是變量的預測值。

顧名思義,均方誤差就是所有數據方差的平均值,我們不妨就把它定義為損失函數。預測結果越好,損失就越低,訓練神經網絡就是將損失最小化。

如果上面網絡的輸出一直是0,也就是預測所有人都是男性,那么損失是:

 

MSE= 1/4 (1+0+0+1)= 0.5

計算損失函數的代碼如下:

import numpy as np

def mse_loss(y_true, y_pred):
  # y_true and y_pred are numpy arrays of the same length.
  return ((y_true - y_pred) ** 2).mean()

y_true = np.array([1, 0, 0, 1])
y_pred = np.array([0, 0, 0, 0])

print(mse_loss(y_true, y_pred)) # 0.5

減少神經網絡損失

這個神經網絡不夠好,還要不斷優化,盡量減少損失。我們知道,改變網絡的權重和偏置可以影響預測值,但我們應該怎么做呢?

為了簡單起見,我們把數據集縮減到只包含Alice一個人的數據。於是損失函數就剩下Alice一個人的方差:

 

預測值是由一系列網絡權重和偏置計算出來的:

 

 

所以損失函數實際上是包含多個權重、偏置的多元函數:

 

(注意!前方高能!需要你有一些基本的多元函數微分知識,比如偏導數、鏈式求導法則。)

如果調整一下w1,損失函數是會變大還是變小?我們需要知道偏導數∂L/∂w1是正是負才能回答這個問題。

根據鏈式求導法則:

 

而L=(1-ypred)2,可以求得第一項偏導數:

 

接下來我們要想辦法獲得ypred和w1的關系,我們已經知道神經元h1、h2和o1的數學運算規則:

 

實際上只有神經元h1中包含權重w1,所以我們再次運用鏈式求導法則:

 

然后求∂h1/∂w1

 

我們在上面的計算中遇到了2次激活函數sigmoid的導數f′(x),sigmoid函數的導數很容易求得:

 

總的鏈式求導公式:

 

這種向后計算偏導數的系統稱為反向傳播(backpropagation)。

上面的數學符號太多,下面我們帶入實際數值來計算一下。h1、h2和o1

h1=f(x1⋅w1+x2⋅w2+b1)=0.0474

h2=f(w3⋅x3+w4⋅x4+b2)=0.0474

o1=f(w5⋅h1+w6⋅h2+b3)=f(0.0474+0.0474+0)=f(0.0948)=0.524

神經網絡的輸出y=0.524,沒有顯示出強烈的是男(1)是女(0)的證據。現在的預測效果還很不好。

我們再計算一下當前網絡的偏導數∂L/∂w1

 

這個結果告訴我們:如果增大w1,損失函數L會有一個非常小的增長。

隨機梯度下降

下面將使用一種稱為隨機梯度下降(SGD)的優化算法,來訓練網絡。

經過前面的運算,我們已經有了訓練神經網絡所有數據。但是該如何操作?SGD定義了改變權重和偏置的方法:

 

η是一個常數,稱為學習率(learning rate),它決定了我們訓練網絡速率的快慢。將w1減去η·∂L/∂w1,就等到了新的權重w1

當∂L/∂w1是正數時,w1會變小;當∂L/∂w1是負數 時,w1會變大。

如果我們用這種方法去逐步改變網絡的權重w和偏置b,損失函數會緩慢地降低,從而改進我們的神經網絡。

訓練流程如下:

1、從數據集中選擇一個樣本;
2、計算損失函數對所有權重和偏置的偏導數;
3、使用更新公式更新每個權重和偏置;
4、回到第1步。

我們用Python代碼實現這個過程:

import numpy as np

def sigmoid(x):
  # Sigmoid activation function: f(x) = 1 / (1 + e^(-x))
  return 1 / (1 + np.exp(-x))

def deriv_sigmoid(x):
  # Derivative of sigmoid: f'(x) = f(x) * (1 - f(x))
  fx = sigmoid(x)
  return fx * (1 - fx)

def mse_loss(y_true, y_pred):
  # y_true and y_pred are numpy arrays of the same length.
  return ((y_true - y_pred) ** 2).mean()

class OurNeuralNetwork:
  '''
  A neural network with:
    - 2 inputs
    - a hidden layer with 2 neurons (h1, h2)
    - an output layer with 1 neuron (o1)

  *** DISCLAIMER ***:
  The code below is intended to be simple and educational, NOT optimal.
  Real neural net code looks nothing like this. DO NOT use this code.
  Instead, read/run it to understand how this specific network works.
  '''
  def __init__(self):
    # Weights
    self.w1 = np.random.normal()
    self.w2 = np.random.normal()
    self.w3 = np.random.normal()
    self.w4 = np.random.normal()
    self.w5 = np.random.normal()
    self.w6 = np.random.normal()

    # Biases
    self.b1 = np.random.normal()
    self.b2 = np.random.normal()
    self.b3 = np.random.normal()

  def feedforward(self, x):
    # x is a numpy array with 2 elements.
    h1 = sigmoid(self.w1 * x[0] + self.w2 * x[1] + self.b1)
    h2 = sigmoid(self.w3 * x[0] + self.w4 * x[1] + self.b2)
    o1 = sigmoid(self.w5 * h1 + self.w6 * h2 + self.b3)
    return o1

  def train(self, data, all_y_trues):
    '''
    - data is a (n x 2) numpy array, n = # of samples in the dataset.
    - all_y_trues is a numpy array with n elements.
      Elements in all_y_trues correspond to those in data.
    '''
    learn_rate = 0.1
    epochs = 1000 # number of times to loop through the entire dataset

    for epoch in range(epochs):
      for x, y_true in zip(data, all_y_trues):
        # --- Do a feedforward (we'll need these values later)
        sum_h1 = self.w1 * x[0] + self.w2 * x[1] + self.b1
        h1 = sigmoid(sum_h1)

        sum_h2 = self.w3 * x[0] + self.w4 * x[1] + self.b2
        h2 = sigmoid(sum_h2)

        sum_o1 = self.w5 * h1 + self.w6 * h2 + self.b3
        o1 = sigmoid(sum_o1)
        y_pred = o1

        # --- Calculate partial derivatives.
        # --- Naming: d_L_d_w1 represents "partial L / partial w1"
        d_L_d_ypred = -2 * (y_true - y_pred)

        # Neuron o1
        d_ypred_d_w5 = h1 * deriv_sigmoid(sum_o1)
        d_ypred_d_w6 = h2 * deriv_sigmoid(sum_o1)
        d_ypred_d_b3 = deriv_sigmoid(sum_o1)

        d_ypred_d_h1 = self.w5 * deriv_sigmoid(sum_o1)
        d_ypred_d_h2 = self.w6 * deriv_sigmoid(sum_o1)

        # Neuron h1
        d_h1_d_w1 = x[0] * deriv_sigmoid(sum_h1)
        d_h1_d_w2 = x[1] * deriv_sigmoid(sum_h1)
        d_h1_d_b1 = deriv_sigmoid(sum_h1)

        # Neuron h2
        d_h2_d_w3 = x[0] * deriv_sigmoid(sum_h2)
        d_h2_d_w4 = x[1] * deriv_sigmoid(sum_h2)
        d_h2_d_b2 = deriv_sigmoid(sum_h2)

        # --- Update weights and biases
        # Neuron h1
        self.w1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w1
        self.w2 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w2
        self.b1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_b1

        # Neuron h2
        self.w3 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w3
        self.w4 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_w4
        self.b2 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h2_d_b2

        # Neuron o1
        self.w5 -= learn_rate * d_L_d_ypred * d_ypred_d_w5
        self.w6 -= learn_rate * d_L_d_ypred * d_ypred_d_w6
        self.b3 -= learn_rate * d_L_d_ypred * d_ypred_d_b3

      # --- Calculate total loss at the end of each epoch
      if epoch % 10 == 0:
        y_preds = np.apply_along_axis(self.feedforward, 1, data)
        loss = mse_loss(all_y_trues, y_preds)
        print("Epoch %d loss: %.3f" % (epoch, loss))

# Define dataset
data = np.array([
  [-2, -1],  # Alice
  [25, 6],   # Bob
  [17, 4],   # Charlie
  [-15, -6], # Diana
])
all_y_trues = np.array([
  1, # Alice
  0, # Bob
  0, # Charlie
  1, # Diana
])

# Train our neural network!
network = OurNeuralNetwork()
network.train(data, all_y_trues)

隨着學習過程的進行,損失函數逐漸減小。

 

 

現在我們可以用它來推測出每個人的性別了:

# Make some predictions
emily = np.array([-7, -3]) # 128 pounds, 63 inches
frank = np.array([20, 2])  # 155 pounds, 68 inches
print("Emily: %.3f" % network.feedforward(emily)) # 0.951 - F
print("Frank: %.3f" % network.feedforward(frank)) # 0.039 - M

更多

這篇教程只是萬里長征第一步,后面還有很多知識需要學習:

1、用更大更好的機器學習庫搭建神經網絡,如Tensorflow、Keras、PyTorch
2、在瀏覽器中的直觀理解神經網絡:https://playground.tensorflow.org/
3、學習sigmoid以外的其他激活函數:https://keras.io/activations/
4、學習SGD以外的其他優化器:https://keras.io/optimizers/
5、學習卷積神經網絡(CNN)
6、學習遞歸神經網絡(RNN)

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM