Tensorflow2.0学习(十) — 基础张量、微分操作及自定义层

因为再后面一些分享的章节的内容很多是基于经典论文的复现了,里面会牵扯到很多自定义的模型及其变换。而这些内容有些是我们的Keras API 无法完成的,例如Resnet的residual block。因此这一节课我们有必要去学习一些基础、底层的张量、微分运算操作以及明白如何去自定义我们的层。

首先我们要知道我们在前面几个章节所实践的内容格式都是张量形式的。例如,一张图片在Tensorflow模型中表现的形式就是张量。那么什么是张量?它是一个数据容器,通俗来说就是矩阵向任意维度的推广。1维的张量其实就向量,而2维的张量则是我们经常使用的矩阵。在Tensorflow2.0,张量(Tensor)运算可以被GPU或TPU加速,减少我们的运行时间。

一.Tensor(张量)的基础操作

1.导入相关库。

from __future__ import absolute_import,division,print_function
import tensorflow as tf
import numpy as np

2.一些基础操作。

print(tf.add(1, 2)) #数值相加

 

print(tf.add([1,2],[3,4])) #一维向量相加

print(tf.square(5)) #数值求平方

print(tf.reduce_sum([1,2,3])) #全部数相加

x = tf.matmul([[1]],[[2,3]]) #矩阵相乘
print(x)

3.查看向量尺寸、类型。

print(x.shape)
print(x.dtype)

4.Tensor和numpy的ndarray进行转换。在使用tensorflow的tensor运算时,如果有遇到ndarray格式的数据,它会默认将它转为Tensor的形式进行运算。同样地,如果在使用numpy进行运算时,碰到tensor,它也会自动将其转为ndarray进行运算。

ndarry = np.ones([3,3]) #3x3的ndarray格式的单位矩阵
tensor = tf.multiply(ndarry,2)
print(tensor)

print(np.add(tensor,1))

二.Tensor(张量)的自动微分

1.我们可以使用 GradientTape()函数进行自动微分操作求梯度。其中watch函数的作用是跟踪变量,而assert函数则是判断该语句是否有异常。如果语句结果不等,则会报错。我们可以看到我们用gradient函数对z求了微分。而z的函数为y^2,对y求导则是2y,因为y的值又等于x值的和(4),因此最后结果等于2x4=8。

x = tf.ones((2, 2))

with tf.GradientTape() as t:
    t.watch(x) #跟踪变量
    y = tf.reduce_sum(x)
    z = tf.multiply(y, y)

dz_dy = t.gradient(z, y)
assert dz_dy.numpy() == 8.0

2.因为使用了python的with...as函数语句,因此在第一次gradient之后,GradientTape的资源就会释放了。那如果我们要进行两次gradient操作,要怎么办?我们可以通过在GradientTape后加一个persistent(持续)参数来解决,并最后再用del语句释放资源。

x = tf.constant(3.0) #常数
with tf.GradientTape(persistent=True) as t: #资源不释放
    t.watch(x) #跟踪变量
    y = x*x
    z = y*y
dz_dx = t.gradient(z,x)  # z=x^4,求导后为4x^3,x代入则为4*3*3*3=108
dy_dx = t.gradient(y,x) # y = x^2,求导后为2x,x代入则为2*3=6
print(dz_dx)
print(dy_dx)
del t #释放资源

3.所求的梯度还可以进行二次微分。

x = tf.Variable(1.0)
with tf.GradientTape() as t:
    with tf.GradientTape() as t2:
        y = x*x*x
    dy_dx = t2.gradient(y,x) # y=x^3,求导为3x^2,x代入则为3
d2y_dx2 = t.gradient(dy_dx,x) #dy_dx为3x^2,求导为6x,x代入则为6

assert dy_dx.numpy() == 3.0
assert d2y_dx2.numpy() == 6.0

三.自定义层

1.这里以一个自定义层的例子来解释怎么自定义我们所需要的层。首先我们需要定义一个类,相关语法可以参照python类语法。其中类中传入的函数是继承了keras的layers层函数,__init__层则是传入一些我们需要的参数,这些参数也是我们在调用时必须传入的。而build函数则规定了一些层输入的尺寸大小。call函数则是前向传播过程。

class MyDenselayer(tf.keras.layers.Layer):
    def __init__(self,num_outputs):
        super(MyDenselayer,self).__init__()
        self.num_outputs = num_outputs
        
    def build(self,input_shape):
        self.kernel = self.add_variable('kernel',shape=[int(input_shape[-1]),self.num_outputs])
    
    def call(self,input):
        return tf.matmul(input,self.kernel)

layer = MyDenseLayer(10)

 

以上就是本节的内容。更多相关的操作和应用,我会在后面的系列内容中体现出来,方便大家更进一步理解。谢谢你们的观看和支持!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章