原文地址:http://joelgrus.com/2016/05/23/fizz-buzz-in-tensorflow(作者:Joel Grus)
話說Fizz Buzz是什么鬼麸祷?
Fizz Buzz是洋人小朋友在學(xué)除法時(shí)常玩的游戲液样,玩法是:從1數(shù)到100,如果遇見了3的倍數(shù)要說Fizz,5的倍數(shù)就說Buzz,如果即是3的倍數(shù)又是5的倍數(shù)就說FizzBuzz。
最后演變?yōu)橐粋€(gè)編程面試題:寫一個(gè)程序輸出1到100,但是如果遇到數(shù)字為3的倍數(shù)時(shí)輸出Fizz,5的倍數(shù)輸出Buzz掰茶,既是3的倍數(shù)又是5的倍數(shù)輸出FizzBuzz。
面試中
面試官:你好蜜笤,在開始面試之前要不要來杯水或來杯咖啡提提神符匾。
我:不用,咖啡啥的我已經(jīng)喝的夠多了瘩例,三鹿也喝了不少啊胶。
面試官:很好甸各,很好,你不介意在小白板上寫代碼吧焰坪。
我:It’s the only way I code!
面試官:….
我:那只是個(gè)笑話趣倾。
面試官:好吧,你是否熟悉”fizz buzz”某饰。
我:….
面試官:你到底知不知道”fizz buzz”儒恋?
我:我知道”fizz buzz”,我只是不敢相信這么牛叉的IT巨頭竟然問這個(gè)問題黔漂。
面試官:OK诫尽,我要你現(xiàn)在寫一個(gè)程序輸出1到100,但是遇到數(shù)字為3的倍數(shù)時(shí)輸出Fizz炬守,5的倍數(shù)輸出Buzz牧嫉,既是3的倍數(shù)又是5的倍數(shù)輸出FizzBuzz。
我:額减途,這個(gè)酣藻,我會(huì)!
面試官:很好鳍置,我們發(fā)現(xiàn)不會(huì)解這個(gè)問題的人不能勝任我們這里的工作辽剧。
我:….
面試官:這是板擦和馬克筆。
我:[想了幾分鐘]
面試官:需不需要幫忙税产。
我:不怕轿,不用。首先先容我導(dǎo)入一些標(biāo)準(zhǔn)庫:
import numpy as np
import tensorflow as tf
面試官:你知道我們的問題是”fizz buzz”吧辟拷?
我:當(dāng)然撤卢,現(xiàn)在讓我們來討論一下模型,我正在想一個(gè)簡(jiǎn)單的只有一個(gè)隱藏層的感知器梧兼。
面試官:感知器?
我:或神經(jīng)網(wǎng)絡(luò)智听,不管你怎么叫它羽杰。給它輸入數(shù)字,然后它能給我們輸出數(shù)字對(duì)應(yīng)的”fizz buzz”到推。但是考赛,首先我們需要把數(shù)字轉(zhuǎn)為向量,最簡(jiǎn)單的方法是把數(shù)字轉(zhuǎn)換為二進(jìn)制表示莉测。
面試官:二進(jìn)制颜骤?
我:你懂的,就是一堆0和1捣卤,像這樣:
def binary_encode(i, num_digits):
return np.array([i >> d & 1 for d in range(num_digits)])
面試官:[盯著小白板看了一分鐘]
我:輸出應(yīng)該用one-hot編碼表示”fizz buzz”:
def fizz_buzz_encode(i):
if? i % 15 == 0: return np.array([0, 0, 0, 1]) # FizzBuzz
elif i % 5? == 0: return np.array([0, 0, 1, 0]) # Buzz
elif i % 3? == 0: return np.array([0, 1, 0, 0]) # Fizz
else:? ? ? ? ? ? return np.array([1, 0, 0, 0])
面試官:等一等忍抽,夠了八孝!
我:沒錯(cuò),基本的準(zhǔn)備工作已經(jīng)完成了○睿現(xiàn)在我們需要生成一個(gè)訓(xùn)練數(shù)據(jù)干跛,我們不用1到100訓(xùn)練,為了增加難度祟绊,我們使用100-1024訓(xùn)練:
NUM_DIGITS = 10
trX = np.array([binary_encode(i, NUM_DIGITS) for i in range(101, 2 ** NUM_DIGITS)])
trY = np.array([fizz_buzz_encode(i)? ? ? ? ? for i in range(101, 2 ** NUM_DIGITS)])
面試官:….
我:現(xiàn)在就可以使用TensorFlow搭模型了楼入,我還不太確定隱藏層要使用多少”神經(jīng)元”,10牧抽,夠不嘉熊?
面試官:….
我:100也許要好點(diǎn),以后還可以再改:
NUM_HIDDEN = 100
定義輸入和輸出:
X = tf.placeholder("float", [None, NUM_DIGITS])
Y = tf.placeholder("float", [None, 4])
面試官:你到底要搞哪樣扬舒。
我:哦阐肤,這個(gè)網(wǎng)絡(luò)只有兩層深,一個(gè)隱藏層和一個(gè)輸出層呼巴。下面泽腮,讓我們使用隨機(jī)數(shù)初始化“神經(jīng)元”的權(quán)重:
def init_weights(shape):
return tf.Variable(tf.random_normal(shape, stddev=0.01))
w_h = init_weights([NUM_DIGITS, NUM_HIDDEN])
w_o = init_weights([NUM_HIDDEN, 4])
現(xiàn)在我們可以定義模型了,就像我前面說的衣赶,一個(gè)隱藏層诊赊。激活函數(shù)用什么呢,我不知道府瞄,就用ReLU吧:
def model(X, w_h, w_o):
h = tf.nn.relu(tf.matmul(X, w_h))
return tf.matmul(h, w_o)
我們可以使用softmax cross-entrop做為coss函數(shù)碧磅,并且試圖最小化它。
py_x = model(X, w_h, w_o)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(py_x, Y))
train_op = tf.train.GradientDescentOptimizer(0.05).minimize(cost)
面試官:….
我:當(dāng)然遵馆,最后還要取概率最大的預(yù)測(cè)做為結(jié)果:
predict_op = tf.argmax(py_x, 1)
面試官:在你偏離軌道過遠(yuǎn)之前鲸郊,我要提醒你,我們的問題是生成1到100的”fizz buzz”货邓。
我:哦秆撮,沒錯(cuò),現(xiàn)在predict_op輸出的值是0-3换况,還要轉(zhuǎn)換為”fizz buzz”輸出:
def fizz_buzz(i, prediction):
return [str(i), "fizz", "buzz", "fizzbuzz"][prediction]
面試官:….
我:現(xiàn)在我們可以訓(xùn)練模型了职辨,首先創(chuàng)建一個(gè)session并初始化變量:
with tf.Session() as sess:
tf.global_variables_initializer().run()
就訓(xùn)練1000個(gè)大周天吧。
面試官:….
我:也許不夠戈二,為了保險(xiǎn)就訓(xùn)練10000個(gè)大周天舒裤。我們的訓(xùn)練數(shù)據(jù)是生成的序列,最好在每個(gè)大周天隨機(jī)打亂一下:
for epoch in range(10000):
p = np.random.permutation(range(len(trX)))
trX, trY = trX[p], trY[p]
每次取多少個(gè)樣本進(jìn)行訓(xùn)練觉吭,我不知道腾供,128怎么樣?
BATCH_SIZE = 128
訓(xùn)練:
for start in range(0, len(trX), BATCH_SIZE):
end = start + BATCH_SIZE
sess.run(train_op, feed_dict={X: trX[start:end], Y: trY[start:end]})
我們還能看準(zhǔn)確率:
print(epoch, np.mean(np.argmax(trY, axis=1) == sess.run(predict_op, feed_dict={X: trX, Y: trY})))
面試官:你是認(rèn)真的嗎?
我:是伴鳖,看準(zhǔn)確率提升曲線非常有幫助节值。
面試官:….
我:模型訓(xùn)練完了,現(xiàn)在是fizz buzz時(shí)間黎侈。給模型輸入1-100的二進(jìn)制表示:
numbers = np.arange(1, 101)
teX = np.transpose(binary_encode(numbers, NUM_DIGITS))
預(yù)測(cè)fizz buzz察署,大功告成:
teY = sess.run(predict_op, feed_dict={X: teX})
output = np.vectorize(fizz_buzz)(numbers, teY)
print(output)
面試官:….
我:這就是你要的”fizz buzz”。
面試官:夠了峻汉,我們會(huì)在聯(lián)系你贴汪。
我:聯(lián)系我!這可真喜人休吠。
面試官:….
后記
我沒有得到offer扳埂,于是我運(yùn)行了一下這個(gè)代碼,事實(shí)證明有一些輸出是錯(cuò)的瘤礁。感謝機(jī)器學(xué)習(xí)十八代Q舳!
['buzz' '2' 'fizz' 'buzz' 'buzz' 'fizz' '7' '8' 'fizz' 'buzz' '11' 'fizz'
'13' '14' 'fizzbuzz' 'fizz' '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' 'fizz' 'buzz' 'fizz' '52' 'fizz' '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']
也許我應(yīng)該使用更深的網(wǎng)絡(luò)柜思。