使用TensorFlow給花朵🌺分類第一步:準備好需要的庫 第二步:準備資料集:在下載下傳完資料集之後,我們對資料集進行預處理:在搭建好網絡之後,我們開始編寫訓練子產品在訓練結束後,我們對使用之前訓練好的模型進行預測:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuEGN2Y2NhRWYmNWOyITMzQTZxYjY2IDM0YTMkJzYhJzMfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
第一步:準備好需要的庫
- tensorflow-gpu 1.8.0
- opencv-python 3.3.1
- numpy
- skimage
- os
- pillow
第二步:準備資料集:
連結:
https://pan.baidu.com/s/1Kbz_UaRhAfhlweFY28R8Sw密碼:iym3
本次使用了花朵分類的資料集,總共有5類
每類裡面有不同形态的同一類花朵
在下載下傳完資料集之後,我們對資料集進行預處理:
from skimage import io, transform
import os
import numpy as np
# 将所有的圖檔resize成100*100
w = 100
h = 100
c = 3
# 讀取圖檔
def read_img(path):
imgs = []
labels = []
classs = os.listdir(path)
for idx, folder in enumerate(classs):
cate = os.path.join(path, folder)
for im in os.listdir(cate):
img_path =os.path.join(cate, im)
# print('reading the images:%s' % (img_path))
img = io.imread(img_path)
img = transform.resize(img, (w, h))
# with open('tests.txt', 'a') as f:
# f.write(img_path+'_'+str(idx)+'\n')
imgs.append(img)
labels.append(idx)
return np.asarray(imgs, np.float32), np.asarray(labels, np.int32)
def suffer(data, label):
# 打亂順序
num_example = data.shape[0]
arr = np.arange(num_example)
np.random.shuffle(arr)
data = data[arr]
label = label[arr]
# 将所有資料分為訓練集和驗證集
ratio = 0.8
s = np.int(num_example * ratio)
x_train = data[:s]
y_train = label[:s]
x_val = data[s:]
y_val = label[s:]
return x_train,y_train,x_val,y_val
def minibatches(inputs=None, targets=None, batch_size=None, shuffle=False):
assert len(inputs) == len(targets)
if shuffle:
indices = np.arange(len(inputs))
np.random.shuffle(indices)
for start_idx in range(0, len(inputs) - batch_size + 1, batch_size):
if shuffle:
excerpt = indices[start_idx:start_idx + batch_size]
else:
excerpt = slice(start_idx, start_idx + batch_size)
yield inputs[excerpt], targets[excerpt]
我們将圖檔統一設為100×100的大小,然後對每一個檔案夾标号,作為标簽。為了檢驗我們是否将标簽與圖檔對齊,我預留了一個寫檔案路徑+标簽的一個檔案。
寫出來是這樣的
在做處理好标簽和圖檔之後我們将其設定為 np.asarray(imgs, np.float32)的格式。
然後将這些圖檔随機打亂順序。以8:2的比例劃分訓練集和驗證集。
接着我們來生成minibatch:将資料切分成batch_size的大小送入網絡。
在預處理完資料之後,我們開始進行網絡的建構
import tensorflow as tf
def batch_norm(x, momentum=0.9, epsilon=1e-5, train=True, name='bn'):
return tf.layers.batch_normalization(x,
momentum=momentum,
epsilon=epsilon,
scale=True,
training=train,
name=name)
def simple_cnn(x):
# 第一個卷積層(100——>50)
conv1 = tf.layers.conv2d(
inputs=x,
filters=32,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
conv1 = batch_norm(conv1, name='pw_bn1')
pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)
# 第二個卷積層(50->25)
conv2 = tf.layers.conv2d(
inputs=pool1,
filters=64,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
conv2 = batch_norm(conv2, name='pw_bn2')
pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)
# 第三個卷積層(25->12)
conv3 = tf.layers.conv2d(
inputs=pool2,
filters=128,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
conv3 = batch_norm(conv3, name='pw_bn3')
pool3 = tf.layers.max_pooling2d(inputs=conv3, pool_size=[2, 2], strides=2)
# 第四個卷積層(12->6)
conv4 = tf.layers.conv2d(
inputs=pool3,
filters=128,
kernel_size=[3, 3],
padding="same",
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01))
conv4 = batch_norm(conv4, name='pw_bn4')
pool4 = tf.layers.max_pooling2d(inputs=conv4, pool_size=[2, 2], strides=2)
re1 = tf.reshape(pool4, [-1, 6 * 6 * 128])
# 全連接配接層
dense1 = tf.layers.dense(inputs=re1,
units=1024,
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),
kernel_regularizer=tf.contrib.layers.l2_regularizer(0.003))
dense2 = tf.layers.dense(inputs=dense1,
units=512,
activation=tf.nn.relu,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),
kernel_regularizer=tf.contrib.layers.l2_regularizer(0.003))
logits = tf.layers.dense(inputs=dense2,
units=5,
activation=None,
kernel_initializer=tf.truncated_normal_initializer(stddev=0.01),
kernel_regularizer=tf.contrib.layers.l2_regularizer(0.003))
pred = tf.nn.softmax(logits, name='prob')
return logits, pred
我們的網絡由4個卷積層,兩個全連接配接層,一個softmax層組成。在每一層的卷積後面加入了batch_normalization,relu和池化。
batch_normalization層很好用,加上它之後,有效的預防了梯度消逝和爆炸,還加速了收斂。
在搭建好網絡之後,我們開始編寫訓練子產品
import tensorflow as tf
import cnn
import dataset
# 将所有的圖檔resize成100*100
w = 100
h = 100
c = 3
path = 'flowers'
x = tf.placeholder(tf.float32, shape=[None, w, h, c], name='x')
y_ = tf.placeholder(tf.int32, shape=[None, ], name='y_')
logits,pred = cnn.simple_cnn(x)
loss = tf.losses.sparse_softmax_cross_entropy(labels=y_, logits=logits)
train_op = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
correct_prediction = tf.equal(tf.cast(tf.argmax(logits, 1), tf.int32), y_)
acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
data, label = dataset.read_img(path)
x_train, y_train,x_val, y_val = dataset.suffer(data, label)
# 訓練和測試資料,可将n_epoch設定更大一些
n_epoch = 11
batch_size = 16
def train():
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
for epoch in range(n_epoch):
train_loss, train_acc, n_batch = 0, 0, 0
for x_train_a, y_train_a in dataset.minibatches(x_train, y_train, batch_size, shuffle=True):
_, err, ac = sess.run([train_op, loss, acc], feed_dict={x: x_train_a, y_: y_train_a})
train_loss += err
train_acc += ac
n_batch += 1
print('Epoch %d - train loss: %f'%(epoch, (train_loss / n_batch)))
print('Epoch %d - train acc: %f'%(epoch,train_acc / n_batch))
# validation
val_loss, val_acc, n_batch = 0, 0, 0
for x_val_a, y_val_a in dataset.minibatches(x_val, y_val, batch_size, shuffle=False):
err, ac = sess.run([loss, acc], feed_dict={x: x_val_a, y_: y_val_a})
val_loss += err
val_acc += ac
n_batch += 1
print('Epoch %d - Validation loss: %f' %(epoch, val_loss / n_batch))
print('Epoch %d - Validation Accuracy: %f'%( epoch,(val_acc / n_batch)))
if epoch % 5 == 0:
saver.save(sess, "./model/save_net.ckpt",epoch)
print('Trained Model Saved.')
train()
訓練時我們首先要定義X,Y作為索引
x = tf.placeholder(tf.float32, shape=[None, w, h, c], name='x')
y_ = tf.placeholder(tf.int32, shape=[None, ], name='y_')
然後對于剛才建構的網絡進行損失的計算,精确度計算以及優化器的選擇。
接着我們将session初始化
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
然後将定義的X,Y索引與你的真實資料,标簽對齊。
使用
_, err, ac = sess.run([train_op, loss, acc], feed_dict={x: x_train_a, y_: y_train_a})
開始運作就可以了。
測試同理,不過測試的時候不需要優化器,是以隻需要加入參數loss,acc就可以了。
我們每隔5次儲存一次模型。
在訓練結束後,我們對使用之前訓練好的模型進行預測:
import numpy as np
import tensorflow as tf
from PIL import Image, ImageDraw, ImageFont
from cnn import simple_cnn
# 将所有的圖檔resize成100*100
w = 100
h = 100
c = 3
classes = ['daisy','dandelion','roses','sunflowers','tulips']
image_test = Image.open('44079668_34dfee3da1_n.jpg')
resized_image = image_test.resize((w, h), Image.BICUBIC)
image_data = np.array(resized_image, dtype='float32')
imgs_holder = tf.placeholder(tf.float32, shape=[1, w, h, c])
logits,pred = simple_cnn(imgs_holder)
saver = tf.train.Saver()
ckpt_dir = './model/'
with tf.Session() as sess:
ckpt = tf.train.get_checkpoint_state(ckpt_dir)
saver.restore(sess, ckpt.model_checkpoint_path)
classes_ = sess.run(pred,feed_dict={ imgs_holder: np.reshape(image_data , [1, w, h, c])})
num = np.argmax(classes_)
print('class is :',classes[int(num)],' Probability is :',classes_[0][int(num)])
在預測時,因為子還需要輸入一張圖檔就可以了,是以我們隻制作圖檔的索引
imgs_holder = tf.placeholder(tf.float32, shape=[1, w, h, c])
然後讀取剛才儲存的參數,隻需要輸入目錄,即可自動讀取最後訓練的模型。
然後運作:
classes_ = sess.run(pred,feed_dict={ imgs_holder: np.reshape(image_data , [1, w, h, c])})
輸出每個類的機率值。
我們将這個機率最大的值的标号讀取出來,對應之前檔案夾的标号。
classes = ['daisy','dandelion','roses','sunflowers','tulips']
然後将這個标号對應的機率數标出來。
本次使用了tf.layer進行了簡單CNN的建構,并且使用了tensorflow傳統的sess.run
的方法來運作圖,沒有使用之前提到的進階API。
在這種方法上進行了簡單的嘗試,接下來會嘗試使用slim架構建構網絡。