Jaa


Taiteen tutkiminen kulttuurin ja keskitason välillä nopeiden, ehdollisten, k-lähien naapureiden avulla

Tämä artikkeli toimii oppaana vastaavuuden löytämiseen lähimpien naapureiden kautta. Määrität koodin, joka sallii kyselyt, joihin liittyy kulttuureja ja taidevälineitä, jotka on kerätty Metropolitanin taidemuseosta Nyc:ssa ja Rijksmuseumista Amsterdamissa.

Edellytykset

  • Liitä muistikirjasi Lakehouseen. Valitse vasemmalla puolella Lisää lisätäksesi aiemmin luodun lakehousen tai luodaksesi lakehousen.

BallTreen yleiskatsaus

KNN-mallin taustalla toimiva rakenne on BallTree, joka on rekursiivinen binaaripuu, jossa jokainen solmu (eli "pallo") sisältää kyselyn kohdepisteiden osion. BallTreen rakentaminen edellyttää arvopisteiden määrittämistä "pallolle", jonka keskipistettä ne ovat lähimpänä (tietyn määritetyn ominaisuuden osalta), mikä johtaa rakenteeseen, joka sallii binaaripuun kaltaisen läpiviennin ja auttaa löytämään k:n lähimmät naapurit BallTree-lehdestä.

Asetusten määrittäminen

Tuo tarvittavat Python-kirjastot ja valmistele tietojoukko.

from synapse.ml.core.platform import *

if running_on_binder():
    from IPython import get_ipython
from pyspark.sql.types import BooleanType
from pyspark.sql.types import *
from pyspark.ml.feature import Normalizer
from pyspark.sql.functions import lit, array, array_contains, udf, col, struct
from synapse.ml.nn import ConditionalKNN, ConditionalKNNModel
from PIL import Image
from io import BytesIO

import requests
import numpy as np
import matplotlib.pyplot as plt
from pyspark.sql import SparkSession

# Bootstrap Spark Session
spark = SparkSession.builder.getOrCreate()

Tietojoukkomme on peräisin taulukosta, joka sisältää taideteostietoja sekä Met- että Rijks-museoista. Rakenne on seuraava:

  • id: Taideteoksen yksilöllinen tunnus
    • Met-mallitunnus: 388395
    • Malli Rijks-tunnus: SK-A-2344
  • Nimi: Taidekappaleen nimi, joka on kirjoitettu museon tietokannassa
  • Taiteilija: Taideteostaiteilija, museon tietokannassa kirjoitettuna
  • Thumbnail_Url: Taideteoksen JPEG-pikkukuvan sijainti
  • Image_Url Sijainti kuvasta, jota isännöidään Met/Rijksin verkkosivuilla
  • Kulttuuri: Kulttuuriluokka, johon taideteos kuuluu
    • Esimerkkikulttuuriluokat: latinalainen amerikkalainen, egyptiläinen jne.
  • Luokitus: Taideteoksen luokka
    • Keskikokoiset malliluokat: puutyöt, maalaukset jne.
  • Museum_Page: Linkki taideteokseen Met/Rijksin verkkosivustolla
  • Norm_Features: Taideteoskuvan upottaminen
  • Museo: Määrittää, mistä museosta teos on peräisin
# loads the dataset and the two trained CKNN models for querying by medium and culture
df = spark.read.parquet(
    "wasbs://publicwasb@mmlspark.blob.core.windows.net/met_and_rijks.parquet"
)
display(df.drop("Norm_Features"))

Määritä luokat, joissa kysely tehdään

Käytetään kahta KNN-mallia: yhtä maa-asetusta ja toista keskikokoa varten.

# mediums = ['prints', 'drawings', 'ceramics', 'textiles', 'paintings', "musical instruments","glass", 'accessories', 'photographs',  "metalwork",
#           "sculptures", "weapons", "stone", "precious", "paper", "woodwork", "leatherwork", "uncategorized"]

mediums = ["paintings", "glass", "ceramics"]

# cultures = ['african (general)', 'american', 'ancient american', 'ancient asian', 'ancient european', 'ancient middle-eastern', 'asian (general)',
#            'austrian', 'belgian', 'british', 'chinese', 'czech', 'dutch', 'egyptian']#, 'european (general)', 'french', 'german', 'greek',
#            'iranian', 'italian', 'japanese', 'latin american', 'middle eastern', 'roman', 'russian', 'south asian', 'southeast asian',
#            'spanish', 'swiss', 'various']

cultures = ["japanese", "american", "african (general)"]

# Uncomment the above for more robust and large scale searches!

classes = cultures + mediums

medium_set = set(mediums)
culture_set = set(cultures)
selected_ids = {"AK-RBK-17525-2", "AK-MAK-1204", "AK-RAK-2015-2-9"}

small_df = df.where(
    udf(
        lambda medium, culture, id_val: (medium in medium_set)
        or (culture in culture_set)
        or (id_val in selected_ids),
        BooleanType(),
    )("Classification", "Culture", "id")
)

small_df.count()

ConditionalKNN-mallien määrittäminen ja sovittaminen

Luo ConditionalKNN-malleja sekä keskikokoisille sarakkeille että maa-asetussarakkeille. kussakin mallissa on tulostarake, ominaisuussarake (ominaisuusvektori), arvot sarake (tulostarakkeen alla olevat soluarvot) ja otsikkosarake (laatu, jolle vastaava KNN on ehdotettu).

medium_cknn = (
    ConditionalKNN()
    .setOutputCol("Matches")
    .setFeaturesCol("Norm_Features")
    .setValuesCol("Thumbnail_Url")
    .setLabelCol("Classification")
    .fit(small_df)
)
culture_cknn = (
    ConditionalKNN()
    .setOutputCol("Matches")
    .setFeaturesCol("Norm_Features")
    .setValuesCol("Thumbnail_Url")
    .setLabelCol("Culture")
    .fit(small_df)
)

Menetelmien vastaavuuden määrittäminen ja visualisointi

Ensimmäisen tietojoukon ja luokan määrittämisen jälkeen valmistele menetelmät, jotka kyselevät ja visualisoivat ehdollisen KNN:n tuloksia.

addMatches() luo Dataframen, jossa on kourallinen otteluita luokkaa kohden.

def add_matches(classes, cknn, df):
    results = df
    for label in classes:
        results = cknn.transform(
            results.withColumn("conditioner", array(lit(label)))
        ).withColumnRenamed("Matches", "Matches_{}".format(label))
    return results

plot_urls() kutsuu plot_img visualisoimaan kunkin luokan parhaat vastaavuudet ruudukkoon.

def plot_img(axis, url, title):
    try:
        response = requests.get(url)
        img = Image.open(BytesIO(response.content)).convert("RGB")
        axis.imshow(img, aspect="equal")
    except:
        pass
    if title is not None:
        axis.set_title(title, fontsize=4)
    axis.axis("off")


def plot_urls(url_arr, titles, filename):
    nx, ny = url_arr.shape

    plt.figure(figsize=(nx * 5, ny * 5), dpi=1600)
    fig, axes = plt.subplots(ny, nx)

    # reshape required in the case of 1 image query
    if len(axes.shape) == 1:
        axes = axes.reshape(1, -1)

    for i in range(nx):
        for j in range(ny):
            if j == 0:
                plot_img(axes[j, i], url_arr[i, j], titles[i])
            else:
                plot_img(axes[j, i], url_arr[i, j], None)

    plt.savefig(filename, dpi=1600)  # saves the results as a PNG

    display(plt.show())

Kaikkien kokoaminen yhteen

Määritä test_all() , otetaanko tiedot, CKNN-mallit, kyselyn art id -arvot ja tiedostopolku, jolle tulosvisualisointi tallennetaan. Keskitaso- ja kulttuurimallit oli aiemmin harjoitettu ja ladattu.

# main method to test a particular dataset with two CKNN models and a set of art IDs, saving the result to filename.png


def test_all(data, cknn_medium, cknn_culture, test_ids, root):
    is_nice_obj = udf(lambda obj: obj in test_ids, BooleanType())
    test_df = data.where(is_nice_obj("id"))

    results_df_medium = add_matches(mediums, cknn_medium, test_df)
    results_df_culture = add_matches(cultures, cknn_culture, results_df_medium)

    results = results_df_culture.collect()

    original_urls = [row["Thumbnail_Url"] for row in results]

    culture_urls = [
        [row["Matches_{}".format(label)][0]["value"] for row in results]
        for label in cultures
    ]
    culture_url_arr = np.array([original_urls] + culture_urls)[:, :]
    plot_urls(culture_url_arr, ["Original"] + cultures, root + "matches_by_culture.png")

    medium_urls = [
        [row["Matches_{}".format(label)][0]["value"] for row in results]
        for label in mediums
    ]
    medium_url_arr = np.array([original_urls] + medium_urls)[:, :]
    plot_urls(medium_url_arr, ["Original"] + mediums, root + "matches_by_medium.png")

    return results_df_culture

Esittely

Seuraava solu suorittaa eriteltyjä kyselyitä, kun sille annetaan halutut kuvatunnukset ja tiedostonimi visualisoinnin tallentamiseksi.

# sample query
result_df = test_all(small_df, medium_cknn, culture_cknn, selected_ids, root=".")