Tensorflow2.1-note

Tensorflow2.1-note

Charles Lv7

基本知识

张量

为什么要在TF2中使用张量?

tensorflow中的数据类型

  • np.array
  • tf.constant()
  • tf.Variable() 将变量标记为“可训练”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
array = np.array([1,2,3,4])
constant = tf.constant(a)
c = tf.Variable(array)
d = tf.Variable(constant)

print(array,constant)
print(array == constant)
print(c,d)
print(c == d)

# 打印结果:
# [1 2 3 4] tf.Tensor([1 2 3 4], shape=(4,), dtype=int64)
# tf.Tensor([ True True True True], shape=(4,), dtype=bool)
# <tf.Variable 'Variable:0' shape=(4,) dtype=int64, numpy=array([1, 2, 3, 4])> <tf.Variable 'Variable:0' shape=(4,) dtype=int64, numpy=array([1, 2, 3, 4])>
# tf.Tensor([ True True True True], shape=(4,), dtype=bool)

结论:np.array和tf.constant没有区别?

张量的表示方法

张量的维数判定

等号后面有几个[,就是几维张量。

1
2
3
4
scalar = 1
vector = [1,2,3]
matrix = [[1,2,3],[4,5,6]]
tensor = [[[...

维度的表示

一维 二维 多维
维度表示 元素个数 [行数,列数] [n,m,j,k……]

axis的含义

对于张量x, shape = (n,m,j,k),对应的axis就是(axis=0,axis=1,axis=2,axis=3)

张量的索引

1
x[m,n,p] # 从最外部的方框逐渐缩小到固定元素

张量的创建:

指定内容 tf.constant / numpy转化 tf. convert_to_tensor / 特殊结构 tf.zeros等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# tf.constant(张量内容,dtype=数据类型(可选))
import tensorflowas tfa=tf.constant([1,5],dtype=tf.int64)
print(a)
print(a.dtype)
print(a.shape)

# tf. convert_to_tensor(数据名,dtype=数据类型(可选))
import tensorflowas tf
import numpyas np
a = np.arange(0, 5)
b = tf.convert_to_tensor( a, dtype=tf.int64 )

# 创建全为0的张量 tf. zeros(维度)
# 创建全为1的张量 tf. ones(维度)
# 创建全为指定值的张量 tf. fill(维度,指定值)

# 生成正态分布的随机数 tf. random.normal(维度,mean=均值,stddev=标准差)
# 生成均匀分布随机数[ minval, maxval) tf. random. uniform(维度,minval=最小值,maxval=最大值)

张量的操作函数

1
2
# 计算张量维度上元素的最小值 tf.reduce_min(张量名, axis=操作轴))
# 计算张量维度上元素的最大值 tf.reduce_max(张量名, axis=操作轴))

指定axis的含义:该axis上的元素作为查找目标/取平均值对象,遍历其他axis上的所有值,最终结果的结构是去除该axis后的值。比如a的shape是(2,3,4),对axis = 1运算,最终结果的shape就是(2,4)

1
# 同理有reduce_mean / reduce_sum

数学运算

对应元素的四则运算:tf.add,tf.subtract,tf.multiply,tf.divide
平方、次方与开方:tf.square,tf.pow,tf.sqrt
矩阵乘:tf.matmul

常用操作

梯度计算

with结构记录计算过程,gradient求出张量的梯度

1
2
3
4
5
6
7
8
9
# with tf.GradientTape( ) as tape:
# 若干个计算过程
# grad=tape.gradient(函数,对谁求导)

with tf.GradientTape( ) as tape:
w = tf.Variable(tf.constant(3.0))
loss = tf.pow(w,2) #loss=w2 loss’=2w
grad = tape.gradient(loss,w)
print(grad)

梯度计算的注意事项

  1. 参与梯度计算的数据类型需要是float

  2. 计算梯度的时候可以直接写+-*/,但不能写^

  3. 二阶导数的计算

    1
    2
    3
    4
    5
    with tf.GradientTape() as tape2:
    with tf.GradientTape() as tape1:
    y = a*tf.pow(x,2) + b*x + c
    dy_dx = tape1.gradient(y,x)
    dy2_dx2 = tape2.gradient(dy_dx,x)
  4. 多元函数的导数怎么表示

    1
    2
    3
    4
    5
    6
    with tf.GradientTape() as tape:
    x1 = tf.Variable(tf.constant(3.0))
    x2 = tf.Variable(tf.constant(3.0))
    y = tf.pow(x1,2)*x2
    grad = tape.gradient(y,[x1,x2])
    print(grad)
  5. 偏导怎么计算?

常用函数

tf.one_hot(待转换数据, depth=几分类)

1
2
3
4
5
6
7
8
9
classes = 3
labels = tf.constant([1,0,2]) #
输入的元素值最小为0,最大为2
output = tf.one_hot( labels, depth=classes )
print(output)
# 运行结果:
# [[0. 1. 0.]
# [1. 0. 0.]
# [0. 0. 1.]], shape=(3, 3), dtype=float32)

data = tf.data.Dataset.from_tensor_slices((输入特征, 标签)) 切分传入张量的第一维度,生成输入特征/标签对,构建数据集

1
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)

自减函数 assign_sub

1
w.assign_sub(1)

NN复杂度

空间复杂度

总参数= 总w + 总b

时间复杂度

乘加运算次数(计算线的个数)

模块处理

基本流程

1
2
3
4
5
6
import
train / test data
model.sequential
model.compile
model.fit
model.summary

数据导入

控制batch

  1. model.fit中设置batch_size
  2. 底层控制

训练

学习率设置

指数衰减学习率 = 初始学习率* 学习率衰减率(当前轮数/ 多少轮衰减一次)

正则化缓解过拟合

loss = loss( y与y_ )+ REGULARIZER * loss(w)

模型的保存与载入

自动进行参数的保存与载入

1
2
3
4
5
6
7
8
9
10
11
checkpoint_save_path = "./checkpoint/mnist.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
print('-------------load the model-----------------')
model.load_weights(checkpoint_save_path) # 如果参数存在则读取参数

# 设置回调函数(也就是保存的选项)
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
save_weights_only=True,
save_best_only=True)
# 添加callbacks就会进行参数保存
history = model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1, callbacks=[cp_callback])

手动进行参数的保存和载入

1
2
3
4
5
6
7
8
9
10
11
12
# 保存权重
model.save_weights('./checkpoints/my_checkpoint')

# 创建模型实例
model = create_model()

# Restore the weights
model.load_weights('./checkpoints/my_checkpoint')

# Evaluate the model
loss,acc = model.evaluate(test_images, test_labels, verbose=2)
print("Restored model, accuracy: {:5.2f}%".format(100*acc))

训练结果的保存

通过history = model.fit记录训练结果

1
2
3
4
5
6
7
# history=model.fit(训练集数据, 训练集标签,batch_size=, epochs=, validation_split=用作测试数据的比例,validation_data=测试集, validation_freq=测试频率)

# 显示训练集和验证集的acc和loss曲线
acc = history.history['sparse_categorical_accuracy']
val_acc = history.history['val_sparse_categorical_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

history.history内部也就只有这4个list

实例程序

TF底层实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 利用鸢尾花数据集,实现前向传播、反向传播,可视化loss曲线

# 导入所需模块
import tensorflow as tf
from sklearn import datasets
from matplotlib import pyplot as plt
import numpy as np
import time ##1##

# 导入数据,分别为输入特征和标签
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target

# 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率)
# seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致)
np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)

# 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行
x_train = x_data[:-30]
y_train = y_data[:-30]
x_test = x_data[-30:]
y_test = y_data[-30:]

# 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)

# from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据)
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)

# 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元
# 用tf.Variable()标记参数可训练
# 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed)
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))

lr = 0.1 # 学习率为0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据
test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和

##########################################################################
m_w, m_b = 0, 0
v_w, v_b = 0, 0
beta1, beta2 = 0.9, 0.999
delta_w, delta_b = 0, 0
global_step = 0
##########################################################################

# 训练部分
now_time = time.time() ##2##
for epoch in range(epoch): # 数据集级别的循环,每个epoch循环一次数据集
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环 ,每个step循环一个batch
##########################################################################
global_step += 1
##########################################################################
with tf.GradientTape() as tape: # with结构记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算
y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss)
y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy
loss = tf.reduce_mean(tf.square(y_ - y)) # 采用均方误差损失函数mse = mean(sum(y-out)^2)
loss_all += loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确
# 计算loss对各个参数的梯度
grads = tape.gradient(loss, [w1, b1])

##########################################################################
# adam
m_w = beta1 * m_w + (1 - beta1) * grads[0]
m_b = beta1 * m_b + (1 - beta1) * grads[1]
v_w = beta2 * v_w + (1 - beta2) * tf.square(grads[0])
v_b = beta2 * v_b + (1 - beta2) * tf.square(grads[1])

m_w_correction = m_w / (1 - tf.pow(beta1, int(global_step)))
m_b_correction = m_b / (1 - tf.pow(beta1, int(global_step)))
v_w_correction = v_w / (1 - tf.pow(beta2, int(global_step)))
v_b_correction = v_b / (1 - tf.pow(beta2, int(global_step)))

w1.assign_sub(lr * m_w_correction / tf.sqrt(v_w_correction))
b1.assign_sub(lr * m_b_correction / tf.sqrt(v_b_correction))
##########################################################################

# 每个epoch,打印loss信息
print("Epoch {}, loss: {}".format(epoch, loss_all / 4))
train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中
loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备

# 测试部分
# total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0
total_correct, total_number = 0, 0
for x_test, y_test in test_db:
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test的数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
# 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
# 将所有batch中的correct数加起来
total_correct += int(correct)
# total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数
total_number += x_test.shape[0]
# 总的准确率等于total_correct/total_number
acc = total_correct / total_number
test_acc.append(acc)
print("Test_acc:", acc)
print("--------------------------")
total_time = time.time() - now_time ##3##
print("total_time", total_time) ##4##

# 绘制 loss 曲线
plt.title('Loss Function Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Loss') # y轴变量名称
plt.plot(train_loss_results, label="$Loss$") # 逐点画出trian_loss_results值并连线,连线图标是Loss
plt.legend() # 画出曲线图标
plt.show() # 画出图像

# 绘制 Accuracy 曲线
plt.title('Acc Curve') # 图片标题
plt.xlabel('Epoch') # x轴变量名称
plt.ylabel('Acc') # y轴变量名称
plt.plot(test_acc, label="$Accuracy$") # 逐点画出test_acc值并连线,连线图标是Accuracy
plt.legend()
plt.show()

# 请将loss曲线、ACC曲线、total_time记录到 class2\优化器对比.docx 对比各优化器收敛情况

Keras

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras import Model

mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0


class MnistModel(Model):
def __init__(self):
super(MnistModel, self).__init__()
self.flatten = Flatten()
self.d1 = Dense(128, activation='relu')
self.d2 = Dense(10, activation='softmax')

def call(self, x):
x = self.flatten(x)
x = self.d1(x)
y = self.d2(x)
return y


model = MnistModel()

model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['sparse_categorical_accuracy'])

model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1)
model.summary()

  • Title: Tensorflow2.1-note
  • Author: Charles
  • Created at : 2023-03-10 15:54:03
  • Updated at : 2023-07-27 16:45:50
  • Link: https://charles2530.github.io/2023/03/10/tensorflow2-1-note/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments