题目:
我們提供給各位的training dataset為兩萬八千張左右48x48 pixel的圖片,以及每一張圖片的表情label(注意:每張圖片都會唯一屬於一種表情)。總共有七種可能的表情(0:生氣, 1:厭惡, 2:恐懼, 3:高興, 4:難過, 5:驚訝, 6:中立(難以區分為前六種的表情))。
Testing data則是七千張左右48x48的圖片,希望各位同學能利用training dataset訓練一個CNN model,預測出每張圖片的表情label(同樣地,為0~6中的某一個)並存在csv檔中。
分析:
1.首先根据train.csv构造自己的数据集
由于每张图片的feature位于一个单元格中,所以首先要用spilt()把数字字符串数据转换成48*48大小的数值型列表,此时要注意数值类型必须为float类型
import pandas as pd
data=pd.read_csv(‘data/train.csv’)
image=data.iloc[idx,1].split()
image=list(map(float,image))
image=np.array(image).reshape(-1,48)
image有了,接下来就是存储lable了,lable是0-6的int型整数.
lable=np.array(self.data.iloc[idx,0])
所以CNN的输出层必然为7层,输入层只有1个channel.
数据准备完毕,便要继承Dataset实现自己的数据集类,使得pytorch能够自动对数据集batch,shuffle,transform等操作,不需要自己写代码完成这些功能
class ISCDataset(Dataset):
def __init__(self,csv_file,transform=None):
self.data=pd.read_csv(csv_file)
self.transform=transform
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
image=self.data.iloc[idx,1].split()
image=list(map(float,image))
image=np.array(image).reshape(-1,48)
lable=np.array(self.data.iloc[idx,0])
sample={'image':image,'lable':lable}
if self.transform:
sample = self.transform(sample)
return sample
2.构造自己的CNN网络
这一部分,仁者见仁智者见智,不同的人设计的层数,参数各有不同,只要网络结构不报错,剩下的便是调参了。值得一提的是,刚开始我的lr设的比较大,结果就是所有图片的预测结果都一样,后来print每次的预测情况才发现----执行几次batch之后,预测结果便不在是数字了,变成了nan或inf,这显然是因为预测值太大造成的,所以就要把lr设的足够小才行。另外由于分类个数(7类)比较多,刚开始正确率很低是极其正常的,让它多循环几次准确率就会不断上升。
class ConvNet(torch.nn.Module):
def __init__(self):
super(ConvNet, self).__init__()
self.conv1=torch.nn.Conv2d(1,6,3,1)
self.pooling1=torch.nn.MaxPool2d(2)
self.conv2=torch.nn.Conv2d(6,1,3,1)
self.fc1=torch.nn.Linear(21*21,100)
self.fc2=torch.nn.Linear(100,10)
self.fc3=torch.nn.Linear(10,10)
self.fc4=torch.nn.Linear(10,7)
def forward(self, x):
x=F.relu(self.conv1(x.float()))
x=self.pooling1(x)
x=F.relu(self.conv2(x))
x=x.view(-1,1*21*21)
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=F.relu(self.fc3(x))
x=self.fc4(x)
#x=F.softmax(x)
return x
另外:由于原始数据未提供测试集,所以要从训练集中选择一部分做验证集,注意这一部分不是在构造数据集时做的,而是在跑模型时,令某几个batch不再更新参数变为验证集,然后对这部分测试正确率。这样做的好处是验证集都是shuffle=True来的,也就很随机,可信度更高。
if i_batch<=6000:
prediction=net(item['image'])
loss=loss_fn(prediction,item['lable'])
optimizer.zero_grad()
loss.backward()
optimizer.step()
else:
#print(len(item['lable']))
with torch.no_grad():
num_verificationData+=len(item['lable'])
veri_prediction=net(item['image'])
veri_prediction=torch.argmax(veri_prediction,dim=1).numpy()
for j in range(len(item['lable'])):
if veri_prediction[j]==item['lable'].numpy()[j]:
num_right+=1
3.保存对test.csv的测试结果到sample.csv
通过分析两个csv文件发现,只需要按顺序(所以加载test.csv时shuffle值必须为False)把test.csv预测结果按顺序写到sample.csv中即可(即更新csv中的某个cell)
#读入test.csv
test_dataset=ISCDataset('data/test.csv',transform=transforms.Compose([ToTensor()]))
testloader=DataLoader(test_dataset,batch_size=4,shuffle=False)
#读入sample.csv
sample=pd.read_csv('data/sample.csv')
for i_batch,item in enumerate(testloader):
prediction=net(item['image'])
prediction=torch.argmax(prediction,dim=1).numpy()
for i in range(len(prediction)):
sample.iloc[item['lable'].numpy()[i],1]=prediction[i]
#sample.iloc[0,1]=10
#print(sample,type(sample))
sample.to_csv('data/sample.csv',index=False)
4.整个项目代码
可运行完整代码已放到github上,欢迎大家fork,star,watch甚至issue
https://github.com/zc-authorization/Image_Sentiment_Classification
另: 有问题大家可以在下面评论,看到都会回复