pytorch如何计算显存大小

2024-04-25 03:38
文章标签 大小 计算 pytorch 显存

本文主要是介绍pytorch如何计算显存大小,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考连接

pytorch 减小显存消耗,优化显存使用避免 outofmemory https://blog.csdn.net/qq_28660035/article/details/80688427

如何计算模型以及中间变量的显存占用大小:https://oldpan.me/archives/how-to-calculate-gpu-memory

如何在Pytorch中精细化利用显存:https://oldpan.me/archives/how-to-use-memory-pytorch

科普帖:深度学习中GPU和显存分析 https://zhuanlan.zhihu.com/p/31558973 

科普帖:深度学习中GPU和显存分析 ppt

PyTorch 有哪些坑/bug?https://www.zhihu.com/question/67209417

keras计算神经网络内存占用 https://blog.csdn.net/u011311291/article/details/82969409

Keras计算内存

如果layer.count_params()或者model.summary()权重参数个数为负数的可以参考:
彻底解决keras model.summary()或者layer.count_params()权重参数个数为负数问题举两个例子,一张(1024,1024,3)的图片,分别使用VGGNet,DenseNet网络。

一.VGGNet内存消耗计算

'''
Created on 2018年9月30日'''from keras import applications
import numpy as npimport cv2
image = cv2.imread("D:\\xxxx\\hashiqi.jpg")
image = cv2.resize(image,(1024,1024),interpolation = cv2.INTER_CUBIC)
x_train = np.expand_dims(image,axis=0)
y_train = np.array([0])
print(image.shape)
# (1024, 1024, 3)model = applications.VGG16(input_shape=(1024,1024,3),include_top=False,weights=None)
print("无全连接层总参数量:",model.count_params())
model = applications.VGG16(input_shape=(1024,1024,3),include_top=True,weights=None)
print("有全连接层总参数量:",model.count_params())
# 无全连接层总参数量: 14714688
# 有全连接层总参数量: 2183080744 可见权重都基本占用在全连接层all_params_memory = 0
all_feature_memory = 0
for layer in model.layers:#训练权重w占用的内存params_memory = layer.count_params()/(1024*1024) * 4print("训练权重w占用的内存:",layer.name,layer.count_params(),str(params_memory)+" M")all_params_memory = all_params_memory + params_memory#特征图占用内存feature_shape = layer.output_shapefeature_size = 1for i in range(1,len(feature_shape)):feature_size = feature_size*feature_shape[i]feature_memory = feature_size/(1024*1024) * 4print("特征图占用内存:",feature_shape,feature_size,str(feature_memory)+" M")all_feature_memory = all_feature_memory + feature_memory# 特征图占用内存: (None, 1024, 1024, 3) 3145728 12.0 M
# 训练权重w占用的内存: block1_conv1 1792 0.0068359375 M
# 特征图占用内存: (None, 1024, 1024, 64) 67108864 256.0 M
# 训练权重w占用的内存: block1_conv2 36928 0.140869140625 M
# 特征图占用内存: (None, 1024, 1024, 64) 67108864 256.0 M
# 训练权重w占用的内存: block1_pool 0 0.0 M
# 特征图占用内存: (None, 512, 512, 64) 16777216 64.0 M
# 训练权重w占用的内存: block2_conv1 73856 0.28173828125 M
# 特征图占用内存: (None, 512, 512, 128) 33554432 128.0 M
# 训练权重w占用的内存: block2_conv2 147584 0.56298828125 M
# 特征图占用内存: (None, 512, 512, 128) 33554432 128.0 M
# 训练权重w占用的内存: block2_pool 0 0.0 M
# 特征图占用内存: (None, 256, 256, 128) 8388608 32.0 M
# 训练权重w占用的内存: block3_conv1 295168 1.1259765625 M
# 特征图占用内存: (None, 256, 256, 256) 16777216 64.0 M
# 训练权重w占用的内存: block3_conv2 590080 2.2509765625 M
# 特征图占用内存: (None, 256, 256, 256) 16777216 64.0 M
# 训练权重w占用的内存: block3_conv3 590080 2.2509765625 M
# 特征图占用内存: (None, 256, 256, 256) 16777216 64.0 M
# 训练权重w占用的内存: block3_pool 0 0.0 M
# 特征图占用内存: (None, 128, 128, 256) 4194304 16.0 M
# 训练权重w占用的内存: block4_conv1 1180160 4.501953125 M
# 特征图占用内存: (None, 128, 128, 512) 8388608 32.0 M
# 训练权重w占用的内存: block4_conv2 2359808 9.001953125 M
# 特征图占用内存: (None, 128, 128, 512) 8388608 32.0 M
# 训练权重w占用的内存: block4_conv3 2359808 9.001953125 M
# 特征图占用内存: (None, 128, 128, 512) 8388608 32.0 M
# 训练权重w占用的内存: block4_pool 0 0.0 M
# 特征图占用内存: (None, 64, 64, 512) 2097152 8.0 M
# 训练权重w占用的内存: block5_conv1 2359808 9.001953125 M
# 特征图占用内存: (None, 64, 64, 512) 2097152 8.0 M
# 训练权重w占用的内存: block5_conv2 2359808 9.001953125 M
# 特征图占用内存: (None, 64, 64, 512) 2097152 8.0 M
# 训练权重w占用的内存: block5_conv3 2359808 9.001953125 M
# 特征图占用内存: (None, 64, 64, 512) 2097152 8.0 M
# 训练权重w占用的内存: block5_pool 0 0.0 M
# 特征图占用内存: (None, 32, 32, 512) 524288 2.0 M
# 训练权重w占用的内存: flatten 0 0.0 M
# 特征图占用内存: (None, 524288) 524288 2.0 M
# 训练权重w占用的内存: fc1 2147487744 8192.015625 M
# 特征图占用内存: (None, 4096) 4096 0.015625 M
# 训练权重w占用的内存: fc2 16781312 64 .015625 M
# 特征图占用内存: (None, 4096) 4096 0.015625 M
# 训练权重w占用的内存: predictions 4097000 15.628814697265625 M
# 特征图占用内存: (None, 1000) 1000 0.003814697265625 Mprint("网络权重W占用总内存:",str(all_params_memory)+" M")
print("网络特征图占用总内存:",str(all_feature_memory)+" M")
print("网络总消耗内存:",str(all_params_memory+all_feature_memory)+" M")
# 网络权重W占用总内存: 8327.79214477539 M
# 网络特征图占用总内存: 1216.0350647 M
# 网络总消耗内存: 9543.82720947 M


二.DenseNet内存消耗计算

'''
Created on 2018年9月30日'''from keras import applications
import numpy as npimport cv2
image = cv2.imread("D:\\xxx\\hashiqi.jpg")
image = cv2.resize(image,(1024,1024),interpolation = cv2.INTER_CUBIC)
x_train = np.expand_dims(image,axis=0)
y_train = np.array([0])
print(image.shape)
# (1024, 1024, 3)model = applications.DenseNet201(input_shape=(1024,1024,3),include_top=False,weights=None)
print("无全连接层总参数量:",model.count_params())
model = applications.DenseNet201(input_shape=(1024,1024,3),include_top=True,weights=None)
print("有全连接层总参数量:",model.count_params())
# 无全连接层总参数量: 18321984
# 有全连接层总参数量: 20242984 因为使用了GlobalAveragePooling2D,使得全连接参数少了很多all_params_memory = 0
all_feature_memory = 0
for layer in model.layers:#训练权重w占用的内存params_memory = layer.count_params()/(1024*1024) * 4print("训练权重w占用的内存:",layer.name,layer.count_params(),str(params_memory)+" M")all_params_memory = all_params_memory + params_memory#特征图占用内存feature_shape = layer.output_shapefeature_size = 1for i in range(1,len(feature_shape)):feature_size = feature_size*feature_shape[i]feature_memory = feature_size/(1024*1024) * 4print("特征图占用内存:",feature_shape,feature_size,str(feature_memory)+" M")all_feature_memory = all_feature_memory + feature_memory# 训练权重w占用的内存: input_2 0 0.0 M
# 特征图占用内存: (None, 1024, 1024, 3) 3145728 12.0 M
# 训练权重w占用的内存: zero_padding2d_3 0 0.0 M
# 特征图占用内存: (None, 1030, 1030, 3) 3182700 12.141036987304688 M
# 训练权重w占用的内存: conv1/conv 9408 0.035888671875 M
# 特征图占用内存: (None, 512, 512, 64) 16777216 64.0 M
# 训练权重w占用的内存: conv1/bn 256 0.0009765625 M
# 特征图占用内存: (None, 512, 512, 64) 16777216 64.0 M
# 训练权重w占用的内存: conv1/relu 0 0.0 M
# 特征图占用内存: (None, 512, 512, 64) 16777216 64.0 M
# .........print("网络权重W占用总内存:",str(all_params_memory)+" M")
print("网络特征图占用总内存:",str(all_feature_memory)+" M")
print("网络总消耗内存:",str(all_params_memory+all_feature_memory)+" M")
# 网络权重W占用总内存: 77.22085571289062 M
# 网络特征图占用总内存: 6151.65315246582 M
# 网络总消耗内存: 6228.874008178711 M 内存消耗基本在特征图上

pytorch优化显存

在Pytorch中优化显存是我们处理大量数据时必要的做法,因为我们并不可能拥有无限的显存。显存是有限的,而数据是无限的,我们只有优化显存的使用量才能够最大化地利用我们的数据,实现多种多样的算法。

估测模型所占的内存

上篇文章中说过,一个模型所占的显存无非是这两种:

  • 模型权重参数
  • 模型所储存的中间变量

其实权重参数一般来说并不会占用很多的显存空间,主要占用显存空间的还是计算时产生的中间变量,当我们定义了一个model之后,我们可以通过以下代码简单计算出这个模型权重参数所占用的数据量:

import numpy as np# model是我们在pytorch定义的神经网络层
# model.parameters()取出这个model所有的权重参数
para = sum([np.prod(list(p.size())) for p in model.parameters()])

假设我们有这样一个model:

Sequential((conv_1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_1): ReLU(inplace)(conv_2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_2): ReLU(inplace)(pool_2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv_3): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)

然后我们得到的para112576,但是我们计算出来的仅仅是权重参数的“数量”,单位是B,我们需要转化一下:

# 下面的type_size是4,因为我们的参数是float32也就是4B,4个字节print('Model {} : params: {:4f}M'.format(model._get_name(), para * type_size / 1000 / 1000))

这样就可以打印出:

Model Sequential : params: 0.450304M

但是我们之前说过一个神经网络的模型,不仅仅有权重参数还要计算中间变量的大小。怎么去计算,我们可以假设一个输入变量,然后将这个输入变量投入这个模型中,然后我们主动提取这些计算出来的中间变量:

# model是我们加载的模型
# input是实际中投入的input(Tensor)变量# 利用clone()去复制一个input,这样不会对input造成影响
input_ = input.clone()   
# 确保不需要计算梯度,因为我们的目的只是为了计算中间变量而已
input_.requires_grad_(requires_grad=False)mods = list(model.modules())
out_sizes = []for i in range(1, len(mods)):m = mods[i]# 注意这里,如果relu激活函数是inplace则不用计算if isinstance(m, nn.ReLU):  if m.inplace:continueout = m(input_)out_sizes.append(np.array(out.size()))input_ = outtotal_nums = 0
for i in range(len(out_sizes)):s = out_sizes[i]nums = np.prod(np.array(s))total_nums += nums

上面得到的值是模型在运行时候产生所有的中间变量的“数量”,当然我们需要换算一下:

# 打印两种,只有 forward 和 foreward、backward的情况
print('Model {} : intermedite variables: {:3f} M (without backward)'.format(model._get_name(), total_nums * type_size / 1000 / 1000))
print('Model {} : intermedite variables: {:3f} M (with backward)'.format(model._get_name(), total_nums * type_size*2 / 1000 / 1000))

因为在backward的时候所有的中间变量需要保存下来再来进行计算,所以我们在计算backward的时候,计算出来的中间变量需要乘个2。

然后我们得出,上面这个模型的中间变量需要的占用的显存,很显然,中间变量占用的值比模型本身的权重值多多了。如果进行一次backward那么需要的就更多。

Model Sequential : intermedite variables: 336.089600 M (without backward)
Model Sequential : intermedite variables: 672.179200 M (with backward)

我们总结一下之前的代码:

# 模型显存占用监测函数
# model:输入的模型
# input:实际中需要输入的Tensor变量
# type_size 默认为 4 默认类型为 float32 def modelsize(model, input, type_size=4):para = sum([np.prod(list(p.size())) for p in model.parameters()])print('Model {} : params: {:4f}M'.format(model._get_name(), para * type_size / 1000 / 1000))input_ = input.clone()input_.requires_grad_(requires_grad=False)mods = list(model.modules())out_sizes = []for i in range(1, len(mods)):m = mods[i]if isinstance(m, nn.ReLU):if m.inplace:continueout = m(input_)out_sizes.append(np.array(out.size()))input_ = outtotal_nums = 0for i in range(len(out_sizes)):s = out_sizes[i]nums = np.prod(np.array(s))total_nums += numsprint('Model {} : intermedite variables: {:3f} M (without backward)'.format(model._get_name(), total_nums * type_size / 1000 / 1000))print('Model {} : intermedite variables: {:3f} M (with backward)'.format(model._get_name(), total_nums * type_size*2 / 1000 / 1000))

当然我们计算出来的占用显存值仅仅是做参考作用,因为Pytorch在运行的时候需要额外的显存值开销,所以实际的显存会比我们计算的稍微大一些。

关于inplace=False

我们都知道激活函数Relu()有一个默认参数inplace,默认设置为False,当设置为True时,我们在通过relu()计算时的得到的新值不会占用新的空间而是直接覆盖原来的值,这也就是为什么当inplace参数设置为True时可以节省一部分内存的缘故。

《如何在Pytorch中精细化利用显存》

牺牲计算速度减少显存使用量

Pytorch-0.4.0出来了一个新的功能,可以将一个计算过程分成两半,也就是如果一个模型需要占用的显存太大了,我们就可以先计算一半,保存后一半需要的中间结果,然后再计算后一半。

也就是说,新的checkpoint允许我们只存储反向传播所需要的部分内容。如果当中缺少一个输出(为了节省内存而导致的),checkpoint将会从最近的检查点重新计算中间输出,以便减少内存使用(当然计算时间增加了):

# 输入
input = torch.rand(1, 10)
# 假设我们有一个非常深的网络
layers = [nn.Linear(10, 10) for _ in range(1000)]
model = nn.Sequential(*layers)
output = model(input)

上面的模型需要占用很多的内存,因为计算中会产生很多的中间变量。为此checkpoint就可以帮助我们来节省内存的占用了。

# 首先设置输入的input=>requires_grad=True
# 如果不设置可能会导致得到的gradient为0input = torch.rand(1, 10, requires_grad=True)
layers = [nn.Linear(10, 10) for _ in range(1000)]# 定义要计算的层函数,可以看到我们定义了两个
# 一个计算前500个层,另一个计算后500个层def run_first_half(*args):x = args[0]for layer in layers[:500]:x = layer(x)return xdef run_second_half(*args):x = args[0]for layer in layers[500:-1]:x = layer(x)return x# 我们引入新加的checkpoint
from torch.utils.checkpoint import checkpointx = checkpoint(run_first_half, input)
x = checkpoint(run_second_half, x)
# 最后一层单独调出来执行
x = layers[-1](x)
x.sum.backward()  # 这样就可以了

对于Sequential-model来说,因为Sequential()中可以包含很多的block,所以官方提供了另一个功能包:

input = torch.rand(1, 10, requires_grad=True)
layers = [nn.Linear(10, 10) for _ in range(1000)]
model = nn.Sequential(*layers)from torch.utils.checkpoint import checkpoint_sequential# 分成两个部分
num_segments = 2
x = checkpoint_sequential(model, num_segments, input)
x.sum().backward()  # 这样就可以了

跟踪显存使用情况

显存的使用情况,在编写程序中我们可能无法精确计算,但是我们可以通过pynvml这个Nvidia的Python环境库和Python的垃圾回收工具,可以实时地打印我们使用的显存以及哪些Tensor使用了我们的显存。

类似于下面的报告:

# 08-Jun-18-17:56:51-gpu_mem_profAt __main__ <module>: line 39                        Total Used Memory:399.4  Mb
At __main__ <module>: line 40                        Total Used Memory:992.5  Mb
+ __main__ <module>: line 40                         (1, 1, 682, 700)     1.82 M <class 'torch.Tensor'>
+ __main__ <module>: line 40                         (1, 3, 682, 700)     5.46 M <class 'torch.Tensor'>
At __main__ <module>: line 126                       Total Used Memory:1088.5 Mb
+ __main__ <module>: line 126                        (64, 64, 3, 3)       0.14 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (128, 64, 3, 3)      0.28 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (128, 128, 3, 3)     0.56 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (64, 3, 3, 3)        0.00 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (256, 256, 3, 3)     2.25 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (512, 256, 3, 3)     4.5 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (512, 512, 3, 3)     9.0 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (64,)                0.00 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (1, 3, 682, 700)     5.46 M <class 'torch.Tensor'>
+ __main__ <module>: line 126                        (128,)               0.00 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (256,)               0.00 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (512,)               0.00 M <class 'torch.nn.parameter.Parameter'>
+ __main__ <module>: line 126                        (3,)                 1.14 M <class 'torch.Tensor'>
+ __main__ <module>: line 126                        (256, 128, 3, 3)     1.12 M <class 'torch.nn.parameter.Parameter'>
...

以下是相关的代码,目前代码依然有些地方需要修改,等修改完善好我会将完整代码以及使用说明放到github上:https://github.com/Oldpan/Pytorch-Memory-Utils
请大家多多留意。

import datetime
import linecache
import osimport gc
import pynvml
import torch
import numpy as npprint_tensor_sizes = True
last_tensor_sizes = set()
gpu_profile_fn = f'{datetime.datetime.now():%d-%b-%y-%H:%M:%S}-gpu_mem_prof.txt'# if 'GPU_DEBUG' in os.environ:
#     print('profiling gpu usage to ', gpu_profile_fn)lineno = None
func_name = None
filename = None
module_name = None# fram = inspect.currentframe()
# func_name = fram.f_code.co_name
# filename = fram.f_globals["__file__"]
# ss = os.path.dirname(os.path.abspath(filename))
# module_name = fram.f_globals["__name__"]def gpu_profile(frame, event):# it is _about to_ execute (!)global last_tensor_sizesglobal lineno, func_name, filename, module_nameif event == 'line':try:# about _previous_ line (!)if lineno is not None:pynvml.nvmlInit()# handle = pynvml.nvmlDeviceGetHandleByIndex(int(os.environ['GPU_DEBUG']))handle = pynvml.nvmlDeviceGetHandleByIndex(0)meminfo = pynvml.nvmlDeviceGetMemoryInfo(handle)line = linecache.getline(filename, lineno)where_str = module_name+' '+func_name+':'+' line '+str(lineno)with open(gpu_profile_fn, 'a+') as f:f.write(f"At {where_str:<50}"f"Total Used Memory:{meminfo.used/1024**2:<7.1f}Mb\n")if print_tensor_sizes is True:for tensor in get_tensors():if not hasattr(tensor, 'dbg_alloc_where'):tensor.dbg_alloc_where = where_strnew_tensor_sizes = {(type(x), tuple(x.size()), np.prod(np.array(x.size()))*4/1024**2,x.dbg_alloc_where) for x in get_tensors()}for t, s, m, loc in new_tensor_sizes - last_tensor_sizes:f.write(f'+ {loc:<50} {str(s):<20} {str(m)[:4]} M {str(t):<10}\n')for t, s, m, loc in last_tensor_sizes - new_tensor_sizes:f.write(f'- {loc:<50} {str(s):<20} {str(m)[:4]} M {str(t):<10}\n')last_tensor_sizes = new_tensor_sizespynvml.nvmlShutdown()# save details about line _to be_ executedlineno = Nonefunc_name = frame.f_code.co_namefilename = frame.f_globals["__file__"]if (filename.endswith(".pyc") orfilename.endswith(".pyo")):filename = filename[:-1]module_name = frame.f_globals["__name__"]lineno = frame.f_linenoreturn gpu_profileexcept Exception as e:print('A exception occured: {}'.format(e))return gpu_profiledef get_tensors():for obj in gc.get_objects():try:if torch.is_tensor(obj):tensor = objelse:continueif tensor.is_cuda:yield tensorexcept Exception as e:print('A exception occured: {}'.format(e))

需要注意的是,linecache中的getlines只能读取缓冲过的文件,如果这个文件没有运行过则返回无效值。Python 的垃圾收集机制会在变量没有应引用的时候立马进行回收,但是为什么模型中计算的中间变量在执行结束后还会存在呢。既然都没有引用了为什么还会占用空间?

一种可能的情况是这些引用不在Python代码中,而是在神经网络层的运行中为了backward被保存为gradient,这些引用都在计算图中,我们在程序中是无法看到的:

《如何在Pytorch中精细化利用显存》

这篇关于pytorch如何计算显存大小的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/933613

相关文章

C#中图片如何自适应pictureBox大小

《C#中图片如何自适应pictureBox大小》文章描述了如何在C#中实现图片自适应pictureBox大小,并展示修改前后的效果,修改步骤包括两步,作者分享了个人经验,希望对大家有所帮助... 目录C#图片自适应pictureBox大小编程修改步骤总结C#图片自适应pictureBox大小上图中“z轴

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

PyTorch使用教程之Tensor包详解

《PyTorch使用教程之Tensor包详解》这篇文章介绍了PyTorch中的张量(Tensor)数据结构,包括张量的数据类型、初始化、常用操作、属性等,张量是PyTorch框架中的核心数据结构,支持... 目录1、张量Tensor2、数据类型3、初始化(构造张量)4、常用操作5、常用属性5.1 存储(st

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

如何用Java结合经纬度位置计算目标点的日出日落时间详解

《如何用Java结合经纬度位置计算目标点的日出日落时间详解》这篇文章主详细讲解了如何基于目标点的经纬度计算日出日落时间,提供了在线API和Java库两种计算方法,并通过实际案例展示了其应用,需要的朋友... 目录前言一、应用示例1、天安门升旗时间2、湖南省日出日落信息二、Java日出日落计算1、在线API2

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

XTU 1237 计算几何

题面: Magic Triangle Problem Description: Huangriq is a respectful acmer in ACM team of XTU because he brought the best place in regional contest in history of XTU. Huangriq works in a big compa

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显