近似FizzBuzz
我正在尝试近似著名的FizzBuzz函数:
def fizzbuzz(start, end): a = list() for i in range(start, end + 1): a.append(fb(i)) return adef fb(i): if i % 3 == 0 and i % 5 == 0: return "FizzBuzz" elif i % 3 == 0: return "Fizz" elif i % 5 == 0: return "Buzz" else: return i
问题是,训练后,对于1到100之间的所有值,我只得到了数字作为输出:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100]
正确的输出应该是:
['1' '2' 'Fizz' '4' 'Buzz' 'Fizz' '7' '8' 'Fizz' 'Buzz' '11' 'Fizz' '13' '14' 'FizzBuzz' '16' '17' 'Fizz' '19' 'Buzz' 'Fizz' '22' '23' 'Fizz' 'Buzz' '26' 'Fizz' '28' '29' 'FizzBuzz' '31' '32' 'Fizz' '34' 'Buzz' 'Fizz' '37' '38' 'Fizz' 'Buzz' '41' 'Fizz' '43' '44' 'FizzBuzz' '46' '47' 'Fizz' '49' 'Buzz' 'Fizz' '52' '53' 'Fizz' 'Buzz' '56' 'Fizz' '58' '59' 'FizzBuzz' '61' '62' 'Fizz' '64' 'Buzz' 'Fizz' '67' '68' 'Fizz' 'Buzz' '71' 'Fizz' '73' '74' 'FizzBuzz' '76' '77' 'Fizz' '79' 'Buzz' 'Fizz' '82' '83' 'Fizz' 'Buzz' '86' 'Fizz' '88' '89' 'FizzBuzz' '91' '92' 'Fizz' '94' 'Buzz' 'Fizz' '97' '98' 'Fizz' 'Buzz']
我的神经网络将每个数字分类为四类之一:
0. "Fizz"1. "Buzz"2. "FizzBuzz"3. 以上皆非
我认为我的神经网络正在学习将每个数字分类到最常被标记为正确类的类别(即第3类:以上皆非),但我不知道如何解决这个问题。
准备数据
我将X(输入)值编码为16位二进制:
def binary_encode_16b_array(a): encoded_a = list() for elem in a: encoded_a.append(binary_encode_16b(elem)) return np.array(encoded_a)def binary_encode_16b(val): bin_arr = list() bin_str = format(val, '016b') for bit in bin_str: bin_arr.append(bit) return np.array(bin_arr)
并将Y(输出)值编码为one-hot向量:
def one_hot_encode_array(a): encoded_a = list() for elem in a: encoded_a.append(one_hot_encode(elem)) return np.array(encoded_a)def one_hot_encode(val): if val == 'Fizz': return np.array([1, 0, 0, 0]) elif val == 'Buzz': return np.array([0, 1, 0, 0]) elif val == 'FizzBuzz': return np.array([0, 0, 1, 0]) else: return np.array([0, 0, 0, 1])
这将把16位二进制输入数据分类为FizzBuzz规则指定的4个可能类别之一。
例如,如果返回[ 0.03 -0.4 -0.4 0.4]
,程序知道不打印任何”Fizz”、”Buzz”或”FizzBuzz”:
# 解码Y的值def one_hot_decode_array(x, y): decoded_a = list() for index, elem in enumerate(y): decoded_a.append(one_hot_decode(x[index], elem)) return np.array(decoded_a)def one_hot_decode(x, val): index = np.argmax(val) if index == 0: return 'Fizz' elif index == 1: return 'Buzz' elif index == 2: return 'FizzBuzz' elif index == 3: return x
初始化数据
这是我如何划分训练和测试数据:
# 使用不会被测试的数据进行训练test_x_start = 1test_x_end = 100train_x_start = 101train_x_end = 10000test_x_raw = np.arange(test_x_start, test_x_end + 1)test_x = binary_encode_16b_array(test_x_raw).reshape([-1, 16])test_y_raw = fizzbuzz(test_x_start, test_x_end)test_y = one_hot_encode_array(test_y_raw)train_x_raw = np.arange(train_x_start, train_x_end + 1)train_x = binary_encode_16b_array(train_x_raw).reshape([-1, 16])train_y_raw = fizzbuzz(train_x_start, train_x_end)train_y = one_hot_encode_array(train_y_raw)
因此,模型使用101到10000之间的值进行训练,并使用1到100之间的值进行测试。
神经网络模型
我的模型架构很简单,包含一个隐藏层,拥有100个隐藏神经元:
# 定义参数input_dim = 16output_dim = 4h1_dim = 100# 构建图X = tf.placeholder(tf.float32, [None, input_dim])Y = tf.placeholder(tf.float32, [None, output_dim])h1_w = tf.Variable(tf.zeros([input_dim, h1_dim]))h1_b = tf.Variable(tf.zeros([h1_dim]))h1_z = tf.nn.relu(tf.matmul(X, h1_w) + h1_b)fc_w = tf.Variable(tf.zeros([h1_dim, output_dim]))fc_b = tf.Variable(tf.zeros([output_dim]))Z = tf.matmul(h1_z, fc_w) + fc_b# 定义损失cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=Z))# 定义优化器train_step = tf.train.AdamOptimizer(0.005).minimize(cross_entropy)# 定义准确率correct_prediction = tf.equal(tf.argmax(Z, 1), tf.argmax(Y, 1))correct_prediction = tf.cast(correct_prediction, tf.float32)accuracy = tf.reduce_mean(correct_prediction)
运行模型
为了简单起见,我选择了不使用批量训练:
with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(1000): sess.run(train_step, feed_dict={X: train_x, Y: train_y}) train_accuracy = sess.run(accuracy, feed_dict={X: train_x, Y: train_y}) print(i, ":", train_accuracy) output = sess.run(Z, feed_dict={X: test_x}) decoded = one_hot_decode_array(test_x_raw, output) print(decoded)
在训练过程中,准确率值未能超过0.533333
。网络被训练为仅根据规则!(i%3==0 || i%5==0) ? i
输出数字,这是FizzBuzz函数中最常见的答案。
编辑:已解决
使用下面@[隐藏人名]提供的解决方案,我将隐藏层和输出层的初始值设为均匀随机。增加迭代次数并降低AdamOptimizer的学习率,我的模型现在在测试数据集上表现完美。我已将工作模型的源代码上传到GitHub仓库中。
回答:
在你的网络中,将所有初始权重设置为相同的值(零)会抵消层内多个神经元的任何好处。随机初始化权重是必要的:
h1_w = tf.Variable(tf.random_normal([input_dim, h1_dim], stddev=0.1))
我的准确率在约200次迭代后才开始变化,但在1000次迭代后,测试集上的准确率达到了0.99。我有点惊讶这甚至只用一个隐藏层就能工作。