pytorch神經網絡擬合FizzBuzz遊戲
1.問題描述
給你一個整數n,從 1 到 n 按照下面的規則打印每個數:
- 如果這個數被 3 整除,打印 fizz.
- 如果這個數被 5 整除,打印 buzz.
- 如果這個數能同時被3和5整除(也就是被 15 整除),打印 fizz buzz .
比如 n = 15, 返回一個字符串數組:
["1", "2", "fizz","4", "buzz", "fizz","7", "8", "fizz","buzz", "11", "fizz","13", "14", "fizz buzz"]
2.源代碼書寫產生訓練數據
#定義該函數對以上數據進行編碼,將任意數字分爲四類
#將fizzbuzz遊戲變爲一個四分類問題,方便pytorch進行訓練
def fizzbuzz_encode(i):
if i%15==0:
return 3
elif i%5==0:
return 2
elif i%3==0:
return 1
else:
return 0
#根據上邊的數字分類,決定要輸出的字符串內容
def fizzbuzz_decode(i,type):
return [str(i),"fizz","buzz","fizzbuzz"][type]
#該函數調用以上倆函數產生訓練數據集
for i in range(1,160):
print(fizzbuzz_decode(i,fizzbuzz_encode(i)))
輸出結果如下所示:
3.pytorch神經網絡擬合
因爲訓練數據爲數字,爲方便訓練,我們將數據轉換爲長度爲10的二進制數組。
import numpy as np
import torch
#定義該函數對以上數據進行編碼,將任意數字分爲四類
#將fizzbuzz遊戲變爲一個四分類問題,方便pytorch進行訓練
def fizzbuzz_encode(i):
if i%15==0:
return 3
elif i%5==0:
return 2
elif i%3==0:
return 1
else:
return 0
#根據上邊的數字分類,決定要輸出的字符串內容
def fizzbuzz_decode(i,type):
return [str(i),"fizz","buzz","fizzbuzz"][type]
#該函數調用以上倆函數產生訓練數據集
for i in range(1,16):
print(fizzbuzz_decode(i,fizzbuzz_encode(i)))
'''
因爲訓練數據爲數字,爲方便訓練,我們將數據轉換爲長度爲10的二進制數組。
'''
NUM_DIGITS=10
def binary_encode(i,num_digits):
return np.array([i>>d & 1 for d in range(num_digits)][::-1])
4.全部代碼及運行結果
4.1 全部代碼
# @Time : 2020/6/3 16:06
# @Author : kingback
# @File : pytorch_FizzBuzz.py
# @Software: PyCharm
import numpy as np
import torch
#定義該函數對以上數據進行編碼,將任意數字分爲四類
#將fizzbuzz遊戲變爲一個四分類問題,方便pytorch進行訓練
def fizzbuzz_encode(i):
if i%15==0:
return 3
elif i%5==0:
return 2
elif i%3==0:
return 1
else:
return 0
#根據上邊的數字分類,決定要輸出的字符串內容
def fizzbuzz_decode(i,type):
return [str(i),"fizz","buzz","fizzbuzz"][type]
#該函數調用以上倆函數產生訓練數據集
for i in range(1,16):
print(fizzbuzz_decode(i,fizzbuzz_encode(i)))
'''
因爲訓練數據爲數字,爲方便訓練,我們將數據轉換爲長度爲10的二進制數組。
'''
NUM_DIGITS=10
def binary_encode(i,num_digits):
return np.array([i>>d & 1 for d in range(num_digits)][::-1])
#輸出轉換後的數字
change_num=binary_encode(1023,NUM_DIGITS)
print(change_num)
'''
下邊開始使用pytorch訓練上邊產生的數據,從而搭建一個fizzbuzz的模型,
'''
#構建訓練數據的X和Y,因爲我們這裏採用的是2**10次方個數字,也就是隻有1024個數字。
#我們將101-1023作爲訓練數據,將1-100作爲測試數據。
trX=torch.Tensor([binary_encode(i,NUM_DIGITS)for i in range(101,2**10)])
trY=torch.LongTensor([fizzbuzz_encode(i)for i in range(101,2**10)])
# print(trX)
# print(trY)
#輸出trY的大小,其大小爲923個數據
# print(trX.shape)
# print(trY.shape)
'''
定義模型model,使用pytorch定義模型,
輸入層爲923*10的矩陣,
隱藏層設置爲100,
加入一個非線性的激活函數,此處選擇Relu函數,
輸出層爲923*4的一個矩陣(因爲此遊戲的結果就是四種類型)。
'''
NUM_HIDDEN=100
model=torch.nn.Sequential(
torch.nn.Linear(NUM_DIGITS,NUM_HIDDEN),
torch.nn.ReLU(),
torch.nn.Linear(NUM_HIDDEN,4)
)
'''
此處含有調用cuda代碼
'''
#判斷機器上的cuda是否可用,如果可以用的話,就調用一下.(默認使用cpu)
# if(torch.cuda.is_available()):
# model=model.cuda()
#定義損失函數,因爲我們的模型爲多分類問題中的四分類問題,於是我們採用如下損失函數
loss_fn=torch.nn.CrossEntropyLoss()
#這裏我們採用的是交叉熵的損失函數CrossEntropyLoss(),交叉熵描述了兩個概率分佈之間的距離,當交叉熵越小說明二者之間越接近。
#儘管交叉熵刻畫的是兩個概率分佈之間的距離,但是神經網絡的輸出卻不一定是一個概率分佈。爲此我們常常用Softmax迴歸將神經網絡前向傳播得到的結果變成概率分佈。
#softmax常用於多分類過程中,它將多個神經元的輸出,歸一化到( 0, 1) 區間內,因此Softmax的輸出可以看成概率,從而來進行多分類
#定義優化函數和學習率,注意在這裏我們要對模型上所有參數進行優化,所以我們需要將模型的所有parameters傳入優化函數
optimizer=torch.optim.SGD(model.parameters(),lr=0.05)
'''
以下開始模型訓練
'''
BATCH_SIZE=128 #跳躍寬度爲128
for epoch in range(10000):
for start in range(0,len(trX),BATCH_SIZE):
end=start+BATCH_SIZE #每一次取的長度區間
bachX=trX[start:end] #取固定長度的訓練數據
bachY=trY[start:end] #取固定長度的訓練數據
'''
此處含有調用cuda代碼
'''
# if(torch.cuda.is_available()):
# bachX=bachX.cuda()
# bachY=bachY.cuda()
y_pred=model(bachX) #調用模型預測
loss=loss_fn(y_pred,bachY) #計算預測值與真實值之間的差值
'''
打印輸出loss值
'''
if(epoch%100==0):
print('now epoch is :',epoch,' loss=',loss.item())
optimizer.zero_grad() #每一次循環之前,將梯度清零
loss.backward() #反向傳播
optimizer.step() #梯度下降
'''
測試我們通過上述步驟訓練的模型效果
之前說過我們將101以上的數據設置爲訓練數據,將101以下的設置爲測試數據
'''
testX=torch.Tensor([binary_encode(i,NUM_DIGITS) for i in range(1,101)])
'''
此處含有調用cuda代碼
'''
# if(torch.cuda.is_available()):
# testX=testX.cuda()
#注意:在進行模型測試的時候我們就不再需要這個grad
with torch.no_grad():
testY=model(testX)
#在這裏說明一下:我們得到的testY是一個100*4的矩陣,其中每一行代表我們的每一個測試數據。
# 四列分別代表的是該數字與四種類型的相似度,數值越大,相似度越高
# print(testY)
#我們取出每一行中的最大值及其所在位置,並將其轉換爲list數值
prections=testY.max(1)[1].data.tolist()
#將range(0,101)和prections打包到一起
prections=zip(range(1,101),prections)
'''
打印我們的預測結果
'''
print([fizzbuzz_decode(i,x) for i,x in prections])
4.2 程序運行結果
我們將1-n任意數字傳入模型,需要得到如下效果:
- 如果這個數被 3 整除,打印 fizz.
- 如果這個數被 5 整除,打印 buzz.
- 如果這個數能同時被3和5整除(也就是被 15 整除),打印 fizz buzz
我們採用的是10位制,所以訓練數據+測試數據總共1024個,其中取101-1023作爲訓練數據,1-100作爲測試數據。
以下就是將我們的測試數據帶入模型後輸出的結果:(注:這是使用cpu訓練的結果)
['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', 'fizz', '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', 'buzz', 'buzz', 'fizz', '67', 'buzz', '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']
我們可以看到,整個的模型效果還是比較好的。
在上邊的圖上我們也是可以看到,損失值loss也是下降的比較快,到最後10000次迭代的時候loss值更是降到了 0.0010646962327882648。好了,此篇博客就寫道這裏,後邊繼續。