Можем ли мы выполнять обработку изображений с помощью Palantir Foundry?

Я изучаю платформу Palantir Foundry, и, похоже, у нее есть масса вариантов для прямоугольных или структурированных данных. У кого-нибудь есть опыт работы с неструктурированными большими данными на платформе Foundry? Как мы можем использовать Foundry для анализа изображений?


person conscious-coder    schedule 19.05.2020    source источник


Ответы (4)


Хотя большинство примеров дается с использованием табличных данных, на самом деле во многих случаях используется литейный цех для обработки как неструктурированных, так и полуструктурированных данных. Вы должны думать о наборе данных как о контейнере файлов с API для доступа и обработки файлов. используя API уровня файлов, вы можете получить доступ к файлам в наборе данных и обрабатывать их по своему усмотрению. Если эти файлы являются изображениями, вы можете извлечь информацию из файла и использовать ее по своему усмотрению. общий вариант использования — иметь PDF-файлы в виде файлов в наборе данных и извлекать информацию из PDF-файла и сохранять ее в виде табличной информации, чтобы вы могли выполнять как структурированный, так и неструктурированный поиск по ней.

вот пример доступа к файлу для извлечения PDF:

import com.palantir.transforms.lang.java.api.Compute;
import com.palantir.transforms.lang.java.api.FoundryInput;
import com.palantir.transforms.lang.java.api.FoundryOutput;
import com.palantir.transforms.lang.java.api.Input;
import com.palantir.transforms.lang.java.api.Output;
import com.palantir.util.syntacticpath.Paths;
import com.google.common.collect.AbstractIterator;
import com.palantir.spark.binarystream.data.PortableFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.UUID;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Encoders;
import org.apache.spark.sql.Row;
import org.apache.pdfbox.pdmodel.PDDocument; 
import org.apache.pdfbox.text.PDFTextStripper;


public final class ExtractPDFText {

    private static String pdf_source_files_rid = "SOME RID";
    private static String dataProxyPath = "/foundry-data-proxy/api/dataproxy/datasets/";
    private static String datasetViewPath = "/views/master/";

    @Compute 
    public void compute(
        @Input("/Base/project_name/treasury_pdf_docs") FoundryInput pdfFiles, 
        @Output("/Base/project_name/clean/pdf_text_extracted") FoundryOutput output) throws IOException {

        Dataset<PortableFile> filesDataset = pdfFiles.asFiles().getFileSystem().filesAsDataset(); 

        Dataset<String> mappedDataset = filesDataset.flatMap((FlatMapFunction<PortableFile, String>) portableFile -> 
            portableFile.convertToIterator(inputStream -> {

                String pdfFileName = portableFile.getLogicalPath().getFileName().toString();
                return new PDFIterator(inputStream, pdfFileName);
            }), Encoders.STRING());

        Dataset<Row> dataset = filesDataset
                .sparkSession()
                .read()
                .option("inferSchema", "false")
                .json(mappedDataset);

        output.getDataFrameWriter(dataset).write();
    }

    private static final class PDFIterator extends AbstractIterator<String> {
        private InputStream inputStream;
        private String pdfFileName;
        private boolean done;

        PDFIterator(InputStream inputStream, String pdfFileName) throws IOException {
            this.inputStream = inputStream;
            this.pdfFileName = pdfFileName;
            this.done = false;
        }

        @Override
        protected String computeNext() {
            if (done) {
                return endOfData();
            }

            try {
                String objectId = pdfFileName;
                String appUrl = dataProxyPath.concat(pdf_source_files_rid).concat(datasetViewPath).concat(pdfFileName);
                PDDocument document = PDDocument.load(inputStream);

                PDFTextStripper pdfStripper = new PDFTextStripper();

                String text = pdfStripper.getText(document);
                String strippedText = text.replace("\"", "'").replace("\\", "").replace("“", "'").replace("”", "'").replace("\n", "").replace("\r", "");

                done = true;
                return "{\"id\": \"" + String.valueOf(UUID.randomUUID()) + "\", \"file_name\": \"" + pdfFileName + "\", \"app_url\": \"" + appUrl + "\", \"object_id\": \"" + objectId + "\", \"text\": \"" + strippedText + "\"}\n";
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
} 
person Eran Witkon    schedule 02.10.2020

Действительно, вы можете выполнять анализ изображений в Foundry, поскольку у вас есть доступ к файлам и вы можете использовать произвольные библиотеки (например, Pillow или Skimage для Python). Это можно сделать в масштабе, а также можно распараллелить.

Простой фрагмент Python для объединения двух изображений должен помочь вам начать работу:

from transforms.api import transform, Input, Output
from PIL import Image


@transform(
    output=Output("/processed/stitched_images"),
    raw=Input("/raw/images"),
    image_meta=Input("/processed/image_meta")
)
def my_compute_function(raw, image_meta, output, ctx):

    image_meta = image_meta.dataframe()

    def stitch_images(clone):
        left = clone["left_file_name"]
        right = clone["right_file_name"]
        image_name = clone["image_name"]
        with raw.filesystem().open(left, mode="rb") as left_file:
            with raw.filesystem().open(right, mode="rb") as right_file:
                with output.filesystem().open(image_name, 'wb') as out_file:

                    left_image = Image.open(left_file)
                    right_image = Image.open(right_file)

                    (width, height) = left_image.size

                    result_width = width * 2
                    result_height = height
                    result = Image.new('RGB', (result_width, result_height))

                    result.paste(im=left_image, box=(0, 0))
                    result.paste(im=right_image, box=(height, 0))

                    result.save(out_file, format='jpeg', quality=90)

    image_meta.rdd.foreach(stitch_images)

Набор данных image_meta — это просто набор данных с двумя именами файлов в строке. Чтобы извлечь имена файлов из набора данных необработанных файлов, вы можете использовать что-то вроде:

@transform(
    output=Output("/processed/image_meta"),
    raw=Input("/raw/images"),
)
def my_compute_function(raw, output, ctx):

    file_names = [(file_status.path, 1) for file_status in raw.filesystem().ls(glob="*.jpg")]

    # create and write spark dataframe based on array
person gergocsegzi    schedule 30.10.2020

Как уже упоминалось, Palantir-Foundry фокусируется на табличных данных и в настоящее время не предоставляет доступ к графическому процессору или другому блоку тензорной обработки. Таким образом, делать что-либо интенсивное, например преобразование БПФ или глубокое обучение, в лучшем случае не рекомендуется, а в худшем — совершенно невозможно.

При этом вы можете загружать файлы изображений в узлы набора данных для доступа на чтение/запись. Вы также можете сохранить их двоичную информацию как тип BLOB-объекта в Dataframe, чтобы хранить файлы в заданном поле записи. Учитывая, что на платформе доступно множество библиотек для обработки изображений Python и матричных математических библиотек, а также учитывая, что пакеты библиотек также можно загружать на платформу вручную через приложение Code Repo, вполне возможно, что кто-то может использовать простые манипуляции. в несколько больших масштабах, если он не был слишком сложным или требовательным к памяти.

person Jeremy David Gamet    schedule 16.04.2021

Обратите внимание, что Foundry, похоже, в настоящее время не поддерживает GPU, поэтому, если вы думаете об обработке изображений на основе глубокого обучения, это будет довольно медленно на процессорах.

person nicornk    schedule 06.11.2020