hello,world!
import os
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, optimizers, datasets
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
(x, y), (x_val, y_val) = datasets.mnist.load_data() # 自动下载数据集
x = tf.convert_to_tensor(x, dtype=tf.float32) / 255. # 归一化
y = tf.convert_to_tensor(y, dtype=tf.int32)
y = tf.one_hot(y, depth=10) # one-hot编码,深度为10
print(x.shape, y.shape)
train_dataset = tf.data.Dataset.from_tensor_slices((x, y)) # 转换为dataset类型
train_dataset = train_dataset.batch(16) # 控制batch
model = keras.Sequential([
layers.Dense(512, activation='relu'), # 三层全连接
layers.Dense(256, activation='relu'),
layers.Dense(10)])
optimizer = optimizers.SGD(learning_rate=0.001)
def train_epoch(epoch):
for step, (x, y) in enumerate(train_dataset):
with tf.GradientTape() as tape:
# [b, 28, 28] => [b, 784]
x = tf.reshape(x, (-1, 28*28)) #自动求导
# Step1. compute output
# [b, 784] => [b, 10]
out = model(x)
# Step2. compute loss
loss = tf.reduce_sum(tf.square(out - y)) / x.shape[0] # 平方差求和
# Step3. optimize and update w1, w2, w3, b1, b2, b3
grads = tape.gradient(loss, model.trainable_variables) # 计算导数
# w' = w - lr * grad
optimizer.apply_gradients(zip(grads, model.trainable_variables)) # 梯度更新
if step % 100 == 0:
print(epoch, step, 'loss:', loss.numpy())
for epoch in range(30):
train_epoch(epoch)
tf.constant(1,dtype=tf.double) # 创建一个tensor 虽然取名为常量,但也是可以改变的
<tf.Tensor: shape=(), dtype=float64, numpy=1.0> # float = flaot32
tf.constant('hello')
<tf.Tensor: shape=(), dtype=string, numpy=b'hello'> # 字符型,bool型
tf.constant([True,False])
<tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, False])>
with tf.device('cpu'):
a = tf.constant([1])
with tf.device('GPU'):
b = tf.range(4)
a.device,b.device
('/job:localhost/replica:0/task:0/device:CPU:0', # 判断设备
'/job:localhost/replica:0/task:0/device:GPU:0')
aa = a.gpu()
aa.device
'/job:localhost/replica:0/task:0/device:GPU:0' # 设备的转换
b.numpy()
array([0, 1, 2, 3], dtype=int32) # 转换为 array
b.shape
TensorShape([4]) # 形状
b.ndim # 维度
1
tf.rank(b)
<tf.Tensor: shape=(), dtype=int32, numpy=1> # 跟 ndim差不多吧。。
tf.rank(tf.ones([3,4,5]))
<tf.Tensor: shape=(), dtype=int32, numpy=3>
tf.is_tensor(b)
True
b.dtype
tf.int32
a = np.arange(5)
a.dtype
dtype('int64')
aa = tf.convert_to_tensor(a,dtype = tf.float32) # array ->tensor
aa
<tf.Tensor: shape=(5,), dtype=float32, numpy=array([0., 1., 2., 3., 4.], dtype=float32)>
tf.cast(aa,dtype=tf.float32) # 数据类型转换
<tf.Tensor: shape=(5,), dtype=float32, numpy=array([0., 1., 2., 3., 4.], dtype=float32)>
b = tf.constant([0,1]) # 整形和bool型的转换
tf.cast(b,dtype = tf.bool)
<tf.Tensor: shape=(2,), dtype=bool, numpy=array([False, True])>
bb = tf.cast(b,dtype=tf.bool)
tf.cast(bb,tf.int32)
<tf.Tensor: shape=(2,), dtype=bool, numpy=array([False, True])>
a = tf.range(5)
b = tf.Variable(a) # 可优化的类型(需要自动求导的)
b.dtype,b.name
(tf.int32, 'Variable:0')
b = tf.Variable(a,name='input') # name没啥用
b.name,b.trainable # 可训练,需要跟踪这个变量
('input:0', True)
tf.is_tensor(b) # 仍是一个tensor
True
b.numpy()
array([0, 1, 2, 3, 4], dtype=int32)
a = tf.ones([])
float(a) # 针对标量,可以直接强制转换吧。。
tf.constant([[1,2],[3,4]])
<tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[1, 2],
[3, 4]], dtype=int32)>
tf.convert_to_tensor(np.ones([2,3])) # numpy 转 tensor
<tf.Tensor: shape=(2, 3), dtype=float64, numpy=
array([[1., 1., 1.],
[1., 1., 1.]])>
tf.convert_to_tensor([[1,2],[3,4]])
<tf.Tensor: shape=(2, 2), dtype=int32, numpy=
array([[1, 2],
[3, 4]], dtype=int32)>
tf.zeros([2,3,3]) # shape
<tf.Tensor: shape=(2, 3, 3), dtype=float32, numpy=
array([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]]], dtype=float32)>
a = tf.zeros([2,3,3])
tf.zeros_like(a)
tf.zeros(a.shape) # 同上
tf.ones([2,3,3])
tf.ones_like(a)
tf.fill([2,3],5) # 指定填充值
<tf.Tensor: shape=(2, 3), dtype=int32, numpy=
array([[5, 5, 5],
[5, 5, 5]], dtype=int32)>
#随机初始化
tf.random.normal([2,2],mean=1,stddev=1) # 正泰分布,均值,方差
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[ 2.16922 , -0.55846536],
[ 2.9959366 , 2.3603005 ]], dtype=float32)>
# 截断分布,就是截断的产生正态分布的随机数,即随机数与均值的差值若大于两倍的标准差,则重新生成。
# 比如用sigmoid函数,这样随机初始化,就可以减缓梯度消失,将梯度小的部分截去了
tf.random.truncated_normal([2,2],mean=0,stddev=1)
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[ 0.4707204 , 0.6333614 ],
[-0.9041825 , -0.66911685]], dtype=float32)>
tf.random.uniform([2,2],minval=0,maxval=10) # 均匀分布,指定范围
idx = tf.range(10)
print(idx)
idx = tf.random.shuffle(idx) # 打乱索引
print(idx)
tf.Tensor([0 1 2 3 4 5 6 7 8 9], shape=(10,), dtype=int32)
tf.Tensor([2 4 6 3 9 0 7 5 8 1], shape=(10,), dtype=int32)
a = tf.random.uniform([10],maxval=10,dtype =tf.int32)
print(a)
a = tf.gather(a,idx) # 根据打乱的索引来打乱吧。。
a
tf.Tensor([5 6 1 9 6 6 1 5 6 0], shape=(10,), dtype=int32)
<tf.Tensor: shape=(10,), dtype=int32, numpy=array([1, 6, 1, 9, 0, 5, 5, 6, 6, 6], dtype=int32)>
a = tf.ones([1,5,5,3])
a[0][0] # shape 5.3
a[0][0][0][2] # shape 1
a[0,0,0,2] # 同上
啊 = tf.range(10)
啊
<tf.Tensor: shape=(10,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)>
啊[-1:] # 反向,最后是 -1
<tf.Tensor: shape=(1,), dtype=int32, numpy=array([9], dtype=int32)>
啊[:-2] # 除了最后几个。。切片
<tf.Tensor: shape=(8,), dtype=int32, numpy=array([0, 1, 2, 3, 4, 5, 6, 7], dtype=int32)>
a = tf.random.uniform([4,28,28,3])
a[0,:,:,:].shape # 同 a[0]
a[:,0,:,:].shape #
TensorShape([4, 28, 3])
a[0:2,:,:,:].shape
TensorShape([2, 28, 28, 3])
a[:,0:28:2,0:28:4,:].shape # start:end:step ,同 ::2
TensorShape([4, 14, 7, 3])
a = tf.range(4)
a[::-1] # 逆序
<tf.Tensor: shape=(4,), dtype=int32, numpy=array([3, 2, 1, 0], dtype=int32)>
a[2::-2]
<tf.Tensor: shape=(2,), dtype=int32, numpy=array([2, 0], dtype=int32)>
a=tf.random.normal([2,4,28,28,3]) # 可以理解为 2 个任务,4张28*28的三通道图片
a[0].shape == a[0,:,:,:,:].shape # Ture
a[0,...].shape # 同上,... 就可以代替一堆中间的维度 :
TensorShape([4, 28, 28, 3])
a[0,...,2].shape
TensorShape([4, 28, 28])
高级的
a = tf.random.normal([4,35,8]) # 假如是4 个班级,每班35个人,8门课
tf.gather(a,axis=0,indices=[2,3]).shape # axis=0表示我们取班级这个维度,indices表示取的班级号
TensorShape([2, 35, 8])
tf.gather(a,axis=1,indices = [2,3,7,1,16]).shape # 顺序不固定。以人数的维度选取
TensorShape([4, 5, 8])
# 对于这种需要嵌套的,就需要一层一层来。gather只能操作一个维度
aa = tf.gather(a,axis=0,indices=[1,2]) # 两个班级两个学生的八门成绩
aaa = tf.gather(aa,axis=2,indices=[9,10])
# gather_nd 操作多维,只需要看最内层就行。。。
tf.gather_nd(a,[0,1]).shape # 0号班级,1号学生的八门成绩
TensorShape([8]) # 相当于 a[0,1]
tf.gather_nd(a,[[0,1,2]]) # 值相同,但维度不同,,,就相当于[a[0,1,1]]
<tf.Tensor: shape=(1,), dtype=float32, numpy=array([1.5100031], dtype=float32)>
tf.gather_nd(a,[0,1,2])
<tf.Tensor: shape=(), dtype=float32, numpy=1.5100031>
tf.gather_nd(a,[[[0,0,0],[1,1,1],[2,2,2]]])
<tf.Tensor: shape=(1, 3), dtype=float32, numpy=array([[ 0.6371678 , -0.72258306, 0.7952548 ]], dtype=float32)>
# 表示 0班0号学生0课的成绩和 1班1号学生1课的成绩 和,,,,,
[[a[0,0,0],a[1,1,1],a[2,2,2]]] # 值是相同的,就是类型不一样。。。
[[<tf.Tensor: shape=(), dtype=float32, numpy=0.6371678>,
<tf.Tensor: shape=(), dtype=float32, numpy=-0.72258306>,
<tf.Tensor: shape=(), dtype=float32, numpy=0.7952548>]]
# 额,,蒙版。。。就是bool索引吧
tf.boolean_mask(a,mask=[True,True,False,False]).shape # 维度要匹配啊,,
TensorShape([2, 35, 8])
b = tf.ones([2,3,4])
tf.boolean_mask(b,mask = [[True,True,False],[False,True,True]]) # 多维
[b,h,w] - > [b,2,h/2 *w] 将一个图片分为了上下两部分
a = tf.random.normal([4,28,28,3])
a.shape,a.ndim
(TensorShape([4, 28, 28, 3]), 4)
tf.reshape(a,[4,28*28,3]).shape #抹掉了行列的概念,变成了一张图片
TensorShape([4, 784, 3])
tf.reshape(a,[4,-1,3]).shape # -1 很好使啊
TensorShape([4, 784, 3])
tf.reshape(a,[4,-1]).shape # 表示一堆数据点
TensorShape([4, 2352])
tf.reshape(tf.reshape(a,[4,-1]),[4,14,56,3]).shape # 只要size正确
tf.transpose(a).shape
TensorShape([3, 28, 28, 4]) # 转置
tf.transpose(a,perm=[0,3,1,2]).shape # 指定维度的排列
TensorShape([4, 3, 28, 28])
# 在pytorch 中图片的维度是 [b,3,h,w] 就可以这样转换
a.shape
TensorShape([4, 28, 28, 3])
tf.expand_dims(a,axis=0).shape # 增加维度
TensorShape([1, 4, 28, 28, 3])
tf.expand_dims(a,axis=3).shape # axis = -1 从后加
TensorShape([4, 28, 28, 1, 3])
b = tf.ones([1,2,1,1,3])
b.shape
tf.squeeze(b).shape
TensorShape([2, 3])
tf.squeeze(b,axis=0).shape # 降维,就是把1 去了8
TensorShape([2, 1, 1, 3])
tf.squeeze(b,axis=2).shape
TensorShape([1, 2, 1, 3])
# Broadcasting 广播机制
# 从最低维对齐开始扩张,比如 [4,32,8] + [5] (维度为1)
# 将 [5] 扩张维 [4,32,8] 意义就是给每个学生的没课加5分,相当于一个偏置
# 可以节省内存。写起来也很简洁。
x = tf.random.normal([4,32,32,3])
(x+tf.random.normal([3])).shape
TensorShape([4, 32, 32, 3])
(x+tf.random.normal([32,32,1])).shape # 广播是自动进行的
TensorShape([4, 32, 32, 3])
(x+tf.random.normal([4,1,1,1])).shape
TensorShape([4, 32, 32, 3])
(x+tf.random.normal([1,4,1,1])).shape
# 报错,无法扩张,从低维开始,若维度不匹配,填充1,然后扩张。
# 这里第二维为4,需要为1 才可以扩张。
a = tf.ones([3,4])
a = tf.broadcast_to(a,[2,3,4]) # 手动进行
a.shape
TensorShape([2, 3, 4])
b = tf.ones([3,4])
b =tf.expand_dims(b,axis=0) # 广播的过程,先扩维,在填充
print(b.shape)
b = tf.tile(b,[2,1,1]) # 要是1 才可以
b.shape
(1, 3, 4)
TensorShape([2, 3, 4])
b = tf.fill([2,2],2.)
a = tf.ones([2,2])
a+b,a-b,a*b,a/b # 逐元素加减乘除
b//2,b%2 # 整除,余数
tf.math.log(a),tf.exp(a) # log ,exp,这里的log 以 e为底,实现log_10等就用个计算
tf.math.log(8,) / tf.math.log(2.) # log_e(8) / log_e(2) = log_2(8)
tf.pow(b,3) # 开方 or b**3
tf.sqrt(b) # 开跟
a@b,tf.matmul(a,b) # 矩阵乘法,可以进行
a=tf.ones([4,2,3])
b=tf.fill([4,3,5],2.) # 就是4 对矩阵[2,3]和[3,5] 的相乘,后两维参与运算
a@b # shape=(4, 2, 5)
c = tf.broadcast_to(b,[4,3,5]) # 如果维度不匹配,还可以进行广播后在矩阵相乘
a@c
x = tf.ones([4,2])
W = tf.ones([2,1])
b = tf.constant(0.1) # 自动广播
x @ W + b
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
(x, y), _ = datasets.mnist.load_data()
x = tf.convert_to_tensor(x, dtype=tf.float32) / 255. # x: [0~255] => [0~1.]
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) # 数据,标签 batch = 128
# [b, 784] => [b, 256] => [b, 128] => [b, 10] 过程
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):
for step, (x, y) in enumerate(train_db):
# 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)
# [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))
函数 | 作用 | 备注 |
---|---|---|
os.environ[‘TF_CPP_MIN_LOG_LEVEL’]=‘2’ | 控制输出信息 | |
tf.constant(data,dtype=) | 创建tensor | 列表,常数,字符,bool都可 |
t.numpy() | 转换为array | |
with tf.device(‘gpu’): | 指定变量存储的设备 | |
a.device/a.shape/a.ndim/b.dtype/b.trainable | 属性 | |
a = b.gpu() | 转移设备 | |
tf.rank(b)/tf.is_tensor(b) | ||
a = tf.convert_to_tensor(a,dtype) | array - > tensor | |
tf.cast(a,dtype) | 数据类型转换 | |
tf.range() | ||
tf.Variable(a) | 可优化类型,需要跟进自动求导的变量 | |
tf.zeros/ones/ones_like/fill(shape,var) | 创建tensor | |
tf.random.normal(shape,mean,stddev) | 正态分布 | |
tf.random.truncated_normal(shape,mean,stddev) | 截断分布,减缓梯度消失 | |
tf.random.uniform(shape,minval,maxval) | 均匀分布 | |
idx = tf.random.shuffle(idx) | 打乱索引(tf.gather(a,idx)打乱数据) | |
a[start:\end:step] a[0,…,2] | 索引和切片 | |
tf.gather(data,axis,indices) | 指定维度,索引选取,嵌套选取,需要多个gather配合 | |
tf.gather_nd(data,[idx]) | 操作多维 | 相当于 [a[idx]]只需要看最内层 |
tf.boolean_mask(a,mask=[bool]) | 蒙版,可多维,需要匹配 | |
tf.reshape(a,shape) | 维度变化,-1的妙用 | |
tf.transpose(a,perm) | 转置,perm指定维度的排列 | |
tf.expand_dims(a,axis) | 在axis出加一维 | |
tf.squeeze(a,axis) | 去掉一维的,axis指定维度 | |
a = tf.broadcast_to(a,shape) | 手动广播 | |
±*/ // % | 逐元素 | |
tf.math.log(a),tf.exp(a) | log_10 ,e | log_e(8) / log_e(2) = log_2(8) |
tf.pow(b,3)/tf.sqrt(b) | 次方 | |
a@b, tf.matmul(a,b) | 矩阵乘法 | |
tf.reduce_min(x)/reduce_max(x) | 最大最小值 | |
tf.data.Dataset.from_tensor_slices((x,y)).batch(16) | 构建dataset 对象 | |
train_iter = iter(train_db) / sample = next(train_iter) | 迭代器 | |
for step, (x, y) in enumerate(train_db): | batch迭代 | |
with tf.GradientTape() as tape | 自动求导,跟踪Variable 变量 | |
y_onehot = tf.one_hot(y, depth=10) | 独热 | |
tf.reduce_mean(loss) | 均值 | |
grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3]) | 求导 | |
w1.assign_sub(lr * grads[0]) | 原地更新参数,类型不变 |