神经网络总体上可分为前馈神经网络和循环神经网络,其依据为网络中是否有环路。前馈神经网络包括多层感知机、自动编码机、受限玻尔兹曼机、BP神经网络、卷积神经网络等。其中BP神经网络虽然称为反向传播网络,其反向指的是误差反向传播,由于不存在环路,其也是前馈神经网络的一种。
一、深度学习中常用的损失函数
损失函数(loss function)是用来估量模型的预测值f(x)与真实值Y的不一致程度,它是一个非负实值函数,通常使用L(Y, f(x))来表示,损失函数越小,模型的鲁棒性就越好。监督学习分为回归和分类两大类,回归问题中常用的损失函数为均方误差,分类问题中常用的损失函数为交叉墒。深度学习的过程也就是使得模型损失函数不断变小,当损失函数达到做小值时,模型的参数最优,模型的输出与期望值更接近。神经网络的训练实际上就是对参数进行优化,让损失函数值最小。
1、均方误差。将目标值和预测值间差值的平方和最小化。
2、交叉墒。交叉墒越小,模型越精确。
交叉墒一般与softmax函数结合使用,神经网络输出yi经过softmax后为:
即输出为被分为每一类的概率,取概率最大值所对应的类为最终分类。然后再计算交叉墒,公式如下:
二、感知机(MP)
感知机只有输入层和输出层,只有输出层具有计算功能,学习能力有限,是一个二分类的线性分类模型,只能用于解决线性任务,连简单的异或问题都不能解决。如果将计算层增加为两层,计算量又过大,由于没有有效的学习算法而受到限制。为了解决非线性分类问题引入了多层感知机(MLP),多层感知机由输入层、隐藏层、输出层组成,能很好地解决异或问题和非线性可分问题,隐藏层对原始数据进行空间变换,使得原始坐标从线性不可分转换为线性可分,输入层和输出层的节点要分别与特征维度、目标维度相匹配,中间层的结点由设计者决定,在神经网络中,除了输出层每一层都有一个偏置,偏置节点没有输入,只有存储功能,偏置节点是为了确保部分节点无论如何都能够被激活。BP神经网络就是一种典型的多层感知机。
三、BP神经网络
BP算法(即反向传播算法)是在有导师指导下,适合于多层神经元网络的一种学习算法,它建立在梯度下降法的基础上。BP网络的输入输出关系实质上是一种映射关系:一个n输入m输出的BP神经网络所完成的功能是从n维欧氏空间向m维欧氏空间中一有限域的连续映射,这一映射具有高度非线性。它的信息处理能力来源于简单非线性函数的多次复合,因此具有很强的函数复现能力。其缺点为收敛速度慢,容易陷入局部最小。
BP算法包括信号的前向传播和误差的反向传播两个过程。即计算误差输出时按从输入到输出的方向进行,而调整权值和阈值则从输出到输入的方向进行,使实际输出和期望输出间的误差均方值(即损失函数,损失函数也可用其它方式表示,比如交叉墒)最小。
BP神经网络激活函数一般采用sigmoid。
BP神经网络隐藏层神经元个数由设计者决定,有经验公式K=1+[M*(N+2)]^0.5,MN分别为输入层、输出层节点数目。
实现过程参考:https://blog.csdn.net/zhaomengszu/article/details/77834845
https://blog.csdn.net/weixin_42555080/article/details/94293064
Matlab实现代码举例:
%******************************%
%======原始数据输入========
p=[2845 2833 4488;2833 4488 4554;4488 4554 2928;4554 2928 3497;2928 3497 2261;...
3497 2261 6921;2261 6921 1391;6921 1391 3580;1391 3580 4451;3580 4451 2636;...
4451 2636 3471;2636 3471 3854;3471 3854 3556;3854 3556 2659;3556 2659 4335;...
2659 4335 2882;4335 2882 4084;4335 2882 1999;2882 1999 2889;1999 2889 2175;...
2889 2175 2510;2175 2510 3409;2510 3409 3729;3409 3729 3489;3729 3489 3172;...
3489 3172 4568;3172 4568 4015;]';
%===========期望输出=======
t=[4554 2928 3497 2261 6921 1391 3580 4451 2636 3471 3854 3556 2659 ...
4335 2882 4084 1999 2889 2175 2510 3409 3729 3489 3172 4568 4015 ...
3666];
ptest=[2845 2833 4488;2833 4488 4554;4488 4554 2928;4554 2928 3497;2928 3497 2261;...
3497 2261 6921;2261 6921 1391;6921 1391 3580;1391 3580 4451;3580 4451 2636;...
4451 2636 3471;2636 3471 3854;3471 3854 3556;3854 3556 2659;3556 2659 4335;...
2659 4335 2882;4335 2882 4084;4335 2882 1999;2882 1999 2889;1999 2889 2175;...
2889 2175 2510;2175 2510 3409;2510 3409 3729;3409 3729 3489;3729 3489 3172;...
3489 3172 4568;3172 4568 4015;4568 4015 3666]';
[pn,minp,maxp,tn,mint,maxt]=premnmx(p,t); %将数据归一化
NodeNum1 =20; % 隐层第一层节点数
NodeNum2=40; % 隐层第二层节点数
TypeNum = 1; % 输出维数
TF1 = 'tansig';
TF2 = 'tansig';
TF3 = 'tansig';
net=newff(minmax(pn),[NodeNum1,NodeNum2,TypeNum],{TF1 TF2 TF3},'traingdx');
%网络创建traingdm
net.trainParam.show=50;
net.trainParam.epochs=50000; %训练次数设置
net.trainParam.goal=1e-5; %训练所要达到的精度
net.trainParam.lr=0.01; %学习速率
net=train(net,pn,tn);
p2n=tramnmx(ptest,minp,maxp);%测试数据的归一化
an=sim(net,p2n);
[a]=postmnmx(an,mint,maxt) %数据的反归一化 ,即最终想得到的预测结果
V=net.iw{1,1};%输入层权值
theta1=net.b{1}%输入层阈值
W=net.lw{2,1};%输出层权值
theta2=net.b{2};%输出层阈值
plot(1:length(t),t,'o',1:length(t)+1,a,'+');
title('o表示预测值--- *表示实际值')
grid on
m=length(a); %向量a的长度
t1=[t,a(m)];
error=t1-a; %误差向量
figure
plot(1:length(error),error,'-.')
title('误差变化图')
grid on
结果:
python代码举例:
import numpy as np
import scipy.special
class neuralNetwork:
def __init__(self, inputnodes, hiddennodes, outputnodes, learning_rate):
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
self.lr = learning_rate
self.wih = (np.random.rand(self.hnodes ,self.inodes)-0.5)
self.who = (np.random.rand(self.onodes ,self.hnodes)-0.5)
self.activation_function =lambda x: scipy.special.expit(x)
def train(self,inputs_list , targets_list):
inputs = np.array(inputs_list,ndmin=2).T
targets =np.array(targets_list,ndmin=2).T
hidden_inputs = np.dot(self.wih, inputs)
hidden_outputs =self.activation_function(hidden_inputs)
final_inputs = np.dot(self.who, hidden_outputs)
final_outputs =self.activation_function(final_inputs)
output_errors = targets - final_outputs
errors_hidden = np.dot(self.who.T , output_errors)
self.who +=self.lr * np.dot( output_errors * final_outputs * (1-final_outputs ) , np.transpose(hidden_outputs) )
self.wih +=self.lr * np.dot( errors_hidden * hidden_outputs * (1-hidden_outputs ) , np.transpose(inputs) )
def query(self ,inputs_list):
inputs = np.array(inputs_list ,ndmin=2).T
hidden_inputs = np.dot(self.wih, inputs)
hidden_outputs =self.activation_function(hidden_inputs)
hidden_outputs = final_inputs
final_inputs = np.dot(self.who, hidden_outputs)
final_outputs =self.activation_function(final_inputs)
return final_outputs
n = neuralNetwork(783,100,10,0.1)
train_data_file =open("C:/Users/Administrator/Desktop/data/kk.txt")
train_data_list = train_data_file.readlines()
train_data_file.close()
for i in range(200):
j = np.random.randint(len(train_data_list))
all_value = train_data_list[j].split(',')
inputs = (np.asfarray(all_value[1:])/255*0.99)+0.01
targets = np.zeros(10)+0.01
targets[int(all_value[0])]=0.99
n.train(inputs,targets)
test_data_file =open("C:/Users/Administrator/Desktop/data/tt.txt")
test_data_list = test_data_file.readlines()
test_data_file.close()
scored = []
for record in test_data_list:
test_value = record.split(',')
inputs = (np.asfarray(test_value[1:]) /255 *0.99) +0.01
outputs = n.query(inputs)
label = np.argmax(outputs)
if label ==int(test_value[0]):
scored.append(1)
else:
scored.append(0)
scored_array =np.asfarray(scored)
print('准确率:',scored_array.sum()/scored_array.size)
四、自动编码器(Auto Encoder)
自动编码器是神经网络的一种,自动编码器(AE)由编码器和解码器组成,编码器实现对输入的映射到隐藏层,解码器将隐藏层的表示解码为输出端的重构结果,假设输入为x,则编码器h=f(x),解码器s=g(h)=g(f(x)),其中f和g表示某种映射关系,通过训练希望x和s的差异尽可能小。自编码器属于无监督学习,输入和输出维数一样,隐藏层维数较小,相当于一个降维过程,和PCA很像,不同之处在于自编码器可以学习到非线性特征。自编码器的主义用途为降维、去噪和图像生成。
编码器有不同形式的变形,主要有以下几类:
1、欠完备自编码器:香草自编码器;多层自编码器;卷积自编码器(CAE)。
2、正则自编码器:稀疏自编码器;去噪自编码器(DAE);收缩自编码器(CAE)。
3、变分自编码器(VAE)。
参考资料:https://zhuanlan.zhihu.com/p/84533223
https://blog.csdn.net/weixin_41697507/article/details/88212472
https://blog.csdn.net/qq_27825451/article/details/84968890
五、受限玻尔兹曼机(RBM)
玻尔兹曼机是一种基于能量的神经网络模型,神经元结构包括显层和隐层,传统的玻尔兹曼机中各个神经元间相互连接,即全连接,神经元是布尔型的,只能取0、1,由于全连接计算复杂度很高,难以解决现实问题。受限玻尔兹曼机是一种可通过输入数据集学习概率分布的随机生成神经网络,随机”是指网络中的神经元是随机神经元,输出状态只有两种(未激活和激活),状态的具体取值根据概率统计法则来决定,受限玻尔兹曼机和玻尔兹曼机的区别在于,RBM层内无连接,只有层间有连接。RBM是一种双层神经网络,是一种用于降维、分类、回归、协同过滤、特征学习和主题建模的算法,RBM是一个生成模型,也是一个无监督模型。RBM常用对比散度(CD)进行训练。
RBN能量函数表示为:
定义RBM的状态为给定v,h的联合概率密度分布为:
其中Z为归一化因子:
RBM可见层到隐藏层、隐藏层到可见层的激活函数都是sigmoid函数。我们期望得到概率函数P的最大值,P越大代表预测概率分布和输入数据概率分布就越接近,将P用损失函数表示,即RBM的训练可理解为求损失函数的最小值,通过不断迭代对权重和偏置进行更新,直到损失函数最小。RBM一般采用对数损失函数:
由于采用梯度下降算法(即通过求损失函数对权值和偏置的导数来更新参数)对RBM模型进行优化计算复杂度非常大,一般采用CD算法。其参数更新如下:
参考资料:https://baijiahao.baidu.com/s?id=1599798281463567369&wfr=spider&for=pc
https://www.baidu.com/link?url=3BVJU-HhbXTKkRew8JcWtu_t9jnfIDveyKzX8g3Lg55hv2mvyFwr4apXGRh77kjKTFqokleOFl4jeDf-YgFs1FigBlR0nJeD1xe-H90_r_m&wd=&eqid=df1c233b0007089d000000065e65ed5e
https://blog.csdn.net/weixin_42398658/article/details/84279293
https://blog.csdn.net/itplus/article/details/19168937
六、深度置信网络(DBN)
DBN由若干个RBM堆叠而成,上一层的输出作为下一层的输入,由低到高逐层进行训练,然后再进行微调。由于RBM可通过CD快速训练,于是这个框架绕过直接从整体上对DBN高度复杂的训练,而是将DBN的训练简化为对多个RBM的训练,从而简化问题。而且通过这种方式训练后,可以再通过传统的全局学习算法(如BP算法)对网络进行微调,从而使模型收敛到局部最优点,通过这种方式可高效训练出一个深层网络出来。
DBN模型的训练步骤:第一步,分别单独无监督地训练每一层 RBM 网络,确保特征向量映射到不同特征空间时,都尽可能多地保留特征信息;第二步,在 DBN 的最后一层设置 BP 网络,接收 RBM 的输出特征向量作为它的输入特征向量,有监督地训练实体关系分类器。而且每一层 RBM 网络只能确保自身层内的权值对该层特征向量映射达到最优,并不是对整个 DBN 的特征向量映射达到最优,所以反向传播网络还将错误信息自顶向下传播至每一层 RBM,微调整个 DBN 网络。RBM 网络训练模型的过程可以看作对一个深层 BP 网络权值参数的初始化,使DBN 克服了 BP 网络因随机初始化权值参数而容易陷入局部最优和训练时间长的缺点.。上述训练模型中第一步在深度学习的术语叫做预训练,第二步叫做微调。最上面有监督学习的那一层,根据具体的应用领域可以换成任何分类器模型,而不一定是BP网络。
python实现代码:
#加载深度置信相关库
import urllib.request
response=urllib.request.urlopen('http://deeplearning.net/tutorial/code/utils.py')
content=response.read().decode('utf-8')
target=open('utils.py','w')
target.write(content)
target.close()
import math
import tensorflow as tf
import numpy as np
from PIL import Image
from utils import tile_raster_images
class RBM(object):
def __init__(self, input_size, output_size):
# Defining the hyperparameters
self._input_size = input_size # Size of input
self._output_size = output_size # Size of output
self.epochs = 5 # Amount of training iterations
self.learning_rate = 1.0 # The step used in gradient descent
self.batchsize = 100 # The size of how much data will be used for training per sub iteration
# Initializing weights and biases as matrices full of zeroes
self.w = np.zeros([input_size, output_size], np.float32) # Creates and initializes the weights with 0
self.hb = np.zeros([output_size], np.float32) # Creates and initializes the hidden biases with 0
self.vb = np.zeros([input_size], np.float32) # Creates and initializes the visible biases with 0
# Fits the result from the weighted visible layer plus the bias into a sigmoid curve
def prob_h_given_v(self, visible, w, hb):
# Sigmoid
return tf.nn.sigmoid(tf.matmul(visible, w) + hb)
# Fits the result from the weighted hidden layer plus the bias into a sigmoid curve
def prob_v_given_h(self, hidden, w, vb):
return tf.nn.sigmoid(tf.matmul(hidden, tf.transpose(w)) + vb)
# Generate the sample probability
def sample_prob(self, probs):
return tf.nn.relu(tf.sign(probs - tf.random_uniform(tf.shape(probs))))
# Training method for the model
def train(self, X):
# Create the placeholders for our parameters
_w = tf.placeholder("float", [self._input_size, self._output_size])
_hb = tf.placeholder("float", [self._output_size])
_vb = tf.placeholder("float", [self._input_size])
prv_w = np.zeros([self._input_size, self._output_size],
np.float32) # Creates and initializes the weights with 0
prv_hb = np.zeros([self._output_size], np.float32) # Creates and initializes the hidden biases with 0
prv_vb = np.zeros([self._input_size], np.float32) # Creates and initializes the visible biases with 0
cur_w = np.zeros([self._input_size, self._output_size], np.float32)
cur_hb = np.zeros([self._output_size], np.float32)
cur_vb = np.zeros([self._input_size], np.float32)
v0 = tf.placeholder("float", [None, self._input_size])
# Initialize with sample probabilities
h0 = self.sample_prob(self.prob_h_given_v(v0, _w, _hb))
v1 = self.sample_prob(self.prob_v_given_h(h0, _w, _vb))
h1 = self.prob_h_given_v(v1, _w, _hb)
# Create the Gradients
positive_grad = tf.matmul(tf.transpose(v0), h0)
negative_grad = tf.matmul(tf.transpose(v1), h1)
# Update learning rates for the layers
update_w = _w + self.learning_rate * (positive_grad - negative_grad) / tf.to_float(tf.shape(v0)[0])
update_vb = _vb + self.learning_rate * tf.reduce_mean(v0 - v1, 0)
update_hb = _hb + self.learning_rate * tf.reduce_mean(h0 - h1, 0)
# Find the error rate
err = tf.reduce_mean(tf.square(v0 - v1))
# Training loop
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
# For each epoch
for epoch in range(self.epochs):
# For each step/batch
for start, end in zip(range(0, len(X), self.batchsize), range(self.batchsize, len(X), self.batchsize)):
batch = X[start:end]
# Update the rates
cur_w = sess.run(update_w, feed_dict={v0: batch, _w: prv_w, _hb: prv_hb, _vb: prv_vb})
cur_hb = sess.run(update_hb, feed_dict={v0: batch, _w: prv_w, _hb: prv_hb, _vb: prv_vb})
cur_vb = sess.run(update_vb, feed_dict={v0: batch, _w: prv_w, _hb: prv_hb, _vb: prv_vb})
prv_w = cur_w
prv_hb = cur_hb
prv_vb = cur_vb
error = sess.run(err, feed_dict={v0: X, _w: cur_w, _vb: cur_vb, _hb: cur_hb})
print('Epoch: %d' % epoch, 'reconstruction error: %f' % error)
self.w = prv_w
self.hb = prv_hb
self.vb = prv_vb
# Create expected output for our DBN
def rbm_outpt(self, X):
input_X = tf.constant(X)
_w = tf.constant(self.w)
_hb = tf.constant(self.hb)
out = tf.nn.sigmoid(tf.matmul(input_X, _w) + _hb)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
return sess.run(out)
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images,mnist.test.labels
RBM_hidden_sizes = [500, 200 , 50 ] #create 4 layers of RBM with size 785-500-200-50
#Since we are training, set input as training data
inpX = trX
#Create list to hold our RBMs
rbm_list = []
#Size of inputs is the number of inputs in the training set
input_size = inpX.shape[1]
#For each RBM we want to generate
for i, size in enumerate(RBM_hidden_sizes):
print('RBM: ',i,' ',input_size,'->', size)
rbm_list.append(RBM(input_size, size))
input_size = size
#For each RBM in our list
for rbm in rbm_list:
print('New RBM:')
#Train a new one
rbm.train(inpX)
#Return the output layer
inpX = rbm.rbm_outpt(inpX)
import numpy as np
import math
import tensorflow as tf
class NN(object):
def __init__(self, sizes, X, Y):
# Initialize hyperparameters
self._sizes = sizes
self._X = X
self._Y = Y
self.w_list = []
self.b_list = []
self._learning_rate = 1.0
self._momentum = 0.0
self._epoches = 10
self._batchsize = 100
input_size = X.shape[1]
# initialization loop
for size in self._sizes + [Y.shape[1]]:
# Define upper limit for the uniform distribution range
max_range = 4 * math.sqrt(6. / (input_size + size))
# Initialize weights through a random uniform distribution
self.w_list.append(
np.random.uniform(-max_range, max_range, [input_size, size]).astype(np.float32))
# Initialize bias as zeroes
self.b_list.append(np.zeros([size], np.float32))
input_size = size
# load data from rbm
def load_from_rbms(self, dbn_sizes, rbm_list):
# Check if expected sizes are correct
assert len(dbn_sizes) == len(self._sizes)
for i in range(len(self._sizes)):
# Check if for each RBN the expected sizes are correct
assert dbn_sizes[i] == self._sizes[i]
# If everything is correct, bring over the weights and biases
for i in range(len(self._sizes)):
self.w_list[i] = rbm_list[i].w
self.b_list[i] = rbm_list[i].hb
# Training method
def train(self):
# Create placeholders for input, weights, biases, output
_a = [None] * (len(self._sizes) + 2)
_w = [None] * (len(self._sizes) + 1)
_b = [None] * (len(self._sizes) + 1)
_a[0] = tf.placeholder("float", [None, self._X.shape[1]])
y = tf.placeholder("float", [None, self._Y.shape[1]])
# Define variables and activation functoin
for i in range(len(self._sizes) + 1):
_w[i] = tf.Variable(self.w_list[i])
_b[i] = tf.Variable(self.b_list[i])
for i in range(1, len(self._sizes) + 2):
_a[i] = tf.nn.sigmoid(tf.matmul(_a[i - 1], _w[i - 1]) + _b[i - 1])
# Define the cost function
cost = tf.reduce_mean(tf.square(_a[-1] - y))
# Define the training operation (Momentum Optimizer minimizing the Cost function)
train_op = tf.train.MomentumOptimizer(
self._learning_rate, self._momentum).minimize(cost)
# Prediction operation
predict_op = tf.argmax(_a[-1], 1)
# Training Loop
with tf.Session() as sess:
# Initialize Variables
sess.run(tf.global_variables_initializer())
# For each epoch
for i in range(self._epoches):
# For each step
for start, end in zip(
range(0, len(self._X), self._batchsize), range(self._batchsize, len(self._X), self._batchsize)):
# Run the training operation on the input data
sess.run(train_op, feed_dict={
_a[0]: self._X[start:end], y: self._Y[start:end]})
for j in range(len(self._sizes) + 1):
# Retrieve weights and biases
self.w_list[j] = sess.run(_w[j])
self.b_list[j] = sess.run(_b[j])
print("Accuracy rating for epoch " + str(i) + ": " + str(np.mean(np.argmax(self._Y, axis=1) == sess.run(predict_op, feed_dict={_a[0]: self._X, y: self._Y}))))
nNet = NN(RBM_hidden_sizes, trX, trY)
nNet.load_from_rbms(RBM_hidden_sizes,rbm_list)
nNet.train()
参考资料:https://www.baidu.com/link?url=k01MHdP-9nN-tR2aFp-VFXJ-4bAWRCCX5jWzcEc8iI4eUtxeNrzPhV-tBdfh8tZx2A-GdhG7wVLvnknxMOaRkK&wd=&eqid=b87b19bc0006cf74000000035e675439
https://www.cnblogs.com/pythonlearing/p/9979161.html
六、卷积神经网络(CNN)
卷积神经网络由输入层、隐藏层和输出层组成,隐藏层又包括卷积层、激励层、池化层、全连层。卷积神经网络采用局部连接+权值共享,降低神经元间权重个数的同时不会使其学习能力降低。代表性CNN模型有:LeNet、AlexNet、VGGNet、GoogleNet、ResNet、DenseNet等。
输入层:为输入的数据做预处理,如归一化等;
卷积层:每一层卷积层都是由若干个卷积核组成,每个卷积核的权重值都是通过反向传播算法最佳化得到的。卷积运算的目的是要对输入的图像数据做特征提取,每一个卷积核提取一种特征,所以卷积核也被称为特征提取器(filter)。第一层卷积层可能只是提取一些低级的特征,后面层的卷积层能够从前层的低级特征中迭代提取出更复杂的特征。因此控制卷积层的层数也显得尤为重要。卷积核的大小、步长和填充方式决定了卷积计算后输出特征图的大小。
激励层:激励层把卷积层的计算结果做非线性的映射,增加了它的非线性分割能力。且常采用的激励函数是ReLU(The Rectified Linear Unit,修正线性单元),它的特点是收敛快,求梯度简单。常用激励函数:sigmoid、tanh、ReLu(速度快)、Leaky ReLu、ELU、Maxout。
池化层:池化层往往夹杂在连续的卷积层之间,用于压缩数据和参数的量,降低网络的复杂度,减少过拟合情况的发生。常用两种下采样包括最大池化和平均池化。一般卷积层间引入最大池化,卷积网络最后一层用平均池化。
全连层:在输出层的前面会有全连接层,把所有局部特征结合变成全局特征,把卷积输出的二维特征图转化成一个一维的向量,并将输出的值送给分类器。在全连接层的特征数会特别多,计算量也相当的大。全连层起到分类的作用。
输出层:输出层将全连接层的结果进行分类输出。
参考资料:https://my.oschina.net/u/876354/blog/1620906
LeNet:https://my.oschina.net/u/876354/blog/1632862#comments
AlexNet:https://my.oschina.net/u/876354/blog/1633143
VGGNet:https://my.oschina.net/u/876354/blog/1634322
GoogLeNet:https://my.oschina.net/u/876354/blog/1637819
常用激活函数:https://my.oschina.net/u/876354/blog/1624376
七、RBF神经网络
RBF是一种三层神经网络,由输入层、隐含层、输出层组成,其中,隐含层的作用是把向量从低维度的p映射到高维度的h,这样低维度线性不可分的情况到高维度就可以变得线性可分了,主要就是核函数的思想。从输入空间到隐层空间的变换是非线性的,从隐层到输出层空间的变换是线性的,加快了学习速度,并可以避免局部最小值问题。径向基神经网络的激活函数为径向基函数,常用的为高斯径向基函数。RBF神经网络具有局部映射特性。
RBF网络的基本思想是:用RBF作为隐单元的“基”构成隐含层空间,这样就可以将输入向量直接映射到隐空间。当RBF的中心点确定以后,这种映射关系也就确定了。而隐含层空间到输出空间的映射是线性的,即网络的输出是隐单元输出的线性加权和。此处的权即为网络可调参数。
方法一:自组织学习
学习过程分为无监督和有监督两个部分,无监督过程求解隐含层基函数的中心与方差,有监督过程求解隐含层到输出层的权值。
随机选取h个训练样本作为中心,做k-means聚类直到聚类中心不再变化,得到最终的基函数中心。
方法二:有监督学习
采用监督学习方法对三种参数进行训练。随机初始化基函数的中心、方差、隐含层到输出层的权值,通过梯度下降对参数进行更新。代价函数为网络输出与期望输出的均方差。
matlab代码:
%拟合函数
clc;
clear;
x=rand(2,400);
x=(x-0.5)*1.5*2;
x1=x(1,:);
x2=x(2,:);
F=20+x1.^2-10*cos(2*pi*x1)+x2.^2-10*cos(2*pi*x2);
net=newrb(x,F);
[i,j]=meshgrid(-1.5:0.1:1.5);
t1=i(:)';
t2=j(:)';
tx=[t1;t2];
ty=sim(net,tx);
[x1,x2]=meshgrid(-1.5:0.1:1.5);
F=20+x1.^2-10*cos(2*pi*x1)+x2.^2-10*cos(2*pi*x2);
subplot(1,3,1)
mesh(x1,x2,F);
zlim([0,60]);
title('函数图像');
subplot(1,3,2)
v=reshape(ty,size(i));
mesh(i,j,v);
zlim([0,60]);
title('拟合结果');
subplot(1,3,3)
mesh(x1,x2,F-v);
zlim([0,60]);
title('误差图像');
set(gcf,'position',[300,250,900,400]);
python:参考https://blog.csdn.net/m0_37602827/article/details/103099972?depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-3&utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-3
#自组织学习选取RBF中心
import tensorflow as tf
import numpy as np
from sklearn.cluster import KMeans
class RBF:
def __init__(self,learning_rate=0.002,step_num=10001,hidden_size=10):
self.learning_rate=learning_rate
self.step_num=step_num
self.hidden_size=hidden_size
def getC_S(self,x,class_num):
estimator=KMeans(n_clusters=class_num,max_iter=10000)
estimator.fit(x)
c=estimator.cluster_centers_
n=len(c)
s=0;
for i in range(n):
j=i+1
while j0 and epoch%500==0:
mse=sess.run(loss,feed_dict={x_:x,y_:y})
print(epoch,mse)
self.w,self.b=sess.run([w,b],feed_dict={x_:x,y_:y})
def kernel2(self,x,c,s):
x1=np.tile(x,[1,self.hidden_size])
x2=np.reshape(x1,[-1,self.hidden_size,self.feature])
dist=np.sum((x2-c)**2,2)
return np.exp(-dist/(2*s**2))
def predict(self,x):
z=self.kernel2(x,self.c,self.s)
pre=np.matmul(z,self.w)+self.b
return pre
from sklearn.datasets import load_iris
iris=load_iris()
x=iris.data
y=iris.target
y=y.reshape(-1,1)
model=RBF()
model.train(x,y)
pre=model.predict(x)
for i,v in enumerate(pre):
if v<1:
pre[i]=0
elif v>=1 and v<1.5:
pre[i]=1
else:
pre[i]=2
acc=np.sum(pre==y)/len(pre)
print(acc)
#有监督学习选取中心
import numpy as np
import tensorflow as tf
class RBF:
def __init__(self,learning_rate=0.002,step_num=10001,hidden_size=10):
self.learning_rate=learning_rate
self.step_num=step_num
self.hidden_size=hidden_size
def kernel(self,x,c,s):
x1=tf.tile(x,[1,self.hidden_size])
x2=tf.reshape(x1,[-1,self.hidden_size,self.feature])
dist=tf.reduce_sum((x2-c)**2,2)
return tf.exp(-dist/(2*s**2))
def train(self,x,y):
self.feature=np.shape(x)[1]
x_=tf.placeholder(tf.float32,[None,self.feature])
y_=tf.placeholder(tf.float32,[None,1])
c=tf.Variable(tf.random_normal([self.hidden_size,self.feature]))
s=tf.Variable(tf.random_normal([self.hidden_size]))
z=self.kernel(x_,c,s)
w=tf.Variable(tf.random_normal([self.hidden_size,1]))
b=tf.Variable(tf.zeros([1]))
yf=tf.matmul(z,w)+b
loss=tf.reduce_mean(tf.square(y_-yf))
optimizer=tf.train.AdamOptimizer(self.learning_rate)
train=optimizer.minimize(loss)
init=tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for epoch in range(self.step_num):
sess.run(train,feed_dict={x_:x,y_:y})
if epoch>0 and epoch%500==0:
mse=sess.run(loss,feed_dict={x_:x,y_:y})
print(epoch,mse)
self.c,self.s,self.w,self.b=sess.run([c,s,w,b],feed_dict={x_:x,y_:y})
def kernel2(self,x,c,s):
x1=np.tile(x,[1,self.hidden_size])
x2=np.reshape(x1,[-1,self.hidden_size,self.feature])
dist=np.sum((x2-c)**2,2)
return np.exp(-dist/(2*s**2))
def predict(self,x):
z=self.kernel2(x,self.c,self.s)
pre=np.matmul(z,self.w)+self.b
return pre
#保存模型
from sklearn.externals import joblib
joblib.dump(model,'rbf_train.m')
clf=joblib.load('rbf_train.m')
clf.predict(x)
八、循环神经网络(RNN)
循环神经网络是一种用于处理序列数据的神经网络,网络会对前面的信息进行记忆并用于当前的输出计算中,隐藏层之间的节点是有连接的,隐藏层的输入不仅包括输入层的输入还包括上一时刻隐藏层的输出。RNN主要用于NLP、语音识别、及其
其中输入序列,隐藏层矢量,输出序列,输入到隐藏层的连接由权重U初始化,隐藏到隐藏的循环连接由权重矩阵W参数化,隐藏到输出的连接由权重矩阵U初始化,假设激活函数使用双曲正切函数,输出用softmax进行概率标准化,则更新方程如下:
import numpy as np
X=[1,2]
state=[0.0,0.0]
w_cell_state=np.asarray([[0.1,0.2],[0.3,0.4]])
w_cell_input=np.asarray([0.5,0.6])
b_cell=np.asarray([0.1,-0.1])
w_output=np.asarray([[1.0],[2.0]])
b_output=0.1
for i in range(len(X)):
before_activation=np.dot(state,w_cell_state)+X[i]*w_cell_input+b_cell
state=np.tanh(before_activation)
final_output=np.dot(state,w_output)+b_output
print("before_activation:",before_activation)
print("state:",state)
print("output:",final_output)
参考:https://my.oschina.net/u/876354/blog/1621839
https://www.jb51.net/article/135642.htm
https://zhuanlan.zhihu.com/p/38184788
参数更新方法BPTT推导参考:
https://blog.csdn.net/Torero_lch/article/details/82631946?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-7&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-7
RNN的训练方法BPTT
http://www.mamicode.com/info-detail-1547845.html
九、LSTM(长短期记忆网络)
随着间隔的不断增大,RNN会出现梯度消失或梯度爆炸现象,这就是RNN的长期依赖问题。LSTM是一种特殊的RNN类型,可以学习长期依赖信息。LSTM的结构一般包括遗忘门、输入门和输出门三种结构以及细胞状态,其结构如下:
遗忘门:以一定的概率控制是否遗忘上一层的隐藏细胞状态,代表遗忘上一层隐藏细胞状态的概率。
输入门:输入门负责处理当前序列位置的输入,从图中可以看出它由两部分组成,第一部分使用了sigmoid激活函数,第二部分使用了tanh激活函数。
细胞状态:更新细胞状态,由更新为。细胞状态更新是通过遗忘门和输入门共同完成的。
,其中为哈达玛积
输出门:
则当前序列索引预测输出为:
参考:https://my.oschina.net/u/876354/blog/1621839
十、GRU网络(门控循环单元)
GRU是LSTM的一个变体,它保持了LSTM的效果(即能解决RNN中长依赖问题),但结构更加简单,GRU模型中只有两个门:更新门和重置门。其网络结构如下:为重置门,为更新门。重置门控制前一状态有多少信息被写入到当前的候选集 上,重置门越小,前一状态的信息被写入的就越少;更新门用于控制前一时刻的状态信息被带入到当前状态中的程度,更新门的值越大说明前一时刻的状态信息带入越多。
网络的前向传播:
其中[ ]表示两个向量相连,*表示矩阵的乘积。
GRU 参数更少因此更容易收敛,但是数据集很大的情况下,LSTM表达性能更好。
参考:https://blog.csdn.net/fu6543210/article/details/90741622
十一、神经网络中常见的防止过拟合(overfitting)方法
在训练神经网络时,我们常常有训练集、测试集和验证集三种数据集。有时候训练出来的神经网络在训练集上表现很好(准确率很高),但在测试集上的准确率比较差,因为在训练模型时对一些参数的设置要求过高,而新的样本数据无法达到如此高的要求,导致模型在测试集上的效果很差。这种现象被称为过拟合,也就是过度学习了训练集上的特征,导致泛化能力较差。常见的防止过拟合有以下几种:
1、早期停止(early stoping)
对模型进行训练的过程即是对模型的参数进行学习更新的过程,这个参数学习的过程往往会用到一些迭代方法,如梯度下降学习算法。早期停止便是一种迭代次数截断的方法来防止过拟合的方法,即在模型对训练数据集迭代收敛之前停止迭代来防止过拟合。
早期停止方法的具体做法是,在每一个Epoch结束时(一个Epoch集为对所有的训练数据的一轮遍历)计算validation data的accuracy,当accuracy不再提高时,就停止训练。因为accurary都不再提高了,在继续训练也是无益的,只会提高训练的时间。
那么该做法的一个重点便是怎样才认为validation accurary不再提高了呢?并不是说validation accuracy一降下来便认为不再提高了,因为可能经过这个Epoch后,accuracy降低了,但是随后的Epoch又让accuracy又上去了,所以不能根据一两次的连续降低就判断不再提高。
一般的做法是,在训练的过程中,记录到目前为止最好的validation accuracy,当连续10次Epoch(或者更多次)没达到最佳accuracy时,则可以认为accuracy不再提高了。此时便可以停止迭代了(早期停止)。这种策略也称为“No-improvement-in-n”,n即Epoch的次数,可以根据实际情况取,如10、20、30……
2、数据增强(data augmentation)
在数据挖掘领域中,有时候往往拥有更多的数据胜过一个好的模型。因为我们在使用训练数据训练模型,通过这个模型对将来的数据进行拟合,而在这之间又一个假设便是,训练数据与将来的数据是独立同分布的。即使用当前的训练数据来对将来的数据进行估计与模拟,而更多的数据往往估计与模拟更准确。而实际中我们拥有的数据有限,可通过人为地创造一些数据,比如对图像进行翻转、裁剪等产生新的数据,数据集扩增可采用以下方法:
a、从数据源头采集更多数据;
b、复制原有数据并加上随机噪声
c、重采样
d、根据当前数据集估计数据分布参数,使用该分布产生更多数据等
3、正则化
为了避免过拟合问题,一个常用的方法就是正则化,正则化也称权重衰减(weight decay)。一般而言模型的复杂度只由权重决定,所以一般只对w进行规范化,不对b进行规范化。神经网络中常用的正则化方法有L1正则化和L2正则化两种,计算公式为:
正则化的思想为,在损失函数后添加L1或L2正则项,例如L2规范化后的交叉墒为:
无论是哪一种正则化方式,基本的思想都是希望通过限制权重的大小,使得模型不能任意拟合训练数据中的随机噪声,正则化的效果为让网络倾向于学习小一点的权重。这两种正则化都惩罚大的权重,但L1正则化会让参数变得稀疏,而L2正则化不会。所谓参数变得更加稀疏是指会有更多的参数变成0,这样可以达到类似特征选取的功能。
4、Dropout
Dropout是一种相当激进的技术,和之前的正则化技术不同,它不改变网络本身,而是会随机地删除网络中的一般隐藏的神经元,并且让输入层和输出层的神经元保持不变。
我们每次使用梯度下降时,只使用随机的一般神经元进行更新权值和偏置,因此我们的神经网络时再一半隐藏神经元被丢弃的情况下学习的。而当我们运行整个网络时,是两倍的神经元会被激活。因此,我们将从隐藏神经元的权重减半。
这种技术的直观理解为:当我们Dropout不同的神经元集合时,有点像我们在训练不同的神经网络。而不同的神经网络会以不同的方式过拟合,所以Dropout就类似于不同的神经网络以投票的方式降低过拟合。
对于不同的技术,其实都可以理解为:我们在训练网络的健壮性。无论是L1、L2规范化倾向于学习小的权重,还是Dropout强制学习在神经元子集中更加健壮的特征,都是让网络对丢失个体连接的场景更加健壮。
十二、深度学习中常用的激活函数
激活函数可以引入非线性因素,加入非线性激励函数后,神经网络就有可能学习到平滑的曲线来分割平面,而不是用复杂的线性组合逼近平滑曲线来分割平面,使神经网络的表示能力更强了,能够更好的拟合目标函数。激活函数分为“饱和激活函数”和“非饱和激活函数”,sigmoid和tanh是常见的“饱和激活函数”,relu及其变体为“非饱和激活函数”,“非饱和激活函数”能解决梯度消失问题,增加收敛速度。
1、sigmoid函数:函数经过sigmoid后输出值的范围为(0~1)。输出不以0为中心,当输入均为正值时,对w求局部梯度都为正,导致在反向传播过程中w要么都往正方向更新,要么都往负方向更新,导致收敛速度缓慢,同时指数的计算速度很慢。
2、tanh函数:tanh函数对sigmoid的输出值进行了一个扩展,输出值的范围为(-1,1),但仍然没有解决梯度弥散的问题。tanh(x)=2sigmoid(2x)-1。
3、relu函数:输入小于0的部分输出均为0,大于等于0的部分输出等于输入值,收敛速度较快,解决了正区域梯度弥散的问题,负区域的梯度弥散问题未解决。
4、noisy relus:在max中加了一个高斯分布的噪声。
5、leaky relus:在relu函数基础上保留了一部分负值,让x为负时乘以a(a取0-1),对负值得信号不是一味地拒绝,而是缩小。
6、elus:在x小于0时做了更复杂的变换。
7、softmax函数:softmax的输出结果只有两种(0、1,或-1、1,或0、x)值,如[0 0 1 0 0 ];通常用于分类,当输入属于某一类的概率大于其它类的概率,则该类的对应值就逼近1,其余类的值逼近0。
参考:https://www.cnblogs.com/XDU-Lakers/p/10557496.html