\[\newcommand{\b}{\mathbf} \]
II.感知机
感知机输入多个信号,输出一个信号。一个最基础的感知机由权重和阈值两部分组成:若输入关于权重的线性组合高于阈值则输出 \(1\),此时神经元被认为激活;否则输出 \(0\),则神经元未被激活。与门、或门都可以被看作基础的感知机。
感知机的一种数学描述是,有权重向量 \(\b w\) 和偏置 \(b\),对于输入向量 \(\b x\),使用 \([b+\b w\cdot\b x>0]\) 作为感知机输出。
感知机有其局限性,例如其仅能将线性空间二分割,故异或门无法实现。
单层感知机无法描述异或门,但是通过多层感知机的叠加,异或门即可得以实现。
使用 sigmoid 函数(下文中出现)的双层感知机是图灵机(?)
III.神经网络
神经网络最基础的分层,是输入层、中间层、输出层三层,层标号自 \(0\) 开始。
偏置 \(b\) 也可以被看作是一个恒一神经元以 \(b\) 的权重对感知机的输入。非首层神经元上有“激活函数”,对输入的组合进行转换:例如,使用 \(h(x)=[x>0]\) 的阶跃函数时,即得朴素感知机。
sigmoid 函数 \(h(x)=\dfrac1{1+e^{-x}}\) 也是常见的激活函数。其是一个具有良好平滑性的函数。
神经网络的激活函数必然都是非线性函数,否则加深神经网络的层数就没有影响了。
最近大家比较喜欢 ReLU 函数 \(h(x)=\max(x,0)\)。
令 \(W^{(i)}\) 为 \(i-1\) 层至 \(i\) 层的转移,则其是线性变换,可以用矩阵描述;令 \(\b x^{(i)}\) 为 \(i\) 层值向量(用行向量描述),\(\b b^{(i)}\) 为 \(i\) 层偏置,则神经网络基础公式即为:
\[\b x^{(i)}=h(\b x^{(i-1)}W^{(i)}+\b b^{(i)}) \]隐藏层的激活函数约定俗成地记作 \(h(x)\),而输出层为统一也有其激活函数,记作 \(\sigma(x)\)。输出层的激活函数设计与神经网络待解决的问题相关:分类问题(对输入离散地归类)往往用 softmax 函数 \(\sigma(\b x)=\dfrac{\exp(\b x)}{\|\exp(\b x)\|_1}\),而回归问题(用输入预测连续输出)往往用恒等函数。
计算 \(\exp\) 有可能爆精度。通过上下同乘 \(C\) 加以处理,最终可以得到修正的 softmax \(\sigma(\b x)=\dfrac{\exp(\b x+C\b1)}{\|\exp(\b x+C\b1)\|_1}\),使用 \(C\) 为 \(-\|\b x\|_\infty\) 即可。
softmax 的输出总是可以被解释为一组概率密度分布。因为 softmax 有一定计算量,softmax 有可能被换为朴素的 argmax。分类问题中,输出层的神经元数目常常即为类别数目。
将多个向量并列拼成矩阵,可以缩短处理时间,被称作批处理。
IV.神经网络的学习
神经网络不重要,重要的神经网络的参数。参数没法人脑拟合,要靠算法自己学习。
方法一是靠人脑提取某些特征量,然后针对特征量跑机器学习。方法二是直接把数据丢到神经网络(深度学习)上跑参数。
损失函数是用于量化神经网络性能的函数。例如,均方误差 \(\dfrac12\sum(t_i-y_i)^2\),其中 \(t_i\) 是监督数据,\(y_i\) 是输出数据;在分类问题中,softmax 函数的输出是概率密度向量,监督数据使用 one-hot 表示,即除了关键位为 \(1\) 外其余位置都是 \(0\)。例如,交叉熵误差 \(E=-\sum t_i\ln y_i\)。加上 epsilon 可以避免出现负无穷。
单个数据的损失函数按照上述方式计算;总数据集损失函数用所有单个函数的损失函数求平均得到。
使用损失函数而非正确预测数目,原因是正确预测数目的梯度在很多地方为零,不好优化。
同理,使用 sigmoid 函数而非阶跃函数,因为阶跃函数几乎处处导数为零。
计算机算导数更喜欢用数值微分,即 \(\dfrac{f(x+h)-f(x)}h\)(称为前向微分)或更常见的 \(\dfrac{f(x+h)-f(x-h)}{2h}\)(称作中心微分)
梯度法使用梯度,沿着负梯度方向走,寻找损失函数最小化。
走多远?往往有一个参数,是 \(10^{-2}\) 或 \(10^{-3}\),然后乘以负梯度并移动。
神经网络的梯度是把 \(W\) 当成向量处理。
流程:
- 从完整数据集中选出一小部分作为训练数据,剩下的作为测试数据。
- 用正态分布初始化 \(W\),用 \(\b0\) 初始化 \(\b b\)。
- 跑。
- 适当调参避免过拟合。
V.误差反向传播法
考虑用一个内向树描述某种计算流程:内向树上每个点接受若干点的输入,并通过某种运算变成输出供给一个点。
现在我们想知道内向树上每个输入对最终输出的贡献。因为是内向树,则终点只有一个方向可以溯源至我们好奇的变量,于是计算终点在其它东西都固定时的偏导,然后回退一步,再计算一步偏导,再回退……将所有的单步偏导求积,即得快速的总梯度计算方法。
单步偏导,如果将总流程描述为若干步加法与乘法的组合(此时采用 sigmoid 函数或 ReLU 函数均可),则每一步都可以算得导数的解析解。
花了好几天一边摆一边对着 std 抄,捣鼓出了一份能在约 20s 内训练出成功率在 98% 附近的神经网络。
mnist.py
:
# 这份代码是直接从这本书上附的代码集中粘出来的,唯一的作用是下载 mnist 数据集并保存在 mnist.pkl 文件中。但是 mnist 网站好像下不下来数据,因此我选择手动下了一份数据集
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):
"""读入MNIST数据集
Parameters
----------
normalize : 将图像的像素值正规化为0.0~1.0
one_hot_label :
one_hot_label为True的情况下,标签作为one-hot数组返回
one-hot数组是指[0,0,1,0,0,0,0,0,0,0]这样的数组
flatten : 是否将图像展开为一维数组
Returns
-------
(训练图像, 训练标签), (测试图像, 测试标签)
"""
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()
Functions.py
:
import numpy as np
def Identity_Function(x):
return x
def Softmax_Function(x):
if x.ndim==2: # case when x is batched
x=np.exp(x-np.max(x,axis=1).reshape(-1,1))
return x/np.sum(x,axis=1).reshape(-1,1)
x=np.exp(x-np.max(x))
return x/np.sum(x)
def Sigmoid(x):
return 1.0/(1.0+np.exp(x))
def Sigmoid_Grad(x):
return (1.0-Sigmoid(x))*Sigmoid(x)
def ReLU(x):
return np.max(x,0)
def ReLU_Grad(x):
grad=np.zeros(x)
grad[x>=0]=1
return grad
def Mean_Squared_Error(y,t):
return 0.5*np.sum((y-t)**2)
def Cross_Entropy_Error(y,t):
if y.ndim==1:
y=y.reshape(1,-1)
t=t.reshape(1,-1)
batchsize=len(y)
# print("Fuctions:",y.shape,t.shape)
# print(y[0],t[0],np.log(y[np.arange(batchsize),t]+1e-7)[0])
return -np.sum(np.log(y[np.arange(batchsize),t]+1e-7))/batchsize
Layers.py
:
import numpy as np
from Functions import *
class ReLULayer:
def __init__(self):
self.neg=None
def forward(self,ip):
self.neg=ip<=0
op=ip.copy()
op[self.neg]=0
return op
def backward(self,ip):
op=ip.copy()
op[self.neg]=0
return op
class SigmoidLayer:
def __init__(self):
self.sig=None
def forward(self,ip):
op=Sigmoid(ip)
self.sig=op.copy()
return op
def backward(self,ip):
op=ip*(1.0-self.sig)*self.sig
return op
class AffineLayer:
def __init__(self,W,b):
self.W=W
self.b=b
self.dW=None
self.db=None
self.x=None
def forward(self,ip):
self.x=ip.copy()
# print(self.x.shape,self.W.shape,self.b.shape)
return np.dot(ip,self.W)+self.b
def backward(self,ip):
tag=False
if ip.ndim==1:
tag=True
ip=ip.reshape(1,-1)
self.dW=np.dot(self.x.T,ip)
self.db=np.sum(ip,axis=0)
op=np.dot(ip,self.W.T)
if tag:
op=op.flatten()
return op
class SoftmaxLayer:
def __init__(self):
self.y=None
self.t=None
def forward(self,ip,tp):
self.y=Softmax_Function(ip)
self.t=tp
op=Cross_Entropy_Error(self.y,self.t)
return op
def backward(self,ip=1):
batchsize=len(self.t)
op=self.y.copy()
op[np.arange(batchsize),self.t]-=1
op/=batchsize
return op
NeuroNetwork.py
:
import numpy as np
from Layers import *
class NeuroNetwork:
def __init__(self,layertypes,layersizes,weight_init_std=0.01,givenW=None,givenb=None):
self.n=len(layersizes)
self.W=[]
self.b=[]
self.layers=[]
for i in range(self.n-1):
if givenW is None and givenb is None:
self.W.append(np.random.randn(layersizes[i],layersizes[i+1])*weight_init_std)
self.b.append(np.zeros(layersizes[i+1]))
else:
self.W.append(givenW[i])
self.b.append(givenb[i])
self.layers.append(AffineLayer(self.W[i],self.b[i]))
if i+1!=self.n-1:
self.layers.append(layertypes[i]())
self.lastlayer=layertypes[-1]()
def predict(self,x):
for i in self.layers:
x=i.forward(x)
return x
def InterpretPrediction(self,x,num=3):
y=self.predict(x)
y=Softmax_Function(y)
arr=[]
for i in range(len(y)):
arr.append((y[i],i))
arr=reversed(sorted(arr))
print("Prediction|",end='')
for i in range(num):
print(int(i[0]*100),"%%being result ",i[1],sep='',end='')
print()
def calcloss(self,x,t):
y=self.predict(x)
return self.lastlayer.forward(y,t)
def accuracy(self,x,t): #in this case x must be batched
y=self.predict(x)
y=np.argmax(y,axis=1)
return 1.0*np.sum(y==t)/len(x)
def gradient(self,x,t):
self.calcloss(x,t)
ip=1
ip=self.lastlayer.backward(ip)
for i in reversed(self.layers):
ip=i.backward(ip)
gradW=[]
gradb=[]
for i in range(0,self.n-1):
gradW.append(self.layers[i*2].dW)
gradb.append(self.layers[i*2].db)
return gradW,gradb
NeuroTrain.py
:
import numpy as np
from mnist import load_mnist
from NeuroNetwork import *
nwk=NeuroNetwork(layertypes=[ReLULayer,SoftmaxLayer],layersizes=[784,50,10])
(x_train,t_train),(x_test,t_test) = load_mnist(normalize=True, one_hot_label=False)
itertime=10000
batchsize=100
trainsize=len(x_train)
learningrate=0.1
reviewsize=max(1,int(trainsize/batchsize))
batchsucceedrate=[]
trainsucceedrate=[]
batchx=[]
trainx=[]
print(trainsize,batchsize,reviewsize)
for i in range(itertime):
ind=np.random.choice(trainsize,batchsize)
x_batch=x_train[ind]
t_batch=t_train[ind]
batchsucceedrate.append(nwk.accuracy(x_batch,t_batch))
batchx.append(i)
gradW,gradb=nwk.gradient(x_batch,t_batch)
for j in range(0,nwk.n-1):
nwk.W[j]-=learningrate*gradW[j]
nwk.b[j]-=learningrate*gradb[j]
# print(i,i%reviewsize)
if i%reviewsize==0:
trainsucceedrate.append(nwk.accuracy(x_train,t_train))
print(trainsucceedrate[-1])
trainx.append(i)
for i in nwk.W:
print(i.shape)
import pickle
with open("neuroW.pkl","wb") as f:
pickle.dump(nwk.W,f)
with open("neurob.pkl","wb") as g:
pickle.dump(nwk.b,g)
import matplotlib.pyplot as plt
plt.plot(batchx,batchsucceedrate,label="batchsuccessrate")
plt.plot(trainx,trainsucceedrate,label="trainsuccessrate")
plt.legend()
plt.show()
NeuroTest.py
:
import pickle
import numpy as np
from mnist import load_mnist
from NeuroNetwork import *
with open("neuroW.pkl","rb") as f:
W=pickle.load(f)
with open("neurob.pkl","rb") as g:
b=pickle.load(g)
nwk=NeuroNetwork(layertypes=[ReLULayer,SoftmaxLayer],layersizes=[784,50,10],givenW=W,givenb=b)
(x_train,t_train),(x_test,t_test) = load_mnist(normalize=True, one_hot_label=False)
testsize=len(x_test)
testbatch=100
ind=np.random.choice(testsize,testbatch)
x_batch=x_test[ind]
t_batch=t_test[ind]
print(nwk.accuracy(x_batch,t_batch))
标签:慎独,儒门,self,dataset,file,np,label,萝莉,def
From: https://www.cnblogs.com/Troverld/p/18288693