Tensorflow系列(二)
简单的全连接实践
如图,模拟的数据:在半径为根号2的圆内的点为红色,圆外的点为蓝色,那么,我想要让神经网络试试能不能将这两类数据分开,随机输入一个点,而预测它的颜色
实验需求:python, tensorflow, numpy, random, matplotlib
本次实验参考中国大学mooc
代码分为两个部分,前向传播网络的构建和反向传播网络参数训练。前向传播文件中有:生成参数w和b的函数,自己构建前向传播网络函数,具体代码有很详细的注释。百度云盘文末附上。经过前向传播,我们会得到网络训练的值。然后再反向传播中,令真实值与训练值的距离为loss,在梯度下降法中,经过20000轮的迭代,让loss不断减小,从而训练出w和b。最后向神经网络喂入密集点阵,得到大量值,以0.5为分界线,画出分类界限。得到下图: 可以看到,训练的分类界限基本上是一个以根号2为半径的圆,模型不错。
前向传播:
# coding:utf-8
import tensorflow as tf
Input_size = 2 # 输入节点层大小
Node_size = 20 # 中间层节点大小
Output_size = 1 # 输出节点层大小
def get_weight(shape, regularizer): # 获取参数w的函数
w = tf.Variable(tf.truncated_normal(shape, stddev=0.1)) # 随机赋值给w
if regularizer is not None:
tf.add_to_collection("losses", tf.contrib.layers.l2_regularizer(regularizer)(w))
return w
def get_b(shape): # 获取偏置b的函数
b = tf.b = tf.Variable(tf.zeros(shape)) # 统一将 bias 初始化为 0
return b
def forward(x, regularizer): # 构建前向传播框架
w1 = get_weight([Input_size, Node_size], regularizer) # 获取参数w1
b1 = get_b([Node_size]) # 获取参数b1
y1 = tf.nn.relu(tf.matmul(x, w1) + b1) # 计算,加上偏置b1, 并且经过激活函数
w2 = get_weight([Node_size, Output_size], regularizer)
b2 = get_b([Output_size])
y = tf.matmul(y1, w2) + b2 # 注意,输出层一般不经过激活函数
return y
反向传播:
# coding:utf-8
import tensorflow as tf
import numpy as np
import random
import bilibili_test1.bilibili_forward as fw
import matplotlib.pyplot as plt
Learning_rate_base = 0.1 # 学习率
Learning_rate_decay = 0.99 # 学习率衰减率
Moving_average_decay = 0.99 # 滑动平均
Regularizer = 0.0001 # 正则化
Seed = 2 # 初始化数据的随机种子
Batch_size = 30 # 一次喂入多少组数据
Steps = 100000 # 训练的轮数
def generate_data(): # 生成数据的函数
rdm = np.random.RandomState(Seed)
X = rdm.randn(300, 2) # 生成300*2的矩阵
Y_ = [int(x0 * x0 + x1 * x1 < 2) for (x0, x1) in X] # 标签,在半径为根号2的圆内的点标签为1,圆外为0
Y_c = ["red" if y else "blue" for y in Y_] # 颜色,圆内为红色, 圆外为蓝色
X = np.vstack(X).reshape(-1, 2) # 改变形状,-1表示随零一维的变化而变化
Y_ = np.vstack(Y_).reshape(-1, 1)
return X, Y_, Y_c
def get_batch_data(X, Y_): # 得到Batch_size个数据的函数
start = random.sample(range(0, 299 - Batch_size), Batch_size) # 在指定范围内随机生成Batch_size个数
batch_x = X[start, :] # 得到数据
batch_y = Y_[start, :] # 得到标签
return batch_x, batch_y
def backward(X, Y_, Y_c): # 反向传播函数
x = tf.placeholder(tf.float32, [None, fw.Input_size]) # 给输入数据占位,因为不知道一次要喂入多少组数据,所以用的None
y_ = tf.placeholder(tf.float32, [None, fw.Output_size]) # 给真实的标签占位
y = fw.forward(x, Regularizer) # 前向传播计算得到的值
global_step = tf.Variable(0, trainable=False)
loss = tf.reduce_mean(tf.square(y_ - y)) # loss值,我们的目的就是让它变小
loss_total = loss + tf.add_n(tf.get_collection("losses"))
learning_rate = tf.train.exponential_decay(
Learning_rate_base,
global_step,
300 / Batch_size,
Learning_rate_decay,
staircase=True
)
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_total) # 反向传播,梯度下降法计算
ema = tf.train.ExponentialMovingAverage(Moving_average_decay, global_step)
ema_op = ema.apply(tf.trainable_variables())
with tf.control_dependencies([train_step, ema_op]):
train_op = tf.no_op(name="train")
with tf.Session() as sess: # 初始化会话
init_op = tf.initialize_all_variables() # 初始化所有参数
sess.run(init_op) # 运行, 这两步是必须的
for step in range(Steps): # 循环,在这里训练
train_x, train_y = get_batch_data(X, Y_) # 得到批数据
sess.run(train_op, feed_dict={x: train_x, y_: train_y}) # 训练
if step % 2000 == 0: # 每2000轮查看训练loss情况
train_loss = sess.run(loss_total, feed_dict={x: train_x, y_: train_y})
print("经过%d轮训练, 训练数据的loss值为:%f" % (step, train_loss))
# 因为数据标签的值为0和1,那么区分是0还是1的界限为0.5
# 下面生成密集点阵喂入神经网络, 画出那些训练结果为0.5的等高线,展示神经网络的分类的界限
xx, yy = np.mgrid[-3:3:0.01, -3:3:0.01]
grid = np.c_[xx.ravel(), yy.ravel()] # 密集的点阵
probs = sess.run(y, feed_dict={x: grid})
probs = probs.reshape(xx.shape)
plt.scatter(X[:, 0], X[:, 1], c=np.squeeze(Y_c)) # 原数据的情况
plt.contour(xx, yy, probs, [0.5]) # 画等高线
plt.show()
if __name__ == "__main__":
X, Y_, Y_c = generate_data()
backward(X, Y_, Y_c)
Twitter
Facebook
Reddit
LinkedIn
StumbleUpon
Pinterest
Email