摘要:最近在抽時間學習這個庫的使用,學的斷斷續續的,看官網上第一個案例就是訓練手寫字符識別。此外,還需要有個,用來把訓練的標簽和實際的標簽對應,比如說對應字母,對應字母。然后使用的函數,把訓練集和測試集分開。
最近在抽時間學習TensorFlow這個DL庫的使用,學的斷斷續續的,看官網上第一個案例就是訓練手寫字符識別。我之前在做Weibo.cn驗證碼識別的時候,自己搞了一個數據集,當時用的c++庫tiny-dnn進行訓練的(見:驗證碼破解技術四部曲之使用卷積神經網絡(四)),現在我把它移植到TensorFlow上試試。
完整代碼見:weibo.cn/tensorflow-impl
使用的庫TensorFlow-1.0
scikit-learn-0.18
pillow
加載數據集數據集下載地址:training_set.zip
解壓過后如下圖:
我把同一類的圖片放到了一個文件夾里,文件夾的名字也就是圖片的label,打開文件夾后可以看到字符的圖片信息。
下面,我們把數據加載到一個pickle文件里面,它需要有train_dataset、train_labels、test_dataset、test_labels四個變量代表訓練集和測試集的數據和標簽。
此外,還需要有個label_map,用來把訓練的標簽和實際的標簽對應,比如說3對應字母M,4對應字母N。
此部分的代碼見:load_models.py。注:很多的代碼參考自udacity的deeplearning課程。
首先根據文件夾的來加載所有的數據,index代表訓練里的標簽,label代表實際的標簽,使用PIL讀取圖片,并轉換成numpy數組。
import numpy as np import os from PIL import Image def load_dataset(): dataset = [] labelset = [] label_map = {} base_dir = "../trainer/training_set/" # 數據集的位置 labels = os.listdir(base_dir) for index, label in enumerate(labels): if label == "ERROR" or label == ".DS_Store": continue print "loading:", label, "index:", index try: image_files = os.listdir(base_dir + label) for image_file in image_files: image_path = base_dir + label + "/" + image_file im = Image.open(image_path).convert("L") dataset.append(np.asarray(im, dtype=np.float32)) labelset.append(index) label_map[index] = label except: pass return np.array(dataset), np.array(labelset), label_map dataset, labelset, label_map = load_dataset()
接下來,把數據打亂。
def randomize(dataset, labels): permutation = np.random.permutation(labels.shape[0]) shuffled_dataset = dataset[permutation, :, :] shuffled_labels = labels[permutation] return shuffled_dataset, shuffled_labels dataset, labelset = randomize(dataset, labelset)
然后使用scikit-learn的函數,把訓練集和測試集分開。
from sklearn.model_selection import train_test_split train_dataset, test_dataset, train_labels, test_labels = train_test_split(dataset, labelset)
在TensorFlow官網給的例子中,會把label進行One-Hot Encoding,并把28*28的圖片轉換成了一維向量(784)。如下圖,查看官網例子的模型。
我也把數據轉換了一下,把32*32的圖片轉換成一維向量(1024),并對標簽進行One-Hot Encoding。
def reformat(dataset, labels, image_size, num_labels): dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32) # Map 1 to [0.0, 1.0, 0.0 ...], 2 to [0.0, 0.0, 1.0 ...] labels = (np.arange(num_labels) == labels[:, None]).astype(np.float32) return dataset, labels train_dataset, train_labels = reformat(train_dataset, train_labels, 32, len(label_map)) test_dataset, test_labels = reformat(test_dataset, test_labels, 32, len(label_map)) print "train_dataset:", train_dataset.shape print "train_labels:", train_labels.shape print "test_dataset:", test_dataset.shape print "test_labels:", test_labels.shape
轉換后,格式就和minist一樣了。
最后,把數據保存到save.pickle里面。
save = { "train_dataset": train_dataset, "train_labels": train_labels, "test_dataset": test_dataset, "test_labels": test_labels, "label_map": label_map } with open("save.pickle", "wb") as f: pickle.dump(save, f)驗證數據集加載是否正確
加載完數據后,需要驗證一下數據是否正確。我選擇的方法很簡單,就是把trainset的第1個(或者第2個、第n個)圖片打開,看看它的標簽和看到的能不能對上。
import cPickle as pickle from PIL import Image import numpy as np def check_dataset(dataset, labels, label_map, index): data = np.uint8(dataset[index]).reshape((32, 32)) i = np.argwhere(labels[index] == 1)[0][0] im = Image.fromarray(data) im.show() print "label:", label_map[i] if __name__ == "__main__": with open("save.pickle", "rb") as f: save = pickle.load(f) train_dataset = save["train_dataset"] train_labels = save["train_labels"] test_dataset = save["test_dataset"] test_labels = save["test_labels"] label_map = save["label_map"] # check if the image is corresponding to it"s label check_dataset(train_dataset, train_labels, label_map, 0)
運行后,可以看到第一張圖片是Y,標簽也是正確的。
數據加載好了之后,就可以開始訓練了,訓練的網絡就使用TensorFlow官網在Deep MNIST for Experts里提供的就好了。
此部分的代碼見:train.py。
先加載一下模型:
import cPickle as pickle import numpy as np import tensorflow as tf with open("save.pickle", "rb") as f: save = pickle.load(f) train_dataset = save["train_dataset"] train_labels = save["train_labels"] test_dataset = save["test_dataset"] test_labels = save["test_labels"] label_map = save["label_map"] image_size = 32 num_labels = len(label_map) print "train_dataset:", train_dataset.shape print "train_labels:", train_labels.shape print "test_dataset:", test_dataset.shape print "test_labels:", test_labels.shape print "num_labels:", num_labels
minist的數據都是28*28的,把里面的網絡改完了之后,如下:
def weight_variable(shape): initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial) def bias_variable(shape): initial = tf.constant(0.1, shape=shape) return tf.Variable(initial) def conv2d(x, W): return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding="SAME") def max_pool_2x2(x): return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME") graph = tf.Graph() with graph.as_default(): x = tf.placeholder(tf.float32, shape=[None, image_size * image_size]) y_ = tf.placeholder(tf.float32, shape=[None, num_labels]) x_image = tf.reshape(x, [-1, 32, 32, 1]) # First Convolutional Layer W_conv1 = weight_variable([5, 5, 1, 32]) b_conv1 = bias_variable([32]) h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) h_pool1 = max_pool_2x2(h_conv1) # Second Convolutional Layer W_conv2 = weight_variable([5, 5, 32, 64]) b_conv2 = bias_variable([64]) h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) h_pool2 = max_pool_2x2(h_conv2) # Densely Connected Layer W_fc1 = weight_variable([image_size / 4 * image_size / 4 * 64, 1024]) b_fc1 = bias_variable([1024]) h_pool2_flat = tf.reshape(h_pool2, [-1, image_size / 4 * image_size / 4 * 64]) h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) # Dropout keep_prob = tf.placeholder(tf.float32) h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) # Readout Layer W_fc2 = weight_variable([1024, num_labels]) b_fc2 = bias_variable([num_labels]) y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2 cross_entropy = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv)) train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
主要改動就是輸入層把28*28改成了image_size*image_size(32*32),然后第三層的全連接網絡把7*7改成了image_size/4*image_size/4(8*8),以及把10(手寫字符一共10類)改成了num_labels。
然后訓練,我這里把batch_size改成了128,訓練批次改少了。
batch_size = 128 with tf.Session(graph=graph) as session: tf.global_variables_initializer().run() print("Initialized") for step in range(2001): offset = (step * batch_size) % (train_labels.shape[0] - batch_size) # Generate a minibatch. batch_data = train_dataset[offset:(offset + batch_size), :] batch_labels = train_labels[offset:(offset + batch_size), :] if step % 50 == 0: train_accuracy = accuracy.eval(feed_dict={ x: batch_data, y_: batch_labels, keep_prob: 1.0}) test_accuracy = accuracy.eval(feed_dict={ x: test_dataset, y_: test_labels, keep_prob: 1.0}) print("Step %d, Training accuracy: %g, Test accuracy: %g" % (step, train_accuracy, test_accuracy)) train_step.run(feed_dict={x: batch_data, y_: batch_labels, keep_prob: 0.5}) print("Test accuracy: %g" % accuracy.eval(feed_dict={ x: test_dataset, y_: test_labels, keep_prob: 1.0}))
運行,可以看到識別率在不斷的上升。
最后,有了接近98%的識別率,只有4000個訓練數據,感覺不錯了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/38574.html
閱讀 982·2021-11-22 09:34
閱讀 2166·2021-11-11 16:54
閱讀 2202·2021-09-27 14:00
閱讀 946·2019-08-30 15:55
閱讀 1534·2019-08-29 12:46
閱讀 605·2019-08-26 18:42
閱讀 645·2019-08-26 13:31
閱讀 3189·2019-08-26 11:52