def dec1(func):
print("1111")
def one():
print("2222")
func()
print("3333")
return one
def dec2(func):
print("aaaa")
#装饰器的内容,返回的函数名需要相同
def two():
print("bbbb")
func()
print("cccc")
return two
#自下而上的装载,自上而下的执行
@dec1 #dec1(two), func指向two, 返回one,此时相当于test = dec1(two)
@dec2 #dec2(test),将func指向test,并返回装饰函数two
def test():
print("test test")
test() #调用one()
#输出
aaaa
1111
2222
bbbb
test test
cccc
3333
深入理解 reshape(), view(), transpose(), permute() 函数
unsqueeze :在指定位置添加维度
repeat :指定维度复制
返回从单独的正态分布中提取的随机数张量,这些正态分布的平均值和标准差是给定的。张量的size是给定的
使用pytorch时,并不是所有的操作都需要进行计算图的生成(计算过程的构建,以便梯度反向传播等操作)。而对于tensor的计算操作,默认是要进行计算图的构建的,在这种情况下,可以使用 with torch.no_grad():,强制之后的内容不进行计算图构建。
>>> def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
>>> for i in mygenerator:
... print(i)
当你调用这个函数的时候,你写在这个函数中的代码并没有真正的运行。这个函数仅仅只是返回一个生成器对象。
当你的for第一次调用函数的时候,它生成一个生成器,并且在你的函数中运行该循环,知道它生成第一个值。然后每次调用都会运行循环并且返回下一个值,直到没有值返回为止。
判断一个函数是否是一个已知的类型
isinstance(object,classinfo)
object : 实例对象。
classinfo : 可以是直接或者间接类名、基本类型或者由它们组成的元组。
返回值:如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False
THOP 是 PyTorch 非常实用的一个第三方库,可以统计模型的 FLOPs 和参数量
FLOPS:注意全大写,是floating point operations per second的缩写,意指每秒浮点运算次数,理解为计算速度。是一个衡量硬件性能的指标。
FLOPs:注意s小写,是floating point operations的缩写(s表复数),意指浮点运算数,理解为计算量。可以用来衡量算法/模型的复杂度。
from thop import clever_format
from thop import profile
class YourModule(nn.Module):
# your definition
def count_your_model(model, x, y):
# your rule here
input = torch.randn(1, 3, 224, 224)
flops, params = profile(model, inputs=(input, ),
custom_ops={YourModule: count_your_model})
flops, params = clever_format([flops, params], "%.3f")
import argparse
def main():
parser = argparse.ArgumentParser(description="Demo of argparse")
parser.add_argument('-n','--name', default=' Li ')
parser.add_argument('-y','--year', default='20')
args = parser.parse_args()
print(args)
name = args.name
year = args.year
print('Hello {} {}'.format(name,year))
if __name__ == '__main__':
main()
在上面的代码中,我们先导入了argparse这个包,然后包中的ArgumentParser类生成一个parser对象(好多博客中把这个叫做参数解析器),其中的description描述这个参数解析器是干什么的,当我们在命令行显示帮助信息的时候会看到description描述的信息。
接着我们通过对象的add_argument函数来增加参数。这里我们增加了两个参数name和year,其中'-n','--name'表示同一个参数,default参数表示我们在运行命令时若没有提供参数,程序会将此值当做参数值。
最后采用对象的parse_args获取解析的参数,由上图可以看到,Namespace中有两个属性(也叫成员)这里要注意个问题,当'-'和'--'同时出现的时候,系统默认后者为参数名,前者不是,但是在命令行输入的时候没有这个区分接下来就是打印参数信息了。
其他参数:
ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
name or flags - 选项字符串的名字或者列表,例如 foo 或者 -f, --foo。
action - 命令行遇到参数时的动作,默认值是 store。
store_const,表示赋值为const;
append,将遇到的值存储成列表,也就是如果参数重复则会保存多个值;
append_const,将参数规范中定义的一个值保存到一个列表;
count,存储遇到的次数;此外,也可以继承 argparse.Action 自定义参数解析;
nargs - 应该读取的命令行参数个数,可以是具体的数字,或者是?号,当不指定值时对于 Positional argument 使用 default,对于 Optional argument 使用 const;或者是 * 号,表示 0 或多个参数;或者是 + 号表示 1 或多个参数。
const - action 和 nargs 所需要的常量值。
default - 不指定参数时的默认值。
type - 命令行参数应该被转换成的类型。
choices - 参数可允许的值的一个容器。
required - 可选参数是否可以省略 (仅针对可选参数)。
help - 参数的帮助信息,当指定为 argparse.SUPPRESS 时表示不显示该参数的帮助信息.
metavar - 在 usage 说明中的参数名称,对于必选参数默认就是参数名称,对于可选参数默认是全大写的参数名称.
dest - 解析后的参数名称,默认情况下,对于可选参数选取最长的名称,中划线转换为下划线.
在训练时统计loss变化时,会用到loss.item(),能够防止tensor无线叠加导致的显存爆炸
loss.item()应该是一个batch size的平均损失,×images.size(0)那就是一个batch size的总损失,所以train_loss很可能是求一个epoch的loss之和。
[input]:import torchvision.models as models
[input]:models.__dict__
[output]:
{
'__name__': 'torchvision.models',
'__doc__': None,
'__package__': 'torchvision.models',
...
...
...
'DenseNet': torchvision.models.densenet.DenseNet,
'densenet121': ,
'densenet169': ,
'densenet201': ,
'densenet161':
}
可以用这种方法来访问对象的属性:
[input]:densenet = models.__dict__['DenseNet']
[input]:densenet
[output]: torchvision.models.densenet.DenseNet
c='abcghidefjkl'
new_c = list(c)
new_c.sort()
print('1.把new_c列表里面的元素按字母排序后:',new_c)
cc =''.join(new_c)
print('2.通过空分隔符把new_c列表里面元素进行分隔,赋值给到cc:',cc)
cc =','.join(new_c)
print('3.通过,分隔符把new_c列表里面元素进行分隔,赋值给到cc:',cc)
1.把new_c列表里面的元素按字母排序后: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l']
2.通过空分隔符把new_c列表里面元素进行分隔,赋值给到cc: abcdefghijkl
3.通过,分隔符把new_c列表里面元素进行分隔,赋值给到cc: a,b,c,d,e,f,g,h,i,j,k,l
我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。
—–而浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。这就和我们寻常意义上的复制有所不同了。
>>> import copy
>>> origin = [1, 2, [3, 4]]
#origin 里边有三个元素:1, 2,[3, 4]
>>> cop1 = copy.copy(origin)
>>> cop2 = copy.deepcopy(origin)
>>> cop1 == cop2
True
>>> cop1 is cop2
False
#cop1 和 cop2 看上去相同,但已不再是同一个object
>>> origin[2][0] = "hey!"
>>> origin
[1, 2, ['hey!', 4]]
>>> cop1
[1, 2, ['hey!', 4]]
>>> cop2
[1, 2, [3, 4]]
#把origin内的子list [3, 4] 改掉了一个元素,观察 cop1 和 cop2
torch.ones_like函数和torch.zeros_like函数的基本功能是根据给定张量,生成与其形状相同的全1张量或全0张量
input = torch.rand(2, 3)
print(input)
# 生成与input形状相同、元素全为1的张量
a = torch.ones_like(input)
print(a)
# 生成与input形状相同、元素全为0的张量
b = torch.zeros_like(input)
print(b)
tensor([[0.0881, 0.9002, 0.7084],
[0.3313, 0.2736, 0.0894]])
tensor([[1., 1., 1.],
[1., 1., 1.]])
tensor([[0., 0., 0.],
[0., 0., 0.]])
生成对角线全1,其余部分全0的二维数组
contiguous 一般用于 transpose/permute 后和 view 前,即使用 transpose 或 permute 进行维度变换后,调用 contiguous,然后方可使用 view 对维度进行变形(如:tensor_var.contiguous().view() ),示例如下:
x = torch.Tensor(2,3)
y = x.permute(1,0) # permute:二维tensor的维度变换,此处功能相当于转置transpose
y.view(-1) # 报错,view使用前需调用contiguous()函数
y = x.permute(1,0).contiguous()
y.view(-1) # OK
维度变换后的变量是之前变量的浅拷贝,指向同一区域,即 view 操作会连带原来的变量一同变形,这是不合法的,所以也会报错。(这个解释有部分道理,也即 contiguous 返回了 tensor 的深拷贝 contiguous copy 数据)
链接
os.pathd的使用
#os.path.splitext() 将文件名和扩展名分开
#os.path.split() 返回文件的路径和文件名
import os
#os.path.join() 将分离的部分合成一个整体
filename=os.path.join('/home/ubuntu/python_coding','split_func')
print filename
#输出为:/home/ubuntu/python_coding/split_func
#os.path.splitext()将文件名和扩展名分开
fname,fename=os.path.splitext('/home/ubuntu/python_coding/split_func/split_function.py')
print 'fname is:',fname
print 'fename is:',fename
#输出为:
# fname is:/home/ubuntu/python_coding/split_func/split_function
#fename is:.py
#os.path.split()返回文件的路径和文件名
dirname,filename=os.path.split('/home/ubuntu/python_coding/split_func/split_function.py')
print dirname
print filename
#输出为:
# /home/ubuntu/python_coding/split_func
#split_function.py
一、unsqueeze()函数
解压操作,用以增加维度。
二、squeeze()函数介绍
1. 首先得到一个维度为(2,3)的tensor(张量)
由图中可以看出c的维度为(1,2,3)
可以看出维度并没有变化,仍然为(1,2,3),这是因为只有维度为1时才会去掉。
链接
返回所有匹配的文件路径列表。它只有一个参数pathname,定义了文件路径匹配规则,这里可以是绝对路径,也可以是相对路径。下面是使用glob.glob的例子:
import glob
#获取指定目录下的所有图片
print (glob.glob(r"/home/qiaoyunhao/*/*.png"),"\n")#加上r让字符串不转义
#获取上级目录的所有.py文件
print (glob.glob(r'../*.py')) #相对路径
获取一个可编历对象,使用它可以逐个获取匹配的文件路径名。与glob.glob()的区别是:glob.glob同时获取所有的匹配路径,而glob.iglob一次只获取一个匹配路径。这有点类似于.NET中操作数据库用到的DataSet与DataReader。下面是一个简单的例子:
import glob
#父目录中的.py文件
f = glob.iglob(r'../*.py')
print (f) #
for py in f:
print (py)
kernal filter滑动窗口展平操作,类似于conv2d
torch.nn.Unfold(kernel_size, dilation=1, padding=0, stride=1)#卷积核的尺寸,空洞大小,填充大小和步长。
unfold的输入为(N , C , H , W ),其中N为batch_size,C是channel个数,H和W分别是channel的长宽。
则unfold的输出为(N NN, C × ∏ C \times \prodC×∏(kernel_size), L LL),其中∏ \prod∏(kernel_size)为kernel_size长和宽的乘积, L是channel的长宽根据kernel_size的长宽滑动裁剪后,得到的区块的数量。
inputs = torch.randn(1, 2, 4, 4)
print(inputs.size())
print(inputs)
unfold = torch.nn.Unfold(kernel_size=(2, 2), stride=2)
patches = unfold(inputs)
print(patches.size())
print(patches)
torch.Size([1, 2, 4, 4])
tensor([[[[ 1.4818, -0.1026, -1.7688, 0.5384],
[-0.4693, -0.0775, -0.7504, 0.2283],
[-0.1414, 1.0006, -0.0942, 2.2981],
[-0.9429, 1.1908, 0.9374, -1.3168]],
[[-1.8184, -0.3926, 0.1875, 1.3847],
[-0.4124, 0.9766, -1.3303, -0.0970],
[ 1.7679, 0.6961, -1.6445, 0.7482],
[ 0.1729, -0.3196, -0.1528, 0.2180]]]])
torch.Size([1, 8, 4])
tensor([[[ 1.4818, -1.7688, -0.1414, -0.0942],
[-0.1026, 0.5384, 1.0006, 2.2981],
[-0.4693, -0.7504, -0.9429, 0.9374],
[-0.0775, 0.2283, 1.1908, -1.3168],
[-1.8184, 0.1875, 1.7679, -1.6445],
[-0.3926, 1.3847, 0.6961, 0.7482],
[-0.4124, -1.3303, 0.1729, -0.1528],
[ 0.9766, -0.0970, -0.3196, 0.2180]]])
_.chunk(arry, [size = 1])
根据size大小将arry数组分组,size是每一组数组的长度。若数组不等均分,那么最后一组数组就会包含剩下的元素。
_.chunk(['a','b','c','d'], 2)
// ['a','b'],['c','d']
_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
rearrange是einops中的一个函数调用方法
链接
链接
链接
drop([ ],axis=0,inplace=True)
drop([]),默认情况下删除某一行;
如果要删除某列,需要axis=1;
参数inplace 默认情况下为False,表示保持原来的数据不变,True 则表示在原来的数据上改变。
链接
将含nan的行或列删除,默认是行
链接
df.replace('Infinity', np.NaN):将“infinity”替换成nan
链接
numpy中nan:not a number,类型为浮点型链接
链接
链接
链接
np.tile
np.unique