TensorFlow学习笔记—基础操作

TensorFlow

在上篇博客:深度学习笔记—线性回归(实战)中,我们使用了常规方法实现Boston房价的预测,效果很明显——费力不讨好,代码实现复杂,基本上是公式的实现,耗费时间长,损失下降不明显,如果我们真拿这个去交付给用户使用,恐怕会被骂个狗血淋头,所以我们得建立一个更好的,效率更高的,更稳定的模型。
人和动物的区别就是是否会使用工具,我们要想更高效的建立和训练模型,也需要学会使用工具—TensorFlow
TensorFlow是一个基于数据流编程(dataflow programming)的符号数学系统,被广泛应用于各类机器学习(machine learning)算法的编程实现,其前身是谷歌的神经网络算法库DistBelief 。
Tensorflow拥有多层级结构,可部署于各类服务器、PC终端和网页并支持GPU和TPU高性能数值计算,被广泛应用于谷歌内部的产品开发和各领域的科学研究 。
TensorFlow由谷歌人工智能团队谷歌大脑(Google Brain)开发和维护,拥有包括TensorFlow Hub、TensorFlow Lite、TensorFlow Research Cloud在内的多个项目以及各类应用程序接口(Application Programming Interface, API) 。自2015年11月9日起,TensorFlow依据阿帕奇授权协议(Apache 2.0 open source license)开放源代码 (摘自百度百科) 。
简单来说,TensorFlow就是一个核心开源库,可以帮助我们开发和训练机器学习模型,如果想了解具体信息可以访问TensorFlow官网进行了解,在这里我们就不赘述了。

TensorFlow基础

  1. TensorFlow中的数据类型

在上一节的代码实现中,我们用了python自带的数据类型和numpy的数据类型,但是这些数据类型都是早于TensorFlow出现的,导致这些数据类型在TensorFlow不能很好的使用,比如numpy中的array数据类型就不能自动求导,也不能支持GPU运算,所以TensorFlow自己定了了一种数据类型tensor,简单来讲,tensor就是TensorFlow可以接受的数据,几乎所有的数据都可以叫做tensor,包括而不仅限于:

  • 标量(scalar)

标量就是一个单独的数。

  • 向量(vector)

一个向量是一列数

  • 矩阵(matrix)

矩阵是一个二维数组

  • 张量(tensor)

一般的,一个数组中的元素分布在若干维坐标的规则网格中,我们称之为张量。

tensor支持的数据类型

  • int float double
  • bool
  • string

action:tensor支持的所有数据类型都要用tf.int或tf.string等这种表示方法。
我们从名字发现一个很有趣的东西,TensorFlow支持的数据类型为tensor,名字为TensorFlow的前一部分单词,剩下的单词为Flow,意为滑动,流动的意思。这生动的解释了TensorFlow的原理,数据在管道中流动处理,再从出口出来,给出我们想要的结果。

  1. 创建tensor

TensorFlow提供了大量功能丰富且繁杂的API接口供使用者调用,除了很复杂的操作外,初学者总能很轻易的找到合适的API实现你想要的功能

但是在使用TensorFlow之前,首先要导入TensorFlow库:

import tensorflow as tf

首先我们来创建一个tensor:

From Numpy List

因为TensorFlow的出现要晚于numpy的出现,所以TensorFlow设计的很多功能和API都学习了numpy的设计,并且对numpy的数据结构也专门设计了方法进行转换:

convert_to_tensor()

convert_to_tensor(
    value,
    dtype=None,
    name=None,
    preferred_dtype=None
)

from Numpy

tf.convert_to_tensor(np.ones([2,3]))
tf.convert_to_tensor(np.zeros([2,3]))

该API可numpy中的矩阵直接转换为tensor,并且不仅限于numpy中矩阵,对于list也可直接转化:

tf.convert_to_tensor([1,2])
tf.convert_to_tensor([1,2.])
tf.convert_to_tensor([1],[2.])

我们可以观察第一行代码和第二行代码,唯一的区别就是第一行第二列的数据类型不同,该API可自动配合合适的数据类型。而第二行和第三行代码的区别则是数据维度不同,在这里我们不再赘述。

constant()

tf.constant(
    value,
    dtype=None,
    shape=None,
    name='Const',
    verify_shape=False
)

创建一个张量,传入list或者数值来填充

使用示例:

tf.constant(1)
tf.constant([1])
tf.constant([1,2.])
tf.constant([1,2.],[3.])#错误用法

注意,若传入多维数据,则每个维度上的数据数量必须一致,否则将发生错误。

zeros() and ones()

tf.zeros(
    shape,
    dtype=tf.float32,
    name=None
)

tf.ones(
	shape,
	dtype=tf.float32, 
	name=None
)

用法示例

tf.zeros([])
tf.zeros([1])
tf.zeros([2,2])
tf.zeros([2,3,3])

tf.ones(1)
tf.ones([2])
tf.ones([2,3])

zeros()和ones() 就像一对孪生兄弟,输入想要的维度,API自动帮你填充0或1,一目了然。

zeros_like() and ones_like()

tf.zeros_like(
		tensor, 
		dtype=None, 
		name=None
)

tf.ones_like(
		tensor,
		dtype=None, 
		name=None
 )

用法示例

a = tf.zeros([2,3,3])
tf.zeros_like(a)
tf.ones_like(a)

除去去ones孪生兄弟外,tensorflow还提供了ones_lie()这对孪生兄弟,但是不同的是,ones兄弟需要给定tensor维度,而ones_like()兄弟则需要给定一个tensor作为参数,该API按照tensor的维度重新建立一个tensor。

fill()

tf.fill(
		dims, 
		value, 
		name=None
	)

dims: 类型为int32的tensor对象,用于表示输出的维度(1-D, n-D),通常为一个int32数组,如:[1], [2,3]等

value: 常量值(字符串,数字等),该参数用于设置到最终返回tensor对象中的值

name: (可选)当前操作别名

用法示例:

tf.fill([2,2],0)
tf.fill([2,2],0.0)
tf.fill([2,2],1)

fill()是一种很灵活的建立tensor的方法,只需要修改填入的数值就可以很轻松的取代ones兄弟和ones_like()兄弟。

random.normal()

用于从服从指定正太分布的数值中取出随机数。一般用于参数初始值的赋值。

tf.random_normal(
    shape,
    mean=0.0,
    stddev=1.0,
    dtype=tf.float32,
    seed=None,
    name=None
)

shape: 输出张量的形状,必选

mean: 正态分布的均值,默认为0

stddev: 正态分布的标准差,默认为1.0

dtype: 输出的类型,默认为tf.float32

seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样

name: 操作的名称

使用示例:

tf.random.normal([2,2],mean=1,stddv=1)#正态分布 均值 方差
tf.random.normal([2,2])#默认均值方差均为0

random.truncated_normal()

输出截断的正态分布的随机值。说的简单些,就是输出正态分布的一部分。

tf.random.truncated_normal(
    shape,
    mean=0.0,
    stddev=1.0,
    dtype=tf.dtypes.float32,
    seed=None,
    name=None
)

shape:一个一维整数张量或Python数组。输出张量的形状。

mean:一个零维张量或Python值,类型为dtype。截断正态分布的均值。均值默认为0

stddev:一个零维张量或Python值,类型为dtype。正态分布的标准偏差,在截断。截断前正态分布的标准偏差,默认为1.0

dtype:输出的类型。

seed:一个Python整数。用于为分布创建随机种子。

名称:操作的名称(可选)。

使用示例:

tf.random.truncated_normal([2,2],mean=0,stddev=1)#截断方差

random.uniform()

random_uniform(
    shape,# 生成的张量的形状
    minval=0,
    maxval=None,
    dtype=tf.float32,
    seed=None,
    name=None
)

shape:一维整数张量或 Python 数组.输出张量的形状
.
minval:dtype 类型的 0-D 张量或 Python 值;生成的随机值范围的下限;默认为0.

maxval:dtype 类型的 0-D 张量或 Python 值.要生成的随机值范围的上限.如果 dtype 是浮点,则默认为1 .

dtype:输出的类型:float16、float32、float64、int32、orint64.

seed:一个 Python 整数.用于为分布创建一个随机种子.查看
tf.set_random_seed 行为.

name:操作的名称(可选).

使用示例:

tf.random.uniform([2,2],minval=0,maxval=1)#均匀分布
tf.random.uniform([2,2],minval=0,maxval=10)

跟random.normal()类似,random.uniform()同样是给出随机值,便于参数更新。

  1. 索引与切片

我们在学习java,c,以及python等编程语言时,可以很方便的使用指针或者或者索引解决找位置的为题,在tensorflow中,为了方便寻找数据,也提供了功能强大是索引方法,与java数组中的索引方式类似。

方法一

import tensorflow as tf
import numpy as np
a = tf.ones([1,5,5,3])
#(1, 5, 5, 3)
print(a.shape)
(5, 3)
print(a[0][0].shape)
#(3,)
print(a[0][0][0].shape)
#()
print(a[0][0][0][2].shape)

tensorflow中的索引方式与numpy矩阵中的索引方式类似,用法也极为相像。

方法二

import tensorflow as tf
a = tf.range(10)
print(a)
print(a[3:5].shape)
#(1.)
print(a[-1:].shape)

注意:此方法仅适用于向量。

方法三

import tensorflow as tf
import numpy as np
a = tf.ones([5,5,5,5])
#(5,5,5)
print(a[2,:,:,:].shape)
#(5,5)
print(a[2,2,:,:].shape)
#(5,5,5)
print(a[:,:,:,3].shape)

:用来占位,即表示该维度全选。

方法四

import tensorflow as tf
import numpy as np
a = tf.ones([5,5,5,5])
#(1,5,5,5)
print(a[2:3,:,:,:].shape)
#(3,5,5,5)
print(a[2:,:,:,:].shape)
#(2,1,5,5)
print(a[2:,2,:,:].shape)

实际上这种切片方法很像是方法二和方法三的混合体,实际上效果也是验证了。

以上四种方法虽然能很便捷的截取tensor的一部分,但是都存在局限性,只能选取某一维度上的某一位置的所有数据,或者是某 一维度上的某几个连续位置上的所有数据,这明显不方便我们对数据使用和处理,所以tensor也提供了几个特殊的方法,满足我们的需求。

gather

gather(
    params,
    indices,
    validate_indices=None,
    name=None
)

params:是一个tensor,

indices:是个值为int的tensor用来指定要从params取得元素的第0维的index。

validate_indices:针对哪一维度进行的操作。

name:操作的名字。

使用示例:

import tensorflow as tf
import numpy as np
a = tf.random.normal([2,4,28,28,3])
#(2, 2, 28, 28, 3)
print(tf.gather(a,axis=1,indices=[2,3]).shape)


gather一词是收集的意思,从结果上我们可以很清楚的看到,确实是收集,针对某一维度的某几个不连续的位置进行数据提取操作,并且组成一个新的张量。

gather_nd

gather_nd(
    params,
    indices,
    name=None
)

params:张量.这个张量是用来收集数值的.

indices:张量.必须是以下类型之一:int32,int64;索引张量.

name:操作的名称(可选).

使用示例:

import tensorflow as tf
import numpy as np
a = tf.random.normal([2,4,28,28,3])
#(4, 28, 28, 3)
print(tf.gather_nd(a,[0]).shape)
#(28, 28, 3)
print(tf.gather_nd(a,[0,1]).shape)
#(28, 3)
print(tf.gather_nd(a,[0,1,2]).shape)
#(1, 28, 3)
print(tf.gather_nd(a,[[0,1,2]]).shape)
#(3, 4, 28, 28, 3)
print(tf.gather_nd(a,[[0],[1],[2]]).shape)
#(2, 28, 28, 3)
print(tf.gather_nd(a,[[0,1],[1,3]]).shape)

从示例中我们可以看到,gather_nd()是一个比gather更为灵活的方法,不仅可以java中索引式取某一维度上所有的数据,还能像gather()方法一样,只取部分数据,并且合并成一个新的张量。

boolean_mask()

tf.boolean_mask(
    tensor,
    mask,
    name='boolean_mask',
    axis=None
)

tensor:N维度的tensor,

mask:由布尔值构成的K维度的列表,注意K小于等于N,

name:可选项也就是这个操作的名字,

axis是一个0维度的int型数字,表示的是从参数tensor的哪个axis开始过滤。

使用示例:

a=tf.random.normal([4,28,28,3])
#([2, 28, 28, 3])
print(tf.boolean_mask(a,mask=[True,True,False,False]).shape)
#([4, 28, 28, 2])
print(tf.boolean_mask(a,mask=[True,True,False],axis=3).shape)

boolean_mask 是依据索引出的TRUE和False值判断是否去该维度的数据,如果仅仅只是那么简单,为什么还要设计这个功能呢,岂不是重复了,所以boolean_mask的功能没有那么简单。

import tensorflow as tf
import numpy as np
a = tf.random.normal([2,3,4])
#(4,4)
print(tf.boolean_mask(a,mask=[[True,False,True],[False,True,True]]).shape)
#(3,4)
print(tf.boolean_mask(a,mask=[[True,False,False],[False,True,True]]).shape)

在boolean_mask()函数中,将mask参数换成多维列表,则可以与tensor中的维度相对应取值,更为方便快捷。

  1. 维度变换
    reshape
tf.reshape(
    tensor,
    shape,
    name=None
)

tensor:需要进行维度变换的的张量。

shape:张量要变成的形状。

name:操作名称。

使用示例:

import tensorflow as tf
import numpy as np
a = tf.random.normal([4,28,28,3])
#(4, 784, 3)
print(tf.reshape(a,[4,28*28,3]).shape)
#(4, 784, 3)
print(tf.reshape(a,[4,-1,3]).shape)
#
print(tf.reshape(a,[4,-1]).shape)
#(4, 1, 784, 3)
print(tf.reshape(tf.reshape(a,[4,-1]),[4,-1,784,3]))

transpose()

tf.transpose(
    matrix,
    perm=None
    )

matrix:待变换的张量。

perm:张量变换方式的具体参数。

使用示例:

import tensorflow as tf
import numpy as np
a = tf.random.normal([4,28,28,3])
#(3, 28, 28, 4)
print(tf.transpose(a).shape)
#(4, 28, 3, 28)
print(tf.transpose(a,perm=[0,1,3,2]).shape)

从使用示例上来看,transpose方法和reshape方法在功能上有些重合,但是在transpose方法更为灵活,在不指定matrix参数时,transpose方法默认将tensor的维度倒序,同时在指定matrix参数指定为列表时,会按照列表排序来变换。

expand_dims()

tf.expand_dims(
    input,
    axis=None,
    name=None,
    dim=None
)

input是输入张量。

axis是指定扩大输入张量形状的维度索引值。

dim等同于轴,一般不推荐使用。

使用示例;

import tensorflow as tf
import numpy as np
a = tf.random.normal([4,28,28,3])
#(1, 4, 28, 28, 3)
print(tf.expand_dims(a,axis=0).shape)
#(4, 28, 28, 3, 1)
print(tf.expand_dims(a,axis=-1).shape)

从示例中我们可以很清楚的看出来,expand_dims()方法用于向张量中加入一个新的维度,而axis参数可控制添加维度的位置。

squeeze()

squeeze(
    input,
    axis=None,
    name=None,
    squeeze_dims=None
)

input: 需要压缩的tensor

axis: 如果指定,只能挤压列出的维度。维度索引从 0 开始。压缩非 1 的维度是错误的,并且必须在范围内。
name: 操作的名称 (可选)

squeeze_dims: 已弃用的关键字参数,现在是axis。

使用示例:

import tensorflow as tf
import numpy as np
a = tf.random.normal([4,28,28,3])
#(2, 3)
print(tf.squeeze(tf.zeros([1,2,1,1,3])).shape)
b =  tf.ones([1,2,1,3])
#(2, 1, 3)
print(tf.squeeze(b,axis=0).shape)
#(1, 2, 3)
print(tf.squeeze(b,axis=2).shape)

该函数返回一个张量,这个张量是将原始input中所有维度为1的那些维都删掉的结果
axis可以用来指定要删掉的为1的维度,此处要注意指定的维度必须确保其是1,否则会报错。如果axis不指定,则默认删除所有为1的维度。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值