摘要:最近在抽時(shí)間學(xué)習(xí)這個(gè)庫的使用,學(xué)的斷斷續(xù)續(xù)的,看官網(wǎng)上第一個(gè)案例就是訓(xùn)練手寫字符識(shí)別。此外,還需要有個(gè),用來把訓(xùn)練的標(biāo)簽和實(shí)際的標(biāo)簽對(duì)應(yīng),比如說對(duì)應(yīng)字母,對(duì)應(yīng)字母。然后使用的函數(shù),把訓(xùn)練集和測(cè)試集分開。
最近在抽時(shí)間學(xué)習(xí)TensorFlow這個(gè)DL庫的使用,學(xué)的斷斷續(xù)續(xù)的,看官網(wǎng)上第一個(gè)案例就是訓(xùn)練手寫字符識(shí)別。我之前在做Weibo.cn驗(yàn)證碼識(shí)別的時(shí)候,自己搞了一個(gè)數(shù)據(jù)集,當(dāng)時(shí)用的c++庫tiny-dnn進(jìn)行訓(xùn)練的(見:驗(yàn)證碼破解技術(shù)四部曲之使用卷積神經(jīng)網(wǎng)絡(luò)(四)),現(xiàn)在我把它移植到TensorFlow上試試。
完整代碼見:weibo.cn/tensorflow-impl
使用的庫TensorFlow-1.0
scikit-learn-0.18
pillow
加載數(shù)據(jù)集數(shù)據(jù)集下載地址:training_set.zip
解壓過后如下圖:
我把同一類的圖片放到了一個(gè)文件夾里,文件夾的名字也就是圖片的label,打開文件夾后可以看到字符的圖片信息。
下面,我們把數(shù)據(jù)加載到一個(gè)pickle文件里面,它需要有train_dataset、train_labels、test_dataset、test_labels四個(gè)變量代表訓(xùn)練集和測(cè)試集的數(shù)據(jù)和標(biāo)簽。
此外,還需要有個(gè)label_map,用來把訓(xùn)練的標(biāo)簽和實(shí)際的標(biāo)簽對(duì)應(yīng),比如說3對(duì)應(yīng)字母M,4對(duì)應(yīng)字母N。
此部分的代碼見:load_models.py。注:很多的代碼參考自u(píng)dacity的deeplearning課程。
首先根據(jù)文件夾的來加載所有的數(shù)據(jù),index代表訓(xùn)練里的標(biāo)簽,label代表實(shí)際的標(biāo)簽,使用PIL讀取圖片,并轉(zhuǎn)換成numpy數(shù)組。
import numpy as np import os from PIL import Image def load_dataset(): dataset = [] labelset = [] label_map = {} base_dir = "../trainer/training_set/" # 數(shù)據(jù)集的位置 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()
接下來,把數(shù)據(jù)打亂。
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的函數(shù),把訓(xùn)練集和測(cè)試集分開。
from sklearn.model_selection import train_test_split train_dataset, test_dataset, train_labels, test_labels = train_test_split(dataset, labelset)
在TensorFlow官網(wǎng)給的例子中,會(huì)把label進(jìn)行One-Hot Encoding,并把28*28的圖片轉(zhuǎn)換成了一維向量(784)。如下圖,查看官網(wǎng)例子的模型。
我也把數(shù)據(jù)轉(zhuǎn)換了一下,把32*32的圖片轉(zhuǎn)換成一維向量(1024),并對(duì)標(biāo)簽進(jìn)行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
轉(zhuǎn)換后,格式就和minist一樣了。
最后,把數(shù)據(jù)保存到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)驗(yàn)證數(shù)據(jù)集加載是否正確
加載完數(shù)據(jù)后,需要驗(yàn)證一下數(shù)據(jù)是否正確。我選擇的方法很簡(jiǎn)單,就是把trainset的第1個(gè)(或者第2個(gè)、第n個(gè))圖片打開,看看它的標(biāo)簽和看到的能不能對(duì)上。
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ùn)行后,可以看到第一張圖片是Y,標(biāo)簽也是正確的。
數(shù)據(jù)加載好了之后,就可以開始訓(xùn)練了,訓(xùn)練的網(wǎng)絡(luò)就使用TensorFlow官網(wǎng)在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的數(shù)據(jù)都是28*28的,把里面的網(wǎng)絡(luò)改完了之后,如下:
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))
主要改動(dòng)就是輸入層把28*28改成了image_size*image_size(32*32),然后第三層的全連接網(wǎng)絡(luò)把7*7改成了image_size/4*image_size/4(8*8),以及把10(手寫字符一共10類)改成了num_labels。
然后訓(xùn)練,我這里把batch_size改成了128,訓(xùn)練批次改少了。
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}))
運(yùn)行,可以看到識(shí)別率在不斷的上升。
最后,有了接近98%的識(shí)別率,只有4000個(gè)訓(xùn)練數(shù)據(jù),感覺不錯(cuò)了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/38574.html
閱讀 977·2021-11-22 09:34
閱讀 2161·2021-11-11 16:54
閱讀 2196·2021-09-27 14:00
閱讀 940·2019-08-30 15:55
閱讀 1525·2019-08-29 12:46
閱讀 599·2019-08-26 18:42
閱讀 639·2019-08-26 13:31
閱讀 3183·2019-08-26 11:52