Tensorflow 入门教程(1) 视频教程链接:
【国家精品课程】北京大学人工智能实践-TensorFlow2.0
一、张量以及常用函数 1.创建张量 由tf.constant()
函数进行创建
1 2 3 4 5 6 import tensorflow as tf a = tf.constant([[1 ,2 ]],dtype=tf.int32) print(a) print(a.dtype) print(a.shape)
运行结果:
将numpy
格式转换为tensor格式
1 2 a = numpy.range(0 ,5 ) b = tf.convert_to_tensor(a,dtype=tf.int64)
创建特殊张量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 创建全部为0 的张量 tf.zeros(维度) # 创建全部为1 的张量 tf.ones(维度) # 创建全为指定值的张量 tf.fill(维度,指定值) # tf.fill([2,2],9) # 生成正太分布的随机数 默认均值为 0 标准差为1 tf.random.normal(维度,mean=均值,stddev=标准差) # 生成截断式正太分布的随机数 生成的随机数据取值在(均值-2 *标准差,均值+2 *标准差) tf.random.truncated_normal(维度,mean=均值,stddev=标准差) # 生成均匀分布随机数 在[minval,maxval]之间 tf.random.uniform(维度,minval=最小值,maxval=最大值)
2.常用函数 1 2 3 4 5 6 7 8 # 强制tensor转换该数据 tf.cast(张量名,dtype=数据类型) # 计算张量维度上元素的最大值 tf.reduce_min(张量名) # 计算张量维度上元素的最大值 tf.reduce_max(张量名)
指定axis
1 2 3 4 5 # 计算张量沿着指定维度的平均值 tf.reduce_mean(张量名,axis=操作轴) # 计算张量沿着指定维度的和 tf.reduce_sum(张量名,axis=操作轴)
示例code:
1 2 3 4 5 6 7 8 9 import tensorflow as tf a = tf.constant([[1 ,2 ,3 ],[2 ,2 ,3 ]],dtype=tf.int32) print(a) print(tf.reduce_mean(a)) print(tf.reduce_sum(a,axis=1 ))
运行结果:
(1)tf.Varible() 1 2 # 将变量标记为可训练,被标记的变量会在反向传播中记录梯度信息 tf.Varible(初始值)
(2)Tensorflow中的数学运算
(3)输入特征与标签配对的函数 numpy与tensor格式都可以用该语句输入数据
1 2 # 切分传入张量的第一维度,生成输入特征与标签对,构建数据集 tf.data.Dataset.from_tensor_slices((输入特征,标签))
示例code:
1 2 3 4 5 6 7 8 9 10 import tensorflow as tf feature = tf.constant([12 ,23 ,10 ,17 ]) labels = tf.constant([0 ,1 ,1 ,0 ]) dataset = tf.data.Dataset.from_tensor_slices((feature,labels)) print(dataset) for els in dataset: print(els)
运行结果:
(4)tf.GradientTape() 1 2 3 4 # 函数对参数的求导运算,with结构记录计算过程,gradient求出张量的梯度 with tf.GradientTape() as tape: 若干计算过程 grad = tape.gradient(函数,对谁求导)
示例:
1 2 3 4 5 with tf.GradientTape() as tape: w = tf.Variable(tf.constant(3.0 )) loss = tf.pow (w, 2 ) grad = tape.gradient(loss, w) print(grad)
运行:
(5)tf.one_hot() 独热编码:在分类问题中,常用独热编码作为标签,标记类别:1表示是,0表示非
1 2 # 将待转换的数据 转换为one-hot形式的数据输出 tf.one_hot(待转换的数据,depth=几分类)
示例:
1 2 3 4 5 #tf.one_hot classes=3 labels=tf.constant([1 ,0 ,2 ]) # 输入的元素值最小为0 最大为2 output=tf.one_hot(labels,depth=classes) print(output)
运行结果:
(6)tf.nn.softmax()
(7) assign_sub() 1 2 3 # 赋值操作 更新参数的值并且返回 # 调用assign_sub之前,先用tf.Varible定义w为可以训练(可自更新) w.assign(w要自减的内容)
示例:
1 2 3 4 #assign_sub w=tf.Variable(4 ) w.assign_sub(1 ) print(w)
运行:
(8)tf.argmax() 1 2 # 返回张量沿指定维度最大值的索引 tf.argmax(张量名,axis=操作轴)
示例:
1 2 3 4 5 6 #tf.argmax import numpy as np test=np.array ([[1 ,2 ,3 ],[2 ,3 ,4 ],[5 ,4 ,3 ],[8 ,7 ,2 ]]) print(test) print(tf.argmax(test,axis=0 ))#返回每一列最大值的索引 print(tf.argmax(test,axis=1 ))#返回每一行最大值的索引
运行:
1 2 3 4 5 6 [[1 2 3 ] [2 3 4 ] [5 4 3 ] [8 7 2 ]] tf.Tensor([3 3 1 ], shape=(3 ,), dtype=int64) tf.Tensor([2 2 0 0 ], shape=(4 ,), dtype=int64)
二、鸢尾花分类 数据集介绍:
1.准备数据 (1)数据集读入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from sklearn import datasetsimport pandas as pd x_data = datasets.load_iris().data # 返回iris数据集所有数据集 y_data = datasets.load_iris().target # 返回iris数据集所有标签 # print("x_data:\n", x_data) # print("y_data:\n", y_data) # 将数据变成表格的形式 x_data = pd.DataFrame(x_data, columns=['花萼长' , '花萼宽' , '花瓣长' , '花瓣宽' ]) pd.set_option('display.unicode.east_asian_width' , True) # 设置列名对齐 print('x_data add index:\n' , x_data) # 在表格中增加一列 x_data['类别' ] = y_data print ('x_data add a column:\n' , x_data )
运行:
(2)数据集乱序 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 from sklearn import datasets from pandas import DataFrame import pandas as pd import tensorflow as tf import numpy as np from matplotlib import pyplot as plt # 读入数据 x_data = datasets.load_iris().data # 返回iris数据集所有数据集 y_data = datasets.load_iris().target # 返回iris数据集所有标签 # 数据集乱序 np.random.seed(116 ) # 使用相同的seed,使输入特征/标签一一对应 np.random.shuffle(x_data) # 打乱 np.random.seed(116 ) np.random.shuffle(y_data) # 数据集分出永不相见的训练集和测试集 x_train = x_data[:-30 ] y_train = y_data[:-30 ] x_test = x_data[-30 :] y_test = y_data[-30 :] # 转换数据类型 x_train = tf.cast(x_train, tf.float32) x_test = tf.cast(x_test, tf.float32) # 配成输入特征,标签对,每次喂入一小撮(32 个样本为一个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 )
2.训练 两层网络,输入层以及输出层(4特征输入 3特征输出)
1 2 3 # 定义神经网络中所有可训练参数(初始化的参数权值) 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))
整体code:
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 from sklearn import datasets from pandas import DataFrame import pandas as pd import tensorflow as tf import numpy as np from matplotlib import pyplot as plt x_data = datasets.load_iris().data # 返回iris数据集所有数据集 y_data = datasets.load_iris().target # 返回iris数据集所有标签 np.random.seed(116 ) # 使用相同的seed,使输入特征/标签一一对应 np.random.shuffle(x_data) # 打乱 np.random.seed(116 ) np.random.shuffle(y_data) # 数据集分出永不相见的训练集和测试集 x_train = x_data[:-30 ] y_train = y_data[:-30 ] x_test = x_data[-30 :] y_test = y_data[-30 :] # 转换数据类型 x_train = tf.cast(x_train, tf.float32) x_test = tf.cast(x_test, tf.float32) # 配成输入特征,标签对,每次喂入一小撮 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 ) # 定义神经网络中所有可训练参数 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 train_loss_result = [] # 将每轮loss记录在此列表中,为后续画loss曲线提供数据 test_acc = [] epoch = 500 loss_all = 0 # 每轮分4 个step,loss_all记录四个step生成4 个loss值 "" "----------- 嵌套循环迭代,with结构更新参数,显示当前loss -----------" "" for epoch in range(epoch): "" "-------训练部分--------" "" for step, (x_train, y_train) in enumerate(train_db): with tf.GradientTape() as tape: # 记录梯度信息 # 前向传播过程记录y y = tf.matmul(x_train, w1) + b1 # 前向传播计算预测值 y = tf.nn.softmax(y) # 使得预测y得分符合概率分布 # 对预测结果使用softmax()函数之后才可以与实际标签的one_hot进行比较 y_ = tf.one_hot(y_train, depth=3 ) # 将标签值独热编码 # 记录总loss loss = tf.reduce_mean(tf.square(y_ - y)) # 采用均方误差损失值mse loss_all += loss.numpy() # 计算loss对各个参数的梯度 grads = tape.gradient(loss, [w1, b1]) # 实现梯度更新,w1=w1-lr*w1_grad b=b-lr*b_grad w1.assign_sub(lr * grads[0 ]) b1.assign_sub(lr * grads[1 ]) # 每个epoch打印loss信息 print("epoch{},loss{}" .format(epoch, loss_all / 4 )) # (训练集有120 组数据,每个step只能喂入32 组数据,需要batch级别循环4 次,求每个step的平均loss) train_loss_result.append(loss_all / 4 ) # 将四个step的loss求平均值记录在此变量中 loss_all = 0 # loss_all值归0 ,为下一个epoch的loss做准备 "" "-------测试部分--------" "" # 计算当前参数前向传播后的准确率,显示当前acc 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) # y符合概率分布 pred = tf.argmax(y, axis=1 ) # 返回y中最大值的索引,即预测的分类 pred = tf.cast(pred, dtype=y_test.dtype) # 调整数据类型与标签一致 correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32) # equal,相等的意思。顾名思义,就是判断,x, y 是不是相等,它的判断方法不是整体判断,而是逐个元素进行判断,如果相等就是True,不相等,就是False。由于是逐个元素判断,所以x,y 的维度要一致。 correct = tf.reduce_sum(correct) # 将所有batch中的correct数加起来 total_correct += int (correct) # 将所有batch中的correct数加起来 total_number += x_test.shape[0 ] # 在矩阵中,[0 ]就表示行数(样本数),[1 ]则表示列数,[2 ]代表通道数 acc = total_correct / total_number test_acc.append(acc) print("test_acc" , acc) print("------------------------------" ) "" "---------------可视化------------" "" # acc/loss可视化 # 绘制loss曲线 plt.title('loss Curve' ) # 图片隐私 plt.xlabel('Epoch' ) # x轴名称 plt.ylabel('loss' ) plt.plot(train_loss_result, label="$loss$" ) # 逐点画出test_acc值并连线,?epoch? plt.legend() plt.show() # 绘制accuracy曲线 plt.title('Acc Curve' ) # 图片隐私 plt.xlabel('Epoch' ) # x轴名称 plt.ylabel('Acc' ) plt.plot(test_acc, label="$Accuracy$" ) # 逐点画出test_acc值并连线,?epoch? plt.legend() plt.show()
三、神经网络的优化过程 1.预备知识 (1)tf.where()
示例code:
1 2 3 4 a = tf.constant([1 , 2 , 3 , 1 , 1 ]) b = tf.constant([0 , 1 , 3 , 4 , 5 ]) c = tf.where(tf.greater(a, b), a, b) # 若a>b,返回a对应位置的元素,否则返回b对应位置的元素 print("c:" , c)
运行:
(2)np.random.RandomState.rand() 产生一个0-1之间的随机数
1 np.random.RandomState.rand(维度)
示例:
1 2 3 4 5 6 7 import numpy as np rdm = np.random.RandomState(seed=1) # 随机数种子 seed为常数导致每一次生成的随机数相同 a = rdm.rand() b = rdm.rand(2, 3) print("a:", a) print("b:", b)
运行:
(3)np.vstack() 将两个数组按照垂直方向叠加
示例:
1 2 3 4 5 6 import numpy as np a = np.array ([1 , 2 , 3 ]) b = np.array ([4 , 5 , 6 ]) c = np.vstack((a, b)) print("c:\n" , c)
运行:
(4)np.mgrid[] .ravel() np.c_[] np.mgrid[] 返回若干组维度相同的等差数组
x.ravel() 将x变为一维数组 把.
前的变量拉直
np.c_[] 使返回的间隔数组点配对
`np.c_[数组1,数组2,…]
示例;
1 2 3 4 5 6 7 8 9 10 11 12 import numpy as np import tensorflow as tf # 生成等间隔数值点 x, y = np.mgrid[1 :3 :1 , 2 :4 :0.5 ] # 将x, y拉直,并合并配对为二维张量,生成二维坐标点 grid = np.c_[x.ravel(), y.ravel()] print("x:\n" , x) print("y:\n" , y) print("x.ravel():\n" , x.ravel()) print("y.ravel():\n" , y.ravel()) print('grid:\n' , grid)
示例;
2.损失函数 (1)均方损失函数
1 LOSS_MSE = tf.reduce_mean(tf.square(y_ - y)) # y 模型前向传播值 y_ 样本标签
(2)交叉熵损失函数
y_与y的距离越近(越接近)其交叉熵就越小
1 LOSS_fn = tf.loss.categorical_crossentropy(y_ - y) # y 模型前向传播值
softmax 与交叉熵结合 输出先过softmax
函数,再计算y
与y_
的交叉熵损失函数
分步计算
1 2 3 # y已经经过前向传播得到的预测值 y_pro = tf.nn.softmax(y) # 经过 softmax函数,得到概率分布 loss_ce1 = tf.losses.categorical_crossentropy(y_,y_pro) # y_ 样本标签
结合计算
1 loss_ce2 = tf.softmax_cross_entropy_with_logits(y_,y)
3.优化器
(1)SGD
(2)SGDM
对于单层网络
1 2 3 4 5 6 7 m_w,m_b = 0 ,0 beta = 0.9 # 动量超参数 m_w = beta * m_w + (1 - beta) * grads[0 ] m_b = beta * m_b + (1 - beta) * grads[1 ] w1.assign_sub(lr * m_w) # 参数自更新 b1.assign_sub(lr * m_b)
(3)Adagrad
Adagrad的一阶动量mt就是当前时刻的梯度,二阶动量是梯度平方的累积和
1 2 3 4 5 6 v_w,v_b = 0 ,0 v_w += tf.square(grads[0 ]) v_b += tf.square(grads[1 ]) w1.assign_sub = (lr *grads[0 ] / tf.sqrt (v_w)) b1.ssign_sub = (lr *grads[1 ] /tf.sqrt (v_b))
(4)RMSProp 在SGD的基础上增加二阶动量,二阶动量vt使用指数滑动平均值计算,表征过去一段时间的平均值
一阶动量是当前时刻梯度
1 2 3 4 5 6 7 v_w,v_b = 0 ,0 beta = 0.9 v_w = beta * v_w + (1 -beta) * tf.square(grads[0 ]) v_b = beta * v_b + (1 -beta) * tf.square(grads[1 ]) w1.assign_sub = (lr *grads[0 ] / tf.sqrt (v_w)) b1.assign_sub = (lr *grads[1 ]/ tf.sqrt (v_b))
(5)Adam 同时结合SGDM一阶动量和RMSProp二阶动量
四、使用八股搭建神经网络 1.使用Tensorflow API : tf.keras搭建网络八股
(1)tf.keras.models.Sequential() 1 tf.keras.models.Sequential([网络结构]) # 描述各层网络
拉直层
全连接层
卷积层
LSTM层
(2)model.compile() 1 model.compile(optimizer = 优化器,loss = 损失函数, metrics = ["准确率" ])
from_logits
询问是否是原始输出,若神经网络的预测结果经过了softmax概率分布则填写False
(3)model.fit() 1 2 3 4 5 model.fit(训练集的属土特征,训练集标签,batch_size= , epochs = , validation_data = (测试集的输入特征,测试集的标签), validation_split=从训练集划分多少比例给测试集, validation_freq = 多少次epoch测试一次 )
(4)model.summary() 1 model.summary() # 打印出网络的结构
2.使用tf.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 33 "" " 使用tf.keras实现鸢尾花分类 " "" import numpy as np import tensorflow as tf from sklearn import datasets # 读入鸢尾花数据 x_train = datasets.load_iris().data y_train = datasets.load_iris().target # 数据集乱序 np.random.seed(116 ) # 随机种子一致导致后文 标签与对应样本的特征乱序顺序一致 np.random.shuffle(x_train) np.random.seed(116 ) np.random.shuffle(y_train) tf.random.set_seed(116 ) # 搭建模型(三分类--单层网络) model = tf.keras.models.Sequential([ tf.keras.layers.Dense(3 ,activation='softmax' ,kernel_regularizer=tf.keras.regularizers.l2()) ]) # 编译 model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.1 ), loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 训练拟合(validation_split=0.2 从训练集划分20 %比例给测试集,validation_freq=20 20 次epoch测试一次) model.fit(x_train,y_train,batch_size=32 ,epochs=500 ,validation_split=0.2 ,validation_freq=20 ) model.summary()
运行:
3.自定义class 类搭建网络结构 用Sequential
搭建出上层输出就是下层输入的顺序网络结构
但是无法写出带有跳连的非顺序网络结构(此时类class
可以 )—类似于pytorch定义自己的网络结构
示例;
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 "" " 使用class实现鸢尾花分类 " "" import numpy as np import tensorflow as tf from sklearn import datasets # 读入鸢尾花数据 x_train = datasets.load_iris().data y_train = datasets.load_iris().target # 数据集乱序 np.random.seed(116 ) # 随机种子一致导致后文 标签与对应样本的特征乱序顺序一致 np.random.shuffle(x_train) np.random.seed(116 ) np.random.shuffle(y_train) tf.random.set_seed(116 ) # 自定义类class搭建模型(三分类--单层网络) class IrisModel(tf.keras.Model): def __init__(self): super(IrisModel,self).__init__() self.d1 = tf.keras.layers.Dense(3 ,activation='softmax' ,kernel_regularizer=tf.keras.regularizers.l2()) def call(self,x): y = self.d1(x) return y model = IrisModel() # 编译 model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=0.1 ), loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 训练拟合(validation_split=0.2 从训练集划分20 %比例给测试集,validation_freq=20 20 次epoch测试一次) model.fit(x_train,y_train,batch_size=32 ,epochs=500 ,validation_split=0.2 ,validation_freq=20 ) model.summary()
4.MNIST数据集
可视化:
(1)手写数字识别(Sequential()) 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 "" " 手写识别MNIST " "" import numpy as np import tensorflow as tf from sklearn import datasets # 读入MNIST数据 mnist = tf.keras.datasets.mnist (x_train,y_train),(x_test,y_test) = mnist.load_data() # 将特征皈依化到0 -1 之间 加快模型收敛 x_train,x_test = x_train / 255.0 , x_test / 255.0 model = tf.keras.models.Sequential([ # 将输入特征展平 28 * 28 tf.keras.layers.Flatten(), tf.keras.layers.Dense(128 ,activation='relu' ), # 输出 10 分类 tf.keras.layers.Dense(10 ,activation='softmax' ), ]) # 编译 model.compile(optimizer='adam' , loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 训练拟合(validation_split=0.2 从训练集划分20 %比例给测试集,validation_freq=20 20 次epoch测试一次) model.fit(x_train,y_train,batch_size=32 ,epochs=5 ,validation_data=(x_test,y_test),validation_freq=1 ) model.summary()
运行:
(2)手写数字识别(自定义类class) 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 "" " 手写识别MNIST---自定义类class " "" import numpy as np import tensorflow as tf from sklearn import datasets # 读入MNIST数据 mnist = tf.keras.datasets.mnist (x_train,y_train),(x_test,y_test) = mnist.load_data() # 将特征皈依化到0 -1 之间 加快模型收敛 x_train,x_test = x_train / 255.0 , x_test / 255.0 # 搭建模型 class MnistModel(tf.keras.Model): def __init__(self): super(MnistModel,self).__init__() self.flatten = tf.keras.layers.Flatten(), self.d1 = tf.keras.layers.Dense(128 ,activation='relu' ) self.d2 = tf.keras.layers.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 = tf.keras.models.Sequential([ # 将输入特征展平 28 * 28 tf.keras.layers.Flatten(), tf.keras.layers.Dense(128 ,activation='relu' ), # 输出 10 分类 tf.keras.layers.Dense(10 ,activation='softmax' ), ]) # 编译 model.compile(optimizer='adam' , loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 训练拟合(validation_split=0.2 从训练集划分20 %比例给测试集,validation_freq=20 20 次epoch测试一次) model.fit(x_train,y_train,batch_size=32 ,epochs=5 ,validation_data=(x_test,y_test),validation_freq=1 ) model.summary()
5.FASHION数据集
五、八股进阶
1.自制数据集 数据结构如下:(图片名 最后的数字即为其标签)
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 "" " 自制数据集 " "" import tensorflow as tf from PIL import Image import numpy as np import os train_path = "./data/mnist_image_label/mnist_train_jpg_60000/" train_txt = "./data/mnist_image_label/mnist_train_jpg_60000.txt" x_train_savepath = "./data/mnist_image_label/mnist_x_train.npy" y_train_savepath = "./data/mnist_image_label/mnist_y_train.npy" test_path = "./data/mnist_image_label/mnist_test_jpg_10000/" test_txt = "./data/mnist_image_label/mnist_train_jpg_10000.txt" x_test_savepath = "./data/mnist_image_label/mnist_x_test.npy" y_test_savepath = "./data/mnist_image_label/mnist_y_test.npy" def generate(path,txt): f = open(txt,'r' ) contents = f.readlines() # 读取txt文件中所有行 f.close() x,y_ = [],[] for content in contents: value = content.split() # 以空格分开,图片路径为value[0 ] 标签文件为value[1 ] 存入列表 img_path = path + value[0 ] # 拼出图片路径以及文件名 img = Image.open(img_path) # 读入图片 img = np.array (img.convert('L' )) # 图片变为8 位宽灰度值的np.array 格式 img = img / 255. # 皈依化 x.append(img) y_.append(value[1 ]) print('loading : ' + content) x = np.array (x) # 变为np.array 形式 y_ = np.array (y_) y_ = y_.astype(np.int64) # 变为64 位整型 return x,y_ "" "---数据集---" "" if os.path.exists(x_train_savepath) and os.path.exists(y_train_savepath) and os.path.exists(x_test_savepath) and os.path.exists(y_test_savepath): print("-----------Load Datasets----------" ) x_train_save = np.load(x_train_savepath) y_train = np.load(y_train_savepath) x_test_save = np.load(x_test_savepath) y_test = np.load(y_test_savepath) x_train = np.reshape(x_train_save,(len(x_train_save),28 ,28 )) x_test = np.reshape(x_test_save,(len(x_test_save,),28 ,28 )) else : print("----------Generate Datasets----------" ) x_train,y_train = generate(train_path,train_txt) x_test,y_test = generate(test_path,test_txt) print("---------- Save Datasets----------" ) x_train_save = np.reshape(x_train,(len(x_train),-1 )) x_test_save = np.reshape(x_test,(len(x_test),-1 )) np.save(x_train_savepath,x_train_save) np.save(y_train_savepath,y_train) np.save(x_test_savepath, x_test_save) np.save(y_test_savepath, y_test) model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(128 , activation='relu' ), # 输出 10 分类 tf.keras.layers.Dense(10 , activation='softmax' ), ]) # 编译 model.compile(optimizer='adam' , loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 训练拟合(validation_split=0.2 从训练集划分20 %比例给测试集,validation_freq=20 20 次epoch测试一次) model.fit(x_train,y_train,batch_size=32 ,epochs=5 ,validation_data=(x_test,y_test),validation_freq=1 ) model.summary()
2.数据增强
(1)注意 1 image_gen_teain.fit(x_train)
fit()
函数需要参数为4D参数,因此需要对数据进行reshape()
6000为样本数量,28*28为样本尺寸大小,1为通道数
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 import tensorflow as tf from tensorflow.keras.preprocessing.image import ImageDataGenerator # 加载mnist 数据 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 x_train = x_train.reshape(x_train.shape[0 ], 28 , 28 , 1 ) # 给数据增加一个维度,从(60000 , 28 , 28 )reshape为(60000 , 28 , 28 , 1 ) # 数据增强 image_gen_train = ImageDataGenerator( rescale=1. / 1. , # 如为图像,分母为255 时,可归至0 ~1 rotation_range=45 , # 随机45 度旋转 width_shift_range=.15 , # 宽度偏移 height_shift_range=.15 , # 高度偏移 horizontal_flip=False, # 水平翻转 zoom_range=0.5 # 将图像随机缩放阈量50 % ) image_gen_train.fit(x_train) model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(128 , activation='relu' ), tf.keras.layers.Dense(10 , activation='softmax' ) ]) model.compile(optimizer='adam' , loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) model.fit(image_gen_train.flow(x_train, y_train, batch_size=32 ), epochs=5 , validation_data=(x_test, y_test), validation_freq=1 ) model.summary()
3.读取保存模型 (1)读取模型
1 2 3 4 5 checkpoint_save_path = "./mnist.ckpt" # 生成ckpt文件时,会同步生成索引表'.index' if os.path.exists(checkpoint_save_path + '.index' ) print('-------load the model--------' ) model.load_weights(checkpoint_save_path)
(2)保存模型
save_weights_only
为是否只保留模型参数、save_best_only
为是否只保留最优结果
执行训练时加入cp_callback选项记录至history中
示例:
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 import os 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 model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(128 , activation='relu' ), tf.keras.layers.Dense(10 , activation='softmax' ) ]) model.compile(optimizer='adam' , loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 读取模型 checkpoint_save_path = "./checkpoint/mnist.ckpt" if os.path.exists(checkpoint_save_path + '.index' ): print('-------------load the model-----------------' ) model.load_weights(checkpoint_save_path) # 创建callback选项 cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path, save_weights_only=True, save_best_only=True) # 执行训练时加入cp_callback选项记录至history中 history = model.fit(x_train, y_train, batch_size=32 , epochs=5 , validation_data=(x_test, y_test), validation_freq=1 , callbacks=[cp_callback]) model.summary()
4.参数提取读入文本 1 model.trainable_varibles # 返回模型中可训练的参数
设置print
输出格式
1 2 3 4 np.set_printoptions(threshold = 超过多少省略显示) # 示例 (这样可以将参数全部显示打印出来,而不会出现省略号) np.set_printoptions(threshold = np.inf) # np.inf 表示无限大
将参数写文本
1 2 3 4 5 6 7 prinr(model.trainable_varibles) file = open('./weights.txt' ,'w' ) for v in model.trainable_varibles: file.write(str(v.name) + '\n' ) file.write(str(v.shape) + '\n' ) file.write(str(v.numpy()) + '\n' ) file.close()
示例:
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 "" " 参数提取读入文本 " "" import tensorflow as tf import os import numpy as np # 设置参数打印方式 (threshold=np.inf 不出现省略全部打印出来) np.set_printoptions(threshold=np.inf) # 读取数据集 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 # 网络模型 model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(128 , activation='relu' ), tf.keras.layers.Dense(10 , activation='softmax' ) ]) # 编译 model.compile(optimizer='adam' , loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 检查是否存在模型训练参数保存的ckpt文件 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) # 训练并且将模型训练参数权重文件进行保存 history = model.fit(x_train, y_train, batch_size=32 , epochs=5 , validation_data=(x_test, y_test), validation_freq=1 , callbacks=[cp_callback]) model.summary() # 打印训练权重文件的参数 print(model.trainable_variables) # 将参数提取写入txt文件中 file = open('./weights.txt' , 'w' ) for v in model.trainable_variables: file.write(str(v.name) + '\n' ) file.write(str(v.shape) + '\n' ) file.write(str(v.numpy()) + '\n' ) file.close()
5.acc 以及 loss 的可视化
在训练model.fit()
的过程中同步记录了以下信息:
可用以下代码进行提取:
可视化代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ############################################### show ############################################### from matplotlib import pyplot as plt # 显示训练集和验证集的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' ] plt.subplot(1 , 2 , 1 ) plt.plot(acc, label='Training Accuracy' ) plt.plot(val_acc, label='Validation Accuracy' ) plt.title('Training and Validation Accuracy' ) plt.legend() plt.subplot(1 , 2 , 2 ) plt.plot(loss, label='Training Loss' ) plt.plot(val_loss, label='Validation Loss' ) plt.title('Training and Validation Loss' ) plt.legend() plt.show()
运行:
6.使用训练后的模型进行预测 输入一张手写数字图片 —-> 输出识别结果
前向传播执行应用
1 predict(输入特征,batch_size = 整数) # 返回前向传播计算结果
下面是预测过程:(复现模型—> 加载参数—> 预测结果)
但是输入的数据需要满足训练的神经网络对于输入数据的要求
六、CNN 卷积神经网络的主要模块
卷积就是特征提取器:CBAPD
1.感受野 卷积神经网络各输出特征图中的每个像素点,在原始输入图片上映射区域的大小
上图中1
是原始输入数据,为5x5
,1
通过一个3x3
的卷积核变为2
,则2的感受野是3
.
在对2
经过一个3x3
的卷积核变为3
,则3
的感受野是5
(原始输入数据为1
)
4
的感受野也是5
2.卷积层
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 import numpy as np import tensorflow as tf model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(6 ,5 ,padding='valid' ,activation='sigmoid' ), tf.keras.layers.MaxPool2D(2 ,2 ), tf.keras.layers.Conv2D(6 ,(5 ,5 ),padding='valid' ,activation='sigmoid' ), tf.keras.layers.MaxPool2D(2 ,(2 ,2 )), tf.keras.layers.Conv2D(filters=6 ,kernel_size=(5 ,5 ),padding='valid' ,activation='sigmoid' ), tf.keras.layers.MaxPool2D(pool_size=(2 ,2 ),strides=2 ), tf.keras.layers.Flatten(), tf.keras.layers.Dense(10 ,activation='softmax' ) ])
3.批量标准化(BN) 神经网络对于0附近的数据更加敏感,但是随着网络层数的增加,特征数据会出现偏离0均值的情况
标准化:使得数据符合0均值,1为标准差的分布(将偏移的数据重新拉回到0附近)
批标准化:对一个batch数据,做标准化处理
批标准化操作会让每个像素点进行减均值除以标准差的自更新计算
在反向传播时,缩放因子,与偏移因子会与其他待训练的参数一同被训练优化,使得标准正太分布后的特征数据,通过缩放因子与偏移因子优化了投入特征数据的宽窄与偏移量,保证了网络的非线性表达力
BN
层位于卷积层之后,激活层之前
(1)BN操作函数 1 tf.keras.layers.BatchNormalization(), # BN层操作
示例:
1 2 3 4 5 6 7 8 9 10 import numpy as np import tensorflow as tf model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(6 ,5 ,padding='valid' ,activation='sigmoid' ), tf.keras.layers.BatchNormalization(), # BN层操作 tf.keras.layers.Activation('relu' ), # 激活层 tf.keras.layers.MaxPool2D(2 ,2 ), tf.keras.layers.Dropout(0.2 ), # Dropout()层 ])
4.池化操作 池化用于减少特征的数据量
最大池化: 可以提取图片纹理
均值池化 :可以保留背景特征
(1)池化函数
示例:
1 2 3 4 5 6 7 8 9 10 import numpy as np import tensorflow as tf model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(6 ,5 ,padding='valid' ,activation='sigmoid' ), tf.keras.layers.BatchNormalization(), # BN层操作 tf.keras.layers.Activation('relu' ), # 激活层 tf.keras.layers.MaxPool2D(pool_size=(2 ,2 ),strides=2 ,padding='same' ), # 池化 tf.keras.layers.Dropout(0.2 ), # Dropout()层 ])
5.舍弃 舍弃(Dropout()
)是一种正则化操作,也是为了防止神经网络过拟合
在神经网络训练时,将一部分神经网络按照一定概率从神经网络中暂时舍弃。神经网络使用时,被舍弃的神经元恢复连接
(1)Dropout函数 1 tf.keras.layers.Dropout(舍弃的概率) # Dropout()层
示例:
1 2 3 4 5 6 7 model = tf.keras.models.Sequential([ tf.keras.layers.Conv2D(6 ,5 ,padding='valid' ,activation='sigmoid' ), tf.keras.layers.BatchNormalization(), # BN层操作 tf.keras.layers.Activation('relu' ), # 激活层 tf.keras.layers.MaxPool2D(pool_size=(2 ,2 ),strides=2 ,padding='same' ), # 池化 tf.keras.layers.Dropout(0.2 ), # Dropout()层 ])
七、CIFAR10数据集
1.导入数据集 1 2 3 4 import tensorflow as tf cifar10 = tf.keras.datasets.cifar10 (x_train,y_train),(x_test,y_test) = cifar10.load_data()
(1)可视化数据集
下载的数据集到下面目录(ubuntu下/home/用户名/.kera
) .kera
是隐藏用户名
2.使用卷积神经网络训练CIFAR10数据集 卷积模型如下:(卷积就是CBAPD—卷积–批量归一化—激活—池化—舍弃)
示例:
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 "" " 搭建卷积神经网络训练 CIFAR10 " "" import tensorflow as tf import os import numpy as np from matplotlib import pyplot as plt np.set_printoptions(threshold=np.inf) cifar10 = tf.keras.datasets.cifar10 (x_train, y_train), (x_test, y_test) = cifar10.load_data() x_train, x_test = x_train / 255.0 , x_test / 255.0 # 搭建网络模型 class Baseline(tf.keras.Model): def __init__(self): super(Baseline, self).__init__() self.c1 = tf.keras.layers.Conv2D(filters=6 , kernel_size=(5 , 5 ), padding='same' ) # C卷积层 self.b1 = tf.keras.layers.BatchNormalization() # B BN层 self.a1 = tf.keras.layers.Activation('relu' ) # A 激活层 self.p1 = tf.keras.layers.MaxPool2D(pool_size=(2 , 2 ), strides=2 , padding='same' ) # P 池化层 self.d1 = tf.keras.layers.Dropout(0.2 ) # D dropout层 self.flatten = tf.keras.layers.Flatten() # 展平层 self.f1 = tf.keras.layers.Dense(128 , activation='relu' ) # 线性层 self.d2 = tf.keras.layers.Dropout(0.2 ) self.f2 = tf.keras.layers.Dense(10 , activation='softmax' ) # 最后10 分类,经过softmax变为概率分布 def call(self, x): x = self.c1(x) x = self.b1(x) x = self.a1(x) x = self.p1(x) x = self.d1(x) x = self.flatten(x) x = self.f1(x) x = self.d2(x) y = self.f2(x) return y # 创建模型示例 model = Baseline() # 编译 model.compile(optimizer='adam' , # 损失函数 传入的非原始数据 from_logits=False (经过了softmax) loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), metrics=['sparse_categorical_accuracy' ]) # 加载模型权重参数 checkpoint_save_path = "./checkpoint/Baseline.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) # 训练 history = model.fit(x_train, y_train, batch_size=32 , epochs=5 , validation_data=(x_test, y_test), validation_freq=1 , callbacks=[cp_callback]) model.summary() # 读取模型训练的权重参数,并进行保存至文本 # print(model.trainable_variables) file = open('./weights.txt' , 'w' ) for v in model.trainable_variables: file.write(str(v.name) + '\n' ) file.write(str(v.shape) + '\n' ) file.write(str(v.numpy()) + '\n' ) file.close() ############################################### show ############################################### # 显示训练集和验证集的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' ] plt.subplot(1 , 2 , 1 ) plt.plot(acc, label='Training Accuracy' ) plt.plot(val_acc, label='Validation Accuracy' ) plt.title('Training and Validation Accuracy' ) plt.legend() plt.subplot(1 , 2 , 2 ) plt.plot(loss, label='Training Loss' ) plt.plot(val_loss, label='Validation Loss' ) plt.title('Training and Validation Loss' ) plt.legend() plt.show()