手写数字识别

This commit is contained in:
2026-07-05 00:31:14 +08:00
parent 9d1968c020
commit 355e01a4a1
7 changed files with 98520 additions and 8 deletions
-8
View File
@@ -100,14 +100,6 @@
],
"execution_count": 241
},
{
"metadata": {},
"cell_type": "code",
"source": "",
"id": "36468cd80d626c74",
"outputs": [],
"execution_count": null
},
{
"metadata": {},
"cell_type": "code",
+207
View File
@@ -0,0 +1,207 @@
# %%
import os
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"
import torch
from torch.utils.data import Dataset, DataLoader
import pandas as pd
import transformers
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from tqdm import tqdm
# %%
train_df = pd.read_csv('./train.csv')
test_df = pd.read_csv('./test.csv')
from sklearn.model_selection import train_test_split
train_df, val_df = train_test_split(train_df, test_size=0.1, random_state=42, stratify=train_df['label'])
print(f"Train: {len(train_df)}, Val: {len(val_df)}, Test: {len(test_df)}")
# %%
train_df.head()
# %%
model_name = "xlm-roberta-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=3)
# %%
embedded_text=tokenizer("你好啊")
# %%
tokenizer.decode(embedded_text['input_ids'],skip_special_tokens=True)
# %%
embedded_text=tokenizer(["你好啊","我是灰太狼"],["我不好","我是红太狼"])
embedded_text=tokenizer("你好啊",return_tensors='pt')
# %%
class NliDataset(Dataset):
def __init__(self, df, tokenizer, max_length=128):
self.df = df.reset_index(drop=True)
self.tokenizer = tokenizer
self.max_length = max_length
def __len__(self):
return len(self.df)
def __getitem__(self, idx):
row = self.df.iloc[idx]
premise = str(row['premise'])
hypothesis = str(row['hypothesis'])
# 编码文本对,返回 input_ids, attention_mask
encoding = self.tokenizer(
premise,
hypothesis,
truncation=True,
padding='max_length',
max_length=self.max_length,
return_tensors='pt' # 返回 PyTorch Tensor
)
# 去掉 batch 维度(因为只处理单条)
item = {
'input_ids': encoding['input_ids'].squeeze(0),
'attention_mask': encoding['attention_mask'].squeeze(0)
}
if 'label' in row:
item['labels'] = torch.tensor(row['label'], dtype=torch.long)
return item
# %%
# %%
batch_size = 16 # 根据显存调整,推荐使用 16 或 32
max_length = 128
train_dataset = NliDataset(train_df, tokenizer, max_length)
val_dataset = NliDataset(val_df, tokenizer, max_length)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)
# %%
# %%
from transformers import get_linear_schedule_with_warmup
from sklearn.metrics import accuracy_score
optimizer = torch.optim.AdamW(model.parameters(), lr=2e-5)
# 计算总训练步数(用于 warmup)
total_steps = len(train_loader) * 3 # 假设训练 3 个 epoch
warmup_steps = int(0.1 * total_steps) # warmup 比例为 10%
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps=warmup_steps,
num_training_steps=total_steps
)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
# %%
def evaluate(model, data_loader, device):
model.eval()
all_preds = []
all_labels = []
with torch.no_grad():
for batch in tqdm(data_loader, desc="Evaluating"):
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
outputs = model(input_ids, attention_mask=attention_mask)
logits = outputs.logits
preds = torch.argmax(logits, dim=1)
all_preds.extend(preds.cpu().numpy())
all_labels.extend(labels.cpu().numpy())
acc = accuracy_score(all_labels, all_preds)
return acc
# %%
num_epochs = 3
best_val_acc = 0.0
for epoch in range(num_epochs):
model.train()
total_loss = 0
progress_bar = tqdm(train_loader, desc=f'Epoch {epoch+1}/{num_epochs}')
for batch in progress_bar:
# 将数据移至设备
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
# 前向传播
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
# 反向传播
loss.backward()
# 梯度裁剪(防止梯度爆炸)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
# 更新参数
optimizer.step()
scheduler.step() # 更新学习率
optimizer.zero_grad()
# 记录损失
total_loss += loss.item()
progress_bar.set_postfix({'loss': loss.item()})
avg_train_loss = total_loss / len(train_loader)
print(f"Epoch {epoch+1} - Average Train Loss: {avg_train_loss:.4f}")
# 在每个 epoch 结束后评估验证集
val_acc = evaluate(model, val_loader, device)
print(f"Epoch {epoch+1} - Validation Accuracy: {val_acc:.4f}")
# 保存最佳模型
if val_acc > best_val_acc:
best_val_acc = val_acc
torch.save(model.state_dict(), 'best_model.pt')
print("Best model saved!")
# %%
# 加载最佳模型权重
model.load_state_dict(torch.load('best_model.pt'))
model.eval()
# 构建测试集 Dataset 和 DataLoader(注意测试集没有 label
class TestDataset(Dataset):
def __init__(self, df, tokenizer, max_length=128):
self.df = df.reset_index(drop=True)
self.tokenizer = tokenizer
self.max_length = max_length
def __len__(self):
return len(self.df)
def __getitem__(self, idx):
row = self.df.iloc[idx]
premise = str(row['premise'])
hypothesis = str(row['hypothesis'])
encoding = self.tokenizer(
premise,
hypothesis,
truncation=True,
padding='max_length',
max_length=self.max_length,
return_tensors='pt'
)
return {
'input_ids': encoding['input_ids'].squeeze(0),
'attention_mask': encoding['attention_mask'].squeeze(0)
}
test_dataset = TestDataset(test_df, tokenizer, max_length)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
# 预测
all_preds = []
with torch.no_grad():
for batch in tqdm(test_loader, desc="Predicting"):
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
outputs = model(input_ids, attention_mask=attention_mask)
logits = outputs.logits
preds = torch.argmax(logits, dim=1)
all_preds.extend(preds.cpu().numpy())
# 生成提交文件
submission = pd.DataFrame({
'id': test_df['id'],
'label': all_preds
})
submission.to_csv('submission.csv', index=False)
print("Submission saved!")
+216
View File
@@ -0,0 +1,216 @@
{
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.12.13",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
}
},
"nbformat_minor": 4,
"nbformat": 4,
"cells": [
{
"cell_type": "code",
"source": "import matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport pandas as pd",
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-03T10:17:12.326817130Z",
"start_time": "2026-07-03T10:17:12.293250353Z"
},
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:16:09.940312Z",
"iopub.execute_input": "2026-07-04T16:16:09.940612Z",
"iopub.status.idle": "2026-07-04T16:16:12.856395Z",
"shell.execute_reply.started": "2026-07-04T16:16:09.940586Z",
"shell.execute_reply": "2026-07-04T16:16:12.855776Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": "%cd /kaggle/working\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\ntrain_df=pd.read_csv(\"/kaggle/input/competitions/digit-recognizer/train.csv\")\ntest_df=pd.read_csv(\"/kaggle/input/competitions/digit-recognizer/test.csv\")",
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-03T10:17:15.014258006Z",
"start_time": "2026-07-03T10:17:12.346500913Z"
},
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:16:12.857730Z",
"iopub.execute_input": "2026-07-04T16:16:12.858065Z",
"iopub.status.idle": "2026-07-04T16:16:16.048768Z",
"shell.execute_reply.started": "2026-07-04T16:16:12.858040Z",
"shell.execute_reply": "2026-07-04T16:16:16.048163Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": "fig, ax = plt.subplots(nrows=2, ncols=2, sharex='all', sharey='all')\nax = ax.flatten()\nfor i in range(4):\n img = train_df.iloc[i][1:].to_numpy().reshape(28,28)\n # ax[i].imshow(img,cmap='Greys')\n ax[i].imshow(img)\n ax[i].set_title(f'{train_df.iloc[i][0]}')",
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-03T10:17:15.565961732Z",
"start_time": "2026-07-03T10:17:15.073738808Z"
},
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:16:16.049873Z",
"iopub.execute_input": "2026-07-04T16:16:16.050089Z",
"iopub.status.idle": "2026-07-04T16:16:16.369380Z",
"shell.execute_reply.started": "2026-07-04T16:16:16.050066Z",
"shell.execute_reply": "2026-07-04T16:16:16.368725Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": "class DatasetMnist(Dataset):\n def __init__(self,df):\n self.df=df\n def __len__(self):\n return len(self.df)\n def __getitem__(self, idx):\n item= {\"Data\": torch.tensor(self.df.iloc[idx][1:].to_numpy().reshape(28, 28),dtype=torch.float), \"label\": torch.tensor(self.df.iloc[idx][0],dtype=torch.long)}\n return item\nbatch_size =64\ntrain_dataset = DatasetMnist(train_df)\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)",
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-03T10:17:15.669173315Z",
"start_time": "2026-07-03T10:17:15.616933550Z"
},
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:16:16.370253Z",
"iopub.execute_input": "2026-07-04T16:16:16.370426Z",
"iopub.status.idle": "2026-07-04T16:16:16.375630Z",
"shell.execute_reply.started": "2026-07-04T16:16:16.370409Z",
"shell.execute_reply": "2026-07-04T16:16:16.375171Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": "class MnistModule(nn.Module):\n def __init__(self):\n super(MnistModule, self).__init__()\n self.fc1 = nn.Linear(28*28, 512)\n self.relu = nn.ReLU()\n self.fc2 = nn.Linear(512, 256)\n self.fc3 = nn.Linear(256, 128)\n self.fc4 = nn.Linear(128,10)\n def forward(self,X):\n return self.fc4(self.relu(self.fc3(self.relu(self.fc2(self.relu(self.fc1(X.view(-1,28*28))))))))",
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-03T10:17:15.729366448Z",
"start_time": "2026-07-03T10:17:15.670668930Z"
},
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:16:16.376258Z",
"iopub.execute_input": "2026-07-04T16:16:16.376401Z",
"iopub.status.idle": "2026-07-04T16:16:16.389616Z",
"shell.execute_reply.started": "2026-07-04T16:16:16.376386Z",
"shell.execute_reply": "2026-07-04T16:16:16.388703Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": "model = MnistModule()\nmodel=model.to(device)\nloss_func = nn.CrossEntropyLoss()\noptimizer = torch.optim.AdamW(model.parameters(), lr=2e-4)\nscheduler=torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10)\n",
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-03T10:17:15.792463697Z",
"start_time": "2026-07-03T10:17:15.730536380Z"
},
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:16:16.390304Z",
"iopub.execute_input": "2026-07-04T16:16:16.390504Z",
"iopub.status.idle": "2026-07-04T16:16:18.580638Z",
"shell.execute_reply.started": "2026-07-04T16:16:16.390482Z",
"shell.execute_reply": "2026-07-04T16:16:18.580038Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": "epochs = 30\nfor epoch in range(epochs):\n model.train()\n training_loss=0\n for batch in train_loader:\n optimizer.zero_grad()\n X = batch['Data']\n labels=batch['label']\n X=X.to(device)\n labels=labels.to(device)\n #print(model(X),'\\n',labels)\n loss = loss_func(model(X),labels)\n loss.backward()\n optimizer.step()\n training_loss+=loss.item()\n scheduler.step()\n print(f\"train_loss: {training_loss/len(train_loader)}\")",
"metadata": {
"ExecuteTime": {
"end_time": "2026-07-03T10:18:55.758148762Z",
"start_time": "2026-07-03T10:17:31.736342843Z"
},
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:16:18.582512Z",
"iopub.execute_input": "2026-07-04T16:16:18.582874Z",
"iopub.status.idle": "2026-07-04T16:18:53.082304Z",
"shell.execute_reply.started": "2026-07-04T16:16:18.582856Z",
"shell.execute_reply": "2026-07-04T16:18:53.081057Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": [
"class DatasetMnistTest(Dataset):\n",
" def __init__(self,df):\n",
" self.df=df\n",
" def __len__(self):\n",
" return len(self.df)\n",
" def __getitem__(self, idx):\n",
" item= {\"Data\": torch.tensor(self.df.iloc[idx].to_numpy().reshape(28, 28),dtype=torch.float)}\n",
" return item\n",
"test_dataset = DatasetMnistTest(test_df)\n",
"test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n",
"all_preds = []\n",
"with torch.no_grad():\n",
" for batch in test_loader:\n",
" input_ids = batch['Data'].to(device)\n",
" outputs = model(input_ids)\n",
" preds = torch.argmax(outputs, dim=1)\n",
" all_preds.extend(preds.cpu().numpy())\n",
"idd = range(1,len(all_preds)+1)\n",
"submission = pd.DataFrame({\n",
" 'ImageId':idd,\n",
" 'Label': all_preds\n",
"})\n",
"print(submission)\n",
"submission.to_csv('submission.csv', index=False)\n",
"print(\"Submission saved!\")"
],
"metadata": {
"trusted": true,
"execution": {
"iopub.status.busy": "2026-07-04T16:19:40.600448Z",
"iopub.execute_input": "2026-07-04T16:19:40.601006Z",
"iopub.status.idle": "2026-07-04T16:19:41.910494Z",
"shell.execute_reply.started": "2026-07-04T16:19:40.600982Z",
"shell.execute_reply": "2026-07-04T16:19:41.909862Z"
}
},
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"source": "",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
}
]
}
+94
View File
@@ -0,0 +1,94 @@
# %%
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import pandas as pd
# %%
# %cd /kaggle/working
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
train_df=pd.read_csv("/kaggle/input/competitions/digit-recognizer/train.csv")
test_df=pd.read_csv("/kaggle/input/competitions/digit-recognizer/test.csv")
# %%
fig, ax = plt.subplots(nrows=2, ncols=2, sharex='all', sharey='all')
ax = ax.flatten()
for i in range(4):
img = train_df.iloc[i][1:].to_numpy().reshape(28,28)
# ax[i].imshow(img,cmap='Greys')
ax[i].imshow(img)
ax[i].set_title(f'{train_df.iloc[i][0]}')
# %%
class DatasetMnist(Dataset):
def __init__(self,df):
self.df=df
def __len__(self):
return len(self.df)
def __getitem__(self, idx):
item= {"Data": torch.tensor(self.df.iloc[idx][1:].to_numpy().reshape(28, 28),dtype=torch.float), "label": torch.tensor(self.df.iloc[idx][0],dtype=torch.long)}
return item
batch_size =64
train_dataset = DatasetMnist(train_df)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# %%
class MnistModule(nn.Module):
def __init__(self):
super(MnistModule, self).__init__()
self.fc1 = nn.Linear(28*28, 512)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(512, 256)
self.fc3 = nn.Linear(256, 128)
self.fc4 = nn.Linear(128,10)
def forward(self,X):
return self.fc4(self.relu(self.fc3(self.relu(self.fc2(self.relu(self.fc1(X.view(-1,28*28))))))))
# %%
model = MnistModule()
model=model.to(device)
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.AdamW(model.parameters(), lr=2e-4)
scheduler=torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10)
# %%
epochs = 30
for epoch in range(epochs):
model.train()
training_loss=0
for batch in train_loader:
optimizer.zero_grad()
X = batch['Data']
labels=batch['label']
X=X.to(device)
labels=labels.to(device)
#print(model(X),'\n',labels)
loss = loss_func(model(X),labels)
loss.backward()
optimizer.step()
training_loss+=loss.item()
scheduler.step()
print(f"train_loss: {training_loss/len(train_loader)}")
# %%
class DatasetMnistTest(Dataset):
def __init__(self,df):
self.df=df
def __len__(self):
return len(self.df)
def __getitem__(self, idx):
item= {"Data": torch.tensor(self.df.iloc[idx].to_numpy().reshape(28, 28),dtype=torch.float)}
return item
test_dataset = DatasetMnistTest(test_df)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
all_preds = []
with torch.no_grad():
for batch in test_loader:
input_ids = batch['Data'].to(device)
outputs = model(input_ids)
preds = torch.argmax(outputs, dim=1)
all_preds.extend(preds.cpu().numpy())
idd = range(1,len(all_preds)+1)
submission = pd.DataFrame({
'ImageId':idd,
'Label': all_preds
})
print(submission)
submission.to_csv('submission.csv', index=False)
print("Submission saved!")
# %%
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long