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。好了,此篇博客就寫道這裏,後邊繼續。

5.參考

pytorch官方文檔查閱入口請戳這裏:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章