4-3日学习笔记

1.接bert的pooled_output输出

https://cloud.tencent.com/developer/article/1588634 这里面提到是不是那个encoded_layers输出,而是第二项输出,但我之前接LSTM都是直接的第一个输出,也就是每个单词的输出,难道就是只接pooled_output效果会更好吗?

但是我又觉得,如果是这样的话,那么lstm的一个参数seq_length就全部为1吗?那这样就是说time_step为1?这样真的能够学的有效吗? 

我还是不太明白,先搁置https://github.com/bentrevett/pytorch-sentiment-analysis/blob/master/6%20-%20Transformers%20for%20Sentiment%20Analysis.ipynb ,这里面给的教程明明是使用的第0个输出,把它当作了bert的emb,然后输入进GRU,所以使用encoded_layers看起来并没有什么毛病?

2.pytest包

python中可以用来测试的包?算了,以后再说,现在用不到。

3.for((i=0;i<5;i++));  

https://www.sololearn.com/Discuss/1725255/why-does-this-exist-for-int-i-0-i-5-i

This kind of loop can be use to create a delay / pause in you program...

主要就是delay的作用。

我又知道了,在shell脚本中,它是进行for循环的意思。。。

4.gradient_accumulation_steps

2020-5-2更新—————— 

https://linux.ctolib.com/guoday-CCF-BDCI-Sentiment-Analysis-Baseline.html,这里提到:

 主要就是为了解决显存小的问题,这样就会默认降低batch_size了,真实的bs=bs/gas,每gas计算一次梯度,累计到bs后更新。

args.train_batch_size = args.train_batch_size // args.gradient_accumulation_steps

这句在训练bert时的代码就可以看出来,bs进行了更新。

        num_train_optimization_steps = int(
            len(train_examples) / args.train_batch_size / args.gradient_accumulation_steps) * args.num_train_epochs

注意:有的实现的地方,num_train_optimization_steps 等号右边没有/args.train_batch_size,所以就是计算方式有所不同,还是看具体的项目中是如何实现的吧。

除或者不除bs,关乎到gas是否可以大于bs。

在simpletransformer的分类模型中,是这么来用的:

        train_dataloader = DataLoader(train_dataset, sampler=train_sampler, batch_size=args["train_batch_size"])

        t_total = len(train_dataloader) // args["gradient_accumulation_steps"] * args["num_train_epochs"]

假设len(train_examples)=128,train_batch_size=4,gradient_accumulation_steps=8,epoch=3,

那么total=128//8*3=48。而在上面的train_dataloader ,仍是以原来的bs加载的数据。

                if args["gradient_accumulation_steps"] > 1:
                    loss = loss / args["gradient_accumulation_steps"]

在train中,loss/8,其实不是很明白上面为什么要loss/gas呢???难道/了之后计算所需的内存就会变小?

每个batch都将loss/gas,

/了之后进行backward,和不/有什么区别呢?

# 每n个batch(把这些batch的梯度求和),更新一次参数 #下面的if。
...
loss.backward()
if (step + 1) % args["gradient_accumulation_steps"] == 0: torch.nn.utils.clip_grad_norm_(model.parameters(), args["max_grad_norm"]) optimizer.step() scheduler.step() model.zero_grad() ....

之后反向传播计算损失,当step进行了8次之后才更新参数。

忽然一点通,loss/gas之后就是为了后面的if时能够一次更新gas个bach的。

那还有个问题,在训练的时候主要的内存占用是反向传播在求loss,还是在更新参数的时候呢?

5.dataframe.fillna(inplace)参数

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.fillna.html 这里是说,

如果在填充时设置为True的话,那么会改变其他非copy的切片列,这个我不太明白,如果是之前的切片,那就会受到影响?那么如果是fillna之后的切片会受到影响吗?

import pandas as pd
import numpy as np
df = pd.DataFrame([[np.nan, 2, np.nan, 0],
                   [3, 4, np.nan, 1],
                   [np.nan, np.nan, np.nan, 5],
                   [np.nan, 3, np.nan, 4]],
                  columns=list('ABCD'))
df1=df.iloc[2]
df=df.fillna('缺失')
df2=df.iloc[2]
print(df1)
print(df2)

#输出:
A    NaN
B    NaN
C    NaN
D    5.0
Name: 2, dtype: float64
A    缺失
B    缺失
C    缺失
D     5
Name: 2, dtype: object

 可以发现,之前的切片是不会受到影响的,即df1,之后的切片会随之改变即df2,那么fillna时设置inplace=True,结果如下:

如果是这样:

df1=df.iloc[2]
df.fillna('缺失')#注意和上面的差别,这里没有返回
df2=df.iloc[2]
print(df1)
print(df2)

#输出:
A    NaN
B    NaN
C    NaN
D    5.0
Name: 2, dtype: float64
A    NaN
B    NaN
C    NaN
D    5.0
Name: 2, dtype: float64
>>> df
     A    B   C  D
0  NaN  2.0 NaN  0
1  3.0  4.0 NaN  1
2  NaN  NaN NaN  5
3  NaN  3.0 NaN  4

发现,如果没有inplace的话它应该要再返回一个副本,之后用这个填充后的副本完成剩下的操作,而:

df1=df.iloc[2]
df.fillna('缺失',inplace=True)
df2=df.iloc[2]
print(df1)
print(df2)

#输出:
A    NaN
B    NaN
C    NaN
D    5.0
Name: 2, dtype: float64
A    缺失
B    缺失
C    缺失
D     5
Name: 2, dtype: object
>>> df
    A   B   C  D
0  缺失   2  缺失  0
1   3   4  缺失  1
2  缺失  缺失  缺失  5
3  缺失   3  缺失  4

这样就完全不必再赋值给df,而且之前的切片并不会受影响哦,受到的只是自身和后来切片的影响。而如果想要尝试赋值:

df1=df.iloc[2]
df=df.fillna('缺失',inplace=True)
df2=df.iloc[2]
print(df1)
print(df2)
#输出:
    df2=df.iloc[2]
AttributeError: 'NoneType' object has no attribute 'iloc'

说明,=True之后的fillna是不返回内容的。

2020-4-4周六——————————————

1.action=store_true参数

这里到底是什么意思呢?

https://blog.csdn.net/LemonTree_Summer/article/details/80749359  说了一些但是还是不太明白,这是要存储这个参数吗?那存储到哪里呢?运行完程序我可以在哪里查看呢?

终于搞明白了,https://www.cnblogs.com/lovemyspring/p/3214598.html 这个讲的真不错。

例子:

import argparse

parser = argparse.ArgumentParser(description='Short sample app')

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

print parser.parse_args(['-a', '-bval', '-c', '3'])
#输出:
Namespace(a=True, b='val', c=3)

上面中,如果a出现了,那么就设置为True,没有出现则为False:

print(parser.parse_args(['-bval', '-c', '3']))
#输出:
Namespace(a=False, b='val', c=3)

如果改变a,

parser.add_argument('-a', action="store_false", default=False)
。。。
print(parser.parse_args(['-bval', '-c', '3']))
#输出:
Namespace(a=False, b='val', c=3)#还是取决于default了

如果去掉default,

parser.add_argument('-a', action="store_false")
。。。
print(parser.parse_args(['-bval', '-c', '3']))
#那么默认就为True了
Namespace(a=True, b='val', c=3)

如果改变b,

parser.add_argument('-b', action="store",dest='bdd')
。。。
print(parser.parse_args(['-bval', '-c', '3']))
#输出:
Namespace(a=True, bdd='val', c=3)

可以发现,action=store的话,如果有dest中的变量名设值为这个值,如果没有dest的话,那就将当前-变量设置为这个值。store_false/True就是设置为false还是True

store_false,出现则为False,不出现为True;store_true则出现为True,不出现为False。终于明白了,我之前还以为store是要把变量存储到文件呢。

如果不给b参数,

parser.add_argument('-b', action="store",dest='bdd')
。。。
print(parser.parse_args([ '-c', '3']))
#输出:
Namespace(a=True, bdd=None, c=3)

上面可以看出,如果没有b参数的话,就默认为None,

2.pytorch fp16

https://blog.csdn.net/britney_f/article/details/89177575讲的还蛮好的,精度降低占用的显存就会变小,但同时好像因为梯度的影响精确度就会下降?

我还是先不尝试了吧。

2020-5-2周六更新————————————

https://discuss.pytorch.org/t/training-with-half-precision/11815,这个是否有人用fp16跑过一些常用模型的问题?

其中探讨了对bn的影响,“您要确保BatchNormalization图层使用float32进行累加,否则会出现收敛问题。”

model.half()  # convert to half precision
for layer in model.modules():
  if isinstance(layer, nn.BatchNorm2d):
    layer.float()

//但是我目前并不明白为什么要bn单独设置。

感觉这个帖子里整体是可以用fp16吧。

https://www.kaggle.com/c/carvana-image-masking-challenge/discussion/37415,这个也探讨了fp16.

这里的回答说,用fp16反倒在GPU上慢了?它只是为了能够说,使数据占用的内存小从而能够拥有更大的模型。

3.os.path.join

import os
a=os.path.join('./', 'train.csv')
print(a)
print(type(a))
#输出:
./train.csv
<class 'str'>

使用了这个模块之后,就a还是str类型的,为什么不直接字符串相加呢?我还是感受不到这个join函数的魅力啊。

4.Syntax error: Bad for loop variable 运行shell文件报错

https://askubuntu.com/questions/400936/loop-variable-error-in-for-loop 果然还是谷歌了一下靠谱,在shell文件中添加#!/bin/bash即可。

5.python垃圾回收机制

https://www.cnblogs.com/franknihao/p/7326849.html 这个有两个讲的不错。

import sys
class Test():
  def __init__(self):
    pass

t = Test()
k = Test()
t._self = t
print sys.getrefcount(t)    #sys.getrefcount函数用来查看一个对象有几个引用
print sys.getrefcount(k)
####结果####
3
2

内存泄漏是说,当前内存块已经没有引用指向了,但又没有别的变量指向这个,所以python既无法清理我们也无法访问。

gc.collect()可以处理循环引用的问题,释放内存。
import sys
import gc

a = [1]
b = [2]
a.append(b)
b.append(a)
####此时a和b之间存在循环引用####
print(sys.getrefcount(a))    #结果应该是3
print(sys.getrefcount(b))    #结果应该是3
del a
del b
####删除了变量名a,b到对象的引用,此时引用计数应该减为1,即只剩下互相引用了####
try:
    sys.getrefcount(a)
except NameError:
     print ('a is invalid')
####此时,原来a指向的那个对象引用不为0,python不会自动回收它的内存空间####
####但是我们又没办法通过变量名a来引用它了,这就导致了内存泄露####
unreachable_count = gc.collect()
####gc.collect()专门用来处理这些循环引用,返回处理这些循环引用一共释放掉的对象个数。这里返回是2####

#但是我跑了之后输出:
3
3
a is invalid
>>> unreachable_count
12
#居然是12哎,这么多吗?

https://www.cnblogs.com/kaituorensheng/p/4449457.html

在Python中,为了解决内存泄露问题,采用了对象引用计数,并基于引用计数实现自动垃圾回

6./bin/bash^M: 解释器错误: 没有那个文件或目录

刚跑那个文件,一样的shebang,#!/bin/bash

OMG,https://blog.csdn.net/u011479200/article/details/79384930 从这里面找到了原因,是因为我是在win下写的shell文件,然后上传到服务器端,会产生换行符的问题,然后用

cat -A run_combine.sh命令,查看,包括显示换行符,结果如下:

而查看之前可以正常运行的文件显示如下: 

 可以发现是换行符存在问题,都多了个^M,这是什么鬼。解决:https://blog.csdn.net/netwalk/article/details/14135307

sed -i 's/
$//' run_combine.sh

即可,会对换行符进行处理。修改之后:

原文地址:https://www.cnblogs.com/BlueBlueSea/p/12629830.html