在Java中调用Python函数:基于socket的方法

最近想写一个算法,考虑到执行效率和开发效率,准备使用Java来实现,不过在算法执行过程中我打算使用基于pytorch的神经网络,此时就涉及如何在Java语言中执行Python程序。

最简单的想法当然就是直接使用命令行调用:Runtime.getRuntime().exec("python xxx.py --yyy zzz"),但是这种方式每次调用python脚本都需要重启python解释器以及重新将pytorch神经网络加载进内存,如果调用频繁的话就会非常耗时,因此并不合适。

更好的方式是让两个程序通过网络来通信,python可以启动时加载好神经网络,之后就开一个socket服务等待请求,让java程序把参数通过socket发给python程序,然后python拿到参数后执行函数,再把返回值发送回java即可。python程序并不退出,因此就不需要重复神经网络的加载过程了。而且基于socket可以让java和python跑在不同的机器上。

Read More »

我该装什么CUDA版本的pytorch-gpu

也许你疑惑过对于自己电脑中的NVIDIA显卡型号,应该装什么CUDA版本的pytroch-gpu。结论是太老或者太新的CUDA版本都不行,一个显卡型号能支持的CUDA版本是一个有限的范围。

首先打开NVIDIA控制面板,点击“帮助->系统信息->组件”,能够看到NVCUDA.dll后面的一个CUDA版本,这个就是当前驱动程序支持的最大CUDA版本,如果你升级了驱动,可能会支持更高的CUDA版本,也可能不会提升。

而当你想跑别人的一份远古pytorch版本的代码时,也许你会发现对于新型号显卡如果安装太老CUDA版本的pytorch-gpu也会无法调用GPU(调用GPU会报错),实际上一个显卡型号支持的CUDA版本也有下限。

Read More »

Windows中C语言与Java的汉字编码问题

你是否遇到过C语言或者Java程序中的汉字字符串输出为乱码的现象,也许你去查询过解决办法,得到的结论就是简单地把源码文件转换为GBK编码存储,然而并未深思其中的原因。本文会解释其原因以及正确的应对方式(不转换源码的编码)。首先明确本文的操作环境:Windows操作系统(中文)、C语言编译器为MinGW-GCC。下面给出两个示例程序:

// a.c(utf-8)
#include <stdio.h>

int main(void)
{
    printf("%s", "你好");
    return 0;
}
// a.java(utf-8)

public class a {
    public static void main(String[] args) {
        System.out.println("你好");
    }
}

以上源码文件均使用UTF-8编码,然后我们打开PowerShell,编译两个文件:gcc a.cjavac a.java,然后运行:.\a.exejava a,会发现输出的均不是“你好”,而是乱码的“浣犲ソ”。实际上,以UTF-8编码的“你好”和以GBK编码的“浣犲ソ”的二进制序列是一样的(E4 BD A0 E5 A5 BD),你发现其中端倪了吗?

Read More »

个人电子书分享

我现在基本上告别了纸质书籍,看书都是用PC(Adobe Acrobat),需要手写的话就用手写板。手里的电子书大部分都是从Z-Library下载的,有一些是去淘宝购买的超星扫描PDF,还有少量是自己以前在异步社区图灵社区买的正版PDF。为了方便阅读,我存下来的PDF都做了个人的规范化处理,比如设置格式化页码(对齐纸质书页码,方便直接输入页码跳转),规范化书签目录还有纸张大小(大部分调整为16开)等等。

Read More »

Pytorch debug经验之RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation

有一次,我在自己写的关于“神经组合优化”的项目中遭遇报错:

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [CUDABoolType [1024, 21]] is at version 139; expected version 138 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).

此报错令人一头雾水,因为抛出异常的位置位于loss.backward(),显然跟真正出问题的地方相去甚远,而其他有价值的信息就只有关于问题张量的数据类型与形状,所以想要进行问题定位还是比较困难的。

Read More »

C语言与C++中关于内联函数的陷阱

C语言的内联函数默认为内部链接,所以不阻止其他文件定义同名外部函数。但如果在其他文件中定义了同名外部函数,则在定义内联函数的文件中调用此函数属于未指定行为,该调用可能会调用外部函数。

注意由于在一个文件中调用函数前需要声明,并且该声明不能和定义冲突,所以即便外部函数与内联函数的原型不同,也做不到在定义内联函数的文件中声明此外部函数,因为对外部函数的声明会和内联函数的定义冲突。此时如果在定义内联函数的文件中又实际调用了外部函数,则调用形式不满足外部函数的实际定义,行为更加危险。

Read More »

C++中explicit的复制构造函数是什么意思

在C++中,对于一个类中只接受一个实参的构造函数,相当于定义了从实参类型到此类型的隐式转换机制。而将这个构造函数声明为explicit的话,则会禁止这样的隐式转换,这个构造函数将无法被隐式调用,而是只能用来直接初始化。

这样就引出一个问题:如果复制构造函数(接受一个const 本类型& 的实参)被声明为explicit,代表什么意思?是说不允许隐式调用复制构造函数了吗?而用等号来对这类对象进行复制初始化时,等号右边的对象总是要先转换为本类型,之后再隐式调用复制构造函数,如果是这样的话,那是不是意味着我们将无法再进行复制初始化,而是只能用直接初始化的方式直接调用此复制构造函数了呢?

Read More »

《计算机系统要素》书评

本书豆瓣页面:https://book.douban.com/subject/1998341

本书的副标题是“从零开始构建现代计算机”,听起来似乎目标过于宏大,不太可能在一本只有300页的书中讲完,然而本书作者真的做到了,此书的内容设计十分精妙,构建的系统可谓是“麻雀虽小,五脏俱全”。本书并非将全部内容放在了纸面文字当中,而是通过书中文字与作者设计的项目来引导读者动手操作,因此阅读此书时应当在电脑上亲自完成书中所介绍的项目,方能体会到其精髓。

我已将本书项目全部完成,本书后半部分的汇编器、虚拟机和编译器项目是使用python写的。全部项目答案已上传至github:https://github.com/ci-ke/nand2tetris-solutions

Read More »

使用torchvision.datasets下载数据集时如何借助代理

比如使用pytorch下载数据集时:

trans = transforms.ToTensor()
mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(root="../data", train=False, transform=trans, download=True)

如果直连网络状况不好,则下载会很慢,此时我们可以通过urllib模块配置代理:

Read More »