1.tensorflow基础操作
1.1数据类型
tensor
tensorflow数据类型和numpy相似,主要有整型,浮点型和布尔型
import tensorflow as tf
# 整型
t1 = tf.constant(1)
# 浮点型
t2 = tf.constant(2.)
# 指定数据类型
t3 = tf.constant(2.,dtype=tf.double)
# 布尔类型
t4 = tf.constant(False)
print(t1,t2,t3,t4)
1.2基本操作
1.2.1将tensor数据转化成numpy数据、判断数据是否属是tensor类型、查看数据维度
import tensorflow as tf
import numpy as np
# 设定tensorflow环境,默认为第一张显卡环境
with tf.device('cpu'):
t1 = tf.constant(1.)
with tf.device('gpu'):
t2 = tf.range(3)
# 使用tensor自带的方法将数据转化为numpy的类型
np1 = t2.numpy()
print(t1.device + '\n' + t2.device)
print(t2,np1)
# 显示tensor数据的维度,使用ndim
# 单个数字是0维,一个数组是一维
shape1 = t1.ndim
shape2 = t2.ndim
print(shape1,shape2)
# 检验一个数据是否为tensor类型tf.is_tensor()
t3 = np.arange(4)
is_tensor1 = tf.is_tensor(t1)
is_tensor2 = tf.is_tensor(t3)
print('判断是否为tensor\nt1:{}\nt3:{}'.format(is_tensor1,is_tensor2))
1.2.2numpy转化为tensor类型、cast方法、Variable类型
import tensorflow as tf
import numpy as np
# 定义一个np数组
a = np.arange(4)
print(a.dtype)
print('a:{}'.format(a))
# 使用convert_to_tensor方法将numpy数据转化成Tensor类型数据,转化后的默认数据类型为tf.int32
b = tf.convert_to_tensor(a)
print(b)
# 使用cast函数将tf.int32类型转化为tf.float32
c = tf.cast(b,dtype=tf.float32)
print(c)
# 将tensor的整型转化成布尔型
d = tf.constant([0,1])
dd = tf.cast(d,dtype=tf.bool)
print(d,dd)
# 将b转化为Variable,转化后可使用数据的trainable属性查看其可训练性
# variable可以将变量标记为用于训练的数据,后续会对该数据进行跟踪
bb = tf.Variable(b,name='input_data')
print(bb.trainable)
1.2.3创建tensor类型数据的方法
import tensorflow as tf
import numpy as np
# 创建tensor的方式
# 将numpy矩阵转换成tensor数据类型
a = tf.convert_to_tensor(np.ones([2,3]))
print(a)
# 转化tensor数据类型
a = tf.cast(a,dtype=tf.float32)
print(a)
# 将list类型数据转化为tensor数据类型
b = tf.convert_to_tensor([1,2,3])
print(b)
# 使用tf内置方法直接创建
# 创建一个scalar,即一个数字
c1 = tf.zeros([])
print(c1)
# 创建一维内容为0的数组
c2 = tf.zeros([1])
print(c2)
# 创建一个内容为0的矩阵
c3 = tf.zeros([2,3])
print(c3)
# 使用zeros_like方法进行创建相似0矩阵
c4 = tf.zeros_like(c3)
print('c4使用zeros_like方法进行创建相似0矩阵')
print(c4)
c5 = tf.zeros(c3.shape)
print('c5效果等同以上方法')
print(c5)
# tf.fill方法创建全部为某个数的矩阵
d = tf.fill([2,2],3)
print('使用full方法创建全部为某个数的矩阵')
print(d)
# 随机方式创建tensor
# 正态分布使用random.normal,其中mean为正态分布均值,stddev为方差
e = tf.random.normal([2,2],mean=1,stddev=1)
print(e)
# 平均分布minval为最小值,maxval为最大值
f = tf.random.uniform([2],minval=0,maxval=10)
print(f)
# 截断的正态分布的数据,会将梯度较小的部分去除掉而在梯度较大的区域重新采样
g = tf.random.truncated_normal([2,3],mean=2,stddev=0.2)
print('截断式的正态分布',g)
one_hot用法
tf.one_hot(indices, depth)
- indices
:需要进行编码的整数数组。
- depth
:编码后向量的长度,即类别的个数。
1.2.4切片
有规律的切片方式
import tensorflow as tf
import numpy as np
a = tf.random.uniform([4,28,28,3])
# numpy方式索引,相比于传统索引不需要使用太多[]
a1 = a[1,2].shape
print(a1)
a2 = a[1,2,3].shape
print(a2)
# 切片,方向是由step决定的,step若为正数则为从左至右,反之从右至左
# 语法格式:start:end:step
b = tf.range(10)
b1 = b[-1:]
b2 = b[:-1]
b3 = b[-2:-1]
print(b1)
print(b2)
print(b3)
# 可以使用:对每一个维度进行切片,最后切除出不同的matrix的shape
c = tf.random.uniform([4,28,28,3])
c1 = c[0,:,:,:].shape
c2 = c[:,::2,::3,:].shape
c3 = c[:,:14,3:4,2].shape
print(c1)
print(c2)
print(c3)
# 省略号代替若干个:
c4 = c[0,...].shape
print(c4)
指定切片
import tensorflow as tf
a = tf.random.uniform([4,35,8])
# 对一个维度进行取样
# gather中第一个参数为要切片的数组,第二个参数axis为要切片维度,第三个数组indices是自定义要取该维度的哪些切片
a1 = tf.gather(a,axis=1,indices=[3,4,5]).shape
print(a1)
# tf.gather_nd可对多个维度进行取样
# tf.gather_nd中第二个参数接受一个数组,数组的每个数字决定原数据对应维度取哪一行
a2 = tf.gather_nd(a,[1,3]).shape
print(a2)
# 数组的元素可以是数组,每个内部数组决定一个取样(即一个独立的矩阵),所有的取样最后形成一个矩阵
# 每个内部数组中的数字对应的位置决定取对应维的哪一行若内部数组[1,2]表示取第一维的1和第二维的2
# tf.gather_nd最终结果是每个内部数组采样的矩阵叠加成更高维的矩阵
# 注意,每个内部数组的长度都应该一样,以便每次采样都能有相同规格的矩阵
a3 = tf.gather_nd(a,[[1],[0]]).shape
print('a3:',a3)
1.3维度变换
1.3.1普通操作——对维度真实操作
import tensorflow as tf
a = tf.random.normal([4,28,28,3])
print(a.shape)
# 使用tf.reshape对矩阵的维度进行变换
a1 = tf.reshape(a,[4,784,3]).shape
print(a1)
# 变换后的维度像素总数应该是一样的!!!
# a2 = tf.reshape(a,[4,783,3]).shape
# print(a2)
# 要变换的维度可以使用-1来代替,程序会自动将对应维度填充
a3 = tf.reshape(a,[4,-1,3]).shape
print(a3)
# 转置
b = tf.random.normal([1,2,3,4])
print('b改变前:',b.shape)
# tf.transpose中的perm参数用于指定转置后的矩阵每一个维度对应原本是哪一个维度
b1 = tf.transpose(b,perm=[0,1,3,2]).shape
print('b转置后:',b1)
# 增加维度,axis参数指定的维数是就是要插入的维度位置,原本维度进行后移
c = tf.random.normal([4,35,8])
print(c.shape)
c1 = tf.expand_dims(c,axis=0).shape
print('在第一维前面增加一维:',c1)
c2 = tf.expand_dims(c,axis=3).shape
print('在最后一维后面增加一维:',c2)
c3 = tf.expand_dims(c,axis=2).shape
print('在中间维增加一维:',c3)
# 减少维度
d = tf.random.normal([1,2,1,1,3])
# 使用tf.squeeze可以清除全部为一维的维度,也可以指定清除某一维度
d1 = tf.squeeze(d).shape
print('将一维全部清除:',d1)
d2 = tf.squeeze(d,axis=0).shape
print('清除第一个维度:',d2)
# 只能清除维度为一维的,否则会报错
# d3 = tf.squeeze(d,axis=1).shape
# print('清除第二个维度:',d3)
1.3.2Broadcasting
用于tensorflow矩阵相加时将维度进行统一,但是被拓展的数组并不是真正的在内存中进行扩展,而是以假设的方式对矩阵进行扩展,然后进行运算,这样可以节省存储和运算资源
# 表示将a扩展为shape为[2,3,4]的矩阵
b = tf.broadcast_to(a,[2,3,4])
1.4数学运算
import tensorflow as tf
a = tf.fill([2,2],2.)
b = tf.ones([2,2])
# +-//基本运算
print('a+b:',a+b)
print('a/b:',a/b)
print('a//b:',a//b)
# tf.math.log,tf.exp
print('log(b):',tf.math.log(b))
# exp()表示以e为底的指数函数
print('e^b:',tf.exp(b))
# 矩阵运算@和tf.matmul
c = tf.ones([4,2,3])
d = tf.fill([4,3,5],2.)
print('c@d:',c@d)#等价于print(tf.matmul(c,d))
1.5实战-前向传播
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets
import os
# 设置CPP环境,使其运行时只打印错误信息,而不打印无关信息
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# 加载mnist数据集,
# x:[60k,28,28]
# y:[60k]
(x, y), _ = datasets.mnist.load_data()
# 将获取的数据转化为tensor格式
# 使得x取在0-1,y取在0-9
x = tf.convert_to_tensor(x,dtype=tf.float32)/255.
y = tf.convert_to_tensor(y,dtype=tf.int32)
print(x.shape,x.dtype,y.shape,y.dtype)
print(tf.reduce_max(x),tf.reduce_min(x))
print(tf.reduce_max(y),tf.reduce_min(y))
# 将数据集切片成样本,使用batch设定每个样本含有128张照片
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]
# 将数据定义为可循训练数据,即转化为tf.Variable类型
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]))
# 定义减缓因子
lr = 1e-3
# 外层决定数据的训练次数
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]
# 将每个batch进行reshape
x = tf.reshape(x, [-1, 28*28])
# 加载用于求梯度训练环境,tf.GradientTape(),并使用tape对变量进行求导
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的类型依旧为tf.Variable类型
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))
1.6合并与分割
import tensorflow as tf
a = tf.ones([2,35,8])
b = tf.ones([4,35,8])
# 合并操作要求除合并的列可以不同,其他的维度必须相同
# tf.concat对矩阵进行融合,不会改变原有的shape
c = tf.concat([a,b],axis=0)
print(c.shape)
bb = tf.ones([4,35,8])
# tf.stack对矩阵进行融合会改变原有的shape
d = tf.stack([b,bb],axis=0)
print(d.shape)
# tf.unstack将矩阵进行分割,会根据指定的维度将矩阵分割为该维度对应的数字个数的矩阵
e = tf.unstack(b,axis=2)
print(len(e))
print(e[0].shape,e[2].shape)
# tf.split可以指定每个矩阵本分割的大小
f = tf.split(b,axis=2,num_or_size_splits=[3,3,2])
print(f[0].shape,f[2].shape)
1.7张量排序
sort
import tensorflow as tf
# 使用tf.random.shuffle对数组进行打乱
a = tf.random.shuffle(tf.range(5))
# tf.sort对数组进行排序
a1 = tf.sort(a,direction='DESCENDING')
a2 = tf.sort(a,direction='ASCENDING')
print(a1)
print(a2)
# tf.argsort返回最值的位置,依次类推
print(a)
a3 = tf.argsort(a,direction='DESCENDING')
print(a3)
# 使用切片器tf.gather根据排序的位置列表对烟油列表进行排序
b = tf.gather(a,indices=a3)
print(b)
top_k:前多少位
res.indices表示原本矩阵的下标
res.values表示排序后的值
1.8填充与复制
import tensorflow as tf
c = tf.random.normal([4,28,28,3])
print(c.shape)
# 使用pad对矩阵进行填充,内部列表第一个表示对第一个维度填充,第二个列表是对第二个维度的填充
# 注意列表数要和维度数一致
c1 = tf.pad(c,[[0,0],[2,2],[2,2],[0,0]]).shape
print(c1)
a = tf.reshape(tf.range(9),[3,3])
print(a)
# tf.title中的列表参数表示矩阵朝着第一维方向复制0次,朝第二维方向复制1次
b = tf.tile(a,[1,2])
print(b)
1.9张量限幅
import tensorflow as tf
a = tf.range(10)
print(a)
# 数组a中大于2
a1 = tf.maximum(a,2)
# 数组a中小于8
a2 = tf.minimum(a,8)
a3 = tf.clip_by_value(a,2,8)
# a4 , _ = tf.clip_by_global_norm(a,10)
print(a1)
print(a2)
print(a3)
1.10高阶操作
scatter_nd
where
import tensorflow as tf
a = tf.random.normal([3,3])
# 对数据进行筛选
mask = a > 0
print(a)
print(mask)
# 使用tf.where找出标记为true的元素的位置
indices = tf.where(mask)
print(indices)
# 使用gather_nd找出这些被标记的元素
res = tf.gather_nd(a,indices)
print(res)
x = tf.linspace(0., 2*3.14, 500)
y = tf.linspace(0., 2*3.14, 500)
# 使用tf.meshgrid创建所有点的坐标轴系,x:[500, 500],y:[500, 500]
point_x, point_y = tf.meshgrid(x, y)
# [500, 500, 2]
# 使用tf.stack对两个矩阵进行合并
points = tf.stack([point_x, point_y], axis=2)
# points = tf.reshape(points, [-1, 2])
print('points:', points.shape)
2.深度学习入门
2.1数据集加载
import tensorflow as tf
from tensorflow.keras import datasets
# 获取数据
# x,y存放训练数据,x_test,y_test存放测试数据
(x,y), (x_test,y_test) = datasets.mnist.load_data()
print(x.shape) #(60000, 28, 28)
print(y.shape) #(60000,)
print(x_test.shape,y_test.shape) #(10000, 28, 28) (10000,)
# 转化数据
# 因为获取的数据时numpy类型,说以需要将数据转化为tensor格式
# 可以使用tf.data.Dataset.from_tensor_slices,将numpy数据转化为tensor对象,这样就可以将其加入迭代器
db = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db1 = next(iter(db))
print(db1[0].shape) #(28, 28)
# 将图片顺序打散
db = db.shuffle(1000)
# batch
db2 = db.batch(3)
result = next(iter(db2))
print(result[0].shape,result[1].shape)
2.2输出方式
使用tf.sigmoid和tf.nn.softmax将数据进行映射,以便将他们映射到对应范围
import tensorflow as tf
a = tf.linspace(-2,2,5)
# 使用tf.sigmoid将a映射到0-1之间
# tf.Tensor([0.11920292 0.26894142 0.5 0.73105858 0.88079708], shape=(5,), dtype=float64)
a1 = tf.sigmoid(a)
print(a1)
# 使用tf.nn.softmax将数据映射到0-1且数据之和为1
# tf.Tensor([0.01165623 0.03168492 0.08612854 0.23412166 0.63640865], shape=(5,), dtype=float64)
a2 = tf.nn.softmax(a)
print(a2)
# tf.Tensor(1.0, shape=(), dtype=float64)
print(tf.reduce_sum(a2))
2.3误差计算
2.3.1MSE(Mean Squared Error)均方差
2.3.2Entropy
熵越小,越不稳定,信息量就越大
根据公式可知,数据越有规律,其熵就越大
交叉熵的计算
2.4梯度简介
tensorflow自动求导
多次使用同一个tape求导需要将persistent设置为true
2.5激活函数及其梯度
2.5.1Simoid
函数形式
导数
使用方法
2.5.2ReLUc
实现
2.6损失函数及其梯度
softmax可以将数据投影到0-1之中,并通过指数的机制将大的数值分配更大的概率,而小的数值分配更小的概率
交叉熵的计算
[外链图片转存中…(img-a1lGXOrt-1696229878364)]
2.4梯度简介
tensorflow自动求导
[外链图片转存中…(img-IqZnlHPN-1696229878365)]
多次使用同一个tape求导需要将persistent设置为true
[外链图片转存中…(img-XTbon1Nf-1696229878365)]
2.5激活函数及其梯度
2.5.1Simoid
函数形式
[外链图片转存中…(img-SWaRotcC-1696229878365)]
导数
[外链图片转存中…(img-Z1odgCoY-1696229878366)]
使用方法
[外链图片转存中…(img-EbCi0Vw6-1696229878366)]
2.5.2ReLUc
[外链图片转存中…(img-qqLDMhcC-1696229878366)]
实现
[外链图片转存中…(img-Qh2KorYI-1696229878367)]
2.6损失函数及其梯度
softmax可以将数据投影到0-1之中,并通过指数的机制将大的数值分配更大的概率,而小的数值分配更小的概率
[外链图片转存中…(img-WC034GC9-1696229878367)]