Skip to content

Commit d96de1f

Browse files
authored
Merge pull request #47 from velimir/matrix-ext
add functions to cast binaries into matrix and tensors
2 parents 796caee + 092dadd commit d96de1f

File tree

4 files changed

+152
-2
lines changed

4 files changed

+152
-2
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CFLAGS = -g -O3 -Wall -std=c99
22
ERLANG_PATH = $(shell erl -eval 'io:format("~s", [lists:concat([code:root_dir(), "/erts-", erlang:system_info(version), "/include"])])' -s init stop -noshell)
3-
LIBTENSORFLOW_PATH = /usr/local/lib
3+
LIBTENSORFLOW_PATH ?= /usr/local/lib
44
CFLAGS += -I$(ERLANG_PATH)
55
CFLAGS += -Ic_src
66
LDFLAGS += -L$(LIBTENSORFLOW_PATH)

c_src/Tensorflex.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,69 @@ static ERL_NIF_TERM tensor_to_matrix(ErlNifEnv *env, int argc,
11601160
return ret;
11611161
}
11621162

1163+
static ERL_NIF_TERM binary_to_matrix(ErlNifEnv *env, int argc,
1164+
const ERL_NIF_TERM argv[]) {
1165+
ErlNifBinary in_binary;
1166+
enif_inspect_binary(env, argv[0], &in_binary);
1167+
1168+
unsigned ncols, nrows;
1169+
enif_get_uint(env, argv[1], &nrows);
1170+
enif_get_uint(env, argv[2], &ncols);
1171+
1172+
Matrix * mx;
1173+
mx = alloc_matrix(env, nrows, ncols);
1174+
for (int i = 0; i < nrows; i++) {
1175+
for (int j = 0; j < ncols; j++) {
1176+
POS(mx, i, j) = in_binary.data[i * ncols + j];
1177+
}
1178+
}
1179+
1180+
ERL_NIF_TERM ret;
1181+
ret = enif_make_resource(env, mx);
1182+
enif_release_resource(mx);
1183+
1184+
return ret;
1185+
}
1186+
1187+
static ERL_NIF_TERM matrix_to_float32_tensor(ErlNifEnv *env, int argc,
1188+
const ERL_NIF_TERM argv[]) {
1189+
TF_Tensor *tensor;
1190+
TF_Tensor **tensor_resource_alloc =
1191+
enif_alloc_resource(tensor_resource, sizeof(TF_Tensor *));
1192+
1193+
mx_t mx;
1194+
if (!enif_get_resource(env, argv[0], resource_type, &mx.vp))
1195+
return enif_make_badarg(env);
1196+
1197+
const int size_alloc = mx.p->ncols * mx.p->nrows * sizeof(float);
1198+
float *data = enif_alloc(size_alloc);
1199+
for (int i = 0; i < mx.p->nrows; ++i) {
1200+
for (int j = 0; j < mx.p->ncols; ++j) {
1201+
data[i * mx.p->ncols + j] = (float)POS(mx.p, i, j);
1202+
}
1203+
}
1204+
1205+
int arity;
1206+
const ERL_NIF_TERM * array;
1207+
enif_get_tuple(env, argv[1], &arity, &array);
1208+
1209+
int64_t * dims = enif_alloc(arity);
1210+
for (int i = 0; i < arity; ++i) {
1211+
unsigned dim;
1212+
enif_get_uint(env, array[i], &dim);
1213+
dims[i] = dim;
1214+
}
1215+
1216+
tensor =
1217+
TF_NewTensor(TF_FLOAT, dims, arity, data, size_alloc, tensor_deallocator, 0);
1218+
memcpy((void *)tensor_resource_alloc, (void *)&tensor, sizeof(TF_Tensor *));
1219+
ERL_NIF_TERM new_tensor = enif_make_resource(env, tensor_resource_alloc);
1220+
enif_release_resource(tensor_resource_alloc);
1221+
1222+
enif_free(dims);
1223+
return enif_make_tuple2(env, enif_make_atom(env, "ok"), new_tensor);
1224+
}
1225+
11631226
static ErlNifFunc nif_funcs[] = {
11641227
{"create_matrix", 3, create_matrix},
11651228
{"matrix_pos", 3, matrix_pos},
@@ -1190,6 +1253,8 @@ static ErlNifFunc nif_funcs[] = {
11901253
{"add_matrices", 2, add_matrices},
11911254
{"subtract_matrices", 2, subtract_matrices},
11921255
{"tensor_to_matrix", 1, tensor_to_matrix},
1256+
{"binary_to_matrix", 3, binary_to_matrix},
1257+
{"matrix_to_float32_tensor", 2, matrix_to_float32_tensor}
11931258
};
11941259

11951260
ERL_NIF_INIT(Elixir.Tensorflex.NIFs, nif_funcs, res_loader, NULL, NULL, NULL)

lib/nifs.ex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,12 @@ defmodule Tensorflex.NIFs do
123123
raise "NIF tensor_to_matrix/1 not implemented"
124124
end
125125

126+
def binary_to_matrix(_binary, _nrows, _ncols) do
127+
raise "NIF binary_to_matrix/3 not implemented"
128+
end
129+
130+
def matrix_to_float32_tensor(_matrix, _dims) do
131+
raise "NIF matrix_to_float32_tensor/2 not implemented"
132+
end
133+
126134
end

lib/tensorflex.ex

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1525,5 +1525,82 @@ defmodule Tensorflex do
15251525
{nrows, ncols} = NIFs.size_of_matrix matrix_ref
15261526
%Matrix{nrows: nrows, ncols: ncols, data: matrix_ref}
15271527
end
1528-
1528+
1529+
@doc """
1530+
Creates a 2-D Tensorflex matrix from a given binary by iterating through a consequently allocated bytes.
1531+
1532+
Takes three input arguments: binary data (`binary`), number of rows in matrix (`nrows`), number of columns in matrix (`ncols`).
1533+
1534+
Returns a `%Matrix` Tensorflex struct type.
1535+
1536+
## Examples:
1537+
1538+
_Creating a new matrix_
1539+
1540+
```elixir
1541+
iex(1)> mat = Tensorflex.binary_to_matrix(<<1, 2, 3, 4>>, 1, 4)
1542+
%Tensorflex.Matrix{
1543+
data: #Reference<0.2581978403.3326476294.49460>,
1544+
ncols: 4,
1545+
nrows: 1
1546+
}
1547+
```
1548+
1549+
Useful when there's a binary (such as an image), that has to be loaded
1550+
into a matrix:
1551+
1552+
```elixir
1553+
iex(1)> image = File.read!("/tmp/image.rgb")
1554+
<<19, 19, 18, 21, 18, 19, 17, 18, 22, 19, 21, 21, 21, 22, 18, ...>>
1555+
iex(2)> Tensorflex.binary_to_matrix(image, 100, 100 * 3)
1556+
%Tensorflex.Matrix{
1557+
data: #Reference<0.2581978403.3326476294.49326>,
1558+
ncols: 300,
1559+
nrows: 100
1560+
}
1561+
```
1562+
1563+
"""
1564+
1565+
def binary_to_matrix(binary, nrows, ncols) do
1566+
matrix_ref = NIFs.binary_to_matrix(binary, nrows, ncols)
1567+
%Matrix{nrows: nrows, ncols: ncols, data: matrix_ref}
1568+
end
1569+
1570+
@doc """
1571+
Creates a `TF_FLOAT` tensor from Tensorflex matrices with a given dimension.
1572+
1573+
Takes two arguments: a `%Matrix` matrix (`matrix1`) containing the values the
1574+
tensor should have a tuple with a desired dimension of a new tensor.
1575+
1576+
Returns a tuple `{:ok, %Tensor}` where `%Tensor` represents an internal
1577+
Tensorflex struct type that is used for holding tensor data and type.
1578+
1579+
## Examples:
1580+
1581+
```elixir
1582+
iex(1)> image = File.read!("/tmp/image.rgb")
1583+
<<19, 19, 18, 21, 18, 19, 17, 18, 22, 19, 21, 21, 21, 22, 18, ...>>
1584+
1585+
iex(2)> mat = Tensorflex.binary_to_matrix(image, 311, 162 * 3)
1586+
%Tensorflex.Matrix{
1587+
data: #Reference<0.2581978403.3326476294.49499>,
1588+
ncols: 486,
1589+
nrows: 311
1590+
}
1591+
1592+
iex(3)> Tensorflex.matrix_to_float32_tensor(mat, {1, 311, 162, 3})
1593+
{:ok,
1594+
%Tensorflex.Tensor{
1595+
datatype: :tf_float,
1596+
tensor: #Reference<0.2581978403.3326476294.49507>
1597+
}}
1598+
```
1599+
"""
1600+
1601+
def matrix_to_float32_tensor(%Matrix{data: matrix_ref}, dims) do
1602+
{:ok, ref} = NIFs.matrix_to_float32_tensor(matrix_ref, dims)
1603+
{:ok, %Tensor{datatype: :tf_float, tensor: ref}}
1604+
end
1605+
15291606
end

0 commit comments

Comments
 (0)