{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-07-17T15:49:50.067430Z","iopub.execute_input":"2023-07-17T15:49:50.068770Z","iopub.status.idle":"2023-07-17T15:49:50.086143Z","shell.execute_reply.started":"2023-07-17T15:49:50.068718Z","shell.execute_reply":"2023-07-17T15:49:50.085252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport numpy as np","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:50.088083Z","iopub.execute_input":"2023-07-17T15:49:50.088783Z","iopub.status.idle":"2023-07-17T15:49:50.093740Z","shell.execute_reply.started":"2023-07-17T15:49:50.088744Z","shell.execute_reply":"2023-07-17T15:49:50.092412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train=pd.read_csv('/kaggle/input/Kannada-MNIST/train.csv')\ntest=pd.read_csv('/kaggle/input/Kannada-MNIST/test.csv')","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:50.095292Z","iopub.execute_input":"2023-07-17T15:49:50.095949Z","iopub.status.idle":"2023-07-17T15:49:53.735548Z","shell.execute_reply.started":"2023-07-17T15:49:50.095917Z","shell.execute_reply":"2023-07-17T15:49:53.734379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_label=train['label'].values\ntrain=train.iloc[:,1:].values\ntest_id=test['id'].values\nTest=test.drop([\"id\"],axis=1).values","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:53.737920Z","iopub.execute_input":"2023-07-17T15:49:53.738270Z","iopub.status.idle":"2023-07-17T15:49:53.753207Z","shell.execute_reply.started":"2023-07-17T15:49:53.738239Z","shell.execute_reply":"2023-07-17T15:49:53.751800Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import StandardScaler\n\ntrain = train.astype(np.float32)\ntest  = test.astype(np.float32)\n# 训练集标准化\nscaler = StandardScaler()\ntrain = scaler.fit_transform(train)\n\n# 测试集标准化\nTest = scaler.transform(Test)","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:53.755050Z","iopub.execute_input":"2023-07-17T15:49:53.755762Z","iopub.status.idle":"2023-07-17T15:49:54.503081Z","shell.execute_reply.started":"2023-07-17T15:49:53.755727Z","shell.execute_reply":"2023-07-17T15:49:54.501859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"valid=train[40000:]\ntrain=train[:40000]\nvalid_label=train_label[40000:]\ntrain_label=train_label[:40000]","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:54.504709Z","iopub.execute_input":"2023-07-17T15:49:54.505353Z","iopub.status.idle":"2023-07-17T15:49:54.510451Z","shell.execute_reply.started":"2023-07-17T15:49:54.505321Z","shell.execute_reply":"2023-07-17T15:49:54.509025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:54.511753Z","iopub.execute_input":"2023-07-17T15:49:54.512842Z","iopub.status.idle":"2023-07-17T15:49:54.522946Z","shell.execute_reply.started":"2023-07-17T15:49:54.512809Z","shell.execute_reply":"2023-07-17T15:49:54.521998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import Dataset,DataLoader\nclass MNISTDataset(Dataset):   #在使用这个数据集类时，可以通过索引操作来获取特定位置的数据样本和标签，\n                                #例如dataset[0]可以获取第一个数据样本和标签。  \n    def __init__(self,x,y=None):  #测试集数据不需要标签\n        self.x=x #数据集的特征向量\n        self.y=y #数据集的标签\n    def __len__(self):\n        return len(self.x)\n    def __getitem__(self,item):\n        xi=torch.tensor(self.x[item]).float()   #通过索引item来获取特定位置的数据样本和标签\n        if self.y is None:                      \n            return xi  #检查self.yh是否为None.如果是None,则说明数据集没有标签,只能返回特征向量xi\n        else:          #否则,将self.y[item]转换成torch.tensor类型,并使用.long()方法转换成长整型,\n            yi=torch.tensor(self.y[item]).long()    #并返回特征向量xi和标签yi\n                                                    #在多分类任务中，标签通常使用整数来表示不同的类别，因此需要将标签转换为长整型以便进行模型训练和评估。\n        #注意,多分类需要用到CrossEntropyLoss\n        return xi,yi                        #Dataset\n\ntrain_ds=MNISTDataset(train,train_label) #创建了训练数据集\nvalid_ds=MNISTDataset(valid,valid_label) #创建了验证数据集\ntest_ds=MNISTDataset(Test)               #创建了测试数据集     #DataLoader\ntrain_dl=DataLoader(train_ds,shuffle=True,batch_size=16)#创建了训练数据加载器\nvalid_dl=DataLoader(valid_ds,shuffle=True,batch_size=16)#创建了验证数据加载器\ntest_dl=DataLoader(test_ds,shuffle=False,batch_size=16) #创建了测试数据加载器","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:54.524625Z","iopub.execute_input":"2023-07-17T15:49:54.526478Z","iopub.status.idle":"2023-07-17T15:49:54.536930Z","shell.execute_reply.started":"2023-07-17T15:49:54.526444Z","shell.execute_reply":"2023-07-17T15:49:54.536088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCH = 1\nBATCH_SIZE = 64\nTIME_STEP = 28\nINPUT_SIZE = 28\nLR = 0.01\nclass CNN(nn.Module):\n    def __init__(self):\n        super(CNN,self).__init__()\n        self.conv1=nn.Sequential( #input shape(1,28,28)\n        nn.Conv2d(         \n        in_channels=1,              #n_filters 输入图像的通道数,通常为1（灰度图像）或3（RGB图像）。\n        out_channels=16,            #          输出通道数,也可以看做是卷积核的数量,out_channels=16表示模型采用16个卷积核对输入图像进行卷积操作\n        kernel_size=5,              #卷积核大小,kernel_size=5等于模型使用5x5的卷积核\n        stride=1,\n        padding=2,                  #padding=(kernel_size-1)/2 if stride=1\n    ),                              #output shape(16,28,28)\n        nn.ReLU(),                  #activation\n        nn.MaxPool2d(kernel_size=2),#choose max value in 2x2 area,\n    )                               #output shape(16,14,14)\n       \n        self.conv2=nn.Sequential(   #input shape(16,14,14)\n        nn.Conv2d(16,32,5,1,2),     #output shape\n        nn.ReLU(),\n        nn.MaxPool2d(2),\n    )\n        self.out=nn.Linear(32*7*7, 10)\n\n    \n    def forward(self,x):\n        x=self.conv1(x)\n        x=self.conv2(x)\n        x=x.view(x.size(0),-1) #flatten the output of conv2 to (batch_size,32*7*7)\n        output=self.out(x) \n        return output\n    ","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:54.538219Z","iopub.execute_input":"2023-07-17T15:49:54.538985Z","iopub.status.idle":"2023-07-17T15:49:54.554933Z","shell.execute_reply.started":"2023-07-17T15:49:54.538953Z","shell.execute_reply":"2023-07-17T15:49:54.553886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model=CNN()\n\n#model.parameters:要被优化的模型参数\noptimizer=torch.optim.Adam(model.parameters(),lr=0.0003) \n\n#使用交叉熵损失函数\nloss_func=torch.nn.CrossEntropyLoss()\n\nmodel","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:54.557896Z","iopub.execute_input":"2023-07-17T15:49:54.558280Z","iopub.status.idle":"2023-07-17T15:49:54.575367Z","shell.execute_reply.started":"2023-07-17T15:49:54.558249Z","shell.execute_reply":"2023-07-17T15:49:54.574126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm.auto import tqdm\nfor epoch in tqdm(range(5)):  #外层循环控制训练轮数\n    model.train()\n    for batch_idx,(data,target) in enumerate(train_dl): \n        #内侧循环用于遍历训练数据集的批次\n        cal_data=model(data.view(-1,1,28,28)) #首先通过模型model对输入数据data进行前向传播计算得到cal_data。\n                             #然后，将计算得到的数据cal_data与目标数据target进行比较，计算损失值loss。\n        #将计算的数据与目标数据求误差损失\n        loss=loss_func(cal_data,target)   \n        optimizer.zero_grad()#清空之前计算的梯度\n        loss.backward()      #反向传播计算\n        optimizer.step()     #更新模型参数\n        \n       #每间隔200*batchsize(200)=40000打印输出结果\n        if batch_idx % 200 == 0:\n                print('训练: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n                epoch, batch_idx * len(data), len(train_dl.dataset), \n                100. * batch_idx / len(train_dl), loss.item()))\n\n #验证\n    model.eval()\n    test_loss=0\n    correct=0\n   \n    for data,target in valid_dl:\n        logits=model(data.view(-1,1,28,28)) #注意是4维的\n#nn.Conv2d输入数据应为‘torch tensor’,并且是四维的\n#输入的维度一般是(batch_size,channels,height,width)\n#batch_size:一次输入的样本数量 channels:表示输入图像的通道数,\n                            #对于彩色图片,通常有3个通道(红,绿,黄),灰度图像1个\n#height和width表示输入图像的高度和宽度,这两个值可以是任意正整数,但是在进行卷积操作时,\n#通常要求输入图像的高度和宽度与卷积核的尺寸相匹配\n        test_loss +=loss_func(logits,target).item()\n#通过loss_func(logits, target)计算模型在当前批次的预测结果logits和真实标签target之间的损失值。\n#假设loss_func是定义的损失函数。\n#然后，通过.item()方法将损失值转换为Python标量，并将其累加到test_loss上。\n        \n        pred=logits.data.argmax(dim=1)\n        #获得预测结果中概率最大的类别的索引\n        #取出预测最大值的索引编号,即预测值\n       \n        correct+=pred.eq(target.data).sum()\n         #统计正确预测的个数\n        \n    test_loss/=len(valid_dl.dataset)\n    print(f\"测试: Average loss: {test_loss:.4f}, Accuracy: {correct}/{len(valid_dl.dataset)} ({100. * correct / len(valid_dl.dataset):.0f}%)\")","metadata":{"execution":{"iopub.status.busy":"2023-07-17T15:49:54.577037Z","iopub.execute_input":"2023-07-17T15:49:54.577362Z","iopub.status.idle":"2023-07-17T15:51:42.707855Z","shell.execute_reply.started":"2023-07-17T15:49:54.577335Z","shell.execute_reply":"2023-07-17T15:51:42.707126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**保存预测结果**","metadata":{}},{"cell_type":"code","source":"model.eval()\npreds=[]\nfor data in test_dl:\n    logits=model(data.view(-1,1,28,28)) #nn.Con2v:用于二维卷积的模块\n    preds.append(logits.argmax(dim=1).cpu().numpy())\n    #选择预测概率最高的类别作为预测结果","metadata":{"execution":{"iopub.status.busy":"2023-07-17T16:01:51.182042Z","iopub.execute_input":"2023-07-17T16:01:51.182465Z","iopub.status.idle":"2023-07-17T16:01:52.018970Z","shell.execute_reply.started":"2023-07-17T16:01:51.182430Z","shell.execute_reply":"2023-07-17T16:01:52.017935Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission=pd.read_csv('/kaggle/input/Kannada-MNIST/sample_submission.csv')\npreds=np.concatenate(preds)\n#将preds列表中的所有元素连接成一个NumPy数组，可以使用np.concatenate()函数。不然原来是个list用不了reshape\nsubmission[\"label\"] = preds.reshape(-1)\n#reshape(-1)的作用是将preds数组展平成一维数组,以便与submission的数据框行数相匹配\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-07-17T16:07:22.471716Z","iopub.execute_input":"2023-07-17T16:07:22.472074Z","iopub.status.idle":"2023-07-17T16:07:22.490794Z","shell.execute_reply.started":"2023-07-17T16:07:22.472047Z","shell.execute_reply":"2023-07-17T16:07:22.489629Z"},"trusted":true},"execution_count":null,"outputs":[]}]}