帖子

tensorflow python script examples

图片
Tensorflow中每个节点的每个输出被称为Tensor。 (Represents one of the outputs of an Operation.)
python中的tf.Tensor只是一个symbolic handle。
下面是tensorflow的一个简单的example
# Build a dataflow graph. c = tf.constant([[1.0, 2.0], [3.0, 4.0]]) d = tf.constant([[1.0, 1.0], [0.0, 1.0]]) e = tf.matmul(c, d) # Construct a `Session` to execute the graph. sess = tf.Session() # Execute the graph and store the value that `e` represents in `result`. result = sess.run(e) #clean up sess.close() 输出:
[[ 1. 3.]
[ 3. 7.]]
上面这段代码中,c,d,e,都是tf.Tensor类型,result是numpy.ndarray类型。矩阵运算是在sess.run()里面执行的。一个graph,就像是数据库里的预编译好的语句(prepared statement),而sess.run()就是执行这个statement。tf.matmul,tf.constant这些都是operation。
就像我们在执行SQL的时候可以塞参数进去一样,执行tensorflow的graph时也是如此。Tensorflow中把这个机制称为Feeding。
Feeding 下面是一个带参数的例子:
import tensorflow as tf # Build a dataflow graph. c = tf.constant([[1.0, 2.0], [3.0, 4.0]]) d = tf.constant([[1.0, 1.0], [0.0, 1.0]]) e = tf.matmul(c, d) # Construct a `Session` to execute the graph. sess = tf.Session() # Execute the…

用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来说,这个过于复杂,不大可能做到。




纯C++的tensorflow trainer

今天写了一个纯C++的tensorflow trainer。大体来讲,main函数里要干这么几件事情:

创建grpc serverload MetaGraph创建session,执行init OP从meta graph得到queue def,创建并运行queue执行training loopsave model 这里的meta graph是用python生成的。主要是因为C++的API还没有把auto gradient做完善。不仅如此,目前用C++构造graph的代码远远比python复杂,没有任何优势。
training loop的跳出方式有两种。 一种是等待抛出out of range错误。这个在C++中可以通过检查run方法的返回值,在python中可以catch异常。 另一种是显式的设置step个数。这种一般需要预先知道有多少training samples。sample_count * iteration_count/mini_batch_size就可以得到max step。这种通常用于需要按iteration调节learning rate的场景。
唔,折腾一半天有啥实际好处呢?我拿alexnet在没有GPU的机器上试了下,performance并没有什么差别。主要是因为对于这样的复杂的网络结构,python层所占的cost很小。我准备明天再在有GPU的机器上试一试看。

mysql jdbc client端也加了一个maxAllowedPacket参数

不知道这是从哪个版本开始的,mysql jdbc client端也加了一个maxAllowedPacket参数。
所以我一再的修改server上的 max_allowed_packet 设置都没有用。

mysql> show global variables like '%packet%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| max_allowed_packet       | 16777216   |
| slave_max_allowed_packet | 1073741824 |
+--------------------------+------------+
2 rows in set (0.00 sec)


java里还是报告

Caused by: com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (100,152 > 65,535). You can change this value on the server by setting the 'max_allowed_packet' variable.
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:100)
at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:1983)
at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:1936)
at com.mysql.cj.jdbc.StatementImpl.executeQuery(StatementImpl.java:1422)

FUCK!

解决办法就是client端也得改