Esempio n. 1
0
def test_shapes(shape1: List[int], shape2: List[int], expected: List[int],
                dtype: str):
    """Test the shapes and np broadcasting. Don't really need to test the 
    broadcasting as that is tested at C++ level. But try a few cases to be sure
    binding works correctly.

    Args:
        shape1 (List[int]): First tensor shape
        shape2 (List[int]): Second Tensor Shape
        expected (List[int]): Expected shape
        dtype (Str): Popart data type to use
    """
    ir, graphs = create_ir(["A"])
    g = graphs[0]
    settings = _ir.Settings(g, "new_settings")
    num_inputs = _ir.NumInputs(1, 1)

    opid = _ir.OperatorIdentifier("ai.onnx", "Identity", 1, num_inputs, 1)
    op = _ir.Op(opid, settings)
    shape = op.prettyNpOut(shape1, shape2)
    assert shape == list(expected)
    t1 = _ir.TensorInfo(dtype, shape1)
    t2 = _ir.TensorInfo(dtype, shape2)
    shape = op.prettyNpOut(t1, t2)
    assert shape == _ir.TensorInfo(dtype, expected)
Esempio n. 2
0
def test_tensor_info_data_operator_eq_neq(dType1, shape1, metaShape1, dType2,
                                          shape2, metaShape2):
    """ Test the operator==() and operator!=() methods of a
    popart._internal.ir.TensorInfo object.
    """
    tensorInfo1 = _ir.TensorInfo(dType1, shape1, metaShape1)
    tensorInfo2 = _ir.TensorInfo(dType2, shape2, metaShape2)
    areEqual = all(
        [dType1 == dType2, shape1 == shape2, metaShape1 == metaShape2])
    assert (tensorInfo1 == tensorInfo2) == areEqual
Esempio n. 3
0
def test_tensor_info_construction():
    """ Test that we can construct a popart._internal.ir.TensorInfo object. """
    dType = _ir.DataType.FLOAT16
    dTypeStr = "FLOAT16"
    shape = [5, 5]
    shapeStr = "(5,5)"
    metaShape = [25, 1]
    _ir.TensorInfo(dType, shape)
    _ir.TensorInfo(dType, shape, metaShape)
    _ir.TensorInfo(dTypeStr, shapeStr)
    _ir.TensorInfo(dTypeStr, shape)
Esempio n. 4
0
def _setup_call_and_repeat(
    pb_ir: _ir.Ir, pb_top_graph: _ir.Graph, pb_bottom_graph: _ir.Graph
) -> Tuple[_ir.Graph, _ir.op.CallOp, _ir.op.LoopOp]:
    """Setup the call and repeat ops, as well as the middle graph that the loop op will loop.

    Args:
        pb_ir (_ir.Ir): The _ir level Ir
        pb_top_graph (_ir.Graph): The _ir top level graph that will contain the loop op.
        pb_bottom_graph (_ir.Graph): The _ir user defined subgraph that will be called.

    Returns:
        Tuple[_ir.Graph, _ir.op.CallOp, _ir.op.LoopOp]: The created _ir-level middle graph, call op
            and loop op.
    """
    # This is the graph we will repeat.
    pb_middle_graph = pb_ir.createGraph(
        _ir.GraphId(
            pb_ir.createUniqueSubgraphId(
                f"{pb_bottom_graph.id.str()}__loop_wrapper")))

    opid = _ir.OperatorIdentifier("ai.graphcore", "Call", 1, _ir.NumInputs(),
                                  0)
    op_name = pb_middle_graph.id.str() + '__call__' + pb_bottom_graph.id.str()

    ctx = get_current_context()
    # Call the bottom_graph
    pb_callop = pb_middle_graph.createOp_CallOp(opid, pb_bottom_graph,
                                                ctx._get_op_settings(op_name))

    opid = _ir.OperatorIdentifier("ai.onnx", "Loop", 11, _ir.NumInputs(), 0)
    op_name = pb_top_graph.id.str() + '__loop__' + pb_middle_graph.id.str()

    # Loop the middle_graph
    pb_loop_op = pb_top_graph.createOp_LoopOp(opid,
                                              ctx._get_op_settings(op_name),
                                              pb_middle_graph)

    # Add mandatory loop iterator tensor to subgraph (is not an output)
    repeatIterId = _ir.addScope(pb_middle_graph, "Iterator___")
    pb_middle_graph.addInput(repeatIterId,
                             _ir.TensorInfo(_ir.DataType.INT32, ()))

    # Add mandatory loop condition tensor to subgraph (is also an output)
    repeatCondId = _ir.addScope(pb_middle_graph, "LoopCond___")
    pb_middle_graph.addInput(repeatCondId,
                             _ir.TensorInfo(_ir.DataType.BOOL, ()))
    pb_middle_graph.markAsOutput(repeatCondId)

    return pb_middle_graph, pb_callop, pb_loop_op
Esempio n. 5
0
def add_tensor(graph: _ir.Graph,
               tid: str = "t",
               shape: List[int] = [1],
               t_type: _ir.TensorType = _ir.TensorType.ActGrad,
               d_type: _ir.DataType = _ir.DataType.FLOAT) -> _ir.Tensor:
    """Add a tensor to the given graph, with given properties.

    Args:
        graph (_ir.Graph): Graph to use
        tid (str, optional): Id for the tensor. Defaults to "t".
        shape (List[int], optional): Shape for the tensor. Defaults to [1].
        t_type (_ir.TensorType, optional): Tensor type. Defaults to _ir.TensorType.ActGrad.
        d_type (_ir.DataType, optional): DataType for the tensor. Defaults to _ir.DataType.FLOAT.

    Returns:
        _ir.Tensor: the tensor that was just added.
    """
    ts = _ir.Tensors(graph)
    tinfo = _ir.TensorInfo(d_type, shape)
    if t_type == _ir.TensorType.ActGrad:
        ts.addActGrad(tid)
    elif t_type == _ir.TensorType.Variable:
        data = np.random.rand(*shape).astype(np.float32)
        ts.addVarInit(tid, tinfo, data)
    elif t_type == _ir.TensorType.Const:
        data = np.random.rand(*shape).astype(np.float32)
        ts.addConstInit(tid, tinfo, data)
    return ts.get(tid)
Esempio n. 6
0
def test_tensor_info_set0():
    """ Test the set() method of a popart._internal.ir.TensorInfo object. """
    dTypeOld = _ir.DataType.FLOAT
    dTypeNew = _ir.DataType.INT8
    tensorInfo = _ir.TensorInfo(dTypeOld, [4, 2])
    tensorInfo.set(dTypeNew)
    assert tensorInfo.dataType() == dTypeNew
Esempio n. 7
0
def init(shape: Iterable[int], dtype: dtypes.dtype,
         name: Optional[str] = None) -> Tensor:
    """
    Init Op: create a tensor with zero values.
        The returned tensor is not considered a variable.

    Args:
        dtype (dtypes.dtype): Data type for the output Tensor
        shape (Tuple[int]): Shape of the output tensor.
        name (str): Name to use for the poplar stream.

    Returns:
        Tensor: The output tensor streamed from host.
    """
    ctx = get_current_context()
    g = ctx.graph

    pb_g = g._pb_graph
    info = _ir.TensorInfo(dtype._pb_dtype, list(shape))

    opid_init = _ir.OperatorIdentifier("ai.graphcore", "Init", 1,
                                       _ir.NumInputs(0), 1)
    op = pb_g.createConnectedOp_InitOp(
        {},
        {0: g._create_tensor_id(name)},
        opid_init,
        info,
        _ir.TensorType.ActGrad,
        _ir.InitType.Zero,
        ctx._get_op_settings('init'),
        -1,
    )

    return Tensor._from_pb_tensor(op.outTensor(0))
Esempio n. 8
0
def prepare_remote_buffer(t: Tensor,
                          remote_buffer_handle: Optional[RemoteBufferHandle],
                          g: Graph) -> RemoteBufferHandle:
    """Prepare the remote buffer.

    Args:
        t (Tensor): Input tensor to the op.
        remote_buffer_handle (Optional[RemoteBufferHandle]): If set:
          The remote buffer handle to use in the preparation
        g (Graph): The graph to set the remote buffer info to

    Raises:
        ValueError: If there is a shape or type mismatch between `t` and
          `remote_buffer_handle`

    Returns:
        RemoteBufferHandle: The remote buffer handle used in the preparation.
    """
    if remote_buffer_handle is None:
        shape = t._pb_tensor.info.shape()
        d_type = dtype.as_dtype(t._pb_tensor.info.data_type_lcase())
        # Check for existing buffer handles
        existing_buffers = RemoteBufferHandle._buffers
        for _, rbh in existing_buffers.items():
            if rbh.tensor_shape == shape and rbh.tensor_dtype == d_type:
                remote_buffer_handle = rbh
                break

        if remote_buffer_handle is None:
            # Create handle if not found
            remote_buffer_handle = RemoteBufferHandle(remote_buffer_id=None,
                                                      tensor_shape=shape,
                                                      tensor_dtype=d_type,
                                                      repeats=1)

    # The remote buffer handle may be set, and may have empty shape and dtype
    if remote_buffer_handle.tensor_shape is None:
        remote_buffer_handle.tensor_shape = t._pb_tensor.info.shape()
    if remote_buffer_handle.tensor_dtype is None:
        remote_buffer_handle.tensor_dtype = dtype.as_dtype(
            t._pb_tensor.info.data_type_lcase())

    info = _ir.TensorInfo(remote_buffer_handle.tensor_dtype._pb_dtype,
                          remote_buffer_handle.tensor_shape)
    if t._pb_tensor.info.dataType() != info.dataType():
        raise ValueError(
            f"DataType of {t.id} ({t._pb_tensor.info.dataType()}) "
            f"does not match that of the RemoteBufferHandle ({info.dataType()})"
        )
    if t._pb_tensor.info.shape() != info.shape():
        raise ValueError(
            f"DataType of {t.id} ({t._pb_tensor.info.shape()}) "
            f"does not match that of the RemoteBufferHandle ({info.shape()})")

    g._ir._pb_ir.setRemoteBufferInfo(
        remote_buffer_handle.remote_buffer_id,
        _ir.RemoteBufferInfo(info, remote_buffer_handle.repeats))

    return remote_buffer_handle
Esempio n. 9
0
def test_tensor_info_set2(dTypeOld, dTypeNew, shapeOld, shapeNew, metaShapeOld,
                          metaShapeNew):
    """ Test the set() method of a popart._internal.ir.TensorInfo object. """
    tensorInfo = _ir.TensorInfo(dTypeOld, shapeOld, metaShapeOld)
    tensorInfo.set(dTypeNew, shapeNew, metaShapeNew)
    assert tensorInfo.shape() == shapeNew
    assert tensorInfo.metaShape() == metaShapeNew
    assert tensorInfo.dataType() == dTypeNew
Esempio n. 10
0
def test_tensor_data_reset_data():
    """ Test the resetData() method of a popart._internal.ir.TensorData object.
    """
    a = np.random.rand(2, 3, 4)
    b = np.random.rand(2, 3, 4)
    tInfo = _ir.TensorInfo(_ir.DataType.FLOAT, a.shape)
    tData = _ir.TensorData(tInfo, a)
    tData.resetData(tInfo, b)
Esempio n. 11
0
def add_actgrad_tensor(id_: str,
                       shape: List[int],
                       g: "_ir.Graph",
                       dtype: "_ir.DataType" = _ir.DataType.FLOAT):
    t_info = _ir.TensorInfo(dtype, shape)
    g.addActGrad(id_)
    t = g.getTensor(id_)
    t.info = t_info
    return t
Esempio n. 12
0
def test_tensor_has_tensor_data():
    """ Test the hasTensorData() method of a popart._internal.ir.Tensor object.
    """
    ir = _ir.Ir()
    g = ir.createGraph("g")
    t = _ir.Tensor("t", _ir.TensorType.ActGrad, g)
    assert t.hasTensorData() == False
    buffer = np.random.rand(2, 3, 4)
    tInfo = _ir.TensorInfo(_ir.DataType.FLOAT, buffer.shape)
    t.setTensorData(tInfo, buffer)
    assert t.hasTensorData() == True
Esempio n. 13
0
def test_loop_op():
    """Test setting up the loop op.
    """
    _, graphs = create_ir(["sub_graph"])  # main graph and 'sub_graph'
    main = graphs[0]
    sub_graph = graphs[1]
    num_inputs = _ir.NumInputs(2, 2)
    main.addConstInit("loopcount", _ir.TensorInfo(_ir.DataType.INT64, []),
                      np.array(10))
    main.addConstInit("keepgoing", _ir.TensorInfo(_ir.DataType.BOOL, []),
                      np.array(True))
    a = add_actgrad_tensor("a", [1, 2, 3], main, _ir.DataType.FLOAT)
    b = add_actgrad_tensor("b", [1, 2, 3], main, _ir.DataType.FLOAT)

    sub_graph.addInput("loopcount", _ir.TensorInfo(_ir.DataType.INT64, []))
    sub_graph.addInput("keepgoing", _ir.TensorInfo(_ir.DataType.BOOL, []))
    sub_graph.addInput("a", a.info)
    sub_graph.addInput("b", b.info)

    opid = _ir.OperatorIdentifier("ai.graphcore", "Loop", 1, num_inputs, 1)

    settings = _ir.Settings(main, "new_settings")

    add = sub_graph.createConnectedOp_AddOp(
        {
            0: a.id,
            1: b.id
        },
        {0: "out"},
        _ir.OperatorIdentifier("ai.onnx", "Add", 1, num_inputs, 1),
        settings,
    )
    sub_graph.markAsOutput(add.outTensor(0).id)
    sub_graph.markAsOutput("keepgoing")

    ins: Dict[int, str] = {0: "loopcount", 1: "keepgoing", 2: a.id}
    outs: Dict[int, str] = {0: add.outTensor(0).id}
    op = main.createConnectedOp_LoopOp(ins, outs, opid, settings, sub_graph)

    assert op.getCalledGraphs()[0] == sub_graph
    assert op.getCalledGraphIds()[0] == "sub_graph"
Esempio n. 14
0
def test_graph_graph_outputs():
    """ Test we can add/remove graph outputs. """
    ir = _ir.Ir()
    g1Id = _ir.GraphId("g1")
    g1 = ir.createGraph(g1Id)

    # We add inputs as a way of adding tensors to the graph that we can mark as
    # outputs.
    g1.addInput("t0", _ir.TensorInfo(_ir.DataType.FLOAT16, [5, 5]))
    g1.addInput("t1", _ir.TensorInfo(_ir.DataType.FLOAT16, [5, 5]))
    g1.addInput("t2", _ir.TensorInfo(_ir.DataType.FLOAT16, [5, 5]))

    # Check markAsInput.
    check_graph_outputs(g1, [])
    g1.markAsOutput("t0")
    check_graph_outputs(g1, ["t0"])
    g1.markAsOutput(0, "t1", False)
    check_graph_outputs(g1, ["t1", "t0"])
    g1.markAsOutput(0, "t2", True)
    check_graph_outputs(g1, ["t2", "t0"])

    # Check getOutputId.
    assert g1.getOutputId(0) == "t2"
    assert g1.getOutputId(1) == "t0"

    # Check getOutputIndex
    assert g1.getOutputIndex("t2") == 0
    assert g1.getOutputIndex("t0") == 1
    with pytest.raises(popart.popart_exception) as excinfo:
        g1.getOutputIndex("nonExistingTensor")

    # Check hasOutputId.
    assert g1.hasOutputId("t0")
    assert g1.hasOutputId("t2")
    assert not g1.hasOutputId("t1")

    # Check removeInput.
    g1.removeOutput(1)
    check_graph_outputs(g1, ["t2"])
    g1.removeOutput("t2")
    check_graph_outputs(g1, [])
Esempio n. 15
0
def test_graph_graph_inputs():
    """ Test we can add/remove graph inputs. """
    ir = _ir.Ir()
    g1Id = _ir.GraphId("g1")
    g1 = ir.createGraph(g1Id)

    # Check initially graph inputs are empty.
    check_graph_inputs(g1, [])

    # Check addInput.
    g1.addInput("inputA", _ir.TensorInfo(_ir.DataType.FLOAT16, [5, 5]))
    check_graph_inputs(g1, ["inputA"])
    g1.addInput("inputB", _ir.TensorInfo(_ir.DataType.FLOAT, [65, 5]))
    check_graph_inputs(g1, ["inputA", "inputB"])
    g1.addInput(1, "input1", _ir.TensorInfo(_ir.DataType.FLOAT, [65, 5]),
                False)
    check_graph_inputs(g1, ["inputA", "input1", "inputB"])
    g1.addInput(1, "input2", _ir.TensorInfo(_ir.DataType.FLOAT, [65, 5]), True)
    check_graph_inputs(g1, ["inputA", "input2", "inputB"])

    # Check getInputId.
    assert g1.getInputId(0) == "inputA"
    assert g1.getInputId(1) == "input2"
    assert g1.getInputId(2) == "inputB"

    # Check getInputIndex
    assert g1.getInputIndex("inputA") == 0
    assert g1.getInputIndex("input2") == 1
    assert g1.getInputIndex("inputB") == 2
    with pytest.raises(popart.popart_exception) as excinfo:
        g1.getInputIndex("nonExistingTensor")

    # Check hasInputId.
    assert g1.hasInputId("inputA")
    assert not g1.hasInputId("input1")

    # Check removeInput.
    g1.removeInput(1)
    check_graph_inputs(g1, ["inputA", "inputB"])
    g1.removeInput("inputA")
    check_graph_inputs(g1, ["inputB"])
Esempio n. 16
0
def test_nll_op(reduction: _ir.ReductionType, ignoreIndex: int,
                connected: bool) -> None:
    """Test the Nll Op, special case with unusual arguments.

    Args:
        reduction (_ir.ReductionType): The reduction type to use
        ignoreIndex (int): The index to ignore. Note this has to be converted to
            an _ir.OptionalInt
        connected (bool): Whether to use the createConnected<opname> function or
            just create<opname>
    """
    _, graphs = create_ir()
    main = graphs[0]
    num_inputs = _ir.NumInputs(2, 2)
    in0 = add_actgrad_tensor("in0", [8, 2, 3], main)

    t_info = _ir.TensorInfo(_ir.DataType.INT32, [8, 2])
    main.addActGrad("label")
    l = main.getTensor("label")
    l.info = t_info

    out0 = add_actgrad_tensor("out0", [1, 2, 3], main)

    opid = _ir.OperatorIdentifier("ai.graphcore", "nll", 1, num_inputs, 1)
    settings = _ir.Settings(main, "nll")

    if connected:
        ins: Dict[int, str] = {0: in0.id, 1: l.id}
        outs: Dict[int, str] = {0: out0.id}
        op = main.createConnectedOp_NllOp(
            ins,
            outs,
            ignoreIndex=_ir.OptionalInt(ignoreIndex),  # <- Note this
            reduction=_ir.ReductionType.Mean,
            inputIsLogProbability=True,
            opid=opid,
            settings=settings)
        return
    op = main.createOp_NllOp(
        opid=opid,
        ignoreIndex=_ir.OptionalInt(ignoreIndex),  # <- Note this
        reduction=_ir.ReductionType.Mean,
        inputIsLogProbability=True,
        settings=settings)
    op.connectInTensor(0, in0.id)
    op.connectInTensor(1, l.id)
    op.connectOutTensor(0, out0.id)
    op.setup()
Esempio n. 17
0
def subgraph_input(shape: Iterable[int],
                   dtype: dtypes.dtype,
                   name: Optional[str] = None,
                   by_ref: bool = False) -> Tensor:
    """Create a new input tensor to the current graph.

    You can use this function when defining a subgraph to create a new input
    tensor. When you call that subgraph, you will have to pass a tensor to the
    subgraph for this input.

    Example:
    ```
    import popart.ir as pir

    def add_w(x):
        w = pir.subgraph_input(x.shape, x.dtype, "w")
        return w + x

    ir = pir.Ir()
    with ir.main_graph():
        w = pir.variable(1)
        x = pir.variable(3)
        add_w_graph = ir.create_graph(add_w, x, w)
        y = ops.call(add_w_graph, x, w)
    ```

    Args:
        shape (Tuple[int, ...])
            The shape of the Tensor
        dtype (dtype):
            The data type of the tensor
        name (Optional[str]):
            The name of the tensor.
    """
    g = gcg()
    pb_g = g._pb_graph

    pb_id = g._create_tensor_id(name)
    pb_info = _ir.TensorInfo(dtype._pb_dtype, list(shape))

    pb_g.addInput(pb_id, pb_info)

    t = Tensor._from_pb_tensor(pb_g.getTensor(pb_id))

    if by_ref:
        g._by_ref_inputs.add(t)

    return t
Esempio n. 18
0
def add_random_tensor(id_: str, t_type: "_ir.TensorType", shape: List[int],
                      g: "_ir.Graph") -> "_ir.Tensor":
    data = np.random.random(shape).astype(np.float32)
    t_info = _ir.TensorInfo(_ir.DataType.FLOAT, shape)
    if t_type == _ir.TensorType.ActGrad:
        raise TypeError("Use add_actgrad_tensor for adding actgrad tensors. "
                        "Actgrad tensors have no initial value.")
    elif t_type == _ir.TensorType.Variable:
        g.addVarInit(id_, t_info, data, "")
        return g.getTensor(id_)
    elif t_type == _ir.TensorType.Const:
        g.addConstInit(id_, t_info, data, "")
        return g.getTensor(id_)

    else:
        raise TypeError("Incorrect tensor type")
Esempio n. 19
0
def constant(
    data: Union[np.ndarray, Iterable[Any], int, float],
    dtype: Optional[dtypes.dtype] = None,
    name: Optional[str] = None,
    downcast: bool = True,
) -> Constant:
    """A constant tensor that is initialised with data during graph creation.

    This tensor cannot change during the runtime of a model. The intended use
    of this class is when doing operations between `popart.ir.Tensor`
    instances and other types, such as `numpy.ndarray` objects, numbers, or
    list or tuples of numbers.

    Example:
    ```
    import popart.ir as pir
    ir = pir.Ir()
    with ir.main_graph():
        a = pir.constant(0)
        # The `1` will be implicitly converted to a `Constant`.
        b = a + 1
    ```

    Args:
        data (np.array, or a value numpy can use to construct an np.ndarray):
            The data used to initialise the tensor.
        dtype (Optional[dtype]):
            The data type of the tensor to be created, if not specified Numpy will infer the data
            type and be downcasted to 32 bits if necessary.
        name (Optional[str]):
            The name of the tensor. Defaults to `None`.
    """
    g = gcg()
    pb_g = g._pb_graph
    np_dtype = dtype.as_numpy() if dtype is not None else None
    np_data: np.ndarray = np.array(data, dtype=np_dtype)
    if np_data.dtype in downcast_np_dtypes and downcast and dtype is None:
        np_data = np_data.astype(downcast_np_dtypes[np_data.dtype])
    pir_dt = dtypes.dtype.as_dtype(np_data)
    info = _ir.TensorInfo(pir_dt._pb_dtype, np_data.shape)
    pb_id = g._create_tensor_id(name)
    pb_g.addConstInit(pb_id, info, np_data)
    return Constant._from_pb_tensor(pb_g.getTensor(pb_id))
Esempio n. 20
0
def variable(
    data: Union[np.ndarray, Iterable[Any], int, float, bool],
    dtype: Optional[dtypes.dtype] = None,
    name: Optional[str] = None,
    downcast: bool = True,
) -> Variable:
    """
    A variable tensor that is initialised with data during graph creation.

    This tensor can be used to represent a model weight or any other
    parameter that can change while running a model.

    Must be created in the main graph scope. Example:
    ```
    import popart.ir as pir
    with pir.Ir().main_graph():
        a = pir.variable(0)
    ```

    Args:
        data (np.ndarray, or a value numpy can use to construct an np.ndarray):
            The data used to initialise the tensor.
        dtype (Optional[dtype]):
            The data type of the tensor to be created, if not specified Numpy will infer the data
            type and be downcasted to 32 bits if necessary.
        name (Optional[str]):
            The name of the tensor. Defaults to `None`.
        downcast (bool):
            If no dtype is provided 64 bit float/ints will be downcasted to 32 bit variants. Default to True.
    """
    g = gcg()
    pb_g = g._pb_graph
    np_dtype = dtype.as_numpy() if dtype is not None else None
    np_data: np.ndarray = np.array(data, dtype=np_dtype)
    if np_data.dtype in downcast_np_dtypes and downcast and dtype is None:
        np_data = np_data.astype(downcast_np_dtypes[np_data.dtype])
    pir_dt = dtypes.dtype.as_dtype(np_data)
    info = _ir.TensorInfo(pir_dt._pb_dtype, np_data.shape)
    pb_id = g._create_tensor_id(name)
    pb_g.addVarInit(pb_id, info, np_data)
    return Variable._from_pb_tensor(pb_g.getTensor(pb_id))
Esempio n. 21
0
def h2d_stream(shape: Iterable[int],
               dtype: dtype,
               name: Optional[str] = None) -> HostToDeviceStream:
    g = gcg()
    mg = g.ir().main_graph()

    if g.name != mg.name:
        raise ValueError(
            "popart.ir: Can only call `h2d_stream` in context of main graph. You are in context of graph:",
            g.name)

    pb_mg = mg._pb_graph

    if name is None:
        name = "h2d_stream"
    name = mg._create_tensor_id(name)

    pb_mg.addStream(name, _ir.TensorInfo(dtype._pb_dtype, list(shape)), name)

    return HostToDeviceStream._from_tensor(
        Tensor._from_pb_tensor(pb_mg.getTensor(name)))
Esempio n. 22
0
def test_tensor_tensor_data():
    """ Test the tensorData() and setTensorData() methods of a
    popart._internal.ir.Tensor object.
    """
    ir = _ir.Ir()
    g = ir.createGraph("g")
    t = _ir.Tensor("t", _ir.TensorType.ActGrad, g)

    with pytest.raises(popart.popart_exception) as e_info:
        t.tensorData()
        assert e_info.value.args[0] == "Data not set for t"
    with pytest.raises(popart.popart_exception) as e_info:
        t.tensorData_const()
        assert e_info.value.args[0] == "Data not set for t"

    buffer = np.random.rand(2, 3, 4)
    tInfo = _ir.TensorInfo(_ir.DataType.FLOAT, buffer.shape)
    t.setTensorData(tInfo, buffer)

    # TODO(T42205): Test that the returned tensor data matches the one that was
    # set.
    t.tensorData()
    t.tensorData_const()
Esempio n. 23
0
def test_tensor_info_meta_shape(metaShape):
    """ Test the metaShape() method of a popart._internal.ir.TensorInfo object.
    """
    tensorInfo = _ir.TensorInfo(_ir.DataType.FLOAT, [6], metaShape)
    assert tensorInfo.metaShape() == metaShape
Esempio n. 24
0
def test_tensor_info_nelms(dType, shape, nBytesInDType):
    """ Test the nelms() method of a popart._internal.ir.TensorInfo object. """
    tensorInfo = _ir.TensorInfo(dType, shape)
    assert tensorInfo.nbytes() == np.prod(shape) * nBytesInDType
Esempio n. 25
0
        assert op.inTensor(i) == t
        assert op.hasInput(i)
        assert op.inId(i) == t.id
    for i, t in outs.items():
        assert op.outTensor(i) == t
        assert op.hasOutput(i)
        assert op.outId(i) == t.id
    assert op.getCalledGraphs() == []
    assert op.getCalledGraphIds() == []


@pytest.mark.parametrize("connected", [True, False])
# yapf: disable, pylint: disable-all
@pytest.mark.parametrize("op_name,inplace,kwargs",
[
("DynamicUpdateOp", False, {"axes_":[0], "sizes_":[1], "noOverlap_":False, "updateInInfo_": _ir.TensorInfo()}),
("DynamicUpdateInplaceOp", False, {"axes_":[0], "sizes_":[1], "noOverlap_":False, "updateInInfo_": _ir.TensorInfo()}),
])
# yapf: enable, pylint: enable-all
def test_ternary_ops(connected: bool, inplace: bool, op_name: str,
                     kwargs: Dict[str, Any]) -> None:
    """Test unary (3 in, 1 out) ops

    Args:
        connected (bool): Whether to use the createConnected<opname> function or 
            just create<opname>
        inplace (bool): Whether this op is inplace
        op_name (str): Name of the op e.g. AddOp
        kwargs (Dict[str, Any]): Additional kwargs to pass to the ops
    """
    _, graphs = create_ir()
Esempio n. 26
0
def test_tensor_info_dim(shape):
    """ Test the dim() method of a popart._internal.ir.TensorInfo object. """
    tensorInfo = _ir.TensorInfo(_ir.DataType.FLOAT, shape)
    for i, dim in enumerate(shape):
        assert tensorInfo.dim(i) == dim
Esempio n. 27
0
def test_tensor_info_data_type(dType):
    """ Test the dataType() method of a popart._internal.ir.TensorInfo object.
    """
    tensorInfo = _ir.TensorInfo(dType, [6])
    assert tensorInfo.dataType() == dType
Esempio n. 28
0
def test_tensor_info_data_type_lcase(dType, dTypeLowerCase):
    """ Test the data_type_lcase() method of a popart._internal.ir.TensorInfo
    object.
    """
    tensorInfo = _ir.TensorInfo(dType, [5, 5])
    assert tensorInfo.data_type_lcase() == dTypeLowerCase
Esempio n. 29
0
def test_tensor_info_shape(dType, shape, expectedShape):
    """ Test the shape() method of a popart._internal.ir.TensorInfo object. """
    tensorInfo = _ir.TensorInfo(dType, shape)
    assert tensorInfo.shape() == expectedShape
Esempio n. 30
0
def make_main_graph(
        num_inputs: int = 2
) -> Tuple[_ir.Ir, List[_ir.Tensor], List[_ir.Tensor]]:
    """
    Creates the following graph, with num_inputs inputs, 
    alternating data inputs and variable inputs.

    Init (act) Init (var)  Init (act) Init (var)
    │          │           │          │
    ▼          ▼           ▼          ▼
    Hostload   Hostload    Hostload   Hostload    etc..
    │          │           │          │
    │          │           │          │
    ▼          ▼           ▼          ▼
    ┌────────────────────────────────────┐
    │                Call                │
    │                                    │
    └──────────────────┬─────────────────┘
                        │
                        │
                        ▼
                    HostStore
    Args:
        num_inputs (int, optional): Number of main graph inputs. Defaults to 2.

    Returns:
        Tuple[_ir.Ir, List[_ir.Tensor], List[_ir.Tensor]]:
            The ir, The subgraph output tensors, and the variable tensors
    """
    ir, _ = create_ir()

    main = ir.getMainGraph()

    t_info = _ir.TensorInfo(_ir.DataType.FLOAT, [1, 2, 3])

    inits: Dict[int, _ir.Op] = dict()
    hostloads: Dict[int, _ir.Op] = dict()
    inputs = {i: t_info for i in range(num_inputs)}

    for i in range(len(inputs)):
        # init i
        opid = _ir.OperatorIdentifier("ai.onnx", f"Init{i}", 1,
                                      _ir.NumInputs(0, 0), 1)
        actgrads = []
        vars_ = []
        settings = _ir.Settings(main, f"input{i}")
        if i % 2 == 0:
            ttype = _ir.TensorType.ActGrad
            inits[i] = main.createConnectedOp_InitOp({}, {0: f"init{i}"}, opid,
                                                     t_info, ttype,
                                                     _ir.InitType.Zero,
                                                     settings, 0)
            actgrads.append(inits[i])
        else:
            ttype = _ir.TensorType.Variable
            inits[i] = main.createConnectedOp_InitOp({}, {0: f"init{i}"}, opid,
                                                     t_info, ttype,
                                                     _ir.InitType.Zero,
                                                     settings, 0)
            vars_.append(inits[i].outTensor(0))

        # hostload i
        opid = _ir.OperatorIdentifier("ai.onnx", f"HostLoad{i}", 1,
                                      _ir.NumInputs(1, 1), 1)
        hostloads[i] = main.createConnectedOp_HostLoadOp(
            {0: inits[i].outTensor(0).id}, {0: f"hostload{i}"}, opid, settings,
            f"hl{i}")

    settings = _ir.Settings(main, "call")
    fwd = make_sub_graph(ir, inputs)

    fwd_outs = [fwd.getTensor(tid) for tid in fwd.getOutputIds()]

    opid = _ir.OperatorIdentifier("ai.graphcore", "Call", 1,
                                  _ir.NumInputs(num_inputs, num_inputs), 1)
    call = main.createConnectedOp_CallOp(
        {i: hostloads[i].outTensor(0).id
         for i in range(len(hostloads))}, {0: "call0"}, opid, fwd, settings)

    # host store
    opid = _ir.OperatorIdentifier("ai.onnx", "HostStore", 1,
                                  _ir.NumInputs(1, 1), 1)
    settings = _ir.Settings(main, "host_store")

    _ = main.createConnectedOp_HostStoreOp({0: call.outTensor(0).id}, {}, opid,
                                           settings, "hs1")

    deviceInfo = popart.DeviceManager().createIpuModelDevice({})
    ir.setDeviceInfo(deviceInfo)

    ir.setIsPrepared()
    ir.logIr()

    print(fwd_outs, vars_)

    return ir, fwd_outs, vars_