大多数神经网络训练过程都是比较漫长的,为了避免过程中发生意外导致训练结果丢失,我们需要采用保存训练过程的方法。另外,物品们无法预知多少次训练才能达到合适的准确率,所以往往要在一次程序训练结束后先保存当时的训练结果,再根据当时的误差率来决定是否继续训练,那么,再次训练的时候就需要载入保存的训练结果再往下训练。
当然,如果训练结果不佳,也要可能调整网络结构后重新开始训练,本节,将介绍保存和载入训练过程的方法。
一、保存训练过程
以下代码以身份证问题作为案例,进行保存训练过程.
以下执行程序命名为:idcard4.py
import tensorflow as tf import random random.seed() #定义输入层张量x的变量结构式 x = tf.placeholder(dtype=tf.float32) #定义输出层张量yYrain的标量结构式 yTrain = tf.placeholder(dtype=tf.float32) #定义w1:第一层权重可变参数的值,输入层有4个节点,隐藏层有8个节点,那么w1就是[4,8]矩阵,服众正态分布 w1 = tf.Variable(tf.random_normal([4,8],mean = 0.5,stddev = 0.1),dtype=tf.float32) #定义b1偏移量,与向量或矩阵进行相加减等操作,会对每一个向量或矩阵中的每一个元素都进行相同的操作 b1 = tf.Variable(0,dtype=tf.float32) #定义xr:将输入数据x从一个思维向量转换为一个[1,4]的矩阵,保存在xr变量中,后面进行矩阵乘法运算。 xr = tf.reshape(x,[1,4]) #n1:隐藏层1的结构,tf.matmul函数为矩阵乘法运算,tf.nn.tanh为激活函数tanh,去线性化的作用。 n1 = tf.nn.tanh(tf.matmul(xr,w1) + b1) #定义w2:第二层权重可变参数的值,第一个隐藏层有8个节点,第二个隐藏层有2个节点,那么w1就是[8,2]矩阵,服众正态分布 #定义第二个隐藏层为2个,是为了让输出到输出层的节点数为2,便于应用sorftmax函数 w2 = tf.Variable(tf.random_normal([8,2],mean = 0.5,stddev = 0.1),dtype=tf.float32) #定义b2偏移量 b2 = tf.Variable(0,dtype=tf.float32) #隐藏层2的结构 n2 = tf.matmul(n1,w2) + b2 y = tf.nn.softmax(tf.reshape(n2,[2])) #采用求均方误差函数求误差 loss = tf.reduce_mean(tf.square(y-yTrain)) optimizer = tf.train.RMSPropOptimizer(0.01) train = optimizer.minimize(loss) #定义一个sess变量,调用会话对象 sess = tf.Session() #定义一个init变量,他返回的是一个专门用于初始化可变参数的对象, init = tf.global_variables_initializer() #调用会话对象sess的run函数run() sess.run(init) lossSum = 0.0 for i in range(5): xDataRandom = [int(random.random()*10),int(random.random()*10),int(random.random()*10),int(random.random()*10)] if xDataRandom[2]%2 ==0: yTrainDataRandom = [0,1] else: yTrainDataRandom = [1,0] result = sess.run([train,x,yTrain,y,loss],feed_dict={x:xDataRandom,yTrain:yTrainDataRandom}) #print(result) lossSum = lossSum + float(result[len(result)-1]) print('i:%d,loss:%10.10f,avgLoss:%10.10f'%(i,float(result[len(result)-1]),lossSum/(i+1)))
trainResultPath = './save/idcard2' print('saving...') tf.train.Saver().save(sess,save_path=trainResultPath)
慢慢看完了代码,可以发现,保存训练过程的代码就是:
trainResultPath = './save/idcard2' print('saving...') tf.train.Saver().save(sess,save_path=trainResultPath)
使用一个标量trainResultPath来指定保存训练过程数据的记录,‘./save/idcard2’:保存的位置是执行程序idcard4.py时当下目录的save子目录以idcard2为基本名称的文本。
调用了tensorflow下train包下的Saver函数返回的Saver对象的save成员函数来进行保存,传入的第一个参数当前的会话对象,第二个参数是传入保存的路径位置。
二、载入保存的训练过程并继续训练
一下代码为:idcard4.py
#载入保存的训练过程并继续训练 import tensorflow as tf import random import os trainResultPath = './save/idcard2' random.seed() #定义输入层张量x的变量结构式 x = tf.placeholder(dtype=tf.float32) #定义输出层张量yYrain的标量结构式 yTrain = tf.placeholder(dtype=tf.float32) #定义w1:第一层权重可变参数的值,输入层有4个节点,隐藏层有8个节点,那么w1就是[4,8]矩阵,服众正态分布 w1 = tf.Variable(tf.random_normal([4,8],mean = 0.5,stddev = 0.1),dtype=tf.float32) #定义b1偏移量,与向量或矩阵进行相加减等操作,会对每一个向量或矩阵中的每一个元素都进行相同的操作 b1 = tf.Variable(0,dtype=tf.float32) #定义xr:将输入数据x从一个思维向量转换为一个[1,4]的矩阵,保存在xr变量中,后面进行矩阵乘法运算。 xr = tf.reshape(x,[1,4]) #n1:隐藏层1的结构,tf.matmul函数为矩阵乘法运算,tf.nn.tanh为激活函数tanh,去线性化的作用。 n1 = tf.nn.tanh(tf.matmul(xr,w1) + b1) #定义w2:第二层权重可变参数的值,第一个隐藏层有8个节点,第二个隐藏层有2个节点,那么w1就是[8,2]矩阵,服众正态分布 #定义第二个隐藏层为2个,是为了让输出到输出层的节点数为2,便于应用sorftmax函数 w2 = tf.Variable(tf.random_normal([8,2],mean = 0.5,stddev = 0.1),dtype=tf.float32) #定义b2偏移量 b2 = tf.Variable(0,dtype=tf.float32) #隐藏层2的结构 n2 = tf.matmul(n1,w2) + b2 #先对第二个隐藏层的矩阵形态[1,2]转换为一个向量,[2]就是转换为二维向量 y = tf.nn.softmax(tf.reshape(n2,[2])) #采用求均方误差函数求误差 loss = tf.reduce_mean(tf.square(y-yTrain)) optimizer = tf.train.RMSPropOptimizer(0.01) train = optimizer.minimize(loss) #定义一个sess变量,调用会话对象 sess = tf.Session() #定义一个init变量,他返回的是一个专门用于初始化可变参数的对象, #init = tf.global_variables_initializer() #调用会话对象sess的run函数run() #sess.run(init) if os.path.exists(trainResultPath+'.index'): print('loading:%s'% trainResultPath) tf.train.Saver().restore(sess,save_path=trainResultPath) else: print('train result path not exists:%s'% trainResultPath) sess.run(tf.global_variables_initializer()) lossSum = 0.0 for i in range(5): xDataRandom = [int(random.random()*10),int(random.random()*10),int(random.random()*10),int(random.random()*10)] if xDataRandom[2]%2 ==0: yTrainDataRandom = [0,1] else: yTrainDataRandom = [1,0] result = sess.run([train,x,yTrain,y,loss],feed_dict={x:xDataRandom,yTrain:yTrainDataRandom}) #print(result) lossSum = lossSum + float(result[len(result)-1]) print('i:%d,loss:%10.10f,avgLoss:%10.10f'%(i,float(result[len(result)-1]),lossSum/(i+1))) print('saving......') tf.train.Saver().save(sess,save_path = trainResultPath)
看完了上方的代码,可以看到有两处与保存训练过程不一样的地方:
1、定义的trainResultPath变量的语句在程序开头部分,因为载入训练数据时也需要用到数据文件保存位置的信息。
2、在定义好sess会话变量后,不想以前一样马上调用sess.run(tf.global_variables_initializer())来对可变参数进行初始化,因为如果要载入训练数据,就不能做初始化操作,否则所有的可变参数又被复原为初始值。加上一个条件判断,如果目录下指定位置保存了训练过程文件,就载入相应文件中保存的训练过程信息;否则才去进行初始化可变参数的操作。
三、通过命令行参数控制是否强制重新开始训练
所谓命令行参数:在cmd这种操作文件的窗口中操作,给出某个参数运行在某个运行程序中。
举个例子吧:
自编一个text.py程序:
import sys argt = sys.arge print(arge) print('打印的是:%s'%arge[1])
在该python程序路径位置下,输入python text.py abc
输出的是:
['text.py', 'abc']
Parameter 1:abc
所以,可以利用命令行参数来执行保存好的训练过程文件。
代码命名为:incard6.py
import tensorflow as tf import random import os import sys ifRestartT = False argt = sys.argv[1:] for v in argt: if v == "-restart": ifRestartT = True trainResultPath = "./save/idcard2" random.seed() x = tf.placeholder(tf.float32) yTrain = tf.placeholder(tf.float32) w1 = tf.Variable(tf.random_normal([4, 8], mean=0.5, stddev=0.1), dtype=tf.float32) b1 = tf.Variable(0, dtype=tf.float32) xr = tf.reshape(x, [1, 4]) n1 = tf.nn.tanh(tf.matmul(xr, w1) + b1) w2 = tf.Variable(tf.random_normal([8, 2], mean=0.5, stddev=0.1), dtype=tf.float32) b2 = tf.Variable(0, dtype=tf.float32) n2 = tf.matmul(n1, w2) + b2 y = tf.nn.softmax(tf.reshape(n2, [2])) loss = tf.reduce_mean(tf.square(y - yTrain)) optimizer = tf.train.RMSPropOptimizer(0.01) train = optimizer.minimize(loss) sess = tf.Session() if ifRestartT == True: print("force restart...") sess.run(tf.global_variables_initializer()) elif os.path.exists(trainResultPath + ".index"): print("loading: %s" % trainResultPath) tf.train.Saver().restore(sess, save_path=trainResultPath) else: print("train result path not exists: %s" % trainResultPath) sess.run(tf.global_variables_initializer()) lossSum = 0.0 for i in range(5): xDataRandom = [int(random.random() * 10), int(random.random() * 10), int(random.random() * 10), int(random.random() * 10)] if xDataRandom[2] % 2 == 0: yTrainDataRandom = [0, 1] else: yTrainDataRandom = [1, 0] result = sess.run([train, x, yTrain, y, loss], feed_dict={x: xDataRandom, yTrain: yTrainDataRandom}) lossSum = lossSum + float(result[len(result) - 1]) print("i: %d, loss: %10.10f, avgLoss: %10.10f" % (i, float(result[len(result) - 1]), lossSum / (i + 1))) print("saving...") tf.train.Saver().save(sess, save_path=trainResultPath)
在cmd窗口下,用python incard6.py -restart 这个命令行来执行程序,运行的结果如下:
force restart... i:0,loss:0.2178457528,avgLoss:0.3178457528 i:1,loss:0.1825756580,avgLoss:0.2002107054 i:2,loss:0.3673197329,avgLoss:0.2559137146 i:3,loss:0.1935390979,avgLoss:0.2403200604 i:4,loss:0.1634049714,avgLoss:0.2249370426 saving......
四、从命令行参数读取需要预测的数据
训练神经网络是让神经网络具有可用性,而真正使用神经网络时需要输入数据进行预测。这些输入数据不想训练数据一样又目标值,而是确实通过神经网络计算来获得预测结果的。
下面,介绍通过命令行参数来输入数据的方法进行预测目标值。
import tensorflow as tf import numpy as np import random import os import sys ifRestartT = False predictData = None argt = sys.argv[1:] for v in argt: if v == "-restart": ifRestartT = True if v.startswith("-predict="): tmpStr = v[len("-predict="):] predictData = np.fromstring(tmpStr, dtype=np.float32, sep=",") print("predictData: %s" % predictData) trainResultPath = "./save/idcard2" random.seed() x = tf.placeholder(tf.float32) yTrain = tf.placeholder(tf.float32) w1 = tf.Variable(tf.random_normal([4, 8], mean=0.5, stddev=0.1), dtype=tf.float32) b1 = tf.Variable(0, dtype=tf.float32) xr = tf.reshape(x, [1, 4]) n1 = tf.nn.tanh(tf.matmul(xr, w1) + b1) w2 = tf.Variable(tf.random_normal([8, 2], mean=0.5, stddev=0.1), dtype=tf.float32) b2 = tf.Variable(0, dtype=tf.float32) n2 = tf.matmul(n1, w2) + b2 y = tf.nn.softmax(tf.reshape(n2, [2])) loss = tf.reduce_mean(tf.square(y - yTrain)) optimizer = tf.train.RMSPropOptimizer(0.01) train = optimizer.minimize(loss) sess = tf.Session() if ifRestartT: print("force restart...") sess.run(tf.global_variables_initializer()) elif os.path.exists(trainResultPath + ".index"): print("loading: %s" % trainResultPath) tf.train.Saver().restore(sess, save_path=trainResultPath) else: print("train result path not exists: %s" % trainResultPath) sess.run(tf.global_variables_initializer()) if predictData is not None: result = sess.run([x, y], feed_dict={x: predictData}) print(result[1]) print(y.eval(session=sess, feed_dict={x: predictData})) sys.exit(0) lossSum = 0.0 for i in range(5): xDataRandom = [int(random.random() * 10), int(random.random() * 10), int(random.random() * 10), int(random.random() * 10)] if xDataRandom[2] % 2 == 0: yTrainDataRandom = [0, 1] else: yTrainDataRandom = [1, 0] result = sess.run([train, x, yTrain, y, loss], feed_dict={x: xDataRandom, yTrain: yTrainDataRandom}) lossSum = lossSum + float(result[len(result) - 1]) print("i: %d, loss: %10.10f, avgLoss: %10.10f" % (i, float(result[len(result) - 1]), lossSum / (i + 1))) if os.path.exists("save.txt"): os.remove("save.txt") print("saving...") tf.train.Saver().save(sess, save_path=trainResultPath) resultT = input('Would you like to save? (y/n)') if resultT == "y": print("saving...") tf.train.Saver().save(sess, save_path=trainResultPath)
predictData:[1,2,3,4]
loading:./save.idcard2 [0.32765886 0.67232467]
[0.32765886 0.67232467]