Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
In dit artikel wordt het zoeken naar overeenkomsten beschreven via het algoritme k-dichtstbijzijnde buren. U bouwt codebronnen die query's mogelijk maken met culturen en mediums kunst die zijn samengesteld uit het Metropolitan Museum of Art in NYC en het Amsterdam Rijksmuseum.
Vereiste voorwaarden
- Een notitieblok dat is gekoppeld aan een lakehouse. Bezoek de gegevens in uw lakehouse met een notitieblok voor meer informatie.
Overzicht van de BallTree
Het k-NN-model is afhankelijk van de BallTree-gegevensstructuur . BallTree is een recursieve binaire structuur, waarbij elk knooppunt (of 'bal') een partitie of subset bevat van de gegevenspunten die u wilt opvragen. Als u een BallTree wilt bouwen, bepaalt u het balcentrum (op basis van een bepaalde opgegeven functie) die het dichtst bij elk gegevenspunt ligt. Wijs vervolgens elk gegevenspunt toe aan dat corresponderende dichtstbijzijnde 'bal'. Deze toewijzingen maken een structuur die binaire doorkruisingen mogelijk maakt en zichzelf leent voor het vinden van k-dichtstbijzijnde buren bij een BallTree-blad.
Configuratie
Importeer de benodigde Python-bibliotheken en bereid de gegevensset voor:
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()
De gegevensset is afkomstig uit een tabel met kunstwerkinformatie van zowel het Met Museum als het Rijksmuseum. De tabel heeft dit schema:
-
Id: Een unieke id voor elk specifiek kunstwerk
- Voorbeeld van met id: 388395
- Voorbeeld Rijks ID: SK-A-2344
- Titel: Titel van kunstwerk, zoals geschreven in de database van het museum
- Kunstenaar: Kunststukkunstenaar, zoals geschreven in de database van het museum
- Thumbnail_Url: Locatie van een JPEG-miniatuur van het kunstwerk
- Image_Url Url-locatie van de website van de afbeelding van het kunstwerk, gehost op de Website van Met/Rijks
-
Cultuur: Cultuurcategorie van het kunstwerk
- Voorbeeldcultuurcategorieën: Latijns-Amerikaan, Egyptisch, enz.
-
Classificatie: Gemiddelde categorie van het kunstwerk
- Voorbeeld medium categorieën: houtwerk, schilderijen, enz.
- Museum_Page: URL-koppeling naar het kunstwerk, gehost op de website van Met/Rijks
- Norm_Features: Insluiten van de afbeelding van het kunstwerk
- Museum: Het museum dat het echte kunstwerk host
# loads the dataset and the two trained conditional k-NN 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"))
Definieer de categorieën om de query te maken
Gebruik twee k-NN-modellen: één voor cultuur en één voor medium:
# 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()
Voorwaardelijke k-NN-modellen definiëren en aanpassen
Maak voorwaardelijke k-NN-modellen voor zowel de medium- als cultuurkolommen. Elk model neemt
- een uitvoerkolom
- een functiekolom (functievector)
- een waardenkolom (celwaarden onder de uitvoerkolom)
- een labelkolom (de kwaliteit waarop de respectieve k-NN is geconditioneerd)
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)
)
Overeenkomende methoden definiëren en visualiseren
Nadat de eerste gegevensset en categorie zijn ingesteld, bereidt u de methoden voor om de resultaten van de voorwaardelijke k-NN op te vragen en te visualiseren:
addMatches()
maakt een Dataframe met een handvol overeenkomsten per categorie:
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()
aanroepen plot_img
om de belangrijkste overeenkomsten voor elke categorie in een raster te visualiseren:
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())
Alles samenbrengen
Om mee te nemen
- de gegevens
- de voorwaardelijke k-NN-modellen
- de art ID-waarden waarop een query moet worden uitgevoerd
- het bestandspad waarin de uitvoervisualisatie wordt opgeslagen
een functie definiëren die wordt aangeroepen test_all()
De medium- en cultuurmodellen werden eerder getraind en geladen.
# main method to test a particular dataset with two conditional k-NN 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
Demo
In de volgende cel worden batchquery's uitgevoerd op basis van de gewenste afbeeldings-id's en een bestandsnaam om de visualisatie op te slaan.
# sample query
result_df = test_all(small_df, medium_cknn, culture_cknn, selected_ids, root=".")