- 数据集下载地址:https://www.kaggle.com/c/digit-recognizer/data
- 本项目以CNN实战流程讲解为主,非准确率效果提升技巧项目.
- 本项目流程规范为作者个人理解,不做指导性建议,读者可根据个人理解梳理.
Step1-数据处理
- 通常是项目中较为麻烦的代码,我们需要把原始数据转变为模型可以处理的格式
def load_data():
"""
加载数据
"""
train = pd.read_csv('./data/train.csv')
data = train.drop('label', axis=1)
test = pd.read_csv('./data/test.csv')
# 测试集 转为 tensor
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()
# 最后进行误差反向传递的时候, 一次性将所有 variable 里面的修改幅度 (梯度) 都计算出来, tensor 没有这个功能
data, y = Variable(data), Variable(y)
return data, y, test_data
def to_image(data):
"""
将数据转为二维, 我们的图片是 28 * 28 的。
:param data:
:return:
"""
data = data.view(-1, 1, 28, 28)
return data
Setp2-定义网络
class conv_net(t.nn.Module):
"""
卷积神经网络, 上篇文章中已经对网络结构做过介绍,直接使用
"""
def __init__(self):
super(conv_net, self).__init__()
self.conv1 = t.nn.Sequential(
t.nn.Conv2d(1, 10, 5),
t.nn.MaxPool2d(2),
t.nn.ReLU(),
t.nn.BatchNorm2d(10)
)
self.conv2 = t.nn.Sequential(
t.nn.Conv2d(10, 20, 5),
t.nn.MaxPool2d(2),
t.nn.ReLU(),
t.nn.BatchNorm2d(20)
)
self.fc1 = t.nn.Sequential(
t.nn.Linear(320, 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, 320)
x = self.fc1(x)
x = self.fc2(x)
x = self.fc3(x)
return x
# 定义网络结构
net = conv_net()
Step3 - 定义损失函数
# 定义模型损失函数
criterion = t.nn.CrossEntropyLoss()
Step4 - 定义优化器
# 定义优化器
optim = t.optim.Adam(net.parameters(), lr=0.001, weight_decay=0.0)
Step5 - 模型训练
因为这里 test_data 没有 label,验证模型效果需要提交到 kaggle 验证,作者这里从 data 中拆分出 10% 当作验证集。想尝试的,也可以直接使用 test_data,提交到 kaggle 验证模型效果。
# 加载数据,处理数据
data, y, test_data = load_data()
data = to_image(data)
# test_data = to_image(test_data)
test_data = data[37800:]
test_y = y[37800:]
data = data[0:37800]
y = y[0:37800]
# 模型训练
EPOCHS = 100
BATCH_SIZE = 500
LR = 0.001
for epoch in tqdm(range(EPOCHS)):
# 动态调整学习率
if epoch % 100 == 0:
for param_group in optim.param_groups:
LR = LR * 0.9
param_group['lr'] = LR
index = 0
# 分批次训练
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
loss = criterion(prediction, batch_y)
# 我们需要在开始进行反向传播之前将梯度设置为零,因为PyTorch 会在随后的向后传递中累积梯度。
# 当网络参量进行反馈时,梯度是被积累的而不是被替换掉;但是在每一个batch时毫无疑问并不需要将两个batch的梯度混合起来累积,因此这里就需要每个batch设置一遍zero_grad
optim.zero_grad()
# 方向传播
loss.backward()
# 参数更新
optim.step()
index = index + BATCH_SIZE
print(loss.item())
# 保存模型
t.save(net.state_dict(), 'conv.pth')
Step6 - 验证模型效果
# 验证模型效果
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)
# t.max返回一个元祖,第一个元素是最大元素值,第二个元素是最大元素位置
_,pred = t.max(result.data, 1)
train_correct = (pred == test_y).sum().item()
accuracy = train_correct/len(pred)
print(accuracy)
一个完整的深度学习项目大致流程如此,熟悉基本套路之后我们才能在此基础之上不断改进。
- 文中具体代码细节,后续不定时补充