\title{myHDL to PYNQ Fabric Only Exsample}
\author{Steven K Armour}
\maketitle

# Refrances

# Libraries and Helper functions

```python
from myhdl import *
from myhdlpeek import Peeker
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sympy import *
init_printing()

import random

#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information myhdl, myhdlpeek, numpy, pandas, matplotlib, sympy, random
```

    The version_information extension is already loaded. To reload it, use:
      %reload_ext version_information

Software	Version

Python	3.6.5 64bit [GCC 7.2.0]

IPython	6.4.0

OS	Linux 4.15.0 30 generic x86_64 with debian buster sid

myhdl	0.10

myhdlpeek	0.0.7

numpy	1.14.3

pandas	0.23.0

matplotlib	2.2.2

sympy	1.1.1

random	The 'random' distribution was not found and is required by the application

Wed Aug 22 22:56:50 2018 MDT

```python
#helper  functions to read in the .v and .vhd generated files into python
def VerilogTextReader(loc, printresult=True):
    with open(f'{loc}.v', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
    return VerilogText

def VHDLTextReader(loc, printresult=True):
    with open(f'{loc}.vhd', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
    return VerilogText
```

# Project 1: 1 Switch 1 LED
https://timetoexplore.net/blog/arty-fpga-verilog-01

## Constraints File

## myHDL Code

```python
@block
def S0L0(sw, clk, led):
    """
    FPGA Hello world of one switch controlling one LED based on
    https://timetoexplore.net/blog/arty-fpga-verilog-01

    Target:
        ZYNQ 7000 Board (Arty, PYNQ-Z1, PYNQ-Z2) with at least 2
        switchs and 4 leds

    Input:
        sw(2bitVec):switch input
        clk(bool): clock input
    Ouput:
        led(4bitVec): led output

    """

    @always(clk.posedge)
    def logic():
        if sw[0]==0:
            led.next[0]=True
        else:
            led.next[0]=False

    return instances()
```

## myHDL Testing

```python
Peeker.clear()
clk=Signal(bool(0)); Peeker(clk, 'clk')
sw=Signal(intbv(0)[2:]); Peeker(sw, 'sw')
led=Signal(intbv(0)[4:]); Peeker(led, 'led')

np.random.seed(18)
swTVals=[int(i) for i in np.random.randint(0,2, 10)]

DUT=S0L0(sw, clk, led)

def S0L0_TB():

    @always(delay(1))
    def ClkGen():
        clk.next=not clk

    @instance
    def stimules():
        for i in range(10):
            sw.next[0]=swTVals[i]
            yield clk.posedge
        raise StopSimulation()

    return instances()

sim=Simulation(DUT, S0L0_TB(), *Peeker.instances()).run()
```

```python
Peeker.to_wavedrom()
```

```python
Peeker.to_dataframe()
```

      clk
      led
      sw

      0
      0
      0
      0

      1
      1
      1
      1

      2
      0
      1
      1

      3
      1
      0
      0

      4
      0
      0
      0

      5
      1
      1
      1

      6
      0
      1
      1

      7
      1
      0
      0

      8
      0
      0
      0

      9
      1
      1
      1

      10
      0
      1
      1

      11
      1
      0
      0

      12
      0
      0
      0

      13
      1
      1
      0

      14
      0
      1
      0

      15
      1
      1
      0

      16
      0
      1
      0

      17
      1
      1
      0

      18
      0
      1
      0

## Verilog Code

```python
DUT.convert()
VerilogTextReader('S0L0');
```

    ***Verilog modual from S0L0.v***

     // File: S0L0.v
    // Generated by MyHDL 0.10
    // Date: Wed Aug 22 22:56:10 2018

    `timescale 1ns/10ps

    module S0L0 (
        sw,
        clk,
        led
    );
    // FPGA Hello world of one switch controlling one LED based on
    // https://timetoexplore.net/blog/arty-fpga-verilog-01
    //
    // Target:
    //     ZYNQ 7000 Board (Arty, PYNQ-Z1, PYNQ-Z2) with at least 2
    //     switchs and 4 leds
    //
    //
    // Input:
    //     sw(2bitVec):switch input
    //     clk(bool): clock input
    // Ouput:
    //     led(4bitVec): led output
    //

    input [1:0] sw;
    input clk;
    output [3:0] led;
    reg [3:0] led;

    always @(posedge clk) begin: S0L0_LOGIC
        if ((sw[0] == 0)) begin
            led[0] <= 1'b1;
        end
        else begin
            led[0] <= 1'b0;
        end
    end

    endmodule

\begin{figure}
\centerline{\includegraphics[width=10cm]{S0L0_RTL.png}}
\caption{\label{fig:S0L0RTL} S0L0 RTL schematic; Xilinx Vivado 2017.4}
\end{figure}

\begin{figure}
\centerline{\includegraphics[width=10cm]{S0L0_SYN.png}}
\caption{\label{fig:S0L0SYN} S0L0 Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}

\begin{figure}
\centerline{\includegraphics[width=10cm]{S0L0_SYN.png}}
\caption{\label{fig:S0L0SYN} S0L0 Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}

## PYNQ-Z1 Constraints File
Below is what is found in file `constrs_S0L0.xdc`

Notice that the orgianl port names found in the PYNQ-Z1 Constraints file have been changed to the port names of the module `S0L0`
## PYNQ-Z1 Board Constraints for S0L0.v
## Based on https://github.com/Digilent/digilent-xdc/blob/master/Arty-Master.xdc

## Clock signal 125 MHz

set_property -dict { PACKAGE_PIN H16   IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L13P_T2_MRCC_35 Sch=clk
create_clock -add -name sys_clk_pin -period 8.00 -waveform {0 4} [get_ports { clk }];

## Switches
set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports {sw[0]}]
set_property -dict {PACKAGE_PIN M19 IOSTANDARD LVCMOS33} [get_ports {sw[1]}]

##LEDs
set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {led[2]}]
set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {led[3]}]
## Verilog Testbench

```python
swTVal=intbv(int(''.join([str(i) for i in swTVals]), 2))[len(swTVals):]
print(f'swTest: {swTVals}, {swTVal}, {[int(i) for i in swTVal]}')

```

    swTest: [0, 1, 0, 1, 0, 1, 0, 0, 0, 0], 150, [0, 1, 0, 1, 0, 1, 0, 0, 0, 0]

```python
@block
def S0L0_TBV():
    clk=Signal(bool(0))
    sw=Signal(intbv(0)[2:])
    led=Signal(intbv(0)[4:])

    #test stimuli
    swTVals=Signal(swTVal)

    @always_comb
    def print_data():
        print(sw, clk, led)

    DUT=S0L0(sw, clk, led)

    @instance
    def clk_signal():
        while True:
            clk.next = not clk
            yield delay(1)

    @instance
    def stimules():
        for i in range(10):
            sw.next[0]=swTVals[i]
            yield clk.posedge
        raise StopSimulation()

    return instances()

TB=S0L0_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('S0L0_TBV');
```

    <class 'myhdl._Signal._Signal'> <class '_ast.Name'>
    <class 'myhdl._Signal._Signal'> <class '_ast.Name'>
    <class 'myhdl._Signal._Signal'> <class '_ast.Name'>
    ***Verilog modual from S0L0_TBV.v***

     // File: S0L0_TBV.v
    // Generated by MyHDL 0.10
    // Date: Sun Aug 19 18:05:54 2018

    `timescale 1ns/10ps

    module S0L0_TBV (

    );

    reg clk = 0;
    reg [1:0] sw = 0;
    reg [3:0] led = 0;
    wire [9:0] swTVals;

    assign swTVals = 10'd336;

    always @(clk, sw, led) begin: S0L0_TBV_PRINT_DATA
        $write("%h", sw);
        $write(" ");
        $write("%h", clk);
        $write(" ");
        $write("%h", led);
        $write("\n");
    end

    always @(posedge clk) begin: S0L0_TBV_S0L00_0_LOGIC
        if ((sw[0] == 0)) begin
            led[0] <= 1'b1;
        end
        else begin
            led[0] <= 1'b0;
        end
    end

    initial begin: S0L0_TBV_CLK_SIGNAL
        while (1'b1) begin
            clk <= (!clk);
            # 1;
        end
    end

    initial begin: S0L0_TBV_STIMULES
        integer i;
        for (i=0; i<10; i=i+1) begin
            sw[0] <= swTVals[i];
            @(posedge clk);
        end
        $finish;
    end

    endmodule

    /home/iridium/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py:349: ToVerilogWarning: Signal is not driven: swTVals
      category=ToVerilogWarning

## Board Verification

# Project 2: 2 Switchs 4 LEDS
https://timetoexplore.net/blog/arty-fpga-verilog-01

## myHDL Code

```python
@block
def S2L4(sw, clk, led):
    """
    FPGA Hello world of two switchs controlling four LED based on
    https://timetoexplore.net/blog/arty-fpga-verilog-01

    Target:
        ZYNQ 7000 Board (Arty, PYNQ-Z1, PYNQ-Z2) with at least 2
        switchs and 4 leds

    Input:
        sw(2bitVec):switch input
        clk(bool): clock input
    Ouput:
        led(4bitVec): led output

    """

    @always(clk.posedge)
    def logic():
        if sw[0]==0:
            led.next[2:]=0
        else:
            led.next[2:]=3

        if sw[1]==0:
            led.next[4:2]=0
        else:
            led.next[4:2]=3

    return instances()
```

## myHDL Testing

```python
Peeker.clear()
clk=Signal(bool(0)); Peeker(clk, 'clk')
sw=Signal(intbv(0)[2:]); Peeker(sw, 'sw')
led=Signal(intbv(0)[4:]); Peeker(led, 'led')

np.random.seed(18)
swTVals=[int(i) for i in np.random.randint(0,4, 10)]

DUT=S2L4(sw, clk, led)

def S2L4_TB():

    @always(delay(1))
    def ClkGen():
        clk.next=not clk

    @instance
    def stimules():
        for i in range(10):
            sw.next=swTVals[i]
            yield clk.posedge
        raise StopSimulation()

    return instances()

sim=Simulation(DUT, S2L4_TB(), *Peeker.instances()).run()
```

```python
Peeker.to_wavedrom()
```

```python
Peeker.to_dataframe()
```

      clk
      led
      sw

      0
      0
      0
      2

      1
      1
      12
      3

      2
      0
      12
      3

      3
      1
      15
      0

      4
      0
      15
      0

      5
      1
      0
      1

      6
      0
      0
      1

      7
      1
      3
      2

      8
      0
      3
      2

      9
      1
      12
      1

      10
      0
      12
      1

      11
      1
      3
      2

      12
      0
      3
      2

      13
      1
      12
      2

      14
      0
      12
      2

      15
      1
      12
      2

      16
      0
      12
      2

      17
      1
      12
      0

      18
      0
      12
      0

## Verilog Code

```python
DUT.convert()
VerilogTextReader('S2L4');
```

    ***Verilog modual from S2L4.v***

     // File: S2L4.v
    // Generated by MyHDL 0.10
    // Date: Sun Aug 19 18:05:54 2018

    `timescale 1ns/10ps

    module S2L4 (
        sw,
        clk,
        led
    );
    // FPGA Hello world of two switchs controlling four LED based on
    // https://timetoexplore.net/blog/arty-fpga-verilog-01
    //
    // Target:
    //     ZYNQ 7000 Board (Arty, PYNQ-Z1, PYNQ-Z2) with at least 2
    //     switchs and 4 leds
    //
    //
    // Input:
    //     sw(2bitVec):switch input
    //     clk(bool): clock input
    // Ouput:
    //     led(4bitVec): led output
    //

    input [1:0] sw;
    input clk;
    output [3:0] led;
    reg [3:0] led;

    always @(posedge clk) begin: S2L4_LOGIC
        if ((sw[0] == 0)) begin
            led[2-1:0] <= 0;
        end
        else begin
            led[2-1:0] <= 3;
        end
        if ((sw[1] == 0)) begin
            led[4-1:2] <= 0;
        end
        else begin
            led[4-1:2] <= 3;
        end
    end

    endmodule

\begin{figure}
\centerline{\includegraphics[width=10cm]{S2L4_RTL.png}}
\caption{\label{fig:S2L4RTL} S2L4 RTL schematic; Xilinx Vivado 2017.4}
\end{figure}

\begin{figure}
\centerline{\includegraphics[width=10cm]{S2L4_SYN.png}}
\caption{\label{fig:S2L4SYN} S2L4 Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}

\begin{figure}
\centerline{\includegraphics[width=10cm]{S2L4_IMP.png}}
\caption{\label{fig:S2L4SYN} S2L4 Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}

## Verilog Testbench (ToDo)
will write later when testbench conversion is improved

## PYNQ-Z1 Constraints File
using same one as in **1 Switch 1 LED**: `constrs_S0L0.xdc`

## Board Verification

```python

```

# Project 3: Countdown

## myHDL Code

```python
@block
def countLED(clk, led):
    counter=Signal(modbv(0)[33:])

    @always(clk.posedge)
    def logic():
        counter.next=counter+1
        led.next[0]=counter[26]
        led.next[1]=counter[24]
        led.next[3]=counter[22]
        led.next[4]=counter[20]

    return instances()
```

## myHDL Testing

```python
Peeker.clear()
clk=Signal(bool(0)); Peeker(clk, 'clk')
led=Signal(intbv(0)[4:]); Peeker(led, 'led')

DUT=countLED(clk, led)

'''
def countLED_TB():

    @always(delay(1))
    def ClkGen():
        clk.next=not clk

    @instance
    def stimules():
        i=0
        while True:
            if i==2**33:
                raise StopSimulation()
            if 1%100==0:
                print(i)
            i+=1
            yield clk.posedge

    return instances()

sim=Simulation(DUT, countLED_TB(), *Peeker.instances()).run()
'''
;
```

    ''

Need to figure out how to write/run these long simulations better in python

## Verilog Code

```python
DUT.convert()
VerilogTextReader('countLED');
```

    ***Verilog modual from countLED.v***

     // File: countLED.v
    // Generated by MyHDL 0.10
    // Date: Sun Aug 19 18:05:54 2018

    `timescale 1ns/10ps

    module countLED (
        clk,
        led
    );

    input clk;
    output [3:0] led;
    reg [3:0] led;

    reg [32:0] counter = 0;

    always @(posedge clk) begin: COUNTLED_LOGIC
        counter <= (counter + 1);
        led[0] <= counter[26];
        led[1] <= counter[24];
        led[3] <= counter[22];
        led[4] <= counter[20];
    end

    endmodule

## Verilog Testbench

## PYNQ-Z1 Constraints File
Below is what is found in file `constrs_S0L0.xdc`

Notice that the orgianl port names found in the PYNQ-Z1 Constraints file have been changed to the port names of the module `S0L0`
## PYNQ-Z1 Board Constraints for countLED.v
## Based on https://github.com/Digilent/digilent-xdc/blob/master/Arty-Master.xdc

## Clock signal 125 MHz

set_property -dict { PACKAGE_PIN H16   IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L13P_T2_MRCC_35 Sch=clk
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { clk }];

##LEDs
set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {led[2]}]
set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {led[3]}]
## Board Verification

# Project 4: Basic Duty Cycle
https://timetoexplore.net/blog/arty-fpga-verilog-02

## myHDL Code

```python
@block
def BDCLed(clk, led):
    counter=Signal(modbv(0)[8:])
    duty_led=Signal(modbv(8)[8:])

    @always(clk.posedge)
    def logic():
        counter.next=counter+1
        if counter<duty_led:
            led.next=15
        else:
            led.next=0

    return instances()
```

## myHDL Testing

```python
Peeker.clear()
clk=Signal(bool(0)); Peeker(clk, 'clk')
led=Signal(intbv(0)[4:]); Peeker(led, 'led')

DUT=BDCLed(clk, led)

def BDCLed_TB():

    @always(delay(1))
    def ClkGen():
        clk.next=not clk

    @instance
    def stimules():
        i=0
        while True:
            if i==1000:
                raise StopSimulation()
            i+=1
            yield clk.posedge

    return instances()

sim=Simulation(DUT, BDCLed_TB(), *Peeker.instances()).run()
```

```python
Peeker.to_wavedrom()
```

```python
BDCLedData=Peeker.to_dataframe()
BDCLedData=BDCLedData[BDCLedData['clk']==1]
BDCLedData.plot(y='led');
```

## Verilog Code

```python
DUT.convert()
VerilogTextReader('BDCLed');
```

    ***Verilog modual from BDCLed.v***

     // File: BDCLed.v
    // Generated by MyHDL 0.10
    // Date: Sun Aug 19 18:11:00 2018

    `timescale 1ns/10ps

    module BDCLed (
        clk,
        led
    );

    input clk;
    output [3:0] led;
    reg [3:0] led;

    wire [7:0] duty_led;
    reg [7:0] counter = 0;

    assign duty_led = 8'd8;

    always @(posedge clk) begin: BDCLED_LOGIC
        counter <= (counter + 1);
        if ((counter < duty_led)) begin
            led <= 15;
        end
        else begin
            led <= 0;
        end
    end

    endmodule

    /home/iridium/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py:349: ToVerilogWarning: Signal is not driven: duty_led
      category=ToVerilogWarning

## PYNQ-Z1 Constraints File
Below is what is found in file `constrs_S0L0.xdc`

Notice that the orgianl port names found in the PYNQ-Z1 Constraints file have been changed to the port names of the module `S0L0`

## Verilog Testbench

```python
@block
def BDCLed_TBV():

    clk=Signal(bool(0))
    led=Signal(intbv(0)[4:])

    @always_comb
    def print_data():
        print(sw, clk, led)

    DUT=BDCLed(clk, led)

    @instance
    def clk_signal():
        while True:
            clk.next = not clk
            yield delay(1)

    @instance
    def stimules():
        i=0
        while True:
            if i==1000:
                raise StopSimulation()
            i+=1
            yield clk.posedge

    return instances()

TB=BDCLed_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('BDCLed_TBV');
```

    <class 'myhdl._Signal._Signal'> <class '_ast.Name'>
    <class 'myhdl._Signal._Signal'> <class '_ast.Name'>
    <class 'myhdl._Signal._Signal'> <class '_ast.Name'>
    ***Verilog modual from BDCLed_TBV.v***

     // File: BDCLed_TBV.v
    // Generated by MyHDL 0.10
    // Date: Sun Aug 19 18:16:51 2018

    `timescale 1ns/10ps

    module BDCLed_TBV (

    );

    reg clk = 0;
    wire [1:0] sw;
    reg [3:0] led = 0;
    wire [7:0] BDCLed0_0_duty_led;
    reg [7:0] BDCLed0_0_counter = 0;

    assign sw = 2'd0;
    assign BDCLed0_0_duty_led = 8'd8;

    always @(clk, sw, led) begin: BDCLED_TBV_PRINT_DATA
        $write("%h", sw);
        $write(" ");
        $write("%h", clk);
        $write(" ");
        $write("%h", led);
        $write("\n");
    end

    always @(posedge clk) begin: BDCLED_TBV_BDCLED0_0_LOGIC
        BDCLed0_0_counter <= (BDCLed0_0_counter + 1);
        if ((BDCLed0_0_counter < BDCLed0_0_duty_led)) begin
            led <= 15;
        end
        else begin
            led <= 0;
        end
    end

    initial begin: BDCLED_TBV_CLK_SIGNAL
        while (1'b1) begin
            clk <= (!clk);
            # 1;
        end
    end

    initial begin: BDCLED_TBV_STIMULES
        integer i;
        i = 0;
        while (1'b1) begin
            if ((i == 1000)) begin
                $finish;
            end
            i = i + 1;
            @(posedge clk);
        end
    end

    endmodule

    /home/iridium/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py:349: ToVerilogWarning: Signal is not driven: sw
      category=ToVerilogWarning
    /home/iridium/anaconda3/lib/python3.6/site-packages/myhdl/conversion/_toVerilog.py:349: ToVerilogWarning: Signal is not driven: BDCLed0_0_duty_led
      category=ToVerilogWarning

## Board Verification

# Project 5: Mid level PWM LED

## pwm myHDL Code

```python
@block
def pwm(clk, dutyCount, o_state):
    counter=Signal(modbv(0)[8:])

    @always(clk.posedge)
    def logic():
        counter.next=counter+1
        o_state.next=counter<dutyCount

    return instances()
```

## pwm myHDL Testing

```python
Peeker.clear()
clk=Signal(bool(0)); Peeker(clk, 'clk')
dutyCount=Signal(intbv(4)[8:]); Peeker(dutyCount, 'dutyCount')
o_state=Signal(bool(0)); Peeker(o_state, 'o_state')

DUT=pwm(clk, dutyCount, o_state)

def pwm_TB():
    pass
```

## pwm Verilog Code

```python

```

```python

```


# KVLCC2 geometry analysis

# Purpose
Analyse the geometry section by section

# Methodology
Load offset points from Rhino

# Setup

```python
# %load imports.py
"""
These is the standard setup for the notebooks.
"""

#%matplotlib inline
%matplotlib notebook
%load_ext autoreload
%autoreload 2

#from jupyterthemes import jtplot
#jtplot.style(theme='onedork', context='notebook', ticks=True, grid=False)

import pandas as pd
pd.options.display.max_rows = 999
pd.options.display.max_columns = 999
pd.set_option("display.max_columns", None)
import numpy as np
import os
import matplotlib.pyplot as plt
from collections import OrderedDict
#plt.style.use('paper')

#import data
import copy
from mdldb.run import Run

from sklearn.pipeline import Pipeline
from rolldecayestimators.transformers import CutTransformer, LowpassFilterDerivatorTransformer, ScaleFactorTransformer, OffsetTransformer
from rolldecayestimators.direct_estimator_cubic import EstimatorQuadraticB, EstimatorCubic
from rolldecayestimators.ikeda_estimator import IkedaQuadraticEstimator
import rolldecayestimators.equations as equations
import rolldecayestimators.lambdas as lambdas
from rolldecayestimators.substitute_dynamic_symbols import lambdify
import rolldecayestimators.symbols as symbols
import sympy as sp

from sympy.physics.vector.printing import vpprint, vlatex
from IPython.display import display, Math, Latex

from sklearn.metrics import r2_score
from src.data import database
from mdldb import tables
import shipflowmotionshelpers.shipflowmotionshelpers as helpers
import src.visualization.visualize as visualize

```

    Duplicate key in file WindowsPath('C:/Users/maa/.matplotlib/stylelib/paper.mplstyle'), line 461 ('figure.figsize   : 5, 3   ## figure size in inches')
    Duplicate key in file WindowsPath('C:/Users/maa/.matplotlib/stylelib/paper.mplstyle'), line 462 ('figure.dpi       : 100        ## figure dots per inch')

```python
from reports.paper_writing import save_fig
```

```python
db = database.get_db()

sql = """
SELECT * from run
INNER JOIN loading_conditions
ON (run.loading_condition_id = loading_conditions.id)
INNER JOIN models
ON (run.model_number = models.model_number)
INNER JOIN ships
ON (run.ship_name = ships.name)
WHERE run.model_number='M5057-01-A' and run.test_type='roll decay' and run.project_number=40178362;
"""
df_rolldecays = pd.read_sql(sql=sql, con=db.engine)
df_rolldecays['rho']=1000
df_rolldecays['g']=9.81
df_rolldecays=df_rolldecays.loc[:,~df_rolldecays.columns.duplicated()]
df_rolldecays.set_index('id', inplace=True)
```

```python
df_rolldecays.head()
```

      project_number
      series_number
      run_number
      test_number
      model_number
      ship_name
      loading_condition_id
      ascii_name
      ship_speed
      comment
      file_path_ascii
      file_path_ascii_temp
      file_path_log
      file_path_hdf5
      date
      test_type
      facility
      angle1
      angle2
      Körfallstyp
      name
      lcg
      kg
      gm
      CW
      TF
      TA
      BWL
      KXX
      KZZ
      BTT1
      CP
      Volume
      A0
      RH
      scale_factor
      lpp
      beam
      ABULB
      BKX
      TWIN
      DCLR
      VDES
      RHBL
      ASKEG
      PD
      ARH
      CFP
      AIX
      PDTDES
      RTYPE
      SFP
      BKL
      BKB
      PROT
      D
      LSKEG
      RR
      XSKEG
      NDES
      AR
      BR
      BRA
      IRUD
      PTYPE
      XRUD
      AI
      HSKEG
      RSKEG
      LOA
      ship_type_id
      rho
      g

      id

      21337
      40178362
      1
      94
      1
      M5057-01-A
      M5057-01-A
      166
      94.0
      NaN
      Roll decay, 0 kn
      NaN
      None
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      2018-04-03
      roll decay
      MDL
      None
      None
      None
      20.8
      11.2672
      18.6
      5.73
      None
      20.8
      20.8
      None
      23.2
      80.0
      None
      None
      312653.0
      0.99538
      None
      68.0
      320.0
      58.0
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      1000
      9.81

      21338
      40178362
      1
      95
      1
      M5057-01-A
      M5057-01-A
      166
      95.0
      NaN
      Roll decay, 0 kn
      NaN
      None
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      2018-04-03
      roll decay
      MDL
      None
      None
      None
      20.8
      11.2672
      18.6
      5.73
      None
      20.8
      20.8
      None
      23.2
      80.0
      None
      None
      312653.0
      0.99538
      None
      68.0
      320.0
      58.0
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      1000
      9.81

      21339
      40178362
      1
      96
      1
      M5057-01-A
      M5057-01-A
      166
      96.0
      NaN
      Roll decay, 0 kn
      NaN
      None
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      2018-11-28
      roll decay
      MDL
      None
      None
      None
      20.8
      11.2672
      18.6
      5.73
      None
      20.8
      20.8
      None
      23.2
      80.0
      None
      None
      312653.0
      0.99538
      None
      68.0
      320.0
      58.0
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      1000
      9.81

      21340
      40178362
      1
      97
      1
      M5057-01-A
      M5057-01-A
      166
      97.0
      15.5
      Roll decay, 15.5 kn
      NaN
      None
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      \\sspa.local\gbg\LABmeasuredataMDL\40178362\00...
      2018-04-04
      roll decay
      MDL
      None
      None
      None
      20.8
      11.2672
      18.6
      5.73
      None
      20.8
      20.8
      None
      23.2
      80.0
      None
      None
      312653.0
      0.99538
      None
      68.0
      320.0
      58.0
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      None
      1000
      9.81

```python
loading_condition = df_rolldecays.loc[21340]
#print(loading_condition.project_path)
```

```python
loading_condition.TA
```

    20.8

```python
loading_condition.TF
```

    20.8

```python
loading_condition.lpp
```

    320.0

```python
draught = (loading_condition.TA + loading_condition.TF)/2
```

```python
file_path = r'S:/2020/40209514-DEMOPS/03_Project/020_PROJECT_MANAGEMENT/arbetsmapp/ISOPE/KVLCC2_points.txt'
points = pd.read_csv(file_path, sep=';', header=None)
points.columns = ['x','y','z']
points.describe()
```

      x
      y
      z

      count
      7140.000000
      7140.000000
      7.140000e+03

      mean
      157.454893
      17.750299
      7.740190e+00

      std
      110.633263
      10.884987
      9.114148e+00

      min
      -5.495000
      -0.000173
      -2.220446e-16

      25%
      48.179054
      6.451813
      8.789816e-01

      50%
      153.290740
      22.257320
      3.160564e+00

      75%
      264.429320
      27.889503
      1.273352e+01

      max
      327.995000
      29.000004
      4.000111e+01

```python
ns = np.arange(10)
n_sections = []
for n in ns:
    n_sections.append( len(points['x'].round(decimals=n).unique()))

fig,ax=plt.subplots()
ax.plot(ns,n_sections)
```

    <IPython.core.display.Javascript object>

    [<matplotlib.lines.Line2D at 0x26026c47f28>]

```python
points['x'] = points['x'].round(decimals=6)
points['z'] = points['z'].round(decimals=2)
x = points['x'].unique()
x_groups = points.groupby(by='x')
points2 = x_groups.filter(lambda x:x['x'].count() > 2)
x = points2['x'].unique()
x_groups = points2.groupby(by='x')
```

```python
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

ax.plot(points['x'], points['y'], points['z'], '.')
```

    <IPython.core.display.Javascript object>

    [<mpl_toolkits.mplot3d.art3d.Line3D at 0x2602ed15748>]

```python

N = 100
z_ = np.linspace(0,1,N)**-1.1
z_ = z_/z_[1]
z = draught*z_[1:]
z = np.concatenate((z,[0]))
z = np.flipud(z)

section = x_groups.get_group(x[int(len(x)/2)])
section.sort_values(by='z', inplace=True)
y = np.interp(z, section['z'], section['y'])

fig,ax=plt.subplots()
section.plot(x='y', y='z', ax=ax)
ax.plot(y,z,'.:')
```

    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:2: RuntimeWarning: divide by zero encountered in power

    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:10: SettingWithCopyWarning:
    A value is trying to be set on a copy of a slice from a DataFrame

    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      # Remove the CWD from sys.path while we load stuff.

    <IPython.core.display.Javascript object>

    [<matplotlib.lines.Line2D at 0x2602ed49668>]

```python
data = {
    'y':[3,2,1],
    'z':[5,3,2],
}
section = pd.DataFrame(data=data)

fig,ax=plt.subplots()
section.plot(x='y', y='z', style = 'ko-', label='original', ax=ax)

xy = section[['y','z']].values.tolist()

if xy[-1][0] > 0:
    centre_end_point = [0,xy[-1][1]]
    xy.append(centre_end_point)  # Adding missing centre end point

if xy[0][1] < draught:
    water_line_point_1 = [xy[0][0],draught]
    xy.insert(0,water_line_point_1)  # Adding missing water line point

top_centre_point = [0,xy[0][1]]
xy.insert(0,top_centre_point)

close_point = xy[-1]
xy.insert(0,close_point)
xy = np.array(xy)

ax.plot(xy[:,0], xy[:,1],'--')
ax.plot(*centre_end_point, 'ro', label='centre end point')
ax.plot(*water_line_point_1, 'bo', label='water_line_point_1')
ax.plot(*top_centre_point, 'yo', label='top_centre_point')
ax.plot(*close_point, 'ro', label='close_point')

ax.legend()

```

    <IPython.core.display.Javascript object>

    <matplotlib.legend.Legend at 0x2602ee4c940>

```python
def close_section(section):

    """
    The sections are defined as:
    (y,z):
            0
            1
            2
            3
           4
    5
    """
    xy = section[['y','z']].values.tolist()

    if xy[-1][0] > 0:
        centre_end_point = [0,xy[-1][1]]
        xy.append(centre_end_point)  # Adding missing centre end point

    if xy[0][1] < draught:
        water_line_point_1 = [xy[0][0],draught]
        xy.insert(0,water_line_point_1)  # Adding missing water line point

    top_centre_point = [0,xy[0][1]]
    xy.insert(0,top_centre_point)

    close_point = xy[-1]
    xy.insert(0,close_point)
    xy = np.array(xy)

    closed_section = pd.DataFrame()
    closed_section['y'] = xy[:,0]
    closed_section['z'] = xy[:,1]
    closed_section['x'] = section.iloc[0].x

    return closed_section

```

```python
x_groups = points.groupby(by='x')
N = 100
z_ = np.linspace(0,1,N)**-1.1
z_ = z_/z_[1]
z = draught*z_[1:]
z = np.concatenate((z,[0]))
z = np.flipud(z)

df_sections = pd.DataFrame()

for i,(x_, section) in enumerate(x_groups):
    #section.sort_values(by='z', inplace=True)
    mask = section['z'] <= draught
    section = section.loc[mask]
    if len(section)==0:
        continue

    new_section = pd.DataFrame()
    new_section['y']=section['y']
    new_section['x']=x_
    new_section['z']=section['z']
    new_closed_section = close_section(new_section)
    new_closed_section['no']=i
    df_sections = df_sections.append(new_closed_section)

```

    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:3: RuntimeWarning: divide by zero encountered in power
      This is separate from the ipykernel package so we can avoid doing imports until

```python
df_sections.head()
```

      y
      z
      x
      no

      0
      -9.001914e-15
      18.80
      -5.495
      0

      1
      0.000000e+00
      20.80
      -5.495
      0

      2
      5.819288e+00
      20.80
      -5.495
      0

      3
      5.819288e+00
      20.75
      -5.495
      0

      4
      5.198539e+00
      20.43
      -5.495
      0

```python
def poly_area(xy):
    """
        Calculates polygon area using Greens formula.
        x = xy[:,0], y = xy[:,1]
    """
    xy1 = np.roll(xy,-1,axis = 0) # shift by -1
    return -0.5*np.inner(xy1[:,0] - xy[:,0],xy1[:,1] + xy[:,1])

def section_area(section):
    xy = section[['y','z']].values
    return np.abs(poly_area(xy=xy))
```

```python
df_sections['x'].unique()
```

    array([ -5.495   ,  -3.258581,  -1.022162,   1.214257,   3.450676,
             5.687095,   7.923513,  10.159932,  12.396351,  14.63277 ,
            16.869189,  19.105608,  21.342027,  23.578446,  25.814865,
            28.051284,  30.287703,  32.524122,  34.760541,  36.996959,
            39.233378,  41.469797,  43.706216,  45.942635,  48.179054,
            50.415473,  52.651892,  54.888311,  57.12473 ,  59.361149,
            61.597568,  63.833986,  66.070405,  68.306824,  70.543243,
            72.779662,  75.016081,  77.2525  ,  79.488919,  81.725338,
            83.961757,  86.198176,  88.434595,  90.671014,  92.907432,
            95.143851,  97.38027 ,  99.616689, 101.85311 , 104.08953 ,
           106.32595 , 108.56236 , 110.79878 , 113.0352  , 115.27162 ,
           117.50804 , 119.74446 , 121.98088 , 124.2173  , 126.45372 ,
           128.69014 , 130.92655 , 133.16297 , 135.39939 , 137.63581 ,
           139.87223 , 142.10865 , 144.34507 , 146.58149 , 148.81791 ,
           151.05432 , 153.29074 , 155.52716 , 157.76358 , 160.      ,
           162.2702  , 164.54041 , 166.81061 , 169.08081 , 171.35101 ,
           173.62122 , 175.89142 , 178.16162 , 180.43182 , 182.70203 ,
           184.97223 , 187.24243 , 189.51264 , 191.78284 , 194.05304 ,
           196.32324 , 198.59345 , 200.86365 , 203.13385 , 205.40405 ,
           207.67426 , 209.94446 , 212.21466 , 214.48486 , 216.75507 ,
           219.02527 , 221.29547 , 223.56568 , 225.83588 , 228.10608 ,
           230.37628 , 232.64649 , 234.91669 , 237.18689 , 239.45709 ,
           241.7273  , 243.9975  , 246.2677  , 248.53791 , 250.80811 ,
           253.07831 , 255.34851 , 257.61872 , 259.88892 , 262.15912 ,
           264.42932 , 266.69953 , 268.96973 , 271.23993 , 273.51014 ,
           275.78034 , 278.05054 , 280.32074 , 282.59095 , 284.86115 ,
           287.13135 , 289.40155 , 291.67176 , 293.94196 , 296.21216 ,
           298.48236 , 300.75257 , 303.02277 , 305.29297 , 307.56318 ,
           309.83338 , 312.10358 , 314.37378 , 316.64399 , 318.91419 ,
           321.18439 , 323.45459 , 325.7248  , 327.995   ])

```python
sections = df_sections.groupby(by='x')
areas = sections.apply(func=section_area)
fig,ax=plt.subplots()
areas.plot(ax=ax)
```

    <IPython.core.display.Javascript object>

    <AxesSubplot:xlabel='x'>

```python
min_area = 1
df_sections2 = sections.filter(func=lambda x : section_area(x) > min_area)
sections = df_sections2.groupby(by='x')
```

```python
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

for no,section, in sections:

    ax.plot(section['x'], section['y'], section['z'])
```

    <IPython.core.display.Javascript object>

```python
x_interps = np.linspace(df_sections2['x'].min(), df_sections2['x'].max(),21)
xs = df_sections2['x'].unique()
x_ = []
for x_interp in x_interps:
    i = np.argmin(np.abs(x_interp - xs))
    x_.append(xs[i])

df_sections3 = pd.DataFrame()
for i,x in enumerate(x_):
    section = sections.get_group(x)
    section['no'] = i
    df_sections3 = df_sections3.append(section)
```

    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:11: SettingWithCopyWarning:
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead

    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      # This is added back by InteractiveShellApp.init_path()

```python
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

sections2 = df_sections3.groupby(by='no')
for no, section in sections2:

    ax.plot(section['x'], section['y'], section['z'], label=no)

ax.legend()
```

    <IPython.core.display.Javascript object>

    <matplotlib.legend.Legend at 0x2602f11d748>

```python
areas2 = sections2.apply(section_area)
fig,ax=plt.subplots()
areas2.plot(ax=ax)
for no,a in areas2.items():
    ax.annotate(no,xy=(no,a))
```

    <IPython.core.display.Javascript object>

```python
def estimate_bilge_radius(section):
    b = section['b']
    t = section['t']
    A = section['area']

    r = np.sqrt((b*t-A)/(1-np.pi/4))

    return r

def section_data(section):

    s = pd.Series()
    s.name=section.name
    s['area'] = 2*section_area(section) # two sides
    s['x'] = section.iloc[0].x
    s['t'] = section.z.max() - section.z.min()
    s['b'] = 2*section.y.max()  # two sides
    s['r_b'] = estimate_bilge_radius(s)

    return s

```

```python
df_section_properties = sections2.apply(func=section_data)
```

    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:12: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.
      if sys.path[0] == '':

```python
df_section_properties.to_csv('../data/interim/kvlcc_areas.csv', sep=';')
```

```python
df_section_properties
```

      area
      x
      t
      b
      r_b

      no

      0
      13.826612
      -5.495000
      2.00
      11.638577
      6.636080

      1
      123.851306
      10.159932
      18.25
      27.893522
      42.367175

      2
      428.211409
      28.051284
      20.80
      41.824284
      45.369454

      3
      683.709165
      43.706216
      20.80
      50.282514
      41.080696

      4
      917.895066
      61.597568
      20.80
      56.159232
      34.146143

      5
      1056.860933
      77.252500
      20.80
      57.870498
      26.158540

      6
      1139.503552
      92.907432
      20.80
      58.000008
      17.655717

      7
      1186.852794
      110.798780
      20.80
      58.000008
      9.543935

      8
      1203.217372
      126.453720
      20.80
      58.000008
      3.851125

      9
      1203.929931
      144.345070
      20.80
      58.000008
      3.392755

      10
      1203.929195
      160.000000
      20.80
      58.000008
      3.393260

      11
      1203.928607
      175.891420
      20.80
      58.000008
      3.393664

      12
      1203.929195
      194.053040
      20.80
      58.000008
      3.393260

      13
      1203.929195
      209.944460
      20.80
      58.000008
      3.393260

      14
      1203.906161
      225.835880
      20.80
      58.000008
      3.409039

      15
      1195.569763
      243.997500
      20.80
      57.987376
      7.017342

      16
      1159.988460
      259.888920
      20.80
      57.487792
      12.908255

      17
      1077.577243
      275.780340
      20.80
      55.361310
      18.561674

      18
      899.155097
      291.671760
      20.80
      48.130896
      21.797880

      19
      502.526691
      309.833380
      20.80
      28.203708
      19.797403

      20
      43.489245
      325.724800
      16.18
      5.709535
      15.093775

```python
fig,ax = plt.subplots()

zmax = sections2['z'].max().max()
for no,section, in sections2:

    section = section.iloc[2:]  # Removing close

    y = section['z']

    if no < 10:
        n = no
        x = -section['y']
        y_text = zmax - n*(zmax/9)
    else:
        n = 20 - no
        x = section['y']
        y_text = zmax - n*(zmax/10)

    x_text = np.interp(y_text,np.flipud(y),np.flipud(x))

    ax.plot(x, y)
    ax.annotate(no,xy=(x_text,y_text))

ymax = sections2['y'].max().max()
ax.plot(1.03*np.array([-ymax,ymax]),[zmax,zmax],'b-', lw=2)
ax.set_xlabel('y [m]')
ax.set_ylabel('z [m]')
ax.grid(True)
save_fig(fig, name='KVLCC2_body_plan')
```

    <IPython.core.display.Javascript object>

```python
section = sections2.get_group(4)
section = section.iloc[2:]
y = section['z']
n = 20 - no
x = section['y']

fig,ax=plt.subplots()
ax.plot(y,x)

np.interp(y_text,np.flipud(y),np.flipud(x))
```

    <IPython.core.display.Javascript object>

    28.079615999999998

```python

```

```python

```

```python

```


# Bringing contextual word representations into your models

```python
__author__ = "Christopher Potts"
__version__ = "CS224u, Stanford, Spring 2021"
```

## Contents

## Overview

This notebook provides a basic introduction to using pre-trained [BERT](https://github.com/google-research/bert) representations with the Hugging Face library. It is meant as a practical companion to our lecture on contextual word representations. The goal of this notebook is just to help you use these representations in your own work.

If you haven't already, I encourage you to review the notebook [vsm_04_contextualreps.ipynb](vsm_04_contextualreps.ipynb) before working with this one. That notebook covers the fundamentals of these models; this one dives into the details more quickly.

A number of the experiments in this notebook are resource-intensive. I've included timing information for the expensive steps, to give you a sense for how long things are likely to take. I ran this notebook on a laptop with a single NVIDIA RTX 2080 GPU.

## General set-up

The following are requirements that you'll already have met if you've been working in this repository. As you can see, we'll use the [Stanford Sentiment Treebank](sst_01_overview.ipynb) for illustrations, and we'll try out a few different deep learning models.

```python
import os
from sklearn.metrics import classification_report
import torch
import torch.nn as nn
from transformers import BertModel, BertTokenizer

from torch_shallow_neural_classifier import TorchShallowNeuralClassifier
from torch_rnn_classifier import TorchRNNModel
from torch_rnn_classifier import TorchRNNClassifier
from torch_rnn_classifier import TorchRNNClassifierModel
from torch_rnn_classifier import TorchRNNClassifier
import sst
import utils
```

```python
utils.fix_random_seeds()
```

```python
SST_HOME = os.path.join("data", "sentiment")
```

The `transformers` library does a lot of logging. To avoid ending up with a cluttered notebook, I am changing the logging level. You might want to skip this as you scale up to building production systems, since the logging is very good – it gives you a lot of insights into what the models and code are doing.

```python
import logging
logger = logging.getLogger()
logger.level = logging.ERROR
```

## Hugging Face BERT models and tokenizers

We'll illustrate with the BERT-base cased model:

```python
weights_name = 'bert-base-cased'
```

There are lots other options for pretrained weights. See [this Hugging Face directory](https://huggingface.co/models).

Next, we specify a tokenizer and a model that match both each other and our choice of pretrained weights:

```python
bert_tokenizer = BertTokenizer.from_pretrained(weights_name)
```

```python
bert_model = BertModel.from_pretrained(weights_name)
```

For modeling (as opposed to creating static representations), we will mostly process examples in batches – generally very small ones, as these models consume _a lot_ of memory. Here's a small batch of texts to use as the starting point for illustrations:

```python
example_texts = [
    "Encode sentence 1. [SEP] And sentence 2!",
    "Bert knows Snuffleupagus"]
```

We will often need to pad (and perhaps truncate) token lists so that we can work with fixed-dimensional tensors: The `batch_encode_plus` has a lot of options for doing this:

```python
example_ids = bert_tokenizer.batch_encode_plus(
    example_texts,
    add_special_tokens=True,
    return_attention_mask=True,
    padding='longest')
```

```python
example_ids.keys()
```

    dict_keys(['input_ids', 'token_type_ids', 'attention_mask'])

The `token_type_ids` is used for multi-text inputs like NLI. The `'input_ids'` field gives the indices for each of the two examples:

```python
example_ids['input_ids']
```

    [[101, 13832, 13775, 5650, 122, 119, 102, 1262, 5650, 123, 106, 102],
     [101, 15035, 3520, 156, 14787, 13327, 4455, 28026, 1116, 102, 0, 0]]

Notice that the final two tokens of the second example are pad tokens.

For fine-tuning, we want to avoid attending to padded tokens. The `'attention_mask'` captures the needed mask, which we'll be able to feed directly to the pretrained BERT model:

```python
example_ids['attention_mask']
```

    [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]]

Finally, we can run these indices and masks through the pretrained model:

```python
X_example = torch.tensor(example_ids['input_ids'])
X_example_mask = torch.tensor(example_ids['attention_mask'])

with torch.no_grad():
    reps = bert_model(X_example, attention_mask=X_example_mask)
```

Hugging Face BERT models create a special `pooler_output` representation that is the final representation above the [CLS] extended with a single layer of parameters:

```python
reps.pooler_output.shape
```

    torch.Size([2, 768])

We have two examples, each representented by a single vector of dimension 768, which is $d_{model}$ for BERT base using the notation from [the original Transformers paper](https://arxiv.org/abs/1706.03762). This is an easy basis for fine-tuning, as we will see.

We can also access the final output for each state:

```python
reps.last_hidden_state.shape
```

    torch.Size([2, 12, 768])

Here, we have 2 examples, each padded to the length of the longer one (12), and each of those representations has dimension 768. These representations can be used for sequence modeling, or pooled somehow for simple classifiers.

Those are all the essential ingredients for working with these parameters in Hugging Face. Of course, the library has a lot of other functionality, but the above suffices to featurize and to fine-tune.

## BERT featurization with Hugging Face

To start, we'll use the Hugging Face interfaces just to featurize examples to create inputs to a separate model. In this setting, the BERT parameters are frozen.

```python
def bert_phi(text):
    input_ids = bert_tokenizer.encode(text, add_special_tokens=True)
    X = torch.tensor([input_ids])
    with torch.no_grad():
        reps = bert_model(X)
        return reps.last_hidden_state.squeeze(0).numpy()
```

### Simple feed-forward experiment

For a simple feed-forward experiment, we can get the representation of the `[CLS]` tokens and use them as the inputs to a shallow neural network:

```python
def bert_classifier_phi(text):
    reps = bert_phi(text)
    #return reps.mean(axis=0)  # Another good, easy option.
    return reps[0]
```

Next we read in the SST train and dev splits:

```python
train = sst.train_reader(SST_HOME)

dev = sst.dev_reader(SST_HOME)
```

Split the input/output pairs out into separate lists:

```python
X_str_train = train.sentence.values
y_train = train.label.values

X_str_dev = dev.sentence.values
y_dev = dev.label.values
```

In the next step, we featurize all of the examples. These steps are likely to be the slowest in these experiments:

```python
%time X_train = [bert_classifier_phi(text) for text in X_str_train]
```

    CPU times: user 3h 3min 16s, sys: 1h 9min 9s, total: 4h 12min 26s
    Wall time: 35min 24s

```python
%time X_dev = [bert_classifier_phi(text) for text in X_str_dev]
```

    CPU times: user 20min 28s, sys: 6min 30s, total: 26min 59s
    Wall time: 4min 7s

Now that all the examples are featurized, we can fit a model and evaluate it:

```python
model = TorchShallowNeuralClassifier(
    early_stopping=True,
    hidden_dim=300)
```

```python
%time _ = model.fit(X_train, y_train)
```

    Stopping after epoch 23. Validation score did not improve by tol=1e-05 for more than 10 epochs. Final error is 5.422645628452301

    CPU times: user 9.19 s, sys: 355 ms, total: 9.55 s
    Wall time: 3.09 s

```python
preds = model.predict(X_dev)
```

```python
print(classification_report(y_dev, preds, digits=3))
```

                  precision    recall  f1-score   support

        negative      0.732     0.741     0.736       428
         neutral      0.397     0.135     0.202       229
        positive      0.659     0.876     0.752       444

        accuracy                          0.669      1101
       macro avg      0.596     0.584     0.564      1101
    weighted avg      0.633     0.669     0.632      1101

### A feed-forward experiment with the sst module

It is straightforward to conduct experiments like the above using `sst.experiment`, which will enable you to do a wider range of experiments without writing or copy-pasting a lot of code.

```python
def fit_shallow_network(X, y):
    mod = TorchShallowNeuralClassifier(
        hidden_dim=300,
        early_stopping=True)
    mod.fit(X, y)
    return mod
```

```python
%%time
_ = sst.experiment(
    sst.train_reader(SST_HOME),
    bert_classifier_phi,
    fit_shallow_network,
    assess_dataframes=sst.dev_reader(SST_HOME),
    vectorize=False)  # Pass in the BERT reps directly!
```

    Stopping after epoch 40. Validation score did not improve by tol=1e-05 for more than 10 epochs. Final error is 5.189640045166016

                  precision    recall  f1-score   support

        negative      0.726     0.757     0.741       428
         neutral      0.412     0.175     0.245       229
        positive      0.688     0.865     0.766       444

        accuracy                          0.679      1101
       macro avg      0.609     0.599     0.584      1101
    weighted avg      0.646     0.679     0.648      1101

    CPU times: user 3h 25min 19s, sys: 1h 14min 58s, total: 4h 40min 17s
    Wall time: 39min 33s

### An RNN experiment with the sst module

We can also use BERT representations as the input to an RNN. There is just one key change from how we used these models before:

* Previously, we would feed in lists of tokens, and they would be converted to indices into a fixed embedding space. This presumes that all words have the same representation no matter what their context is.

* With BERT, we skip the embedding entirely and just feed in lists of BERT vectors, which means that the same word can be represented in different ways.

`TorchRNNClassifier` supports this via `use_embedding=False`. In turn, you needn't supply a vocabulary:

```python
def fit_rnn(X, y):
    mod = TorchRNNClassifier(
        vocab=[],
        early_stopping=True,
        use_embedding=False)  # Pass in the BERT hidden states directly!
    mod.fit(X, y)
    return mod
```

```python
%%time
_ = sst.experiment(
    sst.train_reader(SST_HOME),
    bert_phi,
    fit_rnn,
    assess_dataframes=sst.dev_reader(SST_HOME),
    vectorize=False)  # Pass in the BERT hidden states directly!
```

    Stopping after epoch 35. Validation score did not improve by tol=1e-05 for more than 10 epochs. Final error is 0.5038421787321568

                  precision    recall  f1-score   support

        negative      0.708     0.687     0.698       428
         neutral      0.355     0.328     0.341       229
        positive      0.726     0.777     0.751       444

        accuracy                          0.649      1101
       macro avg      0.597     0.597     0.596      1101
    weighted avg      0.642     0.649     0.645      1101

    CPU times: user 3h 26min 32s, sys: 1h 15min 19s, total: 4h 41min 51s
    Wall time: 39min 59s

## BERT fine-tuning with Hugging Face

The above experiments are quite successful – BERT gives us a reliable boost compared to other methods we've explored for the SST task. However, we might expect to do even better if we fine-tune the BERT parameters as part of fitting our SST classifier. To do that, we need to incorporate the Hugging Face BERT model into our classifier. This too is quite straightforward.

### HfBertClassifier

The most important step is to create an `nn.Module` subclass that has, for its parameters, both the BERT model and parameters for our own classifier. Here we define a very simple fine-tuning set-up in which some layers built on top of the output corresponding to `[CLS]` are used as the basis for the SST classifier:

```python
class HfBertClassifierModel(nn.Module):
    def __init__(self, n_classes, weights_name='bert-base-cased'):
        super().__init__()
        self.n_classes = n_classes
        self.weights_name = weights_name
        self.bert = BertModel.from_pretrained(self.weights_name)
        self.bert.train()
        self.hidden_dim = self.bert.embeddings.word_embeddings.embedding_dim
        # The only new parameters -- the classifier:
        self.classifier_layer = nn.Linear(
            self.hidden_dim, self.n_classes)

    def forward(self, indices, mask):
        reps = self.bert(
            indices, attention_mask=mask)
        return self.classifier_layer(reps.pooler_output)
```

As you can see, `self.bert` does the heavy-lifting: it reads in all the pretrained BERT parameters, and I've specified `self.bert.train()` just to make sure that these parameters can be updated during our training process.

In `forward`, `self.bert` is used to process inputs, and then `pooler_output` is fed into `self.classifier_layer`. Hugging Face has already added a layer on top of the actual output for `[CLS]`, so we can specify the model as

$$
\begin{align}
[h_{1}, \ldots, h_{n}] &= \text{BERT}([x_{1}, \ldots, x_{n}]) \\
h &= \tanh(h_{1}W_{hh} + b_{h}) \\
y &= \textbf{softmax}(hW_{hy} + b_{y})
\end{align}$$

for a tokenized input sequence $[x_{1}, \ldots, x_{n}]$.

The Hugging Face documentation somewhat amusingly says, of `pooler_output`,

> This output is usually _not_ a good summary of the semantic content of the input, you're often better with averaging or pooling the sequence of hidden-states for the whole input sequence.

which is entirely reasonable, but it will require more resources, so we'll do the simpler thing here.

For the training and prediction interface, we can subclass `TorchShallowNeuralClassifier` so that we don't have to write any of our own data-handling, training, or prediction code. The central changes are using `HfBertClassifierModel` in `build_graph` and processing the data with `batch_encode_plus`.

```python
class HfBertClassifier(TorchShallowNeuralClassifier):
    def __init__(self, weights_name, *args, **kwargs):
        self.weights_name = weights_name
        self.tokenizer = BertTokenizer.from_pretrained(self.weights_name)
        super().__init__(*args, **kwargs)
        self.params += ['weights_name']

    def build_graph(self):
        return HfBertClassifierModel(self.n_classes_, self.weights_name)

    def build_dataset(self, X, y=None):
        data = self.tokenizer.batch_encode_plus(
            X,
            max_length=None,
            add_special_tokens=True,
            padding='longest',
            return_attention_mask=True)
        indices = torch.tensor(data['input_ids'])
        mask = torch.tensor(data['attention_mask'])
        if y is None:
            dataset = torch.utils.data.TensorDataset(indices, mask)
        else:
            self.classes_ = sorted(set(y))
            self.n_classes_ = len(self.classes_)
            class2index = dict(zip(self.classes_, range(self.n_classes_)))
            y = [class2index[label] for label in y]
            y = torch.tensor(y)
            dataset = torch.utils.data.TensorDataset(indices, mask, y)
        return dataset
```

### HfBertClassifier experiment

That's it! Let's see how we do on the SST binary, root-only problem. Because fine-tuning is expensive, we'll conduct a modest hyperparameter search and run the model for just one epoch per setting evaluation, as we did when [assessing NLI models](nli_02_models.ipynb).

```python
def bert_fine_tune_phi(text):
    return text
```

```python
def fit_hf_bert_classifier_with_hyperparameter_search(X, y):
    basemod = HfBertClassifier(
        weights_name='bert-base-cased',
        batch_size=8,  # Small batches to avoid memory overload.
        max_iter=1,  # We'll search based on 1 iteration for efficiency.
        n_iter_no_change=5,   # Early-stopping params are for the
        early_stopping=True)  # final evaluation.

    param_grid = {
        'gradient_accumulation_steps': [1, 4, 8],
        'eta': [0.00005, 0.0001, 0.001],
        'hidden_dim': [100, 200, 300]}

    bestmod = utils.fit_classifier_with_hyperparameter_search(
        X, y, basemod, cv=3, param_grid=param_grid)

    return bestmod
```

```python
%%time
bert_classifier_xval = sst.experiment(
    sst.train_reader(SST_HOME),
    bert_fine_tune_phi,
    fit_hf_bert_classifier_with_hyperparameter_search,
    assess_dataframes=sst.dev_reader(SST_HOME),
    vectorize=False)  # Pass in the BERT hidden state directly!
```

    Finished epoch 1 of 1; error is 96.940810058265926

    Best params: {'eta': 0.0001, 'gradient_accumulation_steps': 8, 'hidden_dim': 300}
    Best score: 0.586
                  precision    recall  f1-score   support

        negative      0.715     0.808     0.759       428
         neutral      0.700     0.031     0.059       229
        positive      0.662     0.905     0.765       444

        accuracy                          0.686      1101
       macro avg      0.692     0.581     0.527      1101
    weighted avg      0.691     0.686     0.616      1101

    CPU times: user 1h 48min 23s, sys: 5min 23s, total: 1h 53min 47s
    Wall time: 1h 55min 41s

And now on to the final test-set evaluation, using the best model from above:

```python
optimized_bert_classifier = bert_classifier_xval['model']
```

```python
# Remove the rest of the experiment results to clear out some memory:
del bert_classifier_xval
```

```python
def fit_optimized_hf_bert_classifier(X, y):
    optimized_bert_classifier.max_iter = 1000
    optimized_bert_classifier.fit(X, y)
    return optimized_bert_classifier
```

```python
test_df = sst.sentiment_reader(
    os.path.join(SST_HOME, "sst3-test-labeled.csv"))
```

```python
%%time
_ = sst.experiment(
    sst.train_reader(SST_HOME),
    bert_fine_tune_phi,
    fit_optimized_hf_bert_classifier,
    assess_dataframes=test_df,
    vectorize=False)  # Pass in the BERT hidden state directly!
```

    Stopping after epoch 9. Validation score did not improve by tol=1e-05 for more than 5 epochs. Final error is 7.519404984079301

                  precision    recall  f1-score   support

        negative      0.756     0.825     0.789       912
         neutral      0.338     0.314     0.325       389
        positive      0.821     0.771     0.795       909

        accuracy                          0.713      2210
       macro avg      0.638     0.636     0.636      2210
    weighted avg      0.709     0.713     0.710      2210

    CPU times: user 13min 7s, sys: 19 s, total: 13min 26s
    Wall time: 13min 27s


# **Turma de Pós-Graduação de Ciência de Dados**

**Disciplina: Linguagem de Programação Python**

**prof: Sérgio Assunção Monteiro, DSc**

**Aula 09**

# **Introdução à Computação Quântica**

**Fontes:**

> https://qiskit.org/documentation/intro_tutorial1.html

> https://qiskit.org/textbook/ch-states/introduction.html

```python
pip install qiskit
```

    Collecting qiskit
      Downloading qiskit-0.34.1.tar.gz (13 kB)
    Collecting qiskit-terra==0.19.1
      Downloading qiskit_terra-0.19.1-cp37-cp37m-manylinux2010_x86_64.whl (6.4 MB)
         |████████████████████████████████| 6.4 MB 4.3 MB/s
    Collecting qiskit-aer==0.10.2
      Downloading qiskit_aer-0.10.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (18.0 MB)
         |████████████████████████████████| 18.0 MB 350 kB/s
    Collecting qiskit-ibmq-provider==0.18.3
      Downloading qiskit_ibmq_provider-0.18.3-py3-none-any.whl (238 kB)
         |████████████████████████████████| 238 kB 70.1 MB/s
    Collecting qiskit-ignis==0.7.0
      Downloading qiskit_ignis-0.7.0-py3-none-any.whl (200 kB)
         |████████████████████████████████| 200 kB 72.1 MB/s
    Requirement already satisfied: scipy>=1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aer==0.10.2->qiskit) (1.4.1)
    Requirement already satisfied: numpy>=1.16.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-aer==0.10.2->qiskit) (1.19.5)
    Requirement already satisfied: requests>=2.19 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.3->qiskit) (2.23.0)
    Requirement already satisfied: python-dateutil>=2.8.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.3->qiskit) (2.8.2)
    Collecting requests-ntlm>=1.1.0
      Downloading requests_ntlm-1.1.0-py2.py3-none-any.whl (5.7 kB)
    Collecting websocket-client>=1.0.1
      Downloading websocket_client-1.2.3-py3-none-any.whl (53 kB)
         |████████████████████████████████| 53 kB 1.6 MB/s
    Requirement already satisfied: urllib3>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.3->qiskit) (1.24.3)
    Collecting retworkx>=0.8.0
      Downloading retworkx-0.11.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.6 MB)
         |████████████████████████████████| 1.6 MB 58.7 MB/s
    Requirement already satisfied: setuptools>=40.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ignis==0.7.0->qiskit) (57.4.0)
    Collecting scipy>=1.0
      Downloading scipy-1.7.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (38.1 MB)
         |████████████████████████████████| 38.1 MB 1.3 MB/s
    Collecting symengine>=0.8
      Downloading symengine-0.8.1-cp37-cp37m-manylinux2010_x86_64.whl (38.2 MB)
         |████████████████████████████████| 38.2 MB 1.1 MB/s
    Collecting ply>=3.10
      Downloading ply-3.11-py2.py3-none-any.whl (49 kB)
         |████████████████████████████████| 49 kB 4.1 MB/s
    Collecting stevedore>=3.0.0
      Downloading stevedore-3.5.0-py3-none-any.whl (49 kB)
         |████████████████████████████████| 49 kB 219 kB/s
    Collecting python-constraint>=1.4
      Downloading python-constraint-1.4.0.tar.bz2 (18 kB)
    Requirement already satisfied: psutil>=5 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.19.1->qiskit) (5.4.8)
    Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.19.1->qiskit) (1.7.1)
    Requirement already satisfied: dill>=0.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.19.1->qiskit) (0.3.4)
    Collecting tweedledum<2.0,>=1.1
      Downloading tweedledum-1.1.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (943 kB)
         |████████████████████████████████| 943 kB 65.2 MB/s
    Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.8.0->qiskit-ibmq-provider==0.18.3->qiskit) (1.15.0)
    Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.3->qiskit) (2.10)
    Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.3->qiskit) (3.0.4)
    Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.3->qiskit) (2021.10.8)
    Collecting cryptography>=1.3
      Downloading cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl (3.6 MB)
         |████████████████████████████████| 3.6 MB 58.1 MB/s
    Collecting ntlm-auth>=1.0.2
      Downloading ntlm_auth-1.5.0-py2.py3-none-any.whl (29 kB)
    Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.7/dist-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.3->qiskit) (1.15.0)
    Requirement already satisfied: pycparser in /usr/local/lib/python3.7/dist-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.3->qiskit) (2.21)
    Collecting pbr!=2.1.0,>=2.0.0
      Downloading pbr-5.8.0-py2.py3-none-any.whl (112 kB)
         |████████████████████████████████| 112 kB 58.0 MB/s
    Requirement already satisfied: importlib-metadata>=1.7.0 in /usr/local/lib/python3.7/dist-packages (from stevedore>=3.0.0->qiskit-terra==0.19.1->qiskit) (4.10.0)
    Requirement already satisfied: typing-extensions>=3.6.4 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata>=1.7.0->stevedore>=3.0.0->qiskit-terra==0.19.1->qiskit) (3.10.0.2)
    Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata>=1.7.0->stevedore>=3.0.0->qiskit-terra==0.19.1->qiskit) (3.7.0)
    Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy>=1.3->qiskit-terra==0.19.1->qiskit) (1.2.1)
    Building wheels for collected packages: qiskit, python-constraint
      Building wheel for qiskit (setup.py) ... done
      Created wheel for qiskit: filename=qiskit-0.34.1-py3-none-any.whl size=11771 sha256=86db6f0858d82a18d20e81db5bfa58720eb18dbf6d6d27471a63e5ba617490c2
      Stored in directory: /root/.cache/pip/wheels/79/b1/3f/8cdfd5543a84705e4bd16e081f2362b9b3bfd9898d2e2d4150
      Building wheel for python-constraint (setup.py) ... done
      Created wheel for python-constraint: filename=python_constraint-1.4.0-py2.py3-none-any.whl size=24081 sha256=b209c85fb81681840b73f43a3a02a35b1db5b502382c51a8acbef98ce8ed72e8
      Stored in directory: /root/.cache/pip/wheels/07/27/db/1222c80eb1e431f3d2199c12569cb1cac60f562a451fe30479
    Successfully built qiskit python-constraint
    Installing collected packages: pbr, tweedledum, symengine, stevedore, scipy, retworkx, python-constraint, ply, ntlm-auth, cryptography, websocket-client, requests-ntlm, qiskit-terra, qiskit-ignis, qiskit-ibmq-provider, qiskit-aer, qiskit
      Attempting uninstall: scipy
        Found existing installation: scipy 1.4.1
        Uninstalling scipy-1.4.1:
          Successfully uninstalled scipy-1.4.1
    ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
    albumentations 0.1.12 requires imgaug<0.2.7,>=0.2.5, but you have imgaug 0.2.9 which is incompatible.
    Successfully installed cryptography-36.0.1 ntlm-auth-1.5.0 pbr-5.8.0 ply-3.11 python-constraint-1.4.0 qiskit-0.34.1 qiskit-aer-0.10.2 qiskit-ibmq-provider-0.18.3 qiskit-ignis-0.7.0 qiskit-terra-0.19.1 requests-ntlm-1.1.0 retworkx-0.11.0 scipy-1.7.3 stevedore-3.5.0 symengine-0.8.1 tweedledum-1.1.1 websocket-client-1.2.3

```python
import numpy as np
from qiskit import QuantumCircuit, transpile
from qiskit.providers.aer import QasmSimulator
from qiskit.visualization import plot_histogram
```

```python
# Usar o Aer's qasm_simulator
simulator = QasmSimulator()
```

```python
# Criar um circuito quântico para atuar no registro q
circuit = QuantumCircuit(2, 2)
```

```python
# Adiciona uma porta H no qubit 0
circuit.h(0)
```

    <qiskit.circuit.instructionset.InstructionSet at 0x7f12742e66e0>

```python
# Adiciona uma porta CX (CNOT) o qubit 0 de controle e o qubit 1 alvo
circuit.cx(0, 1)
```

    <qiskit.circuit.instructionset.InstructionSet at 0x7f12742f00f0>

```python
# Mapear a medição quântica para os bits clássicos
circuit.measure([0,1], [0,1])
```

```python
# compilar o circuito para instruções QASM
# suportado pelo back-end
compiled_circuit = transpile(circuit, simulator)
```

```python
# Execute o circuito no simulador qasm
job = simulator.run(compiled_circuit, shots=1000)
```

```python
# Obtenha os resultados do trabalho
result = job.result()
```

```python
# Returna o contador
counts = result.get_counts(compiled_circuit)
print("\nTotal de contagens para 00 e 11 é:",counts)
```

```python
# Desenha o circuito
circuit.draw()
```

```python
# Denhar o histograma
plot_histogram(counts)
```