這篇文章是針對(duì)有tensorflow基礎(chǔ)但是記不住復(fù)雜變量函數(shù)的讀者,文章列舉了從輸入變量到前向傳播,反向優(yōu)化,數(shù)據(jù)增強(qiáng)保存,GPU并行計(jì)算等常用的指令,希望通過(guò)這一篇來(lái)完成整體網(wǎng)絡(luò)的參考實(shí)現(xiàn)。
最后建議寫(xiě)一個(gè)模板化的訓(xùn)練流程,以后改網(wǎng)絡(luò)就可以只修改其中一小部分。-horsetif
1,輸入端:
get_variable 和 Variable
#初始化 1,get_variable,必須指定變量名稱參數(shù)
tf.get_variable(name,shape=[1],initializer=xxx)
#初始化 2,Variable,不必要指定變量名稱參數(shù)
tf.Variable(tf.xxx(a,shape=[]),name)
tf.Variable(0,dtype=tf.float32,name)
#變量后綴
constant,random_normal,truncated_normal,random_uniform,zeros,ones.
命名空間
##############定義命名空間#####################這樣對(duì)調(diào)試很有用
with tf.variable_scope('foo'):
? ? a=tf.get_variable('bar',[1])#受到命名空間影響
with tf.name_scope('a'):
? ? a=tf.Variable([1])#受到命名空間影響
? ? b=tf.get_variable('b',[1])#不受命名空間影響
計(jì)算圖
#graph###############################################
#不同的計(jì)算圖上的張量和運(yùn)算都不會(huì)共享
g1=tf.Graph()
with g1.as_default():
? ? v=tf.get_variable('v',...)
with tf.Session(graph=g1) as sess:
? ? with tf.variable_scope('',reuse=Ture):
? ? ? ? sess.run(tf.get_variable('v'))
張量使用
#張量的使用
a=tf.constant([1.0,2.0],name='a')
session
會(huì)話session########################################
1,sess=tf.Session()? sess.run()? sess.close()
2,with tf.Session() as sess:
3,sess=tf.Session()
with sess.as_default():
? ? print(result.eval())
完全等同于:result.eval(session=sess)
4,sess=tf.InteractiveSession()
result.eval()
sess.close()
config
#################################config##################
config=tf.ConfigProto(allow_soft_placement=True,log_device_placement=True)
Variable初始化賦值
w2=tf.Variable(weight.initialized_value()) 這里的值是完全相同的
trainable,shape,name,type
tf.assign(w1,w2,validate_shape=False)
tf.assign(v1,10)
placeholder? 輸入端動(dòng)態(tài)賦值
placeholder(tf.float32,shape=(1,2),name='input')
? 2,前向傳播端:
tf.add_to_collection('losses',regularizer(weights))
with tf.variable_scope('layer1'):
2)卷積:
filter_weight=tf.get_variable('weights',[5,5,32,16],initializer=tf.truncated_normal_initializer(stddev=0.1))
[卷積核大小,輸入大小,輸出大小]
bias=tf.get_variable('bias',[16j],tf.constant_initializer(0.1))
conv=tf.nn.conv2d(input,filter_weight,strides=[1,1,1,1],padding='SAME'/'VALID')
strides:步長(zhǎng)的第一和第四都要為1。
bias=tf.nn.bias_add(conv,bias)
actived_conv=tf.nn.relu(bias)
#############池化############################
pool=tf.nn.max_pool(actived_conv,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
ksize--過(guò)濾器尺寸,1和4維度必須為1.strides--步長(zhǎng),1和4維度必須為1.
#############pooling 層 轉(zhuǎn)全連接層#########################
pool_shape=pool2.get_shape().as_list()
nodes=pool_shape[1]*pool_shape[2]*pool_shape[3]
reshaped=tf.reshape(pool2,[pool_shape[0],nodes])
###############tensorflow-slim工具#########################
net=slim.conv2d(input,32,[3,3],scope='..')? ? ? #深度,核數(shù)
#######################鏈接不同卷積###########################
net=tf.concat(3,[a,b,c,..e]) 這里的三指的是第三維度,
#############################drop out 層########################
hidden1_drop=tf.nn.dropout(hidden1,keep_prob)
3,反向傳播端
#正則化
tf.contrib.layers.l1_regularizer(.5)(weights)
利用tf.add_to_collection('loss',...) tf.get_collection('loss')
#學(xué)習(xí)率衰減
decayed_learning_rate=learning_rate*decay_rate^(global_step/decay_steps)
learning_rate=tf.train.exponential_decay(basic_learning_rate,global_step,training_step,learning_rate_decay,staircase=True)
training_step:過(guò)完所有訓(xùn)練所需要的訓(xùn)練次數(shù)
#滑動(dòng)平均模型
ema=tf.train.ExponentialMovingAverage(0.99,step)#定義好模型
maintain_average_op=ema.apply([v1])#注冊(cè)輸入variables_averages_op=ema.apply(tfe.trainable_variables())
sess.run(maintain_average_op)#開(kāi)始優(yōu)化
sess.run([v1,ema.average(v1)])#查看輸出
#計(jì)算結(jié)果loss
tf.nn.sparse_softmax_cross_entropy_with_logits(y,tf.argmax(y_1,1))
cross_entropy_mean=tf.reduce_mean(cross_entropy)
loss=cross_entropy_mean+tf.add_n(tf.get_collection('loss'))
loss=-tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))
mse=tf.reduce_mean(tf.square(y_-y))
tf.select(tf.greater(v1,v2),v1,v2)
#反向傳播優(yōu)化函數(shù)
train_step=tf.train.AdamOptimizer(learning_rate).minimize(loss,global_step=global_step)
有時(shí)候使用GradientDescentOptimizer反而好一些
#優(yōu)化函數(shù)和滑動(dòng)平均同時(shí)進(jìn)行
with tf.control_dependencies([train_step,variables_averages_op]):
? ? ? ? ? ? train_op=tf.no_op(name='train')
or: train_op=tf.group(train_step,variables_average_op)
#dropout 一般只在全連接層而不是卷積層
fc1=tf.nn.dropout(fc1,0.5)
4,輸出端:
save and restore
saver=tf.train.Saver()
saver.save(sess,'path/model.ckpt',global_step=global_step)
#checkpoint 文件列表
#model.ckpt.data 變量取值
#model.ckpt.meta 計(jì)算圖結(jié)構(gòu)
saver.restore(sess,'./model/model.ckpt')
#這里初始定義以及其他所有的操作都是需要的,唯一不需要的就是初始化的操作,因?yàn)槌跏蓟僮魑覀兪窃趓estore中讀取的。經(jīng)過(guò)測(cè)試,必須要在同一個(gè)sess中使用。
#如果我們不希望重復(fù)定義圖上的運(yùn)算,我們可以直接加載已經(jīng)持久化的圖。
saver=tf.train.import_meta_graph('./model/model.ckpt.meta')
with tf.Session() as sess:
? ? ? ? saver.restore(sess,'./model/model.ckpt')? ? ? ? print(sess.run(tf.get_default_graph().get_tensor_by_name('add:0')))
#只讀取部分參數(shù)
saver=tf.train.Saver([v1]) #這里只會(huì)讀取v1參數(shù),不會(huì)讀取其他任何參數(shù)
saver2=tf.train.Saver({'v1':v1})#變量重命名
v1=tf.Variable(tf.constant(1,shape=[1]),name='v_other1')
saver2=tf.train.Saver({'v1':v1})
#由于滑動(dòng)平均模型有隱藏變量,所以我們把這些變量對(duì)應(yīng)映射的到真實(shí)變量上
saver=tf.train.Saver(ema.variables_to_restore())
#全部保存
with tf.Session() as sess:
? ? ? ? tf.global_variables_initializer().run()
? ? ? ? graph_def=tf.get_default_graph().as_graph_def()? ? ? ? output_graph_def=graph_util.convert_variables_to_constants(sess,graph_def,['add'])? ? ? ? with tf.gfile.GFile('./model/combined_model.pb','wb') as f:? ? ? ? ? ? ? ? f.write(output_graph_def.SerializeToString())
#整體讀取預(yù)測(cè)評(píng)估:
with tf.Session() as sess:
? ? ? ? with gfile.FastGFile('./model/combined_model.pb','rb') as f:
? ? ? ? ? ? ? ? graph_def=tf.GraphDef()
? ? ? ? ? ? ? graph_def.ParseFromString(f.read())? ? ? ? result=tf.import_graph_def(graph_def,return_elements=['add:0'])#獲取這個(gè)計(jì)算圖的變量? ? ?
? ? print(sess.run(result))
######抽取網(wǎng)絡(luò)中的一部分值
? ? or bootleneck_tensor,image_data=tf.import_graph_def(graph_def,return_elements=['a','b'])
? ? or bottleneck_values=sess.run(bottleneck_tensor,{image_data_tensor:image_data})
5,預(yù)測(cè)評(píng)估端
#預(yù)測(cè)真確率
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))? ? accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#獲取隱含變量
? ema=tf.train.ExponentialMovingAverage(0.99)? ? variables_to_restore=ema.variables_to_restore()? ? saver=tf.train.Saver(variables_to_restore)
#利用checkpoint 獲取最新值:
ckpt=tf.train.get_checkpoint_state('./model/')
? ? ? ? ? ? ? ? if ckpt and ckpt.model_checkpoint_path:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? saver.restore(sess,ckpt.model_checkpoint_path)? ? ? ? ? ? ? ? ? ? ? ? ? ? global_step=ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]? ? ? ? ? ? ? ? ? ? ? ? ? ? accuracy_score=sess.run(accuracy,feed_dict=valid_feed)
? ? ? ? ? ? ? ? ? ? ? ? ? ? print('after %s iterations,the valid set acc= %g'%(global_step,accuracy_score))? ? ? else:
? ? ? ? ? ? ? ? ? ? ? ? print('No checkpoint file found!')? ? return
#如果出現(xiàn)tensor流復(fù)用的情況,會(huì)報(bào)錯(cuò)。這里我們使用:
with tf.Graph().as_default() as g: 這個(gè)方法,每次都能更新新的值。
6,數(shù)據(jù)集處理及其保存讀取
#####################寫(xiě)入TFRecord文件
def _int64_feature(value):
? ? return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
def _bytes_feature(value):
? ? return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
filename='output.tfrecords'
writer=tf.python_io.TFRecordWriter(filename)
for index in range(num_examples):
? ? ? ? image_raw=images[index].tostring()? ? ? ? example=tf.train.Example(features=tf.train.Features(feature={? ? ? ? ? ? ? ? 'pixels':_int64_feature(pixels),? ? ? ? 'label':_int64_feature(np.argmax(labels[index])),? ? ? ? ? ? ? ? 'image_raw':_bytes_feature(image_raw)? ? }))
? ? ? ? writer.write(example.SerializeToString())
writer.close()
###########################讀取TFRecord文件########################
reader=tf.TFRecordReader()filename_queue=tf.train.string_input_producer(['output.tfrecords'])#創(chuàng)建隊(duì)列維護(hù)文件列表
_,serialized_example=reader.read(filename_queue)
features=tf.parse_single_example(? ? serialized_example,? ? features={? ? ? ? ? ? ? ? 'image_raw':tf.FixedLenFeature([],tf.string),
? ? ? ? ? ? ? ? 'pixels':tf.FixedLenFeature([],tf.int64),
? ? ? ? ? ? ? ? 'label':tf.FixedLenFeature([],tf.int64),? ? })
images=tf.decode_raw(features['image_raw'],tf.uint8)labels=tf.cast(features['label'],tf.int32)
pixels=tf.cast(features['pixels'],tf.int32)
sess=tf.Session()
coord=tf.train.Coordinator()#啟動(dòng)多線程
threads=tf.train.start_queue_runners(sess=sess,coord=coord)
for i in range(10):
? ? ? ? ? ? image,label,pixel=sess.run([images,labels,pixels])
##########################關(guān)于圖片的編碼和解碼#####################
img_data=tf.image.decode_jpeg(image_raw_data)
img_data=tf.image.convert_image_dtype(img_data,dtype=tf.float32)
encoded_image=tf.image.encode_jpeg(img_data)
############################圖像讀寫(xiě)##############################
with tf.gfile.GFile('./output','wb') as f:
? ? ? ? f.write(encoded_image.eval())
###############調(diào)整圖像大小########################3
resized=tf.image.resize_images(image_data,[300,300],method=0)
tf.image.resize_iamge_with_crop_or_pad(image_data,1000,3000)
還有其他各種調(diào)整這里先不寫(xiě)了
############################關(guān)于隊(duì)列#####################3
隊(duì)列初始化:q=tf.FIFOQueue(2,'int32') or tf.RandomShuffleQueue(2,'int32')
q.dequeue() q.enqueue([y]) q.enqueue_many(([0,10],))
###########################開(kāi)啟多線程############################
tf.Coordinator()? -->should_stop(查看是否應(yīng)該停止),request_stop(要求全部停止),join(回收線程)
coord=tf.train.Coordinator()
threads=[threading.Thread(target=MyLoop,args=(coord,i)) for i in range(10)]
for t in threads:? ? t.start()
coord.join(threads)
def MyLoop(coord,work_id):
? ? ? ? while not coord.should_stop():
? ? ? ? ? ? ? ? ? ? ? ? ? ? if np.random.rand()<0.05:? ? ? ? ? ? print('stopping from id: %d\n'%(work_id))? ? ? ? ? ? coord.request_stop()
? ? ? ? ? ? ? ? ? ? ? ? ? ? else:? ? ? ? ? ? print('working on id: %d\n'%(work_id)
? ? ? ? time.sleep(2)
###################隊(duì)列版本的多線程服務(wù)###############################
qr=tf.train.QueueRunner(queue,[enqueue_op]*5)(定義隊(duì)列線程以及操作)
tf.train.add_queue_runner(qr) (注冊(cè))
coord=tf.train.Coordinator()? ? threads=tf.train.start_queue_runners(sess=sess,coord=coord)(把隊(duì)列和多線程鏈接)
#下面是sess的正常操作
? ? coord.request_stop()? coord.join(threads)#關(guān)閉和回收
##################################文件多線程操作#####################
files=tf.train.match_filenames_once('./data/data.tfrecords-*')#讀取文件名
filename_queue=tf.train.string_input_producer(files,shuffle=False)#加入文件隊(duì)列
#接下來(lái)是正常的讀取文件套路
tf.local_variables_initializer().run()#這里一定要初始化這個(gè)
coord=tf.train.Coordinator()? ? threads=tf.train.start_queue_runners(sess=sess,coord=coord)#注冊(cè)為多線程
#開(kāi)始讀取
? ? coord.request_stop()
? ? coord.join(threads)
##################################batching ##########################
隊(duì)列的入隊(duì)操作是生成單個(gè)樣本的方法,而每次出隊(duì)得到的是一個(gè)batch的樣例。
#前面是正常的文件名讀取,加入隊(duì)列,配置reader隊(duì)列。
example,label=features['i'],features['j']
example_batch,label_batch=tf.train.batch([example,label],batch_size=batch_size,capacity=capacity)#(batch_size是每一個(gè)batch的大小,capacity是隊(duì)列所能夠承載的能力)
###tf.train.shuffle_batch 是打亂排序的,有一個(gè)特有的參數(shù),就是 min_after_dequeue,限制出隊(duì)時(shí)最小元素個(gè)數(shù)
coord=tf.train.Coordinator()? ? threads=tf.train.start_queue_runners(sess=sess,coord=coord)
cur_example_batch,cur_label_batch=sess.run([example,label])
#接下來(lái)是一樣的
#############################最終讀取注意點(diǎn)##########################
再?gòu)腡FRecord中讀取之后,得到的照片是byte形式的,這里,我們要解析圖像還原為原始尺寸照片。
decoded_image=tf.decode_raw(image,tf.uint8)
decoded_image.set_shape([height,width,channels])
7,tensorboard 可視化調(diào)試
#tensorboard讀取log命令
python /home/horsetif/.local/lib/python3.6/site-packages/nsorboard/main.py --logdir='/home/horsetif/Code/TF_HTF/data/flower_photos/log/'(這里是我自己的地址)
###############保存為日志文件##################################
writer=tf.summary.FileWriter('./log',tf.get_default_graph())
writer.close()
#########################更新節(jié)點(diǎn)信息代碼############################
if i %1000==0:
? ? ? ? run_options=tf.RunOptions(trace_level=tr.RunOptions.FULL_TRACE)? ? ? ? run_metadata=tf.RunMetadata()
? ? ? ? sess.run(...,run_metadata=run_metadata)? ? ? ? train_writer.add_run_metadata(run_metadata,'step%03d'%i)
#############################監(jiān)控指標(biāo)可視化############################
with tf.name_scope('aa'):#先加這個(gè)
tf.scalar_summary(name_path,variable)#標(biāo)量變化
tf.image_summary#輸入圖象變化
tf.histogram_summary#張量變化,如weight
merged=tf.merge_all_summaries()
summary_writer=tf.train.SummaryWriter(SUMMARY_DIR,sess.graph)
summary=sess.run(merged,feed_dict={})
summary_writer.add_summary(summary,i),
8,GPU加速
#如果沒(méi)有明確地指定運(yùn)行路徑,tensorflow會(huì)優(yōu)先選擇GPU。
#改變GPU位置
with device('/gpu:1'):? with device('/cpu:0'):
#如果無(wú)法放在GPU上的代碼,我們讓他們放在cpu上。
sess=tf.Session(config=tf.ConfigProto(allow_soft_placement=True,log_device_placement=True))
#多個(gè)GPU并行計(jì)算問(wèn)題,一般使用并行同步模式。所有設(shè)備同時(shí)讀取參數(shù)取值,并且反向傳播算法完成后同步更新參數(shù)的取值。所有設(shè)備參數(shù)一致,完成反向傳播后,計(jì)算出不同設(shè)備上參數(shù)梯度的平均值,最后再根據(jù)平均值對(duì)參數(shù)進(jìn)行更新。
#主要是利用不同的scope空間來(lái)劃分區(qū)域,然后求和再取平均。
with tf.device('/gpu:%d' %d):
? ? with tf.name_scope('GPU %d'%i) as scope:
tf.get_collection('losses',scope)