Tensorflow学习三—基础操作
Tensorflow包含的数据类型
常见的数据类型载体:
python : list
[1,1.2,“hello”,(1,2)]
numpy : np.array
tensorflow : tf.Tensor
tf.Tensor:
scalar: 1.1
vector(数组): [1.1],[1.1, 2.2, … ]
matrix(矩阵): [[1.1, 2.2],[3.3, 4.4],[5.5, 6.6]]
tensor: 𝑟𝑎𝑛𝑘 > 2(维度大于2)
tensor的数据类型有:int, float, double,bool,string
例子:
1、常数
input:(tf.constant(1))
tf.Tensor(1, shape=(), dtype=int32)
input:(tf.constant(1.))
tf.Tensor(1.0, shape=(), dtype=float32)
input:(tf.constant(2.2,dtype=tf.double))
tf.Tensor(2.2, shape=(), dtype=float64)
input:(tf.constant([True,False]))
tf.Tensor([ True False], shape=(2,), dtype=bool)
input:(tf.constant('hddd'))
tf.Tensor(b'hddd', shape=(), dtype=string)
2、常量值函数
tf.fill(dims, value, name=None)
参数:
- dims: 类型为int32的tensor对象,用于表示输出的维度(1-D, n-D),通常为一个int32数组,如:[1], [2,3]等
- value: 常量值(字符串,数字等),该参数用于设置到最终返回的tensor对象值中
- name: (可选)当前操作别名
3、选择设备数据
with tf.device("cpu"):
a = tf.constant([1])
with tf.device('gpu'):
b = tf.range(4)
/job:localhost/replica:0/task:0/device:CPU:0
/job:localhost/replica:0/task:0/device:GPU:0
4、等差数组
a = np.arange(5)
a = tf.range(5)
5、其他
#转为Tensor
aa = tf.convert_to_tensor(a)
aa = tf.convert_to_tensor(a,dtype=tf.int32)
#数据类型转换
tf.cast(aa,dtype=tf.float32)
a = tf.range(5)
b=tf.Variable(a) #将Tensor有可导属性
print(b.name,b.trainable)
#Variable:0 True
索引切片
索引(indexing)
常规的索引方式:
a = tf.ones([1,5,5,3])
print(a[0][0])
print(a[0][0][0])
numpy索引方式:
a = tf.random.normal([4,28,28,3])
print(a[1].shape)
print(a[1,2].shape)
切片
1、start:end
a = tf.range(10)
#tf.Tensor([0 1 2 3 4 5 6 7 8 9], shape=(10,), dtype=int32)
print(a)
print(a[-1:])
2、start : end : step
= tf.random.normal([4,28,28,3])
print(a[:,0:28:2,:,0].shape)
#(4, 14, 28)
print(a[:,::2,::2,:].shape)
#(4, 14, 14, 3) 0:28:2
3 、…
a = tf.random.normal([2,4,28,28,3])
print(a[0,:,:,:,:].shape)
print(a[0,...].shape)
#(4, 28, 28, 3)
4、tf.gather收集:根据索引收集采样数据
a = tf.random.normal([4,35,8])
#(原,axis=维度,维度的索引)
print(tf.gather(a,axis=0,indices=[2,3]).shape)
#(2, 35, 8)
5、tf.gather_nd
a = tf.random.normal([4,35,8])
print(tf.gather_nd(a,[0]))
print(tf.gather_nd(a,[0,1]))
print(tf.gather_nd(a,[0,1,2]))
print(tf.gather_nd(a,[[0,1,2]]))
print(tf.gather_nd(a,[[0,1],[1,1]]).shape)
#(2, 8)
5、tf.boolean_mask
定义mask
a = tf.random.normal([4,28,28,3])
print(tf.boolean_mask(a,mask=[True,True,False,False]).shape)
#(2, 28, 28, 8)
print(tf.boolean_mask(a,mask=[True,True,False],axis=3).shape)
#(4, 28, 28, 2)
维度变换
每个Tensor都是有一个shape的,例如之前的MNIST数据集来说它的shape就是[b,28,28,1]->[batch,weight,height,channed]。
view(视图):每个数据都是有多种View的看法,例子:
[b,28,28]
[b,28*28]
[b,28,28,1]
1、reshape:
a = tf.random.normal([4,28,28,3])
print(tf.reshape(a,[4,784,3]).shape)
#当你不知道原来的数据的大小就可以使用-1自动计算
print(tf.reshape(a,[4,-1,3]).shape)
#后一个[]恢复大小
print(tf.reshape(a,([4,-1]),[2,28,28,3]).shape)
2、tf.transpose 转置 改变视图
a = tf.random.normal((4,3,2,1))
print(tf.transpose(a).shape)
print(tf.transpose(a,perm=[0,3,2,1]).shape)
这个常用在pytoc<->tensorflow
pytoch中[b,3,h,w] tensorflow[b,h,w,c]
3、expand dim
a = tf.random.normal([4,35,8])
print(tf.expand_dims(a,axis=0).shape)
#(1, 4, 35, 8)
4、squeeze dim
a=tf.zeros([1,2,3,1,2])
print(tf.squeeze(a).shape)
#(2, 3, 2)
print(tf.squeeze(a,axis=0).shape)
#(2, 3, 1, 2)
Broadcasting
什么是Braodcasting,张量维度的扩张手段,他和tf.tile形成对比,它是对张量维度复制但没复制真实数据。
1、使用环境
当两个不同维度的张量进行相加的时候,Tensorflow会自动调用Broadcasting来进行补齐,
或者使用tf.broadcast_to。
2、具体使用流程
当两个不同维度的进行相加的时候小维度对齐,大维度依次补齐。
3、意义
简洁,节省内存
a = tf.random.normal([4,32,32,3])
print((a+tf.random.normal([3])).shape)
#tf.broadcast_to
b=tf.broadcast_to(tf.random.normal([4,1,1,1]),[4,32,32,3])
print(b.shape)
4、broadcast vs tile
a=tf.ones([3,4])
a1=tf.broadcast_to(a,[2,3,4])
print(a1)
"""
tf.Tensor(
[[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]], shape=(2, 3, 4), dtype=float32)
"""
a2=tf.expand_dims(a,axis=0)
a2=tf.tile(a2,[2,1,1])
print(a2)
"""
tf.Tensor(
[[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]], shape=(2, 3, 4), dtype=float32)
"""
数学运算
1、+ - * / // %
2、** pow square sqrt
3、exp log
4、@, matmul 矩阵乘法
向前传播(张量)
作为总结编写一个前向传播使用张量的形式,而不是用层的形式。
依旧是采用之前MNIST数据集的例子。
(x, y), _ = datasets.mnist.load_data()
# x: [0~255] => [0~1.]
x = tf.convert_to_tensor(x, dtype=tf.float32) / 255.
y = tf.convert_to_tensor(y, dtype=tf.int32)
print(x.shape, y.shape, x.dtype, y.dtype)
print(tf.reduce_min(x), tf.reduce_max(x))
print(tf.reduce_min(y), tf.reduce_max(y))
train_db = tf.data.Dataset.from_tensor_slices((x,y)).batch(128)
train_iter = iter(train_db)
sample = next(train_iter)
print('batch:', sample[0].shape, sample[1].shape)
# [b, 784] => [b, 256] => [b, 128] => [b, 10]
# [dim_in, dim_out], [dim_out]
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))
训练+测试
for epoch in range(10): # iterate db for 10
for step, (x, y) in enumerate(train_db): # for every batch
# x:[128, 28, 28]
# y: [128]
# [b, 28, 28] => [b, 28*28]
x = tf.reshape(x, [-1, 28*28])
with tf.GradientTape() as tape: # tf.Variable
# x: [b, 28*28]
# h1 = x@w1 + b1
# [b, 784]@[784, 256] + [256] => [b, 256] + [256] => [b, 256] + [b, 256]
h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0], 256])
h1 = tf.nn.relu(h1)
# [b, 256] => [b, 128]
h2 = h1@w2 + b2
h2 = tf.nn.relu(h2)
# [b, 128] => [b, 10]
out = h2@w3 + b3
# compute loss
# out: [b, 10]
# y: [b] => [b, 10]
y_onehot = tf.one_hot(y, depth=10)
# mse = mean(sum(y-out)^2)
# [b, 10]
loss = tf.square(y_onehot - out)
# mean: scalar
loss = tf.reduce_mean(loss)
# compute gradients
grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
# print(grads)
# w1 = w1 - lr * w1_grad
w1.assign_sub(lr * grads[0])
b1.assign_sub(lr * grads[1])
w2.assign_sub(lr * grads[2])
b2.assign_sub(lr * grads[3])
w3.assign_sub(lr * grads[4])
b3.assign_sub(lr * grads[5])
if step % 100 == 0:
print(epoch, step, 'loss:', float(loss))