TensorFlow基礎(二)
- 2019 年 10 月 6 日
- 筆記
在pandas中也可以讀取數據,但是他存在的問題(僅僅以我們學過的角度來看)有:
1、一次讀取數據,消耗內存
2、一次性進行訓練
而在tensorflow中提供多線程,並行的執行任務,隊列(數據的共享),文件(tfrecords)的方式讀取數據。來提高解析速度。
你可能聽過在Python中沒有真正的多線程,原因是python存在GIL鎖。但是你可能還不知道在numpy中釋放了GIL鎖,而機器學習庫都是基於numpy的。
因此在學習tensorflow讀取數據欠還要了解隊列和線程。
隊列和線程(tensorflow中)
隊列
在tensorflow中對隊列進行了封裝:
tf.FIFOQueue(capacity,dtypes,name='info_queue')
# 前進先出隊列,按順序出隊列
capacity:整數,可能存儲此隊列的元素上限
簡單隊列Demo:
# 1、定義隊列 # 最多放5個數據,類型為float32 Q = tf.FIFOQueue(5,tf.float32) # 放入一些數據,這裡存放列表寫成[[1,2,3,4,5],],防止認為是張量 e_many = Q.enqueue_many([[1,2,3,4,5],]) # 取出數據,乘以2 out_q = Q.dequeue() data = out_q*2 # 再放入隊列 en_q = Q.enqueue(data) with tf.Session() as sess: # 初始化隊列 sess.run(e_many) # 處理數據100次,這裡只用運行en_q,就會運行 # 去除數據,*2,放入隊列這三步操作,Tensorflow中操作具有依賴性 # 運行en_q,en_q依賴data,data依賴out_q for i in range(100): sess.run(en_q) # 取數據 for i in range(Q.size().eval()): print(sess.run(out_q))
tf.RandomShuffleQueue:隨機出隊列
用到的時候再說。
線程
叫做隊列管理器,但是是創建線程的作用。
tf.train.QueueRunner(queque,enqueue_ops=None)
queue: 一個隊列
enqueue_ops:添加線程的隊列操作列表,[]*2代表創建2個線程,[]中寫操作
在sess中啟動線程
create_threads(sess,coord=None,start=False)
coord:線程協調器,當結束後回收子線程
start:True啟動線程,如果為False,還需要條用start()啟動線程。
Demo實例:
# 模擬實現子線程讀取數據,而主線程進行訓練,二者並行 # 定義一個隊列 Q = tf.FIFOQueue(1000,tf.float32) # 定義子線程需要做的事情 循環加1 放入隊列 var = tf.Variable(0.0) # 每次加1,如果不使用assign_add,每次都是0+1會一直是1 data = tf.assign_add(var,1.0) # 放入隊列 en_q = Q.enqueue(data) # 定義隊列管理器op,指定線程做什麼 qr = tf.train.QueueRunner(Q,enqueue_ops=[en_q]*2) # 初始化變量op init_op = tf.global_variables_initializer() with tf.Session() as sess: # 初始化變量 sess.run(init_op) # 開啟線程協調器,當主線程結束回收子線程 coord = tf.train.Coordinator() # 開啟子線程 threads = qr.create_threads(sess,coord=coord,start=True) # 主線程讀取數據,訓練 for i in range(1000): print(sess.run(Q.dequeue())) # 回收子線程 coord.request_stop() coord.join(threads)
注意:其實以上過程以後都不需要自己寫。但是要了解。
文件讀取
文件讀取流程
1、構建一個文件隊列
2、讀取隊列內容
3、解碼
4、批處理
文件讀取api介紹
構造文件隊列
tf.train.string_input_producer(string_tensor)
string_tensor:含有文件名的1階張量
讀取文件內容(不同文件,讀取api不同)
文本,csv文件讀取:tf.TextLineReader,按行讀取
二進制文件:tf.FixedLengthRecordReader(record_bytes)
record_bytes:整型,指定每次讀取的位元組數
Tfrecords文件:tf.TFrecordReader
解碼
解碼csv文件:tf.decode_csv(records,record_defaults=None,dileld_delim=None)
將csv轉換成張量,和tf.TextLineReader搭配使用。
records:讀取的內容
dileld_delim:分隔符,默認為,
record_defaults:張量類型,設置缺少默認值.
解碼二進制:tf.decode_raw()
csv文件讀取Demo
def csvread(filelist): # 構造文件隊列,返回的是一個隊列 file_queue = tf.train.string_input_producer(filelist,shuffle=False) # 構造csv閱讀器讀取隊列數據,默認按照行讀取 reader = tf.TextLineReader() # 得到讀取的數據key是讀取的文件名,value是讀取的數據 key, value = reader.read(file_queue) # 解碼 # record_defaults指定讀取的文件每一列的類型 # 比如csv的第一列數據是1,2,3,第二列為python,java,C # 也就是第一列為float,第二列為string # record_defaults就是指定每列的類型,和默認值 # 1.0為float,說明數據第一列為float類型,默認值是1 # ,""為string類型,說明第二列為string類型,默認值是None records = [[1.0],["None"]] # 返回為每個列的每個值 rad_num,label = tf.decode_csv(value,record_defaults=records) # 讀取多個數據,批處理 # 參數一:批處理的值 # 參數二:每批次讀取多少數據 # 參數三:開啟多少線程 # 參數四:隊列的大小 rad_num_batch,label_batch = tf.train.batch([rad_num,label],batch_size=9,num_threads=1,capacity=9) return rad_num_batch,label_batch if __name__ == "__main__": # 自己創建csv文件,列數不必太多 # 將文件放入列表 import os # 去除警告消息 os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # os.listdir:返回該目錄下文件名的列表 file_name = os.listdir("./csvdata/") # 拼接路徑 filelist = [os.path.join("./csvdata",file) for file in file_name] rad_num_batch,label_batch = csvread(filelist) # 開啟會話 with tf.Session() as sess: # 定義線程協調器 coord = tf.train.Coordinator() # 開啟讀取文件的線程,不用上面那樣麻煩了 threads = tf.train.start_queue_runners(sess, coord=coord) # 打印讀取的內容 print(sess.run([rad_num_batch,label_batch])) # 回收線程 coord.request_stop() coord.join(threads)
讀取圖像和二進制下篇見。