Python

类的继承问题

CSDN: python中super().init()

关键字:assert、raise、yield

CSDN: python中assert的用法(简洁明了)
8. 错误和异常¶

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
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
| +-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning

C语言中文网: Python raise用法(超级详细,看了无师自通)
python中yield的用法详解——最简单,最清晰的解释

关于copy

CSDN: python中的copy.copy和copy.deepcopy
CSDN: 系统学习Python——字典(dict):copy()函数

关于train和eval

CSDN: 【Pytorch】model.train() 和 model.eval() 原理与用法
CSDN: python之*的用法

关于detach和detach_方法

详解.detach()、 .data和.detach_()
pytorch:.detach()、.detach_()的作用和区别
Pytorch中inplace操作
pytorch中的ReLU与inplace原地操作的一些注意点
detach复制一个原变量,但是requires_grad = False,因此对新变量的backward操作会报错。此后如果新变量不改变,则原变量的梯度仍为True,相关的梯度相关操作仍正常进行。新变量一旦改变,原变量由于内存共享,值发生改变,梯度False。这里新变量的改变,需得是那种in-place级别的改变。
这种控制是通过auto_grad控制的,因此如果detach的是原变量.data,即使新变量改变了,原变量仍可以做相关求导操作,只不过返回的梯度值是错误的。
detach_就是in-place升级版,直接把原变量的梯度也给设置成False了。

交叉熵误差

二分类交叉熵,多分类交叉熵,focal loss
假设网络输出为out,真实标签为y,预测标签为y_hat.
(1)对于二分类问题,计算公式为loss=ylog(y^)(1y)log(1y^)loss = -y*log(\hat{y})-(1-y)*log(1-\hat{y})
out,y,y_hat的形状均一致,可谓任意形状张量

1
2
3
4
criterion1 =   nn.BCEWithLogitsLoss() 
criterion2 = nn.BCEWithLoss()
loss1 = criterion1(out ,y) #[out]---sigmoid/softmax--->[y_hat]---y--->loss
loss2 = criterion2(y_hat,y) #[y_hat]---y--->loss

(2)对于多分类交叉熵,计算公式为loss=1ni=1nj=1kyijlog(y^ij)loss = -\frac{1}{n}\sum_{i=1}^{n}\sum_{j=1}^{k}y_{ij}*log(\hat{y}_{ij}),class表示分类的个数,n表示序列长度

1
2
criterion = nn.CrossEntropyLoss()
criterion(out,y) #tensor(2.0968)

①out,y,y_hat的形状分别为(batch,class),(batch),(batch,class)
内部运算时,会将out–softmax–exp–>y_hat,将y–>y.long(),根据y给出的位置信息,在y_hat中找到对应位置的元素,把batch个相加之后求平均。

②out,y,y_hat的形状分别为(batch,class,n),(batch,n),(batch,class,n)
内部运算时,会将out–softmax–exp–>y_hat,将y–>y.long(),根据y给出的位置信息,在y_hat中找到对应位置的元素,把batch个相加之后求平均。注意softmax是在class维度进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
out = [[[0.4100, 0.2784, 0.8864, 0.2563, 0.6145, 0.1003, 0.2250],
[0.8236, 0.3911, 0.7626, 0.4091, 0.5717, 0.1733, 0.7634],
[0.6580, 0.9722, 0.0596, 0.5479, 0.9591, 0.5731, 0.7304]],
[[7.4100, 0.2784, 0.8864, 0.2563, 2.6145, 0.1003, 0.2250],
[0.8236, 2.3911, 0.7626, 0.4091, 0.5717, 4.1733, 0.7634],
[0.6580, 0.9722, 0.0596, 6.5479, 0.9591, 0.5731, 2.7304]]]
y = [[0.4966,2.4566,0.1086, 1.6627,0.3579,2.6607,0.3494],
[1.4966,0.4566,0.1086, 1.6627,1.3579,0.6607,1.3494]]

out = torch.Tensor(out)
y = torch.Tensor(y).long()

#方法1
criterion = nn.CrossEntropyLoss()
print(criterion(out,y)) #tensor(2.2942)

# 方法2
y_hat = out.log_softmax(dim=1)
sum = 0
for batch in range(y.shape[0]):
for i in range(y.shape[1]):
sum = sum -y_hat[batch, y[batch,i] ,i]

sum/len(y.flatten()) #tensor(2.2942)

③对于out,y,y_hat的形状分别为(batch,class,rows,cols),(batch,rows,cols),(batch,class,rows,cols),思路上和②同理。

训练rnn的心得

训练rnn时一定要注意各个变量的形状和组织结构,下面给出一段代码做具体注释。

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
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l

class RNNModel(nn.Module):
def __init__(self,rnn_net,vocab_size) :
super(RNNModel,self).__init__()
self.net = rnn_net
self.vocab_size = vocab_size
self.linear = nn.Linear(self.net.hidden_size,self.vocab_size)

def forward(self,inputs,state):
X = F.one_hot(inputs.T,self.vocab_size)
X = X.to(torch.float32)
Y, state_new = self.net(X, state)
# print(X.shape,Y.shape)
outputs = self.linear(Y.reshape((-1,self.net.hidden_size)))
return outputs, state_new

def begin_state(self,batch_size):
return torch.zeros(1,batch_size,self.net.hidden_size)

def predict_clancy(prefix,num_steps,net,vocab):
state = rnn.begin_state(batch_size=1)
for c in prefix[:-1]:
_, state = net(torch.tensor(vocab.token_to_idx[c]).reshape((1,1)),state)
# print(state.mean())

for _ in range(num_steps):
c, state = rnn(torch.tensor(vocab.token_to_idx[prefix[-1]]).reshape((1,1)) ,state)
prefix = prefix + vocab.idx_to_token[torch.argmax(c,dim=1)]
return prefix

def grad_clipping(net, theta): #@save
"""裁剪梯度"""
if isinstance(net, nn.Module):
params = [p for p in net.parameters() if p.requires_grad]
else:
params = net.params
norm = torch.tensor([torch.sum((p.grad ** 2)) for p in params])
norm = torch.sqrt(torch.sum(norm))
if norm > theta:
for param in params:
param.grad[:] *= theta / norm

batch_size = 16
num_steps = 35
num_epochs = 500
lr = 1
train_iter, vocab = d2l.load_data_time_machine(batch_size,num_steps)
rnn = RNNModel(nn.RNN(input_size = len(vocab),hidden_size = 256,nonlinearity='tanh'),len(vocab))
state = rnn.begin_state(batch_size)
loss = nn.CrossEntropyLoss()
updater = torch.optim.SGD(rnn.parameters(),lr)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(updater, T_max=num_epochs)

ppl = []
for epoch in range(num_epochs):
ppl_epoch = [0,0]
for X, Y in train_iter:
state.detach_()
updater.zero_grad()
Y_new, state = rnn(X, state)
l = loss(Y_new.reshape(num_steps,batch_size,-1).permute(0,2,1),Y.T.long())
# l = loss(Y_new, Y.T.flatten().long()).mean()
l.backward()
grad_clipping(rnn, 1)
updater.step()
scheduler.step()

ppl_epoch[0] += l * Y.numel()
ppl_epoch[1] += Y.numel()

if (epoch)%20==0:
print(epoch,l)

ppl.append(math.exp(ppl_epoch[0] / ppl_epoch[1]))

predict_clancy('time machine ',60 , rnn, vocab)
from matplotlib import pyplot as plt
plt.plot(range(num_epochs),ppl)

从文本读入后,在for X, Y in train_iter中,X:(batch,steps),Y:(batch,steps)
X进入rnn的forward后,会先转置再做one_hot,形状变为X:(steps,batch,len(vocab))
在nn.RNN中,会以steps为循环一步一步地预测,因此Y_hat是由一个个(batch,len(vocab))拼接起来的,最终形状为(steps*batch,len(vocab))
如若想计算交叉熵,有两种方式:

  1. 把Y转置后再拉平,变为(steps*batch),转为long型后再和Y_hat一起进入nn.CrossEntropy,即loss(Y_new, Y.T.flatten().long()).mean()
  2. 把Y_hat换为三维后变为(steps,batch,len(vocab)),再换轴变为(steps,len(vocab),batch),再和转置转整型后的Y一起进入nn.CrossEntropy,即loss(Y_new.reshape(num_steps,batch_size,-1).permute(0,2,1),Y.T.long())。

此段请务必配合上一节一同理解,很重要。分类的类数目class一定要放中间。

numel()函数

pytorch中的numel函数用法说明

注意力机制的理解

用数学语言描述,假设有一个查询
qRq\mathbf{q} \in \mathbb{R}^qmm个“键-值”对
(k1,v1),,(km,vm)(\mathbf{k}_1, \mathbf{v}_1), \ldots, (\mathbf{k}_m, \mathbf{v}_m)
其中kiRk\mathbf{k}_i \in \mathbb{R}^kviRv\mathbf{v}_i \in \mathbb{R}^v
注意力汇聚函数ff就被表示成值的加权和:

f(q,(k1,v1),,(km,vm))=i=1mα(q,ki)viRv,f(\mathbf{q}, (\mathbf{k}_1, \mathbf{v}_1), \ldots, (\mathbf{k}_m, \mathbf{v}_m)) = \sum_{i=1}^m \alpha(\mathbf{q}, \mathbf{k}_i) \mathbf{v}_i \in \mathbb{R}^v,

其中查询q\mathbf{q}和键ki\mathbf{k}_i的注意力权重(标量)是通过注意力评分函数aa 将两个向量映射成标量,再经过softmax运算得到的:

α(q,ki)=softmax(a(q,ki))=exp(a(q,ki))j=1mexp(a(q,kj))R.\alpha(\mathbf{q}, \mathbf{k}_i) = \mathrm{softmax}(a(\mathbf{q}, \mathbf{k}_i)) = \frac{\exp(a(\mathbf{q}, \mathbf{k}_i))}{\sum_{j=1}^m \exp(a(\mathbf{q}, \mathbf{k}_j))} \in \mathbb{R}.

综上,本来的损失函数是q和y直接求,现在变成了y_hat(q,y)和y求,那么理论上说模型的输出在无形中加入了和标签直接相关的信息,也就是注意力机制。

html

学习资料

本人跟学的bilibili的加百利先生的视频:
https://www.bilibili.com/video/BV1kb411n7NJ?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click
我已经学完了,将我自己编的文件发布在了github中:
https://github.com/ClancyCC/html-css-js

Q1:关于目录的读取

./是当前目录
…/是父级目录
/是根目录
根目录指逻辑驱动器的最上一级目录,它是相对子目录来说的。打开“我的电脑”,双击C盘就进入C盘的根目录,双击D盘就进入D盘的根目录。其它类推。根目录在文件系统建立时即已被创建,其目的就是存储子目录(也称为文件夹)或文件的目录项。
但有时调用我发现./和/的应用是不太一样的。有时候不一定哪个是对的。

Q2:关于img前后伪元素伪类的特殊情况

网络解释:

个人发现:

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
<style>
*{
margin: 0;
padding: 0;
}
.box{
background-repeat: no-repeat;
width: 250px;
height: 250px;
overflow: hidden;
margin: 5px;
float: left;
position: relative;
}
.box > *{
position: absolute;
}
.box img{
transform: translateX(0) translateY(0);
}
.box img::after{
content: "hjhghjg";
left: 0px;
top: 0px;
position: absolute;
background: transparent;
height: 250px; width: 250px;
}
.box:hover img::after{
background: rgb(255, 255, 255,0.3);
}
</style>

<div class="box">
<img src="xxxx.png" alt="">
<img src="" alt=""> <!--关键行-->
</div>

<!--对于上文中的内容在此做描述:div容器中显示一张图片,当鼠标滑动至div容器时,会出现以蹭白色的遮罩-->
<!--当时当没有关键行时,效果不显示-->
<!--检查网页时发现,效果出现时,第一张img后的伪元素几乎不存在,第二张的才存在。似乎只要img链接了正确的图片,伪元素就不能正常工作-->

Q3:需要理解伪元素中的content属性有什么特殊意义

暂未解决

Q4:关于在VS code中注释代码语句

1
2
3
注释语句:ctrl+/或者ctrl+K+ctrl+C
取消注释:ctrl+/或者ctrl+K+ctrl+U
块注释,多行注释:选中代码+alt+shift+A

linux

1
2
# username为当前用户名,该命令杀死当前用户下的所有进程
pkill -u username

CSDN:
CSDN:
CSDN: