问题:如何实现数字“5”的识别?O(∩_∩)O~
手写数字“5”的例子:写法因人而异,五花八门
方案: 从图像中提取特征量-----用及其学习技术学习这些特征量的模式
神经网络的学习中所用到的指标称为损失函数。
可以用作损失函数的函数很多,最有名的是均方误差(mean squared error)。
均方误差的表达式:
yk -----------神经网络输出
tk -----------监督数据,one-hot表示
y是softmax函数的输出。softmax函数的输出可以理解为概率。
用python实现均方误差:
def mean_squared_error(y-t):
return 0.5*np.sum((y-t)**2)
除了均方误差,交叉熵误差(cross entropy error)也经常被用作损失函数。
交叉熵误差的表达式:
比如,假设正确解标签的索引是“2”,与之对应的神经网络的输出是 0.6,则交叉熵误差是 -log 0.6 = 0.51;若“2”对应的输出是 0.1,则交叉熵误差为 -log 0.1 = 2.30。也就是说,交叉熵误差的值是由正确解标签所对应的输出结果决定的。
自然对数的图像如图所示:
1 import matplotlib.pyplot as plt
2 import numpy as np
3
4 #生成数据
5 x=np.arange(0.01,1.01,0.01)
6 y=np.log(x)
7
8 #绘制图像
9 plt.plot(x,y)
10 plt.xlabel('x')
11 plt.ylabel('y')
12 plt.show()
代码实现交叉熵误差:
def cross_entropy_error(y,t):
delta=1e-7
return -np.sum(t*np.log(y+delta))
如果计算所有训练数据的损失函数的综合,则公式为:
上述的损失函数都是针对单个数据,加入训练数据一共有6000个,那我们每次拿出100个当做是6000的近似计算一次,这样计算得到的结果就是mini-batch学习的结果。
在之前的笔记中已经知道了读入MNIST数据集的代码,即:
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
(x_train, t_train), (x_test, t_test) = \
load_mnist(normalize=True, one_hot_label=True)
print(x_train.shape) # (60000, 784)
print(t_train.shape) # (60000, 10)
mnist数据下载的代码mnist.py如下:
1 # coding: utf-8
2 try:
3 import urllib.request
4 except ImportError:
5 raise ImportError('You should use Python 3.x')
6 import os.path
7 import gzip
8 import pickle
9 import os
10 import numpy as np
11
12
13 url_base = 'http://yann.lecun.com/exdb/mnist/'
14 key_file = {
15 'train_img':'train-images-idx3-ubyte.gz',
16 'train_label':'train-labels-idx1-ubyte.gz',
17 'test_img':'t10k-images-idx3-ubyte.gz',
18 'test_label':'t10k-labels-idx1-ubyte.gz'
19 }
20
21 dataset_dir = os.path.dirname(os.path.abspath(__file__))
22 save_file = dataset_dir + "/mnist.pkl"
23
24 train_num = 60000
25 test_num = 10000
26 img_dim = (1, 28, 28)
27 img_size = 784
28
29
30 def _download(file_name):
31 file_path = dataset_dir + "/" + file_name
32
33 if os.path.exists(file_path):
34 return
35
36 print("Downloading " + file_name + " ... ")
37 urllib.request.urlretrieve(url_base + file_name, file_path)
38 print("Done")
39
40 def download_mnist():
41 for v in key_file.values():
42 _download(v)
43
44 def _load_label(file_name):
45 file_path = dataset_dir + "/" + file_name
46
47 print("Converting " + file_name + " to NumPy Array ...")
48 with gzip.open(file_path, 'rb') as f:
49 labels = np.frombuffer(f.read(), np.uint8, offset=8)
50 print("Done")
51
52 return labels
53
54 def _load_img(file_name):
55 file_path = dataset_dir + "/" + file_name
56
57 print("Converting " + file_name + " to NumPy Array ...")
58 with gzip.open(file_path, 'rb') as f:
59 data = np.frombuffer(f.read(), np.uint8, offset=16)
60 data = data.reshape(-1, img_size)
61 print("Done")
62
63 return data
64
65 def _convert_numpy():
66 dataset = {}
67 dataset['train_img'] = _load_img(key_file['train_img'])
68 dataset['train_label'] = _load_label(key_file['train_label'])
69 dataset['test_img'] = _load_img(key_file['test_img'])
70 dataset['test_label'] = _load_label(key_file['test_label'])
71
72 return dataset
73
74 def init_mnist():
75 download_mnist()
76 dataset = _convert_numpy()
77 print("Creating pickle file ...")
78 with open(save_file, 'wb') as f:
79 pickle.dump(dataset, f, -1)
80 print("Done!")
81
82 def _change_one_hot_label(X):
83 T = np.zeros((X.size, 10))
84 for idx, row in enumerate(T):
85 row[X[idx]] = 1
86
87 return T
88
89
90 def load_mnist(normalize=True, flatten=True, one_hot_label=False):
91 """读入MNIST数据集
92
93 Parameters
94 ----------
95 normalize : 将图像的像素值正规化为0.0~1.0
96 one_hot_label :
97 one_hot_label为True的情况下,标签作为one-hot数组返回
98 one-hot数组是指[0,0,1,0,0,0,0,0,0,0]这样的数组
99 flatten : 是否将图像展开为一维数组
100
101 Returns
102 -------
103 (训练图像, 训练标签), (测试图像, 测试标签)
104 """
105 if not os.path.exists(save_file):
106 init_mnist()
107
108 with open(save_file, 'rb') as f:
109 dataset = pickle.load(f)
110
111 if normalize:
112 for key in ('train_img', 'test_img'):
113 dataset[key] = dataset[key].astype(np.float32)
114 dataset[key] /= 255.0
115
116 if one_hot_label:
117 dataset['train_label'] = _change_one_hot_label(dataset['train_label'])
118 dataset['test_label'] = _change_one_hot_label(dataset['test_label'])
119
120 if not flatten:
121 for key in ('train_img', 'test_img'):
122 dataset[key] = dataset[key].reshape(-1, 1, 28, 28)
123
124 return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label'])
125
126
127 if __name__ == '__main__':
128 init_mnist()
minst.py在文件夹dataset中,数据在dataset下的mnist.pkl文件中。
目前我还是自己写不出来这样的代码,还是得分析透才能学会,这里先留一下,下次来分析......\
那么,如何从训练数据中随机抽取10笔数据呢?可以使用NumPy的no.random.choice(),携程如下形式:
train_size=x_train.shape[0]
batch_size=10
batch_mask=np.random.choice(train_size,batch_size)
x_batch=x_train[batch_mask]
t_batch=t_train[batch_mask]
mini_batch交叉熵的实现:
def cross_entropy_error(y,t):
if y.ndim==1:
t=t.reshape(1,t.size)
y=y.reshape(1,y.size)
batch_size=y.shape[0]
return -np.sum(t*np.log(y+1e-7))/batch_size
这里,yty 的维度为 1 时,即求单个数据的交叉熵误差时,需要改变数据的形状。并且,当输入为 mini-batch 时,要用 batch 的个数进行正规化,计算单个数据的平均交叉熵误差。
当监督数据是标签形式而不是one-hot表示时,交叉熵代码如下:
def cross_entropy_error(y,t):
if y.ndim==1:
t=t.reshape(1,t.size)
y=y.reshape(1,y.size)
batch_size=y.shape[0]
return -np.sum(np.log(y[np.arange(batch_size),t]+1e-7))/batch_size
实现的要点是,由于 one-hot 表示中ttone-hott * np.log(y)tnp.log( y[np.arange (batch_size), t] )1e-7)。
作为参考,简单介绍一下np.log( y[np.arange(batch_size), t] )
。np.arange (batch_size)
会生成一个从 0 到batch_size-1
的数组。比如当batch_size
np.arange(batch_size)
会生成一个 NumPy 数组[0, 1, 2, 3, 4]
。因为t
中标签是以[2, 7, 0, 9, 4]
的形式存储的,所以y[np.arange(batch_size), t]
y[np.arange(batch_size), t]
会生成 NumPy 数组[y[0,2], y[1,7], y[2,0], y[3,9], y[4,4]]
)。
这部分理解起来并不是很容易,还是得多回顾才能真正掌握。均方误差、交叉熵误差以及下载mnist数据集,这些里面后两部分还得在后续的学习中继续补充。
一定要加油啊,向目标前进~~~
我的前方是万里征途,星辰大海!!