第四次作业:猫狗大战挑战赛

Part1

首先下载了老师给的数据集,完成数据下载之后,需要对数据进行一些预处理:

图片将被整理成 224 × 224 × 3 224\times 224 \times 3224×224×3 的大小,同时还将进行归一化处理。
其他的一些对数据的复杂的预处理/变换 (normalization, cropping, flipping, jittering 等)可以参照 torchvision.tranforms 的官方文档说明。同时将数据拆分为训练集和测试集,将部分图片打印出来可视化以方便测试。

VGG模型提出了迁移学习,所以我们只需要更改最后两层即可,设置梯度下降为FALSE,我们只需要训练测试全连接层即可。

屏幕截图 2021-10-20 190935

屏幕截图 2021-10-20 190954

之后测试为如上图所示的结果。

part2

猫狗大战比赛:

有了老师提供的代码,在其基础上做了一些更改。

首先下载数据集,unrar解压文件。注意到解压后的文件中,val和train中都没有分类出前缀为cat和dog的图片,于是我们要运行脚本将其分离。

运行完以后,如图

QQ图片20211021131113

接下来是我对于代码的改动部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import numpy as np
import matplotlib.pyplot as plt
import os
import torch
import torch.nn as nn
import torchvision
from torchvision import models,transforms,datasets
import time
import json
# 判断是否存在GPU设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print('Using gpu: %s ' % torch.cuda.is_available())
#处理数据
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
vgg_format = transforms.Compose([
transforms.CenterCrop(224),
transforms.ToTensor(),
normalize,
])

data_dir = "/content/cat_dog"

dsets = {x: datasets.ImageFolder(os.path.join(data_dir, x), vgg_format)
for x in ['train', 'val']}

dset_sizes = {x: len(dsets[x]) for x in ['train', 'val']}
dset_classes = dsets['train'].classes

#修改batch_size
loader_train = torch.utils.data.DataLoader(dsets['train'], batch_size=128, shuffle=True, num_workers=6)
loader_valid = torch.utils.data.DataLoader(dsets['val'], batch_size=5, shuffle=False, num_workers=6)
#加载vgg16模型
!wget https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json
#使用vgg16需要
model_vgg = models.vgg16(pretrained=True)

print(model_vgg)

model_vgg_new = model_vgg;

#冻结VGG16中的参数,不进行梯度下降
for param in model_vgg_new.parameters():
param.requires_grad = False
#修改模型后两层
model_vgg_new.classifier._modules['6'] = nn.Linear(4096, 2)
model_vgg_new.classifier._modules['7'] = torch.nn.LogSoftmax(dim = 1)
model_vgg_new = model_vgg_new.to(device)

print(model_vgg_new.classifier)

'''
第一步:创建损失函数和优化器

损失函数 NLLLoss() 的 输入 是一个对数概率向量和一个目标标签.
它不会为我们计算对数概率,适合最后一层是log_softmax()的网络.
'''
criterion = nn.NLLLoss()

# 学习率
lr = 0.001

#修改为Adam优化器
optimizer_vgg = torch.optim.Adam(model_vgg_new.classifier[6].parameters(), lr=lr)

'''
第二步:训练模型
'''

def train_model(model,dataloader,size,epochs=1,optimizer=None):
model.train()
max_acc = 0
for epoch in range(epochs):
running_loss = 0.0
running_corrects = 0
count = 0
for inputs,classes in dataloader:
inputs = inputs.to(device)
classes = classes.to(device)
outputs = model(inputs)
loss = criterion(outputs,classes)
optimizer = optimizer
optimizer.zero_grad()
loss.backward()
optimizer.step()
_,preds = torch.max(outputs.data,1)
# statistics
running_loss += loss.data.item()
running_corrects += torch.sum(preds == classes.data)
count += len(inputs)
#print('Training: No. ', count, ' process ... total: ', size)
epoch_loss = running_loss / size
epoch_acc = running_corrects.data.item() / size

print('epoch: {:} Loss: {:.4f} Acc: {:.4f}\n'.format(epoch,epoch_loss, epoch_acc))
if epoch_acc > max_acc:
max_acc = epoch_acc
path = './sample_data' + str(epoch+1) + '' + str(epoch_acc) + '' + '.pth'
torch.save(model, path)
print("save: ", path,"\n")

# 模型训练,修改训练次数10次
train_model(model_vgg_new, loader_train, size=dset_sizes['train'], epochs=10,
optimizer=optimizer_vgg)

# 第三步:测试模型
def test_model(model,dataloader,size):
model.eval()
predictions = np.zeros(size)
all_classes = np.zeros(size)
all_proba = np.zeros((size,2))
i = 0
running_loss = 0.0
running_corrects = 0
for inputs,classes in dataloader:
inputs = inputs.to(device)
classes = classes.to(device)
outputs = model(inputs)
loss = criterion(outputs,classes)
_,preds = torch.max(outputs.data,1)
# statistics
running_loss += loss.data.item()
running_corrects += torch.sum(preds == classes.data)
predictions[i:i+len(classes)] = preds.to('cpu').numpy()
all_classes[i:i+len(classes)] = classes.to('cpu').numpy()
all_proba[i:i+len(classes),:] = outputs.data.to('cpu').numpy()
i += len(classes)
print('Testing: No. ', i, ' process ... total: ', size)
epoch_loss = running_loss / size
epoch_acc = running_corrects.data.item() / size
print('Loss: {:.4f} Acc: {:.4f}'.format(
epoch_loss, epoch_acc))
return predictions, all_proba, all_classes

# 模型测试
predictions, all_proba, all_classes = test_model(model_vgg_new,loader_valid,size=dset_sizes['val'])

总结起来有以下几点:

1.修改batch_size为128

2.使用Adam优化

3.增加训练次数,保存训练模型以选择最优模型。

QQ图片20211021135318

QQ图片20211021135246

然后选取最佳的模型10号(盲猜训练次数越多正确率越高,且随次数呈正相关)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import torch
import numpy as np
from torchvision import transforms,datasets
from tqdm import tqdm
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
vgg_format = transforms.Compose([
transforms.CenterCrop(224),
transforms.ToTensor(),
normalize,
])

dsets_mine = datasets.ImageFolder(r"/content/cat_dog", vgg_format)
loader_test = torch.utils.data.DataLoader(dsets_mine, batch_size=1, shuffle=False, num_workers=0)
model_vgg_new = torch.load(r'/content/sample_data100.98115.pth')
model_vgg_new = model_vgg_new.to(device)
dic = {}
def test(model,dataloader,size):
model.eval()
predictions = np.zeros(size)
cnt = 0
for inputs,_ in tqdm(dataloader):
inputs = inputs.to(device)
outputs = model(inputs)
_,preds = torch.max(outputs.data,1)
#这里是切割路径,因为dset中的数据不是按1-2000顺序排列的
key = dsets_mine.imgs[cnt][0].split("\\")[-1].split('.')[0]
dic[key] = preds[0]
cnt = cnt +1
test(model_vgg_new,loader_test,size=2000)
with open("result.csv",'a+') as f:
for key in range(2000):
f.write("{},{}\n".format(key,dic["/content/cat_dog/test/"+str(key)]))

这里一开始遇到了一些问题:

1.colab排序是按首位最优先排序,不按位数,所以容易错位 造成1 10 100 1000 2这种错误。

2.关于如何输出csv查阅了相关资料。

得到csv文件后,提交QQ图片20211021153118

98,挺整齐的还可以,跟10号的98.11差不多,可以接受。

小结:1.适当扩充训练集。

​ 2.更换更合适的优化器

​ 3.更改batch_size

​ 4.迁移学习富有魅力

第3次作业:卷积神经网络

第3次作业:卷积神经网络

part1

1

首先是介绍了提纲,了解了视频基本内容

2

随后是对深度学习的步骤进行了概括性的说明

3

这里介绍了损失函数的定义以及常用的公式,主要用于衡量吻合度(偏差)

4

这里介绍了为什么全连接网络处理在图像处理准确度不高的原因:参数过多,考虑的因素太多导致过拟合(即抓不住主要的内容,被细枝末节的信息干扰)。而卷积神经网络将图像分割成块状(局部关联)且进行了参数共享,降低了复杂度与信息熵,抓住了主要的内容,提高了准确度。

image-20211013134707088

而后了解到了卷积的定义以及卷积的计算方式。

image-20211013134837806

即对应位置相乘再相加为一格 通过平移形成了特征图(走到右下角)

image-20211013135004982

验证。

所谓步长就是指平移的单位格个数。

image-20211013135157107

image-20211013135222096

image-20211013135538947

关于这个计算我有一个问题:输出在前面所讲为输出时的概率 而这里却是一个具体的数。

image-20211013135816991

处理深度学习,如果不好看每一层学习的内容可以将其可视化查看。

image-20211013135903111

指在尽量少量损失信息的同时对图片进行缩放。优点如图所示

image-20211013140005171

最大和平均。

image-20211013140436460

简介了历史

image-20211013140616905

image-20211013140927123

卷积-ReLU-池化 介绍了data和参数的计算(卷积)池化只是缩放不存在参数计算。

image-20211013141148627

这个只是调整了一下参数。

image-20211013141427937

VGG 增加了一些层数,同时数据量也是ALEX的2倍左右,提出了迁移学习这一说法即利用别人现有的参数跑自己的任务。

image-20211013141544940

这个模型改变很大,且没有全连接,所以数据量小。

image-20211013141846889

image-20211013141933399

逐渐升级。用卷积核降低参数量,降低卷积核的大小。

image-20211013142043032

带升级。时至今日也经常使用。

同样也是减少了FC

image-20211013142155586

这里去除掉重复的主体部分,突出微小的变化(异或)

开始经典实战:

image-20211013142501104

介绍了各种各样参数的意义。

part2

1.Convnet

6

在能利用局部联系时,卷积远超全连接。7

但可惜,被打乱顺序后,没有局域联系,卷积的优势荡然无存。

9

CNN处理下 准确率只有61。。

盲猜一手更换成ResNet准确率应该有不小的提升。。

10

这里一开始没有用GPU训练,导致第一个就卡住了。

简单的VGG训练就可以达到83%,试想换成ResNet加上Attention机制不知道会如何。。

本期作业到这里 我们下周再见~

第一次作业:深度学习基础

视频学习心得:

有图有真相

pic(1)

pic(4)

pic(5)

pic(17)

pic(10)

这个激活函数非常有意思 和ReLu函数相关性大。

当然 深度学习也有‘不能’的地方

pic(12)

pic(8)

pic(2)pic(6)

pic(7)

pic(18)

pic(16)

pic(19)

总结如下

1.深度学习依靠强大的算力。

2.神经网络是一种强大的学习算法,它的灵感来自于大脑的工作方式。

v2-f9a337697798efeac4d96a7cc845c7bf_1440w

这是多元神经网络。本质上来说就是输入通过神经网络算法的映射从而尽量的靠近甚至命中最终的正确结果。

代码练习

part1

这部分主要通过复制粘贴对应的python代码并进行运行即可。

pic(3)

pic(13)

这个有个有意思的点 10**9会超时,错误原因是Overflow. 看来基础的东西还是不能丢啊。

pic(11)

老师皮了一下

part2

pic(14)

这是线性模型分类 可以看出其准确率不高,对于这样的数据分布是难以进行准确分类的。

4554d4ee0a067c707c9fec6bdf42ce6

而这个是通过ReLU函数作为激活函数 分类的准确率确实得到了极大的提高。

小结

1.激活函数是用来加入非线性因素的,因为线性模型的表达力不够,比如上面两幅图的对比。

2.ReLU函数就是斜坡函数。
$$
f(x)=max(0,x),
$$
从表达式和可以明显地看出:ReLU其实就是个取最大值的函数。
ReLU函数其实是分段线性函数,把所有的负值都变为0,而正值不变,这种操作被成为单侧抑制。(也就是说:在输入是负值的情况下,它会输出0,那么神经元就不会被激活。这意味着同一时间只有部分神经元会被激活,从而使得网络很稀疏,进而对计算来说是非常有效率的。)正因为有了这单侧抑制,才使得神经网络中的神经元也具有了稀疏激活性。尤其体现在深度神经网络模型(如CNN)中,当模型增加N层之后,理论上ReLU神经元的激活率将降低2的N次方倍。

ReLU模型的优势如下:

1.没有饱和区,不存在梯度消失问题。
2.没有复杂的指数运算,计算简单、效率提高。
3.实际收敛速度较快,比 Sigmoid/tanh 快很多。
4.比 Sigmoid 更符合生物学神经激活机制。

参考博客:(https://blog.csdn.net/u013146742/article/details/51986575)

​ (https://www.cnblogs.com/tianqizhi/p/9570975.html)

​ (https://blog.csdn.net/tyhj_sf/article/details/79932893)

​ (https://www.jianshu.com/p/338afb1389c9)

ya的前半生

一切都可以被解构 可是然后呢?

在马基的最后一节课,老师让我们写《生活的意义》为题的小作文儿。这题目是很有趣的,导向性也极为明显,肯定要结合马克思主义来谈(毕竟是马基课)。作为一个马基课总共只去了三次的三好学生,自然是不明白也不了解马克思主义的内容与含义,只是在小作文儿末尾匆匆加上马克思主义,并且空洞的表示要热爱祖国,为祖国的事业添砖加瓦。可我当时没意识到,这个小作文本身就是个伏笔。

回到正题,ya的前半生是怎么样的呢?ya的总结是:做题,混日子,网抑云。先说做题吧

做题

做题这方面我并没有什么天赋。在高强度重复训练中,我发觉我很难做到其他人那样愈发炉火纯青,反而会因为训练的过多,导致水平会有些许下滑,这在应试教育里面自然是不占优势的。那既然ya的脑子⑧支持刷题套路,为啥ya还能有个学可以上呢?经过ya的探索,发觉有以下几点:

1.假学的人太多了。好比定义定理理论,学习之后自然要通过事物或逻辑去反复的验证,去反复的推敲。见过不少人,只是单单记忆下了文字载体,而对其中的内容压根不进行思索与考量,随着定理理论量的扩大,而人脑容量尚且一定,不少人越来越差,还不明白自己那么 ‘ 努力 ’却不进反退。

2.ya接受的不是最顶尖的教育,ya从小到大周围的菜逼浓度比较高,显得我好像还可以。

3.创造力要求不高,而ya创造力从小学编故事就看得出属实⑧行。ya唯一优势可能在于联想力还⑧错,而考试这玩意儿最考验的也是联想力(题目原型的变种)。

混日子&网抑云

混日子是很舒服的,摸鱼也是很自在的。非DDL不慌,以选择的路太多劝退自己朝着某个方向努力。啥都懂点儿,啥都不精通。这肯定不行,但也有一点好处,那就是我是一个有常识的人。

网抑云对人有害但上瘾,跟酒精一样。但这玩意儿在白天不好使,白天很难有所波澜,唯独容易夜深人静躺在床上尤其微醺或醉酒状态进行网抑云。网抑云就网抑云吧,别喝完酒乱给人家小姑娘发消息就成,不然第二天早上起来恨不得remake。

总之得找点事儿做

别纠缠于虚妄的概念,去做点事吧。

生活的意义是啥?这类问题有意义吗,肯定有,但是目前ya也没说服自己。虚无主义,解构主义能将建构起来的一切意义给摧毁的一干二净。这楼一盖就垮,那就换个地儿呗。我对线对不赢你,我就多支援多参团,总不能啥都你赢。想不通那就干脆别想,投身现实中,做点儿事情,不管是喜欢的还是不喜欢的,多关注具体的事物,别让内心的能量消耗在纠缠的概念之中。纠缠这些没意思而且基本无用,属于原地踏步那种。

未完待续。

韦达跳跃

韦达跳跃

起因是b哥深夜突然甩了个数学题给我。

求这个玩意儿 x,y的整数解形式。👴一看,这不就重要不等式吗,答案很显然。

后来发觉我看反了。

总而言之就是求 (x^2+y^2)/(x*y+1)为整数时 x和y的形式是什么

首先按照常规 x^2+y^2=k(1+x*y) 当然这个k⑧是0 肯定得是正整数。

然后👴就走上了错误的道路 尝试通过k的值找规律 然而肯定是不行的 因为这个题k很必要 我搁着充分的整显然很NT

思考无果 去寻求b哥正解是啥 聊天记录如下:

2

韦达跳跃 我一看名字就想起了韦达定理 不知道这俩有啥关系 去百度搜搜看

好家伙 不仅是IMO的题 还是最难的那道 b哥就是b哥 太抬举我了。

于是去看看解答如何:

3

首先假设k为非平方数。4

解答果然用了韦达定理,意思是将a作为未知数,b作为常量,通过韦达定理把a1 a2两个解 用a1单独表示出来即可。

5

6

由式子1可知 a2必然为整数 因为kb a1均为正整数

由式子2可知a2必然不为0 因为我们假设k不为平方数 且a1!=0 故b1^2-k必然不为0

有意思的就在这里,根据

7

我们得知 a1必然小于等于a2

但是根据式子2 我们得知 b1<a1 所以 (b1^2-k)/a1 必然小于a1

8

这就产生了矛盾 因为你假设的情况是 a1+b1为最小和 但是出现了a2+b1<a1+b1的情况 于是这种就不成立了

根据反证法可得 k在正整数的前提下 不是非平方数 那就是平方数 于是该题得证

啥也别说了 没有b哥就没有今天这个博客 为了庆祝👴博客没有胎死腹中 👴写下了文末的感谢词 决定开学请b哥好好的喝一场。