master 4c22eac01ee8 cached
67 files
135.4 KB
40.6k tokens
20 symbols
1 requests
Download .txt
Repository: NegatioN/OnlineMiningTripletLoss
Branch: master
Commit: 4c22eac01ee8
Files: 67
Total size: 135.4 KB

Directory structure:
gitextract_53kablsc/

├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── docs/
│   ├── .gitignore
│   ├── Gemfile
│   ├── _config.yml
│   ├── _data/
│   │   ├── alerts.yml
│   │   ├── definitions.yml
│   │   ├── glossary.yml
│   │   ├── sidebars/
│   │   │   └── home_sidebar.yml
│   │   ├── tags.yml
│   │   ├── terms.yml
│   │   └── topnav.yml
│   ├── _includes/
│   │   ├── archive.html
│   │   ├── callout.html
│   │   ├── footer.html
│   │   ├── google_analytics.html
│   │   ├── head.html
│   │   ├── head_print.html
│   │   ├── image.html
│   │   ├── important.html
│   │   ├── initialize_shuffle.html
│   │   ├── inline_image.html
│   │   ├── links.html
│   │   ├── note.html
│   │   ├── search_google_custom.html
│   │   ├── search_simple_jekyll.html
│   │   ├── sidebar.html
│   │   ├── tip.html
│   │   ├── toc.html
│   │   ├── topnav.html
│   │   └── warning.html
│   ├── _layouts/
│   │   ├── default.html
│   │   ├── default_print.html
│   │   ├── none.html
│   │   ├── page.html
│   │   └── page_print.html
│   ├── css/
│   │   ├── boxshadowproperties.css
│   │   ├── customstyles.css
│   │   ├── fonts/
│   │   │   └── FontAwesome.otf
│   │   ├── modern-business.css
│   │   ├── printstyles.css
│   │   ├── syntax.css
│   │   ├── theme-blue.css
│   │   └── theme-green.css
│   ├── feed.xml
│   ├── fonts/
│   │   └── FontAwesome.otf
│   ├── index.html
│   ├── js/
│   │   ├── customscripts.js
│   │   ├── jekyll-search.js
│   │   └── toc.js
│   ├── licenses/
│   │   ├── LICENSE
│   │   └── LICENSE-BSD-NAVGOCO.txt
│   ├── sidebar.json
│   ├── sitemap.xml
│   ├── tooltips.json
│   └── triplet_loss.html
├── index.ipynb
├── online_triplet_loss/
│   ├── __init__.py
│   ├── _nbdev.py
│   └── losses.py
├── settings.ini
├── setup.py
└── triplet_loss.ipynb

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - uses: actions/setup-python@v1
      with:
        python-version: '3.6'
        architecture: 'x64'
    - name: Install the library
      run: |
        pip install nbdev jupyter
        pip install -e .
    - name: Read all notebooks
      run: |
        nbdev_read_nbs
    - name: Check if all notebooks are cleaned
      run: |
        echo "Check we are starting with clean git checkout"
        if [ -n "$(git status -uno -s)" ]; then echo "git status is not clean"; false; fi
        echo "Trying to strip out notebooks"
        nbdev_clean_nbs
        echo "Check that strip out was unnecessary"
        git status -s # display the status to see which nbs need cleaning up
        if [ -n "$(git status -uno -s)" ]; then echo -e "!!! Detected unstripped out notebooks\n!!!Remember to run nbdev_install_git_hooks"; false; fi
    - name: Check if there is no diff library/notebooks
      run: |
        if [ -n "$(nbdev_diff_nbs)" ]; then echo -e "!!! Detected difference between the notebooks and the library"; false; fi
    - name: Run tests
      run: |
        nbdev_test_nbs


================================================
FILE: .gitignore
================================================
.last_checked
.idea/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so
.gitconfig
.gitattributes

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/


================================================
FILE: CONTRIBUTING.md
================================================
# How to contribute

## How to get started

Before anything else, please install the git hooks that run automatic scripts during each commit and merge to strip the notebooks of superfluous metadata (and avoid merge conflicts). After cloning the repository, run the following command inside it:
```
nbdev_install_git_hooks
```

## Did you find a bug?

* Ensure the bug was not already reported by searching on GitHub under Issues.
* If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
* Be sure to add the complete error messages.

#### Did you write a patch that fixes a bug?

* Open a new GitHub pull request with the patch.
* Ensure that your PR includes a test that fails without your patch, and pass with it.
* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.

## PR submission guidelines

* Keep each PR focused. While it's more convenient, do not combine several unrelated fixes together. Create as many branches as needing to keep each PR focused.
* Do not mix style changes/fixes with "functional" changes. It's very difficult to review such PRs and it most likely get rejected.
* Do not add/remove vertical whitespace. Preserve the original style of the file you edit as much as you can.
* Do not turn an already submitted PR into your development playground. If after you submitted PR, you discovered that more work is needed - close the PR, do the required work and then submit a new PR. Otherwise each of your commits requires attention from maintainers of the project.
* If, however, you submitted a PR and received a request for changes, you should proceed with commits inside that PR, so that the maintainer can see the incremental fixes and won't need to review the whole PR again. In the exception case where you realize it'll take many many commits to complete the requests, then it's probably best to close the PR, do the work and then submit it again. Use common sense where you'd choose one way over another.

## Do you want to contribute to the documentation?

* Docs are automatically created from the notebooks in the nbs folder.



================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) [2019] [Joakim Rishaug]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: Makefile
================================================
SRC = $(wildcard lib/*.ipynb)

all: "online_triplet_loss" docs

"online_triplet_loss": $(SRC)
	nbdev_build_lib
	touch "online_triplet_loss"

docs_serve: docs
	cd docs && bundle exec jekyll serve

docs: $(SRC)
	nbdev_build_docs
	touch docs

test:
	nbdev_test_nbs

release: pypi
	nbdev_bump_version

pypi: dist
	twine upload --repository pypi dist/*

dist: clean
	python setup.py sdist bdist_wheel

clean:
	rm -rf dist

================================================
FILE: README.md
================================================
# online_triplet_loss
> PyTorch conversion of the excellent post on the <a href='https://omoindrot.github.io/triplet-loss'>same topic in Tensorflow</a>. Simply an implementation of a triple loss with online mining of candidate triplets used in semi-supervised learning.


## Install

`pip install online_triplet_loss`

Then import with:
`from online_triplet_loss.losses import *`

PS: Requires Pytorch version 1.1.0 or above to use.

## How to use

In these examples I use a really large margin, since the embedding space is so small. A more realistic margins seems to be between `0.1 and 2.0`

```
from torch import nn
import torch

model = nn.Embedding(10, 10)
```

```
#from online_triplet_loss.losses import *
labels = torch.randint(high=10, size=(5,)) # our five labels

embeddings = model(labels)
print('Labels:', labels)
print('Embeddings:', embeddings)
loss = batch_hard_triplet_loss(labels, embeddings, margin=100)
print('Loss:', loss)
loss.backward()
```

    Labels: tensor([6, 1, 3, 6, 6])
    Embeddings: tensor([[-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
              0.0180, -0.4500],
            [ 1.0757, -0.8420, -0.7630, -0.0746,  1.1545,  0.4017,  0.5587,  1.7947,
              0.1992, -2.2288],
            [ 0.2646,  1.2383,  0.1949,  0.5743, -0.8460, -0.9929, -2.0350,  0.2095,
              0.2129, -0.4855],
            [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
              0.0180, -0.4500],
            [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
              0.0180, -0.4500]], grad_fn=<EmbeddingBackward>)
    Loss: tensor(95.1271, grad_fn=<MeanBackward0>)


```
#from online_triplet_loss.losses import *
embeddings = model(labels)
print('Labels:', labels)
print('Embeddings:', embeddings)
loss, fraction_pos = batch_all_triplet_loss(labels, embeddings, squared=False, margin=100)
print('Loss:', loss)
loss.backward()
```

    Labels: tensor([6, 1, 3, 6, 6])
    Embeddings: tensor([[-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
              0.0180, -0.4500],
            [ 1.0757, -0.8420, -0.7630, -0.0746,  1.1545,  0.4017,  0.5587,  1.7947,
              0.1992, -2.2288],
            [ 0.2646,  1.2383,  0.1949,  0.5743, -0.8460, -0.9929, -2.0350,  0.2095,
              0.2129, -0.4855],
            [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
              0.0180, -0.4500],
            [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
              0.0180, -0.4500]], grad_fn=<EmbeddingBackward>)
    tensor(94.9947, grad_fn=<DivBackward0>) tensor(1.)
    Loss: tensor(94.9947, grad_fn=<DivBackward0>)


## References
* [Triplet Loss and Online Triplet Mining in Tensorflow](https://github.com/omoindrot/tensorflow-triplet-loss)
* [Facenet paper](https://arxiv.org/abs/1503.03832)
* [adambielski's nice implementation](https://github.com/adambielski/siamese-triplet) (unfortunately context switches between CPU / GPU)


================================================
FILE: docs/.gitignore
================================================
_site/


================================================
FILE: docs/Gemfile
================================================
source "https://rubygems.org"

gem 'github-pages', group: :jekyll_plugins


# Added at 2019-11-25 10:11:40 -0800 by jhoward:
gem "jekyll", "~> 3.7"


================================================
FILE: docs/_config.yml
================================================
repository: "NegatioN/OnlineMiningTripletLoss"
output: web
topnav_title: "online_triplet_loss"
site_title: "online_triplet_loss"
company_name: "Joakim Rishaug"
description: "Online mining triplet losses for Pytorch"
# Set to false to disable KaTeX math
use_math: true
# Add Google analytics id if you have one and want to use it here
google_analytics:
# See http://nbdev.fast.ai/search for help with adding Search
google_search:

host: 127.0.0.1
# the preview server used. Leave as is.
port: 4000
# the port where the preview is rendered.

exclude:
  - .idea/
  - .gitignore
  - vendor
 
exclude: [vendor]

highlighter: rouge
markdown: kramdown
kramdown:
 input: GFM
 auto_ids: true
 hard_wrap: false
 syntax_highlighter: rouge

collections:
  tooltips:
    output: false

defaults:
  -
    scope:
      path: ""
      type: "pages"
    values:
      layout: "page"
      comments: true
      search: true
      sidebar: home_sidebar
      topnav: topnav
  -
    scope:
      path: ""
      type: "tooltips"
    values:
      layout: "page"
      comments: true
      search: true
      tooltip: true

sidebars:
- home_sidebar
permalink: pretty

theme: jekyll-theme-cayman
baseurl: /OnlineMiningTripletLoss/

================================================
FILE: docs/_data/alerts.yml
================================================
tip: '<div class="alert alert-success" role="alert"><i class="fa fa-check-square-o"></i> <b>Tip: </b>'
note: '<div class="alert alert-info" role="alert"><i class="fa fa-info-circle"></i> <b>Note: </b>'
important: '<div class="alert alert-warning" role="alert"><i class="fa fa-warning"></i> <b>Important: </b>'
warning: '<div class="alert alert-danger" role="alert"><i class="fa fa-exclamation-circle"></i> <b>Warning: </b>'
end: '</div>'

callout_danger: '<div class="bs-callout bs-callout-danger">'
callout_default: '<div class="bs-callout bs-callout-default">'
callout_primary: '<div class="bs-callout bs-callout-primary">'
callout_success: '<div class="bs-callout bs-callout-success">'
callout_info: '<div class="bs-callout bs-callout-info">'
callout_warning: '<div class="bs-callout bs-callout-warning">'

hr_faded: '<hr class="faded"/>'
hr_shaded: '<hr class="shaded"/>'

================================================
FILE: docs/_data/definitions.yml
================================================



================================================
FILE: docs/_data/glossary.yml
================================================



================================================
FILE: docs/_data/sidebars/home_sidebar.yml
================================================

#################################################
### THIS FILE WAS AUTOGENERATED! DO NOT EDIT! ###
#################################################
# Instead edit ../../sidebar.json
entries:
- folders:
  - folderitems:
    - output: web,pdf
      title: Overview
      url: /
    - output: web,pdf
      title: Losses
      url: /triplet_loss
    output: web
    title: online_triplet_loss
  output: web
  title: Sidebar


================================================
FILE: docs/_data/tags.yml
================================================
allowed-tags:
  - getting_started
  - navigation


================================================
FILE: docs/_data/terms.yml
================================================


================================================
FILE: docs/_data/topnav.yml
================================================
topnav:
- title: Topnav
  items:
    - title: GitHub
      external_url: https://github.com/"NegatioN"/"online_triplet_loss"

#Topnav dropdowns
topnav_dropdowns:
- title: Topnav dropdowns
  folders:

================================================
FILE: docs/_includes/archive.html
================================================
---
layout: default
type: archive
---

<div class="post-header">
  <h1 class="post-title-main">{{ page.title }}</h1>
</div>
<div class="post-content">

{{ content }}
</div>

 



================================================
FILE: docs/_includes/callout.html
================================================
<div markdown="span" class="bs-callout bs-callout-{{include.type}}">{{include.content}}</div>


================================================
FILE: docs/_includes/footer.html
================================================
<footer>
            <div class="row">
                <div class="col-lg-12 footer">
                  <p><img src="{{ "/images/company_logo.png" | prepend: site.baseurl }}" alt="Company logo"/></p>
               &copy;{{ site.time | date: "%Y"  }} {{site.company_name}}. All rights reserved. <br />
{% if page.last_updated %}<span>Page last updated:</span> {{page.last_updated}}<br/>{% endif %} Site last generated: {{ site.time | date: "%b %-d, %Y"  }} <br />
                </div>
            </div>
</footer>


================================================
FILE: docs/_includes/google_analytics.html
================================================
<!-- the google_analytics_id gets auto inserted from the config file -->

{% if site.google_analytics %}

<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create','{{site.google_analytics}}','auto');ga('require','displayfeatures');ga('send','pageview');</script>
{% endif %}

================================================
FILE: docs/_includes/head.html
================================================
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="{% if page.summary %}{{ page.summary | strip_html | strip_newlines | truncate: 160 }}{% endif %}">
<meta name="keywords" content="{{page.tags}}{% if page.tags %}, {% endif %} {{page.keywords}}">
<title>{{ page.title }} | {{ site.site_title }}</title>
<link rel="stylesheet" href="{{ "/css/syntax.css" | prepend: site.baseurl }}">

<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!--<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">-->
<link rel="stylesheet" href="{{ "/css/modern-business.css" | prepend: site.baseurl }}">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="{{ "/css/customstyles.css" | prepend: site.baseurl }}">
<link rel="stylesheet" href="{{ "/css/boxshadowproperties.css" | prepend: site.baseurl }}">
<!-- most color styles are extracted out to here -->
<link rel="stylesheet" href="{{ "/css/theme-blue.css" | prepend: site.baseurl }}">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="{{ "/js/jquery.navgoco.min.js" | prepend: site.baseurl }}"></script>

{% if site.use_math %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/contrib/auto-render.min.js" integrity="sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
  renderMathInElement( document.body, {
    delimiters: [
      {left: "$$", right: "$$", display: true},
      {left: "[%", right: "%]", display: true},
      {left: "$", right: "$", display: false}
    ]}
  );
});
</script>
{% endif %}

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!-- Anchor.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/2.0.0/anchor.min.js"></script>
<script src="{{ "/js/toc.js" | prepend: site.baseurl }}"></script>
<script src="{{ "/js/customscripts.js" | prepend: site.baseurl }}"></script>

<link rel="shortcut icon" href="{{ "/images/favicon.ico?"  | prepend: site.baseurl }}">

<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->

<link rel="alternate" type="application/rss+xml" title="{{ site.title }}" href="{{ "/feed.xml" | prepend: site.baseurl | prepend: site.url }}">



================================================
FILE: docs/_includes/head_print.html
================================================
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="{% if page.summary %}{{ page.summary | strip_html | strip_newlines | truncate: 160 }}{% endif %}">
<meta name="keywords" content="{{page.tags}}{% if page.tags %}, {% endif %} {{page.keywords}}">
<title>{% if page.homepage == true %} {{site.homepage_title}} {% elsif page.title %}{{ page.title }}{% endif %}  | {{ site.site_title }}</title>


<link rel="stylesheet" href="{{ "/css/syntax.css" | prepend: site.baseurl | prepend: site.url }}">
<link rel="stylesheet" href="{{ "/css/font-awesome.min.css" | prepend: site.baseurl | prepend: site.url }}">
<link rel="stylesheet" href="{{ "/css/bootstrap.min.css" | prepend: site.baseurl | prepend: site.url }}">
<link rel="stylesheet" href="{{ "/css/modern-business.css" | prepend: site.baseurl | prepend: site.url }}">
<link rel="stylesheet" href="{{ "/css/customstyles.css" | prepend: site.baseurl | prepend: site.url }}">
<link rel="stylesheet" href="{{ "/css/theme-blue.css" | prepend: site.baseurl | prepend: site.url }}">
<link rel="stylesheet" href="{{ "/css/syntax.css" | prepend: site.baseurl | prepend: site.url }}">
<link rel="stylesheet" href="{{ "/css/printstyles.css" | prepend: site.baseurl }}">

<script>
    Prince.addScriptFunc("datestamp", function() {
        return "PDF last generated: {{ site.time | date: '%B %d, %Y' }}";
    });
</script>

<script>
    Prince.addScriptFunc("guideName", function() {
        return "{{site.print_title}} User Guide";
    });
</script>


================================================
FILE: docs/_includes/image.html
================================================
<figure>{% if {{include.url}} %}<a class="no_icon" target="_blank" href="{{include.url}}">{% endif %}<img class="docimage" src="{{include.file}}" alt="{{include.alt}}" {% if {{include.max-width}} %}style="max-width: {{include.max-width}}px"{% endif %} />{% if {{include.url}} %}</a>{% endif %}{% if {{include.caption}} %}<figcaption>{{include.caption}}</figcaption>{% endif %}</figure>


================================================
FILE: docs/_includes/important.html
================================================
<div markdown="span" class="alert alert-warning" role="alert"><i class="fa fa-warning"></i> <b>Important:</b> {{include.content}}</div>

================================================
FILE: docs/_includes/initialize_shuffle.html
================================================
<script type="text/javascript">
$(document).ready(function() {
    $('#toc').toc({ minimumHeaders: 0, listType: 'ul', showSpeed: 0, headers: 'h2,h3,h4' });
});

</script>
<!-- shuffle -->
<script>
var shuffleme = (function( $ ) {
  'use strict';

  var $grid = $('#grid'),
      $filterOptions = $('.filter-options'),
      $sizer = $grid.find('.shuffle_sizer'),

  init = function() {

    // None of these need to be executed synchronously
    setTimeout(function() {
      listen();
      setupFilters();
    }, 100);

    // instantiate the plugin
    $grid.shuffle({
      itemSelector: '[class*="col-"]',
      sizer: $sizer    
    });
  },

  // Set up button clicks
  setupFilters = function() {
    var $btns = $filterOptions.children();
    $btns.on('click', function() {
      var $this = $(this),
          isActive = $this.hasClass( 'active' ),
          group = isActive ? 'all' : $this.data('group');

      // Hide current label, show current label in title
      if ( !isActive ) {
        $('.filter-options .active').removeClass('active');
      }

      $this.toggleClass('active');

      // Filter elements
      $grid.shuffle( 'shuffle', group );
    });

    $btns = null;
  },

  // Re layout shuffle when images load. This is only needed
  // below 768 pixels because the .picture-item height is auto and therefore
  // the height of the picture-item is dependent on the image
  // I recommend using imagesloaded to determine when an image is loaded
  // but that doesn't support IE7
  listen = function() {
    var debouncedLayout = $.throttle( 300, function() {
      $grid.shuffle('update');
    });

    // Get all images inside shuffle
    $grid.find('img').each(function() {
      var proxyImage;

      // Image already loaded
      if ( this.complete && this.naturalWidth !== undefined ) {
        return;
      }

      // If none of the checks above matched, simulate loading on detached element.
      proxyImage = new Image();
      $( proxyImage ).on('load', function() {
        $(this).off('load');
        debouncedLayout();
      });

      proxyImage.src = this.src;
    });

    // Because this method doesn't seem to be perfect.
    setTimeout(function() {
      debouncedLayout();
    }, 500);
  };      

  return {
    init: init
  };
}( jQuery ));



$(document).ready(function() {
  shuffleme.init();
});

    </script>

    <!-- new attempt-->

    <script>
    $(document).ready(function() {
     
    /* initialize shuffle plugin */
    var $grid = $('#grid');
         
    $grid.shuffle({
        itemSelector: '.item' // the selector for the items in the grid
    });
 
});</script>

<script>
$('#filter a').click(function (e) {
    e.preventDefault();
         
    // set active class
    $('#filter a').removeClass('active');
    $(this).addClass('active');
         
    // get group name from clicked item
    var groupName = $(this).attr('data-group');
         
    // reshuffle grid
    $grid.shuffle('shuffle', groupName );
});</script>




================================================
FILE: docs/_includes/inline_image.html
================================================
<img class="inline" src="images/{{include.file}}" alt="{{include.alt}}" />


================================================
FILE: docs/_includes/links.html
================================================
{% comment %}Get links from each sidebar, as listed in the _config.yml file under sidebars{% endcomment %}

{% for sidebar in site.sidebars %}
{% for entry in site.data.sidebars[sidebar].entries %}
{% for folder in entry.folders %}
{% for folderitem in folder.folderitems %}
{% if folderitem.url contains "html#" %}
[{{folderitem.url | remove: "/" }}]: {{folderitem.url | remove: "/"}}
{% else %}
[{{folderitem.url | remove: "/"  | remove: ".html"}}]: {{folderitem.url | remove: "/"}}
{% endif %}
{% for subfolders in folderitem.subfolders %}
{% for subfolderitem in subfolders.subfolderitems %}
[{{subfolderitem.url | remove: "/"  | remove: ".html"}}]: {{subfolderitem.url | remove: "/"}}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}


{% comment %} Get links from topnav {% endcomment %}

{% for entry in site.data.topnav.topnav %}
{% for item in entry.items %}
{% if item.external_url == null %}
[{{item.url | remove: "/" | remove: ".html"}}]: {{item.url | remove: "/"}}
{% endif %}
{% endfor %}
{% endfor %}

{% comment %}Get links from topnav dropdowns {% endcomment %}

{% for entry in site.data.topnav.topnav_dropdowns %}
{% for folder in entry.folders %}
{% for folderitem in folder.folderitems %}
{% if folderitem.external_url == null %}
[{{folderitem.url | remove: "/"  | remove: ".html"}}]: {{folderitem.url | remove: "/"}}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}



================================================
FILE: docs/_includes/note.html
================================================
<div markdown="span" class="alert alert-info" role="alert"><i class="fa fa-info-circle"></i> <b>Note:</b> {{include.content}}</div>


================================================
FILE: docs/_includes/search_google_custom.html
================================================
<script>
  (function() {
    var cx = '{{site.google_search}}';
    var gcse = document.createElement('script');
    gcse.type = 'text/javascript';
    gcse.async = true;
    gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(gcse, s);
  })();
</script>

<div id="gcs-search-container">
    <gcse:search></gcse:search>
</div>



================================================
FILE: docs/_includes/search_simple_jekyll.html
================================================
<div id="search-demo-container">
    <input type="text" id="search-input" placeholder="{{site.data.strings.search_placeholder_text}}">
    <ul id="results-container"></ul>
</div>
<script src="{{ "js/jekyll-search.js"}}" type="text/javascript"></script>
<script type="text/javascript">
        SimpleJekyllSearch.init({
            searchInput: document.getElementById('search-input'),
            resultsContainer: document.getElementById('results-container'),
            dataSource: '{{ "search.json" }}',
            searchResultTemplate: '<li><a href="{url}" title="{{page.title | escape }}">{title}</a></li>',
noResultsText: '{{site.data.strings.search_no_results_text}}',
        limit: 10,
        fuzzy: true,
})
</script>


================================================
FILE: docs/_includes/sidebar.html
================================================
{% assign sidebar = site.data.sidebars[page.sidebar].entries %}
{% assign pageurl = page.url  | remove: ".html" %}

<ul id="mysidebar" class="nav">
  <li class="sidebarTitle">{{sidebar[0].product}} {{sidebar[0].version}}</li>
  {% for entry in sidebar %}
  {% for folder in entry.folders %}
  {% if folder.output contains "web" %}
  <li>
      <a href="#">{{ folder.title }}</a>
      <ul>
          {% for folderitem in folder.folderitems %}
          {% if folderitem.output contains "web" %}
          {% if folderitem.external_url %}
          <li><a href="{{folderitem.external_url}}" target="_blank">{{folderitem.title}}</a></li>
          {% elsif pageurl == folderitem.url %}
          <li class="active"><a href="{{folderitem.url | prepend: site.baseurl}}">{{folderitem.title}}</a></li>
          {% elsif folderitem.type == "empty" %}
          <li><a href="{{folderitem.url | prepend: site.baseurl}}">{{folderitem.title}}</a></li>

          {% else %}
          <li><a href="{{folderitem.url | prepend: site.baseurl}}">{{folderitem.title}}</a></li>
          {% endif %}
          {% for subfolders in folderitem.subfolders %}
          {% if subfolders.output contains "web" %}
          <li class="subfolders">
              <a href="#">{{ subfolders.title }}</a>
              <ul>
                  {% for subfolderitem in subfolders.subfolderitems %}
                  {% if subfolderitem.output contains "web" %}
                  {% if subfolderitem.external_url %}
                  <li><a href="{{subfolderitem.external_url}}" target="_blank">{{subfolderitem.title}}</a></li>
                  {% elsif pageurl == subfolderitem.url %}
                  <li class="active"><a href="{{subfolderitem.url | prepend: site.baseurl}}">{{subfolderitem.title}}</a></li>
                  {% else %}
                  <li><a href="{{subfolderitem.url | prepend: site.baseurl}}">{{subfolderitem.title}}</a></li>
                  {% endif %}
                  {% endif %}
                  {% endfor %}
              </ul>
          </li>
          {% endif %}
          {% endfor %}
          {% endif %}
          {% endfor %}
      </ul>
   </li>
     {% endif %}
      {% endfor %}
      {% endfor %}
      <!-- if you aren't using the accordion, uncomment this block:
         <p class="external">
             <a href="#" id="collapseAll">Collapse All</a> | <a href="#" id="expandAll">Expand All</a>
         </p>
         -->
</ul>

<!-- this highlights the active parent class in the navgoco sidebar. this is critical so that the parent expands when you're viewing a page. This must appear below the sidebar code above. Otherwise, if placed inside customscripts.js, the script runs before the sidebar code runs and the class never gets inserted.-->
<script>$("li.active").parents('li').toggleClass("active");</script>


================================================
FILE: docs/_includes/tip.html
================================================
<div markdown="span" class="alert alert-success" role="alert"><i class="fa fa-check-square-o"></i> <b>Tip:</b> {{include.content}}</div>

================================================
FILE: docs/_includes/toc.html
================================================

<!-- this handles the automatic toc. use ## for subheads to auto-generate the on-page minitoc. if you use html tags, you must supply an ID for the heading element in order for it to appear in the minitoc. -->
<script>
$( document ).ready(function() {
  // Handler for .ready() called.

$('#toc').toc({ minimumHeaders: 0, listType: 'ul', showSpeed: 0, headers: 'h2,h3,h4' });

/* this offset helps account for the space taken up by the floating toolbar. */
$('#toc').on('click', 'a', function() {
  var target = $(this.getAttribute('href'))
    , scroll_target = target.offset().top

  $(window).scrollTop(scroll_target - 10);
  return false
})
  
});
</script>

<div id="toc"></div>


================================================
FILE: docs/_includes/topnav.html
================================================
<!-- Navigation -->
<nav class="navbar navbar-inverse navbar-static-top">
    <div class="container topnavlinks">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="fa fa-home fa-lg navbar-brand" href="index.html">&nbsp;<span class="projectTitle"> {{site.topnav_title}}</span></a>
        </div>
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav navbar-right">
                <!-- toggle sidebar button -->
                <li><a id="tg-sb-link" href="#"><i id="tg-sb-icon" class="fa fa-toggle-on"></i> Nav</a></li>
                <!-- entries without drop-downs appear here -->

{% assign topnav = site.data[page.topnav] %}
{% assign topnav_dropdowns = site.data[page.topnav].topnav_dropdowns %}

                {% for entry in topnav.topnav %}
                {% for item in entry.items %}
                {% if item.external_url %}
                <li><a href="{{item.external_url}}" target="_blank">{{item.title}}</a></li>
                {% elsif page.url contains item.url %}
                <li class="active"><a href="{{item.url | remove: "/"}}">{{item.title}}</a></li>
                {% else %}
                <li><a href="{{item.url | remove: "/"}}">{{item.title}}</a></li>
                {% endif %}
                {% endfor %}
                {% endfor %}
                <!-- entries with drop-downs appear here -->
                <!-- conditional logic to control which topnav appears for the audience defined in the configuration file.-->
                {% for entry in topnav_dropdowns %}
                {% for folder in entry.folders %}
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ folder.title }}<b class="caret"></b></a>
                    <ul class="dropdown-menu">
                        {% for folderitem in folder.folderitems %}
                        {% if folderitem.external_url %}
                        <li><a href="{{folderitem.external_url}}" target="_blank">{{folderitem.title}}</a></li>
                        {% elsif page.url contains folderitem.url %}
                        <li class="dropdownActive"><a href="{{folderitem.url |  remove: "/"}}">{{folderitem.title}}</a></li>
                        {% else %}
                        <li><a href="{{folderitem.url | remove: "/"}}">{{folderitem.title}}</a></li>
                        {% endif %}
                        {% endfor %}
                    </ul>
                </li>
                {% endfor %}
                {% endfor %}
                {% if site.google_search %}
                <li>
                    {% include search_google_custom.html %}
                </li>
                {% endif %}
            </ul>
        </div>
        </div>
        <!-- /.container -->
</nav>


================================================
FILE: docs/_includes/warning.html
================================================
<div markdown="span" class="alert alert-danger" role="alert"><i class="fa fa-exclamation-circle"></i> <b>Warning:</b> {{include.content}}</div>

================================================
FILE: docs/_layouts/default.html
================================================
<!DOCTYPE html>
<html>
<head>
    {% include head.html %}
    <script>
        $(document).ready(function() {
            // Initialize navgoco with default options
            $("#mysidebar").navgoco({
                caretHtml: '',
                accordion: true,
                openClass: 'active', // open
                save: false, // leave false or nav highlighting doesn't work right
                cookie: {
                    name: 'navgoco',
                    expires: false,
                    path: '/'
                },
                slide: {
                    duration: 400,
                    easing: 'swing'
                }
            });

            $("#collapseAll").click(function(e) {
                e.preventDefault();
                $("#mysidebar").navgoco('toggle', false);
            });

            $("#expandAll").click(function(e) {
                e.preventDefault();
                $("#mysidebar").navgoco('toggle', true);
            });

            // activate menu items where href is matching to current page
            $("#mysidebar a[href='" + location.pathname.match(/\/([^\/]*)$/)[1] + "']")
                .parents('li').addClass('active')
                .parents('ul').css('display', 'block');
        });

    </script>
    <script>
        $(function () {
            $('[data-toggle="tooltip"]').tooltip()
        })
    </script>
    <script>
        $(document).ready(function() {
            $("#tg-sb-link").click(function() {
                $("#tg-sb-sidebar").toggle();
                $("#tg-sb-content").toggleClass('col-md-9');
                $("#tg-sb-content").toggleClass('col-md-12');
                $("#tg-sb-icon").toggleClass('fa-toggle-on');
                $("#tg-sb-icon").toggleClass('fa-toggle-off');
            });
        });
    </script>
    {% if page.datatable == true %}
    <!-- Include the standard DataTables bits -->
    <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/1.10.13/css/jquery.dataTables.css">
    <script type="text/javascript" charset="utf8" src="//cdn.datatables.net/1.10.13/js/jquery.dataTables.js"></script>
    <!-- First, this walks through the tables that occur between ...-begin
         and ...-end and add the "datatable" class to them.
         Then it invokes DataTable's standard initializer
         Credit here: http://www.beardedhacker.com/blog/2015/08/28/add-class-attribute-to-markdown-table/
      -->
    <script>
      $(document).ready(function(){
          $('div.datatable-begin').nextUntil('div.datatable-end', 'table').addClass('display');
          $('table.display').DataTable( {
              paging: true,
              stateSave: true,
              searching: true
          });
       });
    </script>
    {% endif %}

</head>
<body>
{% include topnav.html %}
<!-- Page Content -->
<div class="container">
  <div id="main">
    <!-- Content Row -->
    <div class="row">
        {% assign content_col_size = "col-md-12" %}
        {% unless page.hide_sidebar %}
            <!-- Sidebar Column -->
            <div class="col-md-3" id="tg-sb-sidebar">
                {% include sidebar.html %}
            </div>
            {% assign content_col_size = "col-md-9" %}
        {% endunless %}

        <!-- Content Column -->
        <div class="{{content_col_size}}" id="tg-sb-content">
            {{content}}
        </div>
    <!-- /.row -->
</div>
<!-- /.container -->
</div>
<!-- /#main -->
    </div>

</body>
{% if site.google_analytics %}
{% include google_analytics.html %}
{% endif %}
</html>


================================================
FILE: docs/_layouts/default_print.html
================================================
<!DOCTYPE html>
<html lang="en">
<html>
<head>
    {% include head_print.html %}


</head>

<body class="{% if page.type == "title"%}title{% elsif page.type == "frontmatter" %}frontmatter{% elsif page.type == "first_page" %}first_page{% endif %} print">

<!-- Page Content -->
<div class="container">
    <!-- Content Column -->
    <div class="col-md-9">

        {{content}}
    </div>

</div>    <!-- /.container -->

</body>

</html>



================================================
FILE: docs/_layouts/none.html
================================================
---
---
{{content}}

================================================
FILE: docs/_layouts/page.html
================================================
---
layout: default
---

<div class="post-header">
    <a id="{{page.title}}"></a>
    <h1 class="post-title-main">{{ page.title }}</h1>
</div>

{% if page.simple_map == true %}

<script>
    $(document).ready ( function(){
        $('.box{{page.box_number}}').addClass('active');
    });
</script>

{% include custom/{{page.map_name}}.html %}

{% elsif page.complex_map == true %}

<script>
    $(document).ready ( function(){
        $('.modalButton{{page.box_number}}').addClass('active');
    });
</script>

{% include custom/{{page.map_name}}.html %}

{% endif %}

<div class="post-content">

   {% if page.summary %}
    <div class="summary">{{page.summary}}</div>
   {% endif %}

    {% unless page.toc == false %}
    {% include toc.html %}
    {% endunless %}


    {% if site.github_editme_path %}

    <a target="_blank" href="https://github.com/{{site.github_editme_path}}{{page.path}}" class="btn btn-default githubEditButton" role="button"><i class="fa fa-github fa-lg"></i> Edit me</a>

    {% endif %}

   {{content}}

    <div class="tags">
        {% if page.tags != null %}
        <b>Tags: </b>
        {% assign projectTags = site.data.tags.allowed-tags %}
        {% for tag in page.tags %}
        {% if projectTags contains tag %}
        <a href="{{ "tag_" | append: tag | append: ".html" }}" class="btn btn-default navbar-btn cursorNorm" role="button">{{page.tagName}}{{tag}}</a>
        {% endif %}
        {% endfor %}
        {% endif %}
    </div>

</div>

{{site.data.alerts.hr_shaded}}

{% include footer.html %}


================================================
FILE: docs/_layouts/page_print.html
================================================
---
layout: default_print
comments: true
---
<div class="post-header">
    <h1 class="post-title-main" id="{{page.permalink | replace: '/', '' }}">{{ page.title }}</h1>
</div>

<div class="post-content">

    {% if page.summary %}
    <div class="summary">{{page.summary}}</div>
    {% endif %}
    {{ content }}
</div>


================================================
FILE: docs/css/boxshadowproperties.css
================================================
/* box-shadow fonts return errors with prince, so extracting here to put in web output only */

#search-demo-container ul#results-container {
    box-shadow: 2px 3px 2px #dedede;
}


hr.shaded {
    box-shadow: inset 0 6px 6px -6px rgba(0,0,0,0.5);
}

.videoThumbs img {
    box-shadow: 2px 2px 1px #f0f0f0;
}

.box {
    box-shadow: 2px 2px 4px #dedede;
}

@media (max-width: 1200px) {
    .navbar-collapse {
        box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
    }
}


================================================
FILE: docs/css/customstyles.css
================================================
.anchor-link {
    display: none;
}

body {
    font-size:15px;
}

.bs-callout {
    padding: 20px;
    margin: 20px 0;
    border: 1px solid #eee;
    border-left-width: 5px;
    border-radius: 3px;
}
.bs-callout h4 {
    margin-top: 0;
    margin-bottom: 5px;
}
.bs-callout p:last-child {
    margin-bottom: 0;
}
.bs-callout code {
    border-radius: 3px;
}
.bs-callout+.bs-callout {
    margin-top: -5px;
}
.bs-callout-default {
    border-left-color: #777;
}
.bs-callout-default h4 {
    color: #777;
}
.bs-callout-primary {
    border-left-color: #428bca;
}
.bs-callout-primary h4 {
    color: #428bca;
}
.bs-callout-success {
    border-left-color: #5cb85c;
}
.bs-callout-success h4 {
    color: #5cb85c;
}
.bs-callout-danger {
    border-left-color: #d9534f;
}
.bs-callout-danger h4 {
    color: #d9534f;
}
.bs-callout-warning {
    border-left-color: #f0ad4e;
}
.bs-callout-warning h4 {
    color: #f0ad4e;
}
.bs-callout-info {
    border-left-color: #5bc0de;
}
.bs-callout-info h4 {
    color: #5bc0de;
}


.gi-2x{font-size: 2em;}
.gi-3x{font-size: 3em;}
.gi-4x{font-size: 4em;}
.gi-5x{font-size: 5em;}


.breadcrumb > .active {color: #777 !important;}

/* make room for the nav bar */
h1[id]
/*,h2[id],
h3[id],
h4[id],
h5[id],
h6[id],
dt[id]*/
{
padding-top: 60px;
margin-top: -40px
}

.output_html a{
    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
    margin: 25px 0px;
    display: block;
    padding: 9.5px;
    font-size: 13px;
    line-height: 1.42857143;
    color: #333;
    word-break: break-all;
    word-wrap: break-word;
    background-color: #F5F5F5;
    border: 1px solid #FFA500;
    border-radius: 4px;
    white-space: pre-wrap;
    box-sizing: border-box;
    overflow: auto;
}

.col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9 {
        float: left;
}

.col-md-9 {
    width: 75%;
}

/* From: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_download_button' */
.cstm_btn a{
   background-color: DodgerBlue;
   border: none;
   color: white;
   padding: 12px 30px;
   cursor: pointer;
   font-size: 20px;
   box-sizing: 15px;
   position: absolute;
}

/* Darker background on mouse-over */
.cstm_btn a:hover {
    background-color: RoyalBlue;
}

.container #notebook-container{
    width: 100%;
    box-sizing: border-box;
            }

.post-content img {
    margin: 12px 0px 3px 0px;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
}

.post-content ol li, .post-content ul li {
    margin: 10px 0px;
}

.pageSummary {
    font-size:13px;
    display:block;
    margin-bottom:15px;
    padding-left:20px;
}

.post-summary {
    margin-bottom:12px;
}

.bs-example{
    margin: 20px;
}

.breadcrumb li {
    color: gray;
}

table {
    background-color: transparent;
}
caption {
    padding-top: 8px;
    padding-bottom: 8px;
    color: #777;
    text-align: left;
}
th {
    text-align: left;
}
table {
    max-width: 90%;
    margin-bottom: 20px;
    border: 1px solid #dedede;
}

table > thead > tr > th,
table > tbody > tr > th,
table > tfoot > tr > th,
table > thead > tr > td,
table > tbody > tr > td,
table > tfoot > tr > td {
    padding: 8px;
    line-height: 1.42857143;
    vertical-align: top;
    border-top: 1px solid #ddd;
}
table > thead > tr > th {
    vertical-align: bottom;
    border-bottom: 2px solid #ddd;
    text-transform: none;
    background-color: #777;
    color: white;
    text-align: left;
}
table > caption + thead > tr:first-child > th,
table > colgroup + thead > tr:first-child > th,
table > thead:first-child > tr:first-child > th,
table > caption + thead > tr:first-child > td,
table > colgroup + thead > tr:first-child > td,
table > thead:first-child > tr:first-child > td {
    border-top: 0;
}

table > tbody > tr:nth-of-type(odd) {
    background-color: #f9f9f9;
}

table col[class*="col-"] {
    position: static;
    display: table-column;
    float: none;
}
table td[class*="col-"],
table th[class*="col-"] {
    position: static;
    display: table-cell;
    float: none;
}

table tr td {
    hyphens: auto;
}


p.external a {
    text-align:right;
    font-size:12px;
    color: #0088cc;
    display:inline;
}

#definition-box-container div a.active {
    font-weight: bold;
}
p.post-meta {font-size: 80%; color: #777;}

.entry-date{font-size:14px;font-size:0.875rem;line-height:1.71429;margin-bottom:0;text-transform:uppercase;}

/* search area */
#search-demo-container ul#results-container {
    list-style: none;
    font-size: 12px;
    background-color: white;
    position: absolute;
    top: 40px; /* if you change anything about the nav, you'll prob. need to reset the top and left values here.*/
    left: 20px;
    z-index: -1;
    width:223px;
    border-left: 1px solid #dedede;
}


ul#results-container a {
    background-color: transparent;
}

ul#results-container a:hover {
    color: black;
}


#search-demo-container a:hover {
    color: black;
}
#search-input {
    padding: .5em;
    margin-left:20px;
    width:20em;
    font-size: 0.8em;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    margin-top:10px;
}
/* end search */

.filter-options {
    margin-bottom: 20px;
}
.filter-options button {
    margin: 3px;
}

a.source_link {
    float:right;
    font-size:15px;
    font-weight:normal;
}

div#toc ul {
    font-size: 90%;
    background-color: whitesmoke;
    padding: 5px;
    border-radius: 5px;
    max-width: 450px;
    color: gray;
    list-style-type: none;
}

/* when using relative fonts like 0.9em or 90%, remember to then set the nested items to 1em or 100%, otherwise each level will get smaller and smaller and less readable */
div#toc ul li {
    margin: 8px 0px 8px 22px;
    font-size: 100%;
    list-style-type: none;
}

div#toc ul li ul {
    font-size: 100%;
    padding-left:30px;
    padding-top: 0px;
    padding-bottom: 0px;
    list-style-type: none;
}

div#toc ul li ul li.hide_content::before {
    content: none;
}

div#toc >ul::before {
    content: "Table of Contents";
    font-weight: 500;
    color: #555;
    text-align:center;
    margin-left:auto;
    margin-right:auto;
    width:70px;
    padding-top:150px;
    padding-bottom:40px;
    padding-left:10px;
}

li.dropdownActive a {
    font-weight: bold;
}


.post-content a.fa-rss {
    color: orange;
}


.navbar-inverse .navbar-nav > li > a {
    background-color: transparent;
    margin-top:10px;
}

.post-content .rssfeedLink {
    color: #248EC2;
}

footer {
    font-size: smaller;
}

/* FAQ page */
#accordion .panel-heading {
    font-size: 12px;
}

a.accordion-toggle, a.accordion-collapsed {
    font-size: 14px;
    text-decoration: none;
}

/* navgoco sidebar styles (customized) */
.nav, .nav ul, .nav li {
    list-style: none;
}

.nav ul {
    padding: 0;
    /*margin: 0 0 0 18px;*/
    margin:0px;
}

.nav {
    /* padding: 4px;*/
    padding:0px;
    margin: 0px;
}

.nav > li {
    margin: 1px 0;
}

.nav > li li {
    margin: 2px 0;
}

.nav a {
    color: #333;
    display: block;
    outline: none;
    /*-webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    border-radius: 4px;*/
    text-decoration: none;
}

.nav li > a > span {
    float: right;
    font-size: 19px;
    font-weight: bolder;
}


.nav li > a > span:after {
    content: '\25be';
}
.nav li.active > a > span:after {
    content: '\25b4';
}

.nav a:hover, .nav li.active > a {
    background-color: #8D8D8D;
    color: #f5f5f5;
}

.nav > li.active > a  {
background-color: #347DBE;
}

.nav li a {
    font-size: 12px;
    line-height: 18px;
    padding: 2px 10px;
    background-color: #f1f1f1;
}

.nav > li > a {
    font-size: 14px;
    line-height: 20px;
    padding: 4px 10px;
}

ul#mysidebar {
    border-radius:0px;
}

.nav ul li ul li a {
    padding-left:40px;
}

.nav li.thirdlevel > a {
    color: #248EC2;
    font-weight:bold;
    padding-left:20px;
    background-color: whitesmoke !important;
}


.nav ul li a {
    background-color: #FAFAFA;
}

.nav li a {
    padding-right:10px;
}

.nav li a:hover {
    background-color: #8D8D8D;
}

.nav ul li a {
    border-top:1px solid whitesmoke;
    padding-left:10px;
}
/* end sidebar */

.navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {
    border-radius:5px;
}

.navbar-inverse .navbar-nav>.open>a, .navbar-inverse .navbar-nav>.open>a:focus, .navbar-inverse .navbar-nav>.open>a:hover {
    border-radius: 5px;
}

span.projectTitle {
    font-family: Helvetica;
    font-weight: bold;
}

.footer {
    text-align: right;
}

.footerMeta {
    background-color: whitesmoke;
    padding: 10px;
    max-width: 250px;
    border-radius: 5px;
    margin-top: 50px;
    font-style:italic;
    font-size:12px;
}

img.screenshotSmall {
    max-width: 300px;
}


dl dt p {
    margin-left:20px;
}


dl dd {
    margin-top:10px;
    margin-bottom:10px;
}

dl.dl-horizontal dd {
    padding-top: 20px;
}

figcaption {

    padding-bottom:12px;
    padding-top:6px;
    max-width: 90%;
    margin-bottom:20px;
    font-style: italic;
    color: gray;

}

.testing {
    color: orange;
}

.preference {
    color: red;
}


table.dataTable thead {
    background-color: #444;
}
table td {
    hyphens: auto;
}

section table tr.success {
    background-color: #dff0d8 !important;
}

table tr.info {
    background-color: #d9edf7 !important;
}

section table tr.warning, table tr.testing, table tr.testing > td.sorting_1  {
    background-color: #fcf8e3 !important;
}
section table tr.danger, table tr.preference, table tr.preference > td.sorting_1  {
    background-color: #f2dede !important;
}

.orange {
    color: orange;
}

table.profile thead tr th {
    background-color: #248ec2;
}

table.request thead tr th {
    background-color: #ED1951;
}

.audienceLabel {
    margin: 10px;
    float: right;
    border:1px solid #dedede;
    padding:7px;
}

.prefaceAudienceLabel {
    color: gray;
    text-align: center;
    margin:5px;
}
span.myLabel {
    padding-left:10px;
    padding-right:10px;
}

button.cursorNorm {
    cursor: default;
}

a.dropdown-toggle, .navbar-inverse .navbar-nav > li > a  {
    margin-left: 10px;
}

hr.faded {
    border: 0;
    height: 1px;
    background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
    background-image:    -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
    background-image:     -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
    background-image:      -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,0.75), rgba(0,0,0,0));
}

hr.shaded {
    height: 12px;
    border: 0;
    margin-top: 70px;
    background: white;
    width: 100%;
    margin-bottom: 10px;
}

.fa-6x{font-size:900%;}
.fa-7x{font-size:1100%;}
.fa-8x{font-size:1300%;}
.fa-9x{font-size:1500%;}
.fa-10x{font-size:1700%;}

i.border {
    padding: 10px 20px;
    background-color: whitesmoke;
}

a[data-toggle] {
    color: #248EC2;
}

.summary {
    font-size:120%;
    color: #808080;
    margin:20px 0px 20px 0px;
    border-left: 5px solid #ED1951;
    padding-left: 10px;

}

a.fa.fa-envelope-o.mailto {
    font-weight: 600;
}

h3 {color: #ED1951; font-weight:normal; font-size:130%;}
h4 {color: #000000; font-weight:normal; font-size:120%; font-weight:bold;}

.alert, .callout {
    overflow: hidden;
}

.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
    background-color: #248ec2;
    color: white;
}

ol li ol li {list-style-type: lower-alpha;}
ol li ul li {list-style-type: disc;}

li img {clear:both; }

div#toc ul li ul li {
    list-style-type: none;
    margin: 5px 0px 0px 0px;
}

.tab-content {
    padding: 15px;
    background-color: #FAFAFA;
}

span.tagTitle {font-weight: 500;}

li.activeSeries {
    font-weight: bold;
}

.seriesContext .dropdown-menu li.active {
    font-weight: bold;
    margin-left: 43px;
    font-size:18px;
}

.alert-warning {
    color: #444;
}

div.alert code, h2 code {
    background-color: transparent !important;
}
/* without this, the links in these notes aren't visible.*/
.alert a {
    text-decoration: underline;
}

div.tags {padding: 10px 5px;}

.tabLabel {
    font-weight: normal;
}

hr {
    background: #999;
    margin: 30px 0px;
    width: 90%;
    margin-left: auto;
    margin-right: auto;
}

button.cursorNorm {
    cursor: pointer;
}

h2  {
    font-size:24px;
    line-height:29px;
    border-top: 3px solid blue;
    padding-top: 5px;
}

span.otherProgrammingLanguages {
    font-style: normal;
}

a[data-toggle="tooltip"] {
    color: #649345;
    font-style: italic;
    cursor: default;
}

.seriesNext, .seriesContext {
    margin-top: 15px;
    margin-bottom: 15px;
}

.seriescontext ol li {
    list-style-type: upper-roman;
}

ol.series li {
    list-style-type: decimal;
    margin-left: 40px;
    padding-left: 0px;
}

.siteTagline {
    font-size: 200%;
    font-weight: bold;
    color: silver;
    font-family: monospace;
    text-align: center;
    line-height: 10px;
    margin: 20px 0px;
    display: block;
}

.versionTagline {
    text-align: center;
    margin-bottom: 20px;
    font-family: courier;
    color: silver;
    color: #444;
    display:block;
}

/* not sure if using this ...*/
.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
    border-color: #248ec2 !important;
}

#mysidebar .nav ul {
    background-color: #FAFAFA;
}
.nav ul.series li {
    list-style: decimal;
    font-size:12px;
}

.nav ul.series li a:hover {
    background-color: gray;
}
.nav ul.series {
    padding-left: 30px;
}

.nav ul.series {
    background-color: #FAFAFA;
}

/*
a.dropdown-toggle.otherProgLangs {
    color: #f7e68f !important;
}
*/

span.muted {color: #666;}

table code {background-color: transparent;}

.highlight .err {
    color: #a61717;
    background-color: transparent !important;
}

table p {
    margin-top: 12px;
    margin-bottom: 12px;
}

pre, table code {
    white-space: pre-wrap;       /* css-3 */
    white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
    white-space: -pre-wrap;      /* Opera 4-6 */
    white-space: -o-pre-wrap;    /* Opera 7 */
    word-wrap: break-word;       /* Internet Explorer 5.5+ */
}

pre {
    margin: 25px 0px;
}

#json-box-container pre {
    margin: 0px;
}

.video-js {
    margin: 30px 0px;
}

video {
    display: block;
    margin: 30px 0px;
    border: 1px solid #c0c0c0;
}


p.required, p.dataType {display: block; color: #c0c0c0; font-size: 80%; margin-left:4px;}

dd {margin-left:20px;}

.post-content img.inline {
    margin:0px;
    margin-bottom:6px;
}
.panel-heading {
    font-weight: bold;
}

.note code, .alert code, .warning code, div#toc code, h2 code, h3 code, h4 code {
    color: inherit;
    padding: 0px;
}

.alert {
    margin-bottom:10px;
    margin-top:10px;
}

a.accordion-toggle {
    font-style: normal;
}

span.red {
    color: red;
    font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
}

h3.codeExplanation {
    font-size:18px;
    font-style:normal;
    color: black;
    line-height: 24px;
}

span.soft {
    color: #c0c0c0;
}

.githubEditButton {
    margin-bottom:7px;
}

.endpoint {
    padding: 15px;
    background-color: #f0f0f0;
    font-family: courier;
    font-size: 110%;
    margin: 20px 0px;
    color: #444;
}

.parameter {
    font-family: courier;
    color: red !important;
}

.formBoundary {
    border: 1px solid gray;
    padding: 15px;
    margin: 15px 0px;
    background-color: whitesmoke;
}

@media (max-width: 767px) {
    .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
        color: #444;
    }
}

@media (max-width: 990px) {
    #mysidebar {
        position: relative;
    }
        .col-md-9 {
            width: 95%;
        }
}


@media (min-width: 1000px) {

    ul#mysidebar {
        width: 225px;
    }
}

@media (max-width: 900px) {

    ul#mysidebar {
        max-width: 100%;
    }
}

.col-md-9 img {
    max-width: 100%;
    max-height: 100%;
}


.post-content img {
    margin: 12px 0px 3px 0px;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
}
.col-md-9 img {
    max-width: 100%;
    max-height: 100%;
}


.post-content img {
    margin: 12px 0px 3px 0px;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
}

.videoThumbs img {
    float: left;
    margin:15px 15px 15px 0px;
    border: 1px solid #dedede;
}


@media only screen and (min-width: 900px), only screen and (min-device-width: 900px) {
    .col-md-9 img {
        max-width: 990px;
        max-height: 700px;
    }
}

*:hover > .anchorjs-link {
    transition: color .25s linear;
    text-decoration: none;
}

.kbCaption {
    color: white;
    background-color: #444;
    padding:10px;
}

/* Strip the outbound icon when this class is present */
a[href].noCrossRef::after,
a.no_icon:after
 {
    content:"" !important;
    padding-left: 0;
}

.btn-default {
    margin-bottom: 10px;
}

/* algolia search */

.search {
    text-align: left;
}
.search input {
    font-size: 20px;
    width: 300px;
}
.results {
    margin: auto;
    text-align: left;
}
.results ul {
    list-style-type: none;
    padding: 0;
}

/* algolia */

div.results {
    position: absolute;
    background-color: white;
    width: 100%;
}

.post-meta {
    font-size: 14px;
    color: #828282;
}

.post-link {
    font-size: 22px;
}

.post-list p {
    margin: 10px 0px;
}

time {
    margin-right: 10px;
}

p.post-meta time {
    margin-right: 0px;
}

span.label.label-default {
    background-color: gray;
}

span.label.label-primary {
    background-color: #f0ad4e;
}
.col-lg-12 .nav li a {background-color: white}


.nav li.active > a.subfoldersTitle {
    background-color: whitesmoke;
    font-weight: bold;
    color: black;
    }

code {
        color: #1d1f5b;
        background-color: #f3f3f3;
}

a code {
    color: #0082C2;
}

table th code {
    color: white;
}

ol li ul li ol li {
    list-style: decimal;
}

ol li ul li ol li ul li{
    list-style: disc;
}

.post-content table th {
    vertical-align: top;
}

table thead th code.highlighter-rouge {
    background-color: transparent;
}


.box {
    padding: 10px;
    border: 1px solid #888;
    width: 100px;
    height: 80px;
    background-color: #f5f5f5;
    font-family: Arial;
    font-size: 12px;
    hyphens: auto;
    float: left;
    font-size: 12px;
}

.box:hover {
    background-color: #f0f0f0;
}

#userMap {
    overflow-x: auto;
    overflow-y: auto;
    padding: 20px;
    min-width: 770px;
}

#userMap .active {
    background-color: #d6f5d6;
    border:1px solid #555;
    font-weight: bold;
}

h2.userMapTitle {
    font-family: Arial;
}

#userMap a:hover {
    text-decoration: none;
  }

div.arrow {
    max-width: 50px;
    margin-left: 15px;
    margin-right: 15px;
    font-size: 20px;
}

div.content {
    max-width: 110px
}

#userMap div.arrow, #userMap div.content {
    float: left;
}

.clearfix {
    clear: both;
}


#userMap div.arrow {
    position: relative;
    top: 30px;
}

.box1 {
    margin-left:0px;
}

button.btn.btn-default.btn-lg.modalButton1 {
    margin-left: -20px;
}

div.box.box1 {
    margin-left: -20px;
}

#userMap .btn-lg {
    width: 100px;
    height: 80px;

}

#userMap .complexArrow {
    font-size: 22px;
    margin: 0px 10px;
}


#userMap .btn-lg .active {
    background-color: #d6f5d6;
}

#userMap .btn-lg  {
        white-space: pre-wrap;       /* css-3 */
        white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
        white-space: -pre-wrap;      /* Opera 4-6 */
        white-space: -o-pre-wrap;    /* Opera 7 */
        word-wrap: break-word;       /* Internet Explorer 5.5+ */
        font-size: 14px;
    }

/*
 * Let's target IE to respect aspect ratios and sizes for img tags containing SVG files
 *
 * [1] IE9
 * [2] IE10+
 */
/* 1 */
.ie9 img[src$=".svg"] {
    width: 100%;
}
/* 2 */
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
    img[src$=".svg"] {
        width: 100%;
    }
}

h4.panel-title {
    padding-top: 0px;
    margin-top: 0px;
}

/*set navbar breakpoint so that it converts to hamburger earlier */

@media (max-width: 1200px) {
    .navbar-header {
        float: none;
    }
    .navbar-left,.navbar-right {
        float: none !important;
    }
    .navbar-toggle {
        display: block;
    }
    .navbar-collapse {
        border-top: 1px solid transparent;
    }
    .navbar-fixed-top {
        top: 0;
        border-width: 0 0 1px;
    }
    .navbar-collapse.collapse {
        display: none!important;
    }
    .navbar-nav {
        float: none!important;
        margin-top: 7.5px;
    }
    .navbar-nav>li {
        float: none;
    }
    .navbar-nav>li>a {
        padding-top: 10px;
        padding-bottom: 10px;
    }
    .collapse.in{
        display:block !important;
    }
}

.input_area pre {
        padding-bottom: 3;
        margin-top: 10px;
        background-color: #f5f1e0;
        border: 0px;
}
.output_area pre {
        padding-top: 3;
        margin-top: -25px;
        margin-bottom: 10px;
        border: 0px;
        padding-left: 2em;
}
.pytest_card {
    padding: 10px 1em 4px 1em;
    background-color: #eef2ff;
    border-radius: 5px;
    margin-bottom: 20px;
}
.pytest_card .close {
    color: #000
}
blockquote {
        font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
}
blockquote code {
        background-color: white;
}
h4 code {
        background-color: white;
}

/* Google Custom Search styling */

#gcs-search-container {
    width: 340px !important; /* ToDo: define width without using absolute px value */
    display: inline-block !important;
}

.gsc-search-box.gsc-search-box-tools table {
  margin-bottom: 0px !important;
}
.gsc-input, .gsc-search-button {
    padding: 0;
}
.gsc-control-cse {
    padding: 6px !important;
}
input.gsc-input {
    font-size: 12px !important;
}


================================================
FILE: docs/css/modern-business.css
================================================
/*!
 * Start Bootstrap - Modern Business HTML Template (http://startbootstrap.com)
 * Code licensed under the Apache License v2.0.
 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 */

/* Global Styles */

html,
body {
    height: 100%;
}

.img-portfolio {
    margin-bottom: 30px;
}

.img-hover:hover {
    opacity: 0.8;
}

/* Home Page Carousel */

header.carousel {
    height: 50%;
}

header.carousel .item,
header.carousel .item.active,
header.carousel .carousel-inner {
    height: 100%;
}

header.carousel .fill {
    width: 100%;
    height: 100%;
    background-position: center;
    background-size: cover;
}

/* 404 Page Styles */

.error-404 {
    font-size: 100px;
}

/* Pricing Page Styles */

.price {
    display: block;
    font-size: 50px;
    line-height: 50px;
}

.price sup {
    top: -20px;
    left: 2px;
    font-size: 20px;
}

.period {
    display: block;
    font-style: italic;
}

/* Footer Styles */

footer {
    margin: 50px 0;
}

/* Responsive Styles */

@media(max-width:991px) {
    .client-img,
    .img-related {
        margin-bottom: 30px;
    }
}

@media(max-width:767px) {
    .img-portfolio {
        margin-bottom: 15px;
    }

    header.carousel .carousel {
        height: 70%;
    }
}


================================================
FILE: docs/css/printstyles.css
================================================

/*body.print .container {max-width: 650px;}*/

body {
    font-size:14px;
}
.nav ul li a {border-top:0px; background-color:transparent; color: #808080; }
#navig a[href] {color: #595959 !important;}
table .table {max-width:650px;}

#navig li.sectionHead {font-weight: bold; font-size: 18px; color: #595959 !important; }
#navig li {font-weight: normal; }

#navig a[href]::after { content: leader(".") target-counter(attr(href), page); }

a[href]::after {
    content: " (page " target-counter(attr(href), page) ")"
}

a[href^="http:"]::after, a[href^="https:"]::after {
    content: "";
}

a[href] {
    color: blue !important;
}
a[href*="mailto"]::after, a[data-toggle="tooltip"]::after, a[href].noCrossRef::after {
    content: "";
}


@page {
    margin: 60pt 90pt 60pt 90pt;
    font-family: sans-serif;
    font-style:none;
    color: gray;

}

.printTitle {
    line-height:30pt;
    font-size:27pt;
    font-weight: bold;
    letter-spacing: -.5px;
    margin-bottom:25px;
}

.printSubtitle {
    font-size: 19pt;
    color: #cccccc !important;
    font-family: "Grotesque MT Light";
    line-height: 22pt;
    letter-spacing: -.5px;
    margin-bottom:20px;
}
.printTitleArea hr {
    color: #999999 !important;
    height: 2px;
    width: 100%;
}

.printTitleImage {
    max-width:300px;
    margin-bottom:200px;
}


.printTitleImage {
    max-width: 250px;
}

#navig {
    /*page-break-before: always;*/
}

.copyrightBoilerplate {
    page-break-before:always;
    font-size:14px;
}

.lastGeneratedDate {
    font-style: italic;
    font-size:14px;
    color: gray;
}

.alert a {
    text-decoration: none !important;
}


body.title { page: title }

@page title {
    @top-left {
        content: " ";
    }
    @top-right {
        content: " "
    }
    @bottom-right {
        content: " ";
    }
    @bottom-left {
        content: " ";
    }
}

body.frontmatter { page: frontmatter }
body.frontmatter {counter-reset: page 1}


@page frontmatter {
    @top-left {
        content: prince-script(guideName);
    }
    @top-right {
        content: prince-script(datestamp);
    }
    @bottom-right {
        content: counter(page, lower-roman);
    }
    @bottom-left {
        content: "youremail@domain.com";   }
}

body.first_page {counter-reset: page 1}

h1 { string-set: doctitle content() }

@page {
    @top-left {
        content: string(doctitle);
        font-size: 11px;
        font-style: italic;
    }
    @top-right {
        content: prince-script(datestamp);
        font-size: 11px;
    }

    @bottom-right {
        content: "Page " counter(page);
        font-size: 11px;
    }
    @bottom-left {
        content: prince-script(guideName);
        font-size: 11px;
    }
}
.alert {
    background-color: #fafafa !important;
    border-color: #dedede !important;
    color: black;
}

pre {
    background-color: #fafafa;
}


================================================
FILE: docs/css/syntax.css
================================================
.highlight  { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d14 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d14 } /* Literal.String.Backtick */
.highlight .sc { color: #d14 } /* Literal.String.Char */
.highlight .sd { color: #d14 } /* Literal.String.Doc */
.highlight .s2 { color: #d14 } /* Literal.String.Double */
.highlight .se { color: #d14 } /* Literal.String.Escape */
.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
.highlight .si { color: #d14 } /* Literal.String.Interpol */
.highlight .sx { color: #d14 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d14 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */

================================================
FILE: docs/css/theme-blue.css
================================================
.summary {
    color: #808080;
    border-left: 5px solid #ED1951;
    font-size:16px;
}


h3 {color: #000000; }
h4 {color: #000000; }

.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
    background-color: #248ec2;
    color: white;
}

.nav > li.active > a {
    background-color: #347DBE;
}

.nav > li > a:hover {
    background-color: #248ec2;
}

div.navbar-collapse .dropdown-menu > li > a:hover {
    background-color: #347DBE;
}

.nav li.thirdlevel > a {
    background-color: #FAFAFA !important;
    color: #248EC2;
    font-weight: bold;
}

a[data-toggle="tooltip"] {
    color: #649345;
    font-style: italic;
    cursor: default;
}

.navbar-inverse {
    background-color: #347DBE;
    border-color: #015CAE;
}
.navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-brand {
    color: white;
}

.navbar-inverse .navbar-nav>li>a:hover, a.fa.fa-home.fa-lg.navbar-brand:hover {
     color: #f0f0f0;
}

a.navbar-brand:hover {
  color: #f0f0f0;
}

.navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
    color: #015CAE;
}

.navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
    background-color: #015CAE;
    color: #ffffff;
}

.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
    border-color: #248ec2 !important;
}

.btn-primary {
    color: #ffffff;
    background-color: #347DBE;
    border-color: #347DBE;
}

.navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {
    background-color: #347DBE;
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary.active,
.open .dropdown-toggle.btn-primary {
    background-color: #248ec2;
    border-color: #347DBE;
}

.printTitle {
    color: #015CAE !important;
}

body.print h1 {color: #015CAE !important; font-size:28px !important;}
body.print h2 {color: #595959 !important; font-size:20px !important;}
body.print h3 {color: #E50E51 !important; font-size:14px !important;}
body.print h4 {color: #679DCE !important; font-size:14px; font-style: italic !important;}

.anchorjs-link:hover {
    color: #216f9b;
}

div.sidebarTitle {
    color: #015CAE;
}

li.sidebarTitle {
  margin-top:20px;
    font-weight:normal;
    font-size:130%;
    color: #ED1951;
    margin-bottom:10px;
    margin-left: 5px;

}

.navbar-inverse .navbar-toggle:focus, .navbar-inverse .navbar-toggle:hover {
    background-color: #015CAE;
}

.navbar-inverse .navbar-toggle {
    border-color: #015CAE;
}


================================================
FILE: docs/css/theme-green.css
================================================
.summary {
    color: #808080;
    border-left: 5px solid #E50E51;
    font-size:16px;
}


h3 {color: #E50E51; }
h4 {color: #808080; }

.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
    background-color: #248ec2;
    color: white;
}

.nav > li.active > a {
    background-color: #72ac4a;
}

.nav > li > a:hover {
    background-color: #72ac4a;
}

div.navbar-collapse .dropdown-menu > li > a:hover {
    background-color: #72ac4a;
}

.navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-brand {
    color: white;
}

.navbar-inverse .navbar-nav>li>a:hover, a.fa.fa-home.fa-lg.navbar-brand:hover {
     color: #f0f0f0;
}

.nav li.thirdlevel > a {
    background-color: #FAFAFA !important;
    color: #72ac4a;
    font-weight: bold;
}

a[data-toggle="tooltip"] {
    color: #649345;
    font-style: italic;
    cursor: default;
}

.navbar-inverse {
    background-color: #72ac4a;
    border-color: #5b893c;
}

.navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
    color: #5b893c;
}

.navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
    background-color: #5b893c;
    color: #ffffff;
}

/* not sure if using this ...*/
.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
    border-color: #72ac4a !important;
}

.btn-primary {
    color: #ffffff;
    background-color: #5b893c;
    border-color: #5b893c;
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary.active,
.open .dropdown-toggle.btn-primary {
    background-color: #72ac4a;
    border-color: #5b893c;
}

.printTitle {
    color: #5b893c !important;
}

body.print h1 {color: #5b893c !important; font-size:28px;}
body.print h2 {color: #595959 !important; font-size:24px;}
body.print h3 {color: #E50E51 !important; font-size:14px;}
body.print h4 {color: #679DCE !important; font-size:14px; font-style: italic;}

.anchorjs-link:hover {
    color: #4f7233;
}

div.sidebarTitle {
    color: #E50E51;
}

li.sidebarTitle {
    margin-top:20px;
    font-weight:normal;
    font-size:130%;
    color: #ED1951;
    margin-bottom:10px;
    margin-left: 5px;
}

.navbar-inverse .navbar-toggle:focus, .navbar-inverse .navbar-toggle:hover {
    background-color: #E50E51;
}


================================================
FILE: docs/feed.xml
================================================
---
search: exclude
layout: none
---

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>{{ site.title | xml_escape }}</title>
        <description>{{ site.description | xml_escape }}</description>
        <link>{{ site.url }}/</link>
        <atom:link href="{{ "/feed.xml" | prepend: site.url }}" rel="self" type="application/rss+xml"/>
        <pubDate>{{ site.time | date_to_rfc822 }}</pubDate>
        <lastBuildDate>{{ site.time | date_to_rfc822 }}</lastBuildDate>
        <generator>Jekyll v{{ jekyll.version }}</generator>
        {% for post in site.posts limit:10 %}
        <item>
            <title>{{ post.title | xml_escape }}</title>
            <description>{{ post.content | xml_escape }}</description>
            <pubDate>{{ post.date | date_to_rfc822 }}</pubDate>
            <link>{{ post.url | prepend: site.url }}</link>
            <guid isPermaLink="true">{{ post.url | prepend: site.url }}</guid>
            {% for tag in post.tags %}
            <category>{{ tag | xml_escape }}</category>
            {% endfor %}
            {% for tag in page.tags %}
            <category>{{ cat | xml_escape }}</category>
            {% endfor %}
        </item>
        {% endfor %}
    </channel>
</rss>


================================================
FILE: docs/index.html
================================================
---

title: online_triplet_loss

keywords: fastai
sidebar: home_sidebar

summary: "PyTorch conversion of the excellent post on the <a href='https://omoindrot.github.io/triplet-loss'>same topic in Tensorflow</a>. Simply an implementation of a triple loss with online mining of candidate triplets used in semi-supervised learning."
description: "PyTorch conversion of the excellent post on the <a href='https://omoindrot.github.io/triplet-loss'>same topic in Tensorflow</a>. Simply an implementation of a triple loss with online mining of candidate triplets used in semi-supervised learning."
---
<!--

#################################################
### THIS FILE WAS AUTOGENERATED! DO NOT EDIT! ###
#################################################
# file to edit: index.ipynb
# command to build the docs after a change: nbdev_build_docs

-->

<div class="container" id="notebook-container">
        
    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">

</div>
    {% endraw %}

<div class="cell border-box-sizing text_cell rendered"><div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="Install">Install<a class="anchor-link" href="#Install"> </a></h2>
</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered"><div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<p><code>pip install online_triplet_loss</code></p>
<p>Then import with:
<code>from online_triplet_loss.losses import *</code></p>
<p>PS: Requires Pytorch version 1.1.0 or above to use.</p>

</div>
</div>
</div>
<div class="cell border-box-sizing text_cell rendered"><div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="How-to-use">How to use<a class="anchor-link" href="#How-to-use"> </a></h2><p>In these examples I use a really large margin, since the embedding space is so small. A more realistic margins seems to be between <code>0.1 and 2.0</code></p>

</div>
</div>
</div>
    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">
<div class="input">

<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="kn">from</span> <span class="nn">torch</span> <span class="kn">import</span> <span class="n">nn</span>
<span class="kn">import</span> <span class="nn">torch</span>

<span class="n">model</span> <span class="o">=</span> <span class="n">nn</span><span class="o">.</span><span class="n">Embedding</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
</pre></div>

    </div>
</div>
</div>

</div>
    {% endraw %}

    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">
<div class="input">

<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="c1">#from online_triplet_loss.losses import *</span>
<span class="n">labels</span> <span class="o">=</span> <span class="n">torch</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="n">high</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,))</span> <span class="c1"># our five labels</span>

<span class="n">embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">labels</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Labels:&#39;</span><span class="p">,</span> <span class="n">labels</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Embeddings:&#39;</span><span class="p">,</span> <span class="n">embeddings</span><span class="p">)</span>
<span class="n">loss</span> <span class="o">=</span> <span class="n">batch_hard_triplet_loss</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="n">embeddings</span><span class="p">,</span> <span class="n">margin</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Loss:&#39;</span><span class="p">,</span> <span class="n">loss</span><span class="p">)</span>
<span class="n">loss</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
</pre></div>

    </div>
</div>
</div>

<div class="output_wrapper">
<div class="output">

<div class="output_area">

<div class="output_subarea output_stream output_stdout output_text">
<pre>Labels: tensor([6, 1, 3, 6, 6])
Embeddings: tensor([[-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
          0.0180, -0.4500],
        [ 1.0757, -0.8420, -0.7630, -0.0746,  1.1545,  0.4017,  0.5587,  1.7947,
          0.1992, -2.2288],
        [ 0.2646,  1.2383,  0.1949,  0.5743, -0.8460, -0.9929, -2.0350,  0.2095,
          0.2129, -0.4855],
        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
          0.0180, -0.4500],
        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
          0.0180, -0.4500]], grad_fn=&lt;EmbeddingBackward&gt;)
Loss: tensor(95.1271, grad_fn=&lt;MeanBackward0&gt;)
</pre>
</div>
</div>

</div>
</div>

</div>
    {% endraw %}

    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">
<div class="input">

<div class="inner_cell">
    <div class="input_area">
<div class=" highlight hl-ipython3"><pre><span></span><span class="c1">#from online_triplet_loss.losses import *</span>
<span class="n">embeddings</span> <span class="o">=</span> <span class="n">model</span><span class="p">(</span><span class="n">labels</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Labels:&#39;</span><span class="p">,</span> <span class="n">labels</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Embeddings:&#39;</span><span class="p">,</span> <span class="n">embeddings</span><span class="p">)</span>
<span class="n">loss</span><span class="p">,</span> <span class="n">fraction_pos</span> <span class="o">=</span> <span class="n">batch_all_triplet_loss</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="n">embeddings</span><span class="p">,</span> <span class="n">squared</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">margin</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Loss:&#39;</span><span class="p">,</span> <span class="n">loss</span><span class="p">)</span>
<span class="n">loss</span><span class="o">.</span><span class="n">backward</span><span class="p">()</span>
</pre></div>

    </div>
</div>
</div>

<div class="output_wrapper">
<div class="output">

<div class="output_area">

<div class="output_subarea output_stream output_stdout output_text">
<pre>Labels: tensor([6, 1, 3, 6, 6])
Embeddings: tensor([[-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
          0.0180, -0.4500],
        [ 1.0757, -0.8420, -0.7630, -0.0746,  1.1545,  0.4017,  0.5587,  1.7947,
          0.1992, -2.2288],
        [ 0.2646,  1.2383,  0.1949,  0.5743, -0.8460, -0.9929, -2.0350,  0.2095,
          0.2129, -0.4855],
        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
          0.0180, -0.4500],
        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,
          0.0180, -0.4500]], grad_fn=&lt;EmbeddingBackward&gt;)
tensor(94.9947, grad_fn=&lt;DivBackward0&gt;) tensor(1.)
Loss: tensor(94.9947, grad_fn=&lt;DivBackward0&gt;)
</pre>
</div>
</div>

</div>
</div>

</div>
    {% endraw %}

<div class="cell border-box-sizing text_cell rendered"><div class="inner_cell">
<div class="text_cell_render border-box-sizing rendered_html">
<h2 id="References">References<a class="anchor-link" href="#References"> </a></h2><ul>
<li><a href="https://github.com/omoindrot/tensorflow-triplet-loss">Triplet Loss and Online Triplet Mining in Tensorflow</a></li>
<li><a href="https://arxiv.org/abs/1503.03832">Facenet paper</a></li>
<li><a href="https://github.com/adambielski/siamese-triplet">adambielski's nice implementation</a> (unfortunately context switches between CPU / GPU)</li>
</ul>

</div>
</div>
</div>
</div>
 



================================================
FILE: docs/js/customscripts.js
================================================
$('#mysidebar').height($(".nav").height());


$( document ).ready(function() {

    //this script says, if the height of the viewport is greater than 800px, then insert affix class, which makes the nav bar float in a fixed
    // position as your scroll. if you have a lot of nav items, this height may not work for you.
    var h = $(window).height();
    //console.log (h);
    if (h > 800) {
        $( "#mysidebar" ).attr("class", "nav affix");
    }
    // activate tooltips. although this is a bootstrap js function, it must be activated this way in your theme.
    $('[data-toggle="tooltip"]').tooltip({
        placement : 'top'
    });

    /**
     * AnchorJS
     */
    anchors.add('h2,h3,h4,h5');

});

// needed for nav tabs on pages. See Formatting > Nav tabs for more details.
// script from http://stackoverflow.com/questions/10523433/how-do-i-keep-the-current-tab-active-with-twitter-bootstrap-after-a-page-reload
$(function() {
    var json, tabsState;
    $('a[data-toggle="pill"], a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
        var href, json, parentId, tabsState;

        tabsState = localStorage.getItem("tabs-state");
        json = JSON.parse(tabsState || "{}");
        parentId = $(e.target).parents("ul.nav.nav-pills, ul.nav.nav-tabs").attr("id");
        href = $(e.target).attr('href');
        json[parentId] = href;

        return localStorage.setItem("tabs-state", JSON.stringify(json));
    });

    tabsState = localStorage.getItem("tabs-state");
    json = JSON.parse(tabsState || "{}");

    $.each(json, function(containerId, href) {
        return $("#" + containerId + " a[href=" + href + "]").tab('show');
    });

    $("ul.nav.nav-pills, ul.nav.nav-tabs").each(function() {
        var $this = $(this);
        if (!json[$this.attr("id")]) {
            return $this.find("a[data-toggle=tab]:first, a[data-toggle=pill]:first").tab("show");
        }
    });
});


================================================
FILE: docs/js/jekyll-search.js
================================================
!function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module){module.exports=function(){function receivedResponse(xhr){return 200==xhr.status&&4==xhr.readyState}function handleResponse(xhr,callback){xhr.onreadystatechange=function(){if(receivedResponse(xhr))try{callback(null,JSON.parse(xhr.responseText))}catch(err){callback(err,null)}}}var self=this;self.load=function(location,callback){var xhr=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");xhr.open("GET",location,!0),handleResponse(xhr,callback),xhr.send()}}},{}],2:[function(require,module){function FuzzySearchStrategy(){function createFuzzyRegExpFromString(string){return new RegExp(string.split("").join(".*?"),"gi")}var self=this;self.matches=function(string,crit){return"string"!=typeof string?!1:(string=string.trim(),!!string.match(createFuzzyRegExpFromString(crit)))}}module.exports=new FuzzySearchStrategy},{}],3:[function(require,module){function LiteralSearchStrategy(){function doMatch(string,crit){return string.toLowerCase().indexOf(crit.toLowerCase())>=0}var self=this;self.matches=function(string,crit){return"string"!=typeof string?!1:(string=string.trim(),doMatch(string,crit))}}module.exports=new LiteralSearchStrategy},{}],4:[function(require,module){module.exports=function(){function findMatches(store,crit,strategy){for(var data=store.get(),i=0;i<data.length&&matches.length<limit;i++)findMatchesInObject(data[i],crit,strategy);return matches}function findMatchesInObject(obj,crit,strategy){for(var key in obj)if(strategy.matches(obj[key],crit)){matches.push(obj);break}}function getSearchStrategy(){return fuzzy?fuzzySearchStrategy:literalSearchStrategy}var self=this,matches=[],fuzzy=!1,limit=10,fuzzySearchStrategy=require("./SearchStrategies/fuzzy"),literalSearchStrategy=require("./SearchStrategies/literal");self.setFuzzy=function(_fuzzy){fuzzy=!!_fuzzy},self.setLimit=function(_limit){limit=parseInt(_limit,10)||limit},self.search=function(data,crit){return crit?(matches.length=0,findMatches(data,crit,getSearchStrategy())):[]}}},{"./SearchStrategies/fuzzy":2,"./SearchStrategies/literal":3}],5:[function(require,module){module.exports=function(_store){function isObject(obj){return!!obj&&"[object Object]"==Object.prototype.toString.call(obj)}function isArray(obj){return!!obj&&"[object Array]"==Object.prototype.toString.call(obj)}function addObject(data){return store.push(data),data}function addArray(data){for(var added=[],i=0;i<data.length;i++)isObject(data[i])&&added.push(addObject(data[i]));return added}var self=this,store=[];isArray(_store)&&addArray(_store),self.clear=function(){return store.length=0,store},self.get=function(){return store},self.put=function(data){return isObject(data)?addObject(data):isArray(data)?addArray(data):void 0}}},{}],6:[function(require,module){module.exports=function(){var self=this,templatePattern=/\{(.*?)\}/g;self.setTemplatePattern=function(newTemplatePattern){templatePattern=newTemplatePattern},self.render=function(t,data){return t.replace(templatePattern,function(match,prop){return data[prop]||match})}}},{}],7:[function(require){!function(window){"use strict";function SimpleJekyllSearch(){function initWithJSON(){store.put(opt.dataSource),registerInput()}function initWithURL(url){jsonLoader.load(url,function(err,json){err?throwError("failed to get JSON ("+url+")"):(store.put(json),registerInput())})}function throwError(message){throw new Error("SimpleJekyllSearch --- "+message)}function validateOptions(_opt){for(var i=0;i<requiredOptions.length;i++){var req=requiredOptions[i];_opt[req]||throwError("You must specify a "+req)}}function assignOptions(_opt){for(var option in opt)opt[option]=_opt[option]||opt[option]}function isJSON(json){try{return json instanceof Object&&JSON.parse(JSON.stringify(json))}catch(e){return!1}}function emptyResultsContainer(){opt.resultsContainer.innerHTML=""}function appendToResultsContainer(text){opt.resultsContainer.innerHTML+=text}function registerInput(){opt.searchInput.addEventListener("keyup",function(e){return 0==e.target.value.length?void emptyResultsContainer():void render(searcher.search(store,e.target.value))})}function render(results){if(emptyResultsContainer(),0==results.length)return appendToResultsContainer(opt.noResultsText);for(var i=0;i<results.length;i++)appendToResultsContainer(templater.render(opt.searchResultTemplate,results[i]))}var self=this,requiredOptions=["searchInput","resultsContainer","dataSource"],opt={searchInput:null,resultsContainer:null,dataSource:[],searchResultTemplate:'<li><a href="{url}" title="{desc}">{title}</a></li>',noResultsText:"No results found",limit:10,fuzzy:!1};self.init=function(_opt){validateOptions(_opt),assignOptions(_opt),isJSON(opt.dataSource)?initWithJSON(opt.dataSource):initWithURL(opt.dataSource)}}var Searcher=require("./Searcher"),Templater=require("./Templater"),Store=require("./Store"),JSONLoader=require("./JSONLoader"),searcher=new Searcher,templater=new Templater,store=new Store,jsonLoader=new JSONLoader;window.SimpleJekyllSearch=new SimpleJekyllSearch}(window,document)},{"./JSONLoader":1,"./Searcher":4,"./Store":5,"./Templater":6}]},{},[7]);


================================================
FILE: docs/js/toc.js
================================================
// https://github.com/ghiculescu/jekyll-table-of-contents
// this library modified by fastai to:
// - update the location.href with the correct anchor when a toc item is clicked on
(function($){
  $.fn.toc = function(options) {
    var defaults = {
      noBackToTopLinks: false,
      title: '',
      minimumHeaders: 3,
      headers: 'h1, h2, h3, h4',
      listType: 'ol', // values: [ol|ul]
      showEffect: 'show', // values: [show|slideDown|fadeIn|none]
      showSpeed: 'slow' // set to 0 to deactivate effect
    },
    settings = $.extend(defaults, options);

    var headers = $(settings.headers).filter(function() {
      // get all headers with an ID
      var previousSiblingName = $(this).prev().attr( "name" );
      if (!this.id && previousSiblingName) {
        this.id = $(this).attr( "id", previousSiblingName.replace(/\./g, "-") );
      }
      return this.id;
    }), output = $(this);
    if (!headers.length || headers.length < settings.minimumHeaders || !output.length) {
      return;
    }

    if (0 === settings.showSpeed) {
      settings.showEffect = 'none';
    }

    var render = {
      show: function() { output.hide().html(html).show(settings.showSpeed); },
      slideDown: function() { output.hide().html(html).slideDown(settings.showSpeed); },
      fadeIn: function() { output.hide().html(html).fadeIn(settings.showSpeed); },
      none: function() { output.html(html); }
    };

    var get_level = function(ele) { return parseInt(ele.nodeName.replace("H", ""), 10); }
    var highest_level = headers.map(function(_, ele) { return get_level(ele); }).get().sort()[0];
    //var return_to_top = '<i class="glyphicon glyphicon-upload back-to-top"></i>';
    // other nice icons that can be used instead: glyphicon-upload glyphicon-hand-up glyphicon-chevron-up glyphicon-menu-up glyphicon-triangle-top
    var level = get_level(headers[0]),
      this_level,
      html = settings.title + " <"+settings.listType+">";
    headers.on('click', function() {
      if (!settings.noBackToTopLinks) {
        var pos = $(window).scrollTop();
        window.location.hash = this.id;
        $(window).scrollTop(pos);
      }
    })
    .addClass('clickable-header')
    .each(function(_, header) {
      base_url = window.location.href;
      base_url = base_url.replace(/#.*$/, "");
      this_level = get_level(header);
      //if (!settings.noBackToTopLinks && this_level > 1) {
      //  $(header).addClass('top-level-header').before(return_to_top);
      //}
      txt = header.textContent.split('¶')[0].split(/\[(test|source)\]/)[0];
      if (!txt) {return;}
      if (this_level === level) // same level as before; same indenting
        html += "<li><a href='" + base_url + "#" + header.id + "'>" + txt + "</a>";
      else if (this_level <= level){ // higher level than before; end parent ol
        for(i = this_level; i < level; i++) {
          html += "</li></"+settings.listType+">"
        }
        html += "<li><a href='" + base_url + "#" + header.id + "'>" + txt + "</a>";
      }
      else if (this_level > level) { // lower level than before; expand the previous to contain a ol
        for(i = this_level; i > level; i--) {
          html += "<"+settings.listType+">"+((i-level == 2) ? "<li class=\"hide_content\">" : "<li>")
        }
        html += "<a href='" + base_url + "#" + header.id + "'>" + txt + "</a>";
      }
      level = this_level; // update for the next one
    });
    html += "</"+settings.listType+">";
    if (!settings.noBackToTopLinks) {
      $(document).on('click', '.back-to-top', function() {
        $(window).scrollTop(0);
        window.location.hash = '';
      });
    }

    render[settings.showEffect]();
  };
})(jQuery);


================================================
FILE: docs/licenses/LICENSE
================================================
/* This license pertains to the docs template, except for the Navgoco jQuery component. */

The MIT License (MIT)

Original theme: Copyright (c) 2016 Tom Johnson
Modifications: Copyright (c) 2017 onwards fast.ai, Inc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: docs/licenses/LICENSE-BSD-NAVGOCO.txt
================================================
/* This license pertains to the Navgoco jQuery component used for the sidebar. */

Copyright (c) 2013, Christodoulos Tsoulloftas, http://www.komposta.net
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
   * Neither the name of the <Christodoulos Tsoulloftas> nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

================================================
FILE: docs/sidebar.json
================================================
{
  "online_triplet_loss": {
    "Overview": "/",
    "Losses": "/triplet_loss"
  }
}

================================================
FILE: docs/sitemap.xml
================================================
---
layout: none
search: exclude
---

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  {% for post in site.posts %}
  {% unless post.search == "exclude" %}
  <url>
    <loc>{{site.url}}{{post.url}}</loc>
  </url>
  {% endunless %}
  {% endfor %}


  {% for page in site.pages %}
  {% unless page.search == "exclude" %}
  <url>
    <loc>{{site.url}}{{ page.url}}</loc>
  </url>
  {% endunless %}
  {% endfor %}
</urlset>

================================================
FILE: docs/tooltips.json
================================================
---
layout: null
search: exclude
---

{
"entries":
[
{% for page in site.tooltips %}
{
"doc_id": "{{ page.doc_id }}",
"body": "{{ page.content | strip_newlines | replace: '\', '\\\\' | replace: '"', '\\"' }}"
} {% unless forloop.last %},{% endunless %}
{% endfor %}
]
}





================================================
FILE: docs/triplet_loss.html
================================================
---

title: Losses

keywords: fastai
sidebar: home_sidebar

summary: "Where all of the losses are situated."
description: "Where all of the losses are situated."
---
<!--

#################################################
### THIS FILE WAS AUTOGENERATED! DO NOT EDIT! ###
#################################################
# file to edit: triplet_loss.ipynb
# command to build the docs after a change: nbdev_build_docs

-->

<div class="container" id="notebook-container">
        
    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">

</div>
    {% endraw %}

    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">

</div>
    {% endraw %}

    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">

</div>
    {% endraw %}

    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">

<div class="output_wrapper">
<div class="output">

<div class="output_area">


<div class="output_markdown rendered_html output_subarea ">
<h4 id="batch_hard_triplet_loss" class="doc_header"><code>batch_hard_triplet_loss</code><a href="https://github.com/NegatioN/OnlineMiningTripletLoss/tree/master/online_triplet_loss/losses.py#L103" class="source_link" style="float:right">[source]</a></h4><blockquote><p><code>batch_hard_triplet_loss</code>(<strong><code>labels</code></strong>, <strong><code>embeddings</code></strong>, <strong><code>margin</code></strong>, <strong><code>squared</code></strong>=<em><code>False</code></em>)</p>
</blockquote>
<p>Build the triplet loss over a batch of embeddings.</p>
<p>For each anchor, we get the hardest positive and hardest negative to form a triplet.</p>
<p>Args:
    labels: labels of the batch, of size (batch_size,)
    embeddings: tensor of shape (batch_size, embed_dim)
    margin: margin for triplet loss
    squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
             If false, output is the pairwise euclidean distance matrix.</p>
<p>Returns:
    triplet_loss: scalar tensor containing the triplet loss</p>

</div>

</div>

</div>
</div>

</div>
    {% endraw %}

    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">

</div>
    {% endraw %}

    {% raw %}
    
<div class="cell border-box-sizing code_cell rendered">

<div class="output_wrapper">
<div class="output">

<div class="output_area">


<div class="output_markdown rendered_html output_subarea ">
<h4 id="batch_all_triplet_loss" class="doc_header"><code>batch_all_triplet_loss</code><a href="https://github.com/NegatioN/OnlineMiningTripletLoss/tree/master/online_triplet_loss/losses.py#L150" class="source_link" style="float:right">[source]</a></h4><blockquote><p><code>batch_all_triplet_loss</code>(<strong><code>labels</code></strong>, <strong><code>embeddings</code></strong>, <strong><code>margin</code></strong>, <strong><code>squared</code></strong>=<em><code>False</code></em>)</p>
</blockquote>
<p>Build the triplet loss over a batch of embeddings.</p>
<p>We generate all the valid triplets and average the loss over the positive ones.</p>
<p>Args:
    labels: labels of the batch, of size (batch_size,)
    embeddings: tensor of shape (batch_size, embed_dim)
    margin: margin for triplet loss
    squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
             If false, output is the pairwise euclidean distance matrix.</p>
<p>Returns:
    triplet_loss: scalar tensor containing the triplet loss</p>

</div>

</div>

</div>
</div>

</div>
    {% endraw %}

</div>
 



================================================
FILE: index.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "from online_triplet_loss.losses import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# online_triplet_loss\n",
    "\n",
    "> PyTorch conversion of the excellent post on the [same topic in Tensorflow](https://omoindrot.github.io/triplet-loss). Simply an implementation of a triple loss with online mining of candidate triplets used in semi-supervised learning."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`pip install online_triplet_loss`\n",
    "\n",
    "Then import with:\n",
    "`from online_triplet_loss.losses import *`\n",
    "\n",
    "PS: Requires Pytorch version 1.1.0 or above to use."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How to use\n",
    "\n",
    "In these examples I use a really large margin, since the embedding space is so small. A more realistic margins seems to be between `0.1 and 2.0`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "import torch\n",
    "\n",
    "model = nn.Embedding(10, 10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": "Labels: tensor([6, 1, 3, 6, 6])\nEmbeddings: tensor([[-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,\n          0.0180, -0.4500],\n        [ 1.0757, -0.8420, -0.7630, -0.0746,  1.1545,  0.4017,  0.5587,  1.7947,\n          0.1992, -2.2288],\n        [ 0.2646,  1.2383,  0.1949,  0.5743, -0.8460, -0.9929, -2.0350,  0.2095,\n          0.2129, -0.4855],\n        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,\n          0.0180, -0.4500],\n        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,\n          0.0180, -0.4500]], grad_fn=<EmbeddingBackward>)\nLoss: tensor(95.1271, grad_fn=<MeanBackward0>)\n"
    }
   ],
   "source": [
    "#from online_triplet_loss.losses import *\n",
    "labels = torch.randint(high=10, size=(5,)) # our five labels\n",
    "\n",
    "embeddings = model(labels)\n",
    "print('Labels:', labels)\n",
    "print('Embeddings:', embeddings)\n",
    "loss = batch_hard_triplet_loss(labels, embeddings, margin=100)\n",
    "print('Loss:', loss)\n",
    "loss.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": "Labels: tensor([6, 1, 3, 6, 6])\nEmbeddings: tensor([[-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,\n          0.0180, -0.4500],\n        [ 1.0757, -0.8420, -0.7630, -0.0746,  1.1545,  0.4017,  0.5587,  1.7947,\n          0.1992, -2.2288],\n        [ 0.2646,  1.2383,  0.1949,  0.5743, -0.8460, -0.9929, -2.0350,  0.2095,\n          0.2129, -0.4855],\n        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,\n          0.0180, -0.4500],\n        [-1.1335,  0.3364, -3.0174, -0.8732, -0.9301,  1.3619,  0.3746,  0.0457,\n          0.0180, -0.4500]], grad_fn=<EmbeddingBackward>)\ntensor(94.9947, grad_fn=<DivBackward0>) tensor(1.)\nLoss: tensor(94.9947, grad_fn=<DivBackward0>)\n"
    }
   ],
   "source": [
    "#from online_triplet_loss.losses import *\n",
    "embeddings = model(labels)\n",
    "print('Labels:', labels)\n",
    "print('Embeddings:', embeddings)\n",
    "loss, fraction_pos = batch_all_triplet_loss(labels, embeddings, squared=False, margin=100)\n",
    "print('Loss:', loss)\n",
    "loss.backward()"
   ]
  },
  {
   "cell_type": "markdown",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## References\n",
    "* [Triplet Loss and Online Triplet Mining in Tensorflow](https://github.com/omoindrot/tensorflow-triplet-loss)\n",
    "* [Facenet paper](https://arxiv.org/abs/1503.03832)\n",
    "* [adambielski's nice implementation](https://github.com/adambielski/siamese-triplet) (unfortunately context switches between CPU / GPU)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}


================================================
FILE: online_triplet_loss/__init__.py
================================================
__version__ = "0.0.6"


================================================
FILE: online_triplet_loss/_nbdev.py
================================================
# AUTOGENERATED BY NBDEV! DO NOT EDIT!

__all__ = ["index", "modules", "custom_doc_links", "git_url"]

index = {"batch_hard_triplet_loss": "triplet_loss.ipynb",
         "batch_all_triplet_loss": "triplet_loss.ipynb"}

modules = ["losses.py"]

doc_url = "https://NegatioN.github.io/OnlineMiningTripletLoss/"

git_url = "https://github.com/NegatioN/OnlineMiningTripletLoss/tree/master/"

def custom_doc_links(name): return None


================================================
FILE: online_triplet_loss/losses.py
================================================
# AUTOGENERATED! DO NOT EDIT! File to edit: triplet_loss.ipynb (unless otherwise specified).

__all__ = ['batch_hard_triplet_loss', 'batch_all_triplet_loss']

# Cell
import torch
import torch.nn.functional as F
def _pairwise_distances(embeddings, squared=False):
    """Compute the 2D matrix of distances between all the embeddings.

    Args:
        embeddings: tensor of shape (batch_size, embed_dim)
        squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
                 If false, output is the pairwise euclidean distance matrix.

    Returns:
        pairwise_distances: tensor of shape (batch_size, batch_size)
    """
    dot_product = torch.matmul(embeddings, embeddings.t())

    # Get squared L2 norm for each embedding. We can just take the diagonal of `dot_product`.
    # This also provides more numerical stability (the diagonal of the result will be exactly 0).
    # shape (batch_size,)
    square_norm = torch.diag(dot_product)

    # Compute the pairwise distance matrix as we have:
    # ||a - b||^2 = ||a||^2  - 2 <a, b> + ||b||^2
    # shape (batch_size, batch_size)
    distances = square_norm.unsqueeze(0) - 2.0 * dot_product + square_norm.unsqueeze(1)

    # Because of computation errors, some distances might be negative so we put everything >= 0.0
    distances[distances < 0] = 0

    if not squared:
        # Because the gradient of sqrt is infinite when distances == 0.0 (ex: on the diagonal)
        # we need to add a small epsilon where distances == 0.0
        mask = distances.eq(0).float()
        distances = distances + mask * 1e-16

        distances = (1.0 -mask) * torch.sqrt(distances)

    return distances

def _get_triplet_mask(labels):
    """Return a 3D mask where mask[a, p, n] is True iff the triplet (a, p, n) is valid.
    A triplet (i, j, k) is valid if:
        - i, j, k are distinct
        - labels[i] == labels[j] and labels[i] != labels[k]
    Args:
        labels: tf.int32 `Tensor` with shape [batch_size]
    """
    # Check that i, j and k are distinct
    indices_equal = torch.eye(labels.size(0), device=labels.device).bool()
    indices_not_equal = ~indices_equal
    i_not_equal_j = indices_not_equal.unsqueeze(2)
    i_not_equal_k = indices_not_equal.unsqueeze(1)
    j_not_equal_k = indices_not_equal.unsqueeze(0)

    distinct_indices = (i_not_equal_j & i_not_equal_k) & j_not_equal_k


    label_equal = labels.unsqueeze(0) == labels.unsqueeze(1)
    i_equal_j = label_equal.unsqueeze(2)
    i_equal_k = label_equal.unsqueeze(1)

    valid_labels = ~i_equal_k & i_equal_j

    return valid_labels & distinct_indices


def _get_anchor_positive_triplet_mask(labels):
    """Return a 2D mask where mask[a, p] is True iff a and p are distinct and have same label.
    Args:
        labels: tf.int32 `Tensor` with shape [batch_size]
    Returns:
        mask: tf.bool `Tensor` with shape [batch_size, batch_size]
    """
    # Check that i and j are distinct
    indices_equal = torch.eye(labels.size(0), device=labels.device).bool()
    indices_not_equal = ~indices_equal

    # Check if labels[i] == labels[j]
    # Uses broadcasting where the 1st argument has shape (1, batch_size) and the 2nd (batch_size, 1)
    labels_equal = labels.unsqueeze(0) == labels.unsqueeze(1)

    return labels_equal & indices_not_equal


def _get_anchor_negative_triplet_mask(labels):
    """Return a 2D mask where mask[a, n] is True iff a and n have distinct labels.
    Args:
        labels: tf.int32 `Tensor` with shape [batch_size]
    Returns:
        mask: tf.bool `Tensor` with shape [batch_size, batch_size]
    """
    # Check if labels[i] != labels[k]
    # Uses broadcasting where the 1st argument has shape (1, batch_size) and the 2nd (batch_size, 1)

    return ~(labels.unsqueeze(0) == labels.unsqueeze(1))


# Cell
def batch_hard_triplet_loss(labels, embeddings, margin, squared=False):
    """Build the triplet loss over a batch of embeddings.

    For each anchor, we get the hardest positive and hardest negative to form a triplet.

    Args:
        labels: labels of the batch, of size (batch_size,)
        embeddings: tensor of shape (batch_size, embed_dim)
        margin: margin for triplet loss
        squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
                 If false, output is the pairwise euclidean distance matrix.

    Returns:
        triplet_loss: scalar tensor containing the triplet loss
    """
    # Get the pairwise distance matrix
    pairwise_dist = _pairwise_distances(embeddings, squared=squared)

    # For each anchor, get the hardest positive
    # First, we need to get a mask for every valid positive (they should have same label)
    mask_anchor_positive = _get_anchor_positive_triplet_mask(labels).float()

    # We put to 0 any element where (a, p) is not valid (valid if a != p and label(a) == label(p))
    anchor_positive_dist = mask_anchor_positive * pairwise_dist

    # shape (batch_size, 1)
    hardest_positive_dist, _ = anchor_positive_dist.max(1, keepdim=True)

    # For each anchor, get the hardest negative
    # First, we need to get a mask for every valid negative (they should have different labels)
    mask_anchor_negative = _get_anchor_negative_triplet_mask(labels).float()

    # We add the maximum value in each row to the invalid negatives (label(a) == label(n))
    max_anchor_negative_dist, _ = pairwise_dist.max(1, keepdim=True)
    anchor_negative_dist = pairwise_dist + max_anchor_negative_dist * (1.0 - mask_anchor_negative)

    # shape (batch_size,)
    hardest_negative_dist, _ = anchor_negative_dist.min(1, keepdim=True)

    # Combine biggest d(a, p) and smallest d(a, n) into final triplet loss
    tl = hardest_positive_dist - hardest_negative_dist + margin
    tl = F.relu(tl)
    triplet_loss = tl.mean()

    return triplet_loss

# Cell
def batch_all_triplet_loss(labels, embeddings, margin, squared=False):
    """Build the triplet loss over a batch of embeddings.

    We generate all the valid triplets and average the loss over the positive ones.

    Args:
        labels: labels of the batch, of size (batch_size,)
        embeddings: tensor of shape (batch_size, embed_dim)
        margin: margin for triplet loss
        squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
                 If false, output is the pairwise euclidean distance matrix.

    Returns:
        triplet_loss: scalar tensor containing the triplet loss
    """
    # Get the pairwise distance matrix
    pairwise_dist = _pairwise_distances(embeddings, squared=squared)

    anchor_positive_dist = pairwise_dist.unsqueeze(2)
    anchor_negative_dist = pairwise_dist.unsqueeze(1)

    # Compute a 3D tensor of size (batch_size, batch_size, batch_size)
    # triplet_loss[i, j, k] will contain the triplet loss of anchor=i, positive=j, negative=k
    # Uses broadcasting where the 1st argument has shape (batch_size, batch_size, 1)
    # and the 2nd (batch_size, 1, batch_size)
    triplet_loss = anchor_positive_dist - anchor_negative_dist + margin



    # Put to zero the invalid triplets
    # (where label(a) != label(p) or label(n) == label(a) or a == p)
    mask = _get_triplet_mask(labels)
    triplet_loss = mask.float() * triplet_loss

    # Remove negative losses (i.e. the easy triplets)
    triplet_loss = F.relu(triplet_loss)

    # Count number of positive triplets (where triplet_loss > 0)
    valid_triplets = triplet_loss[triplet_loss > 1e-16]
    num_positive_triplets = valid_triplets.size(0)
    num_valid_triplets = mask.sum()

    fraction_positive_triplets = num_positive_triplets / (num_valid_triplets.float() + 1e-16)

    # Get final mean triplet loss over the positive valid triplets
    triplet_loss = triplet_loss.sum() / (num_positive_triplets + 1e-16)

    return triplet_loss, fraction_positive_triplets


================================================
FILE: settings.ini
================================================
[DEFAULT]
lib_name = online_triplet_loss
user = NegatioN
description = "Online mining triplet losses for Pytorch"
keywords = pytorch loss online triplet mining
author = "Joakim Rishaug"
author_email = "joakimrishaug@notmyrealemail.com"
copyright = "Joakim Rishaug"
branch = master
version = 0.0.6
min_python = 3.6
audience = Developers
language = English
custom_sidebar = False
license = apache2
status = 2
nbs_path = .
doc_path = docs
requirements = numpy>=1.15.4 torch>=1.1.0
repo_name = OnlineMiningTripletLoss
doc_host = https://NegatioN.github.io
doc_baseurl = /OnlineMiningTripletLoss/
git_url = https://github.com/NegatioN/OnlineMiningTripletLoss/tree/master/
lib_path = online_triplet_loss
title = OnlineMiningTripletLoss
host = github



================================================
FILE: setup.py
================================================
from packaging.version import parse
from configparser import ConfigParser
import setuptools
assert parse(setuptools.__version__)>=parse('36.2')

# note: all settings are in settings.ini; edit there, not here
config = ConfigParser(delimiters=['='])
config.read('settings.ini')
cfg = config['DEFAULT']

cfg_keys = 'version description keywords author author_email'.split()
expected = cfg_keys + "lib_name user branch license status min_python audience language".split()
for o in expected: assert o in cfg, "missing expected setting: {}".format(o)
setup_cfg = {o:cfg[o] for o in cfg_keys}

licenses = {
    'apache2': ('Apache Software License 2.0','OSI Approved :: Apache Software License'),
}
statuses = [ '1 - Planning', '2 - Pre-Alpha', '3 - Alpha',
    '4 - Beta', '5 - Production/Stable', '6 - Mature', '7 - Inactive' ]
py_versions = '2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8'.split()

requirements = cfg.get('requirements','').split()
lic = licenses[cfg['license']]
min_python = cfg['min_python']

setuptools.setup(
    name = cfg['lib_name'],
    license = lic[0],
    classifiers = [
        'Development Status :: ' + statuses[int(cfg['status'])],
        'Intended Audience :: ' + cfg['audience'].title(),
        'License :: ' + lic[1],
        'Natural Language :: ' + cfg['language'].title(),
    ] + ['Programming Language :: Python :: '+o for o in py_versions[py_versions.index(min_python):]],
    url = 'https://github.com/{}/{}'.format(cfg['user'],cfg['repo_name']),
    packages = setuptools.find_packages(),
    include_package_data = True,
    install_requires = requirements,
    python_requires  = '>=' + cfg['min_python'],
    long_description = open('README.md').read(),
    long_description_content_type = 'text/markdown',
    zip_safe = False,
    entry_points = { 'console_scripts': cfg.get('console_scripts','').split() },
    **setup_cfg)



================================================
FILE: triplet_loss.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp losses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Losses\n",
    "> Where all of the losses are situated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "from nbdev.showdoc import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "import torch\n",
    "import torch.nn.functional as F\n",
    "def _pairwise_distances(embeddings, squared=False):\n",
    "    \"\"\"Compute the 2D matrix of distances between all the embeddings.\n",
    "\n",
    "    Args:\n",
    "        embeddings: tensor of shape (batch_size, embed_dim)\n",
    "        squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.\n",
    "                 If false, output is the pairwise euclidean distance matrix.\n",
    "\n",
    "    Returns:\n",
    "        pairwise_distances: tensor of shape (batch_size, batch_size)\n",
    "    \"\"\"\n",
    "    dot_product = torch.matmul(embeddings, embeddings.t())\n",
    "\n",
    "    # Get squared L2 norm for each embedding. We can just take the diagonal of `dot_product`.\n",
    "    # This also provides more numerical stability (the diagonal of the result will be exactly 0).\n",
    "    # shape (batch_size,)\n",
    "    square_norm = torch.diag(dot_product)\n",
    "\n",
    "    # Compute the pairwise distance matrix as we have:\n",
    "    # ||a - b||^2 = ||a||^2  - 2 <a, b> + ||b||^2\n",
    "    # shape (batch_size, batch_size)\n",
    "    distances = square_norm.unsqueeze(0) - 2.0 * dot_product + square_norm.unsqueeze(1)\n",
    "\n",
    "    # Because of computation errors, some distances might be negative so we put everything >= 0.0\n",
    "    distances[distances < 0] = 0\n",
    "\n",
    "    if not squared:\n",
    "        # Because the gradient of sqrt is infinite when distances == 0.0 (ex: on the diagonal)\n",
    "        # we need to add a small epsilon where distances == 0.0\n",
    "        mask = distances.eq(0).float()\n",
    "        distances = distances + mask * 1e-16\n",
    "\n",
    "        distances = (1.0 -mask) * torch.sqrt(distances)\n",
    "\n",
    "    return distances\n",
    "\n",
    "def _get_triplet_mask(labels):\n",
    "    \"\"\"Return a 3D mask where mask[a, p, n] is True iff the triplet (a, p, n) is valid.\n",
    "    A triplet (i, j, k) is valid if:\n",
    "        - i, j, k are distinct\n",
    "        - labels[i] == labels[j] and labels[i] != labels[k]\n",
    "    Args:\n",
    "        labels: tf.int32 `Tensor` with shape [batch_size]\n",
    "    \"\"\"\n",
    "    # Check that i, j and k are distinct\n",
    "    indices_equal = torch.eye(labels.size(0), device=labels.device).bool()\n",
    "    indices_not_equal = ~indices_equal\n",
    "    i_not_equal_j = indices_not_equal.unsqueeze(2)\n",
    "    i_not_equal_k = indices_not_equal.unsqueeze(1)\n",
    "    j_not_equal_k = indices_not_equal.unsqueeze(0)\n",
    "\n",
    "    distinct_indices = (i_not_equal_j & i_not_equal_k) & j_not_equal_k\n",
    "\n",
    "\n",
    "    label_equal = labels.unsqueeze(0) == labels.unsqueeze(1)\n",
    "    i_equal_j = label_equal.unsqueeze(2)\n",
    "    i_equal_k = label_equal.unsqueeze(1)\n",
    "\n",
    "    valid_labels = ~i_equal_k & i_equal_j\n",
    "\n",
    "    return valid_labels & distinct_indices\n",
    "\n",
    "\n",
    "def _get_anchor_positive_triplet_mask(labels):\n",
    "    \"\"\"Return a 2D mask where mask[a, p] is True iff a and p are distinct and have same label.\n",
    "    Args:\n",
    "        labels: tf.int32 `Tensor` with shape [batch_size]\n",
    "    Returns:\n",
    "        mask: tf.bool `Tensor` with shape [batch_size, batch_size]\n",
    "    \"\"\"\n",
    "    # Check that i and j are distinct\n",
    "    indices_equal = torch.eye(labels.size(0), device=labels.device).bool()\n",
    "    indices_not_equal = ~indices_equal\n",
    "\n",
    "    # Check if labels[i] == labels[j]\n",
    "    # Uses broadcasting where the 1st argument has shape (1, batch_size) and the 2nd (batch_size, 1)\n",
    "    labels_equal = labels.unsqueeze(0) == labels.unsqueeze(1)\n",
    "\n",
    "    return labels_equal & indices_not_equal\n",
    "\n",
    "\n",
    "def _get_anchor_negative_triplet_mask(labels):\n",
    "    \"\"\"Return a 2D mask where mask[a, n] is True iff a and n have distinct labels.\n",
    "    Args:\n",
    "        labels: tf.int32 `Tensor` with shape [batch_size]\n",
    "    Returns:\n",
    "        mask: tf.bool `Tensor` with shape [batch_size, batch_size]\n",
    "    \"\"\"\n",
    "    # Check if labels[i] != labels[k]\n",
    "    # Uses broadcasting where the 1st argument has shape (1, batch_size) and the 2nd (batch_size, 1)\n",
    "\n",
    "    return ~(labels.unsqueeze(0) == labels.unsqueeze(1))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "import numpy as np\n",
    "\n",
    "# Test-suite from https://github.com/omoindrot/tensorflow-triplet-loss/blob/master/model/tests/test_triplet_loss.py\n",
    "# Skipped the `test_gradients_pairwise_distances()` test since it's trivial to see if your model loss turns NaN\n",
    "# and porting it proved more difficult than expected.\n",
    "\n",
    "def pairwise_distance_np(feature, squared=False):\n",
    "    \"\"\"Computes the pairwise distance matrix in numpy.\n",
    "    Args:\n",
    "        feature: 2-D numpy array of size [number of data, feature dimension]\n",
    "        squared: Boolean. If true, output is the pairwise squared euclidean\n",
    "                 distance matrix; else, output is the pairwise euclidean distance matrix.\n",
    "    Returns:\n",
    "        pairwise_distances: 2-D numpy array of size\n",
    "                            [number of data, number of data].\n",
    "    \"\"\"\n",
    "    triu = np.triu_indices(feature.shape[0], 1)\n",
    "    upper_tri_pdists = np.linalg.norm(feature[triu[1]] - feature[triu[0]], axis=1)\n",
    "    if squared:\n",
    "        upper_tri_pdists **= 2.\n",
    "    num_data = feature.shape[0]\n",
    "    pairwise_distances = np.zeros((num_data, num_data))\n",
    "    pairwise_distances[np.triu_indices(num_data, 1)] = upper_tri_pdists\n",
    "    # Make symmetrical.\n",
    "    pairwise_distances = pairwise_distances + pairwise_distances.T - np.diag(\n",
    "        pairwise_distances.diagonal())\n",
    "    return pairwise_distances\n",
    "\n",
    "def test_pairwise_distances():\n",
    "    \"\"\"Test the pairwise distances function.\"\"\"\n",
    "    num_data = 64\n",
    "    feat_dim = 6\n",
    "    np.random.seed(42)\n",
    "\n",
    "    embeddings = np.random.randn(num_data, feat_dim).astype(np.float32)\n",
    "    embeddings[1] = embeddings[0]  # to get distance 0\n",
    "\n",
    "    for squared in [True, False]:\n",
    "        res_np = pairwise_distance_np(embeddings, squared=squared)\n",
    "        res_pt = _pairwise_distances(torch.from_numpy(embeddings), squared=squared)\n",
    "        assert np.allclose(res_np, res_pt)\n",
    "\n",
    "def test_pairwise_distances_are_positive():\n",
    "    \"\"\"Test that the pairwise distances are always positive.\n",
    "    Use a tricky case where numerical errors are common.\n",
    "    \"\"\"\n",
    "    num_data = 64\n",
    "    feat_dim = 6\n",
    "    np.random.seed(42)\n",
    "\n",
    "    # Create embeddings very close to each other in [1.0 - 2e-7, 1.0 + 2e-7]\n",
    "    # This will encourage errors in the computation\n",
    "    embeddings = 1.0 + 2e-7 * np.random.randn(num_data, feat_dim).astype(np.float32)\n",
    "    embeddings[1] = embeddings[0]  # to get distance 0\n",
    "\n",
    "    for squared in [True, False]:\n",
    "        res_tf = _pairwise_distances(torch.from_numpy(embeddings), squared=squared)\n",
    "        assert res_tf[res_tf < 0].sum() == 0\n",
    "\n",
    "\n",
    "def test_triplet_mask():\n",
    "    \"\"\"Test function _get_triplet_mask.\"\"\"\n",
    "    num_data = 64\n",
    "    num_classes = 10\n",
    "    np.random.seed(42)\n",
    "\n",
    "    labels = np.random.randint(0, num_classes, size=(num_data)).astype(np.float32)\n",
    "\n",
    "    mask_np = np.zeros((num_data, num_data, num_data))\n",
    "    for i in range(num_data):\n",
    "        for j in range(num_data):\n",
    "            for k in range(num_data):\n",
    "                distinct = (i != j and i != k and j != k)\n",
    "                valid = (labels[i] == labels[j]) and (labels[i] != labels[k])\n",
    "                mask_np[i, j, k] = (distinct and valid)\n",
    "\n",
    "    mask_tf_val = _get_triplet_mask(torch.from_numpy(labels))\n",
    "    assert np.allclose(mask_np, mask_tf_val)\n",
    "\n",
    "def test_anchor_positive_triplet_mask():\n",
    "    \"\"\"Test function _get_anchor_positive_triplet_mask.\"\"\"\n",
    "    num_data = 64\n",
    "    num_classes = 10\n",
    "    np.random.seed(42)\n",
    "\n",
    "    labels = np.random.randint(0, num_classes, size=(num_data)).astype(np.float32)\n",
    "\n",
    "    mask_np = np.zeros((num_data, num_data))\n",
    "    for i in range(num_data):\n",
    "        for j in range(num_data):\n",
    "            distinct = (i != j)\n",
    "            valid = labels[i] == labels[j]\n",
    "            mask_np[i, j] = (distinct and valid)\n",
    "\n",
    "    mask_tf_val = _get_anchor_positive_triplet_mask(torch.from_numpy(labels))\n",
    "\n",
    "    assert np.allclose(mask_np, mask_tf_val)\n",
    "\n",
    "def test_anchor_negative_triplet_mask():\n",
    "    \"\"\"Test function _get_anchor_negative_triplet_mask.\"\"\"\n",
    "    num_data = 64\n",
    "    num_classes = 10\n",
    "    np.random.seed(42)\n",
    "\n",
    "    labels = np.random.randint(0, num_classes, size=(num_data)).astype(np.float32)\n",
    "\n",
    "    mask_np = np.zeros((num_data, num_data))\n",
    "    for i in range(num_data):\n",
    "        for k in range(num_data):\n",
    "            distinct = (i != k)\n",
    "            valid = (labels[i] != labels[k])\n",
    "            mask_np[i, k] = (distinct and valid)\n",
    "\n",
    "    mask_tf_val = _get_anchor_negative_triplet_mask(torch.from_numpy(labels))\n",
    "\n",
    "    assert np.allclose(mask_np, mask_tf_val)\n",
    "\n",
    "test_pairwise_distances()\n",
    "test_pairwise_distances_are_positive()\n",
    "test_triplet_mask()\n",
    "test_anchor_positive_triplet_mask()\n",
    "test_anchor_negative_triplet_mask()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def batch_hard_triplet_loss(labels, embeddings, margin, squared=False):\n",
    "    \"\"\"Build the triplet loss over a batch of embeddings.\n",
    "\n",
    "    For each anchor, we get the hardest positive and hardest negative to form a triplet.\n",
    "\n",
    "    Args:\n",
    "        labels: labels of the batch, of size (batch_size,)\n",
    "        embeddings: tensor of shape (batch_size, embed_dim)\n",
    "        margin: margin for triplet loss\n",
    "        squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.\n",
    "                 If false, output is the pairwise euclidean distance matrix.\n",
    "\n",
    "    Returns:\n",
    "        triplet_loss: scalar tensor containing the triplet loss\n",
    "    \"\"\"\n",
    "    # Get the pairwise distance matrix\n",
    "    pairwise_dist = _pairwise_distances(embeddings, squared=squared)\n",
    "\n",
    "    # For each anchor, get the hardest positive\n",
    "    # First, we need to get a mask for every valid positive (they should have same label)\n",
    "    mask_anchor_positive = _get_anchor_positive_triplet_mask(labels).float()\n",
    "\n",
    "    # We put to 0 any element where (a, p) is not valid (valid if a != p and label(a) == label(p))\n",
    "    anchor_positive_dist = mask_anchor_positive * pairwise_dist\n",
    "\n",
    "    # shape (batch_size, 1)\n",
    "    hardest_positive_dist, _ = anchor_positive_dist.max(1, keepdim=True)\n",
    "\n",
    "    # For each anchor, get the hardest negative\n",
    "    # First, we need to get a mask for every valid negative (they should have different labels)\n",
    "    mask_anchor_negative = _get_anchor_negative_triplet_mask(labels).float()\n",
    "\n",
    "    # We add the maximum value in each row to the invalid negatives (label(a) == label(n))\n",
    "    max_anchor_negative_dist, _ = pairwise_dist.max(1, keepdim=True)\n",
    "    anchor_negative_dist = pairwise_dist + max_anchor_negative_dist * (1.0 - mask_anchor_negative)\n",
    "\n",
    "    # shape (batch_size,)\n",
    "    hardest_negative_dist, _ = anchor_negative_dist.min(1, keepdim=True)\n",
    "\n",
    "    # Combine biggest d(a, p) and smallest d(a, n) into final triplet loss\n",
    "    tl = hardest_positive_dist - hardest_negative_dist + margin\n",
    "    tl = F.relu(tl)\n",
    "    triplet_loss = tl.mean()\n",
    "\n",
    "    return triplet_loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "def batch_all_triplet_loss(labels, embeddings, margin, squared=False):\n",
    "    \"\"\"Build the triplet loss over a batch of embeddings.\n",
    "\n",
    "    We generate all the valid triplets and average the loss over the positive ones.\n",
    "\n",
    "    Args:\n",
    "        labels: labels of the batch, of size (batch_size,)\n",
    "        embeddings: tensor of shape (batch_size, embed_dim)\n",
    "        margin: margin for triplet loss\n",
    "        squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.\n",
    "                 If false, output is the pairwise euclidean distance matrix.\n",
    "\n",
    "    Returns:\n",
    "        triplet_loss: scalar tensor containing the triplet loss\n",
    "    \"\"\"\n",
    "    # Get the pairwise distance matrix\n",
    "    pairwise_dist = _pairwise_distances(embeddings, squared=squared)\n",
    "\n",
    "    anchor_positive_dist = pairwise_dist.unsqueeze(2)\n",
    "    anchor_negative_dist = pairwise_dist.unsqueeze(1)\n",
    "\n",
    "    # Compute a 3D tensor of size (batch_size, batch_size, batch_size)\n",
    "    # triplet_loss[i, j, k] will contain the triplet loss of anchor=i, positive=j, negative=k\n",
    "    # Uses broadcasting where the 1st argument has shape (batch_size, batch_size, 1)\n",
    "    # and the 2nd (batch_size, 1, batch_size)\n",
    "    triplet_loss = anchor_positive_dist - anchor_negative_dist + margin\n",
    "\n",
    "\n",
    "\n",
    "    # Put to zero the invalid triplets\n",
    "    # (where label(a) != label(p) or label(n) == label(a) or a == p)\n",
    "    mask = _get_triplet_mask(labels)\n",
    "    triplet_loss = mask.float() * triplet_loss\n",
    "\n",
    "    # Remove negative losses (i.e. the easy triplets)\n",
    "    triplet_loss = F.relu(triplet_loss)\n",
    "\n",
    "    # Count number of positive triplets (where triplet_loss > 0)\n",
    "    valid_triplets = triplet_loss[triplet_loss > 1e-16]\n",
    "    num_positive_triplets = valid_triplets.size(0)\n",
    "    num_valid_triplets = mask.sum()\n",
    "\n",
    "    fraction_positive_triplets = num_positive_triplets / (num_valid_triplets.float() + 1e-16)\n",
    "\n",
    "    # Get final mean triplet loss over the positive valid triplets\n",
    "    triplet_loss = triplet_loss.sum() / (num_positive_triplets + 1e-16)\n",
    "\n",
    "    return triplet_loss, fraction_positive_triplets\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(0.) tensor(0.)\n",
      "tensor(0.) tensor(0.)\n",
      "tensor(0.7060) tensor(0.7155)\n",
      "tensor(0.3978) tensor(0.8276)\n"
     ]
    }
   ],
   "source": [
    "#hide\n",
    "def test_simple_batch_all_triplet_loss():\n",
    "    \"\"\"Test the triplet loss with batch all triplet mining in a simple case.\n",
    "    There is just one class in this super simple edge case, and we want to make sure that\n",
    "    the loss is 0.\n",
    "    \"\"\"\n",
    "    num_data = 10\n",
    "    feat_dim = 6\n",
    "    margin = 0.2\n",
    "    num_classes = 1\n",
    "    np.random.seed(42)\n",
    "\n",
    "    embeddings = np.random.rand(num_data, feat_dim).astype(np.float32)\n",
    "    labels = np.random.randint(0, num_classes, size=(num_data)).astype(np.float32)\n",
    "    labels, embeddings = torch.from_numpy(labels), torch.from_numpy(embeddings)\n",
    "\n",
    "    for squared in [True, False]:\n",
    "        loss_np = 0.0\n",
    "\n",
    "        # Compute the loss in TF.\n",
    "        loss_tf_val, fraction_val = batch_all_triplet_loss(labels, embeddings, margin, squared=squared)\n",
    "        print(loss_tf_val, fraction_val)\n",
    "        assert np.allclose(loss_np, loss_tf_val)\n",
    "        assert np.allclose(fraction_val, 0.0)\n",
    "\n",
    "\n",
    "def test_batch_all_triplet_loss():\n",
    "    \"\"\"Test the triplet loss with batch all triplet mining\"\"\"\n",
    "    num_data = 10\n",
    "    feat_dim = 6\n",
    "    margin = 0.2\n",
    "    num_classes = 5\n",
    "    np.random.seed(42)\n",
    "\n",
    "    embeddings = np.random.rand(num_data, feat_dim).astype(np.float32)\n",
    "    labels = np.random.randint(0, num_classes, size=(num_data)).astype(np.float32)\n",
    "\n",
    "    for squared in [True, False]:\n",
    "        pdist_matrix = pairwise_distance_np(embeddings, squared=squared)\n",
    "\n",
    "        loss_np = 0.0\n",
    "        num_positives = 0.0\n",
    "        num_valid = 0.0\n",
    "        for i in range(num_data):\n",
    "            for j in range(num_data):\n",
    "                for k in range(num_data):\n",
    "                    distinct = (i != j and i != k and j != k)\n",
    "                    valid = (labels[i] == labels[j]) and (labels[i] != labels[k])\n",
    "                    if distinct and valid:\n",
    "                        num_valid += 1.0\n",
    "\n",
    "                        pos_distance = pdist_matrix[i][j]\n",
    "                        neg_distance = pdist_matrix[i][k]\n",
    "\n",
    "                        loss = np.maximum(0.0, pos_distance - neg_distance + margin)\n",
    "                        loss_np += loss\n",
    "\n",
    "                        num_positives += (loss > 0)\n",
    "\n",
    "        loss_np /= num_positives\n",
    "\n",
    "        # Compute the loss in TF.\n",
    "        loss_tf_val, fraction_val = batch_all_triplet_loss(torch.from_numpy(labels), torch.from_numpy(embeddings), margin, squared=squared)\n",
    "        print(loss_tf_val, fraction_val)\n",
    "        assert np.allclose(loss_np, loss_tf_val)\n",
    "        assert np.allclose(num_positives / num_valid, fraction_val)\n",
    "\n",
    "def test_batch_hard_triplet_loss():\n",
    "    \"\"\"Test the triplet loss with batch hard triplet mining\"\"\"\n",
    "    num_data = 50\n",
    "    feat_dim = 6\n",
    "    margin = 0.2\n",
    "    num_classes = 5\n",
    "    np.random.seed(42)\n",
    "\n",
    "    embeddings = np.random.rand(num_data, feat_dim).astype(np.float32)\n",
    "    labels = np.random.randint(0, num_classes, size=(num_data)).astype(np.float32)\n",
    "\n",
    "    for squared in [True, False]:\n",
    "        pdist_matrix = pairwise_distance_np(embeddings, squared=squared)\n",
    "\n",
    "        loss_np = 0.0\n",
    "        for i in range(num_data):\n",
    "            # Select the hardest positive\n",
    "            max_pos_dist = np.max(pdist_matrix[i][labels == labels[i]])\n",
    "\n",
    "            # Select the hardest negative\n",
    "            min_neg_dist = np.min(pdist_matrix[i][labels != labels[i]])\n",
    "\n",
    "            loss = np.maximum(0.0, max_pos_dist - min_neg_dist + margin)\n",
    "            loss_np += loss\n",
    "\n",
    "        loss_np /= num_data\n",
    "\n",
    "        # Compute the loss in TF.\n",
    "        loss_tf_val = batch_hard_triplet_loss(torch.from_numpy(labels), torch.from_numpy(embeddings), margin, squared=squared)\n",
    "        assert np.allclose(loss_np, loss_tf_val)\n",
    "\n",
    "test_simple_batch_all_triplet_loss()\n",
    "test_batch_all_triplet_loss()\n",
    "test_batch_hard_triplet_loss()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
Download .txt
gitextract_53kablsc/

├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── docs/
│   ├── .gitignore
│   ├── Gemfile
│   ├── _config.yml
│   ├── _data/
│   │   ├── alerts.yml
│   │   ├── definitions.yml
│   │   ├── glossary.yml
│   │   ├── sidebars/
│   │   │   └── home_sidebar.yml
│   │   ├── tags.yml
│   │   ├── terms.yml
│   │   └── topnav.yml
│   ├── _includes/
│   │   ├── archive.html
│   │   ├── callout.html
│   │   ├── footer.html
│   │   ├── google_analytics.html
│   │   ├── head.html
│   │   ├── head_print.html
│   │   ├── image.html
│   │   ├── important.html
│   │   ├── initialize_shuffle.html
│   │   ├── inline_image.html
│   │   ├── links.html
│   │   ├── note.html
│   │   ├── search_google_custom.html
│   │   ├── search_simple_jekyll.html
│   │   ├── sidebar.html
│   │   ├── tip.html
│   │   ├── toc.html
│   │   ├── topnav.html
│   │   └── warning.html
│   ├── _layouts/
│   │   ├── default.html
│   │   ├── default_print.html
│   │   ├── none.html
│   │   ├── page.html
│   │   └── page_print.html
│   ├── css/
│   │   ├── boxshadowproperties.css
│   │   ├── customstyles.css
│   │   ├── fonts/
│   │   │   └── FontAwesome.otf
│   │   ├── modern-business.css
│   │   ├── printstyles.css
│   │   ├── syntax.css
│   │   ├── theme-blue.css
│   │   └── theme-green.css
│   ├── feed.xml
│   ├── fonts/
│   │   └── FontAwesome.otf
│   ├── index.html
│   ├── js/
│   │   ├── customscripts.js
│   │   ├── jekyll-search.js
│   │   └── toc.js
│   ├── licenses/
│   │   ├── LICENSE
│   │   └── LICENSE-BSD-NAVGOCO.txt
│   ├── sidebar.json
│   ├── sitemap.xml
│   ├── tooltips.json
│   └── triplet_loss.html
├── index.ipynb
├── online_triplet_loss/
│   ├── __init__.py
│   ├── _nbdev.py
│   └── losses.py
├── settings.ini
├── setup.py
└── triplet_loss.ipynb
Download .txt
SYMBOL INDEX (20 symbols across 3 files)

FILE: docs/js/jekyll-search.js
  function s (line 1) | function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&re...
  function receivedResponse (line 1) | function receivedResponse(xhr){return 200==xhr.status&&4==xhr.readyState}
  function handleResponse (line 1) | function handleResponse(xhr,callback){xhr.onreadystatechange=function(){...
  function FuzzySearchStrategy (line 1) | function FuzzySearchStrategy(){function createFuzzyRegExpFromString(stri...
  function LiteralSearchStrategy (line 1) | function LiteralSearchStrategy(){function doMatch(string,crit){return st...
  function findMatches (line 1) | function findMatches(store,crit,strategy){for(var data=store.get(),i=0;i...
  function findMatchesInObject (line 1) | function findMatchesInObject(obj,crit,strategy){for(var key in obj)if(st...
  function getSearchStrategy (line 1) | function getSearchStrategy(){return fuzzy?fuzzySearchStrategy:literalSea...
  function isObject (line 1) | function isObject(obj){return!!obj&&"[object Object]"==Object.prototype....
  function isArray (line 1) | function isArray(obj){return!!obj&&"[object Array]"==Object.prototype.to...
  function addObject (line 1) | function addObject(data){return store.push(data),data}
  function addArray (line 1) | function addArray(data){for(var added=[],i=0;i<data.length;i++)isObject(...
  function SimpleJekyllSearch (line 1) | function SimpleJekyllSearch(){function initWithJSON(){store.put(opt.data...

FILE: online_triplet_loss/_nbdev.py
  function custom_doc_links (line 14) | def custom_doc_links(name): return None

FILE: online_triplet_loss/losses.py
  function _pairwise_distances (line 8) | def _pairwise_distances(embeddings, squared=False):
  function _get_triplet_mask (line 44) | def _get_triplet_mask(labels):
  function _get_anchor_positive_triplet_mask (line 71) | def _get_anchor_positive_triplet_mask(labels):
  function _get_anchor_negative_triplet_mask (line 89) | def _get_anchor_negative_triplet_mask(labels):
  function batch_hard_triplet_loss (line 103) | def batch_hard_triplet_loss(labels, embeddings, margin, squared=False):
  function batch_all_triplet_loss (line 150) | def batch_all_triplet_loss(labels, embeddings, margin, squared=False):
Condensed preview — 67 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (150K chars).
[
  {
    "path": ".github/workflows/main.yml",
    "chars": 1196,
    "preview": "name: CI\non: [push]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v1\n    - uses: act"
  },
  {
    "path": ".gitignore",
    "chars": 1250,
    "preview": ".last_checked\n.idea/\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n.git"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2348,
    "preview": "# How to contribute\n\n## How to get started\n\nBefore anything else, please install the git hooks that run automatic script"
  },
  {
    "path": "LICENSE",
    "chars": 1076,
    "preview": "MIT License\n\nCopyright (c) [2019] [Joakim Rishaug]\n\nPermission is hereby granted, free of charge, to any person obtainin"
  },
  {
    "path": "Makefile",
    "chars": 416,
    "preview": "SRC = $(wildcard lib/*.ipynb)\n\nall: \"online_triplet_loss\" docs\n\n\"online_triplet_loss\": $(SRC)\n\tnbdev_build_lib\n\ttouch \"o"
  },
  {
    "path": "README.md",
    "chars": 3030,
    "preview": "# online_triplet_loss\n> PyTorch conversion of the excellent post on the <a href='https://omoindrot.github.io/triplet-los"
  },
  {
    "path": "docs/.gitignore",
    "chars": 7,
    "preview": "_site/\n"
  },
  {
    "path": "docs/Gemfile",
    "chars": 148,
    "preview": "source \"https://rubygems.org\"\n\ngem 'github-pages', group: :jekyll_plugins\n\n\n# Added at 2019-11-25 10:11:40 -0800 by jhow"
  },
  {
    "path": "docs/_config.yml",
    "chars": 1207,
    "preview": "repository: \"NegatioN/OnlineMiningTripletLoss\"\noutput: web\ntopnav_title: \"online_triplet_loss\"\nsite_title: \"online_tripl"
  },
  {
    "path": "docs/_data/alerts.yml",
    "chars": 875,
    "preview": "tip: '<div class=\"alert alert-success\" role=\"alert\"><i class=\"fa fa-check-square-o\"></i> <b>Tip: </b>'\nnote: '<div class"
  },
  {
    "path": "docs/_data/definitions.yml",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "docs/_data/glossary.yml",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "docs/_data/sidebars/home_sidebar.yml",
    "chars": 424,
    "preview": "\n#################################################\n### THIS FILE WAS AUTOGENERATED! DO NOT EDIT! ###\n###################"
  },
  {
    "path": "docs/_data/tags.yml",
    "chars": 49,
    "preview": "allowed-tags:\n  - getting_started\n  - navigation\n"
  },
  {
    "path": "docs/_data/terms.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/_data/topnav.yml",
    "chars": 198,
    "preview": "topnav:\n- title: Topnav\n  items:\n    - title: GitHub\n      external_url: https://github.com/\"NegatioN\"/\"online_triplet_l"
  },
  {
    "path": "docs/_includes/archive.html",
    "chars": 177,
    "preview": "---\nlayout: default\ntype: archive\n---\n\n<div class=\"post-header\">\n  <h1 class=\"post-title-main\">{{ page.title }}</h1>\n</d"
  },
  {
    "path": "docs/_includes/callout.html",
    "chars": 94,
    "preview": "<div markdown=\"span\" class=\"bs-callout bs-callout-{{include.type}}\">{{include.content}}</div>\n"
  },
  {
    "path": "docs/_includes/footer.html",
    "chars": 516,
    "preview": "<footer>\n            <div class=\"row\">\n                <div class=\"col-lg-12 footer\">\n                  <p><img src=\"{{ "
  },
  {
    "path": "docs/_includes/google_analytics.html",
    "chars": 546,
    "preview": "<!-- the google_analytics_id gets auto inserted from the config file -->\n\n{% if site.google_analytics %}\n\n<script>(funct"
  },
  {
    "path": "docs/_includes/head.html",
    "chars": 3677,
    "preview": "<meta charset=\"utf-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta name=\"viewport\" content=\"width=device"
  },
  {
    "path": "docs/_includes/head_print.html",
    "chars": 1617,
    "preview": "<meta charset=\"utf-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta name=\"viewport\" content=\"width=device"
  },
  {
    "path": "docs/_includes/image.html",
    "chars": 386,
    "preview": "<figure>{% if {{include.url}} %}<a class=\"no_icon\" target=\"_blank\" href=\"{{include.url}}\">{% endif %}<img class=\"docimag"
  },
  {
    "path": "docs/_includes/important.html",
    "chars": 135,
    "preview": "<div markdown=\"span\" class=\"alert alert-warning\" role=\"alert\"><i class=\"fa fa-warning\"></i> <b>Important:</b> {{include."
  },
  {
    "path": "docs/_includes/initialize_shuffle.html",
    "chars": 3006,
    "preview": "<script type=\"text/javascript\">\n$(document).ready(function() {\n    $('#toc').toc({ minimumHeaders: 0, listType: 'ul', sh"
  },
  {
    "path": "docs/_includes/inline_image.html",
    "chars": 75,
    "preview": "<img class=\"inline\" src=\"images/{{include.file}}\" alt=\"{{include.alt}}\" />\n"
  },
  {
    "path": "docs/_includes/links.html",
    "chars": 1420,
    "preview": "{% comment %}Get links from each sidebar, as listed in the _config.yml file under sidebars{% endcomment %}\n\n{% for sideb"
  },
  {
    "path": "docs/_includes/note.html",
    "chars": 132,
    "preview": "<div markdown=\"span\" class=\"alert alert-info\" role=\"alert\"><i class=\"fa fa-info-circle\"></i> <b>Note:</b> {{include.cont"
  },
  {
    "path": "docs/_includes/search_google_custom.html",
    "chars": 415,
    "preview": "<script>\n  (function() {\n    var cx = '{{site.google_search}}';\n    var gcse = document.createElement('script');\n    gcs"
  },
  {
    "path": "docs/_includes/search_simple_jekyll.html",
    "chars": 731,
    "preview": "<div id=\"search-demo-container\">\n    <input type=\"text\" id=\"search-input\" placeholder=\"{{site.data.strings.search_placeh"
  },
  {
    "path": "docs/_includes/sidebar.html",
    "chars": 2836,
    "preview": "{% assign sidebar = site.data.sidebars[page.sidebar].entries %}\n{% assign pageurl = page.url  | remove: \".html\" %}\n\n<ul "
  },
  {
    "path": "docs/_includes/tip.html",
    "chars": 136,
    "preview": "<div markdown=\"span\" class=\"alert alert-success\" role=\"alert\"><i class=\"fa fa-check-square-o\"></i> <b>Tip:</b> {{include"
  },
  {
    "path": "docs/_includes/toc.html",
    "chars": 684,
    "preview": "\n<!-- this handles the automatic toc. use ## for subheads to auto-generate the on-page minitoc. if you use html tags, yo"
  },
  {
    "path": "docs/_includes/topnav.html",
    "chars": 3202,
    "preview": "<!-- Navigation -->\n<nav class=\"navbar navbar-inverse navbar-static-top\">\n    <div class=\"container topnavlinks\">\n      "
  },
  {
    "path": "docs/_includes/warning.html",
    "chars": 143,
    "preview": "<div markdown=\"span\" class=\"alert alert-danger\" role=\"alert\"><i class=\"fa fa-exclamation-circle\"></i> <b>Warning:</b> {{"
  },
  {
    "path": "docs/_layouts/default.html",
    "chars": 3574,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    {% include head.html %}\n    <script>\n        $(document).ready(function() {\n          "
  },
  {
    "path": "docs/_layouts/default_print.html",
    "chars": 439,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<html>\n<head>\n    {% include head_print.html %}\n\n\n</head>\n\n<body class=\"{% if page.type"
  },
  {
    "path": "docs/_layouts/none.html",
    "chars": 19,
    "preview": "---\n---\n{{content}}"
  },
  {
    "path": "docs/_layouts/page.html",
    "chars": 1545,
    "preview": "---\nlayout: default\n---\n\n<div class=\"post-header\">\n    <a id=\"{{page.title}}\"></a>\n    <h1 class=\"post-title-main\">{{ pa"
  },
  {
    "path": "docs/_layouts/page_print.html",
    "chars": 320,
    "preview": "---\nlayout: default_print\ncomments: true\n---\n<div class=\"post-header\">\n    <h1 class=\"post-title-main\" id=\"{{page.permal"
  },
  {
    "path": "docs/css/boxshadowproperties.css",
    "chars": 475,
    "preview": "/* box-shadow fonts return errors with prince, so extracting here to put in web output only */\n\n#search-demo-container u"
  },
  {
    "path": "docs/css/customstyles.css",
    "chars": 21979,
    "preview": ".anchor-link {\n    display: none;\n}\n\nbody {\n    font-size:15px;\n}\n\n.bs-callout {\n    padding: 20px;\n    margin: 20px 0;\n"
  },
  {
    "path": "docs/css/modern-business.css",
    "chars": 1246,
    "preview": "/*!\n * Start Bootstrap - Modern Business HTML Template (http://startbootstrap.com)\n * Code licensed under the Apache Lic"
  },
  {
    "path": "docs/css/printstyles.css",
    "chars": 2854,
    "preview": "\n/*body.print .container {max-width: 650px;}*/\n\nbody {\n    font-size:14px;\n}\n.nav ul li a {border-top:0px; background-co"
  },
  {
    "path": "docs/css/syntax.css",
    "chars": 3737,
    "preview": ".highlight  { background: #ffffff; }\n.highlight .c { color: #999988; font-style: italic } /* Comment */\n.highlight .err "
  },
  {
    "path": "docs/css/theme-blue.css",
    "chars": 2670,
    "preview": ".summary {\n    color: #808080;\n    border-left: 5px solid #ED1951;\n    font-size:16px;\n}\n\n\nh3 {color: #000000; }\nh4 {col"
  },
  {
    "path": "docs/css/theme-green.css",
    "chars": 2377,
    "preview": ".summary {\n    color: #808080;\n    border-left: 5px solid #E50E51;\n    font-size:16px;\n}\n\n\nh3 {color: #E50E51; }\nh4 {col"
  },
  {
    "path": "docs/feed.xml",
    "chars": 1300,
    "preview": "---\nsearch: exclude\nlayout: none\n---\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w"
  },
  {
    "path": "docs/index.html",
    "chars": 8669,
    "preview": "---\n\ntitle: online_triplet_loss\n\nkeywords: fastai\nsidebar: home_sidebar\n\nsummary: \"PyTorch conversion of the excellent p"
  },
  {
    "path": "docs/js/customscripts.js",
    "chars": 1924,
    "preview": "$('#mysidebar').height($(\".nav\").height());\n\n\n$( document ).ready(function() {\n\n    //this script says, if the height of"
  },
  {
    "path": "docs/js/jekyll-search.js",
    "chars": 5517,
    "preview": "!function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=\"function\"==typeof require&&require;if(!u&&a)return a(o,!0)"
  },
  {
    "path": "docs/js/toc.js",
    "chars": 3713,
    "preview": "// https://github.com/ghiculescu/jekyll-table-of-contents\n// this library modified by fastai to:\n// - update the locatio"
  },
  {
    "path": "docs/licenses/LICENSE",
    "chars": 1241,
    "preview": "/* This license pertains to the docs template, except for the Navgoco jQuery component. */\n\nThe MIT License (MIT)\n\nOrigi"
  },
  {
    "path": "docs/licenses/LICENSE-BSD-NAVGOCO.txt",
    "chars": 1649,
    "preview": "/* This license pertains to the Navgoco jQuery component used for the sidebar. */\n\nCopyright (c) 2013, Christodoulos Tso"
  },
  {
    "path": "docs/sidebar.json",
    "chars": 85,
    "preview": "{\n  \"online_triplet_loss\": {\n    \"Overview\": \"/\",\n    \"Losses\": \"/triplet_loss\"\n  }\n}"
  },
  {
    "path": "docs/sitemap.xml",
    "chars": 472,
    "preview": "---\nlayout: none\nsearch: exclude\n---\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/sche"
  },
  {
    "path": "docs/tooltips.json",
    "chars": 273,
    "preview": "---\nlayout: null\nsearch: exclude\n---\n\n{\n\"entries\":\n[\n{% for page in site.tooltips %}\n{\n\"doc_id\": \"{{ page.doc_id }}\",\n\"b"
  },
  {
    "path": "docs/triplet_loss.html",
    "chars": 3545,
    "preview": "---\n\ntitle: Losses\n\nkeywords: fastai\nsidebar: home_sidebar\n\nsummary: \"Where all of the losses are situated.\"\ndescription"
  },
  {
    "path": "index.ipynb",
    "chars": 4636,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": "
  },
  {
    "path": "online_triplet_loss/__init__.py",
    "chars": 22,
    "preview": "__version__ = \"0.0.6\"\n"
  },
  {
    "path": "online_triplet_loss/_nbdev.py",
    "chars": 427,
    "preview": "# AUTOGENERATED BY NBDEV! DO NOT EDIT!\n\n__all__ = [\"index\", \"modules\", \"custom_doc_links\", \"git_url\"]\n\nindex = {\"batch_h"
  },
  {
    "path": "online_triplet_loss/losses.py",
    "chars": 7873,
    "preview": "# AUTOGENERATED! DO NOT EDIT! File to edit: triplet_loss.ipynb (unless otherwise specified).\n\n__all__ = ['batch_hard_tri"
  },
  {
    "path": "settings.ini",
    "chars": 745,
    "preview": "[DEFAULT]\nlib_name = online_triplet_loss\nuser = NegatioN\ndescription = \"Online mining triplet losses for Pytorch\"\nkeywor"
  },
  {
    "path": "setup.py",
    "chars": 1894,
    "preview": "from packaging.version import parse\nfrom configparser import ConfigParser\nimport setuptools\nassert parse(setuptools.__ve"
  },
  {
    "path": "triplet_loss.ipynb",
    "chars": 21229,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": "
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the NegatioN/OnlineMiningTripletLoss GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 67 files (135.4 KB), approximately 40.6k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!