Close Menu
    Trending
    • Implementing IBCS rules in Power BI
    • What comes next for AI copyright lawsuits?
    • Why PDF Extraction Still Feels LikeHack
    • GenAI Will Fuel People’s Jobs, Not Replace Them. Here’s Why
    • Millions of websites to get ‘game-changing’ AI bot blocker
    • I Worked Through Labor, My Wedding and Burnout — For What?
    • Cloudflare will now block AI bots from crawling its clients’ websites by default
    • 🚗 Predicting Car Purchase Amounts with Neural Networks in Keras (with Code & Dataset) | by Smruti Ranjan Nayak | Jul, 2025
    AIBS News
    • Home
    • Artificial Intelligence
    • Machine Learning
    • AI Technology
    • Data Science
    • More
      • Technology
      • Business
    AIBS News
    Home»Artificial Intelligence»LyRec: A Song Recommender That Reads Between the Lyrics 🎶 | by Sujan Dutta | Jan, 2025
    Artificial Intelligence

    LyRec: A Song Recommender That Reads Between the Lyrics 🎶 | by Sujan Dutta | Jan, 2025

    Team_AIBS NewsBy Team_AIBS NewsJanuary 21, 2025No Comments6 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Telegram Email
    Share
    Facebook Twitter LinkedIn Pinterest Email


    Dataset

    In fact, the very first thing I wanted was a music lyrics dataset. Thankfully, I discovered one on Kaggle! This dataset is below a Artistic Commons (CC0: Public Area) license.

    This dataset accommodates about 60K music lyrics together with the title and artist identify. I do know 60K won’t cowl all of the songs you like, however I believe it’s an excellent start line for LyRec.

    songs_df = pd.read_csv(f"{root_dir}/spotify_millsongdata.csv")
    songs_df = songs_df.drop(columns=["link"])
    songs_df["song_id"] = songs_df.index + 1

    I didn’t have to carry out any pre-processing on this information. I simply eliminated the hyperlink column and added an ID for every music.

    Fashions

    I wanted to pick two LLMs: One for computing the embeddings and one other for producing the music summaries. Choosing the proper LLM in your activity could also be somewhat tough due to the sheer variety of them! It’s a good suggestion to have a look at the leaderboard to search out the present greatest ones. For the embedding mannequin, I checked the MTEB leaderboard hosted by HuggingFace.

    I used to be searching for a smaller mannequin (clearly!) with out compromising an excessive amount of accuracy; therefore, I made a decision on GTE-Qwen2-1.5B-Instruct.

    from sentence_transformers import SentenceTransformer
    import torch

    mannequin = SentenceTransformer(
    "Alibaba-NLP/gte-Qwen2-1.5B-instruct",
    model_kwargs={"torch_dtype": torch.float16}
    )

    For the summarizer, I simply wanted a sufficiently small instruction following LLM, so I went with Gemma-2–2b-It. In my expertise, it’s the most effective small fashions as of now.

    import torch
    from transformers import pipeline

    pipe = pipeline(
    "text-generation",
    mannequin="google/gemma-2-2b-it",
    model_kwargs={"torch_dtype": torch.bfloat16},
    system="cuda",
    )

    Pre-computing the Embeddings

    Computing the lyrics embeddings was fairly simple. I simply used the .encode(…) methodology with a batch_size of 32 for quicker processing.

    song_lyrics = songs_df["text"].values

    lyrics_embeddings = mannequin.encode(
    song_lyrics,
    batch_size=32,
    show_progress_bar=True
    )

    np.save(f"{root_dir}/60k_song_lyrics_embeddings.npy", lyrics_embeddings)

    At this level, I saved these embeddings in a .npy file. I might have used a extra structured format, however it did the job for me.

    Coming to the abstract embeddings, I first wanted to generate the summaries. I had to make sure that the abstract captured the emotion and the music’s theme whereas not being too prolonged. So, I got here up with the next immediate for Gemma-2.

    You might be an skilled music summarizer. 
    You can be given the total lyrics to a music.
    Your activity is to jot down a concise, cohesive abstract that
    captures the central emotion, overarching theme, and
    narrative arc of the music in 150 phrases.

    {music lyrics}

    Right here’s the code snippet for abstract era. For simplicity, the next reveals a sequential processing. I’ve included the batch-processing model within the GitHub repo.

    def get_summary(song_lyrics):
    messages = [
    {"role": "user",
    "content": f'''You are an expert song summarizer.
    You will be given the full lyrics to a song.
    Your task is to write a concise, cohesive summary that
    captures the central emotion, overarching theme, and
    narrative arc of the song in 150 words.nn{song_lyrics}'''},
    ]

    outputs = pipe(messages, max_new_tokens=256)
    assistant_response = outputs[0]["generated_text"][-1]["content"].strip()
    return assistant_response

    songs_df["summary"] = songs_df["text"].progress_apply(get_description)

    Unsurprisingly, this step took essentially the most time. Fortunately, this must be completed solely as soon as, and naturally, after we wish to replace the database with new songs.

    Then, I computed and saved the embedding identical to the final time.

    song_summary = songs_df["summary"].values

    summary_embeddings = mannequin.encode(
    song_summary,
    batch_size=32,
    show_progress_bar=True
    )

    np.save(f"{root_dir}/60k_song_summary_embeddings.npy", summary_embeddings)

    Vector Search

    With the embeddings in place, it was time to implement the semantic search primarily based on embedding similarity. There are a number of superior open-source vector databases out there for this job. I made a decision to make use of a easy one known as FAISS (Fb AI Similarity Search). It simply takes two traces so as to add the embeddings into the database. First, we create a FAISS index. Right here, we have to point out the similarity metric you wish to make the most of for looking out and the dimension of the vectors. I used the dot product (interior product) because the similarity measure. Then, we add the embeddings to the index.

    Observe: Our database is sufficiently small to do an exhaustive search utilizing dot product. For bigger databases, it’s really helpful to carry out an approximate nearest neighbor (ANN) search. FAISS has help for that.

    import faiss

    lyrics_embeddings = np.load(f"{root_dir}/60k_song_lyrics_embeddings.npy")
    lyrics_index = faiss.IndexFlatIP(lyrics_embeddings.form[1])
    lyrics_index.add(lyrics_embeddings.astype(np.float32))

    summary_embeddings = np.load(f"{root_dir}/60k_song_summary_embeddings.npy")
    summary_index = faiss.IndexFlatIP(summary_embeddings.form[1])
    summary_index.add(summary_embeddings.astype(np.float32))

    To seek out essentially the most related songs given a question, we first have to generate the question embedding after which name the .search(…) methodology on the index. Beneath the hood, this methodology computes the similarity between the question and each entry in our database and returns the highest ok entries and the corresponding scores. Right here’s the code performing a semantic search on lyrics embeddings.

    query_lyrics = 'Think about the final music you fell in love with'
    query_embedding = mannequin.encode(f'''Instruct: Given the lyrics,
    retrieve related songsnQuery: {query_lyrics}''')
    query_embedding = query_embedding.reshape(1, -1).astype(np.float32)
    lyrics_scores, lyrics_ids = lyrics_index.search(query_embedding, 10)

    Discover that I added a easy immediate within the question. That is really helpful for this mannequin. The identical applies to the abstract embeddings.

    query_description = 'Describe the kind of music you wanna hearken to'
    query_embedding = mannequin.encode(f'''Given an outline,
    retrieve related songsnQuery: {query_description}''')
    query_embedding = query_embedding.reshape(1, -1).astype(np.float32)
    summary_scores, summary_ids = summary_index.search(query_embedding, ok)

    Professional tip: How do you do a sanity verify?
    Simply put any entry from the database within the question and see if the search returns the identical because the top-scoring entry!

    Implementing the Options

    At this stage, I had the constructing blocks of LyRec. Now, it was the time to place these collectively. Keep in mind the three objectives I set to start with? Right here’s how I applied these.

    To maintain issues tidy, I created a category named LyRec that might have a way for every function. The primary two options are fairly simple to implement.

    The tactic .get_songs_with_similar_lyrics(…) takes a music (lyrics) and an entire quantity ok as enter and returns an inventory of ok most related songs primarily based on the lyrics similarity. Every aspect within the listing is a dictionary containing the artist’s identify, music title, and lyrics.

    Equally, .get_songs_with_similar_description(…) takes a free-form textual content and an entire quantity ok as enter and returns an inventory of ok most related songs primarily based on the outline.

    Right here’s the related code snippet.

    class LyRec:
    def __init__(self, songs_df, lyrics_index, summary_index, embedding_model):
    self.songs_df = songs_df
    self.lyrics_index = lyrics_index
    self.summary_index = summary_index
    self.embedding_model = embedding_model

    def get_records_from_id(self, song_ids):
    songs = []
    for _id in song_ids:
    songs.lengthen(self.songs_df[self.songs_df["song_id"]==_id+1].to_dict(orient='information'))
    return songs

    def get_songs_with_similar_lyrics(self, query_lyrics, ok=10):
    query_embedding = self.embedding_model.encode(
    f"Instruct: Given the lyrics, retrieve related songsn Question: {query_lyrics}"
    ).reshape(1, -1).astype(np.float32)

    scores, song_ids = self.lyrics_index.search(query_embedding, ok)
    return self.get_records_from_id(song_ids[0])

    def get_songs_with_similar_description(self, query_description, ok=10):
    query_embedding = self.embedding_model.encode(
    f"Instruct: Given an outline, retrieve related songsn Question: {query_description}"
    ).reshape(1, -1).astype(np.float32)

    scores, song_ids = self.summary_index.search(query_embedding, ok)
    return self.get_records_from_id(song_ids[0])

    The ultimate function was somewhat tough to implement. Recall that we have to first retrieve the highest songs primarily based on lyrics after which re-rank them primarily based on the textual description. The primary retrieval was simple. For the second, we solely want to contemplate the top-scoring songs. I made a decision to create a brief FAISS index with the highest songs after which seek for the songs with the very best abstract similarity scores. Right here’s my implementation.

    def get_songs_with_similar_lyrics_and_description(self, query_lyrics, query_description, ok=10):
    query_lyrics_embedding = self.embedding_model.encode(
    f"Instruct: Given the lyrics, retrieve related songsn Question: {query_lyrics}"
    ).reshape(1, -1).astype(np.float32)

    scores, song_ids = self.lyrics_index.search(query_lyrics_embedding, 500)
    top_k_indices = song_ids[0]

    summary_candidates = []
    for idx in top_k_indices:
    emb = self.summary_index.reconstruct(int(idx))
    summary_candidates.append(emb)
    summary_candidates = np.array(summary_candidates, dtype=np.float32)

    temp_index = faiss.IndexFlatIP(summary_candidates.form[1])
    temp_index.add(summary_candidates)

    query_description_embedding = self.embedding_model.encode(
    f"Instruct: Given an outline, retrieve related songsn Question: {query_description}"
    ).reshape(1, -1).astype(np.float32)

    scores, temp_ids = temp_index.search(query_description_embedding, ok)
    final_song_ids = [top_k_indices[i] for i in temp_ids[0]]

    return self.get_records_from_id(final_song_ids)

    Viola! Lastly, LyRec is prepared. You’ll find the whole implementation on this repo. Please depart a star when you discover this beneficial! 😃



    Source link

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Previous ArticleWeek 1: Generative AI Landscape. Last week was the first official week… | by Jackson Aaron | Jan, 2025
    Next Article Employers Would Rather Hire AI, Robots Than Recent Grads
    Team_AIBS News
    • Website

    Related Posts

    Artificial Intelligence

    Implementing IBCS rules in Power BI

    July 1, 2025
    Artificial Intelligence

    Become a Better Data Scientist with These Prompt Engineering Tips and Tricks

    July 1, 2025
    Artificial Intelligence

    Lessons Learned After 6.5 Years Of Machine Learning

    July 1, 2025
    Add A Comment
    Leave A Reply Cancel Reply

    Top Posts

    Implementing IBCS rules in Power BI

    July 1, 2025

    I Tried Buying a Car Through Amazon: Here Are the Pros, Cons

    December 10, 2024

    Amazon and eBay to pay ‘fair share’ for e-waste recycling

    December 10, 2024

    Artificial Intelligence Concerns & Predictions For 2025

    December 10, 2024

    Barbara Corcoran: Entrepreneurs Must ‘Embrace Change’

    December 10, 2024
    Categories
    • AI Technology
    • Artificial Intelligence
    • Business
    • Data Science
    • Machine Learning
    • Technology
    Most Popular

    Part 1: Is the Replica Really You? | by Excel Akushie | Apr, 2025

    April 11, 2025

    Vulcan Robots: Amazon’s Stowing Game-Changer

    May 7, 2025

    Robert W. McChesney, Who Warned of Corporate Media Control, Dies at 72

    April 8, 2025
    Our Picks

    Implementing IBCS rules in Power BI

    July 1, 2025

    What comes next for AI copyright lawsuits?

    July 1, 2025

    Why PDF Extraction Still Feels LikeHack

    July 1, 2025
    Categories
    • AI Technology
    • Artificial Intelligence
    • Business
    • Data Science
    • Machine Learning
    • Technology
    • Privacy Policy
    • Disclaimer
    • Terms and Conditions
    • About us
    • Contact us
    Copyright © 2024 Aibsnews.comAll Rights Reserved.

    Type above and press Enter to search. Press Esc to cancel.