会飞的鱼

2020
Godam
首页 » 人工智能 » 深度学习入门--基于Python的理论与实现

深度学习入门--基于Python的理论与实现

第一章 Python入门

numpy

import numpy as np
# 生成numpy数组
x = np.array([1.0, 2.0, 3.0])
print(x)
print(type(x))

# numpy的算术运算
x = np.array([1.0, 2.0, 3.0])
y = np.array([2.0, 4.0, 6.0])
print(x+y)
print(x-y)
print(x*y)
print(x/y)

# numpy的多维数组
A = np.array([[1, 2], [3, 4]])
print(A)
print(A.shape)  # 形状
print(A.dtype)  #数据类型

# 广播标量10会被扩展成为2x2的形状,再与矩阵A相乘
A = np.array([[1, 2], [3, 4]])
B = np.array([10, 10])
print(A*B)

#访问元素
X = np.array([[51, 55], [14, 19], [0, 4]])
print(X[0])
print(X[0][1])

# 遍历
for row in X:
    print(row)

X = X.flatten()  #将X转为一维数组
print(X)
print(X[np.array([0, 2, 4])])  #获取索引为0,2,4的元素

# 若要从X中抽出大于15的元素
print(X>15)
print(X[X>15])

matplotlib

import matplotlib.pyplot as plt
%matplotlib inline

x = np.arange(0, 6, 0.1)  #以0.1为单位,生成0到6的数据
y1 = np.sin(x)
y2 = np.cos(x)
# 绘制图形
plt.plot(x, y1, label="sin")
plt.plot(x, y2, linestyle="--", label="cos")  #用虚线绘制
plt.xlabel("x")  #x轴标签
plt.ylabel("y")  #y轴标签
plt.title('sin & cos')  #标题
plt.legend()
plt.show()

# 显示图像
from matplotlib.image import imread
img = imread(r'C:\Users\Godam\Desktop\1.png')  #读入图像
plt.imshow(img)
plt.show()

第二章 感知机

感知机是什么?

感知机接收多个输入信号,输出一个信号。输入信号被送往神经元时,会被乘以固定的权重,神经元会计算传送过来的信号总和,只有当总和超过某个界限值时,才会输出1.这也被成为“神经元被激活”,这里将界限值成为阈值

感知机的实现

简单实现

def AND(x1, x2):
    w1, w2, theta = 0.5, 0.5, 0.7
    tmp = x1*w1 + x2*w2
    if tmp <= theta:
        return 0
    elif tmp > theta:
        return 1
AND(0, 0) # 输出0
AND(1, 0) # 输出0
AND(0, 1) # 输出0
AND(1, 1) # 输出1

这样子就实现了与门,但这个有些过于简单,我们考虑到之后的应用,将其改为下面的形式,将其中的theta改为-b,式子就变成了y = b + w1x1 + w2x2,其中b成为偏置,w1和w2称为权重,下面我们使用numpy来实现:

x = np.array([0, 1])  #输入
w = np.array([0.5, 0.5])  #权重
b = -0.7  #偏置
print(w*x)
print(np.sum(w*x)+b)

如上w*x就是各个元素分别相乘之后的,然后把偏置加到这个加权总和上。

使用权重和偏置的实现

def AND(x1, x2):
    w = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w*x) +b
    if tmp <= 0:
        return 0
    else:
        return 1

这里的权重是控制输入信号的重要性的参数,而偏置是调整神经元被激活的容易程度的参数。接着,我们实现与非门和或门:

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])  #仅权重和偏置与AND不同
    b = 0.7
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])  #仅权重和偏置与AND不同
    b = -0.2
    tmp = np.sum(w*x) + b
    if tmp <= 0:
        return 0
    else:
        return 1

感知机的局限性

上文中我们讨论的感知机实现均是线性的,在坐标轴上表示时,坐标系会被感知机函数(一条直线)划分为两个线性空间,这对于异或门等需要非线性空间的逻辑来言是无法实现的。因此我们将会通过多层感知机来实现这些。

多层感知机

def XOR(x1, x2):
    s1 = NAND(x1, x2)
    s2 = OR(x1, x2)
    y = AND(s1, s2)
    return y

XOR(0, 0) #输出0
XOR(0, 1) #输出1
XOR(1, 0) #输出1
XOR(1, 1) #输出0

如上述代码,同过基本门电路的组合来实现复杂门电路。

第三章 神经网络

从感知机到神经网络

神经网络经过输入层、中间层(也称隐藏测)、输出层处理数据。神经网络由多个神经元(感知机)组成,乍一看和上一章感知机,没有任何差异,但对于神经网络,我们引入函数h(x),将感知机中的函数转化为y = h(b + w1x1 + w2x2)
这里的h(x)将输入信号的总和转换为输出信号,这种函数一般被称为激活函数,激活函数的作用在于如何来激活输入信号的总和。这里可以理解成先通过加和函数将输入加和之后再通过激活函数处理转换为输出。

激活函数

sigmoid函数

首先我们来实现一个阶跃函数,当输入超过0时,输出1,否则输出0,可以如下简单地进行实现:

def step_function(x):
    if x > 0:
       return 1
    else:
       return 0

这个只能接收实数(浮点数),下面的函数支持numpy数组:

def step_function(x):
    y = x > 0
    return y.astype(np.int)

上述函数只有两行,这是因为使用了NumPy中的技巧,下面来解释下使用了什么技巧:

x = np.array([-1.0, 1.0, 2.0])
y = x > 0
y = astype(np.int)

不要忘记我们在numpy部分提到的,对numpy数组进行不等号运算后返回地是一个布尔型数组,而通过astype函数指定转换的数据类型之后,True会变成1,而false会变成0。

def step_function(x):
    return np.array(x > 0, dtype = np.int)

x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)  #指定y轴的范围
plt.show()

如图所示,它的值呈阶梯式变化,所以称为阶跃函数。
阶跃函数
下面我们来实现sigmoid函数

def sigmoid(x):
    return 1 / (1 + np.exp(-x))
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1) #指定y轴的范围
plt.show()

sll2ad.png

ReLU函数

ReLU函数在输入大于0时,直接输出该值;在输入小于等于0时,输出0。这个的实现很简单:

def relu(x):
    return np.maximum(0, x)

多维数组的运算

数组的维度可以通过np.ndim()函数获得,形状可以通过A.shape获得。矩阵的点积可以通过np.dot()函数计算。

三层神经网络的实现

def init_network():
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])

    return network

def identity_function(x):
    return x

def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)

    return y

network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y)

这里的init_network()函数会进行权重和偏置的初始化,并保存在network字典中,forward()函数则封装了将输入信号转换为输出信号的处理过程。另外,这里的forward(前向)一词,表示的时从输入到输出方向的传递处理。后面将会有backward,从输出到输入方向的处理。

输出层的设计

神经网络可以用在分类问题和回归问题上,一般而言,回归问题用恒等函数,分类问题用softmax函数。下面我们来实现softmax函数:

def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a

    return y

但对于这个函数来说,并不完善,因为当a很大时可能会发生溢出,下面,将其减去x中的最大值之后进行运算作为改进:

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)  #溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a

    return y

softmax函数输出的总是0到1的实数,并且输出值总和为1,有了这个性质,我们可以把softmax函数理解为“概率”。

文章如无特别注明均为原创! 作者: 果果, 转载或复制请以 超链接形式 并注明出处 GODAM|博客|godam
原文地址《 深度学习入门--基于Python的理论与实现》发布于2021-1-10

分享到:
打赏

评论

游客

切换注册

登录

您也可以使用第三方帐号快捷登录

切换登录

注册

sitemap