关闭

神经网络基础概念

标签: 神经网络
224人阅读 评论(0) 收藏 举报
分类:

TensorFlow:实战Google深度学习框架》学习笔记
UFLDL教程:http://deeplearning.stanford.edu/wiki/index.php/UFLDL%E6%95%99%E7%A8%8B


一个模拟神经网络运行状况的网站:http://playground.tensorflow.org

这里写图片描述

神经网络两个重要特性:多层,非线性

线性模型的局限性:
线性模型的最大特点是 任意线性模型的组合仍然是线性模型

激活函数实现去线性化

如果每一个神经元(也就是神经网络中的节点)的输出通过一个非线性函数,那么整个神经网络模型就不再是线性的了。

这里写图片描述

TensorFlow中提供的7中非线性激活函数:
tf.nn.relu, tf.sigmoid, tf.tanh是常用的三个

官方文档中的激活函数API:
https://www.tensorflow.org/versions/r0.12/api_docs/python/nn.html#activation-functions

Activation Functions.

The activation ops provide different types of nonlinearities for use in neural networks. These include smooth nonlinearities (sigmoid, tanh, elu, softplus, and softsign), continuous but not everywhere differentiable functions (relu, relu6, crelu and relu_x), and random regularization (dropout).

All activation ops apply componentwise, and produce a tensor of the same shape as the input tensor.


损失函数

神经网络模型的效果以及优化的目标是通过损失函数(loss function)来定义的。

经典的损失函数:

交叉熵(cross entropy):刻画了两个概率分布之间的距离

参考:交叉熵损失函数 http://www.cnblogs.com/crackpotisback/p/6781872.html

# tensorflow 实现交叉熵
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, le-10, 1.0)))

# y_ : 正确结果
# y  : 预测结果
# tf.clip_by_value(y, le-10, 1.0): 将张量 y 限制在 le-10 和 1.0 之间

TensorFlow对交叉熵和softmax回归进行了统一封装

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(y, y_)
# 获取使用了softmax回归之后的交叉熵

对于回归问题,最常用的损失函数是均方误差(MSE, mean squared error)
这里写图片描述

通过TensorFlow实现均方误差

mse = tf.reduce_mean(tf.square(y_ - y))
# y : 输出答案
# y_: 标准答案

自定义损失函数

# coding: utf-8
import tensorflow as tf
from numpy.random import RandomState

# #### 1. 定义神经网络的相关参数和变量。
batch_size = 8
x = tf.placeholder(tf.float32, shape=(None, 2), name="x-input")
y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')
w1= tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w1)

# #### 2. 设置自定义的损失函数。
# 定义损失函数使得预测少了的损失大,于是模型应该偏向多的方向预测。
loss_less = 10
loss_more = 1
loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_) * loss_more, (y_ - y) * loss_less))
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)

# #### 3. 生成模拟数据集。
rdm = RandomState(1)
X = rdm.rand(128,2)
Y = [[x1+x2+rdm.rand()/10.0-0.05] for (x1, x2) in X]

# #### 4. 训练模型。
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    STEPS = 5000
    for i in range(STEPS):
        start = (i*batch_size) % 128
        end = (i*batch_size) % 128 + batch_size
        sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 1000 == 0:
            print("After %d training step(s), w1 is: " % (i))
            print sess.run(w1), "\n"
    print "Final w1 is: \n", sess.run(w1)

# #### 6. 定义损失函数为MSE。
loss = tf.contrib.losses.mean_squared_error(y, y_)
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)

with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    STEPS = 5000
    for i in range(STEPS):
        start = (i*batch_size) % 128
        end = (i*batch_size) % 128 + batch_size
        sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 1000 == 0:
            print("After %d training step(s), w1 is: " % (i))
            print sess.run(w1), "\n"
    print "Final w1 is: \n", sess.run(w1)

神经网络优化算法

反向传播算法:http://deeplearning.stanford.edu/wiki/index.php/%E5%8F%8D%E5%90%91%E4%BC%A0%E5%AF%BC%E7%AE%97%E6%B3%95
梯度下降算法:https://zh.wikipedia.org/wiki/%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E6%B3%95

梯度下降算法主要用于优化单个参数的取值,而反向传播算法给出了一个高效的方式在所有参数上使用梯度下降算法,从而使神经网络模型在训练数据上的损失函数尽可能小。

通过参数的梯度和学习率,参数更新的公式为:
这里写图片描述

随机梯度下降算法
这个算法在每一轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数更新的速度就大大加快了。

为了综合梯度下降算法和随机梯度下降算法的优缺点,实际的常用做法:每次计算一小部分训练数据的损失函数。这一小部分数据被称之为一个batch,通过矩阵运算,每次在一个batch上优化神经网络的参数并不会比单个数据慢太多。另一方面,每次使用一个batch可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。

学习率的设置

学习率决定了参数每次更新的幅度,
如果幅度过大,那么可能导致参数在极优值的两侧来回移动;
如果学习率过小,虽然能保证收敛性,但是这会大大降低优化速度。

指数衰减法
先使用较大的学习率来快速得到一个比较优的解,然后随着迭代的继续逐步减小学习率,使得模型在训练后期更加稳定。

# 指数衰减法
decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)

# decayed_learning_rate 为每一轮优化时使用的学习率
# learning_rate 为事先设定的初始学习率
# decay_rate 为衰减系数
# decay_steps 为衰减速度

TensorFlow实现指数衰减法

global_step = tf.Variable(0)

# 通过 exponential_decay函数生成学习率
learning_rate = tf.train.exponential_decay(
    0.1, global_step, 100, 0.96, staircase=True)
# 使用指数衰减法的学习率,在minimize函数中传入global_step将自动更新
# global_step 参数,从而是的学习率也得到相应更新
learning_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(...my_loss..., global_step=global_step)

过拟合

当一个模型过于复杂之后,它可以很好地“记忆”每一个训练数据中随机噪音的部分而忘记了要去“学习”训练数据中通用的趋势。以致于不能很好的对未知数据做出可靠的判断

这里写图片描述

正则化
在损失函数中加入刻画模型复杂程度的指标

机器学习之正则化(Regularization):
http://www.cnblogs.com/jianxinzhou/p/4083921.html

这里写图片描述

w = tf.Variable(tf.random_normal([2,1], stddev=1, seed=1))
y = tf.matmul(x, w)

# 损失函数中加入L2 正则化的值
loss = tf.reduce_mean(tf.square(y_ - y)) 
    + tf.contrib.layers.l2_regularizer(lambda)(w)

TensorFlow正则化示例:

# 1. 生成模拟数据集。
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np

data = []
label = []
np.random.seed(0)

# 以原点为圆心,半径为1的圆把散点划分成红蓝两部分,并加入随机噪音。
for i in range(150):
    x1 = np.random.uniform(-1,1)
    x2 = np.random.uniform(0,2)
    if x1**2 + x2**2 <= 1:
        data.append([np.random.normal(x1, 0.1),np.random.normal(x2,0.1)])
        label.append(0)
    else:
        data.append([np.random.normal(x1, 0.1), np.random.normal(x2, 0.1)])
        label.append(1)

data = np.hstack(data).reshape(-1,2)
label = np.hstack(label).reshape(-1, 1)
plt.scatter(data[:,0], data[:,1], c=label,
           cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white")
plt.show()

# 2. 定义一个获取权重,并自动加入L2正则项到损失的函数。
def get_weight(shape, lambda1):
    var = tf.Variable(tf.random_normal(shape), dtype=tf.float32)
    tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambda1)(var))
    return var

# 3. 定义神经网络。
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
sample_size = len(data)

# 每层节点的个数
layer_dimension = [2,10,5,3,1]

n_layers = len(layer_dimension)

cur_layer = x
in_dimension = layer_dimension[0]

# 循环生成网络结构:5层全连接网络
for i in range(1, n_layers):
    out_dimension = layer_dimension[i]
    weight = get_weight([in_dimension, out_dimension], 0.003)
    bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))
    cur_layer = tf.nn.elu(tf.matmul(cur_layer, weight) + bias)
    in_dimension = layer_dimension[i]

y= cur_layer # 最后一层是输出层

# 输出层的损失函数的定义。
mse_loss = tf.reduce_sum(tf.pow(y_ - y, 2)) / sample_size
tf.add_to_collection('losses', mse_loss)
loss = tf.add_n(tf.get_collection('losses'))

# 5. 训练带正则项的损失函数loss。
# 定义训练的目标函数loss,训练次数及训练模型
train_op = tf.train.AdamOptimizer(0.001).minimize(loss)
TRAINING_STEPS = 40000

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    for i in range(TRAINING_STEPS):
        sess.run(train_op, feed_dict={x: data, y_: label})
        if i % 2000 == 0:
            print("After %d steps, loss: %f" % (i, sess.run(loss, feed_dict={x: data, y_: label})))

    # 画出训练后的分割曲线       
    xx, yy = np.mgrid[-1:1:.01, 0:2:.01]
    grid = np.c_[xx.ravel(), yy.ravel()]
    probs = sess.run(y, feed_dict={x:grid})
    probs = probs.reshape(xx.shape)

plt.scatter(data[:,0], data[:,1], c=label,
           cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white")
plt.contour(xx, yy, probs, levels=[.5], cmap="Greys", vmin=0, vmax=.1)
plt.show()

滑动平均模型

在采用随机梯度下降算法训练神经网络时,使用 tf.train.ExponentialMovingAverage 滑动平均操作的意义在于提高模型在测试数据上的健壮性(robustness)。

tensorflow 下的 tf.train.ExponentialMovingAverage 需要提供一个衰减率(decay)。该衰减率用于控制模型更新的速度。该衰减率用于控制模型更新的速度,ExponentialMovingAverage 对每一个(待更新训练学习的)变量(variable)都会维护一个影子变量(shadow variable)。影子变量的初始值就是这个变量的初始值,

shadow_variable=decay×shadow_variable+(1−decay)×variable
由上述公式可知, decay 控制着模型更新的速度,越大越趋于稳定。实际运用中,decay 一般会设置为十分接近 1 的常数(0.99或0.999)。为了使得模型在训练的初始阶段更新得更快,ExponentialMovingAverage 还提供了 num_updates 参数来动态设置 decay 的大小:

这里写图片描述

import tensorflow as tf

# 1. 定义变量及滑动平均类
v1 = tf.Variable(0, dtype=tf.float32)
step = tf.Variable(0, trainable=False)
ema = tf.train.ExponentialMovingAverage(0.99, step)
maintain_averages_op = ema.apply([v1]) 

# 2. 查看不同迭代中变量取值的变化。
with tf.Session() as sess:

    # 初始化
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    print sess.run([v1, ema.average(v1)])

    # 更新变量v1的取值
    sess.run(tf.assign(v1, 5))
    sess.run(maintain_averages_op)
    print sess.run([v1, ema.average(v1)]) 

    # 更新step和v1的取值
    sess.run(tf.assign(step, 10000))  
    sess.run(tf.assign(v1, 10))
    sess.run(maintain_averages_op)
    print sess.run([v1, ema.average(v1)])       

    # 更新一次v1的滑动平均值
    sess.run(maintain_averages_op)
    print sess.run([v1, ema.average(v1)])  
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:67106次
    • 积分:2059
    • 等级:
    • 排名:第19728名
    • 原创:135篇
    • 转载:52篇
    • 译文:0篇
    • 评论:23条
    博客专栏