本文作为tensorflow笔记, 其中将会包含强化学习的笔记

Tensorflow

NakedTensor

tensorflow思想的重点在于误差的定义, 对于图片可以定义的是输入图片与卷积神经网络的误差, 还是对于一个音乐序列与递归神经网络的误差, 只要误差定义了, 我们就可以用tensorflow去训练它, 从而得到结果

Serial.py


import tensorflow as tf

'''
Your dataset.
'''
xs = [ 0.00,  1.00,  2.00, 3.00, 4.00, 5.00, 6.00, 7.00] # Features
ys = [-0.82, -0.94, -0.12, 0.26, 0.39, 0.64, 1.02, 1.00] # Labels

'''
Initial guesses, which will be refined by TensorFlow.
'''
m_initial = -0.5 # Initial guesses
b_initial =  1.0

'''
Define free variables to be solved.
'''
m = tf.Variable(m_initial) # Parameters
b = tf.Variable(b_initial)

'''
Define the error between the data and the model one point at a time (slow).
'''
total_error = 0.0
for x, y in zip(xs, ys):
    y_model = m*x + b # Output of the model aka yhat
    total_error += (y-y_model)**2 # Difference squared - this is the "cost" to be minimized

'''
Once cost function is defined, create gradient descent optimizer.
'''
optimizer_operation = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(total_error) # Does one step

'''
Create operator for initialization.
'''
initializer_operation = tf.global_variables_initializer()

'''
All calculations are done in a session.
'''
with tf.Session() as session:

    session.run(initializer_operation) # Call operator

    _EPOCHS = 10000 # number of "sweeps" across data
    for iteration in range(_EPOCHS):
        session.run(optimizer_operation) # Call operator

    slope, intercept = session.run((m, b)) # Call "m" and "b", which are operators
    print('Slope:', slope, 'Intercept:', intercept)

Tensor.py

import tensorflow as tf

'''
Your dataset.
'''
xs = [ 0.00,  1.00,  2.00, 3.00, 4.00, 5.00, 6.00, 7.00] # Features
ys = [-0.82, -0.94, -0.12, 0.26, 0.39, 0.64, 1.02, 1.00] # Labels

'''
Initial guesses, which will be refined by TensorFlow.
'''
m_initial = -0.5 # Initial guesses
b_initial =  1.0

'''
Define free variables to be solved.
'''
m = tf.Variable(m_initial) # Parameters
b = tf.Variable(b_initial)

'''
Define the error between the data and the model as a tensor (distributed computing).
'''
ys_model = m*xs+b # Tensorflow knows this is a vector operation
total_error = tf.reduce_sum((ys-ys_model)**2) # Sum up every item in the vector

'''
Once cost function is defined, create gradient descent optimizer.
'''
optimizer_operation = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(total_error) # Does one step

'''
Create operator for initialization.
'''
initializer_operation = tf.global_variables_initializer()

'''
All calculations are done in a session.
'''
with tf.Session() as session:

    session.run(initializer_operation) # Call operator

    _EPOCHS = 10000 # number of "sweeps" across data
    for iteration in range(_EPOCHS):
        session.run(optimizer_operation) # Call operator

    slope, intercept = session.run((m, b)) # Call "m" and "b", which are operators
    print('Slope:', slope, 'Intercept:', intercept)

变成张量进行乘除, 最后直接tf.reduce_sum()就可以求出误差, 然后传入optimizer即可.

BigData.py

import tensorflow as tf
import numpy as np

'''
Your dataset.
'''
xs = np.linspace(0.0, 8.0, 8000000) # 8-million features
ys = 0.3*xs-0.8+np.random.normal(scale=0.25, size=len(xs)) # 8-million labels

'''
Initial guesses, which will be refined by TensorFlow.
'''
m_initial = -0.5 # Initial guesses
b_initial =  1.0

'''
Define free variables to be solved.
'''
m = tf.Variable(m_initial) # Parameters
b = tf.Variable(b_initial)

'''
Define placeholders for big data.
'''
_BATCH = 8 # Use only eight points at a time.
xs_placeholder = tf.placeholder(tf.float32, [_BATCH])
ys_placeholder = tf.placeholder(tf.float32, [_BATCH]) 

'''
Define the error between the data and the model as a tensor (distributed computing).
'''
ys_model = m*xs_placeholder+b # Tensorflow knows this is a vector operation
total_error = tf.reduce_sum((ys_placeholder-ys_model)**2) # Sum up every item in the vector

'''
Once cost function is defined, create gradient descent optimizer.
'''
optimizer_operation = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(total_error) # Does one step

'''
Create operator for initialization.
'''
initializer_operation = tf.global_variables_initializer()

'''
All calculations are done in a session.
'''
with tf.Session() as session:

    session.run(initializer_operation) # Call operator

    _EPOCHS = 10000 # Number of "sweeps" across data
    for iteration in range(_EPOCHS):
        random_indices = np.random.randint(len(xs), size=_BATCH) # Randomly sample the data
        feed = {
            xs_placeholder: xs[random_indices],
            ys_placeholder: ys[random_indices]
        }
        session.run(optimizer_operation, feed_dict=feed) # Call operator

    slope, intercept = session.run((m, b)) # Call "m" and "b", which are operators
    print('Slope:', slope, 'Intercept:', intercept)

对于大的数据, 更加抽象的, 我们只先用tf.Variable定义要优化的变量, tf.placeholder 来定义用来训练的数据集及batch数.

直到训练的时候才进行feed即可, 这里feed定义为xs_placeholderys_placeholder的字典, 把数据丢进去然后对抽象模型进行训练即可.

可以看到最重要的是定义变量和误差函数也就是抽象的模型, 然后丢入数据进行训练即可.

As you worked through the scripts, you hopefully saw how the error can be anything you wanted it to be. It could be the error between a set of images and a convolutional neural network. It could be the error between classical music and a recurrent neural network. Let your imagination run wild. Once the error is defined, you can use TensorFlow to try and minimize it.

深度学习

深度学习与神经网络书

传统的BP算法在深度网络中的问题是反向传播的越深, 梯度就越不稳定, 导致训练失败, 即消失的梯度问题 . 那么我们引入新的技巧: 卷积、pooling、使用 GPU 来更好地训练、 训练数据的算法性扩展(避免过匹配)、dropout 技术的使用(同样为了防止过匹配现象)、网络 的 ensemble 使用和其他技术.

卷积利用了数据的空间结构, 比如图像是一个二维结构, 如果我们把它向量化, 那么就会失去空间结构这个信息.

卷积神经网络利用了三个基本概念

  1. 局部感受野(local receptive fields)
  2. 共享权重(shared weights)
  3. 混合(pooling)

局部感受野

不同的神经元学习不同的局部感受野(也就是图像上不同的小窗口), 普通的神经网络是全连接的.

比如2828的图像矩阵, 使用55的局部感受野, 跨距为1, 可以得到一个24*24个神经元的隐藏层.

共享权重

虽然感受野是不同的, 但是权重$w$与偏置$b$是共享的. 因此实际上同一个隐藏层实际上在学习同一个特征, 所以称为特征映射, 特征映射又可以成为卷积核(特征可以是一个图像中特定的一些形状), 利用了图像的平移不变性(一只猫的图片稍微一动一下还是一只猫). 由于只有一个特征, 因此一个完整的卷积层有几个不同的特征映射.

共享权重和偏置的好处是大大减少了卷积网络的参数(相比全连接模型更好训练), 每一个特征映射我们只需要学习比如5*5(局部感受野的大小)+1(偏置)的参数.

混合层(pooling)

除了卷积层还包含混合层, 用来简化从卷积层输出的信息, 把卷积层的特征进一步压缩, 常用的就是最大值混合, 2424的卷积层就变成了1212的混合层, 可以把最大值混合看做是否一个特定的特征在图像的确定区域出现, 然后扔掉确定的信息. 还有一种混合是$L2$混合, 取平方和的平方根. 混合用来浓缩特征信息, 有助于减少训练的参数.

综合上面三点我们就可以构造一个完整的卷积神经网络.

net = Network([ConvPoolLayer(image_shape=(mini_batch_size, 1, 28, 28), filter_shape=(20,1,5,5), poolsize=(2,2)),FullyConnectedLayer(n_in=20*12+12,n_out=100),SoftmaxLayer(n_in=100,n_out=10)],mini_batch_size)

net.SGD(training_data, 60, mini_batch_size, 0.1, validation_data, test_data)

通常用tanh的结果和sigmoid的结果差不多, 但是训练的速度会更快一些.

改进

ReLU

进一步引入LeNet-5, 使用修正线性单元代替sigmoid函数(基于实验, 没有很好的理解)

$$ReLU(z)=max(0,z)$$

扩展训练数据

通过旋转, 扭曲和位移(还有弹性扭曲, 模仿人写字的时候的手部肌肉随机振动)来扩展原来的数据集. 两个卷层, 一个100层的隐藏全连接层.

继续插入一个全连接层

filter(卷积)维度进行减少, pooling(混合)维度直接相除.

dropout(弃权)

对全连接层可以进行dropout防止过拟合.

检测过拟合可以跟踪在测试数据上的准确率, 更一般的, 在测试集之外包含一个验证集作为跟踪模型的准确率. 这种方法称为 hold out (验证集是训练集中拿出的数据)

进一步可以规范化, 对权重求范数后加到代价函数中. 从而导致权重衰减.

如果不进行规范化, 权重向量随着时间的推移变得很长, 使得其卡在朝着变大或者变小的方向上, 而长度很大的时候梯度下降带来的变化仅仅会引起优化方向微小的方向, 使得我们很难有效的探索整个权重空间. 同时小的权重也意味着更低的复杂度(对数据有更简单更强大的解释). 一般我们不需要对偏置进行规范化, 同时大的偏置业允许神经网络更加灵活.

但是奥卡姆剃刀也不一定正确(比如相对论, 比牛顿法加入了复杂度, 但却解释了更多的现象)

人脑的优点在于小的训练数据就能达到非常好的效果, 而机器不行.

L1范数的导数就是$SIGN$函数. 注意L1和L2两者缩小权重的方式是不同的, L1倾向于使网络的权重集中在少量的高重要度连接中, 而L2倾向于成比例缩小.

进一步可以引入dropout

总之, 避免过拟合的步骤如下

  1. 引入正则项
  2. 引入验证集
  3. 引入dropout
  4. 认为扩展数据
  5. 组合网络(训练多个进行投票, 相当于bagging)

dropout相当于训练很多个不同的神经网络, 然后对他们的效果取平均, 具体做法就是训练好一次后随即丢掉一部分训练好的参数, 让其重新初始化, 这种方法一般对于全连接层使用.
因为本身卷积就有对过拟合的抵抗, 因为共享权重使得其会从整个图像去学习, 而不会陷入局部特征. 所以没必要对卷积层进行正则化.

深层网络的梯度问题

深层网路会带来梯度爆炸和梯度消失的问题, 而梯度是我们寻找最优解的方向, 所以会带来问题. 可以进行解决

  1. 使用卷积层减少参数数目
  2. 使用正则化减少过拟合
  3. 使用线性RELU
  4. 使用GPU
  5. 初始化
  6. 数据扩展

深度学习的突破在于认识到其性能超过1,2层的普通网络是可行的. 神经网路的主要调整的参数有三个, 学习速率, 规范化参数, minibatch大小..(可以用网格搜索进行自动化搜索)

RNN

RNN, 隐藏层神经元的行为不只是收到上一层的神经元影响, 还受到更早的层上的神经元的激活值影响, 具有时间特性, 在时序数据上很有效(语音识别), 在普通神经网络中的很多技巧也可以直接应用到RNN上.

LSTM

RNN的困难在模型很难训练, 主要就是梯度的不稳定稳定, 反向传播的时候梯度越变越小, 使得前面的层学习速度非常缓慢, RNN中更为严重, 因为不仅仅通过层反向传播, 还通过时间反向传播. 使得梯度的学习变得非常不稳定. 此时可以引入一个长短期记忆的单元进入RNN中, 使得RNN的训练变得简单.

深度置信网络, 生成模型和boltzman机

DBN是最早的深度学习模型, 但是最近前馈和RNN表现出更好的特性.

DBN的特性是

  1. 生成式模型. 不仅仅可以前向运行, 还可以反向运行. 比如说可以用来生成和手写数字很像的图像. 换句话说, 生成模型不仅可以读, 还可以写.(要识别, 先会写)
  2. DBN可以进行无监督和半监督学习. 即使训练图像是无标注的也可以用来学习

为什么不用DBN, 因为前馈式和RNN已经取得了很好的效果. 其主要的部件就是boltzman机
, 其潜能有待挖掘.

CRF

matlab程序

该条件随机场程序(CRF)是针对语句进行标注,matlab实现,部分程序由C语言实现并在matlab上进行编译。该程序包中实现了线性链结构的条件随机场(chain structured CRF),包括解码采用维特比(Viterbi)算法,推理采用前向-后向算法,采样采用前向过滤-后向采样算法,参数估计采用拟牛顿方法。

强化学习

强化学习

K-臂赌博机

最简单的K-臂赌博机引入探索和利用两个行为, 但是由于试探的次数是有限的, 所以两者之间存在一个均衡.

$\epsilon$贪心策略

为了进行两者的均衡, 引入$\epsilon$贪心, 以$\epsilon$概率进行平均探索, 以$1-\epsilon$概率进行利用(选择最优策略)

softmax

并非直接进行概率贪心, softmax基于boltzmann分布, 将原来的策略概率进行变换后仍然按照概率进行选择.

有模型学习

讨论在模型训练好的情况下选择最优策略$\pi$

无模型学习

现实情况下基本都是无模型学习, 由于模型未知, 采用进行多次采样后取平均累计奖励作为期望累计奖励的近似这样一个蒙特卡洛强化学习方法.

1. 蒙特卡洛强化学习

可以分为同策略蒙特卡洛和异策略蒙特卡洛, 一般来说无模型学习的过程有三步

  1. 采样(用学习到的$\pi$进行采样)
  2. 评估策略得到Q(平均累计奖励)
  3. 用Q改进策略$\pi$

这里的同异策略指的是评估和改进的是不是同一个策略(如一个采用$\epsilon$贪心, 另外一个没有采用), 一般策略的不同在于采用了$\epsilon$贪心. 我们可以在评估的时候引入贪心, 而在改进的时候仍然使用原来的策略.

2. 时序差分(TD)学习

相比蒙特卡洛, 利用了MKP的结构提高了效率.

蒙特卡洛中是采样完成后进行改进, 而TD可以边采样边改进. 以此每执行一步策略就更新一次值函数估计Q, 每次更新需要前一步状态(state), 前一步动作(action), 奖励(reward), 当前状态(state), 将要执行的动作(action), 因此称为sarsa算法. 为同策略算法, 如果改成异策略算法, 就是Q-learning. 这里的异在于执行和评估的不同. 因为TD学习的过程为

  1. 执行
  2. 评估
  3. 改进

Q-learning和sarsa的不同在于其是异策略的, 执行过程是不采用$\epsilon$贪心的. sarsa在执行的时候采用$\epsilon$贪心.

值函数近似

用一个线性函数去近似Q表格.

模仿学习

直接模仿学习

搜索空间很大导致用累计奖励来学习很困难, 可以采用模仿专家的轨迹数据来进行学习.

逆模仿学习

通过序列学习奖励函数, 利用专家轨迹数据反推出奖励函数.

可以看到一个是学习$\pi$, 一个是学习Q

常见随机优化算法

本文将对常见的优化方法进行了比较和实验.

SGD

SGD就是随机采样一些数据点, 而不是取全部数据进行求梯度, 然后更新参数, 可以加快优化速度.

SGD + Momentum

Momentum就是动量方法, 记录历史梯度信息的线性组合用来作参数更新的方向, 且时间越久远的梯度信息对当前动量的贡献越小

$$v_1=\alpha{\nabla}J(\theta^0)$$
$$v^k={\mu}v^{k-1}+\alpha{\nabla}J(\theta^{k-1})$$
$$\theta^k=\theta^{k-1}-v^k$$
$$(\mu^0,\mu^1,\mu^2,\mu^3,\mu^4,\mu^5,…)$$

Adagrad

主要的不同在于自适应, 记录一个历史梯度的平方信息, 对其求倒数对来当前梯度进行缩放和扩大, 其想法就是如果历史梯度平方和大, 那么参数变化量也就大, 对其求导数后就会使得当前梯度进行缩放, 如果历史梯度平方和小, 那么参数变化量也小, 求倒数后就会对当前梯度进行放大, 从而自适应学习.

Adadelta

adadelta是对adagrad的改进, 改进了adagrad的倒数可能为0的缺点.

主要是两个方面的不同

  1. 只考虑最近的梯度信息而不是全部的.
  2. 像动量法一样引入一个加速度项收集历史梯度信息.

Adam