{"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!pip install pandas==1.3.1\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\nimport torch\nfrom torch.utils.data import Dataset\nfrom torchvision import datasets\nfrom torchvision.transforms import ToTensor\nimport torchvision.transforms\nimport matplotlib.pyplot as plt\nimport os\nfrom torch.utils.data import Dataset,DataLoader\nfrom torchvision.io import read_image\nfrom PIL import Image\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\n\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-03-30T06:38:38.328508Z","iopub.execute_input":"2023-03-30T06:38:38.328965Z","iopub.status.idle":"2023-03-30T06:39:07.111302Z","shell.execute_reply.started":"2023-03-30T06:38:38.328912Z","shell.execute_reply":"2023-03-30T06:39:07.110168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install d2l\nfrom d2l import torch as d2l","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:07.113127Z","iopub.execute_input":"2023-03-30T06:39:07.113657Z","iopub.status.idle":"2023-03-30T06:39:29.999243Z","shell.execute_reply.started":"2023-03-30T06:39:07.113627Z","shell.execute_reply":"2023-03-30T06:39:29.998017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 将字符标签处理为整形数字类型","metadata":{}},{"cell_type":"code","source":"#from sklearn import preprocessing\n\n# t_labelencode = preprocessing.LabelEncoder()\n# label = t_labelencode.fit(data['label'])\n# s = t_labelencode.transform(data['label'])\n# data['label'] = s\n\ndata = pd.read_csv(\"../input/classify-leaves/train.csv\")\ndata_labels = sorted(list(set(data[\"label\"])))\nlabel_num = dict(zip(data_labels,range(len(data_labels))))\n","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.000973Z","iopub.execute_input":"2023-03-30T06:39:30.001691Z","iopub.status.idle":"2023-03-30T06:39:30.052312Z","shell.execute_reply.started":"2023-03-30T06:39:30.001654Z","shell.execute_reply":"2023-03-30T06:39:30.051409Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 按照7：3开的比例切成训练集和验证集","metadata":{}},{"cell_type":"code","source":"s_len=len(data)\nn_train = int(s_len * 0.7)\ntrain_data = data[0:n_train]\nvalid_data = data[n_train:]\nvalid_data\n# train_data = data\n\n# data2 = pd.read_csv(\"../input/classify-leaves/sample_submission.csv\")\n# t_labelencode = preprocessing.LabelEncoder()\n# label = t_labelencode.fit(data2['label'])\n# s1= t_labelencode.transform(data2['label'])\n# data2['label'] = s1\n# valid_data = data2\n# valid_data\n\n#label_num(train_data['label'].values[5])\n#label_num(train_data['label'].values[0])\n #== 'broussonettia_papyrifera'\nlabel_num[train_data['label'].values[5]]","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.05541Z","iopub.execute_input":"2023-03-30T06:39:30.055781Z","iopub.status.idle":"2023-03-30T06:39:30.188969Z","shell.execute_reply.started":"2023-03-30T06:39:30.055734Z","shell.execute_reply":"2023-03-30T06:39:30.187947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class  MyDataSet(Dataset):\n    \n    def __init__(self,rootpath,img_data_path,transform=None,df=None,mode='train'):\n        # 使用RGB通道的均值和标准差，以标准化每个通道\n        self.normalize = torchvision.transforms.Normalize(\n            [0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n\n        self.train_augs = torchvision.transforms.Compose([\n            torchvision.transforms.RandomResizedCrop(224),\n            torchvision.transforms.RandomHorizontalFlip(),\n            torchvision.transforms.ToTensor(),\n            self.normalize])\n\n        self.test_augs = torchvision.transforms.Compose([\n            torchvision.transforms.Resize(256),\n            torchvision.transforms.CenterCrop(224),\n            torchvision.transforms.ToTensor(),\n            self.normalize])\n        \n        self.rootpath = rootpath\n        self.img_path = img_data_path\n       \n        self.df =df\n        self.mode = mode\n        if mode == 'train':\n            self.transform = self.train_augs\n        else : \n            self.transform = self.test_augs\n        \n      \n    def __getitem__(self,idx): ##这是重写的核心方法，Dataloader只在意我们的这个方法的返回结果\n        \"\"\n        #df里面存的文件名\n        #通过文件名拼接实现懒加载\n        '''\n        ../input/classify-leaves/train.csv 里面存的元数据\n        '''\n        if(self.mode=='train'):\n               \n            img_name = self.df['image'].values[idx]\n            img_file_path = os.path.join(self.rootpath,\n                               img_name)\n            img = Image.open(img_file_path)\n            tensor_trans = self.transform\n            x = tensor_trans(img)\n            label_str = self.df['label'].values[idx]\n            y = label_num[label_str]\n            return x,y\n        else :\n           \n            img_name = self.df['image'].values[idx]\n            img_file_path = os.path.join(self.rootpath,\n                               img_name)\n            img = Image.open(img_file_path)\n            tensor_trans = self.transform\n            x = tensor_trans(img)\n            #label_str = f['label'].values[idx]\n            #y = label_num[label_str]\n            return  x  #最后用模型预测的时候输入 要构建一个返回只有x没有y的dataloader\n                  \n    def __len__(self):\n        return len(self.df)\n        ","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.190482Z","iopub.execute_input":"2023-03-30T06:39:30.191061Z","iopub.status.idle":"2023-03-30T06:39:30.206421Z","shell.execute_reply.started":"2023-03-30T06:39:30.191024Z","shell.execute_reply":"2023-03-30T06:39:30.205345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ntrain_dataset = MyDataSet(\"../input/classify-leaves\",\"../input/classify-leaves/train.csv\",ToTensor(),\n                   train_data)\nvalid_dataset = MyDataSet(\"../input/classify-leaves\",\"../input/classify-leaves/sample_submission.csv\",ToTensor(),\n                   valid_data)\ntrain_dataset.__getitem__(0),valid_dataset.__getitem__(0)\n","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.20771Z","iopub.execute_input":"2023-03-30T06:39:30.208203Z","iopub.status.idle":"2023-03-30T06:39:30.304294Z","shell.execute_reply.started":"2023-03-30T06:39:30.208167Z","shell.execute_reply":"2023-03-30T06:39:30.303224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_iter = DataLoader(train_dataset,batch_size=256,shuffle=True,num_workers=2)\nvalid_iter = DataLoader(valid_dataset,batch_size=256,shuffle=True,num_workers=2)","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.30704Z","iopub.execute_input":"2023-03-30T06:39:30.307706Z","iopub.status.idle":"2023-03-30T06:39:30.313285Z","shell.execute_reply.started":"2023-03-30T06:39:30.307669Z","shell.execute_reply":"2023-03-30T06:39:30.312164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# AlexNet模型","metadata":{}},{"cell_type":"code","source":"class AlexNetModule(nn.Module):\n    def __init__(self):\n        super(AlexNetModule, self).__init__()\n        self.my_net  = nn.Sequential(\n            \n            nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),\n            nn.MaxPool2d(kernel_size=3, stride=2),\n \n            nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),\n            nn.MaxPool2d(kernel_size=3, stride=2),\n  \n            nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),\n            nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),\n            nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),\n            nn.MaxPool2d(kernel_size=3, stride=2),\n            nn.Flatten(),\n    # 这里，全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合\n            nn.Linear(6400, 4096), nn.ReLU(),\n            nn.Dropout(p=0.5),\n            nn.Linear(4096, 4096), nn.ReLU(),\n            nn.Dropout(p=0.5),\n  \n            nn.Linear(4096, 176))\n        \n    def forward(self,x):\n        return self.my_net(x)\n","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.316434Z","iopub.execute_input":"2023-03-30T06:39:30.316863Z","iopub.status.idle":"2023-03-30T06:39:30.328673Z","shell.execute_reply.started":"2023-03-30T06:39:30.316823Z","shell.execute_reply":"2023-03-30T06:39:30.326081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 残差神经网络模型","metadata":{}},{"cell_type":"code","source":"class Residual(nn.Module): \n    def __init__(self, input_channels, num_channels,use_1x1conv=False, strides=1):\n        super().__init__()\n\n        self.conv1 = nn.Conv2d(input_channels, num_channels,\n                               kernel_size=3, padding=1, stride=strides) #若strides=2 ，h-3+1+2/2 ==h/2像素减半\n        self.conv2 = nn.Conv2d(num_channels, num_channels,\n                               kernel_size=3, padding=1)\n        if use_1x1conv:\n            self.conv3 = nn.Conv2d(input_channels, num_channels,\n                                   kernel_size=1, stride=strides)\n        else:\n            self.conv3 = None\n        self.bn1 = nn.BatchNorm2d(num_channels)\n        self.bn2 = nn.BatchNorm2d(num_channels)\n\n    def forward(self, X):\n        Y = F.relu(self.bn1(self.conv1(X)))\n        Y = self.bn2(self.conv2(Y))\n        if self.conv3:\n            X = self.conv3(X)\n        Y += X\n        return F.relu(Y)\n    \nclass ResNet(nn.Module):\n    def __init__(self,num_residuals):\n        super(ResNet,self).__init__()\n        self.num_residuals = num_residuals\n        self.net=nn.Sequential(\n         \n            nn.Conv2d(3,64,kernel_size=7,stride=2,padding=3),\n            nn.BatchNorm2d(64),nn.ReLU(),\n           \n            nn.MaxPool2d(kernel_size=3,stride = 2, padding=1),\n            \n           # '''将若干个残差块连接起来，每个残差块里面有num_residuals个残差层（Residual）'''\n            * self.resnet_block(64,64,2,first_block=True),\n            * self.resnet_block(64,128,2),\n            * self.resnet_block(128,256,2),\n            * self.resnet_block(256,1024,2),\n            nn.AdaptiveAvgPool2d((1,1)),\n            nn.Flatten(), \n            \n            nn.Linear(1024, 176)\n        )\n        \n    def resnet_block(self,input_channels,num_channels,num_residuals,first_block=False):\n        blk=[]\n        for i in range(num_residuals):\n            if i == 0 and not first_block:\n                blk.append(Residual(input_channels,num_channels,use_1x1conv=True, strides=2))\n            else:\n                blk.append(Residual(num_channels, num_channels))\n        return blk\n    \n    def forward(self, X):\n       \n        return self.net(X)\n        ","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.330475Z","iopub.execute_input":"2023-03-30T06:39:30.330879Z","iopub.status.idle":"2023-03-30T06:39:30.346032Z","shell.execute_reply.started":"2023-03-30T06:39:30.330846Z","shell.execute_reply":"2023-03-30T06:39:30.345158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr, num_epochs = 0.05, 50 \ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nloss_fn = nn.CrossEntropyLoss()\n\nalex_model = AlexNetModule().to(device)\n#alex_optimizer = torch.optim.SGD(params=alex_model.parameters(), lr=lr)\n\nres_model= ResNet(2).to(device)\n#res_optimizer = torch.optim.SGD(params=res_model.parameters(), lr=lr)\ndevice","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:30.349731Z","iopub.execute_input":"2023-03-30T06:39:30.350445Z","iopub.status.idle":"2023-03-30T06:39:34.621125Z","shell.execute_reply.started":"2023-03-30T06:39:30.350417Z","shell.execute_reply":"2023-03-30T06:39:34.62016Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision.models as models\ndef res_model(num_classes, feature_extract = False, use_pretrained=True):\n\n    model_ft = models.resnet18(pretrained=use_pretrained)\n    \n    #set_parameter_requires_grad(model_ft, feature_extract)\n    num_ftrs = model_ft.fc.in_features\n    model_ft.fc = nn.Sequential(nn.Linear(num_ftrs, num_classes))\n\n    return model_ft\n\n","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:34.625533Z","iopub.execute_input":"2023-03-30T06:39:34.627762Z","iopub.status.idle":"2023-03-30T06:39:34.635638Z","shell.execute_reply.started":"2023-03-30T06:39:34.627721Z","shell.execute_reply":"2023-03-30T06:39:34.634471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 如果param_group=True，输出层中的模型参数将使用十倍的学习率\ndef train_fine_tuning(net, learning_rate, batch_size=128, num_epochs=5,\n                      param_group=True):\n\n    devices = d2l.try_all_gpus()\n    loss = nn.CrossEntropyLoss(reduction=\"none\")\n    if param_group:\n        params_1x = [param for name, param in net.named_parameters() if name not in [\"fc.weight\", \"fc.bias\"]]\n        trainer = torch.optim.SGD(\n            [\n                {'params': params_1x},\n                {'params': net.fc.parameters(),'lr': learning_rate * 10}\n            ],\n            lr=learning_rate, weight_decay=0.001\n        )\n    else:\n        trainer = torch.optim.SGD(net.parameters(), lr=learning_rate,\n                                  weight_decay=0.001)\n    return net,trainer\n\nnet = res_model(176)","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:19:34.807369Z","iopub.execute_input":"2023-03-30T06:19:34.807693Z","iopub.status.idle":"2023-03-30T06:19:35.042628Z","shell.execute_reply.started":"2023-03-30T06:19:34.807668Z","shell.execute_reply":"2023-03-30T06:19:35.041682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\nmodel ,trainer= train_fine_tuning(net,5e-5,batch_size = 128,num_epochs = 20,param_group = True)\n#torch.optim.SGD(a,)","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:28:11.133036Z","iopub.execute_input":"2023-03-30T06:28:11.133825Z","iopub.status.idle":"2023-03-30T06:28:11.244648Z","shell.execute_reply.started":"2023-03-30T06:28:11.133789Z","shell.execute_reply":"2023-03-30T06:28:11.243234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"res_model = res_model(176)\nlr, num_epochs = 0.05, 50 \nd2l.train_ch6(res_model, train_iter, valid_iter, num_epochs, lr, d2l.try_gpu())","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:39:34.640187Z","iopub.execute_input":"2023-03-30T06:39:34.643075Z","iopub.status.idle":"2023-03-30T07:34:27.271489Z","shell.execute_reply.started":"2023-03-30T06:39:34.643036Z","shell.execute_reply":"2023-03-30T07:34:27.270458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 李沐代码测试\n","metadata":{}},{"cell_type":"code","source":"train_iter = DataLoader(train_dataset,batch_size=256,shuffle=True,num_workers=2)\nvalid_iter = DataLoader(valid_dataset,batch_size=256,shuffle=True,num_workers=2)","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:12:32.545232Z","iopub.execute_input":"2023-03-30T06:12:32.545929Z","iopub.status.idle":"2023-03-30T06:12:32.551686Z","shell.execute_reply.started":"2023-03-30T06:12:32.545892Z","shell.execute_reply":"2023-03-30T06:12:32.550422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"finetune_net = torchvision.models.resnet18(pretrained=True)\nfinetune_net.fc = nn.Sequential(nn.Linear(finetune_net.fc.in_features, 512),nn.Dropout(0.4),nn.Linear(512,176))\n#nn.init.xavier_uniform_(finetune_net.fc.weight)\n# 如果param_group=True，输出层中的模型参数将使用十倍的学习率\ndef train_fine_tuning(net, learning_rate, batch_size=128, num_epochs=5,\n                      param_group=False):\n  \n    devices = d2l.try_all_gpus()\n    loss = nn.CrossEntropyLoss()\n    if param_group:\n        params_1x = [param for name, param in net.named_parameters()\n             if name not in [\"fc.weight\", \"fc.bias\"]]\n        trainer = torch.optim.SGD(\n            [\n                {'params': params_1x},\n                {'params': net.fc.parameters(),\n                     'lr': learning_rate * 10}],\n                                lr=learning_rate, weight_decay=0.001)\n    else:\n        trainer = torch.optim.SGD(net.parameters(), lr=learning_rate,\n                                  weight_decay=0.001)\n    net.fc=nn.Sequential(nn.Linear(net.fc.in_features, 512),nn.Dropout(0.4),nn.Linear(512,176))\n    return net ,trainer\n\nnet,trainer = train_fine_tuning(finetune_net,5e-5)","metadata":{"execution":{"iopub.status.busy":"2023-03-30T06:19:05.827217Z","iopub.execute_input":"2023-03-30T06:19:05.827608Z","iopub.status.idle":"2023-03-30T06:19:06.185719Z","shell.execute_reply.started":"2023-03-30T06:19:05.827576Z","shell.execute_reply":"2023-03-30T06:19:06.18319Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"d2l.train_ch13(net, train_iter, valid_iter, nn.CrossEntropyLoss(reduction=\"none\"), trainer, 20,\n                    devices = d2l.try_all_gpus())","metadata":{"execution":{"iopub.status.busy":"2022-07-13T08:56:24.127213Z","iopub.execute_input":"2022-07-13T08:56:24.127577Z","iopub.status.idle":"2022-07-13T09:17:51.701331Z","shell.execute_reply.started":"2022-07-13T08:56:24.127546Z","shell.execute_reply":"2022-07-13T09:17:51.700121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df =  pd.read_csv(\"../input/classify-leaves/test.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-07-13T09:17:58.204697Z","iopub.execute_input":"2022-07-13T09:17:58.205624Z","iopub.status.idle":"2022-07-13T09:17:58.22521Z","shell.execute_reply.started":"2022-07-13T09:17:58.205573Z","shell.execute_reply":"2022-07-13T09:17:58.224289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dataset = MyDataSet(\"../input/classify-leaves\",\"../input/classify-leaves/test.csv\",ToTensor(),\n                   df,mode='test')\ntest_iter = DataLoader(test_dataset,batch_size=256,shuffle=True,num_workers=2)\ntest_dataset.__getitem__(0)","metadata":{"execution":{"iopub.status.busy":"2022-07-13T09:18:42.765661Z","iopub.execute_input":"2022-07-13T09:18:42.766145Z","iopub.status.idle":"2022-07-13T09:18:42.796847Z","shell.execute_reply.started":"2022-07-13T09:18:42.766107Z","shell.execute_reply":"2022-07-13T09:18:42.795761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm import tqdm\nmodel_path = './pre_res_model.ckpt'\ntorch.save(net.state_dict(), model_path)\nsaveFileName = './submission.csv'\nnet.eval()#这个模式是在模型训练好后开始用来预测的\nnum_to_class = {v : k for k, v in label_num.items()}#测试的时候需要用从数字转回label得到结果\n# Initialize a list to store the predictions.\npredictions = []\n# Iterate the testing set by batches.\nfor batch in tqdm(test_iter):\n    \n    imgs = batch\n    with torch.no_grad():\n        logits = net(imgs.to(d2l.try_gpu()))\n    \n    # Take the class with greatest logit as prediction and record it.\n    predictions.extend(logits.argmax(dim=-1).cpu().numpy().tolist())\n\npreds = []\nfor i in predictions:\n    preds.append(num_to_class[i])\ntest_path = \"../input/classify-leaves/test.csv\"\ntest_data = pd.read_csv(test_path)\ntest_data['label'] = pd.Series(preds)\nsubmission = pd.concat([test_data['image'], test_data['label']], axis=1)\nprint(submission)\nsubmission.to_csv(\"./My_submission2.csv\", index=False)\nprint(\"Done!!!!!!!!!!!!!!!!!!!!!!!!!!!\")","metadata":{"execution":{"iopub.status.busy":"2022-07-13T09:20:07.291393Z","iopub.execute_input":"2022-07-13T09:20:07.291782Z","iopub.status.idle":"2022-07-13T09:20:49.432888Z","shell.execute_reply.started":"2022-07-13T09:20:07.291745Z","shell.execute_reply":"2022-07-13T09:20:49.431803Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2022-07-13T09:20:50.616906Z","iopub.execute_input":"2022-07-13T09:20:50.617467Z","iopub.status.idle":"2022-07-13T09:20:50.624843Z","shell.execute_reply.started":"2022-07-13T09:20:50.617434Z","shell.execute_reply":"2022-07-13T09:20:50.623847Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for x in test_iter:\n    yhat = res_model(x)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(dataloader, model, loss_fn, optimizer):\n    size = len(dataloader.dataset)\n    model.train()\n    for batch, (X, y) in enumerate(dataloader):\n     \n        X,y = X.to(device),y.to(device)\n        # Compute prediction error\n        pred = model(X)\n        loss = loss_fn(pred, y)\n\n        # Backpropagation\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        if batch % 100 == 0:\n            loss, current = loss.item(), batch * len(X)\n            print(f\"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nfor i in range(10):\n    \n    train(train_iter,resmodel,loss_fn,optimizer)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for batch, (X, y) in enumerate(train_iter):\n        print(model(X).shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python -V","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 别人的\n","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport pandas as pd\nimport numpy as np\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\nimport os\n#import matplotlib.pyplot as plt\nimport torchvision.models as models\n# This is for the progress bar.\nfrom tqdm import tqdm\nimport seaborn as sns\nfrom d2l import  torch as d2l","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 看看label文件长啥样\nlabels_dataframe = pd.read_csv('../input/classify-leaves/train.csv')\nlabels_dataframe.head(5)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 把label文件排个序\nleaves_labels = sorted(list(set(labels_dataframe['label'])))\nn_classes = len(leaves_labels)\nprint(n_classes)\nleaves_labels[:10]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 把label转成对应的数字\nclass_to_num = dict(zip(leaves_labels, range(n_classes)))\n# 再转换回来，方便最后预测的时候使用\nnum_to_class = {v : k for k, v in class_to_num.items()}\nnum_to_class","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 继承pytorch的dataset，创建自己的\nclass LeavesData(Dataset):\n    def __init__(self, csv_path, file_path, mode='train', valid_ratio=0.2, resize_height=256, resize_width=256):\n        \"\"\"\n        Args:\n            csv_path (string): csv 文件路径\n            img_path (string): 图像文件所在路径\n            mode (string): 训练模式还是测试模式\n            valid_ratio (float): 验证集比例\n        \"\"\"\n        \n        # 需要调整后的照片尺寸，我这里每张图片的大小尺寸不一致#\n        self.resize_height = resize_height\n        self.resize_width = resize_width\n\n        self.file_path = file_path\n        self.mode = mode\n\n        # 读取 csv 文件\n        # 利用pandas读取csv文件\n        self.data_info = pd.read_csv(csv_path, header=None)  #header=None是去掉表头部分\n        # 计算 length\n        self.data_len = len(self.data_info.index) - 1\n        self.train_len = int(self.data_len * (1 - valid_ratio))\n        \n        if mode == 'train':\n            # 第一列包含图像文件的名称\n            self.train_image = np.asarray(self.data_info.iloc[1:self.train_len, 0])  #self.data_info.iloc[1:,0]表示读取第一列，从第二行开始到train_len\n            # 第二列是图像的 label\n            self.train_label = np.asarray(self.data_info.iloc[1:self.train_len, 1])\n            self.image_arr = self.train_image \n            self.label_arr = self.train_label\n        elif mode == 'valid':\n            self.valid_image = np.asarray(self.data_info.iloc[self.train_len:, 0])  \n            self.valid_label = np.asarray(self.data_info.iloc[self.train_len:, 1])\n            self.image_arr = self.valid_image\n            self.label_arr = self.valid_label\n        elif mode == 'test':\n            self.test_image = np.asarray(self.data_info.iloc[1:, 0])\n            self.image_arr = self.test_image\n            \n        self.real_len = len(self.image_arr)\n\n        print('Finished reading the {} set of Leaves Dataset ({} samples found)'\n              .format(mode, self.real_len))\n\n    def __getitem__(self, index):\n        # 从 image_arr中得到索引对应的文件名\n        single_image_name = self.image_arr[index]\n\n        # 读取图像文件\n        img_as_img = Image.open(self.file_path + single_image_name)\n\n        #如果需要将RGB三通道的图片转换成灰度图片可参考下面两行\n#         if img_as_img.mode != 'L':\n#             img_as_img = img_as_img.convert('L')\n\n        #设置好需要转换的变量，还可以包括一系列的nomarlize等等操作\n        if self.mode == 'train':\n            transform = transforms.Compose([\n                transforms.Resize((224, 224)),\n                transforms.RandomHorizontalFlip(p=0.5),   #随机水平翻转 选择一个概率\n                transforms.ToTensor()\n            ])\n        else:\n            # valid和test不做数据增强\n            transform = transforms.Compose([\n                transforms.Resize((224, 224)),\n                transforms.ToTensor()\n            ])\n        \n        img_as_img = transform(img_as_img)\n        \n        if self.mode == 'test':\n            return img_as_img\n        else:\n            # 得到图像的 string label\n            label = self.label_arr[index]\n            # number label\n            number_label = class_to_num[label]\n\n            return img_as_img, number_label  #返回每一个index对应的图片数据和对应的label\n\n    def __len__(self):\n        return self.real_len\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 是否要冻住模型的前面一些层\ndef set_parameter_requires_grad(model, feature_extracting):\n    if feature_extracting:\n        model = model\n        for param in model.parameters():\n            param.requires_grad = False\n# resnet34模型\ndef res_model(num_classes, feature_extract = False, use_pretrained=True):\n\n    model_ft = models.resnet34(pretrained=use_pretrained)\n    set_parameter_requires_grad(model_ft, feature_extract)\n    num_ftrs = model_ft.fc.in_features\n    model_ft.fc = nn.Sequential(nn.Linear(num_ftrs, num_classes))\n\n    return model_ft","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 看一下是在cpu还是GPU上\ndef get_device():\n    return 'cuda' if torch.cuda.is_available() else 'cpu'\n\ndevice = get_device()\nprint(device)\nmodel = res_model(176)\nmodel = model.to(device)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_path = '../input/classify-leaves/train.csv'\ntest_path = '../input/classify-leaves/test.csv'\n# csv文件中已经images的路径了，因此这里只到上一级目录\nimg_path = '../input/classify-leaves/'\n\ntrain_dataset = LeavesData(train_path, img_path, mode='train')\nval_dataset = LeavesData(train_path, img_path, mode='valid')\ntest_dataset = LeavesData(test_path, img_path, mode='test')\nprint(train_dataset)\nprint(val_dataset)\nprint(test_dataset)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 定义data loader\ntrain_loader = torch.utils.data.DataLoader(\n        dataset=train_dataset,\n        batch_size=8, \n        shuffle=False,\n        num_workers=5\n    )\n\nval_loader = torch.utils.data.DataLoader(\n        dataset=val_dataset,\n        batch_size=8, \n        shuffle=False,\n        num_workers=5\n    )\ntest_loader = torch.utils.data.DataLoader(\n        dataset=test_dataset,\n        batch_size=8, \n        shuffle=False,\n        num_workers=5\n    )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_epochs = 50\nlr = 3e-4","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"d2l.train_ch6(model,train_loader, val_loader, num_epochs=num_epochs, lr=lr, device = d2l.try_gpu())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}