Tensorflow 直接对于图片进行3通道卷积
June 4, 2018, 10:22 a.m.
read: 1154
每张图的信息如下大小 218 * 82
0x00
需要预测的图片如下:
实际上是3个通道(RGB,有些图片会存在4个通道 RGBA, 包含透明度A),那就是 218 x 82 x 3
0x01
很多教程都建议把图片转化成灰度图片,把三个通道合并成一个通道进行卷积,在我的训练中发现,图片不进行转化,直接对三通道卷积并且不需要进行转置这样训练的效果更好,集中表现在收敛速度特别快。在训练以上集合的时候,在BATCH_SIZE等于64的时候,往往一千步以内就能收敛完成。(我猜可能这个留下的信息会更多,适合卷积)
给出训练代码如下:
import tensorflow as tf
import numpy as np
from PIL import Image
import os
import random
train_data_dir = r'C:\Users\HUPENG\Desktop\check_code_crack\check_code\train'
test_data_dir = r''
train_file_name_list = os.listdir(train_data_dir)
def gen_train_data(batch_size=32):
selected_train_file_name_list = random.sample(train_file_name_list, batch_size)
x_data = []
y_data = []
for selected_train_file_name in selected_train_file_name_list:
captcha_image = Image.open(train_data_dir + "/" + selected_train_file_name)
captcha_image_np = np.array(captcha_image)
x_data.append(captcha_image_np)
y_data.append(np.array(list(selected_train_file_name.split('.')[0])).astype(np.int32))
x_data = np.array(x_data)
y_data = np.array(y_data)
return x_data, y_data
X = tf.placeholder(tf.float32, name="input")
Y = tf.placeholder(tf.int32)
keep_prob = tf.placeholder(tf.float32)
y_one_hot = tf.one_hot(Y, 10, 1, 0)
y_one_hot = tf.cast(y_one_hot, tf.float32)
# keep_prob = 1.0
def net(w_alpha=0.01, b_alpha=0.1):
x_reshape = tf.reshape(X, (-1, 218, 82, 3))
w_c1 = tf.Variable(w_alpha * tf.random_normal([3, 3, 3, 16]))
b_c1 = tf.Variable(b_alpha * tf.random_normal([16]))
conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x_reshape, w_c1, strides=[1, 1, 1, 1], padding='SAME'), b_c1))
conv1 = tf.nn.max_pool(conv1, ksize=[1, 4, 4, 1], strides=[1, 2, 2, 1], padding='SAME')
conv1 = tf.nn.dropout(conv1, keep_prob)
w_c2 = tf.Variable(w_alpha * tf.random_normal([3, 3, 16, 16]))
b_c2 = tf.Variable(b_alpha * tf.random_normal([16]))
conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1, w_c2, strides=[1, 1, 1, 1], padding='SAME'), b_c2))
conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
conv2 = tf.nn.dropout(conv2, keep_prob)
w_c3 = tf.Variable(w_alpha * tf.random_normal([3, 3, 16, 16]))
b_c3 = tf.Variable(b_alpha * tf.random_normal([16]))
conv3 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2, w_c3, strides=[1, 1, 1, 1], padding='SAME'), b_c3))
conv3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
conv3 = tf.nn.dropout(conv3, keep_prob)
# Fully connected layer
# 随机生成权重
w_d = tf.Variable(w_alpha * tf.random_normal([28 * 11 * 16, 1024]))
# 随机生成偏置
b_d = tf.Variable(b_alpha * tf.random_normal([1024]))
dense = tf.reshape(conv3, [-1, w_d.get_shape().as_list()[0]])
dense = tf.nn.relu(tf.add(tf.matmul(dense, w_d), b_d))
w_out = tf.Variable(w_alpha * tf.random_normal([1024, 5 * 10]))
b_out = tf.Variable(b_alpha * tf.random_normal([5 * 10]))
out = tf.add(tf.matmul(dense, w_out), b_out)
out = tf.reshape(out, (-1, 5, 10))
# out = tf.nn.softmax(out)
return out
cnn = net()
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=cnn, labels=y_one_hot))
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)
def train():
saver = tf.train.Saver()
with tf.Session() as sess:
step = 0
tf.global_variables_initializer().run()
while True:
x_data, y_data = gen_train_data(64)
x_data = np.reshape(x_data, (-1))
loss_, cnn_, y_one_hot_, optimizer_ = sess.run([loss, cnn, y_one_hot, optimizer],
feed_dict={Y: y_data, X: x_data, keep_prob: 0.75})
print(loss_)
if loss_ < 0.001:
saver.save(sess, "./crack_capcha.model", global_step=step)
print("save model successful!")
break
step += 1
if __name__=='__main__':
train()
print("ok")
0x02
一些细节:
验证码是5位数字,此处并不是直接预测5个数字,(我没试过直接预测5个数字的,有兴趣的读者可以尝试下,在评论区留下训练情况,一起交流下)。
在把所有的数字进行了one-hot encoding再扔进去训练的。
实际上one-hot之后网络的输出 需要softmax之后效果会更好,但是在这里进过softmax之后收敛速度不行。
还有最后一点,预测出来的值需要arg_max之后才能用 。arg max之前的值跟label one hot 之后的值相差很大,应该是和loss表达式关系比较大,此处用的交叉熵,应该和上一点softmax的问题存在一定的联系。
把上述的代码的
tf.nn.sigmoid_cross_entropy_with_logits
改成
tf.nn.softmax_cross_entropy_with_logits
问题就没有了~