Parallel Programming using MPI in Python

This post introduces Parallel Programming using MPI in Python.

The library is mpi4py (MPI and python extensions of MPI), see here for its code repo on bitbucket.

Laurent Duchesne provides an excellent step-by-step guide for parallelizing your Python code using multiple processors and MPI. Craig Finch has a more practical example for high throughput MPI on GitHub. See here for more mpi4py examples from Craig Finch.

An example of TensorFlow using MPI can be found here.

References:

 

Overcoming frustration: Correctly using unicode in python2

>>> string = unicode(raw_input(), 'utf8')
café
>>> log = open('/var/tmp/debug.log', 'w')
>>> log.write(string)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 3: ordinal not in range(128)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 3: ordinal not in range(128)

Okay, this is simple enough to solve: Just convert to a byte str and we’re all set:

>>> string = unicode(raw_input(), 'utf8')
café
>>> string_for_output = string.encode('utf8', 'replace')
>>> log = open('/var/tmp/debug.log', 'w')
>>> log.write(string_for_output)
>>>

Deal exclusively with unicode objects as much as possible by decoding things to unicode objects when you first get them and encoding them as necessary on the way out.

If your string is actually a unicode object, you’ll need to convert it to a unicode-encoded string object before writing it to a file:

(if you are not sure what is the type of your string. use type(your string) to check it, if it is something looks like u ‘….’, it is a unicode string.)

foo = u'Δ, Й, ק, ‎ م, ๗, あ, 叶, 葉, and 말.'
f = open('test', 'w')
f.write(foo.encode('utf8'))
f.close()

When you read that file again, you’ll get a unicode-encoded string that you can decode to a unicode object:

f = file('test', 'r')
print f.read().decode('utf8')

 

MPI and OpenMP with Python

This post lists resources for using MPI with Python.

An application built with the hybrid model of parallel programming can run on a computer cluster using both OpenMP and Message Passing Interface (MPI), such that OpenMP is used for parallelism within a (multi-core) node while MPI is used for parallelism between nodes. There have also been efforts to run OpenMP on software distributed shared memory systems,[6] to translate OpenMP into MPI[7][8] and to extend OpenMP for non-shared memory systems.

cython.parallel is built on top of OpenMP (see Using Parallelism)

Please read Laurent Duchesne’s excellent step-by-step guide for parallelizing your Python code using multiple processors and MPI.

On our cluster, to run MPI Python programs, mpi4py has been compiled against OpenMPI 1.10.1 therefore we need to load that additional package:

module load python/3.4.3 mpi/openmpi/1.10.1-gcc

Create the the test MPI example file as described in Laurent’s guide above, using the same name mpi.py:

from mpi4py import MPI

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

print("I am rank", rank, "of", size)

Create the SLURM submission script submit.sh:

#SBATCH -n 4 
mpirun python mpi.py

You should get output similar to:

I am rank 3 of 4
I am rank 0 of 4
I am rank 1 of 4
I am rank 2 of 4

Craig Finch has a more practical example for high throughput MPI on GitHub.

 

References:

 

Image format conversion and change of image quality and size using Python

The code to read tif files in a folder and convert them into jpeg automatically (with the same or reduced quality, and with reduced size).

See here for a pretty good handbook of Python Imaging Library (PIL).

import os
from PIL import Image

current_path = os.getcwd()
for root, dirs, files in os.walk(current_path, topdown=False):
    for name in files:
        print(os.path.join(root, name))
        #if os.path.splitext(os.path.join(root, name))[1].lower() == ".tiff":
        if os.path.splitext(os.path.join(root, name))[1].lower() == ".tif":
            if os.path.isfile(os.path.splitext(os.path.join(root, name))[0] + ".jpg"):
                print "A jpeg file already exists for %s" % name
            # If a jpeg with the name does *NOT* exist, covert one from the tif.
            else:
                outputfile = os.path.splitext(os.path.join(root, name))[0] + ".jpg"
                try:
                    im = Image.open(os.path.join(root, name))
                    print "Converting jpeg for %s" % name
                    im.thumbnail(im.size)
                    im.save(outputfile, "JPEG", quality=100)
                except Exception, e:
                    print e

The above code will covert tif files to a jpg file with the same or reduced (change quality number less then 100 to reduce the quality) quality (file size), but the resulted image will keep the same size (the height and width of the image).

To covert tif file to a reduce size, use attribute size and method resize  provided by PIL.

Note that in resize() method, be sure to use ANTIALIAS filter (ANTIALIAS  is a high-quality downsampling filter) unless speed is much more important than quality. The bilinear and bicubic filters in the current version of PIL are not well-suited for large downsampling ratios (e.g. when creating thumbnails).

im = Image.open("my_image.jpg")
size =im.size   # get the size of the input image
ratio = 0.9  # reduced the size to 90% of the input image
reduced_size = int(size[0] * ratio), int(size[1] * ratio)     

im_resized = im.resize(reduced_size, Image.ANTIALIAS)
im_resized.save("my_image_resized.jpg", "JPEG")
#im_resized.save(outputfile, "JPEG", quality=100) # uncomment this line if you want to reduce image size without quality loss.
#im_resized.save(outputfile, "JPEG", quality=100, optimize=True) # uncomment this line if you want to optimize the result image.

Code snippet to save as different dpi

from PIL import Image 
im = Image.open("test.jpg") 
im.save("test_600.jpg", dpi=(600,600) )

Referenced materials:

The Image Module (resize, size, save)

os.path document

Using Python to Reduce JPEG and PNG Image File Sizes Without Loss of Quality (Jan 3, 2015)

http://stackoverflow.com/questions/28870504/converting-tiff-to-jpeg-in-python

Install gensim and nltk into Virtualenv

This post introduces how to install gensim and nltk into a virtualenv. It is always a good strategy to install some package(s)/library(s) you often use (together) into a separate virtualenv, so it will not be interrupted by other libraries (because different libraries may depend on different versions of another libraries).

$ sudo apt-get install python-pip python-dev python-virtualenv
  • Create a Virtualenv environment in the directory for python  ~/gensim-venv:

Note that you can setup your virtualenv in any directory you want — just replace the ~/gensim-venv with your preferred directory path. But be sure to change it accordingly when you follow the rest of the tutorial.

$ virtualenv --system-site-packages -p python ~/gensim-venv # for python 

$ virtualenv --system-site-packages -p python3 ~/gensim-venv3 # for python 3, it is better to add "venv3" when naming your virtualenv, so you know it is for python3

The --system-site-packages Option

If you build with virtualenv --system-site-packages ENV, your virtual environment will inherit packages from /usr/lib/python2.7/site-packages(or wherever your global site-packages directory is).

This can be used if you have control over the global site-packages directory, and you want to depend on the packages there. If you want isolation from the global system, do not use this flag (and note that if you do not use the “system-site-packages” flag, you NEED to install the version of the python you need in the virtualenv that you just created)

  • Activate the virtual environment:
$ source ~/gensim-venv/bin/activate  # If using bash
(gensim-venv)$  # Your prompt should change
  • Install gensim in the virtualenv for python:
pip install --upgrade gensim
  • After the install you will activate the Virtualenv environment each time you want to use gensim.
  • With the Virtualenv environment activated, you can now test your gensim installation.
  •  When you are done using gensim, deactivate the environment.
(gensim-venv)$ deactivate

$  # Your prompt should change back

To use gensim later you will have to activate the Virtualenv environment again:

$ source ~/gensim-venv/bin/activate  # If using bash.

(gensim-venv)$  # Your prompt should change.
# Run Python programs that use gensim.
...
# When you are done using gensim, deactivate the environment.
(gensim-venv)$ deactivate
  • To delete a virtual environment, just delete its folder. (In this case, it would be rm -rf gensim-venv.)
  • To install nltk into the virtualenv gensim-venv, just issue this command after you activated the gensim-venv
(gensim-venv)$ pip install -U nltk

Note: you may notice that those commands issued inside a virtualenv (i.e., after you create a virtualenv and activated it), you do not need to add sudo before the commands. Because all those commands will all be confined within that virtualenv folder you created – that is why  it will not affect other packages installed in other virtualenv or system-wide, and it will not be affected by other packages installed in another virtualenv(s). You can create as many as virtualenv you want, so please naming your virtualenv with meaning name, otherwise, over time, we will forget what was actually being installed in some virtualenv:)

 

Books and Courses and Tutorials: Python

This page provides some useful resources (books and courses) with Python. (See this post for text processing related resources, and this post for a collection of python packages and related resources)

(I have created a page for this topic, so stop editing this post, BUT KEEP this post, because not every book on this page has been moved to the page.)

Read file from line 2 or skip header row in Python

This post introduces how to read file from line 2 in Python.

  • method 1:
with open(fname) as f:
  next(f)
  for line in f:
    #do something

Note: If you need the header later, instead of next(f) use f.readline() and store it as a variable.
Or use header_line = next(f).

  • method 2
f = open(fname,'r')
lines = f.readlines()[1:]
f.close()

This will skip 1 line. for example, [‘a’, ‘b’, ‘c’][1:] => [‘b’, ‘c’]

 

Find which version of TensorFlow was installed

This depends on how you installed TensorFlow.

Pip installation

Run:

python -c 'import tensorflow as tf; print(tf.__version__)'  # for Python 2
python3 -c 'import tensorflow as tf; print(tf.__version__)'  # for Python 3

Note that python is symlinked to /usr/bin/python3 in some Linux distributions, so use pythoninstead of python3 in these cases.

pip list | grep tensorflow for Python 2 or pip3 list | grep tensorflow for Python 3 will also show the version of Tensorflow installed.

Virtualenv installation

Run:

python -c 'import tensorflow as tf; print(tf.__version__)'  # for both Python 2 and Python 3

pip list | grep tensorflow will also show the version of Tensorflow installed.

Examples

For example, I have installed TensorFlow 0.12.1 in a virtualenv for Python 3. So, I get:

and installed TensorFlow from source for Python 2 (not in a virtualenv).

Referenced:

Install TensorFlow for Python 2.7 and Python 3.5 on the same machine (Ubuntu 16.04)

I already installed GPU TensorFlow from source for Python 2 (see this post), and now I would like to also install GPU TensorFlow for Python 3 on the same machine using Virtualenv.

Virtualenv is a tool to keep the dependencies required by different Python projects in separate places. The Virtualenv installation of TensorFlow will not override pre-existing version of the Python packages needed by TensorFlow. See here for a detailed introduction of how virtualenv works and some basic usage.

With Virtualenv the installation is as follows:

  • Install pip and Virtualenv:
$ sudo apt-get update
$ sudo apt-get install python-pip python-dev python-virtualenv
  • Create a Virtualenv environment in the directory for python 3 ~/tensorflow-venv3:
$ virtualenv --system-site-packages -p python3 ~/tensorflow-venv3 

#for python 2
$ virtualenv --system-site-packages -p python ~/tensorflow-venv 

The --system-site-packages Option

If you build with virtualenv --system-site-packages ENV, your virtual environment will inherit packages from /usr/lib/python2.7/site-packages (or wherever your global site-packages directory is).

This can be used if you have control over the global site-packages directory, and you want to depend on the packages there. If you want isolation from the global system, do not use this flag.

  • Activate the virtual environment:
$ source ~/tensorflow-venv3/bin/activate  # If using bash
(tensorflow-venv3)$  # Your prompt should change
  • Install TensorFlow in the virtualenv for python 3:

Now, install TensorFlow just as you would for a regular Pip installation. First select the correct binary to install (from this page):

# Ubuntu/Linux 64-bit, GPU enabled, Python 3.5
# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.
(tensorflow-venv3)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.1-cp35-cp35m-linux_x86_64.whl
# Python 2
(tensorflow-venv2)$ pip install --upgrade $TF_BINARY_URL

# Python 3
(tensorflow-venv3)$ pip3 install --upgrade $TF_BINARY_URL

Or you can choose the .whl file you built from source by yourself. Like the one I built in the post GPU tensorflow installation from source

# Python 2 pip install /path to/the .whl file you built from source/tensorflow-0.12.1-cp27-cp27mu-linux_x86_64.whl # Python 3 pip3 install /path to/the .whl file you built from source/tensorflow-0.12.1-cp27-cp27mu-linux_x86_64.whl

Note that when I used the .whl file I built to intall tensorflow into the virtualenv, I met this error. So I ended up installing the binary file from this page.

pip3 install ~/tensorflow_pkg/tensorflow-0.12.1-cp27-cp27mu-linux_x86_64.whl 
tensorflow-0.12.1-cp27-cp27mu-linux_x86_64.whl is not a supported wheel on this platform.
# Ubuntu/Linux 64-bit, GPU enabled, Python 3.5
# Requires CUDA toolkit 8.0 and CuDNN v5. For other versions, see "Installing from sources" below.
(tensorflow-venv3)$ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.1-cp35-cp35m-linux_x86_64.whl
  • After the install you will activate the Virtualenv environment each time you want to use TensorFlow.
  • With the Virtualenv environment activated, you can now test your TensorFlow installation.

In your virtualenv, open a python session and type import tensorflow as tf.

If all went well, you should see the following output:

Python 3.5.2 (default, Nov 17 2016, 17:05:23) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcurand.so locally
>>>
  •  When you are done using TensorFlow, deactivate the environment.
    (tensorflow-venv3)$ deactivate
    
    $  # Your prompt should change back
    

To use TensorFlow later you will have to activate the Virtualenv environment again:

$ source ~/tensorflow-venv3/bin/activate  # If using bash.

(tensorflow-venv3)$  # Your prompt should change.
# Run Python programs that use TensorFlow.
...
# When you are done using TensorFlow, deactivate the environment.
(tensorflow-venv3)$ deactivate
  • To delete a virtual environment, just delete its folder. (In this case, it would be rm -rf tensorflow-venv3.)

You can test whether both TensorFlow installed in python 2 and python 3 works. See below for my example.

 

Posts I referenced:

Open multiple files using “open ” and “with open” in Python

This post introduces two ways to open multiple files in Python.

  • “with open” # do not need to bother to close the file(s) if use “with open”
with open("datafile.csv" , "r") as f:
  f.read()
with open("datafile2.csv" , "r") as f2:
  f2.read()

Or

try:
  with open('file.csv', 'w') as f, open('file2.csv', 'w') as f2:
    do_something()
except IOError as e:
  print 'Operation failed: %s' % e.strerror
  • “open”  # need to close the file when use open.
f = open("datafile.csv" , "r")
f2 = open("datafile2.csv" , "r")
f.read()
f2.read()
f.close()
f2.close()

 

References: