Εξερεύνηση της τέχνης σε όλο τον πολιτισμό και της μεσαίας με γρήγορο, υπό όρους, k-πλησιέστερους γείτονες
Αυτό το άρθρο αποτελεί μια οδηγία για την εύρεση αντιστοιχιών μέσω των πλησιέστερων γειτόνων. Ρυθμίζετε κώδικα που επιτρέπει ερωτήματα που αφορούν πολιτισμούς και μέσα τέχνης που συγκεντρώνονται από το Μητροπολιτικό Μουσείο Τέχνης της Νέας Υόρκης και το Rijksmuseum στο Άμστερνταμ.
Προαπαιτούμενα στοιχεία
- Επισυνάψτε το σημειωματάριό σας σε ένα lakehouse. Στην αριστερή πλευρά, επιλέξτε Προσθήκη για να προσθέσετε μια υπάρχουσα λίμνη ή να δημιουργήσετε μια λίμνη.
Επισκόπηση του BallTree
Η δομή που λειτουργεί πίσω από το μοντέλο KNN είναι ένα BallTree, το οποίο είναι ένα επαναλαμβανόμενο δυαδικό δέντρο όπου κάθε κόμβος (ή "μπάλα") περιέχει ένα διαμέρισμα των σημείων δεδομένων στα οποία θα υποβληθούν ερωτήματα. Η δημιουργία ενός BallTree περιλαμβάνει την εκχώρηση σημείων δεδομένων στην "μπάλα" της οποίας το κέντρο βρίσκεται πιο κοντά (σε σχέση με μια συγκεκριμένη καθορισμένη δυνατότητα), με αποτέλεσμα μια δομή που επιτρέπει τη διέλευση τύπου δυαδικού δέντρου και προσφέρεται για την εύρεση του πλησιέστερου γείτονα k σε ένα φύλλο BallTree.
Ρύθμιση
Εισαγάγετε τις απαραίτητες βιβλιοθήκες Python και προετοιμάστε το σύνολο δεδομένων.
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()
Το σύνολο δεδομένων μας προέρχεται από έναν πίνακα που περιέχει πληροφορίες γραφικών έργων τέχνης από τα μουσεία Met και Rijks. Το σχήμα έχει ως εξής:
- id: Ένα μοναδικό αναγνωριστικό για ένα έργο τέχνης
- Δείγμα αναγνωριστικού met: 388395
- Αναγνωριστικό δείγματος Rijks: SK-A-2344
- Τίτλος: Τίτλος έργου τέχνης, όπως γράφτηκε στη βάση δεδομένων του μουσείου
- Καλλιτέχνης: Καλλιτέχνης έργων τέχνης, όπως γράφτηκε στη βάση δεδομένων του μουσείου
- Thumbnail_Url: Θέση μιας μικρογραφίας JPEG του έργου τέχνης
- Image_Url θέση μιας εικόνας του έργου τέχνης που φιλοξενείται στην ιστοσελίδα Met / Rijks
- Κουλτούρα: Κατηγορία πολιτισμού στην οποία εμπίπτει το έργο τέχνης
- Κατηγορίες δειγμάτων πολιτισμών: λατινοαμερικάνος, αιγύπτιος, κ.λπ.
- Ταξινόμηση: Κατηγορία μέσου κάτω από την οποία εμπίπτει το έργο τέχνης
- Δείγμα μεσαίων κατηγοριών: ξυλουργική, πίνακες ζωγραφικής κ.λπ.
- Museum_Page: Σύνδεση με το έργο τέχνης στην ιστοσελίδα met/Rijks
- Norm_Features: Ενσωμάτωση της εικόνας του κομματιού τέχνης
- Μουσείο: Καθορίζει από ποιο μουσείο προήλθε το κομμάτι
# 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"))
Ορισμός κατηγοριών για τις οποίες θα υποβληθούν ερωτήματα
Χρησιμοποιούνται δύο μοντέλα KNN: ένα για κουλτούρα και ένα για μεσαίο.
# 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
Δημιουργήστε μοντέλα ConditionalKNN για αμφότερες τις στήλες μεσαίου μεγέθους και κουλτούρας. κάθε μοντέλο λαμβάνει μια στήλη εξόδου, τη στήλη δυνατοτήτων (διανυσματικό δυνατότητας), τη στήλη τιμών (τιμές κελιών κάτω από τη στήλη εξόδου) και τη στήλη ετικέτας (την ποιότητα στην οποία εξαρτάται το αντίστοιχο KNN).
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)
)
Ορισμός μεθόδων αντιστοίχισης και απεικόνισης
Μετά την αρχική ρύθμιση του συνόλου δεδομένων και της κατηγορίας, προετοιμάστε μεθόδους που θα υποβάλλουν ερωτήματα και θα απεικονίσουν τα αποτελέσματα του KNN υπό όρους.
addMatches()
Η δημιουργεί ένα πλαίσιο δεδομένων με λίγες αντιστοιχίσεις ανά κατηγορία.
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()
Οι κλήσεις plot_img
για την απεικόνιση κορυφαίων αντιστοιχιών για κάθε κατηγορία σε ένα πλέγμα.
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())
Συνδυάστε τα όλα
Ορίστε test_all()
για να λάβετε τα δεδομένα, τα μοντέλα CKNN, τις τιμές αναγνωριστικού τέχνης στα οποία θα υποβάλετε ερώτημα και τη διαδρομή αρχείου στην οποία θα αποθηκεύσετε την απεικόνιση εξόδου. Τα μεσαία μοντέλα και τα μοντέλα κουλτούρας είχαν εκπαιδευτεί και φορτωθεί προηγουμένως.
# 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
Επίδειξη
Το ακόλουθο κελί εκτελεί ερωτήματα δέσμης στα επιθυμητά αναγνωριστικά εικόνας και ένα όνομα αρχείου για την αποθήκευση της απεικόνισης.
# sample query
result_df = test_all(small_df, medium_cknn, culture_cknn, selected_ids, root=".")