我在github上看到了这个LSTM语言模型的例子(链接).它一般来说对我来说非常清楚.但是我仍然在努力理解调用的内容contiguous(),这在代码中会多次发生.
例如,在代码输入的第74/75行中,创建LSTM的目标序列.数据(存储在其中ids)是二维的,其中第一维是批量大小.
for i in range(0, ids.size(1) - seq_length, seq_length):
# Get batch inputs and targets
inputs = Variable(ids[:, i:i+seq_length])
targets = Variable(ids[:, (i+1):(i+1)+seq_length].contiguous())
Run Code Online (Sandbox Code Playgroud)
举个简单的例子,当使用批量大小为1和seq_length10时inputs,targets看起来像这样:
inputs Variable containing:
0 1 2 3 4 5 6 7 8 9
[torch.LongTensor of size 1x10]
targets Variable containing:
1 2 3 4 5 6 7 8 9 10
[torch.LongTensor of size 1x10]
Run Code Online (Sandbox Code Playgroud)
所以一般来说我的问题是,contiguous()我需要什么以及为什么需要它?
此外,我不明白为什么该方法被调用目标序列而不是输入序列,因为两个变量都包含相同的数据.
怎么可能targets是inputs不连续的,仍然是连续的? …
我读过这std::vector应该是连续的.我的理解是,它的元素应该存储在一起,而不是分散在内存中.我简单地接受了这个事实,并在使用其data()方法获取底层连续内存时使用了这些知识.
但是,我遇到了一种情况,即向量的内存以奇怪的方式运行:
std::vector<int> numbers;
std::vector<int*> ptr_numbers;
for (int i = 0; i < 8; i++) {
numbers.push_back(i);
ptr_numbers.push_back(&numbers.back());
}
Run Code Online (Sandbox Code Playgroud)
我希望这能给我一些数字的向量和这些数字的指针向量.但是,当列出ptr_numbers指针的内容时,有不同的看似随机的数字,好像我正在访问错误的内存部分.
我试图每步检查一下内容:
for (int i = 0; i < 8; i++) {
numbers.push_back(i);
ptr_numbers.push_back(&numbers.back());
for (auto ptr_number : ptr_numbers)
std::cout << *ptr_number << std::endl;
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
结果看起来大致如下:
1
some random number
2
some random number
some random number
3
Run Code Online (Sandbox Code Playgroud)
因此,当我push_back()对numbers向量时,它的旧元素似乎改变了它们的位置.
那究竟是什么意思呢,这std::vector是一个连续的容器,为什么它的元素会移动?是否可以将它们存储在一起,但是当需要更多空间时将它们一起移动?
编辑:std::vector仅在C++ 17之后是连续的吗?(只是为了保留对我之前的声明的评论与未来的读者相关.)
内存是std::array连续的吗?以下是有效/良好的做法吗?
std::array<type1,Num> arr = //initialize value
type1 * ptr = &arr[0];
Run Code Online (Sandbox Code Playgroud)
我可以传递ptr给期望c风格数组的函数吗?
我对以下代码有两个问题:1)元素是否faces会连续?
2)插入时是否std::vector复制或移动Face f?
#include <vector>
int main()
{
struct Face {};
std::vector<Face> faces;
for (int i=0; i<10; ++i)
{
Face f;
faces.push_back (f);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 在全球历史气候网络已其收藏的天气测量的标记无效或错误的数据.删除这些元素后,有大量数据不再具有连续的日期部分.数据类似于:
"2007-12-01";14 -- Start of December
"2007-12-29";8
"2007-12-30";11
"2007-12-31";7
"2008-01-01";8 -- Start of January
"2008-01-02";12
"2008-01-29";0
"2008-01-31";7
"2008-02-01";4 -- Start of February
... entire month is complete ...
"2008-02-29";12
"2008-03-01";14 -- Start of March
"2008-03-02";17
"2008-03-05";17
Run Code Online (Sandbox Code Playgroud)
虽然可以推断缺失的数据(例如,通过平均其他年份)来提供连续的范围,但为了简化系统,我想根据是否有一个连续的日期范围填写月份来标记非连续的段:
D;"2007-12-01";14 -- Start of December
D;"2007-12-29";8
D;"2007-12-30";11
D;"2007-12-31";7
D;"2008-01-01";8 -- Start of January
D;"2008-01-02";12
D;"2008-01-29";0
D;"2008-01-31";7
"2008-02-01";4 -- Start of February
... entire month is complete ...
"2008-02-29";12
D;"2008-03-01";14 -- Start of March
D;"2008-03-02";17
D;"2008-03-05";17
Run Code Online (Sandbox Code Playgroud)
一些测量是在1843年进行的.
对于所有气象站,您如何标记缺少一天或多天的所有日期?
C++11std::begin(std::valarray&)以及std::end(std::valarray&).
C++17 引入了std::data()它与std::vector, std::array, C 风格的数组等一起使用。但是为什么没有为std::data()引入重载std::valarray?
std::valarray被指定为具有连续存储,可以通过获取a[0](见注释)的地址来访问。
std::data(std::valarray& a)可以简单地定义为 return &(a[0])。为什么没有做到这一点?是疏忽吗?
我的动机是我正在开发一个通用的序列化库。当它从源(例如 CBOR)接收连续的二进制数数组时,它会检测目标容器是否具有重载data(container)函数、container.resize(n)成员函数以及适当的value_type(匹配原始数字类型)。这三者的存在使得memcpy()将源数据直接高效地导入目标容器成为可能。如果有std::data(std::valarray&)超载,它会让我的生活更简单。缺少它并不是一个阻碍,但它确实使代码更加混乱。
附录:我想检测一个data函数的原因是它告诉我目标容器是连续的。如果它是连续的,那么我可以进行有效的字节复制(通过std::memcpy或std::copy无关紧要)。如果它不是连续的,那么我解压每次打开一个未对齐的源阵列头号和使用它附加到目标容器push_back,emplace等取决于容器的类型。
附录 2:我决定使用适配器和特征方法,而不是检测data函数的存在。这将使支持非标准或用户定义的容器类型变得更加容易。我关于为什么没有std::data(std::valarray& a)仍然站的问题。
附录 3:我应该澄清一下,我需要对 CBOR 类型的数组(只能是数字)执行此操作。此外,源缓冲区中的数字未与元素边界对齐。我知道二进制数据可能需要字节序交换,如果不小心处理,将字节复制到浮点类型可能会触发奇怪的 NaN 行为。
我现在后悔提到我的动机,应该让这个std::data(std::valarray& a)问题独立存在。这个问题已经变成了一个火车事故,哈哈。:-)
如何在没有C++中其他内存管理器(如Malloc/New)的帮助下,如何创建自定义MemoryManager来管理给定的连续内存块?
这里有一些更多的背景:
MemManager::MemManager(void* memory, unsigned char totalsize)
{
Memory = memory;
MemSize = totalsize;
}
Run Code Online (Sandbox Code Playgroud)
我需要能够使用MemManager分配和释放这个连续内存的块.构造函数以字节为单位给出块的总大小.
Allocate函数应该以字节为单位占用所需的内存量,并返回指向该内存块开头的指针.如果没有剩余内存,则返回NULL指针.
Deallocate函数应该接收指向必须释放的内存块的指针,并将其返回给MemManager以备将来使用.
请注意以下约束:
- 除了给它的内存块,MemManager不能使用任何动态内存
- 最初指定,MemManager不能使用其他内存管理器来执行其功能,包括new/malloc和delete/free
我已经在几次面试中收到了这个问题,但即使是几个小时的在线研究也没有帮助我,我每次都失败了.我已经找到了类似的实现,但它们都使用了malloc/new,或者是来自操作系统的通用和请求的内存,我不允许这样做.
请注意,我很乐意使用malloc/new和free/delete,并且使用它们时遇到的问题很少.
我尝试过以LinkedList方式利用节点对象的实现,这些实现指向分配的内存块并说明使用了多少字节.然而,在这些实现中,我总是被迫在堆栈中创建新节点并将它们插入到列表中,但是一旦它们超出范围,整个程序就会因地址和内存大小丢失而中断.
如果有人对如何实现这样的事情有某种想法,我将非常感激.提前致谢!
编辑:我忘了在我的原始帖子中直接指定这个,但是用这个MemManager分配的对象可以是不同的大小.
编辑2:我最终使用了同源内存块,由于下面的答案提供的信息,实际上很容易实现.没有指定有关实现本身的确切规则,因此我将每个块分成8个字节.如果用户请求超过8个字节,我将无法提供,但如果用户请求少于8个字节(但> 0),那么我会给予额外的内存.如果传入的内存量不能被8整除,那么最后会浪费内存,我认为这比使用更多内存要好得多.
是的,我最终会将它用于 DMA,但暂时将一致性放在一边。我有 64 位 BAR 寄存器,因此,AFAIK,所有 RAM(例如高于 4G)都可用于 DMA。
我正在寻找大约 64MB 的连续 RAM。是的,很多。
Ubuntu 16 和 18 具有CONFIG_CMA=y但未CONFIG_DMA_CMA在内核编译时设置。
我注意到,如果两者都设置(在内核构建时),我可以简单地调用dma_alloc_coherent,但是,出于逻辑原因,重新编译内核是不可取的。
这些机器将始终具有至少 32GB 的 RAM,不运行任何占用大量内存的东西,并且内核模块将在启动后不久加载,然后 RAM 变得明显碎片化,而且,AFAIK,没有其他东西使用 CMA。
我已经设置了内核参数 CMA=1G。(并尝试过 256M 和 512M)
# dmesg | grep cma
[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.4.170 root=UUID=2b25933c-e10c-4833-b5b2-92e9d3a33fec ro cma=1G
[ 0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.4.170 root=UUID=2b25933c-e10c-4833-b5b2-92e9d3a33fec ro cma=1G
[ 0.000000] Memory: 65612056K/67073924K available (8604K kernel code, 1332K rwdata, 3972K rodata, 1484K init, 1316K bss, 1461868K reserved, 0K cma-reserved)
Run Code Online (Sandbox Code Playgroud)
我试过了 …
contiguous ×10
c++ ×6
memory ×3
c++11 ×2
vector ×2
allocation ×1
arrays ×1
boolean ×1
date-range ×1
dma ×1
linux-kernel ×1
lstm ×1
memcpy ×1
numpy ×1
pointers ×1
postgresql ×1
python ×1
pytorch ×1
sql ×1
stdvector ×1
valarray ×1