Configuring the Jetson Nano

Background

If you’ve never heard of Nvidia’s Jetson Nano you can think of it as a Raspberry Pi with a built-in GPU; their developer community page has some pretty interesting projects if you’d like to learn more.

Now, you’re only going to get some milage out of the rest of this post if you’ve already setup your Jetson Nano hardware. I set mine up to use the barrel jack for a power source, added a wifi card to the board, and connected it to the Raspberry Pi camera (to collect training data and use for real-time inference).

So, while a number of cool projects with the Jetson Nano exists, I didn’t contribute to any of them so that’s why we’re here. I have this idea that I think could be a pretty amazing applicaiton of deep learning and I want to build out the prototype and what better way to go about it than to create documentation as I go (i.e. fill up this blog with a ton posts). Hopefully, once I get far enough in my endeavors my idea will become more apparent but until then you’ll just have to wait it out and check back in.

Todays Goals - Device Configuartion

  1. Mount a swap file for when the compute load gets a bit heavy on the Jetson

  2. Get my python setup the way I like it

  1. Enable SSH‘ing into the device

Note, all code below can be found in my joys-of-jetson repo.

1. Swap file setup (source code)

You can copy the code below or the repo from git but once you run the script a swap file should be mounted to the Jetson. You’ll need to restart your device for this to take effect.

#!/bin/bash

# 8GB swap file setup 
# Source Ref:
# https://support.rackspace.com/how-to/create-a-linux-swap-file/
# TODO Parameterize memory size
set -e

# Swapiness config
# swapiness values: 0-100
# 0 = swap is used when system is completely out of memory
# Higher values enable system to swap idel prcoesses
SWAPINESS=60 # typical value

echo 'Create swap file and formating'
sudo fallocate -l 8G /mnt/8GB.swap # Create swap file
sudo mkswap /mnt/8GB.swap # Format file
sudo swapon /mnt/8GB.swap # Add to filesystem as swap

echo 'Mounting swap file on boot'
# <file system> <mount point> <type> <options> <dump> <pass>
echo '/mnt/8GB.swap none swap sw 0 0' | sudo tee -a /etc/fstab > /dev/null

echo "Adding swapiness, $SWAPINESS, to sysctl.conf"
echo "vm.swappiness=$SWAPINESS" | sudo tee -a /etc/sysctl.conf > /dev/null

# Show swap status
sudo swapon -s

echo '/mnt/8GB.swap should be active above - Restart Device'

2. Python & Pytorch Setup (source code)

Installing the pytorch wheel can take a bit so I suggest killing any non-essential processes (i.e. chromium, emacs, whatever you’re working with just kill it).

And I know this script is a bit chunky but I figure it’s easier to have this configuation in one place then spread out over different scripts, for record keeping/reproducibility/tidy purposes.

You can walk through it line by line if you want since I added comments but it boils down to a few functions for appending files, installing dependencies, and running a python script to check we can import pytorch and that cuda is available.

#!/bin/bash

appendFile(){
    echo "$1" | sudo tee -a "$2" > /dev/null
}

appendBashrc(){
    FILE="$HOME/.bashrc"

    # Check is string exists in ~/.bashrc
    if ! grep -q "$1" $FILE; then
       appendFile "$1" "$FILE"
       source ~/.bashrc
    else
       echo "$1 exists in $FILE"
    fi
}

PYTORCH_VIRTUAL_ENV_NAME="pytorch"
TORCH_URL="https://nvidia.box.com/shared/static/06vlvedmqpqstu1dym49fo7aapgfyyu9.whl"
TORCH_WHL="torch-1.2.0a0+8554416-cp36-cp36m-linux_aarch64.whl"
TORCH_VISION_VERSION="v0.4.0"

# Setup pip and python3 dev 
sudo apt update \
&& sudo apt-get -y install python3-pip \
libatlas-base-dev gfortran libhdf5-serial-dev hdf5-tools \
python3-dev

# Install virutal environments
sudo pip3 install virtualenv virtualenvwrapper

# Setting virtual env. paths
appendBashrc "WORKON_HOME=$HOME/.virtualenvs"
appendBashrc 'VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3'
appendBashrc 'source /usr/local/bin/virtualenvwrapper.sh'

# In case source ~/.bashrc not working because of scope
VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 
source /usr/local/bin/virtualenvwrapper.sh

mkvirtualenv "$PYTORCH_VIRTUAL_ENV_NAME" -p python3
workon "$PYTORCH_VIRTUAL_ENV_NAME"

# Install pytorch for Jetson
# Source: https://devtalk.nvidia.com/default/topic/1049071/jetson-nano/pytorch-for-jetson-nano-version-1-3-0-now-available/
wget $TORCH_URL -O $TORCH_WHL
pip3 install numpy $TORCH_WHL && rm $TORCH_WHL

# TorchVision
sudo apt-get -y install libjpeg-dev zlib1g-dev
echo 'Starting TorchVision Build - will take a little bit'
git clone --branch $TORCH_VISION_VERSION https://github.com/pytorch/vision torchvision \
&& cd torchvision && sudo python3 setup.py install && cd ..

# https://stackoverflow.com/questions/23929235/multi-line-string-with-extra-space-preserved-indentation
ASSERT_SCRIPT=$(cat <<-END
#!/usr/bin/python3
import sys
if __name__ == "__main__":
    try:
        import torch
        if torch.cuda.is_available():
            sys.exit("true")
    except Exception as e:
        sys.exit(f"false, str(e)")
END
)

# https://vividcode.io/return-value-from-python-script-to-bash-shell/
INSTALLED=$(python3 -c "$ASSERT_SCRIPT" 2>&1 > /dev/null)
echo "PyTorch imported and cuda available: $INSTALLED"

If after running this script you get a something that says PyTorch imported and cuda available: false, <Error> then something went wrong along the way (hopefully, it won’t but feel free to comment if it does). Other wise your PyTorch configuration should be ready to go.

3. SSH’ing into Jetson

Finally, since powering an external monitor can be a bit resource intense I’m going to leave you with a bash command to print out the IP address of the Jetson Nano so you can SSH into it and use whatever editor you prefer/have installed (I use emacs).

The command below might not work on your Jeston specifically but if you have an Intel Dual Band Wireless-Ac 8265 card installed it might work just fine; if it doesn’t work you’ll just have to scour the print out from ifconfig or ip addr show for your Nano’s IP. I commented the command below so you can adjust as needed.

# Show wlan0 portion of IP |
# grep 'inet ' line |
# 'print' the second element from matched 'inet ' grep |
# split string: return 1st element after spliting on delimiter '/'
ip addr show wlan0 | grep 'inet ' | awk '{print $2}' | cut -f1 -d'/'

After you get the IP, go to your work station terminal and ssh <jeson_user_name>@<jetson_ip> and you should be all ready to develop remotely.

The end

Thanks for reading and feel free to comment or suggest corrections.

And here’s a list of sources that helped me bring all of this together:

Comments

comments powered by Disqus