Skip to content

Instantly share code, notes, and snippets.

@lucasmpavelski
Last active October 17, 2017 13:27
Show Gist options
  • Save lucasmpavelski/bdff11ec0560cd79584724a2c44be5a9 to your computer and use it in GitHub Desktop.
Save lucasmpavelski/bdff11ec0560cd79584724a2c44be5a9 to your computer and use it in GitHub Desktop.
Testes RNAs para o flowshop - Parte II: PyTorch
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Testes RNAs para o flowshop - Parte II: PyTorch"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A biblioteca PyTorch ([pytorch.org](https://pytorch.org/)) foi utilizada para a segunda parte dos testes. PyTorch possui código aberto, foi construída sobre bibliotecas eficientes de álgebra linear e possui bom desempenho computacional. Além disso vários métodos do estado da arte estão disponíveis."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import torch\n",
"import torch.nn\n",
"import torch.utils.data\n",
"from torch.autograd import Variable\n",
"import pandas as pd\n",
"import numpy as np\n",
"from scipy.stats.mstats import rankdata"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Pré-processamento dos dados\n",
"\n",
"Cada linha do arquivo `N_M_makespan.csv` possui uma instância do problema flowshop com N tarefas e M máquinas, juntamente com a sequência ótima e o makespan correspondente (não utilizado). Para cada linha, são geradas N exemplos de treinamento (um para cada saída da rede). Finalmente, as entradas e saídas são normalizadas para valores entre 0 e 1."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"no_jobs = 7\n",
"no_mach = 10\n",
"dt = pd.read_csv('data/%d_%d_makespan.csv' % (no_jobs, no_mach))\n",
"no_data = dt.shape[0]\n",
"no_samples = no_data * no_jobs\n",
"input_dim = no_mach * 3\n",
"output_dim = 1\n",
"\n",
"proc_times = np.reshape(dt.values[:,0:no_jobs*no_mach] / 100, (no_data, no_jobs, no_mach))\n",
"means = np.repeat(proc_times.mean(axis=1), no_jobs, axis=0)\n",
"stds = np.repeat(proc_times.std(axis=1), no_jobs, axis=0)\n",
"\n",
"input_data = np.empty((no_samples, input_dim))\n",
"input_data[:,0:no_mach] = proc_times.reshape((no_samples, no_mach))\n",
"input_data[:,no_mach:2*no_mach] = means\n",
"input_data[:,2*no_mach:3*no_mach] = stds\n",
"\n",
"output_data = dt.values[:,no_jobs*no_mach:(no_jobs*no_mach+no_jobs)].reshape((no_data * no_jobs, output_dim))\n",
"output_data = 0.1 + (0.8 / (no_jobs - 1)) * output_data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conjuntos de treinamento e teste\n",
"\n",
"O conjunto de exemplos é dividido com 80% para treinamento e 20% para teste. O tipo Tensor do PyTorch permite representar qualquer matriz n-dimencional e TensorDataset organiza os dados de entrada e saída em um conjuto de exemplos."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"input_data, output_data = torch.Tensor(input_data), torch.Tensor(output_data)\n",
"\n",
"no_train_samples = int(no_samples * 0.8)\n",
"no_test_samples = int(no_samples * 0.2)\n",
"\n",
"part1 = no_train_samples\n",
"part2 = no_train_samples + no_test_samples\n",
"\n",
"train_ds = torch.utils.data.TensorDataset(input_data[0:part1,:], output_data[0:part1])\n",
"test_ds = torch.utils.data.TensorDataset(input_data[part1:part2,:], output_data[part1:part2])\n",
"#validation_ds = torch.utils.data.TensorDataset(input_data[part2:no_samples,:], output_data[part2:no_samples])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Treinamento\n",
"\n",
"Os parâmetros de treinamento especificados são:\n",
"\n",
"- taxa de aprendizado\n",
"- tamanho do minibatch\n",
"- número de épocas\n",
"- número de neurônios ocultos e\n",
"- frequência de saída dos erros de teste)\n",
"\n",
"X e Y são variáveis que assumirão os dados de entrada e saída e nn.Sequential especifica a arquitetura da rede (camadas em sequencia). "
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"70 30 200 1\n",
"Iter,Treinamento,Teste\n",
"0\t0.220866\t0.221222\n",
"1000\t0.173111\t0.172596\n",
"2000\t0.134897\t0.135721\n",
"3000\t0.108572\t0.108894\n",
"4000\t0.091926\t0.090816\n",
"5000\t0.077824\t0.080168\n",
"6000\t0.075983\t0.075188\n",
"7000\t0.075471\t0.073613\n",
"8000\t0.074914\t0.073276\n",
"9000\t0.070197\t0.073111\n",
"10000\t0.074211\t0.072935\n",
"11000\t0.074769\t0.072757\n",
"12000\t0.073869\t0.072588\n",
"13000\t0.069837\t0.072429\n",
"14000\t0.073650\t0.072282\n",
"15000\t0.074077\t0.072153\n",
"16000\t0.072931\t0.072038\n",
"17000\t0.069639\t0.071933\n",
"18000\t0.073162\t0.071838\n",
"19000\t0.073599\t0.071754\n",
"20000\t0.072201\t0.071679\n",
"21000\t0.069536\t0.071611\n",
"22000\t0.072806\t0.071549\n",
"23000\t0.073270\t0.071493\n",
"24000\t0.071664\t0.071444\n",
"25000\t0.069487\t0.071398\n",
"26000\t0.072522\t0.071356\n",
"27000\t0.073050\t0.071318\n",
"28000\t0.071255\t0.071285\n",
"29000\t0.069482\t0.071253\n",
"30000\t0.072309\t0.071224\n",
"31000\t0.072884\t0.071197\n",
"32000\t0.070948\t0.071174\n",
"33000\t0.069486\t0.071151\n",
"34000\t0.072150\t0.071130\n",
"35000\t0.072747\t0.071111\n",
"36000\t0.070707\t0.071094\n",
"37000\t0.069491\t0.071078\n",
"38000\t0.072034\t0.071062\n",
"39000\t0.072631\t0.071048\n",
"40000\t0.070514\t0.071035\n",
"41000\t0.069514\t0.071022\n",
"42000\t0.071943\t0.071011\n",
"43000\t0.072541\t0.070999\n",
"44000\t0.070370\t0.070989\n",
"45000\t0.069541\t0.070979\n",
"46000\t0.071876\t0.070970\n",
"47000\t0.072472\t0.070961\n",
"48000\t0.070249\t0.070953\n",
"49000\t0.069572\t0.070945\n",
"50000\t0.071814\t0.070938\n",
"51000\t0.072418\t0.070930\n",
"52000\t0.070147\t0.070924\n",
"53000\t0.069596\t0.070917\n",
"54000\t0.071772\t0.070912\n",
"55000\t0.072362\t0.070905\n",
"56000\t0.070063\t0.070900\n",
"57000\t0.069611\t0.070894\n",
"58000\t0.071743\t0.070890\n",
"59000\t0.072312\t0.070884\n",
"60000\t0.069991\t0.070879\n",
"61000\t0.069618\t0.070875\n",
"62000\t0.071719\t0.070871\n",
"63000\t0.072259\t0.070866\n",
"64000\t0.069920\t0.070862\n",
"65000\t0.069618\t0.070858\n",
"66000\t0.071697\t0.070854\n",
"67000\t0.072207\t0.070850\n",
"68000\t0.069857\t0.070846\n",
"69000\t0.069617\t0.070843\n",
"70000\t0.071677\t0.070839\n",
"71000\t0.072166\t0.070836\n",
"72000\t0.069803\t0.070832\n",
"73000\t0.069617\t0.070829\n",
"74000\t0.071663\t0.070827\n",
"75000\t0.072125\t0.070823\n",
"76000\t0.069759\t0.070820\n",
"77000\t0.069612\t0.070817\n",
"78000\t0.071648\t0.070815\n",
"79000\t0.072085\t0.070812\n",
"CPU times: user 6min 11s, sys: 2.89 s, total: 6min 14s\n",
"Wall time: 2min 16s\n"
]
}
],
"source": [
"%%time\n",
"\n",
"learning_rate = 1e-6\n",
"batch_size = no_jobs * 10\n",
"no_epochs = 100\n",
"test_freq = 1000\n",
"no_hidden = 200\n",
"\n",
"train_dl = torch.utils.data.DataLoader(train_ds, batch_size=batch_size)\n",
"test_dl = torch.utils.data.DataLoader(test_ds, batch_size=batch_size)\n",
"\n",
"N, D_in, H, D_out = batch_size, input_dim, no_hidden, output_dim\n",
"print(N, D_in, H, D_out)\n",
"\n",
"x = Variable(torch.randn(N, D_in))\n",
"y = Variable(torch.randn(N, D_out), requires_grad=False)\n",
"\n",
"model = torch.nn.Sequential(\n",
" torch.nn.Linear(D_in, H),\n",
" torch.nn.ReLU(),\n",
" torch.nn.Linear(H, D_out)\n",
" )\n",
"\n",
"criterion = torch.nn.MSELoss(size_average=True)\n",
"val_criterion = torch.nn.MSELoss(size_average=True)\n",
"optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n",
"print(\"Iter,Treinamento,Teste\")\n",
"\n",
"for epoch in range(no_epochs): # loop over the dataset multiple times \n",
" for i, data in enumerate(train_dl, 0):\n",
" # pegando as entradas e saidas\n",
" inputs, labels = data\n",
"\n",
" # convertendo em variaveis\n",
" inputs, labels = Variable(inputs), Variable(labels)\n",
"\n",
" # zerando os gradientes \n",
" optimizer.zero_grad()\n",
"\n",
" # forward + backward + otimiza\n",
" outputs = model(inputs)\n",
" loss = criterion(outputs, labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" \n",
" g_iter = (epoch - 1) * len(train_dl) + i\n",
" # imprime estatísticas\n",
" if (g_iter + 1) % test_freq == 0 : \n",
" # test\n",
" test_input, test_output = Variable(input_data[part1:part2,:]), Variable(output_data[part1:part2,:])\n",
" predictions = model(test_input)\n",
" test_loss = val_criterion(predictions, test_output)\n",
" print('%d\\t%.6f\\t%.6f' % (g_iter + 1, loss.data[0], test_loss.data[0]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Validação\n",
"\n",
"Por fim, um último teste é feito como a diferença entre a sequência gerada pela rede e a sequência ótima da instância."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.307530612245\n"
]
}
],
"source": [
"from scipy.stats.mstats import rankdata\n",
"\n",
"predictions = model(Variable(input_data[part1:part2,:]))\n",
"\n",
"job_rows = int(no_test_samples / no_jobs)\n",
"\n",
"predictions = predictions.data.numpy()\n",
"predictions = predictions.reshape((job_rows, no_jobs, 1))\n",
"\n",
"test_output = output_data[part1:part2,:]\n",
"test_output = test_output.numpy().reshape((job_rows, no_jobs, 1))\n",
"\n",
"print(np.sum(np.abs(rankdata(predictions, axis=1) - rankdata(test_output, axis=1))) / (no_test_samples*no_jobs))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment