Torch-RNN运行过程中的坑 [1](读取Lua非空table,size为0)

0、踩坑背景

执行Torch-RNN的时候,在LanguageModel.lua中的encode_string函数中,对start_text的各个character进行id映射编码,实现功能类似“北京天安门”-->“5 10 88 32 111”,方便后面的计算。

这个函数会利用一个全局的类似HashMap的table,hashmap中的key是character(char),value是id(int),涉及到一个从hashmap中按照key取值的操作,代码如下:

local idx = self.token_to_idx[token]
assert(idx ~= nil, ‘Got invalid idx‘)

但是每次运行到assert语句时,都会报错,返回的是nil。

我的训练数据集的规模足够大,同时编码正确的情况下,那么我就需要从几个方面debug:

  • 这个字典table文件压根没数据(本文测试的内容)
  • token确实在table中未命中

我对 self.token_to_idx 这个table类型的变量的大小,进行打印的时候,采用了多种方式:

print(table.getn(self.token_to_idx))
print(table.maxn(self.token_to_idx))
print(#self.token_to_idx)

但是输出都为0,奇了怪了,我用如下语句打印这个table,是有值的:

for k,v in pairs(self.token_to_idx) do
    print(k,v)
end

--------------------------------------------------------------------

那么这是为什么呢?明明table不为空,取table size的时候都是0?

1、lua中的table是什么,各种size函数的区别?

在上一篇《Torch-RNN运行过程中的坑 [0](一些基础概念)》中,我们了解到了lua的introduction中有一句:

自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;

也就是说lua中的数组和hashmap两种数据类型是合并的,美其名曰通用类型的表。

table的API本篇不研究,抛一个链接:Lua table(表),我们先研究一下咱们碰到的问题,即如何取table的真实size。

下面有四种方法(均在Lua 5.14下进行):

  • table.getn(t)

返回table中元素的个数。给出一个调用例子:

> t1 = {1, 2, 3, 5};
> print(table.getn(t1))
4

> t2 = {[1]=1,[2]=2,[3]=3,[4]=5};
> print(table.getn(t2))
4

这不正和我们的要求吻合嘛,继续试试:

> t3 = {[1]=1,[2]=2,[3]=3,[6]=5};
> print(table.getn(t2))
3  --第4个元素下标为6,非连续

> t4 = {[1]=1,[2]=2,nil,[6]=5};
> print(table.getn(t4))
0  --有nil,长度异常

> t5 = {[1]=1,["2"]=2,nil,[6]=5};
> print(table.getn(t5))
0  --有nil,长度异常

> t6 = {[1]=1,["2"]=2,[6]=5};
> print(table.getn(t6))
1  --1后面没有2,没连续上

> t7 = {[1]=1,["2"]=2,[2]=5};
> print(table.getn(t7))
2  --即使1和2两个index没有写连上,但是table首先排序后,计数为2

> t8 = {["20"]=1,["2"]=2,["3"]=5};
> print(table.getn(t8))
0  --hashmap型长度异常

好像出问题了,在index不连续的情况下、在含有nil的情况下、有hashmap、数组与hashmap混搭等情况下getn返回的结果都不正常。

----------------------------------------------------------------------------------------------------------

lua的table长度问题中,作者提出了table可以存储两种类型,一种是list类型(数组,key必为正整数),另外一种是record类型(hashmap,key为非正整数),getn函数统计的是连续的key为正整数的数目,所以我们看头两个例子是输出正常的。

所以没必要记这个规律,除了上面几个例子,getn肯定还有一些其他的规律没发现,不过记住这个getn函数要在有序正整数key的size计数时,输出才是正确的。。。

  • table.maxn(t)

Lua中的table函数库中总结的很好,在这里引用一下:

table.maxn()函数返回指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0. 此函数不限于table的数组部分.

  下面的例子也搬运一下:

> tbl = {[1] = "a", [2] = "b", [3] = "c", [26] = "z"}
> print(#tbl)
3  -- 因为26和之前的数字不连续, 所以不算在数组部分内
> print(table.maxn(tbl))
26 

> tbl[91.32] = true
> print(table.maxn(tbl))
91.32
  • #t

  #方法取size,经测试,效果上应该与getn()方法一毛一样。从1开始,连续整数key的元素个数(必须从1开始计数,结果才正常)。再抛几个例子,希望看官不要花眼。。。

> t5 = {[1]=1,[9]=2,["22"]=9,[2]=5};
> print(#t5)
2  --1和2连续

> t5 = {[1]=1,[9]=2,["22"]=9,[0]=5};
> print(#t5)
1  --从1开始计数,下一个就是9了,不连续

> t5 = {[2]=1,[9]=2,["22"]=9,[5]=5};
> print(#t5)
0  --没从1开始计数,非常遗憾
  • for遍历cnt++

  那么难道没有API可以对hashmap计数了吗?让我这个Java流选手写Lua情何以堪。。。最后找了一位同学同样的疑问,它使用了for循环对key-value计数。。。

function count(ht)
  local n = 0;
  for _, v in pairs(ht) do
    n = n + 1;
  end
  return n;
end

2、重点来啦,那么解决问题的方法?

相信大家看完文章,答案自然成竹于胸,也是很尴尬。那就是:

Lua中“hashmap型”table的元素计数,还得用for循环cnt++的方法。。。。

3、结论与感慨

该踩的坑还是得踩啊。。。

时间: 2024-10-07 04:19:51

Torch-RNN运行过程中的坑 [1](读取Lua非空table,size为0)的相关文章

Torch-RNN运行过程中的坑 [2](Lua的string sub函数,读取中文失败,乱码?)

0.踩坑背景 仍然是torch-rnn/LanguageModel.lua文件中的一些问题,仍然是这个狗血的LM:encode_string函数: function LM:encode_string(s) local encoded = torch.LongTensor(#s) for i = 1, #s do local token = s:sub(i, i) local idx = self.token_to_idx[token] assert(idx ~= nil, 'Got invali

Perl 关于在程序运行过程中重新开启标准输入的问题

遇见问题是,如何程序运行的时候已经将标准输入使用"<"符号或者"|"符合在命令行定向为一个文件. 可是在程序的运行过程中希望从键盘得到输入内容. 因为/dev/tty为当前进程的控制台,STDIN 为当前的标准输入. 如果重定向,例如: perl script.pl <myfile.txt STDIN 被指向 myfile.txt, 但是 /dev/tty 仍然来自于控制终端.所有的Unix都是这样,不单单是指这个perl. 那么解决方案: #!/usr

在程序运行过程中,对象所占的空间是不能随时释放的

使用类名定义的对象(请查看:C++类的声明和对象的定义)都是静态的,在程序运行过程中,对象所占的空间是不能随时释放的.但有时人们希望在需要用到对象时才建立对象,在不需要用该对象时就撤销它,释放它所占的内存空间以供别的数据使用.这样可提高内存空间的利用率. 在C++中,可以使用new运算符动态地分配内存,用delete运算符释放这些内存空间(请查看:C++动态分配内存(new)和撤销内存(delete)).这也适用于对象,可以用new运算符动态建立对象,用delete运算符撤销对象. 如果已经定义

程序在运行过程中变量的保存位置与生命周期

本例说明了一个程序在运行的时候,各种变量所保存的位置.因为位置不同,自然,变量的生命周期也各不相同. 代码示例: #include <iostream> using namespace std; int nGNum1; void showStackAddress(){    cout<<"address of showStackAddress() is:\t["<<(void*)&showStackAddress<<"]

菜鸟帮你跳过openstack配置过程中的坑

一:前言 对于一个以前做java全栈工程师而言,而且没学过Linux,很少用虚拟机(还是在大学的时候简单的用过),去配置openstack我想我入的坑肯定比有基础的一定要多,躺在每个坑中徘徊思索的时间一定比老鸟们久.所以现在总结一下openstack在配置过程中的几大坑点,让各位在配置过程中不再问天问大地,灵魂一片片凋落. 1. 如果是新手一定要学会用快照,一定要多用快照,从镜像安装完成开始,最好每一个章节模块配置完成后都用上一个快照,人生苦短,快照帮你性感. 2.一定要仔细看配种配置以及环境要

[转载] linux 程序运行过程中替换文件

今天被朋友问及“Linux下可以替换运行中的程序么?”,以前依稀记得Linux下是可以的(而Windows就不让),于是随口答道“OK”.结果朋友发来一个执行结果:(test正在运行中)# cp test2 test cp: cannot create regular file `test': Text file busy 看起来是程序被占用,无法覆盖.于是自己又再做了几个实验: (1)先rm删除正在运行的test,然后cp test2 test就没有错误了.(2)先mv改名正在运行的test,

log4j 日志信息的引入(通用版)——解决项目运行过程中的日志信息

定义 log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件,甚至是套接口服务器.NT的事件记录器.UNIX Syslog守护进程等:我们也可以控制每一条日志的输出格式:通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程.最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码. 一.log4j.properties 的使用详解 1.输出级别的种类 ERROR.WARN.INFO.D

app在android 6.0或以上平台版本运行过程中请求权限

原文作者:Google 原文地址:http://developer.android.com/intl/zh-cn/training/permissions/requesting.html 原文版权:Creative Commons 2.5 Attribution License 译文作者:Jianan - [email protected] 版本信息:本文基于2016-04-27版本翻译 译文版权:CC BY-NC-ND 4.0,允许复制转载,但必须保留译文作者署名及译文链接,不得演绎和用于商业

Loadrunner脚本回放 场景运行过程中常见错误分析

问题一:Loadrunner超时错误问题描述 Loadrunner超时错误:在录制Web协议脚本回放时超时情况经常出现,产生错误的原因也有很多,解决的方法也不同. 问题现象Error -27728: Step download timeout (120 seconds) has expired when downloading non-resource(s). 错误分析对于HTTP协议,默认的超时时间是120秒(可以在LoadRunner中修改),客户端发送一个请求到服务器端,如果超过120秒服