欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PaddlePaddle的静态图与动态图

程序员文章站 2024-01-19 12:40:52
...

本篇为《深度学习》系列博客的第十一篇,该系列博客主要记录深度学习相关知识的学习过程和自己的理解,方便以后查阅。

今天想着把自己的网络结构用VisualDL看一下,然后发现了save函数,然后函数的输入变量是fluid.default_main_program(),就想着改变一下程序, 写了一中午,就是调试不通,才发现是静态图和动态图的问题!!!

静态图与动态图的概念

目前神经网络框架分为静态图框架动态图框架,PyTorch 和 TensorFlow、Caffe 等框架最大的区别就是他们拥有不同的计算图表现形式
TensorFlow 使用静态图,这意味着我们先定义计算图,然后不断使用它,而在 PyTorch 中,每次都会重新构建一个新的计算图。

他们之间的区别和差异如下:
动态计算意味着程序将按照我们编写命令的顺序进行执行。
这种机制将使得调试更加容易,并且也使得我们将大脑中的想法转化为实际代码变得更加容易
静态计算则意味着程序在编译执行时将先生成神经网络的结构,然后再执行相应操作。而静态计算是通过先定义后运行的方式,之后再次运行的时候就不再需要重新构建计算图,所以速度会比动态图更快
从理论上讲,静态计算这样的机制允许编译器进行更大程度的优化,但是这也意味着你所期望的程序与编译器实际执行之间存在着更多的代沟。这也意味着,代码中的错误将更加难以发现。

静态图与动态图代码对比

使用tensorflow实现静态图代码

# tensorflow
import tensorflow as tf
first_counter = tf.constant(0)
second_counter = tf.constant(10)
# tensorflow
import tensorflow as tf
first_counter = tf.constant(0)
second_counter = tf.constant(10)
def cond(first_counter, second_counter, *args):
    return first_counter < second_counter
def body(first_counter, second_counter):
    first_counter = tf.add(first_counter, 2)
    second_counter = tf.add(second_counter, 1)
    return first_counter, second_counter
c1, c2 = tf.while_loop(cond, body, [first_counter, second_counter])
with tf.Session() as sess:
    counter_1_res, counter_2_res = sess.run([c1, c2])
print(counter_1_res)
print(counter_2_res)

可以看到 TensorFlow 需要将整个图构建成静态的,换句话说,每次运行的时候图都是一样的,是不能够改变的,所以不能直接使用 Python 的 while 循环语句,需要使用辅助函数 tf.while_loop 写成 TensorFlow 内部的形式.

使用PyTorch实现动态图代码

# pytorch
import torch
first_counter = torch.Tensor([0])
second_counter = torch.Tensor([10])
 
while (first_counter < second_counter)[0]:
    first_counter += 2
    second_counter += 1
 
print(first_counter)
print(second_counter)

可以看到 PyTorch 的写法跟 Python 的写法是完全一致的,没有任何额外的学习成本。

使用PaddlePaddle实现静态图和动态图代码

使用PaddlePaddle实现静态图代码

import paddle.fluid as fluid
import numpy as np

x_np = np.random.rand(1).astype("float32")
y_np = np.random.rand(1).astype("float32")

x = fluid.data( shape=[1], name="x", dtype="float32")
y = fluid.data( shape=[1], name="y", dtype="float32")

z = fluid.layers.cond( x > y, lambda: x + y, lambda: x -y)

exe = fluid.Executor()
out = exe.run(fluid.default_main_program(), 
			  feed={ "x" : x_np, "y" : y_np}, 
			  fetch_list=[z])
print( out )

使用PaddlePaddle实现动态图代码

import paddle.fluid as fluid
import numpy as np

fluid.enable_imperative()# 该接口打开动态图模式。

x_np = np.random.rand(1).astype("float32")
y_np = np.random.rand(1).astype("float32")

x = fluid.dygraph.to_variable( x_np )  
y = fluid.dygraph.to_variable( y_np )

z =  x + y if x > y else x -y

print(z.numpy())

使用PaddlePaddle实现静态图和动态图的卷积代码

使用PaddlePaddle实现静态图卷积代码

import paddle.fluid as fluid
import numpy as np

data = fluid.layers.data(name='data', shape=[3, 32, 32], dtype='float32')
param_attr = fluid.ParamAttr(name='conv2d.weight', initializer=fluid.initializer.Xavier(uniform=False), learning_rate=0.001)

res = fluid.layers.conv2d(input=data, num_filters=2, filter_size=3, act="relu", param_attr=param_attr)

place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())

x = np.random.rand(1, 3, 32, 32).astype("float32")

output = exe.run(feed={"data": x}, fetch_list=[res])

print(output)

使用PaddlePaddle实现动态图卷积代码

from paddle.fluid.dygraph.base import to_variable
import paddle.fluid as fluid
from paddle.fluid.dygraph import Conv2D
import numpy as np

x = np.random.rand(1, 3, 32, 32).astype("float32")

with fluid.dygraph.guard():
    conv2d = Conv2D(num_channels=3,
                    num_filters=2,
                    filter_size=3,
                    act='relu')
    data = to_variable(x)
    conv = conv2d(data)

    print(conv.numpy())

参考文章:
机器学习中常见的动态图和静态图
一文搞懂飞桨静态图与动态图(从API分清描述式编程与命令式编程的区别)