赞
踩
学习笔记
- # coding: utf-8
- import numpy as np
- import matplotlib.pylab as plt
-
- def step_function(x):
- y = x > 0
- return y.astype(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.xlabel("x") # x轴的标签
- plt.ylabel("y") # y轴的标签
- plt.title("step_function")
-
- plt.show()
- # coding: utf-8
- import numpy as np
- import matplotlib.pylab as plt
-
- 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)
-
- plt.xlabel("x") # x轴的标签
- plt.ylabel("y") # y轴的标签
- plt.title("sigmoid_function")
- plt.show()
- # coding: utf-8
- import numpy as np
- import matplotlib.pylab as plt
-
- def sigmoid(x):
- return 1 / (1 + np.exp(-x))
-
- def step_function(x):
- return np.array(x > 0, dtype=int)
-
- x = np.arange(-5.0, 5.0, 0.1)
- y1 = sigmoid(x)
- y2 = step_function(x)
-
- plt.plot(x, y1)
- plt.plot(x, y2, 'k--')
- plt.ylim(-0.1, 1.1) #指定图中绘制的y轴的范围
- plt.show()
- # coding: utf-8
- import numpy as np
- import matplotlib.pylab as plt
-
- def relu(x):
- return np.maximum(0, x)
-
- x = np.arange(-6.0, 6.0, 0.1)
- y = relu(x)
-
- plt.plot(x, y,'b')
- plt.ylim(-1, 5)
- plt.xlabel("x") # x轴的标签
- plt.ylabel("y") # y轴的标签
- plt.title("relu function")
- plt.show()
图3-9 ReLU函数
- import numpy as np
- A = np.array([1, 2, 3, 4])
- print('A = ', A)
- b = np.ndim(A)
- print('b = ',b)
- c = A.shape
- print('c = ',c)
- print(A.shape[0])
- A = [1 2 3 4]
- b = 1
- c = (4,)
- 4
- >>> X = np.array([1, 2])
- >>> X.shape
- (2,)
- >>> W = np.array([[1, 3, 5], [2, 4, 6]])
- >>> print(W)
- [[1 3 5]
- [2 4 6]]
- >>> W.shape
- (2, 3)
- >>> Y = np.dot(X, W)
- >>> print(Y)
- [ 5 11 17]
- 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])
- print(W1.shape) # (2, 3)
- print(X.shape) # (2,)
- print(B1.shape) # (3,)
- A1 = np.dot(X, W1) + B1
- def sigmoid(x):
- return 1/(1+np.exp(-x))
-
- Z1 = sigmoid(A1)
- print(A1) # [0.3, 0.7, 1.1]
- print(Z1) # [0.57444252, 0.66818777, 0.75026011]
- B2 = np.array([0.1, 0.2])
- W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
- print(Z1.shape) # (3,)
- print(W2.shape) # (3, 2)
- print(B2.shape) # (2,)
- A2 = np.dot(Z1, W2) + B2
- Z2 = sigmoid(A2)
- print("A2 = ", A2) # A2 = [0.51615984 1.21402696]
-
- print("Z2 = ", Z2) # Z2 = [0.62624937 0.7710107 ]
A2 = np.dot(Z1, W2) + B2
- def identity_function(x):
- return x
- W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
- B3 = np.array([0.1, 0.2])
- A3 = np.dot(Z2, W3) + B3
- Y = identity_function(A3) # 或者Y = A3
- import numpy as np
-
-
- def sigmoid(x):
- return 1 / (1 + np.exp(-x))
-
-
- def identity_function(x):
- return x
-
-
- 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 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) # [ 0.31682708 0.69627909]
- >>> a = np.array([0.3, 2.9, 4.0])
- >>>
- >>> exp_a = np.exp(a) # 指数函数
- >>> print(exp_a)
- [ 1.34985881 18.17414537 54.59815003]
- >>>
- >>> sum_exp_a = np.sum(exp_a) # 指数函数的和
- >>> print(sum_exp_a)
- 74.1221542102
- >>>
- >>> y = exp_a / sum_exp_a
- >>> print(y)
- [ 0.01821127 0.24519181 0.73659691]
- def softmax(a):
- exp_a = np.exp(a)
- sum_exp_a = np.sum(exp_a)
- y = exp_a / sum_exp_a
- return y
-
- a = np.array([0.3, 2.9, 4.0])
- y = softmax(a)
- print('y = ', y) # y = [0.01821127 0.24519181 0.73659691]
- >>> a = np.array([1010, 1000, 990])
- >>> np.exp(a) / np.sum(np.exp(a)) # softmax函数的运算
- array([ nan, nan, nan]) # 没有被正确计算
- >>>
- >>> c = np.max(a) # 1010
- >>> a - c
- array([ 0, -10, -20])
- >>>
- >>> np.exp(a - c) / np.sum(np.exp(a - c))
- array([ 9.99954600e-01, 4.53978686e-05, 2.06106005e-09])
- 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()函数,可以按如下方式计算神经网络的输出。
- >>> a = np.array([0.3, 2.9, 4.0])
- >>> y = softmax(a)
- >>> print(y)
- [ 0.01821127 0.24519181 0.73659691]
- >>> np.sum(y)
- 1.0
如上所示,softmax函数的输出是0.0到1.0之间的实数。并且,softmax函数的输出值的总和是1。输出总和为1是softmax函数的一个重要性质。正因为有了这个性质,我们才可以把softmax函数的输出解释为“概率”。
比如,上面的例子可以解释成y[0]的概率是0.018(1.8 %),y[1]的概率是0.245(24.5 %),y[2]的概率是0.737(73.7 %)。从概率的结果来看,可以说“因为第2个元素的概率最高,所以答案是第2个类别”。而且,还可以回答“有74 %的概率是第2个类别,有25 %的概率是第1个类别,有1 %的概率是第0个类别”。也就是说,通过使用softmax函数,我们可以用概率的(统计的)方法处理问题。
这里需要注意的是,即便使用了softmax函数,各个元素之间的大小关系也不会改变。这是因为指数函数(y = exp(x))是单调递增函数。实际上,上例中a的各元素的大小关系和y的各元素的大小关系并没有改变。比如,a的最大值是第2个元素,y的最大值也仍是第2个元素。
一般而言,神经网络只把输出值最大的神经元所对应的类别作为识别结果。并且,即便使用softmax函数,输出值最大的神经元的位置也不会变。因此,神经网络在进行分类时,输出层的softmax函数可以省略。在实际的问题中,由于指数函数的运算需要一定的计算机运算量,因此输出层的softmax函数一般会被省略。
求解机器学习问题的步骤可以分为“学习”和“推理”两个阶段。首先,在学习阶段进行模型的学习,然后,在推理阶段,用学到的模型对未知的数据进行推理(分类)。如前所述,推理阶段一般会省略输出层的 softmax函数。在输出层使用 softmax函数是因为它和神经网络的学习有关系(详细内容请参考下一章)。
输出层的神经元数量需要根据待解决的问题来决定。对于分类问题,输出层的神经元数量一般设定为类别的数量。比如,对于某个输入图像,预测是图中的数字0到9中的哪一个的问题(10类别分类问题),可以像图3-23这样,将输出层的神经元设定为10个。
如图3-23所示,在这个例子中,输出层的神经元从上往下依次对应数字0, 1, ..., 9。此外,图中输出层的神经元的值用不同的灰度表示。这个例子中神经元y2颜色最深,输出的值最大。这表明这个神经网络预测的是y2对应的类别,也就是“2”。
介绍完神经网络的结构之后,现在我们来试着解决实际问题。这里我们来进行手写数字图像的分类。假设学习已经全部结束,我们使用学习到的参数,先实现神经网络的“推理处理”。这个推理处理也称为神经网络的前向传播(forward propagation)。
和求解机器学习问题的步骤(分成学习和推理两个阶段进行)一样,使用神经网络解决问题时,也需要首先使用训练数据(学习数据)进行权重参数的学习;进行推理时,使用刚才学习到的参数,对输入数据进行分类。
这里使用的数据集是MNIST手写数字图像集。MNIST是机器学习领域最有名的数据集之一,被应用于从简单的实验到发表的论文研究等各种场合。实际上,在阅读图像识别或机器学习的论文时,MNIST数据集经常作为实验用的数据出现。
MNIST数据集是由0到9的数字图像构成的(图3-24)。训练图像有6万张,测试图像有1万张,这些图像可以用于学习和推理。MNIST数据集的一般使用方法是,先用训练图像进行学习,再用学习到的模型度量能在多大程度上对测试图像进行正确的分类。
MNIST的图像数据是28像素 × 28像素的灰度图像(1通道),各个像素的取值在0到255之间。每个图像数据都相应地标有“7”“2”“1”等标签。
以下是Python脚本mnist.py,该脚本支持从下载MNIST数据集到将这些数据转换成NumPy数组等处理(mnist.py在dataset目录下)。使用mnist.py时,当前目录必须是ch01、ch02、ch03、…、ch08目录中的一个。使用mnist.py中的load_mnist()函数,就可以按下述方式轻松读入MNIST数据。
- import sys, os
- sys.path.append(os.pardir) # 为了导入父目录中的文件而进行的设定
- from dataset.mnist import load_mnist
- # 第一次调用会花费几分钟 ……
- (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True,
- normalize=False)
- # 输出各个数据的形状
- print(x_train.shape) # (60000, 784)
- print(t_train.shape) # (60000,)
- print(x_test.shape) # (10000, 784)
- print(t_test.shape) # (10000,)
首先,为了导入父目录中的文件,进行相应的设定。然后,导入dataset/mnist.py中的 load_mnist函数。最后,使用 load_mnist函数,读入MNIST数据集。第一次调用load_mnist函数时,因为要下载MNIST数据集,所以需要接入网络。第2次及以后的调用只需读入保存在本地的文件(pickle文件)即可,因此处理所需的时间非常短。
用来读入MNIST图像的文件在本书提供的源代码的dataset目录下。并且,我们假定了这个MNIST数据集只能从ch01、ch02、ch03、…、ch08目录中使用,因此,使用时需要从父目录(dataset目录)中导入文件,为此需要添加sys.path.append(os.pardir)语句。
load_mnist函数以“(训练图像 ,训练标签 ),(测试图像,测试标签 )”的形式返回读入的MNIST数据。此外,还可以像load_mnist(normalize=True,flatten=True, one_hot_label=False) 这 样,设 置 3 个 参 数。第 1 个参数normalize设置是否将输入图像正规化为0.0~1.0的值。如果将该参数设置为False,则输入图像的像素会保持原来的0~255。第2个参数flatten设置是否展开输入图像(变成一维数组)。如果将该参数设置为False,则输入图像为1 × 28 × 28的三维数组;若设置为True,则输入图像会保存为由784个元素构成的一维数组。第3个参数one_hot_label设置是否将标签保存为onehot表示(one-hot representation)。one-hot表示是仅正确解标签为1,其余皆为0的数组,就像[0,0,1,0,0,0,0,0,0,0]这样。当one_hot_label为False时,只是像7、2这样简单保存正确解标签;当one_hot_label为True时,标签则保存为one-hot表示。
Python有 pickle这个便利的功能。这个功能可以将程序运行中的对象保存为文件。如果加载保存过的 pickle文件,可以立刻复原之前程序运行中的对象。用于读入MNIST数据集的load_mnist()函数内部也使用了 pickle功能(在第 2次及以后读入时)。利用 pickle功能,可以高效地完成MNIST数据的准备工作。
现在,我们试着显示MNIST图像,同时也确认一下数据。图像的显示使用PIL(Python Image Library)模块。执行下述代码后,训练图像的第一张就会显示出来,如图3-25所示(源代码在ch03/mnist_show.py中)。
- import sys, os
- sys.path.append(os.pardir)
- import numpy as np
- from dataset.mnist import load_mnist
- from PIL import Image
- def img_show(img):
- pil_img = Image.fromarray(np.uint8(img))
- pil_img.show()
- (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True,
- normalize=False)
- img = x_train[0]
- label = t_train[0]
- print(label) # 5
- print(img.shape) # (784,)
- img = img.reshape(28, 28) # 把图像的形状变成原来的尺寸
- print(img.shape) # (28, 28)
- img_show(img)
这里需要注意的是,flatten=True时读入的图像是以一列(一维)NumPy数组的形式保存的。因此,显示图像时,需要把它变为原来的28像素 × 28像素的形状。可以通过reshape()方法的参数指定期望的形状,更改NumPy数组的形状。此外,还需要把保存为NumPy数组的图像数据转换为PIL用的数据对象,这个转换处理由Image.fromarray()来完成。
下面,我们对这个MNIST数据集实现神经网络的推理处理。神经网络的输入层有784个神经元,输出层有10个神经元。输入层的784这个数字来源于图像大小的28 × 28 = 784,输出层的10这个数字来源于10类别分类(数字0到9,共10类别)。此外,这个神经网络有2个隐藏层,第1个隐藏层有50个神经元,第2个隐藏层有100个神经元。这个50和100可以设置为任何值。下面我们先定义get_data()、init_network()、predict()这3个函数(代码在ch03/neuralnet_mnist.py中)。
- # coding: utf-8
- import sys, os
- sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
- import numpy as np
- import pickle
-
- #从dataset/mnist文件夹导入load_minst函数
- from dataset.mnist import load_mnist
- from common.functions import sigmoid, softmax
- #从common/functions文件夹导入sigmoid和softmax函数
-
-
- def get_data():
- (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=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
-
-
- x, t = get_data()
- network = init_network()
- accuracy_cnt = 0
- #用for语句逐一取出保存在x中的图像数据,用predict()函数进行分类
- for i in range(len(x)):
- y = predict(network, x[i])
- p= np.argmax(y) # 用np.argmax(x)函数取出数组中的最大值的索引
- if p == t[i]:
- accuracy_cnt += 1
-
- print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
- #Accuracy:0.9352
- >>> x, _ = get_data()
- >>> network = init_network()
- >>> W1, W2, W3 = network['W1'], network['W2'], network['W3']
- >>>
- >>> x.shape
- (10000, 784)
- >>> x[0].shape
- (784,)
- >>> W1.shape
- (784, 50)
- >>> W2.shape
- (50, 100)
- >>> W3.shape
- (100, 10)
如图 3-27 所示,输入数据的形状为 100 × 784,输出数据的形状为100 × 10。这表示输入的100张图像的结果被一次性输出了。比如,x[0]和y[0]中保存了第0张图像及其推理结果,x[1]和y[1]中保存了第1张图像及其推理结果,等等。
- >>> list( range(0, 10) )
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- >>> list( range(0, 10, 3) )
- [0, 3, 6, 9]
- >>> x = np.array([[0.1, 0.8, 0.1], [0.3, 0.1, 0.6],
- ... [0.2, 0.5, 0.3], [0.8, 0.1, 0.1]])
- >>> y = np.argmax(x, axis=1)
- >>> print(y)
- [1 2 1 0]
- >>> y = np.array([1, 2, 1, 0])
- >>> t = np.array([1, 2, 0, 0])
- >>> print(y==t)
- [True True False True]
- >>> np.sum(y==t)
- 3
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。