最近论文需要用到深度学习,发现一年没用过的tensorflow,基本上都忘了。这篇文章是北大软微曹健老师的视频笔记
基础
在tensorflow中,用张量表示数据,用计算图搭建神网络,用会话(session)执行计算图,优化线上的权重,得到模型。
张量: n维数组,0阶是标亮、1阶是向量、2阶是矩阵、n阶就是张量了
计算图: 搭建神经网络的计算过程,只搭
看一个最简单的计算图:
import tensorflow as tf
a = tf.constant([1.0, 2.0])
b = tf.constant([3.0, 4.0])
result = a + b
print(result)
结果
Tensor("add:0", shape=(2,), dtype=float32)
这里可以看出来,计算图只描述计算过程,不计算运算结果
会话: 如果要得到计算图的计算结果,就需要使用会话
with tf.session() as sess:
print(sess.run(result))
参数
Variable表示 tensorflow 中的变量,线上的权重W,用变量表示,随机给初值
# random_normal表示生成标准正太分布的矩阵,其他可选的还有 truncated_normal() ->去掉过大偏离点的正态分布 random_uniform ->平均分布
# [2,3]表示矩阵为两行三列的矩阵
# stddev表示矩阵的标准差为2
# mean表示均值为0
# seed是随机种子,如果不设置,每次生成的随机数会不一样
w = tf.Variable(tf.random_normal([2,3], stddev=2, mean=0, seed=1))
tf.zeros([3,2], int32) #三行两列的全0数组
tf.ones([3,2], int32) #三行两列的全1数组
tf.fill([3,2],6) #三行两列,数组值全是6
tf.constant([3,2,1]) #直接生成[3,2,1] tensorflow中运算,就需要使用tensorflow的数据格式
占位符
在神经网络的训练中输入参数可能有多组,用placeholder来接收输入参数x
x = tf.placeholder(tf.float32, shape(1,2)) #生成一个一行两列的占位符
全局参数初始化
Variable生成的过程,只是指定了初始化的方式,由于计算图本身不进行任何运算,因此并没有真正初始化,如果要初始化就需要使用下面的方式:
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
一个简单训练的实现过程
神经网络的实现过程大致可以分为以下几步:
- 准备数据集,提取特征,作为输入喂给神经网络
- 搭建NN结构,从输入到输出(包括搭建计算图,会话执行,前向传播)
- 大量特征数据喂给NN,迭代优化NN参数(反向传播,优化参数,训练模型)
- 使用训练好的模型预测和分类
下面看一个简单的例子:
import tensorflow as tf
import numpy as np
BATCH_SIZE = 8
seed = 23455
# 准备数据集
rng = np.random.RandomState(seed)
X = rng.rand(32, 2) #产生32行2列的随机矩阵
Y = [[int(x0+x1<1)] for (x0,x1) in X]
print(Y)
# 搭建网络结构
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
w1 = tf.Variable(tf.random_normal([2,3], stddev=1, seed=1))
w2 = tf.Variable(tf.random_normal([3,1], stddev=1, seed=1))
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
loss = tf.reduce_mean(tf.square(y-y_))
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss)
#train_step = tf.train.MomentumOptimizer(0.001).minimize(loss)
#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 = 3000
for i in range(STEPS):
start = (i*BATCH_SIZE) % 32
end = start + BATCH_SIZE
sess.run(train_step, feed_dict={x: X[start: end], y_ : Y[start: end]})
if i % 500 == 0:
total_loss = sess.run(loss, feed_dict={x:X, y_:Y})
print("After %d training step(s), loss on all data is %g" % (i, total_loss))
print("end")
神经网络的优化
激活函数,常用的有
tf.nn.relu()
tf.nn.sigmoid()
tf.nn.tanh()
损失函数 常用的有:
#均芳误差
loss_mse = tf.reduce_mean(tf.square(y_ - y))
#交叉熵表示两个概率分布之间的距离,越大距离越远
#y小于1e-12为1e-12,大于1.0为1.0(这就要求输入数据都在0-1之间,毕竟是概率)
ce = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-12, 1.0)))
#如果输出不满足 0-1 的要求,就无法使用交叉熵,这个时候可以让输出经过softmax来满足这一点
#tf.argmax()和np.argmax()效果一样,只是需要运行才能有最终的结果
#如果axis=0,返回列最大元素所在的索引,如果axis=1,返回行最大元素的索引(由于标签大多数是one-hot的形式,每一行1所在的元素就是正确的类别)
ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, axis=1))
cem = tf.reduce_mean(ce)
自定义损失函数
下面的损失函数表示,如果y大于y_,执行第一个式子,COST(y-y_),否则执行第二个式子,PROFIT(y_-y)
loss = tf.reduce_sum(tf.where(tf.greater(y, y_), COST*(y-y_), PROFIT*(y_ - y)))
学习率:
普通学习率的设置上面已经用过了,这里记录下指数衰减的学习率
learning_rate = tf.train.exponential_decay(
LEARNINF_RATE_BASE, #学习率基础
global_step, #运行多少轮
LEARNING_RATE_STEP, #多久更新一次学习率,一般就是 总样本数/batch_size
LEARNING_RATE_DECAY, #学习衰减率(0,1)
staircase=True
)
滑动平均
也叫影子值,记录了每个参数一段时间过往值的平均,增加了模型的泛化性(就好像给参数加上了影子,参数变化,影子缓慢跟随)
影子 = 衰减率 * 影子 + (1-衰减率)* 参数
衰减率 = min{MOVING_AVERAGE_DECAY, (1+轮数)/(10+轮数)}
其中 MOVING_AVERAGE_DECAY 是超参数(一般是一个比较大的数,比如0.99)
tf中使用滑动窗口平均
#global_step 当前轮数
ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY), global_step)
# ema_op = ema.apply([])
ema_op = ema.apply(tf.trainable_variables()) #trainable_variables可以将所有待训练的参数整理成列表的形式返回
with tf.control_dependencies([train_step, ema_op]):
train_op = tf.no_op(name='train')
# 返回某些参数的滑动平均值
ema.average(参数名)
正则化:
loss(w) = tf.contrib.layers.l1_regularizer(REGULARIZER)(w) #l1正则化项
loss(w) = tf.contrib.laryers.l2_regularizer(REGULARIZER)(w) #l2正则化项
# 把内容加到集合对应位置做加法
tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))
loss = cem + tf.add_n(tf.get_collection('losses')) #再加上交叉熵为总loss
模块化的神经网络搭建
前向传播(forward.py):
def forward(x, regularizer):
w=
b=
y=
return y
def get_weight(shape, reguarizer):
w = tf.Variable( ) #赋初值
tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w)) #将w的损失加入到总损失losses中
return w
def get_bias(shape):
b = tf.Variable( ) #赋初值
return b
反向传播(backward.py)
def backward():
x = tf.placeholder( )
y_ = tf.placeholder( )
y = forward.forward(x, REGULARIZER)
global_step = tf.Variable(0, trainable=False)
loss = # 这里有多种,前面的交叉熵、均方误差都可以
loss = loss + tf.add_n(tf.get_collection('losses')) # 加入正则化项
learning_rate = #这里学习率可以是固定值,也可以是前面说到的指数衰减学习率
大概就是这么个流程,视频后面内容没看了。
LSTM实现手写数字识别
# 使用rnn实现mnist数据集分类
# 了解rnn的基本结构和实现
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
lr = 0.001
training_iters = 100000
batch_size = 128
#28*28的图片,每个向量是一行,一共28行
n_input = 28
n_step = 28
n_hidden_unis = 128
n_classes = 10
x = tf.placeholder(tf.float32, [None, n_step, n_input])
y = tf.placeholder(tf.float32, [None, n_classes])
weights = {
'in' : tf.Variable(tf.random_normal([n_input, n_hidden_unis])),
'out' : tf.Variable(tf.random_normal([n_hidden_unis, n_classes]))
}
biases = {
'in' : tf.Variable(tf.constant(0.1, shape=[n_hidden_unis,])),
'out' : tf.Variable(tf.constant(0.1, shape=[n_classes,]))
}
def RNN(X, weights, biases):
#: X[batch_size,28,28] -> X[128*28, 28]
X = tf.reshape(X, [-1, n_input])
X_in = tf.matmul(X, weights['in']+biases['in'])
#: x_in[128*28,128] -> x_in[128,28,128]
X_in = tf.reshape(X_in, [-1, n_step, n_hidden_unis])
# cell: forget_bias=1.0 表示不希望忘记前面的东西 state_is_tuple
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_unis, forget_bias=1.0, state_is_tuple=True)
_init_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)
#time_major=False time_step 不是第一个维度
outputs, state = tf.nn.dynamic_rnn(lstm_cell, X_in, initial_state = _init_state, time_major=False)
# hidden layer for output as the final result
# tf.transpose(outputs, [1,0,2])) 将第一和第二两个维度交换(维度1换到0的位置,就是第一个维度,维度0换到1的位置就是第二个维度)
outputs = tf.unstack(tf.transpose(outputs, [1,0,2]))
result = tf.matmul(outputs[-1], weights['out']+biases['out'])
# results = tf.matmul(state[1], weights['out']) + biases['out'] 在这个例子中和上面结果是一样的
return result
pred = RNN(x, weights, biases)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
train_op = tf.train.AdamOptimizer(lr).minimize(cost)
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1)) #one-hot编码的预测结果
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) #tf.cast数据类型变换
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
step = 0
while step * batch_size < training_iters:
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
batch_xs = batch_xs.reshape([batch_size, n_step, n_input])
sess.run([train_op], feed_dict={
x: batch_xs,
y: batch_ys
})
if step % 20 == 0:
print(sess.run(accuracy, feed_dict={
x: batch_xs,
y: batch_ys
}))
step += 1