tensorflow框架学习 两个简单的神经网络示例,回归与分类

 

一、回归神经网络

1、神经网络结构

定义一个简单的回归神经网络结构:

  • 数据集为(xi,yi),数据的特征数为1,所以x的维度为1。
  • 输入层1个神经元。
  • 隐藏层数为1,4个神经元。
  • 输出层1个神经元。
  • 隐藏层的激活函数为f(x)=x,输出层的激活函数为ReLU

结构图如下:

 

 

2、代码示例

相关函数说明:

  • tf.random_normal :用于生成正太分布随机数矩阵的tensor,tensorFlow有很多随机数函数,可以查找官方文档获得。
  • tf.zeros :用于生成0矩阵的tensor,tf.ones可以用来获得单位矩阵。
  • tf.nn.relu :tensorflow定义的用来实现ReLU激活函数的方法。
  • tf.reduce_sum :求和函数,通过axis来控制在哪个方向上求和,axis=[0]表示按行求和,axis=[1]表示按列求和。
  • tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) :梯度下降优化函数,learning_rate表示学习率,minimize表示最小化,loss是优化的损失函数。tensorFlow有很多优化函数,可以查找官方文档获得。

 

代码:

复制代码

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

# 创建数据训练数据集,
x_data = np.linspace(-1, 1, 500).reshape(500, 1)
noise = np.random.normal(0, 0.05, [500, 1])  # 制作噪音
y_data = np.square(x_data) + 0.5 + noise

# 创建占位符用于minibatch的梯度下降训练,建议数据类型使用tf.float32、tf.float64等浮点型数据
x_in = tf.placeholder(tf.float32, [None, 1])
y_in = tf.placeholder(tf.float32, [None, 1])


# 定义一个添加层的函数
def add_layer(input_, in_size, out_size, activation_funtion=None):
    '''
    :param input_: 输入的tensor
    :param in_size: 输入的维度,即上一层的神经元个数
    :param out_size: 输出的维度,即当前层的神经元个数即当前层的
    :param activation_funtion: 激活函数
    :return: 返回一个tensor
    '''
    weight = tf.Variable(tf.random_normal([in_size, out_size]))  # 权重,随机的in_size*out_size大小的权重矩阵
    biase = tf.Variable(tf.zeros([1, out_size]) + 0.01)  # 偏置,1*out_size大小的0.01矩阵,不用0矩阵避免计算出错
    if not activation_funtion:  # 根据是否有激活函数决定输出
        output = tf.matmul(input_, weight) + biase
    else:
        output = activation_funtion(tf.matmul(input_, weight) + biase)
    return output


# 定义隐藏层,输入为原始数据,特征为1,所以输入为1个神经元,输出为4个神经元
layer1 = add_layer(x_in, 1, 4, tf.nn.relu)

# 定义输出层,输入为layer1返回的tensor,输入为4个神经元,输出为1个神经元,激活函数为ReLU
predict = add_layer(layer1, 4, 1)

# 定义损失函数
loss = tf.reduce_mean(tf.reduce_sum(tf.square(y_in - predict), axis=[1]))  # tf.reduce_sum的axis=[1]表示按列求和

# 定义训练的优化方式为梯度下降
train = tf.train.GradientDescentOptimizer(0.1).minimize(loss)  # 学习率为0.1

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    # 训练1000次
    for step in range(1000):
        # 执行训练,因为有占位符所以要传入字典,占位符的好处是可以用来做minibatch训练,这里数据量小,直接传入全部数据来训练
        sess.run(train, feed_dict={x_in: x_data, y_in: y_data})
        # 每50步输出一次loss
        if step % 49 == 0:
            print(sess.run(loss, feed_dict={x_in: x_data, y_in: y_data}))

    # 最后画出实际的散点图与拟合的折线图进行对比
    predict_value = sess.run(predict, feed_dict={x_in: x_data})  # 先要获得预测值
    plt.figure()
    plt.scatter(x_data, y_data, c='r', marker='o')
    plt.plot(x_data, predict_value, '--', lw=2, c='b')
    plt.show()

复制代码

 

 

二、分类神经网络——mnist手写字数据

1、网络结构与数据来源

数据的详细说明请查看:tensorflow中文社区

结构说明:
  • 数据集(xi,yi):数据共有60000张图。其中xi是表示的是每一个图片的数据,长度为28x28 = 784,即一张图片特征为784列;yi有0-9共10种结果,由于是分类,所以使用softmax函数,则yi最后对应的输出层需要有10个神经元对应,有几个类就有几个神经元。
  • 隐藏层:个数为0,定义隐藏层拟合效果较差,所以这里不定义。
  • 输出层:为10个神经元,激活函数为softmax。
  • 损失函数loss:交叉熵损失函数。(交叉熵损失请查阅:详解机器学习中的熵、条件熵、相对熵和交叉熵
  • 迭代方法:由于数据集过大,使用minbtach方法。
  • 准确度的计算 :tensorflow中文社区中有详细说明。

 

2、代码示例

相关函数说明:
  • input_data.read_data_sets(train_dir='MNIST_data',one_hot=True) :函数作用说明,读取数据,代码会自动下载数据(若网络原因可自行下载),下载的是数据文件夹,在当前工作目录下,里面包含训练集mnist.train(包含特征mnist.train.images与标签mnist.train.labels)与测试集mnist.test(包含特征mnist.test.images与标签mnist.test.labels)。参数说明,train_dir:数据相对路径,one_hot:是否为独热编码。mnist.train.next_batch。

  • tf.argmax(input,dimension) :返回input张量的最大值所在的位置,dimension=1为列最大。
  • tf.equal(x,y) :返回一个bool数组,当x==y则值为True。
  • mnist.train.next_batch(batch_size) :用来获取mnist每批次的数据,每次使用会自动获取下一批batch_size大小的数据集。

代码:

复制代码

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

# 读取数据,代码会自动下载数据,下载的是数据文件夹,在当前工作目录下,里面包含训练集与测试集,train_dir:数据路径,one_hot:是否为独热编码。
mnist = input_data.read_data_sets(train_dir='MNIST_data', one_hot=True)

# 数据较大,因此用minbatch,batch_size每个批次的数据个数,batch_num为批次个数
batch_size = 1000
batch_num = mnist.train.num_examples // batch_size

# 创建占位符用于minibatch的梯度下降训练,建议数据类型使用tf.float32、tf.float64等浮点型数据
x_in = tf.placeholder(tf.float32, [None, 784])
y_in = tf.placeholder(tf.float32, [None, 10])


# 定义一个添加层的函数
def add_layer(input_, in_size, out_size, activation_funtion=None):
    '''
    :param input_: 输入的tensor
    :param in_size: 输入的维度,即上一层的神经元个数
    :param out_size: 输出的维度,即当前层的神经元个数即当前层的
    :param activation_funtion: 激活函数
    :return: 返回一个tensor
    '''
    weight = tf.Variable(tf.random_normal([in_size, out_size]))  # 权重,随机的in_size*out_size大小的权重矩阵
    biase = tf.Variable(tf.zeros([1, out_size]) + 0.01)  # 偏置,1*out_size大小的0.01矩阵,不用0矩阵避免计算出错
    if not activation_funtion:  # 根据是否有激活函数决定输出
        output = tf.matmul(input_, weight) + biase
    else:
        output = activation_funtion(tf.matmul(input_, weight) + biase)
    return output


# 定义输出层,输入为layer1返回的tensor,输入为784个神经元,输出为10个神经元,激活函数为softmax。
prediction = add_layer(x_in, 784, 10)  # 这个对应下一步定义交叉熵损失函数的method1,不需要激活函数softmax

# 定义交叉熵损失函数,这里用method1
# method1:用自带的函数,这个函数会自动对prediction进行softmax操作所以不需要前面定义prediction不需要激活函数
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_in, logits=prediction))

# #method2:手动计算,这里tf.clip_by_value函数的作用是为了避免输入为负数或者0,log函数的定义域是大于0的,不这么做会出现LOSS=NAN且模型准确度不变的情况,这个坑会在代码示例后面说明。
# cross_entropy = -tf.reduce_sum(y_in * tf.log(tf.clip_by_value(prediction,1e-8,1.0)))


# 定义训练的优化方式为梯度下降
train = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy)  # 学习率为0.1

# 准确度,先得到bool型的数组correct_prediction ,再计算值为True的平均值即为准确率
correct_prediction = tf.equal(tf.argmax(y_in, 1), tf.argmax(prediction, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    # 训练20代
    for epoch in range(20):
        # 每代对数据进行一轮minibatch
        for batch in range(batch_num):
            batch_x, batch_y = mnist.train.next_batch(batch_size)  # 每个循环读取batch_size大小批次的数据
            sess.run(train, feed_dict={x_in: batch_x, y_in: batch_y})

            acc = sess.run(accuracy, feed_dict={x_in: mnist.test.images, y_in: mnist.test.labels})  # 用测试数据计算准确度
            print('第%d代%d批次,准确率为%.6f' % (epoch + 1, batch + 1, acc))

复制代码

 

3、 使用交叉商的坑

第一个坑:

使用method1计算较差熵时,定义prediction不能有激活函数tf.nn.softmax,因为tf.nn.softmax_cross_entropy_with_logits函数会自动对prediction进行softmax处理,所以正确的代码如下:

复制代码

#定义输出层
prediction = add_layer(x_in, 784, 10)  

#定义交叉熵
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_in, logits=prediction))

复制代码

可以尝试使用method1计算交叉熵,并定义prediction的时候传入激活函数,会发现拟合效果变差,代码如下

复制代码

#定义输出层
prediction = add_layer(x_in, 784, 10, tf.nn.softmax)  

#定义交叉熵
cross_entropy = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=y_in, logits=prediction))

复制代码

 

第二个坑:

先来看一下,当使用method2手动计算交叉熵时,不使用tf.clip_by_value时候的代码的时候运行是什么样子的,代码修改如下:

#method2:手动计算,这里tf.clip_by_value函数的作用是为了避免输入为负数或者0,log函数的定义域是大于0的,不这么做会出现LOSS=NAN且模型准确度不变的情况,这个坑会在代码示例后面说明。
cross_entropy = -tf.reduce_sum(y_in * tf.log(prediction))

运行结果为:

复制代码

C:\Users\EDZ\PycharmProjects\DY\Scripts\python.exe C:/Users/EDZ/.PyCharm2019.1/config/scratches/tf.py
Extracting MNIST_data\train-images-idx3-ubyte.gz
Extracting MNIST_data\train-labels-idx1-ubyte.gz
Extracting MNIST_data\t10k-images-idx3-ubyte.gz
Extracting MNIST_data\t10k-labels-idx1-ubyte.gz
第1代1批次,准确率为0.098000
第1代2批次,准确率为0.098000
第1代3批次,准确率为0.098000
第1代4批次,准确率为0.098000
第1代5批次,准确率为0.098000
第1代6批次,准确率为0.098000
第1代7批次,准确率为0.098000

复制代码

可以看出准确率完全没有变化,准确率没有变化说明cross_entropy没有变,没有进行训练,于是输出每次迭代cross_entropy的值,代码修改如下:

# print('第%d代%d批次,准确率为%.6f' % (epoch + 1, batch + 1, acc))
            loss = sess.run(cross_entropy, feed_dict={x_in: mnist.test.images, y_in: mnist.test.labels})
            print('第%d代%d批次,loss为%.6f' % (epoch + 1, batch + 1, loss))

运行结果为:

复制代码

C:\Users\EDZ\PycharmProjects\DY\Scripts\python.exe C:/Users/EDZ/.PyCharm2019.1/config/scratches/tf.py
Extracting MNIST_data\train-images-idx3-ubyte.gz
Extracting MNIST_data\train-labels-idx1-ubyte.gz
Extracting MNIST_data\t10k-images-idx3-ubyte.gz
Extracting MNIST_data\t10k-labels-idx1-ubyte.gz
第1代1批次,loss为nan
第1代2批次,loss为nan
第1代3批次,loss为nan
第1代4批次,loss为nan
第1代5批次,loss为nan
第1代6批次,loss为nan
第1代7批次,loss为nan

复制代码

出现这样的结果是因为,log函数的定义域是x>0,但是传入的数据predicttion可能含有0或者负数,此时就会出现计算结果为NAN的情况,为了避免这个情况就需要用到tf.clip_by_value函数将数据限制在0-1之间,下面是这个函数的介绍:

tf.clip_by_value(t,clip_value_min,clip_value_max,name=None)

  • tTensor or IndexedSlices.
  • clip_value_min: A 0-D (scalar) Tensor, or a Tensor with the same shape as t. The minimum value to clip by.
  • clip_value_max: A 0-D (scalar) Tensor, or a Tensor with the same shape as t. The maximum value to clip by.
  • name: A name for the operation (optional).

作用:截断tensor数据的值,让数据的值在区间 [clip_value_min , clip_value_max] 内。若tensor的值value<clip_value_min,则返回value=clip_value_min;若clip_value_min<=value<=clip_value_max,则返回value;若clip_value_max<value,则返回clip_value_max。

转载于:https://my.oschina.net/lwaif/blog/3101297

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值