笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值,找寻数据的秘密,笔者认为,数据的价值不仅仅只体现在企业中,个人也可以体会到数据的魅力,用技术力量探索行为密码,让大数据助跑每一个人,欢迎直筒们关注我的公众号,大家一起讨论数据中的那些有趣的事情。
我的公众号为:livandata
神经网络相关的内容比较复杂,笔者只能逐一的进行总结,不足之处敬请谅解,如有遗漏,也欢迎大家留言沟通,学习的过程,本省就是相学相长的过程,以下内容希望对大家有所帮助。
1、神经网络用到的知识点为:
# 选取tensor中索引对应的元素:
c = np.random.random([10, 1])
# 取出第二个、第四个元素
b = tf.nn.embedding_lookup(c, [1,3])
sess = tf.Session()
print(sess.run(b))
print(c)
a = tf.get_variable('a', shape=[5, 2])
b = tf.get_variable('b', shape=[5, 2], trainable=False)
# 获取可以训练的变量a;
tvar = tf.trainable_variables()
sess = tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
print(sess.run(tvar))
print(sess.run(a))
2、损失函数的计算一般会采用梯度递减的方式进行,一般在使用梯度时会有很多现成的方法,比如:train = tf.train.GradientDescentOptimizer(0.01).minimize(loss),但是在调优过程中有时存在梯度消失或梯度爆炸等情况,其原因是由于链式求导法则中存在的问题,需要对函数的梯度进行优化或者更换激活函数,来减少梯度消失和爆炸的问题,下面提供了几个梯度优化的方法,仅供参考:
# 选取tensor中索引对应的元素:
c = np.random.random([10, 1])
# 取出第二个、第四个元素
b = tf.nn.embedding_lookup(c, [1,3])
sess = tf.Session()
print(sess.run(b))
print(c)
a = tf.get_variable('a', shape=[5, 2])
b = tf.get_variable('b', shape=[5, 2], trainable=False)
# 获取可以训练的变量a;
tvar = tf.trainable_variables()
sess = tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
print(sess.run(tvar))
print(sess.run(a))
神经网络梯度规则:
1)梯度求导:
grad = tf.gradients(ys=b, xs=a):即对b进行求导,自变量为a;
grad = tf.gradients(ys=[y1, y2], xs=[x1,x2,x3]):则相当于对y1+y2求偏导,偏导的自变量为[x1, x2, x3];
x_input = tf.placeholder(tf.float32, name='x_input')
y_input = tf.placeholder(tf.float32, name='y_input')
w = tf.Variable(2.0, name='weight')
b = tf.Variable(1.0, name='biases')
y = tf.add(tf.multiply(x_input, w), b)
gradient:梯度求导;
loss = tf.reduce_mean(tf.pow(y_input - y, 2))/(2*32)
train = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
sess = tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
# train为训练之后的模型
batch_xs, batch_ys = mnist.train.next_batch(100)
train.run({x:batch_xs, y:batch_ys})
print(sess.run(y, feed_dict={x_input:x_train[i], y_input:y_train[i]}))
2)加权重求导:即对xs中的每个元素的求导值加权重。
w1 = tf.get_variable('w1', shape=[1])
w2 = tf.get_variable('w2', shape=[1])
w3 = tf.get_variable('w3', shape=[1])
w4 = tf.get_variable('w4', shape=[1])
z1 = 3*w1+2*w2+w3
z2 = -1*w3+w4
# grad_ys=[[-2.0, -3.0, -4.0],[-2.0, -3.0, -4.0]]
# 原来的值是对(z1+z2)求偏导;
# 现在的值是对((-2)*z1+(-3)*z2)求偏导;
grads = tf.gradients([z1, z2], [w1, w2, w3, w4], grad_ys=[[-2.0],[-3.0]])
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(grads))
3)梯度阻挡:
主要是阻挡一个方向的梯度,使其不再向上传播:
w1 = tf.Variable(2.0)
w2 = tf.Variable(2.0)
a = tf.multiply(w1, 3.0)
a_stoped = tf.stop_gradient(a)
b = tf.multiply(a_stoped, w2)
# b = w1*3.0*w2
gradients = tf.gradients(b, xs=[w1, w2])
# 上面的模型是为了构建一个含有两个变量的函数式,对b求导时主要分两步:
# 第一步求w1的导数,因为在运算中针对w1方向的梯度已经停掉,所以输出none;
# 第二步求w2的导数,运算中针对w2方向的梯度正常运算,所以输出正常的值;
# 可以将b函数看作是一个树状结构,stop_gradient限制了一个分枝,其他分枝不受影响;
print(gradients)
4)梯度修剪(梯度爆炸控制:由于权重的更新过于迅猛):
梯度爆炸与梯度消减的原因一样,都是因为链式法则求导的关系,导致梯度指数级衰减,为了避免梯度爆炸,需要进行梯度修剪;
tf.clip_by_global_norm(t_list, clip_norm, use_norm, name):
gradients得到的是一个梯度,有时这个梯度太大,导致梯度爆炸,因此需要进行梯度的修剪,
主要是按照clip_norm的平方和对t_list进行修剪,得到修剪后的梯度值。
原理为:
第一步:在solver中先设置一个clip_gradient;
第二步:在进行前向传播或者后向传播时,会得到每个权重的梯度diff,这时不像通常那样直接使用这些梯度进行权重更新,而是先求所有权重梯度的平方和sumsq_diff,
缩放因子为:scale_factor=clip_gradient/sumsq_diff;这个scale_factor在(0,1)之间,如果权重梯度的平方和越大,则缩放因子将越小;
第三步:将所有的权重梯度乘以这个缩放因子,这时得到的梯度才是最后的梯度信息;
import tensorflow as tf
def gradient_clip(gradients, max_gradient_norm):
"""计算的过程为:clipped_gradients=gradients/平方和(max_gradient_norm)"""
clipped_gradients, gradient_norm = tf.clip_by_global_norm(
gradients, max_gradient_norm)
gradient_norm_summary = [tf.summary.scalar("grad_norm", gradient_norm)]
gradient_norm_summary.append(
tf.summary.scalar("clipped_gradient", tf.global_norm(clipped_gradients)))
return clipped_gradients
w1 = tf.Variable([[3.0,2.0]])
params = tf.trainable_variables()
res = tf.matmul(w1, [[3.0],[1.]])
grads = tf.gradients(res,[w1])
clipped_gradients = gradient_clip(grads,2.0)
global_step = tf.Variable(0, name='global_step', trainable=False)
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(res))
print(sess.run(grads))
print(sess.run(clipped_gradients))
dropout(x, keep_drop)函数:主要是防止训练过程中的过拟合,按照概率将x中的元素置为零,并将其他值放大;
x是一个张量,而keep_prod是一个(0,1)之间的值,x中的元素清零的概率相互独立,为1-keep_prod,其他的元素按照1/keep_prod重新计算概率;
a = tf.get_variable('a', shape=[2,5])
b=a
a_drop=tf.nn.dropout(a,0.8)
sess = tf.InteractiveSession()
sess.run(tf.initialize_all_variables())
print(sess.run(b))
print(sess.run(a_drop))