关于人工智能:用Python从头开始构建神经网络

42次阅读

共计 5151 个字符,预计需要花费 13 分钟才能阅读完成。

作者 |Rashida Nasrin Sucky
编译 |VK
起源 |Medium

神经网络曾经被开发用来模仿人脑。尽管咱们还没有做到这一点,但神经网络在机器学习方面是十分无效的。它在上世纪 80 年代和 90 年代很风行,最近越来越风行。计算机的速度足以在正当的工夫内运行一个大型神经网络。在本文中,我将探讨如何实现一个神经网络。

我倡议你仔细阅读“神经网络的思维”局部。但如果你不太分明,不要放心。能够转到实现局部。我把它分解成更小的碎片帮忙了解。

神经网络的工作原理

在一个简略的神经网络中,神经元是根本的计算单元。它们获取输出特色并将其作为输入。以下是根本神经网络的外观:

这里,“layer1”是输出特色。“Layer1”进入另一个节点 layer2,最初输入预测的类或假如。layer2 是暗藏层。能够应用多个暗藏层。

你必须依据你的数据集和精度要求来设计你的神经网络。

前向流传

从第 1 层挪动到第 3 层的过程称为前向流传。前向流传的步骤:

  1. 为每个输出特色初始化系数 θ。比方说,咱们有 100 个训练例子。这意味着 100 行数据。在这种状况下,如果假如有 10 个输出特色,咱们的输出矩阵的大小是 100×10。当初确定 $θ_1$ 的大小。行数须要与输出特色的数量雷同。在这个例子中,是 10。列数应该是你抉择的暗藏层的大小。
  2. 将输出特色 X 乘以相应的 θ,而后增加一个偏置项。通过激活函数传递后果。

有几个激活函数可用,如 sigmoid,tanh,relu,softmax,swish

我将应用一个 sigmoid 激活函数来演示神经网络。

这里,“a”代表暗藏层或第 2 层,b 示意偏置。

g(z)是 sigmoid 激活函数:

  1. 为暗藏层初始化 $\theta_2$。大小将是暗藏层的长度乘以输入类的数量。在这个例子中,下一层是输入层,因为咱们没有更多的暗藏层。
  2. 而后咱们须要依照以前一样的流程。将 θ 和暗藏层相乘,通过 sigmoid 激活层失去预测输入。

反向流传

反向流传是从输入层挪动到第二层的过程。在这个过程中,咱们计算了误差。

  1. 首先,从原始输入 y 减去预测输入,这就是咱们的 $\delta_3$。

  1. 当初,计算 $\theta_2$ 的梯度。将 $\delta_3$ 乘以 $\theta_2$。乘以“$a^2$”乘以“$1-a^2$”。在上面的公式中,“a”上的上标 2 示意第 2 层。请不要把它误会为平方。

  1. 用训练样本数 m 计算没有正则化版本的梯度 $\delta$。

训练网络

修改 $\delta$。将输出特色乘以 $\delta_2$ 乘以学习速率失去 $\theta_1$。请留神 $\theta_1$ 的维度。

反复前向流传和反向流传的过程,并不断更新参数,直到达到最佳老本。这是老本函数的公式。只是揭示一下,老本函数表明,预测离原始输入变量有多远。

如果你留神到的话,这个老本函数公式简直和逻辑回归老本函数一样。

神经网络的实现

我将应用 Andrew Ng 在 Coursera 的机器学习课程的数据集。请从以下链接下载数据集:

https://github.com/rashida048…

上面是一个逐渐实现的神经网络。我激励你本人运行每一行代码并打印输出以更好地了解它。

  1. 首先导入必要的包和数据集。
import pandas as pd
import numpy as np
xls = pd.ExcelFile('ex3d1.xlsx')
df = pd.read_excel(xls, 'X', header = None)

这是数据集的前五行。这些是数字的像素值。

在这个数据集中,输出和输入变量被组织在独自的 excel 表格中。让咱们导入输入变量:

y = pd.read_excel(xls, 'y', header=None)

这也是数据集的前五行。输入变量是从 1 到 10 的数字。这个我的项目的指标是应用存储在 ’df’ 中的输出变量来预测数字。

  1. 求输入输出变量的维数
df.shape
y.shape

输出变量或 df 的形态为 5000 x 400,输入变量或 y 的形态为 5000 x 1。

  1. 定义神经网络

为了简略起见,咱们将只应用一个由 25 个神经元组成的暗藏层。

hidden_layer = 25

失去输入类。

y_arr = y[0].unique()# 输入:
array([10,  1,  2,  3,  4,  5,  6,  7,  8,  9], dtype=int64)

正如你在下面看到的,有 10 个输入类。

  1. 初始化 θ 和偏置

咱们将随机初始化层 1 和层 2 的 θ。因为咱们有三层,所以会有 $\theta_1$ 和 $\theta_2$。

$\theta_1$ 的维度:第 1 层的大小 x 第 2 层的大小

$\theta_2$ 的维度:第 2 层的大小 x 第 3 层的大小

从步骤 2 开始,“df”的形态为 5000 x 400。这意味着有 400 个输出特色。所以,第 1 层的大小是 400。当咱们指定暗藏层大小为 25 时,层 2 的大小为 25。咱们有 10 个输入类。所以,第 3 层的大小是 10。

$\theta_1$ 的维度:400 x 25

$\theta_2$ 的维度:25×10

同样,会有两个随机初始化的偏置 b1 和 b2。

$b_1$ 的维度:第 2 层的大小(本例中为 25)

$b_1$ 的维度:第 3 层的大小(本例中为 10)

定义一个随机初始化 theta 的函数:

def randInitializeWeights(Lin, Lout):
    epi = (6**1/2) / (Lin + Lout)**0.5
    w = np.random.rand(Lout, Lin)*(2*epi) -epi
    return w

应用此函数初始化 theta

hidden_layer = 25
output =10
theta1 = randInitializeWeights(len(df.T), hidden_layer)
theta2 = randInitializeWeights(hidden_layer, output)
theta = [theta1, theta2]

当初,初始化咱们下面探讨过的偏置项:

b1 = np.random.randn(25,)
b2 = np.random.randn(10,)
  1. 实现前向流传

应用前向流传局部中的公式。

为了不便起见,定义一个函数来乘以 θ 和 X

def z_calc(X, theta):
    return np.dot(X, theta.T)

咱们也将屡次应用激活函数。同样定义一个函数

def sigmoid(z):
    return 1/(1+ np.exp(-z))

当初我将逐渐演示正向流传。首先,计算 z 项:

z1 =z_calc(df, theta1) + b1

当初通过激活函数传递这个 z1,失去暗藏层

a1 = sigmoid(z1)

a1 是暗藏层。a1 的形态是 5000 x 25。反复雷同的过程来计算第 3 层或输入层

z2 = z_calc(a1, theta2) + b2
a2 = sigmoid(z2)

a2 的形态是 5000 x 10。10 列代表 10 个类。a2 是咱们的第 3 层或最终输入。如果在这个例子中有更多的暗藏层,在从一个层到另一个层的过程中会有更多的反复步骤。这种利用输出特色计算输入层的过程称为前向流传。

l = 3  #层数
b = [b1, b2]
def hypothesis(df, theta):
    a = []
    z = []
    for i in range (0, l-1):
        z1 = z_calc(df, theta[i]) + b[i]
        out = sigmoid(z1)
        a.append(out)
        z.append(z1)
        df = out
    return out, a, z
  1. 实现反向流传

这是反向计算梯度和更新 θ 的过程。在此之前,咱们须要批改 ’y’。咱们在“y”有 10 个类。但咱们须要将每个类在其列中离开。例如,针对第 10 类的列。咱们将为 10 替换 1,为其余类替换 0。这样咱们将为每个类创立一个独自的列。

y1 = np.zeros([len(df), len(y_arr)])
y1 = pd.DataFrame(y1)
for i in range(0, len(y_arr)):
    for j in range(0, len(y1)):
        if y[0][j] == y_arr[i]:
            y1.iloc[j, i] = 1
        else: 
            y1.iloc[j, i] = 0
y1.head()

之前我一步一步地演示了向前流传,而后把所有的都放在一个函数中,我将对反向流传做同样的事件。应用上述反向流传局部的梯度公式,首先计算 $\delta_3$。咱们将应用前向流传实现中的 z1、z2、a1 和 a2。

del3 = y1-a2

当初应用以下公式计算 delta2:

这里是 delta2:

del2 = np.dot(del3, theta2) * a1*(1 - a1)

在这里咱们须要学习一个新的概念。这是一个 sigmoid 梯度。sigmoid 梯度的公式为:

如果你留神到了,这和 delta 公式中的 a(1-a) 完全相同。因为 a 是 sigmoid(z)。咱们来写一个对于 sigmoid 梯度的函数:

def sigmoid_grad(z):
    return sigmoid(z)*(1 - sigmoid(z))

最初,应用以下公式更新 θ:

咱们须要抉择一个学习率。我选了 0.003。我激励你尝试应用其余学习率,看看它的体现:

theta1 = np.dot(del2.T, pd.DataFrame(a1)) * 0.003
theta2 = np.dot(del3.T, pd.DataFrame(a2)) * 0.003

这就是 θ 须要更新的形式。这个过程称为反向流传,因为它向后挪动。在编写反向流传函数之前,咱们须要定义老本函数。因为我会把老本的计算也包含在反向流传办法中。但它是能够增加到前向流传中,或者能够在训练网络时将其离开的。

def cost_function(y, y_calc, l):
    return (np.sum(np.sum(-np.log(y_calc)*y - np.log(1-y_calc)*(1-y))))/m

这里 m 是训练实例的数量。综合起来的代码:

m = len(df)
def backpropagation(df, theta, y1, alpha):
    out, a, z = hypothesis(df, theta)
    delta = []
    delta.append(y1-a[-1])
    i = l - 2
    while i > 0:
        delta.append(np.dot(delta[-i], theta[-i])*sigmoid_grad(z[-(i+1)]))
        i -= 1
    theta[0] = np.dot(delta[-1].T, df) * alpha
    for i in range(1, len(theta)):
        theta[i] = np.dot(delta[-(i+1)].T, pd.DataFrame(a[0])) * alpha
    out, a, z = hypothesis(df, theta)
    cost = cost_function(y1, a[-1], 1)
    return theta, cost
  1. 训练网络

我将用 20 个 epoch 训练网络。我在这个代码片段中再次初始化 theta。

theta1 = randInitializeWeights(len(df.T), hidden_layer)
theta2 = randInitializeWeights(hidden_layer, output)
theta = [theta1, theta2]
cost_list = []
for i in range(20):
    theta, cost= backpropagation(df, theta, y1, 0.003)
    cost_list.append(cost)
cost_list

我应用了 0.003 的学习率并运行了 20 个 epoch。然而请看文章末提供的 GitHub 链接。我有试着用不同的学习率和不同的 epoch 数训练模型。

咱们失去了每个 epoch 计算的老本,以及最终更新的 θ。用最初的 θ 来预测输入。

  1. 预测输入并计算精度

只需应用假如函数并传递更新后的 θ 来预测输入:

out, a, z = hypothesis(df, theta)

当初计算一下准确率,

accuracy= 0
for i in range(0, len(out)):
    for j in range(0, len(out[i])):
        if out[i][j] >= 0.5 and y1.iloc[i, j] == 1:
            accuracy += 1
accuracy/len(df)

准确率为 100%。完满,对吧?但咱们并不是始终都能失去 100% 的准确率。有时取得 70% 的准确率是很好的,这取决于数据集。

祝贺!你刚刚开发了一个残缺的神经网络!

以下是残缺工作代码的 GitHub 链接:

https://github.com/rashida048…

原文链接:https://medium.com/towards-ar…

欢送关注磐创 AI 博客站:
http://panchuang.net/

sklearn 机器学习中文官网文档:
http://sklearn123.com/

欢送关注磐创博客资源汇总站:
http://docs.panchuang.net/

正文完
 0