Fizz Buzz in Pytorch

王 茂南 2019年6月6日09:19:36
评论
1 4708字阅读15分41秒
摘要这一篇文章会简单实现一下Fizz Buzz, 原文是一个挺好玩的故事, 在这里自己实现了一下. 整个过程是一个可以用来练手学习Pytorch, 或是练手网络的搭建等.

介绍

这个的想法来自下面的这篇文章,Fizz Buzz in Tensorflow,作者写成了一个面试的故事(还是很有趣的,可以看一下原文)。

大致的意思如下:

面试官有一题有这样的要求:I need you to print the numbers from 1 to 100, except that if the number is divisible by 3 print "fizz", if it's divisible by 5 print "buzz", and if it's divisible by 15 print "fizzbuzz".

然后我们使用神经网络来做解答。大致的思路是下面这样的,主要是train data的表示

  • Train Data : 101-1024, 转换为二进制, 每个数使用10个0或1来进行表示.
  • Label : 使用one-hot表示四种格式.

其实,这个做法看起来是没什么道理的,就是我们有更加简单的方法可以解决这个问题。不过,All Models Are Wrong, Some Are Useful。最终能实现目的即可。

Fizz Buzz in Pytorch

下面贴一下详细的实现的过程。

Pytorch详细实现过程

Start with some standard imports

  1. import numpy as np
  2. import torch
  3. import torch.nn as nn
  4. import torch.utils.data as Data
  5. from torch.autograd import Variable

定义encode函数

我们在这里先定义两个函数:

  • binary_encode : 将十进制转为二进制
  • fizz_buzz_encode : 将数字转为最后需要预测的四个类别
  1. def binary_encode(i, num_digits):
  2.     """将每个input转换为binary digits(转换为二进制的表示, 最多可是表示2^num_digits)
  3.     """
  4.     return np.array([i >> d & 1 for d in range(num_digits)])
  5. def fizz_buzz_encode(i):
  6.     """将output转换为lebel
  7.     """
  8.     if   i % 15 == 0: return 3
  9.     elif i % 5  == 0: return 2
  10.     elif i % 3  == 0: return 1
  11.     else:             return 0

产生训练数据

我们使用101-1024作为训练数据。

  1. NUM_DIGITS = 10
  2. trX = np.array([binary_encode(i, NUM_DIGITS) for i in range(101, 2**NUM_DIGITS)])
  3. trY = np.array([fizz_buzz_encode(i) for i in range(101, 2**NUM_DIGITS)])

我们看一下数据的内容

Fizz Buzz in Pytorch

定义模型

接下来,我们就可以定义我们需要使用的model了。

  1. class FizzBuzzModel(nn.Module):
  2.     def __init__(self, in_features, out_classes, hidden_size, n_hidden_layers):
  3.         super(FizzBuzzModel,self).__init__()
  4.         layers = []
  5.         for i in range(n_hidden_layers):
  6.             layers.append(nn.Linear(hidden_size,hidden_size))
  7.             # layers.append(nn.Dropout(0.5))
  8.             layers.append(nn.BatchNorm1d(hidden_size))
  9.             layers.append(nn.ReLU())
  10.         self.inputLayer = nn.Linear(in_features, hidden_size)
  11.         self.relu = nn.ReLU()
  12.         self.layers = nn.Sequential(*layers)
  13.         self.outputLayer = nn.Linear(hidden_size, out_classes)
  14.     def forward(self,x):
  15.         x = self.inputLayer(x)
  16.         x = self.relu(x)
  17.         x = self.layers(x)
  18.         out = self.outputLayer(x)
  19.         return out

模型的训练

模型初始化, 定义loss和优化器

  1. # Device configuration
  2. device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  3. # define the model
  4. simpleModel = FizzBuzzModel(10,4,150,3).to(device)
  5. print(simpleModel)
  6. # Loss and optimizer
  7. learning_rate = 0.05
  8. criterion = nn.CrossEntropyLoss()
  9. optimizer = torch.optim.Adam(simpleModel.parameters(), lr=learning_rate)

定义DataLoader

  1. # 使用batch进行训练
  2. FizzBuzzDataset = Data.TensorDataset(torch.from_numpy(trX).float().to(device),
  3.                                     torch.from_numpy(trY).long().to(device))
  4. loader = Data.DataLoader(dataset=FizzBuzzDataset,
  5.                         batch_size=128*5,
  6.                         shuffle=True)

进行训练

  1. # 进行训练
  2. simpleModel.train()
  3. epochs = 3000
  4. for epoch in range(1,epochs):
  5.     for step,(batch_x, batch_y) in enumerate(loader):
  6.         out = simpleModel(batch_x) # 前向传播
  7.         loss = criterion(out, batch_y) # 计算损失
  8.         optimizer.zero_grad() # 梯度清零
  9.         loss.backward() # 反向传播
  10.         optimizer.step() # 随机梯度下降
  11.     correct = 0
  12.     total = 0
  13.     _, predicted = torch.max(out.data, 1)
  14.     total += batch_y.size(0)
  15.     correct += (predicted == batch_y).sum().item()
  16.     acc = 100*correct/total
  17.     print('Epoch : {:0>4d} | Loss : {:<6.4f} | Train Accuracy : {:<6.2f}%'.format(epoch,loss,acc))

这里我们进行了3000个epoch的训练,最后准确率可以到100%

Fizz Buzz in Pytorch

模型的测试

最后我们在测试集(也就是1-100)上进行测试,看一下测试集上的准确率是多少。

我们首先定义一个格式转换的函数

  1. def fizz_buzz_decode(i, prediction):
  2.     return [str(i), "fizz", "buzz", "fizzbuzz"][prediction]

接着我们进行预测, 注意模型使用的时候需要进行模式的切换(切换为eval模式), 具体可以查看这篇文章, Batch Normalization技术介绍

  1. simpleModel.eval()
  2. # 进行预测
  3. testX = np.array([binary_encode(i, NUM_DIGITS) for i in range(1, 101)])
  4. predicts = simpleModel(torch.from_numpy(testX).float().to(device))
  5. # 预测的结果
  6. _,res = torch.max(predicts,1)
  7. res
  8. # 格式的转换
  9. predictions = [fizz_buzz_decode(i,prediction) for (i,prediction) in zip(range(1,101),res)]
  10. print(predictions)

看一下输出的结果:

  1. ['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']

这个准确率是100%的,我就不在这里贴代码了,可以自己实现一下,还是很简单的。

总结

其实我做完这个例子,觉得这是一个很好的练手的例子。因为他的数据量较小, 所以训练的速度比较快。而且数据和这个问题比较好理解,所以还是可以用来熟悉一下整体的架构和流程的。

关于详细的代码可以查看下面的连接, 下载notebook进行运行 : Fizz Buzz in Pytorch

  • 微信公众号
  • 关注微信公众号
  • weinxin
  • QQ群
  • 我们的QQ群号
  • weinxin
王 茂南
  • 本文由 发表于 2019年6月6日09:19:36
  • 转载请务必保留本文链接:https://mathpretty.com/10526.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: