博文

目前显示的是 三月, 2017的博文

用java生tensorflow的tfrecord文件

如果你的training data在hadoop上,那么java恐怕是你做数据预处理的最佳语言。为了在Hadoop上生TFRecord文件,你需要三样东西:

protoc,版本需要和hadoop上的protobuf版本保持一致tensorflow的源代码下面的TFRecordFileWriter
首先运行下面的命令生成protobuf messages的java文件 protoc --proto_path=C:\tensorflow --java_out=. C:\tensorflow\tensorflow\core\example\example.proto
然后把下面这个class添加到你的项目中 package com.bing.imagetool; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import org.tensorflow.example.BytesList; import org.tensorflow.example.Feature; import org.tensorflow.example.FloatList; import org.tensorflow.example.Int64List; import com.google.protobuf.ByteString; public class TFRecordFileWriter implements Closeable { /** * Implements CRC32-C as defined in: "Optimization of Cyclic Redundancy-CHeck Codes with 24 and 32 * Parity Bits", IEEE Transactions on Communications 41(6): 883-892 (1993). * * The implementation of this class has been sourced from the Appe…

盼了多年的“医药分离”终于来了,玩这么多猫腻就为了给医保省钱

现在去医院看病,医院会对药物收15%的加价。比如进价100,卖给病人115。这其中的15块钱就留作利润供医院运转。这样的模式让医生、病人、医保都怨声载道。医院为了利润,就拼命开药,过度医疗。病人每次一去医院就是一张大处方,背一书包的药回来。医保则是想不通,它为什么要出这15%的钱。医生觉得自己很郁闷,做一台手术才几百块钱的手术费,价值得不到体现,还不如跟医药代表合作,多开点吃不死人也没什么疗效的中成药。这其中的弊端谁都知道。于是医药分离提了至少10多年了,国家各种媒体从我上中学提到现在。

那现在的结局是怎样呢?简单点解释是这样:医保说,病人啊,你以后每次看病,来我这领一张价值100元的优惠券,然后凭此券去医院开药,可享受9折优惠,每张券限使用一次。然后医院拿着这个券去找医保报销,把它损失的药费要回来。这个优惠券就叫医事服务费。你觉得这样好吗?

核心问题在于:医保每年给每个病人所能支出的费用是固定的。医保就是个保险,国家基本不出钱,只抽管理费。每个参保人平均来算,交上去的肯定比拿回来的多。差值就是管理费。支出总额固定的情况下,一部分变成了“优惠券”,那么病人能享受到的药品、耗材就必须减少。具体来说,比如挂号费42,医保报销40,个人出2元。那么这些钱,其实就相当于股票基金的赎回费率。你去医院挂号,就相当于是在申请赎回基金,你在申请把你之前存进去的钱拿一部分回来。看病掏的挂号费,赎基金掏的是基金手续费。你不会因为挂号费从5块钱变成42,14变成100,就能因此得到更好的医疗服务。做梦呢。该3分钟打发你还是3分钟打发你。举个例子,北医三院现在是5块钱的挂号费,朝阳医院是42元,你能感受到朝阳医院的医疗服务比北医三院好?或者朝阳医院的医疗服务比它提价之前好?医院虽然诊疗费的收入提高了,但是药费利润没了啊。医保办是纯赚。参保人是亏。

医保办要求再次降低药占比,今年要降低到30%。举个例子,有个老人高血压,以前花5块钱挂号费,就开800的药回来。现在不行了。他要花200块钱挂号费才能开100块钱的药回来。挂号费改革后一次最贵100。他花了100块钱挂最贵的号,只能开50块钱的药。根本不够一周的药费。于是医生只能说,那这样,我给你测个血压,这一项再收你300的服务费,这样就可以开药了。测个血压为什么要300?国家逼的啊。媒体吹了这么久的风说要提高医师服务费,就是因为这个。



bug经历: 物理内存耗尽,但是不知道是哪个进程干的

最近我发现一个很奇怪的事情,tensorflow的windows版有一个很奇怪的内存泄露的bug。我的电脑有16GB内存。但是tensorflow一旦跑起来,机器很快就会内存不足,然后page file频繁的换入换出。但是tensorflow这个进程本身呢,并没有内存泄露。它的堆并没有增长。我用windbg仔细检查过它的所有内存,堆的,栈的,各种类型的,都没有增长。嗯,电脑突然没了10几GB的物理内存,但是tensorflow只占了几百M。我把这个电脑里所有进程的所有内存使用量加起来,也远远不够10GB。我可以肯定是tensorflow干的。因为我一旦把tensorflow的进程杀死,丢失的内存立马就回来了。一旦重新启动tensorflow,内存又逐渐的没了。

最终,我发现,是我的一个美国同事,checkin了一个很糟糕的修改。他给tensorflow的windows file system的实现引入了两个很严重的bug。
他原始的pull request是:https://github.com/tensorflow/tensorflow/pull/5020
第一个被发现的bug是:https://github.com/tensorflow/tensorflow/pull/6805
第二个就是我刚才说的,内存泄露。

sysinternals里有两个工具可以查看内存去哪了。一个是vmmap。是查看单个进程的。另一个是RAMMAP,可以查看物理内存具体被map到哪去了。最终我发现,是以memory mapped file的方式消耗掉了。而那个file就是tensorflow运行时正在读的那个file。

揭秘的时刻来了。原来是它打开文件的时候加了FILE_FLAG_RANDOM_ACCESS参数。然后windows内核在看到这个参数后,就会把所有已读入的内容,一直lock在内存里。参见https://support.microsoft.com/en-us/help/2549369 。 不加这个参数,文件系统也会做cache,但是这部分内存的类型是Standby。加了这个参数,这部分内存就变成了Active状态。

最后,我把这个报告了给tensorflow的github仓库,看看他们准备怎么办。https://github.com/tensorflow/tensorflo…

痛苦的DLL

有时候你必须得用到DLL。

比如,假如你想在python或者java中调用C/C++的code。那么这些native code必须得编译成一个DLL。
再比如,VC对单个exe/lib/pdb的文件大小有2GB的限制,这些限制很容易在debug版中hit到。

最大的麻烦在于将一个DLL拆成多个DLL。windows下要求DLL之间不能有循环依赖。举个例子,假如你实现了一个vfs.dll。这个dlll声明了一个IFileSystem的interface,和一个FileSystemFactory的Singleton。然后在其它的dll中有IFileSystem具体实现。比如hdfs.dll,httpfs.dll,nfs.dll…… 与Linux不同的是,Windows下编译hdfs.dll等这些dll的时候,它所用到的所有符号必须要能找到具体的实现。也就是说,这些dll必须要链接到vfs.dll。vfs.dll必须把所有实现时所需要用到的函数、类、全局变量都导出。举个例子,假设vfs.dll和其它的dll都用到了zlib。那么要么zlib被全部打包进vfs.dll,那么zlib也必须编译成一个dll。否则,如果这些dll都静态链接到zlib,那么zlib中的全局变量就会有多份拷贝。

不是所有的符号都可以导出。一个典型的麻烦例子就是STL里的容器。How to export an instantiation of a Standard Template Library (STL) class and a class that contains a data member that is an STL object . 简单点说:std::string以及STL里除了std::vector以外的所有容器都是不可导出的。所以,一般来讲,DLL的interface里最好不要有STL的数据结构。这个限制挺让人恼火的。

追根溯源,DLL并没有weak symbol这样的东西。于是template class里的静态变量就会在同一个进程里有多份实例,每个dll里都可有一个。一个典型的例子就是std::string::npos。唯一的解决办法就是显式的对模板类实例化。但是对于STL来说,这个过于复杂,不大可能做到。