在上一章感知机的基础上,详细介绍神经网络。
3.1 从感知机到神经网络
3.1.1 神经网络的例子
3.1.2 复习感知机
3.1.3 激活函数登场
刚才登场的 h (x )函数会将输入信号的总和转换为输出信号,这种函数一般称为激活函数 (activation function)。
3.2 激活函数
3.2.1 sigmoid 函数
上一章介绍的感知机和接下来要介绍的神经网络的主要区别就在于这个激活函数。
3.2.2 阶跃函数的实现
>>> import numpy as np
>>> x=np.array([-1.0,1.0,2.0])
>>> x
array([-1., 1., 2.])
>>> y=x>0
>>> y
array([False, True, True])
>>> y=y.astype(np.int)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\xxx\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\numpy\__init__.py", line 338, in __getattr__
raise AttributeError(__former_attrs__[attr])
AttributeError: module 'numpy' has no attribute 'int'.
`np.int` was a deprecated alias for the builtin `int`. To avoid this error in existing code, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
The aliases was originally deprecated in NumPy 1.20; for more details and guidance see the original release note at:
https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations. Did you mean: 'inf'?
>>> y=y.astype(int)
>>> y
array([0, 1, 1])
运行书上的代码出现错误,不再使用np.int,直接使用int,我的python版本已经是
\ml\ch03> python --version
Python 3.12.4
3.2.3 阶跃函数的图形
它的值呈阶梯式变化,所以称为阶跃函数。step_function.py
# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
def step_function(x):
return np.array(x > 0, dtype=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()
图形效果
3.2.4 sigmoid 函数的实现
首先注意到的是“平滑性”的不同。sigmoid 函数是一条平滑的曲线,输出随着输入发生连续性的变化。而阶跃函数以 0 为界,输出发生急剧性的变化。sigmoid 函数的平滑性对神经网络的学习具有重要意义。
>>> import numpy as np
>>> def sigmoid(x):
... return 1/(1+np.exp(-x))
...
>>> x=np.array([-1.0,1.0,2.0])
>>> sigmoid(x)
array([0.26894142, 0.73105858, 0.88079708])
>>>
>>> t=np.array([1.0,2.0,3.0])
>>> 1.0+t
array([2., 3., 4.])
>>> 1.0/t
array([1. , 0.5 , 0.33333333])
>>>
sigmoid.py
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.show()
效果:
3.2.5 sigmoid 函数和阶跃函数的比较
差异:
1)平滑对急剧变化
2)感知机中神经元之间流动的是 0 或 1 的二元信号,而神经网络中流动的是连续的实数值信号。
共同性质:
1)两者的结构均是“输入小时,输出接近 0(为 0);随着输入增大,输出向 1 靠近(变成 1)
2)不管输入信号有多小,或者有多大,输出信号的值都在 0 到 1 之间
3.2.6 非线性函数
两者都属于非线性的函数。
为什么不能使用线性函数呢?因为使用线性函数的话,加深神经网络的层数就没有意义了。
3.3 多维数组的运算
如果掌握了 NumPy 多维数组的运算,就可以高效地实现神经网络.
一维数组:
>>> import numpy as np
>>> A=np.array([1,2,3,4])
>>> print(A)
[1 2 3 4]
>>> np.ndim(A)
1
>>> A.shape
(4,)
>>> A.shape[0]
4
二维数组:
>>> B=np.array([[1,2],[3,4],[5,6]])
>>> print(B)
[[1 2]
[3 4]
[5 6]]
>>> np.ndim(B)
2
>>> B.shape
(3, 2)
二维数组也称为矩阵 (matrix)
3.3.2 矩阵乘法
矩阵的乘积是通过左边矩阵的行(横向)和右边矩阵的列(纵向)以对应元素的方式相乘后再求和而得到的。
>>> A=np.array([[1,2],[3,4]])
>>> A.shape
(2, 2)
>>> B=np.array([[5,6],[7,8]])
>>> B.shape
(2, 2)
>>> np.dot(A,B)
array([[19, 22],
[43, 50]])
3.6 手写数字识别
3.6.1 MNIST 数据集
本书提供了便利的 Python 脚本 mnist.py ,该脚本支持从下载 MNIST 数据集到将这些数据转换成 NumPy 数组等处理(mnist.py 在 dataset 目录下)。
使用 mnist.py 时,当前目录必须是 ch01 、ch02 、ch03、…、ch08 目录中的一个。使用 mnist.py 中的 load_mnist() 函数,就可以按下述方式轻松读入 MNIST 数据。
实际使用中是报错的,提示urllib.request获取数据失败,检查代码:
from dataset.mnist import load_mnist
使用的是dataset目录下的mnist.py中的load_mnist函数
直接查看mnist.py源码:
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"
上面的代码是把从网站下载的4个文件放到mnist.pkl中保存。下载代码如下:
def _download(file_name):
file_path = dataset_dir + "/" + file_name
if os.path.exists(file_path):
return
urllib.request.urlretrieve(url_base + file_name, file_path)
直接运行,下载这一步报错了。从浏览器直接下载试试
MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges
下载被拒绝,网上搜了一下原因,然后就更换为:
GitHub - zalandoresearch/fashion-mnist: A MNIST-like fashion product database. Benchmark
下载OK了,但里面的图明显不是0-9的数字,库不太对,又找了一个:
https://ossci-datasets.s3.amazonaws.com/mnist/
这个库也不太对,里面显示的应该也是各种衬衫、裙子的识别,估计和fashion-mnist是一样的。
最终在github上找到了原始的0-9数字数据集:
https://github.com/geektutu/tensorflow-tutorial-samples/blob/master/mnist/data_set/
通过浏览器下载到dataset目录,就可以了。
程序下载经常会失败,原因众所周知,国内访问github总是时灵时不灵,用浏览器也要多刷几次才行(骂一句万恶的墙,啥时候才能拆了接轨世界)。
插曲:如果是内网,python下载需要在程序中设置代理。
file_path = dataset_dir + "/" + file_name
if os.path.exists(file_path):
return
print("set proxy...")
# 设置代理
proxies = {'http': 'http://proxy.xxx:80', 'https': 'https://proxy.xxx:80'}
proxy_handler = urllib.request.ProxyHandler(proxies)
# 创建Opener
opener = urllib.request.build_opener(proxy_handler)
# 安装Opener
urllib.request.install_opener(opener)
print("Downloading " + file_name + " ... ")
urllib.request.urlretrieve(url_base + file_name, file_path)
print("Done")
下载好了dataset就可以mnist_show.py了,提示还有错误:
D:\python\test\ch03>py mnist_show.py
Traceback (most recent call last):
File "mnist_show.py", line 5, in <module>
from PIL import Image
ModuleNotFoundError: No module named 'PIL'
PIL 库没有?
py -m pip install Pillow --proxy http://proxy.xxx.cn:80 -i https://pypi.tuna.tsinghua.edu.cn/simple
Installing collected packages: Pillow
Successfully installed Pillow-9.5.0
成功安装Pillow后问题解决。
mnist_show.py代码,加了注释
import sys,os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定,这里要用dataset目录下的mnist.py文件
import numpy as np
from dataset.mnist import load_mnist # 导入mnist.py文件中的load_mnist函数
from PIL import Image # 这个包需要单独安装,py -m pip install Pillow --proxy http://proxy.xxx.cn:80 -i https://pypi.tuna.tsinghua.edu.cn/simple
def img_show(img):
pil_img = Image.fromarray(np.uint8(img)) # 把保存为 NumPy 数组的图像数据转换为 PIL 用的数据对象
pil_img.show()
# 第一次加载需要几分钟,load_mnist是从网上下载,如前所述,直接手工下载到dataset目录就行了,不需要执行下载,这样就快了
# load_mnist 函数以“( 训练图像, 训练标签 ),( 测试图像, 测试标签 ) ”的形式返回读入的 MNIST 数据
(x_train, t_train),(x_test, t_test) = load_mnist(
flatten=True, # flatten=True 时读入的图像是以784个元素构成的一维数组的形式保存的。因此,显示图像时,需要把它变为原来的 28像素 × 28 像素的形状。
normalize=False) # normalize 设置是否将输入图像正规化为 0.0~1.0 的值。如果将该参数设置为 False ,则输入图像的像素会保持原来的 0~255
# 输出各数据的形状
print(x_train.shape) # (60000, 784)
print(t_train.shape) # (60000,)
print(x_test.shape) # (10000, 784)
print(t_test.shape) # (10000,)
img = x_train[0]
label = t_train[0]
print(label)
print(img.shape)
img = img.reshape(28,28) # 通过 reshape() 方法的参数指定期望的形状,更改 NumPy 数组的形状。
print(img.shape)
img_show(img)
运行结果和书上是一样的,标签是5,图形也是5,侧面证明和书上的数据集是一套。
D:\python\test\ch03>py mnist_show.py
(60000, 784)
(60000,)
(10000, 784)
(10000,)
5
(784,)
(28, 28)
图形:
其他内容待续: