|
| 1 | +#!/usr/bin/python3 |
| 2 | +# coding: utf-8 |
| 3 | +''' |
| 4 | +Created on 2017-12-18 |
| 5 | +Update on 2018-03-27 |
| 6 | +Author: 片刻 |
| 7 | +Github: https://github.com/apachecn/kaggle |
| 8 | +Result: |
| 9 | + BATCH_SIZE = 10 and EPOCH = 10; [10, 4000] loss: 0.069 |
| 10 | + BATCH_SIZE = 10 and EPOCH = 15; [10, 4000] loss: 0.069 |
| 11 | +''' |
| 12 | +# import csv |
| 13 | +import pandas as pd |
| 14 | + |
| 15 | +# third-party library |
| 16 | +import torch |
| 17 | +import torch.nn as nn |
| 18 | +from torch.autograd import Variable |
| 19 | +from torch.utils.data import Dataset, DataLoader |
| 20 | + |
| 21 | + |
| 22 | +class CustomedDataSet(Dataset): |
| 23 | + def __init__(self, train=True): |
| 24 | + self.train = train |
| 25 | + if self.train: |
| 26 | + trainX = pd.read_csv( |
| 27 | + '/opt/data/kaggle/getting-started/digit-recognizer/input/train.csv' |
| 28 | + # names=["ImageId", "Label"] |
| 29 | + ) |
| 30 | + trainY = trainX.label.as_matrix().tolist() |
| 31 | + trainX = trainX.drop( |
| 32 | + 'label', axis=1).as_matrix().reshape(trainX.shape[0], 1, 28, 28) |
| 33 | + self.datalist = trainX |
| 34 | + self.labellist = trainY |
| 35 | + else: |
| 36 | + testX = pd.read_csv( |
| 37 | + '/opt/data/kaggle/getting-started/digit-recognizer/input/test.csv' |
| 38 | + ) |
| 39 | + self.testID = testX.index |
| 40 | + testX = testX.as_matrix().reshape(testX.shape[0], 1, 28, 28) |
| 41 | + self.datalist = testX |
| 42 | + |
| 43 | + def __getitem__(self, index): |
| 44 | + if self.train: |
| 45 | + return torch.Tensor( |
| 46 | + self.datalist[index].astype(float)), self.labellist[index] |
| 47 | + else: |
| 48 | + return torch.Tensor(self.datalist[index].astype(float)) |
| 49 | + |
| 50 | + def __len__(self): |
| 51 | + return self.datalist.shape[0] |
| 52 | + |
| 53 | + |
| 54 | +train_data = CustomedDataSet() |
| 55 | +test_data = CustomedDataSet(train=False) |
| 56 | + |
| 57 | +BATCH_SIZE = 150 |
| 58 | +train_loader = DataLoader( |
| 59 | + dataset=train_data, batch_size=BATCH_SIZE, shuffle=True, num_workers=2) |
| 60 | +test_loader = DataLoader( |
| 61 | + dataset=test_data, batch_size=BATCH_SIZE, shuffle=False, num_workers=2) |
| 62 | + |
| 63 | + |
| 64 | +class CNN(nn.Module): |
| 65 | + def __init__(self): |
| 66 | + super(CNN, self).__init__() |
| 67 | + self.conv1 = nn.Sequential( # input shape (1, 28, 28) |
| 68 | + nn.Conv2d( |
| 69 | + in_channels=1, # input height |
| 70 | + out_channels=16, # n_filters |
| 71 | + kernel_size=5, # filter size |
| 72 | + stride=1, # filter movement/step |
| 73 | + padding=2, # if want same width and length of this image after con2d, padding=(kernel_size-1)/2 if stride=1 |
| 74 | + ), # output shape (16, 28, 28) |
| 75 | + nn.ReLU(), # activation |
| 76 | + nn.MaxPool2d( |
| 77 | + kernel_size=2 |
| 78 | + ), # choose max value in 2x2 area, output shape (16, 14, 14) |
| 79 | + ) |
| 80 | + self.conv2 = nn.Sequential( # input shape (1, 14, 14) |
| 81 | + nn.Conv2d(16, 32, 5, 1, 2), # output shape (32, 14, 14) |
| 82 | + nn.ReLU(), # activation |
| 83 | + nn.MaxPool2d(2), # output shape (32, 7, 7) |
| 84 | + ) |
| 85 | + self.out = nn.Linear(32 * 7 * 7, |
| 86 | + 10) # fully connected layer, output 10 classes |
| 87 | + |
| 88 | + def forward(self, x): |
| 89 | + x = self.conv1(x) |
| 90 | + x = self.conv2(x) |
| 91 | + x = x.view( |
| 92 | + x.size(0), |
| 93 | + -1) # flatten the output of conv2 to (batch_size, 32 * 7 * 7) |
| 94 | + output = self.out(x) |
| 95 | + return output, x # return x for visualization |
| 96 | + |
| 97 | + |
| 98 | +cnn = CNN() |
| 99 | +# print(cnn) # net architecture |
| 100 | + |
| 101 | +LR = 0.001 # learning rate |
| 102 | +optimizer = torch.optim.Adam( |
| 103 | + cnn.parameters(), lr=LR) # optimize all cnn parameters |
| 104 | +loss_func = nn.CrossEntropyLoss() # the target label is not one-hotted |
| 105 | + |
| 106 | +# training and testing |
| 107 | +print(u'开始训练') |
| 108 | +EPOCH = 5 # train the training data n times, to save time, we just train 1 epoch |
| 109 | +for epoch in range(EPOCH): |
| 110 | + running_loss = 0.0 |
| 111 | + |
| 112 | + for step, (x, y) in enumerate( |
| 113 | + train_loader |
| 114 | + ): # gives batch data, normalize x when iterate train_loader |
| 115 | + b_x = Variable(x) # batch x |
| 116 | + b_y = Variable(y) # batch y |
| 117 | + |
| 118 | + output = cnn(b_x)[0] # 输入训练数据 |
| 119 | + loss = loss_func(output, b_y) # 计算误差 |
| 120 | + optimizer.zero_grad() # 清空上一次梯度 |
| 121 | + loss.backward() # 误差反向传递 |
| 122 | + optimizer.step() # 优化器参数更新 |
| 123 | + |
| 124 | + # 每1000批数据打印一次平均loss值 |
| 125 | + running_loss += loss.data[ |
| 126 | + 0] # loss本身为Variable类型,所以要使用data获取其Tensor,因为其为标量,所以取0 |
| 127 | + if step % 500 == 499: # 每2000批打印一次 |
| 128 | + print('[%d, %5d] loss: %.3f' % |
| 129 | + (epoch + 1, step + 1, running_loss / 500)) |
| 130 | + running_loss = 0.0 |
| 131 | +print('Finished Training') |
| 132 | + |
| 133 | +# correct = 0 |
| 134 | +# total = 0 |
| 135 | +# for img, label in test_loader: |
| 136 | +# img = Variable(img, volatile=True) |
| 137 | +# label = Variable(label, volatile=True) |
| 138 | + |
| 139 | +# outputs = cnn(img) |
| 140 | +# _, predicted = torch.max(outputs[0], 1) |
| 141 | +# # print('1-', type(label), '-------', label) |
| 142 | +# # print('2-', type(predicted), '-------', predicted) |
| 143 | +# total += label.size(0) |
| 144 | +# num_correct = (predicted == label).sum() |
| 145 | +# correct += num_correct.data[0] |
| 146 | + |
| 147 | +# print('Accuracy of the network on the %d test images: %.3f %%' % (total, 100 * correct / total)) |
| 148 | + |
| 149 | +# I just can't throw all of test data into the network,since it was so huge that my GPU memory cann't afford it |
| 150 | +ans = torch.LongTensor() # build a tensor to concatenate answers |
| 151 | +for img in test_loader: |
| 152 | + img = Variable(img) |
| 153 | + outputs = cnn(img) |
| 154 | + _, predicted = torch.max(outputs[0], 1) |
| 155 | + # print('type(predicted) = ', type(predicted), predicted) |
| 156 | + ans = torch.cat([ans, predicted.data], 0) |
| 157 | + |
| 158 | +testLabel = ans.numpy() # only tensor on cpu can transform to the numpy array |
| 159 | + |
| 160 | +# # 结果输出保存 |
| 161 | +# def saveResult(result, csvName): |
| 162 | +# with open(csvName, 'w') as myFile: |
| 163 | +# myWriter = csv.writer(myFile) |
| 164 | +# myWriter.writerow(["ImageId", "Label"]) |
| 165 | +# index = 0 |
| 166 | +# for r in result: |
| 167 | +# index += 1 |
| 168 | +# myWriter.writerow([index, int(r)]) |
| 169 | + |
| 170 | +# print('Saved successfully...') # 保存预测结果 |
| 171 | + |
| 172 | +# saveResult(testLabel, |
| 173 | +# '/opt/data/kaggle/getting-started/digit-recognizer/output/Result_pytorch_CNN.csv') |
| 174 | + |
| 175 | +# 提交结果 |
| 176 | +submission_df = pd.DataFrame( |
| 177 | + data={'ImageId': test_data.testID+1, |
| 178 | + 'Label': testLabel}) |
| 179 | +# print(submission_df.head(10)) |
| 180 | +submission_df.to_csv( |
| 181 | + '/opt/data/kaggle/getting-started/digit-recognizer/output/Result_pytorch_CNN.csv', |
| 182 | + columns=["ImageId", "Label"], |
| 183 | + index=False) |
0 commit comments