深度学习入门之2--神经网络

目录

1神经网络初解

2激活函数及实现

2.1初识激活函数

2.1激活函数类型及实现

2.1.1阶跃函数及实现

2.1.2sigmoid函数及实现

2.1.3Relu函数及实现

2.1.4恒等函数和softmax函数及实现

3手写数字识别

3.1mnist数据集

3.1.1下载数据集

3.1.2读取数据集

3.2神经网络推理处理

3.2.1ch03/neuralnet_mnist.py

3.2.2dataset/mnist.py

3.2.3common/active.py

3.3批处理


该文章是对《深度学习入门 基于Python的理论与实现》的总结,作者是[日]斋藤康毅

1神经网络初解

如图所示。我们把最左边的一列称为输入层,最右边的一列称为输出层,中间的一列称为中间层。中间层有时也称为隐藏层。

深度学习入门之2--神经网络_第1张图片

第0层对应输入层,第1层对应中间层,第2层对应输出层。本书将根据实质上拥有权重的层数(输入层、隐藏层、输出层的总数减去1后的数量)来表示网络的名称。

2激活函数及实现

2.1初识激活函数

使用h(x)函数会将输入信号的总和转换为输出信号,这种函数一般称为激活函数(activation function)。先计算输入信号的加权总和,然后用激活函数转换这一总和,激活函数是连接感知机和神经网络的桥梁。

可以用下面的图来表示

深度学习入门之2--神经网络_第2张图片

由上图:信号的加权总和为节点a,然后节点a被激活函数h()转换成节点y。

【注】:“朴素感知机”是指单层网络,指的是激活函数使用了阶跃函数的模型。

【注】:“多层感知机”是指神经网络,即使用sigmoid函数等平滑的激活函数的多层网络。

2.1激活函数类型及实现

2.1.1阶跃函数及实现

激活函数以阈值为界,一旦输入超过阈值,就切换输出。这样的函数称为“阶跃函数”。在激活函数的众多候选函数中,感知机使用了阶跃函数。

图像如下图:

深度学习入门之2--神经网络_第3张图片

代码如下:当输入超过0时,输出1,否则输出0。

import numpy as np
import matplotlib.pylab as plt


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


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


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


if __name__ == "__main__":
    x = np.arange(-5.0, 5.0, 0.1)
    y = step_function(x)
    plt.plot(x, y)
    plt.ylim(-0.1, 1.1)
    plt.show()

2.1.2sigmoid函数及实现

sigmoid的函数式为:
深度学习入门之2--神经网络_第4张图片

代码如下:

import numpy as np
import matplotlib.pylab as plt


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


if __name__ == "__main__":
    x = np.arange(-5.0, 5.0, 0.1)
    y = sigmoid(x)
    plt.title("sigmoid")
    plt.xlabel("x")
    plt.ylabel("y")
    plt.plot(x, y)
    plt.ylim(-0.1, 1.1)
    plt.show()

得到的图像如下

深度学习入门之2--神经网络_第5张图片

2.1.3Relu函数及实现

阶跃函数和sigmoid函数还有其他共同点,就是两者均为非线性函数。sigmoid函数是一条曲线,阶跃函数是一条像阶梯一样的折线,两者都属于非线性的函数。

线性函数是一条笔直的直线。而非线性函数,顾名思义,指的是不像线性函数那样呈现出一条直线的函数。

神经网络的激活函数必须使用非线性函数。换句话说,激活函数不能使用线性函数。为什么不能使用线性函数呢?因为使用线性函数的话,加深神经网络的层数就没有意义了。

为了发挥叠加层所带来的优势,激活函数必须使用非线性函数。

Relu函数格式如下:

代码实现如下:

import numpy as np
import matplotlib.pylab as plt


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


if __name__ == "__main__":
    x = np.arange(-5.0, 5.0, 0.1)
    y = relu(x)
    plt.title("Relu")
    plt.xlabel("x")
    plt.ylabel("y")
    plt.plot(x, y)
    plt.ylim(-0.1, 1.1)
    plt.show()

图像绘制如下:
深度学习入门之2--神经网络_第6张图片

2.1.4恒等函数和softmax函数及实现

恒等函数会将输入按原样输出,对于输入的信息,不加以任何改动地直接输出。因此,在输出层使用恒等函数时,输入信号会原封不动地被输出。另外,将恒等函数的处理过程用之前的神经网络图来表示的话,则如图3-21所示。和前面介绍的隐藏层的激活函数一样,恒等函数进行的转换处理可以用一根箭头来表示。

恒等函数:

深度学习入门之2--神经网络_第7张图片

softmax格式如下:

softmax函数改进:

深度学习入门之2--神经网络_第8张图片

【注】:在计算机的运算上有一定的缺陷。这个缺陷就是溢出问题。softmax函数的实现中要进行指数函数的运算,但是此时指数函数的值很容易变得非常大。比如,e 10 的值会超过20000,e 100 会变成一个后面有40多个0的超大值,e 1000 的结果会返回一个表示无穷大的 inf 。如果在这些超大值之间进行除法运算,结果会出现“不确定”的情况。

【注】:上式在分子和分母上都乘上C这个任意的常数(因为同时对分母和分子乘以相同的常数,所以计算结果不变)。然后,把这个C移动到指数函数(exp)中,记为log C。最后,把log C替换为另一个符号C 。在进行softmax的指数函数的运算时,加上(或者减去)某个常数并不会改变运算的结果。这里的C可以使用任何值,但是为了防止溢出,一般会使用输入信号中的最大值。

假设输出层共有n个神经元,计算第k个神经元的输出y k ,softmax函数的分子是输入信号a k 的指数函数,分母是所有输入信号的指数函数的和。softmax函数的输出通过箭头与所有的输入信号相连。这是因为,从上式可以看出,输出层的各个神经元都受到所有输入信号的影响。

softmax图像如下:
深度学习入门之2--神经网络_第9张图片

代码如下:

import numpy as np
import matplotlib.pylab as plt


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


if __name__ == "__main__":
    x = np.arange(-5.0, 5.0, 0.1)
    y = softmax(x)
    plt.title("softmax")
    plt.xlabel("x")
    plt.ylabel("y")
    plt.plot(x, y)
    plt.ylim(-0.1, 1.1)
    plt.show()

图像绘制如下:
深度学习入门之2--神经网络_第10张图片

3手写数字识别

神经网络和求解机器学习问题的步骤(分成学习推理两个阶段进行)一样,1、使用神经网络解决问题时,也需要首先使用训练数据(学习数据)进行权重参数的学习;2、进行推理时,使用刚才学习到的参数,对输入数据进行分类。先实现神经网络的“推理处理”。这个推理处理也称为神经网络的前向传播(forward propagation)。

该项目目录如下:

 

3.1mnist数据集

3.1.1下载数据集

MNIST的图像数据是28像素 × 28像素的灰度图像(1通道),各个像素的取值在0到255之间。每个图像数据都相应地标有“7”“2”“1”等标签。

可以使用dataset/mnist.py文件下载数据集以及模型:

# coding: utf-8
try:
    import urllib.request
except ImportError:
    raise ImportError('You should use Python 3.x')
import os.path
import gzip
import pickle
import os
import numpy as np


url_base = 'http://yann.lecun.com/exdb/mnist/'
key_file = {
    'train_img':'train-images-idx3-ubyte.gz',
    'train_label':'train-labels-idx1-ubyte.gz',
    'test_img':'t10k-images-idx3-ubyte.gz',
    'test_label':'t10k-labels-idx1-ubyte.gz'
}

dataset_dir = os.path.dirname(os.path.abspath(__file__))
save_file = dataset_dir + "/mnist.pkl"

train_num = 60000
test_num = 10000
img_dim = (1, 28, 28)
img_size = 784


def _download(file_name):
    file_path = dataset_dir + "/" + file_name

    if os.path.exists(file_path):
        return

    print("Downloading " + file_name + " ... ")
    urllib.request.urlretrieve(url_base + file_name, file_path)
    print("Done")


def download_mnist():
    for v in key_file.values():
       _download(v)


def _load_label(file_name):
    file_path = dataset_dir + "/" + file_name

    print("Converting " + file_name + " to NumPy Array ...")
    with gzip.open(file_path, 'rb') as f:
            labels = np.frombuffer(f.read(), np.uint8, offset=8)
    print("Done")

    return labels


def _load_img(file_name):
    file_path = dataset_dir + "/" + file_name

    print("Converting " + file_name + " to NumPy Array ...")
    with gzip.open(file_path, 'rb') as f:
            data = np.frombuffer(f.read(), np.uint8, offset=16)
    data = data.reshape(-1, img_size)
    print("Done")

    return data


def _convert_numpy():
    dataset = {}
    dataset['train_img'] = _load_img(key_file['train_img'])
    dataset['train_label'] = _load_label(key_file['train_label'])
    dataset['test_img'] = _load_img(key_file['test_img'])
    dataset['test_label'] = _load_label(key_file['test_label'])

    return dataset


def init_mnist():
    download_mnist()
    dataset = _convert_numpy()
    print("Creating pickle file ...")
    with open(save_file, 'wb') as f:
        pickle.dump(dataset, f, -1)
    print("Done!")


def _change_one_hot_label(X):
    T = np.zeros((X.size, 10))
    for idx, row in enumerate(T):
        row[X[idx]] = 1

    return T


def load_mnist(normalize=True, flatten=True, one_hot_label=False):
    if not os.path.exists(save_file):
        init_mnist()

    with open(save_file, 'rb') as f:
        dataset = pickle.load(f)

    if normalize:
        for key in ('train_img', 'test_img'):
            dataset[key] = dataset[key].astype(np.float32)
            dataset[key] /= 255.0

    if one_hot_label:
        dataset['train_label'] = _change_one_hot_label(dataset['train_label'])
        dataset['test_label'] = _change_one_hot_label(dataset['test_label'])

    if not flatten:
         for key in ('train_img', 'test_img'):
            dataset[key] = dataset[key].reshape(-1, 1, 28, 28)

    return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label'])


if __name__ == '__main__':
    init_mnist()

则可以得到下图:
深度学习入门之2--神经网络_第11张图片

深度学习入门之2--神经网络_第12张图片

3.1.2读取数据集

import sys, os
'''sys.path.append(os.pardir) 语句实际上是把父目录 demo加入到 sys.path (Python的搜索模块的路径集)
中,从而可以导入demo下的任何目录(包括 dataset 目录)中的任何文件。
'''
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
from dataset.mnist import load_mnist

# 第一次调用会花费几分钟
'''
1、normalize :设置是否将输入图像正规化为0.0~1.0的值。如果将该参数设置为 False ,
则输入图像的像素会保持原来的0~255
2、第2个参数 flatten 设置是否展开输入图像(变成一维数组)。

'''
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)

# 输出各个数据的形状
print(os.pardir)  # ..
print(sys.path.append(os.pardir))  # None
print(x_train.shape)  # (60000, 784)
print(t_train.shape)  # (60000,)
print(x_test.shape)  # (10000, 784)
print(t_test.shape)  # (10000,)

3.2神经网络推理处理

所需文件:ch03/neuralnet_mnist.py,dataset/mnist.py,common/active.py

3.2.1ch03/neuralnet_mnist.py

import sys, os
sys.path.append(os.pardir)
import pickle
import numpy as np
from dataset.mnist import load_mnist
from common.active import sigmoid, softmax
from PIL import Image


def img_show(img):
    pil_img = Image.fromarray(np.uint(img))
    pil_img.show()


def get_data():
    (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=True, one_hot_label=False)
    return x_test, t_test


# init_network() 会读入保存在pickle文件 sample_weight.pkl 中的学习到的权重参数A 。
def init_network():
    with open("sample_weight.pkl", 'rb') as f:
        network = pickle.load(f)
    return network


def predict(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 = softmax(a3)
    return y


if __name__ == "__main__":
    network = init_network()
    # print(network['W1'][0].shape)  # (784, 50)
    # print(network['b1'].shape)  # (50, )
    # print(network['W2'].shape)  # (50, 100)
    # print(network['b2'].shape)  # (100,)
    # print(network['W3'].shape)  # (100, 10)
    # print(network['b3'].shape)  # (10,)

    x, t = get_data()  # 读取测试集的图片和标签
    # img_show(x[0])
    print(t[0])
    accuracy_cnt = 0
    for i in range(len(x)):  # 共有10000张测试集图片
        y = predict(network, x[i])  # 传入图片进行训练
        p = np.argmax(y)  # 获取概率最高的元素的指引
        if p == t[i]:  # 判断训练结果与标签是否一致,检验正确性
            accuracy_cnt += 1  # 正确的结果进行累加

    print("Accuracy: "+str(float(accuracy_cnt)/len(x)))  # 正确的数量除以总的结果数

3.2.2dataset/mnist.py

见上

3.2.3common/active.py

import numpy as np
import matplotlib.pylab as plt


# 1、阶跃函数的实现
def step_func(x):
    return np.array(x > 0, dtype=np.int)


# 2、sigmoid函数的实现
def sigmoid(x):
    return 1/(1 + np.exp(-x))


# 3、relu函数的实现
def relu(x):
    return np.maximum(0, x)


# 4、不做操作
def identity_function(x):
    return x


# 5、输出层的激活函数
def softmax(x):
    c = np.max(x)
    exp_a = np.exp(x - c) # 溢出对策
    sum_exp_a = np.sum(exp_a)
    y = exp_a/sum_exp_a
    return y


if __name__ == "__main__":
    X = np.array([1.0, 0.5])
    W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    B1 = np.array([0.1, 0.2, 0.3])

    A1 = np.dot(X, W1) + B1

    Z1 = sigmoid(A1)
    print(A1)
    print(Z1)

3.3批处理

修改ch03/neuralnet_mnist.py

import sys, os
sys.path.append(os.pardir)
import pickle
import numpy as np
from dataset.mnist import load_mnist
from common.active import sigmoid, softmax
from PIL import Image


def img_show(img):
    pil_img = Image.fromarray(np.uint(img))
    pil_img.show()


def get_data():
    (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=True, one_hot_label=False)
    return x_test, t_test


# init_network() 会读入保存在pickle文件 sample_weight.pkl 中的学习到的权重参数A 。
def init_network():
    with open("sample_weight.pkl", 'rb') as f:
        network = pickle.load(f)
    return network


def predict(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 = softmax(a3)
    return y


if __name__ == "__main__":
    network = init_network()
    # print(network['W1'][0].shape)  # (784, 50)
    # print(network['b1'].shape)  # (50, )
    # print(network['W2'].shape)  # (50, 100)
    # print(network['b2'].shape)  # (100,)
    # print(network['W3'].shape)  # (100, 10)
    # print(network['b3'].shape)  # (10,)

    x, t = get_data()  # 读取测试集的图片和标签
    # img_show(x[0])
    print(t[0])

    batch_size = 100  # 批数量
    accuracy_cnt = 0
    for i in range(0, len(x), batch_size):  # 共有10000张测试集图片
        x_batch = x[i:i+batch_size]  # 0-100
        y_batch = predict(network, x_batch)
        p = np.argmax(y_batch, axis=1)
        accuracy_cnt += np.sum(p == t[i:i+batch_size])
    print("Accuracy: "+str(float(accuracy_cnt)/len(x)))  # 正确的数量除以总的结果数

 

你可能感兴趣的:(人工智能,python)