task7

【Task7(2天)】手写数字识别
用PyTorch完成手写数字识别
参考: https://www.jianshu.com/p/43478538bbc6

import torch as t
def to_image(data):
    data = data.view(-1,1,28,28)
    return data

class fc_net(t.nn.Module):
    '''
    全连接网络
    '''
    def __init__(self):
        super(fc_net,self).__init__()
        self.fc1 = t.nn.Sequential(t.nn.Linear(784,200),t.nn.ReLU())
        self.fc2 = t.nn.Sequential(t.nn.Linear(200,100),t.nn.ReLU())
        self.fc3 = t.nn.Sequential(t.nn.Linear(100,20),t.nn.ReLU())
        self.fc4 = t.nn.Linear(20,10)
    def forward(self,x):
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        x = self.fc4(x)
        return x

class conv_net(t.nn.Module):
    '''
    卷积网络,需先将数据转为2维图片形式
    '''
    def __init__(self):
        super(conv_net,self).__init__()
        self.conv1 = t.nn.Sequential(
            t.nn.Conv2d(1,10,5,1,1),
            t.nn.MaxPool2d(2),
            t.nn.ReLU(),
            t.nn.BatchNorm2d(10)
        )
        self.conv2 = t.nn.Sequential(
            t.nn.Conv2d(10,20,5,1,1),
            t.nn.MaxPool2d(2),
            t.nn.ReLU(),
            t.nn.BatchNorm2d(20) # num_features为通道数
        )
        self.fc1 = t.nn.Sequential(
            t.nn.Linear(500,60),
            t.nn.Dropout(0.5),
            t.nn.ReLU()
        )
        self.fc2 = t.nn.Sequential(
            t.nn.Linear(60,20),
            t.nn.Dropout(0.5),
            t.nn.ReLU()
        )
        self.fc3 = t.nn.Linear(20,10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(-1,500)
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x

class AlexNet(t.nn.Module):
    '''
    类似AlexNet的神经网络,因为电脑配置及MNIST数据集图片尺寸问题,将Kernel_size和stride都改小了
    '''
    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        self.features = t.nn.Sequential(
            t.nn.Conv2d(1, 64, kernel_size=5, stride=1, padding=2),
            t.nn.ReLU(inplace=True),
            t.nn.MaxPool2d(kernel_size=3, stride=1),
            t.nn.Conv2d(64, 192, kernel_size=3, padding=2),
            t.nn.ReLU(inplace=True),
            t.nn.MaxPool2d(kernel_size=3, stride=2),
            t.nn.Conv2d(192, 384, kernel_size=3, padding=1),
            t.nn.ReLU(inplace=True),
            t.nn.Conv2d(384, 256, kernel_size=3, padding=1),
            t.nn.ReLU(inplace=True),
            t.nn.Conv2d(256, 256, kernel_size=3, padding=1),
            t.nn.ReLU(inplace=True),
            t.nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.classifier = t.nn.Sequential(
            t.nn.Dropout(),
            t.nn.Linear(256 * 6 * 6, 4096),
            t.nn.ReLU(inplace=True),
            t.nn.Dropout(),
            t.nn.Linear(4096, 4096),
            t.nn.ReLU(inplace=True),
            t.nn.Linear(4096, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        print(x.shape)
        x = x.view(x.size(0), 256 * 6 * 6)
        print(x.shape)
        x = self.classifier(x)
        return x
import os
import pandas as pd
import torch.nn.functional as F
from torchvision import models
import matplotlib.pyplot as plt
import torch as t
from tqdm import tqdm
from torch.autograd import Variable
from mnist_models import conv_net,to_image,fc_net,AlexNet
import signal

# 设置模型参数
TYPE = 'cla'
METHOD = 'conv'
EPOCHS = 400
BATCH_SIZE = 500
LR = 0.001

# 读取数据
train = pd.read_csv('./data/train.csv')
data = train.drop('label',axis=1)
test = pd.read_csv('./data/test.csv')
test_data = t.from_numpy(test.values).float()
data = data.values

# 标签与自变量处理
y = train['label'].values
y = t.from_numpy(y).long()
data = t.from_numpy(data).float()
data,y = Variable(data),Variable(y)

# 初始化模型
if METHOD == 'conv':
    data = to_image(data) # 将数据转为二维
    test_data = to_image(test_data)
    net = conv_net()
elif METHOD == 'fc':
    net = fc_net()
elif METHOD == 'res':
    # 使用resnet18进行迁移学习,微调参数,如果冻结参数,将resnet作为特征选择器的话,训练速度更快。
    # 因为resnet参数过多,不建议使用CPU运算,使用Xeon E5620一个EPOCH要训练三个小时
    data = to_image(data)
    test_data = to_image(test_data)
    net = models.resnet18(pretrained=True)
    # 固定参数
    for p in net.parameters():
        p.requires_grad = False

    # 因为MNIST图片是单通道,并且尺寸较小,所以需要对resnet进行一些细节修改
    net.conv1 = t.nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=3,
                           bias=False)
    net.maxpool = t.nn.MaxPool2d(kernel_size=2, stride=1, padding=1)
    net.avgpool = t.nn.AvgPool2d(5, stride=1)

    num_ftrs = net.fc.in_features
    net.fc = t.nn.Linear(num_ftrs,10)

elif METHOD == 'alex':
    data = to_image(data)
    test_data = to_image(test_data)
    net = AlexNet()

else:
    raise Exception("Wrong Method!")


# 如果模型文件存在则尝试加载模型参数
if os.path.exists('H:/learning_notes/MNIST/%s.pth' % METHOD):
    try:
        net.load_state_dict(t.load('H:/learning_notes/MNIST/%s.pth' % METHOD))
    except Exception as e:
        print(e)
        print("Parameters Error")

# 定义模型代价函数
if TYPE == 'reg':
    criterion = t.nn.MSELoss()
elif TYPE == 'cla':
    criterion = t.nn.CrossEntropyLoss()
else:
    raise Exception("Wrong Type!")

# 定义优化器
if METHOD == 'res':
    # 如果是用的resnet,则只训练最后的全连接层的参数
    optim = t.optim.Adam(net.fc.parameters(),lr = 0.001,weight_decay=0.0)
else:
    optim = t.optim.Adam(net.parameters(),lr=0.001,weight_decay=0.0)


# plt.ion() # 用于绘制动态图
# losses = []

# 用于捕捉KeyboardInterrupt错误,效果比try except好得多
# 可以人为终止训练,并将训练得到的参数保存下来,实现断点训练
def exit(signum, frame):
    print("Model Saved")
    t.save(net.state_dict(), 'H:/learning_notes/MNIST/%s.pth' % METHOD)
    raise KeyboardInterrupt

signal.signal(signal.SIGINT, exit)
signal.signal(signal.SIGTERM, exit)


# 开始训练
for epoch in tqdm(range(EPOCHS)):
    index = 0
    if epoch % 100 == 0:
        for param_group in optim.param_groups:
            LR = LR * 0.9
            param_group['lr'] = LR
    for i in tqdm(range(int(len(data)/BATCH_SIZE)),total=int(len(data)/BATCH_SIZE)):

        batch_x = data[index:index + BATCH_SIZE]
        batch_y = y[index:index + BATCH_SIZE]
        prediction = net.forward(batch_x)
        loss = criterion(prediction, batch_y)
        optim.zero_grad()
        loss.backward()
        optim.step()
        index += BATCH_SIZE  # 进入下一个batch
        # if loss <= 0.3:
            # losses.append(loss)
        # plt.plot(losses)
        # plt.pause(0.001)

        print(loss)
t.save(net.state_dict(),'H:/learning_notes/MNIST/%s.pth' % METHOD)
# plt.ioff()
submission = pd.read_csv("./data/sample_submission.csv")

print('=======Predicting========')

# 切换成验证模式,验证模式下DROPOUT将不起作用
net.eval()

test_data = Variable(test_data)

result = t.Tensor()

index = 0

# 分段进行预测,节省内存
for i in tqdm(range(int(test_data.shape[0]/BATCH_SIZE)),total=int(test_data.shape[0]/BATCH_SIZE)):
    label_prediction = net(test_data[index:index+BATCH_SIZE])
    index += BATCH_SIZE
    result = t.cat((result,label_prediction),0)

# 结果处理
if TYPE == 'cla':
    _,submission['Label'] = t.max(result.data,1) # t.max返回一个元祖,第一个元素是最大元素值,第二个元素是最大元素位置
elif TYPE == 'reg':
    submission['Label'] = submission['Label'].astype('int')
    submission['Label'] = submission['Label'].apply(lambda x:9 if x>= 10 else x)


submission.to_csv("submission.csv",index=False)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值