文档章节

TensorFlow学习系列(四):利用神经网络实现泛逼近器(universal approximator)

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:22
字数 2184
阅读 10
收藏 0
点赞 0
评论 0

这篇教程是翻译Morgan写的TensorFlow教程,作者已经授权翻译,这是原文


目录


TensorFlow学习系列(一):初识TensorFlow

TensorFlow学习系列(二):形状和动态维度

TensorFlow学习系列(三):保存/恢复和混合多个模型

TensorFlow学习系列(四):利用神经网络实现泛逼近器(universal approximator)

TensorFlow学习系列(五):如何使用队列和多线程优化输入管道


今天,我们先不用TensorFlow去实现具体的东西,而是去学习一点新的东西。

你听说过泛逼近定理 “Universal approximation theorem” 吗?

简单地,这个定理可以描述成如下三步(没有所有细节):

  • 对于任何定义域为 R^n 的连续函数 f ...
  • 你能找到一个拥有足够宽的一层隐藏层的神经网络 ...
  • 在一个闭区间上,这个神经网络就会逼近函数 f ...

听起来是不是很简单。

那让我们直接利用 TensorFlow 实现一个简单的例子吧,比如将一个函数从 R 维度映射到 R 维度。简单地,我们构造一个只拥有一层隐藏层的神经网络,并且在输出层不加偏置项,具体代码如下:

import tensorflow as tf

def univAprox(x, hidden_dim=50):
    # The simple case is f: R -> R
    input_dim = 1 
    output_dim = 1

    with tf.variable_scope('UniversalApproximator'):
        ua_w = tf.get_variable('ua_w', shape=[input_dim, hidden_dim], initializer=tf.random_normal_initializer(stddev=.1))
        ua_b = tf.get_variable('ua_b', shape=[hidden_dim], initializer=tf.constant_initializer(0.))
        z = tf.matmul(x, ua_w) + ua_b
        a = tf.nn.relu(z) # we now have our hidden_dim activations

        ua_v = tf.get_variable('ua_v', shape=[hidden_dim, output_dim], initializer=tf.random_normal_initializer(stddev=.1))
        z = tf.matmul(a, ua_v)

    return z

一些注意事项:

  • x 必须是秩为2的TensorFlow张量,也就是说 x 的维度是 [None, 1] 。其中,None表示批处理大小,你可以把它看做是在单个神经元上面计算所需要的容量。
  • 在这里,input_dimoutput_dim参数我们都是采取硬编码方式,当然如果你想要处理更复杂的函数,你可以修改这两个参数。在我们的例子中,我们取一个神经元是为了使问题尽量的简单。
  • 最后,我们使用了 Relu 激活函数。当然我们可以使用很多不同的激活函数来代替 Relu 函数,但是对于这个理论是无所谓的,因为我们只需要一个递增的函数就行了,选择不同的激活函数只是和学习的速度有关。

接下来,让我们编写一个很简单的脚本来评估这个函数:

x = tf.placeholder(tf.float32, shape=[None, 1], name="x")
y = univAprox(x)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    y_res = sess.run(y, feed_dict={
        x: [[0], [1], [2]] # We are batching 3 value at the same time
    })
    print(y_res) # -> [[ 0. ] [ 0.0373688 ] [ 0.07473759]]
    # Those values will be different for you, since we initialize our variables randomly

至此,我们已经完成了泛逼近器(UA)的设计和开发。

接下来我们需要去训练这个泛逼近器,去逼近我们给定的闭区间内的任何函数。

让我们从正弦函数(the sine function)开始吧,我个人不是很相信神经网络可以很好的近似一个函数。

提示:如果你和我一样,想知道这种近似是怎么做到的,我可以给你一个数学提示:

  • 在闭区间上的任何连续函数都可以通过分段常数函数 piecewise constant function 来近似。
  • 你可以手动建立一个神经网络,通过添加必要的神经元来构造这个分段函数。

接下来,我们可以构造一个脚本来做三件事:

  • 在正弦函数上训练我们的UA。
  • 用图来对比我们神经网络的结果和原始的正弦函数。
  • 从命令行中可以导入 hidden_dim 参数的值,以便能够更加轻松的修改它。

我将直接在这里发布整个脚本文件,包含说明注释。

我相信发布一个完整的代码对你的学习是非常有利的(不要害怕文件太长,里面包含了很多的注释和空行)。

# First let's import all the tools needed
# Some basic tools
import time, os, argparse, io
dir = os.path.dirname(os.path.realpath(__file__))

# Tensorflow and numpy!
import tensorflow as tf
import numpy as np

# Matplotlib, so we can graph our functions
# The Agg backend is here for those running this on a server without X sessions
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

# Our UA function
def univAprox(x, hidden_dim=50):
    # The simple case is f: R -> R
    input_dim = 1 
    output_dim = 1

    with tf.variable_scope('UniversalApproximator'):
        ua_w = tf.get_variable(
            name='ua_w'
            , shape=[input_dim, hidden_dim]
            , initializer=tf.random_normal_initializer(stddev=.1)
        )
        ua_b = tf.get_variable(
            name='ua_b'
            , shape=[hidden_dim]
            , initializer=tf.constant_initializer(0.)
        )
        z = tf.matmul(x, ua_w) + ua_b
        a = tf.nn.relu(z) # we now have our hidden_dim activations

        ua_v = tf.get_variable(
            name='ua_v'
            , shape=[hidden_dim, output_dim]
            , initializer=tf.random_normal_initializer(stddev=.1)
        )
        z = tf.matmul(a, ua_v)

    return z

# We define the function we want to approximate
def func_to_approx(x):
    return tf.sin(x)


if __name__ == '__main__': # When we call the script directly ...
    # ... we parse a potentiel --nb_neurons argument 
    parser = argparse.ArgumentParser()
    parser.add_argument("--nb_neurons", default=50, type=int, help="Number of neurons or the UA")
    args = parser.parse_args()

    # We build the computation graph
    with tf.variable_scope('Graph') as scope:
        # Our inputs will be a batch of values taken by our functions
        x = tf.placeholder(tf.float32, shape=[None, 1], name="x")

        # We define the ground truth and our approximation 
        y_true = func_to_approx(x)
        y = univAprox(x, args.nb_neurons)

        # We define the resulting loss and graph it using tensorboard
        with tf.variable_scope('Loss'):
            loss = tf.reduce_mean(tf.square(y - y_true))
            # (Note the "_t" suffix here. It is pretty handy to avoid mixing 
            # tensor summaries and their actual computed summaries)
            loss_summary_t = tf.summary.scalar('loss', loss) 

        # We define our train operation using the Adam optimizer
        adam = tf.train.AdamOptimizer(learning_rate=1e-2)
        train_op = adam.minimize(loss)

    # This is some tricks to push our matplotlib graph inside tensorboard
    with tf.variable_scope('TensorboardMatplotlibInput') as scope:
        # Matplotlib will give us the image as a string ...
        img_strbuf_plh = tf.placeholder(tf.string, shape=[]) 
        # ... encoded in the PNG format ...
        my_img = tf.image.decode_png(img_strbuf_plh, 4) 
        # ... that we transform into an image summary
        img_summary = tf.summary.image( 
            'matplotlib_graph'
            , tf.expand_dims(my_img, 0)
        ) 

    # We create a Saver as we want to save our UA after training
    saver = tf.train.Saver()
    with tf.Session() as sess:
        # We create a SummaryWriter to save data for TensorBoard
        result_folder = dir + '/results/' + str(int(time.time()))
        sw = tf.summary.FileWriter(result_folder, sess.graph)

        print('Training our universal approximator')
        sess.run(tf.global_variables_initializer())
        for i in range(3000):
            # We uniformly select a lot of points for a good approximation ...
            x_in = np.random.uniform(-10, 10, [100000, 1])
            # ... and train on it
            current_loss, loss_summary, _ = sess.run([loss, loss_summary_t, train_op], feed_dict={
                x: x_in
            })
            # We leverage tensorboard by keeping track of the loss in real time
            sw.add_summary(loss_summary, i + 1)

            if (i + 1) % 100 == 0:
                print('batch: %d, loss: %f' % (i + 1, current_loss))

        print('Plotting graphs')
        # We compute a dense enough graph of our functions
        inputs = np.array([ [(i - 1000) / 100] for i in range(2000) ])
        y_true_res, y_res = sess.run([y_true, y], feed_dict={
            x: inputs
        })
        # We plot it using matplotlib
        # (This is some matplotlib wizardry to get an image as a string,
        # read the matplotlib documentation for more information)
        plt.figure(1)
        plt.subplot(211)
        plt.plot(inputs, y_true_res.flatten())
        plt.subplot(212)
        plt.plot(inputs, y_res)
        imgdata = io.BytesIO()
        plt.savefig(imgdata, format='png')
        imgdata.seek(0)
        # We push our graph into TensorBoard
        plot_img_summary = sess.run(img_summary, feed_dict={
            img_strbuf_plh: imgdata.getvalue()
        })
        sw.add_summary(plot_img_summary, i + 1)
        plt.clf()

        # Finally we save the graph to check that it looks like what we wanted
        saver.save(sess, result_folder + '/data.chkp')

现在你可以在电脑上打开两个终端,并在主目录下启动以下命令来看看能发生什么:

  • python myfile.py --nb_neurons 50
  • tensorboard --logdir results --reload_interval 5 (默认的 reload_interval 是120秒,以避免在计算机上面太快统计,但是在我们的情况下,我们可以安全地加速一点)

现在,你可以实时的查看 UA 的训练过程了,观察它是怎么学习正弦函数的。

请记住,如果我们增加隐藏层的神经元个数,那么对于函数的近似效果会更加的好。

让我给你展示一下 4 种不同的隐藏层神经元个数 [20, 50, 100,500],所带来的函数近似效果吧。


Different graph showing the effect of the number of neurons in the UA

正如所预期的,如果我们增加神经元的数量,那么我们的近似函数 UA 将更好的近似我们的正弦函数。事实上,我们可以让神经网络模拟的数值尽可能的近似目标函数。这个工作是不是很漂亮 :)

然而,我们的 UA 模型有一个巨大的缺点,如果 input_dim 开始改变,那么我们不能对它进行重用。

我有一个疯狂的想法,如果我们能设计一个 UA,使得它能逼近一个复杂神经网络的激活函数!难道这不是一个很酷的设想吗?

我认为这是一个很好的练习例子,你怎么做能够欺骗 TensorFlow 去实现处理一个动态的输入维度。(具体可以参考我的 Github,但我建议你自己先写一下。)

在文章的最后,送大家一个小礼物:在MNIST数据集上,我已经使用了第二种方法去训练了一个神经网络,也就是说我们在一个神经网络中,使用另一个神经网络来代替激活函数。

以下图是激活函数近似的图形,是不是看起来很激动!


提示:在第二种 UA 中,我使用 ELU 函数作为了激活函数,所以看起来是一个凸的。所以,这些近似结果发生了多次。
我在 MNIST 测试集上面取得了 0.98 的正确率,这个结果给我一个启发,有可能激活函数对于一个任务的学习可能不是很重要。


Reference:

Universal approximation theorem

Universal Approximation Theorem — Neural Networks

本文转载自:http://www.jianshu.com/p/52e773d47338

共有 人打赏支持
AllenOR灵感
粉丝 10
博文 2634
码字总数 82983
作品 0
程序员
史上最全TensorFlow学习资源汇总

来源 悦动智能(公众号ID:aibbtcom) 本篇文章将为大家总结TensorFlow纯干货学习资源,非常适合新手学习,建议大家收藏。 ▌一 、TensorFlow教程资源 1)适合初学者的TensorFlow教程和代码示...

悦动智能
04/12
0
0
资源 | 概率编程工具:TensorFlow Probability官方简介

  选自Medium   作者:Josh Dillon、Mike Shwe、Dustin Tran   机器之心编译   参与:白妤昕、李泽南      在 2018 年 TensorFlow 开发者峰会上,谷歌发布了 TensorFlow Probabi...

机器之心
04/22
0
0
【干货】史上最全的Tensorflow学习资源汇总,速藏!

一 、Tensorflow教程资源: 1)适合初学者的Tensorflow教程和代码示例:(https://github.com/aymericdamien/TensorFlow-Examples)该教程不光提供了一些经典的数据集,更是从实现最简单的“Hel...

技术小能手
04/16
0
0
Artificial Intelligence Yourself

TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算,TensorFlow为张量从流...

孟飞阳
07/16
0
0
PaddleFluid和TensorFlow基本使用概念对比 | PaddlePaddle专栏

深度学习平台的演化 时至今日,深度学习已成为事实上最流行的机器学习技术。学术界多年研究加上工业界的长期实践提出了若干有效的基本建模单元:全连接,卷积,循环神经网络等;设计各类训练...

技术小能手
06/21
0
0
Tensorflow 笔记:搭建神经网络

目标:搭建神经网络,总结搭建八股 一、基本概念 1:基于 Tensorflow 的 NN: 用张量表示数据,用计算图搭建神经网络,用会话执行计算图,优化线上的权重(参数),得到模型。 2:TensorFlow的...

云时之间
05/02
0
0
机器学习者必知的5种深度学习框架

雷锋网按:本文为雷锋字幕组编译的技术博客,原标题The 5 Deep Learning Frameworks Every Serious Machine Learner Should Be Familiar With,作者为James Le。 翻译 | 杨恕权 张晓雪 陈明霏...

雷锋字幕组
05/03
0
0
《Scikit-Learn与TensorFlow机器学习实用指南》第9章 启动并运行TensorFlow

第9章 启动并运行TensorFlow 来源:ApacheCN《Sklearn 与 TensorFlow 机器学习实用指南》翻译项目 译者:@akonwang @WilsonQu 校对:@Lisanaaa @飞龙 TensorFlow 是一款用于数值计算的强大的...

apachecn_飞龙
04/23
0
0
送书&优惠丨对深度学习感兴趣的你,不了解这些就太OUT了!

点击上方“程序人生”,选择“置顶公众号” 第一时间关注程序猿(媛)身边的故事 TensorFlow是什么? TensorFlow的前身是谷歌大脑(google brain)团队研发的DistBelief。自创建以来,它便被...

csdnsevenn
05/03
0
0
TensorFlow应用实战-18-Policy Gradient算法

Policy Gradient算法 policy Gradient算法不止一种。 有兴趣的话: 深度增强学习之Policy Gradient方法1 https://zhuanlan.zhihu.com/p/21725498 A3c实现3d赛车游戏: 成果展示 numworkders是 ...

天涯明月笙
06/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java设计模式学习之工厂模式

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之...

路小磊
16分钟前
0
0
npm profile 新功能介绍

转载地址 npm profile 新功能介绍 npm新版本新推来一个功能,npm profile,这个可以更改自己简介信息的命令,以后可以不用去登录网站来修改自己的简介了 具体的这个功能的支持大概是在6这个版...

durban
27分钟前
0
0
Serial2Ethernet Bi-redirection

Serial Tool Serial Tool is a utility for developing serial communications, custom protocols or device testing. You can set up bytes to send accordingly to your protocol and save......

zungyiu
33分钟前
0
0
python里求解物理学上的双弹簧质能系统

物理的模型如下: 在这个系统里有两个物体,它们的质量分别是m1和m2,被两个弹簧连接在一起,伸缩系统为k1和k2,左端固定。假定没有外力时,两个弹簧的长度为L1和L2。 由于两物体有重力,那么...

wangxuwei
48分钟前
0
0
apolloxlua 介绍

##项目介绍 apolloxlua 目前支持javascript到lua的翻译。可以在openresty和luajit里使用。这个工具分为两种模式, 一种是web模式,可以通过网页使用。另外一种是tool模式, 通常作为大规模翻...

钟元OSS
54分钟前
0
0
Mybatis入门

简介: 定义:Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。 途径:MyBatis通过XML文件或者注解的形式配置映射,实现数据库查询。 特性:动态SQL语句。 文件结构:Mybat...

霍淇滨
今天
0
0
开发技术瓶颈期,如何突破

前言 读书、学习的那些事情,以前我也陆续叨叨了不少,但总觉得 “学习方法” 就是一个永远在路上的话题。个人的能力、经验积累与习惯方法不尽相同,而且一篇文章甚至一本书都很难将学习方法...

_小迷糊
今天
0
0
安装tensorflow-XXX报错

报错: tensorflow-0.5.0-cp27-none-linux_x86_64.whl is not a supported wheel on this platform. 解决: wget https://bootstrap.pypa.io/get-pip.py sudo python2.7 get-pip.py sudo p......

Yao--靠自己
今天
0
0
JVM学习手册(一):JVM模型

一直从事JAVA开发,天天和JVM打交道,仔细想想对JVM还真的不是特别了解,实在是不应该.周六看了许多资料,也算有点心得,记录一下。 JVM内存模型分为5个区域:方法区,堆,虚拟机栈,本地方法栈,程序计...

勤奋的蚂蚁
今天
0
0
转行零基础该如何学Python?这些一定要明白!

转行零基础学Python编程开发难度大吗?从哪学起?近期很多小伙伴问我,如果自己转行学习Python,完全0基础能否学会呢?Python的难度到底有多大?今天,小编就来为大家详细解读一下这个问题。...

猫咪编程
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部