貓狗大戰2.0 使用tensorflow和tfrecord
距離上次的部落格已經過去了半個月兩週左右的時間,自己在b站和部落格上學習了很多相關的知識,自我感覺自己的tensorflow的水平已經算是到了入門的水平,在部落格上有相關的非tensorboard匯入資料,實測有效(傳送門由於時間久了,暫時找不到了,自己找一下吧)。不過通過tensorboard的可執行資料卻十分少,所以自己在此記錄一下自己的程式,也算是自己整理一下。
如果感覺有用,可以點一下關注喲!我會不定期更新一些自己學習的東西。
使用的IDE是vscode(python3.5),資料下載可以在其他部落格中找一下。
首先工程圖如下:
Data資料夾下有train和test兩個資料夾,就是下載的資料集。Logs存放咱們所有的程式。
首先我們要建立建立tfrecord的檔案:
首先得到資料夾train下的所有檔名稱,貼出程式碼如下:
import tensorflow as tf import numpy as np import os NumClass = 2 ImageWidth = 208 ImageHeight = 208 ImageChannel = 3 def get_files(file_dic): cats = [] dogs = [] cats_labels = [] dogs_labels = [] for file in os.listdir(file_dic): #得到檔案下所有的檔名稱,也就是cat.0jpg.... name = file.split(sep='.') if name[0] == 'cat': cats.append(file_dic+'/'+file) cats_labels.append(0) if name[0] == 'dog': dogs.append(file_dic+'/'+file) dogs_labels.append(1) return cats, cats_labels, dogs, dogs_labels cats, cats_labels, dogs, dogs_labels = get_files('G:/CatsAndDogs/data/train') print(cats)
得到的輸出為:
['G:/CatsAndDogs/data/train/cat.0.jpg', 'G:/CatsAndDogs/data/train/cat.1.jpg'...
可以看到檔名稱都已匯入cats等列表當中,那麼接下來的操作就是把image和label的列表連線起來並打亂資料。程式碼貼出如下。
#將檔案打亂順序 image_list = np.hstack((cats, dogs)) #將兩個列表連線起來 labels_list = np.hstack((cats_labels, dogs_labels)) temp = np.array([image_list, labels_list]) temp = temp.transpose() #轉置矩陣 np.random.shuffle(temp) #打亂資料,下面的圖片是temp現在的資料 ##從打亂的temp中再取出list,相當於洗牌之後的重新摸牌 image_list = list(temp[:, 0]) label_list = list(temp[:, 1]) label_list = [int(i) for i in label_list] # 字串型別轉換為int型別
現在temp程式跑到這的資料結果如下圖所示:
嗯,到現在為止也很成功,那我們接下來繼續操作,這個時候又變成了需要對整個列表的操作,所以我們需要整個列表的長度,再把相片的解碼出來。
from scipy.misc import imread,imresize #注意是得重新載入一個model
#首先要確定整個列表的長度並且初始化相片的格式
num_file = len(cats_labels) + len(dogs_labels)
images = np.zeros((num_file, ImageHeight, ImageWidth, ImageChannel), dtype = np.uint8)
for index in range(num_file):
img = imread(image_list[index])
img = imresize(img, (ImageWidth, ImageHeight))
images[index] = img
接下來我們可以把這些相片,labels等資訊傳入一個類中,用來建立接下來的tdrecord檔案。
class ImgData(object):
pass
result = ImgData()
result.images = images
result.labels = label_list
result.num = num_file
到此我們就完成了第一個函式。此時得到了資料夾中亂序的所有照片及相應的標籤,暫時完成了第一步的工作。接下來我們就開始第二部的工作,完成tfrecord檔案的完成。
def convert(data, destination, destination1):
"""將圖片儲存為.tfrecords檔案
引數:
data: 上述函式返回的ImageData物件
destination: 目標檔名
"""
images = data.images
labels = data.labels
num_examples = data.num - 3000
#使用上面使用的類進行下面的tfreord建立,照片標籤以及資料
# 儲存的檔名
filename = destination
#儲存時的檔名(帶路徑的)
# 使用TFRecordWriter來寫入資料
writer = tf.python_io.TFRecordWriter(filename)
#使用tfrecord進行寫入
# 遍歷圖片
for index in range(num_examples):
# 轉為二進位制
image = images[index].tostring()
label = labels[index]
#直接使用上面所建立的類進行輸入
# tf.train下有Feature和Features,需要注意其區別
# 層級關係為Example->Features->Feature(很重要)
#注意圖片一般的型別為ByteList,其他的有Int64List和FloatList型
example = tf.train.Example(features=tf.train.Features(feature={
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
}))
# 寫入建立的example
writer.write(example.SerializeToString())
writer.close()
filename1 = destination1
writer = tf.python_io.TFRecordWriter(filename1)
for index in range(3000):
# 轉為二進位制
image = images[index+num_examples].tostring()
label = labels[index+num_examples]
example = tf.train.Example(features=tf.train.Features(feature={
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
}))
writer.write(example.SerializeToString())
writer.close()
convert(result, 'G:/CatsAndDogs/logs/traintfrecord', 'G:/CatsAndDogs/logs/testtfrecord')
上面的註釋很清楚,應該可以看懂,主要是有train和test兩個部分,不太懂的也可以百度查一下,應該可以找到相關的資料。接下來的就是解碼一下資料。
def read_and_decode(filename_queue, batch_size, capacity):
"""讀取.tfrecords檔案
引數:
filename_queue: 檔名, 一個列表
返回:
img, label: **單張圖片和對應標籤**
"""
# 建立一個圖節點,該節點負責資料輸入
filename_queue = tf.train.string_input_producer([filename_queue])
# tf.train.string_input_producer函式把我們需要的全部檔案打包為一個tf內部的queue型別
# 之後tf開檔案就從這個queue中取目錄了,要注意一點的是這個函式的shuffle引數預設是True
# 所以讀取的順序可能不一樣
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
# 讀取前面所建立的資料目錄
# 解析單個example
# 暫時不大清楚下面的操作,不過感覺應該是得到各個features
features = tf.parse_single_example(serialized_example, features={
'image': tf.FixedLenFeature([], tf.string),
'label': tf.FixedLenFeature([], tf.int64)
})
# tf.decode_raw函式的意思是將原來編碼為字串型別的變數重新變回來
# 這個方法在資料集dataset中很常用,因為製作圖片源資料一般寫進tfrecord裡用to_bytes的形式,也就是字串
# 這裡將原始資料取出來,必須制定原始資料的格式,原始資料是什麼格式這裡解析必須是什麼格式!!
# tf.cast這個函式主要用於資料型別的轉變,不會改變原始資料的值還有形狀的
image = tf.decode_raw(features['image'], tf.uint8)
image = tf.reshape(image, [ImageHeight, ImageWidth, ImageChannel])
image = tf.cast(image, tf.float32)
label = tf.cast(features['label'], tf.int32)
image_batch, label_batch = tf.train.batch([image, label],
batch_size=batch_size,
num_threads=64, # 執行緒
capacity=capacity)
return image, label
上面是解析tfrecord的函式,那麼可以利用下面的程式進行train和test資料的獲得。
image, label = read_and_decode('G:/CatsAndDogs/logs/traintfrecord', 16, 2000)
image1, label1 = read_and_decode('G:/CatsAndDogs/logs/testtfrecord', 16, 2000)
整體的函式如下:
import tensorflow as tf
import numpy as np
import os
from scipy.misc import imread,imresize
NumClass = 2
ImageWidth = 208
ImageHeight = 208
ImageChannel = 3
def get_files(file_dic):
cats = []
dogs = []
cats_labels = []
dogs_labels = []
#得到檔案下所有的檔名稱,也就是cat.0jpg....
for file in os.listdir(file_dic):
name = file.split(sep='.')
if name[0] == 'cat':
cats.append(file_dic+'/'+file)
cats_labels.append(0)
if name[0] == 'dog':
dogs.append(file_dic+'/'+file)
dogs_labels.append(1)
num_file = len(cats_labels) + len(dogs_labels)
images = np.zeros((num_file, ImageHeight, ImageWidth, ImageChannel), dtype = np.uint8)
print("There are %d cats\nThere are %d dogs" % (len(cats), len(dogs)))
#將檔案打亂順序
image_list = np.hstack((cats, dogs))
labels_list = np.hstack((cats_labels, dogs_labels))
temp = np.array([image_list, labels_list])
temp = temp.transpose()
np.random.shuffle(temp)
##從打亂的temp中再取出list(img和lab)
image_list = list(temp[:, 0])
label_list = list(temp[:, 1])
label_list = [int(i) for i in label_list] # 字串型別轉換為int型別
for index in range(num_file):
img = imread(image_list[index])
img = imresize(img, (ImageWidth, ImageHeight))
images[index] = img
class ImgData(object):
pass
result = ImgData()
result.images = images
result.labels = label_list
result.num = num_file
return result
def convert(data, destination, destination1):
"""將圖片儲存為.tfrecords檔案
引數:
data: 上述函式返回的ImageData物件
destination: 目標檔名
"""
images = data.images
labels = data.labels
num_examples = data.num - 3000
#使用上面使用的類進行下面的tfreord建立,照片標籤以及資料
# 儲存的檔名
filename = destination
#儲存時的檔名(帶路徑的)
# 使用TFRecordWriter來寫入資料
writer = tf.python_io.TFRecordWriter(filename)
#使用tfrecord進行寫入
# 遍歷圖片
for index in range(num_examples):
# 轉為二進位制
image = images[index].tostring()
label = labels[index]
#直接使用上面所建立的類進行輸入
# tf.train下有Feature和Features,需要注意其區別
# 層級關係為Example->Features->Feature(很重要)
#注意圖片一般的型別為ByteList,其他的有Int64List和FloatList型
example = tf.train.Example(features=tf.train.Features(feature={
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
}))
# 寫入建立的example
writer.write(example.SerializeToString())
writer.close()
filename1 = destination1
writer = tf.python_io.TFRecordWriter(filename1)
for index in range(3000):
# 轉為二進位制
image = images[index+num_examples].tostring()
label = labels[index+num_examples]
example = tf.train.Example(features=tf.train.Features(feature={
'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
}))
writer.write(example.SerializeToString())
writer.close()
convert(result, 'G:/CatsAndDogs/logs/traintfrecord', 'G:/CatsAndDogs/logs/testtfrecord')
def read_and_decode(filename_queue, batch_size, capacity):
"""讀取.tfrecords檔案
引數:
filename_queue: 檔名, 一個列表
返回:
img, label: **單張圖片和對應標籤**
"""
# 建立一個圖節點,該節點負責資料輸入
filename_queue = tf.train.string_input_producer([filename_queue])
# tf.train.string_input_producer函式把我們需要的全部檔案打包為一個tf內部的queue型別
# 之後tf開檔案就從這個queue中取目錄了,要注意一點的是這個函式的shuffle引數預設是True
# 所以讀取的順序可能不一樣
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
# 讀取前面所建立的資料目錄
# 解析單個example
# 暫時不大清楚下面的操作,不過感覺應該是得到各個features
features = tf.parse_single_example(serialized_example, features={
'image': tf.FixedLenFeature([], tf.string),
'label': tf.FixedLenFeature([], tf.int64)
})
# tf.decode_raw函式的意思是將原來編碼為字串型別的變數重新變回來
# 這個方法在資料集dataset中很常用,因為製作圖片源資料一般寫進tfrecord裡用to_bytes的形式,也就是字串
# 這裡將原始資料取出來,必須制定原始資料的格式,原始資料是什麼格式這裡解析必須是什麼格式!!
# tf.cast這個函式主要用於資料型別的轉變,不會改變原始資料的值還有形狀的
image = tf.decode_raw(features['image'], tf.uint8)
image = tf.reshape(image, [ImageHeight, ImageWidth, ImageChannel])
image = tf.cast(image, tf.float32)
label = tf.cast(features['label'], tf.int32)
image_batch, label_batch = tf.train.batch([image, label],
batch_size=batch_size,
num_threads=64, # 執行緒
capacity=capacity)
return image, label
image, label = read_and_decode('G:/CatsAndDogs/logs/traintfrecord', 16, 2000)
image1, label1 = read_and_decode('G:/CatsAndDogs/logs/testtfrecord', 16, 2000)
不過要注意先用前兩個函式生成所需的tfrecord檔案才能跑第三個函式。
明天繼續剩下的部分。