圖像分類任務中,Tensorflow與Keras 到底哪個更厲害?
本文為 AI 研習社編譯的技術博客,原標題 Tensorflow Vs Keras? — Comparison by building a model for image classification,作者為DataTurks: Data Annotations Made Super Easy。
翻譯 | shunshun 整理 | 凡江
是的,標題中的問題在數據科學家之間的談話中是很常見。有人說TensorFlow更好,有人說Keras更好。讓我們看看這個問題在圖像分類的實際應用中的答案。
在此之前,先介紹Keras和Tensorflow這兩個術語,幫助你在10分鐘內構建強大的圖像分類器。
Tensorflow:
Tensorflow是開發深度學習模型最常用的庫。它是有史以來最好的庫,在日常實驗中被許多極客選擇。如果我說Google已經將Tensor Processing Units(TPU)用於處理張量,你能想像嗎?是的,他們已經這樣做了。他們提出了一個名為TPU的獨立實例,它具有最強大的功率驅動計算能力來處理tensorflow的深度學習模型。
是時候做一個了!
我現在將幫助你使用tensorflow創建一個功能強大的圖像分類器。等等!什麼是分類器?這只是一個簡單的問題,你向你的tensorflow代碼詢問,給定的圖像是玫瑰還是鬱金香。所以,首先的首先,讓我們在機器上安裝tensorflow。官方文檔有兩個版本,即CPU和GPU版本。對於CPU版本:
請注意,我是在GPU上而非CPU上進行實驗後才寫的這篇博客。這裡給出了詳細的GPU安裝。
現在,讓我們採用Google的Tensorflow進行實驗來訓練模型。谷歌的這個倉庫有許多令人驚嘆的處理圖像的簡單實驗的腳本。它非常簡潔,足以滿足我們的目的。還記得前面我用過「強大」這個詞嗎?是的,當我們使用稱為遷移學習的方法時,這個詞就會生效。遷移學習是一種有效的方式,它使用預訓練模型,這些模型已經訓練了幾天或幾周,然後改變最後一層以適應我們自己的類別。
Inception V3是一個非常好的模型,在[2015 ImageNet Challenge](//image-net.org/challenges/LSVRC/2015/results)圖像分類競賽中排名第二。當數據集的每個類別具有較少圖像數量時,它被提及為遷移學習的最佳網路。
Inception V3
現在克隆git倉庫:
現在,你可以選擇圖像。你所要做的就是以下面的方式存儲數據集文件夾。
FLOWER DATA
它看起來應該像上面圖那樣(忽略image.py)。通過下面代碼獲得flower_photos文件夾:
創建數據
你可以使用任何你喜歡的圖像。越多越好(目標是幾千)。向上面文件夾格式那樣以類別將它們分開,並確保它們在一個名為tf_files的文件夾中。
你可以下載已經存在的有多種任務使用的數據集,如癌症檢測,權力的遊戲中的人物分類。這裡有各種圖像分類數據集。
或者,如果你有自己獨特的用例,則可以為其創建自己的數據集。你可以從網上下載圖像並立即製作大型數據集,使用像Dataturks這樣的注釋工具,你可以手動上傳圖像並標記圖像。更好的是,Dataturks的輸出可以很容易地用於構建tf_files。
使用Dataturks創建數據
我發現了一個很棒的插件,可以在Google Chrome上批量下載圖像。這個和Dataturks將使構建訓練數據變得輕而易舉。鏈接在這裡。
您可以嘗試使用dataturks的image_classification工具執行此操作。這裡該工具提供的最佳功能是,如果我們有一個非結構化數據集,其中所有圖像都在一個文件夾中。通過手動標記圖像的類別,你可以下載一個json文件,該文件包含嵌入其中的類的圖像的所有詳細信息。然後使用下面給出的keras和tensorflow腳本:
訓練
現在是時候訓練模型了。在tensorflow-for-poets-2文件夾中,有一個名為scripts的文件夾,它包含重新訓練模型所需的一切。retrain.py有一種特殊的裁剪和縮放圖像的方式,非常酷。
然後使用以下命令訓練,選項名稱本身描述所需的訓練路徑的位置。
這將下載inception模型並使用training文件夾和給定的參數訓練最後一層。我使用12GB Nvidia Tesla k80和7GB Vram在GCP實例上訓練了4000步。
訓練時80%數據集用作訓練,20%用作測試,我們可以看到,它給出了91%的test_accuracy。現在是時候測試了!我們在`tf_files/`中有一個.pb文件,可用於測試。`label_image.py`中添加了以下更改:
上面的代碼將幫助我們繪製正在測試的圖像的準確性並保存它。對於rodom圖像的置信度百分比如下所示
下面顯示了幾個測試圖像的輸出
包含所有類別的少量輸出的拼貼畫
正如我們所看到的,結果對於所述任務來說真的很好了。
Keras
Keras是一個基於TensorFlow構建的高級API(也可以在Theano之上使用)。與Tensorflow相比,它更加用戶友好且易於使用。如果我們是所有這些深度學習的新手,並想從頭開始編寫一個新模型,那麼我會建議使用Keras,因為其易讀性和易寫性。可以通過下面指令安裝:
甚至這個東西都包含了tensorflow,所以CPU v/s GPU兼容性變化也將適用於此。
因為,我們必須執行使用inception模型的遷移學習對花進行分類的相同任務,我已經看到Keras以標準格式載入模型,如API編寫的那樣。
Keras有一種載入數據集的標準格式,即我們不是直接在數據集文件夾中提供文件夾,而是手動劃分訓練和測試數據,並按以下方式排列。我使用了我在tensorflow部分下載的相同數據集,並按照以下說明進行了一些更改。
它看起來應該如下所示:
TRAIN FOLDER
至於,我們現在已完成數據集的設置,是時候進行訓練了。我已經寫了一小段代碼來進行下面的訓練:
importos
importsys
importglob
importargparse
importmatplotlib.pyplotasplt
fromkerasimport__version__
fromkeras.applications.inception_v3importInceptionV3, preprocess_input
fromkeras.modelsimportModel
fromkeras.layersimportDense, GlobalAveragePooling2D
fromkeras.preprocessing.imageimportImageDataGenerator
fromkeras.optimizersimportSGD
IM_WIDTH, IM_HEIGHT =299,299#fixed size for InceptionV3
NB_EPOCHS =3
BAT_SIZE =32
FC_SIZE =1024
NB_IV3_LAYERS_TO_FREEZE =172
defget_nb_files(directory):
"""Get number of files by searching directory recursively"""
ifnotos.path.exists(directory):
return
cnt =
forr, dirs, filesinos.walk(directory):
fordrindirs:
cnt += len(glob.glob(os.path.join(r, dr +"/*")))
returncnt
defsetup_to_transfer_learn(model, base_model):
"""Freeze all layers and compile the model"""
forlayerinbase_model.layers:
layer.trainable =False
model.compile(optimizer="rmsprop", loss="categorical_crossentropy", metrics=["accuracy"])
defadd_new_last_layer(base_model, nb_classes):
"""Add last layer to the convnet
Args:
base_model: keras model excluding top
nb_classes: # of classes
Returns:
new keras model with last layer
"""
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(FC_SIZE, activation="relu")(x)#new FC layer, random init
predictions = Dense(nb_classes, activation="softmax")(x)#new softmax layer
model = Model(input=base_model.input, output=predictions)
returnmodel
defsetup_to_finetune(model):
"""Freeze the bottom NB_IV3_LAYERS and retrain the remaining top layers.
note: NB_IV3_LAYERS corresponds to the top 2 inception blocks in the inceptionv3 arch
Args:
model: keras model
"""
forlayerinmodel.layers[:NB_IV3_LAYERS_TO_FREEZE]:
layer.trainable =False
forlayerinmodel.layers[NB_IV3_LAYERS_TO_FREEZE:]:
layer.trainable =True
model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss="categorical_crossentropy", metrics=["accuracy"])
deftrain(args):
"""Use transfer learning and fine-tuning to train a network on a new dataset"""
nb_train_samples = get_nb_files(args.train_dir)
nb_classes = len(glob.glob(args.train_dir +"/*"))
nb_val_samples = get_nb_files(args.val_dir)
nb_epoch = int(args.nb_epoch)
batch_size = int(args.batch_size)
# data prep
train_datagen = ImageDataGenerator(
preprocessing_function=preprocess_input,
rotation_range=30,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True
)
test_datagen = ImageDataGenerator(
preprocessing_function=preprocess_input,
rotation_range=30,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True
)
train_generator = train_datagen.flow_from_directory(
args.train_dir,
target_size=(IM_WIDTH, IM_HEIGHT),
batch_size=batch_size,
)
validation_generator = test_datagen.flow_from_directory(
args.val_dir,
target_size=(IM_WIDTH, IM_HEIGHT),
batch_size=batch_size,
)
# setup model
base_model = InceptionV3(weights="imagenet", include_top=False)#include_top=False excludes final FC layer
model = add_new_last_layer(base_model, nb_classes)
# transfer learning
setup_to_transfer_learn(model, base_model)
history_tl = model.fit_generator(
train_generator,
nb_epoch=nb_epoch,
samples_per_epoch=nb_train_samples,
validation_data=validation_generator,
nb_val_samples=nb_val_samples,
class_weight="auto")
# fine-tuning
setup_to_finetune(model)
history_ft = model.fit_generator(
train_generator,
samples_per_epoch=nb_train_samples,
nb_epoch=nb_epoch,
validation_data=validation_generator,
nb_val_samples=nb_val_samples,
class_weight="auto")
model.save(args.output_model_file)
ifargs.plot:
plot_training(history_ft)
defplot_training(history):
acc = history.history["acc"]
val_acc = history.history["val_acc"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]
epochs = range(len(acc))
plt.plot(epochs, acc,"r.")
plt.plot(epochs, val_acc,"r")
plt.title("Training and validation accuracy")
plt.figure()
plt.plot(epochs, loss,"r.")
plt.plot(epochs, val_loss,"r-")
plt.title("Training and validation loss")
plt.show()
if__name__=="__main__":
a = argparse.ArgumentParser()
a.add_argument(" - train_dir")
a.add_argument(" - val_dir")
a.add_argument(" - nb_epoch", default=NB_EPOCHS)
a.add_argument(" - batch_size", default=BAT_SIZE)
a.add_argument(" - output_model_file", default="inceptionv3-ft.model")
a.add_argument(" - plot", action="store_true")
args = a.parse_args()
ifargs.train_dirisNoneorargs.val_dirisNone:
a.print_help()
sys.exit(1)
if(notos.path.exists(args.train_dir))or(notos.path.exists(args.val_dir)):
print("directories do not exist")
sys.exit(1)
train(args)
這段代碼編寫得很整齊,可以通過傳遞給下面命令的參數輕鬆理解:
我的GPU上訓練一分鐘1 epoch,每個epoch 292步,並且訓練了50個epoch(這是非常多!),批量大小為10,數據分割為80%訓練集,20%測試集。
哇哦。我們完成了訓練並得到了約91%的測試準確率,損失為0.38。該模型已保存為一個inception.model文件,可以再次載入並測試。為此,編寫了另一個腳本,同時在圖像上繪製預測類別並保存它。測試腳本如下:
importsys
importargparse
importnumpyasnp
fromPILimportImage
importrequests
fromioimportBytesIO
importmatplotlib.pyplotasplt
fromPILimportImage,ImageDraw,ImageFont
fromkeras.preprocessingimportimage
fromkeras.modelsimportload_model
fromkeras.applications.inception_v3importpreprocess_input
target_size = (229,229)#fixed size for InceptionV3 architecture
defpredict(model, img, target_size):
"""Run model prediction on image
Args:
model: keras model
img: PIL format image
target_size: (w,h) tuple
Returns:
list of predicted labels and their probabilities
"""
ifimg.size != target_size:
img = img.resize(target_size)
x = image.img_to_array(img)
x = np.expand_dims(x, axis=)
x = preprocess_input(x)
preds = model.predict(x)
returnpreds[]
defplot_preds(image, preds):
"""Displays image and the top-n predicted probabilities in a bar graph
Args:
image: PIL image
preds: list of predicted labels and their probabilities
"""
plt.imshow(image)
plt.axis("off")
plt.figure()
labels = ("daisy","dandelion","roses","sunflower","tulips")
plt.barh([,1,2,3,4], preds, alpha=0.5)
plt.yticks([,1,2,3,4], labels)
plt.xlabel("Probability")
plt.xlim(,1.01)
plt.tight_layout()
plt.show()
if__name__=="__main__":
a = argparse.ArgumentParser()
a.add_argument(" - image", help="path to image")
a.add_argument(" - image_url", help="url to image")
a.add_argument(" - model")
args = a.parse_args()
ifargs.imageisNoneandargs.image_urlisNone:
a.print_help()
sys.exit(1)
model = load_model(args.model)
model.fit()
ifargs.imageisnotNone:
labels = ("daisy","dandelion","roses","sunflower","tulips")
image1 = Image.open(args.image)
preds = predict(model, image1, target_size)
print(preds)
preds = preds.tolist()
plot_preds(image1, preds)
fonttype = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",18)
draw = ImageDraw.Draw(image1)
draw.text(xy=(5,5),text = str(labels[preds.index(max(preds))])+":"+str(max(preds)),fill = (255,255,255,128),font = fonttype)
image1.show()
image1.save((args.image).split(".")[]+"1"+".jpg")
inception_test.py
可以通過下面的命令進行測試
所有類別的預測置信度百分比輸出如下
[daisy,dandelion,roses,sunflower,tulip]
以下是帶圖表的少數輸出
帶有概率圖表的測試圖像
最後!您已經學會了如何使用Keras和tensorflow構建強大的分類器。但是,哪一個是最好的仍然是我們頭腦中的問題!因此,讓我們僅根據此分類任務進行比較研究。
keras的全部訓練和測試代碼以及tensorflow的更改的腳本都可以在我的github中找到。
原型:
如果你真的想快速編寫代碼並構建一個模型,那麼Keras就是一個很好的選擇。我們可以在幾分鐘內建立複雜模型!Model和Sequential API非常強大,因為它們易於使用,它們甚至不會讓你感覺自己是構建強大的模型。
model = Sequential()
model.add(Dense(32, activation="relu", input_dim=100))
model.add(Dense(1, activation="sigmoid"))
model.compile(optimizer="rmsprop",
loss="binary_crossentropy",
metrics=["accuracy"])
# Generate dummy data
importnumpyasnp
data = np.random.random((1000,100))
labels = np.random.randint(2, size=(1000,1))
# Train the model, iterating on the data in batches of 32 samples
model.fit(data, labels, epochs=10, batch_size=32)
就是這樣,一個模型就準備好了!甚至相對於tensorflow,遷移學習在Keras中更容易編碼實現。在你是一個非常厲害的程序員之前,Tensorflow從頭開始編碼都太難。
從0開始以及靈活性:
上述模型是在相同的數據集上訓練的,我們看到相比於tensorflow,Keras需要更多的時間進行訓練。Tensorflow在15分鐘內完成了4000步的訓練,而Keras在50個epoch內花了大約2個小時。可能是我們無法比較epoch與步長,但在這種情況下你看到了,相比之下兩者的測試準確度均為91%,因此我們可以描述keras訓練比tensorflow慢一點。除此之外,由於tensorflow是一個低級庫,因此它是有道理的。
訓練時間和處理能力:
上述模型是在相同的數據集上訓練的,我們看到相比於tensorflow,Keras需要更多的時間進行訓練。Tensorflow在15分鐘內完成了4000步的訓練,而Keras在50個epoch內花了大約2個小時。可能是我們無法比較epoch與步長,但在這種情況下你看到了,相比之下兩者的測試準確度均為91%,因此我們可以描述keras訓練比tensorflow慢一點。除此之外,由於tensorflow是一個低級庫,因此它是有道理的。
提供額外功能:
Tensorflow有一個內置的調試器,可以在訓練期間調試以及生成圖形。
TensorFlow調試器快照 (來源:TensorFlow文檔)
Tensorflow甚至支持線程和隊列來非同步訓練大型張量!這為TPU提供了更好,更快的處理速度。線程的示例代碼如下所示:
# Create the graph, etc.
init_op = tf.global_variables_initializer()
# Create a session for running operations in the Graph.
sess = tf.Session()
# Initialize the variables (like the epoch counter).
sess.run(init_op)
# Start input enqueue threads.
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
try:
whilenotcoord.should_stop():
# Run training steps or whatever
sess.run(train_op)
excepttf.errors.OutOfRangeError:
print("Done training -- epoch limit reached")
finally:
# When done, ask the threads to stop.
coord.request_stop()
# Wait for threads to finish.
coord.join(threads)
sess.close()
監測和控制:
根據我在深度學習方面的經驗,我認為tensorflow非常適合許多情況,儘管它有點難度。例如,我們可以非常輕鬆地監控每個和所有內容,例如控制網路的權重和梯度。我們可以選擇應該訓練哪個步驟,哪個不應該。這在Keras中是不可行的。下面給出就是魔法!
結論:
無論如何,Keras很快將被整合到tensorflow中!那麼,為什麼要去pythonic?(Keras是pythonic)。我的建議是花一些時間習慣tensorflow。上面的分類問題,如果您已經關注博客並相應地完成了相應的步驟,然後你會覺得相比於tensorflow,Keras在很多方面都little painful and patience killer。所以,嘗試使用其他類,並嘗試為應用程序訓練分類器,如假筆記檢測...
希望這篇博客能讓你更好地了解何時使用它們!
※Machine Can See 2018 圖像對抗攻擊大賽比賽心得
※針對計算機視覺一些問題的分析
TAG:AI研習社 |