Hugo Future Imperfect Slim

Xiang.Y

A bioinformation student

Tensorflow系列(二)

简单的全连接实践

Xiang.Y

3 minute read

Pic 1

如图,模拟的数据:在半径为根号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)

Recent posts

See more

Categories

About

Something to say