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
即可,会对换行符进行处理。修改之后: