CoolFace
Apppublic

neuralcomputation/batik

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
explore.py340 linesDownload Raw Back to root
1import streamlit as st2import plotly.express as px3import numpy as np4import pandas as pd5import torch6from utils.mp4Io import mp4Io_reader7from utils.seqIo import seqIo_reader8import pandas as pd9from PIL import Image10from pathlib import Path11from transformers import AutoProcessor, AutoModel12from tempfile import NamedTemporaryFile13from tqdm import tqdm14from utils.utils import create_embeddings_csv_io, process_dataset_in_mem, generate_embeddings_stream_io15from get_llava_response import get_llava_response, load_llava_checkpoint_hf16from sklearn.manifold import TSNE17from openai import OpenAI18import cv219import base6420from hdbscan import HDBSCAN, all_points_membership_vectors21import random22 23# --server.maxUploadSize 300024REPO_NAME = 'ncoria/llava-lora-vicuna-clip-5-epochs-merge'25 26def load_llava_model():27    return load_llava_checkpoint_hf(REPO_NAME)28 29def get_unique_labels(label_list: list[str]):30    label_set = set()31    for label in label_list:32        individual_labels = label.split('||')33        for individual_label in individual_labels:34            label_set.add(individual_label)35    return list(label_set)36 37SYSTEM_PROMPT = """You are a researcher studying mice interactions from videos of the inside of a resident 38intruder box where there is either just the resident mouse (the black one) or the resident and the intruder mouse (the white one).39Your job is to answer questions about the behavior of the mice in the image given the context that each image is a frame of a continuous video.40Thus, you should use the visual information about the mice in the image to try to provide a detailed behavioral description of the image."""41 42@st.cache_resource43def get_io_reader(uploaded_file):44    if uploaded_file.name[-3:]=='seq':45        with NamedTemporaryFile(suffix="seq", delete=False) as temp:46            temp.write(uploaded_file.getvalue())47            sr = seqIo_reader(temp.name)48    else:49        with NamedTemporaryFile(suffix="mp4", delete=False) as temp:50            temp.write(uploaded_file.getvalue())51            sr = mp4Io_reader(temp.name)52    return sr53 54def get_image(sr, frame_no: int):55    image, _ = sr.getFrame(frame_no)56    return image57 58@st.cache_data59def get_2d_embedding(embeddings: pd.DataFrame):60    tsne = TSNE(n_jobs=4, n_components=2, random_state=42, perplexity=50)61    embedding_2d = tsne.fit_transform(np.array(embeddings))62    return embedding_2d63 64HDBSCAN_PARAMS = {65    'min_samples': 166}67 68@st.cache_data69def hdbscan_classification(umap_embeddings, embeddings_2d, cluster_range):70    max_num_clusters = -np.infty71    num_clusters = []72    min_cluster_size = np.linspace(cluster_range[0], cluster_range[1], 4)73    for min_c in min_cluster_size:74        learned_hierarchy = HDBSCAN(75            prediction_data=True, min_cluster_size=int(round(min_c * 0.01 *umap_embeddings.shape[0])),76            cluster_selection_method='leaf' ,77            **HDBSCAN_PARAMS).fit(umap_embeddings)78        num_clusters.append(len(np.unique(learned_hierarchy.labels_)))79        if num_clusters[-1] > max_num_clusters:80            max_num_clusters = num_clusters[-1]81            retained_hierarchy = learned_hierarchy82    assignments = retained_hierarchy.labels_83    assign_prob = all_points_membership_vectors(retained_hierarchy)84    soft_assignments = np.argmax(assign_prob, axis=1)85    retained_hierarchy.fit(embeddings_2d)86    return retained_hierarchy, assignments, assign_prob, soft_assignments87 88def upload_image(frame: np.ndarray):89    """returns the file ID."""90    _, encoded_image = cv2.imencode('.png', frame)91    return base64.b64encode(encoded_image.tobytes()).decode('utf-8')92 93def ask_question_with_image_gpt(file_id, system_prompt, question, api_key):94    """Asks a question about the uploaded image."""95    client = OpenAI(api_key=api_key)96 97    if file_id != None:98        response = client.chat.completions.create(99            model="gpt-4o",100            messages=[101                {"role": "system", "content": system_prompt},102                {"role": "user", "content": [103                    {"type": "text", "text": question},104                    {"type": "image_url",  "image_url": {"url": f"data:image/jpg:base64, {file_id}"}}]105                }106            ]107        )108    else:109        response = client.chat.completions.create(110            model="gpt-4o",111            messages=[112                {"role": "system", "content": system_prompt},113                {"role": "user", "content": question}114            ]115        )116    return response.choices[0].message.content117 118def ask_question_with_image_llava(image, system_prompt, question,119                                  tokenizer, model, image_processor):120    outputs = get_llava_response([question],121                                 [image],122                                 system_prompt,123                                 tokenizer,124                                 model,125                                 image_processor,126                                 REPO_NAME,127                                 stream_output=False)128    return outputs[0]129 130def ask_summary_question(image_array, label_array, api_key):131    # load llava model132    with st.spinner("Loading LLaVA model. This can take 10 to 30 minutes. Please wait..."):133        tokenizer, model, image_processor = load_llava_model()134 135    # global variable136    system_prompt = SYSTEM_PROMPT137 138    # collect responses139    responses = []140 141    # create progress bar142    j = 0143    pbar_text = lambda j: f'Creating llava response {j}/{len(label_array)}.'144    pbar = st.progress(0, text=pbar_text(0))145 146    for i, image in enumerate(image_array):147        label = label_array[i]148        question = f"The frame is annotated by a human observer with the label: {label}. Give evidence for this label using the posture of the mice and their current behavior. "149        question += "Also, designate a behavioral subtype of the given label that describes the current social interaction based on what you see about the posture of the mice and "\150                    "how they are positioned with respect to each other. Usually, the body parts (i.e., tail, genitals, face, body, ears, paws)"\151                    "of the mice that are closest to each other will give some clue. Please limit behavioral subtype to a 1-4 word phrase. limit your response to 4 sentences."152        response = ask_question_with_image_llava(image, system_prompt, question,153                                                 tokenizer, model, image_processor)154        responses.append(response)155        # update progress bar156        j += 1157        pbar.progress(j/len(label_array), pbar_text(j))158 159    system_prompt_summarize = "You are a researcher studying mice interactions from videos of the inside of a resident "\160                            "intruder box where there is either just the resident mouse (the black one) or the resident and the intruder mouse (the white one). "\161                            "You will be given a question about a list of descriptions from frames of these videos. "\162                            "Your job is to answer the question by focusing on the behaviors of the mice and their postures "\163                            "as well as any other aspects of the descriptions that may be relevant to the class label associated with them"164    user_prompt_summarize = "Here are several descriptions of individual frames from a mouse behavior video. Please summarize these descriptions and provide a suggestion for a "\165                            "behavior label which captures what is described in the descriptions: \n\n"166    user_prompt_summarize = user_prompt_summarize + '\n'.join(responses)167    summary_response = ask_question_with_image_gpt(None, system_prompt_summarize, user_prompt_summarize, api_key)168    return summary_response169 170if "embeddings_df" not in st.session_state:171    st.session_state.embeddings_df = None172 173st.title('batik: behavior discovery and LLM-based interpretation')174 175api_key = st.text_input("OpenAI API Key:","")176 177st.subheader("generate or import embeddings")178 179st.text("Upload files to generate embeddings.")180with st.form('embedding_generation_settings'):181    seq_file = st.file_uploader("Choose a video file", type=['seq', 'mp4'])182    annot_files = st.file_uploader("Choose an annotation File", type=['annot','csv'], accept_multiple_files=True)183    downsample_rate = st.number_input('Downsample Rate',value=4)184    submit_embed_settings = st.form_submit_button('Create Embeddings', type='secondary')185 186st.markdown("**(Optional)** Upload embeddings.")187embeddings_csv = st.file_uploader("Choose a .csv File", type=['csv'])188 189if submit_embed_settings and seq_file is not None and annot_files is not None:190    video_embeddings, video_frames = generate_embeddings_stream_io([seq_file],191                                                                "SLIP",192                                                                downsample_rate,193                                                                False)194    195    fnames = [seq_file.name]196    embeddings_df = create_embeddings_csv_io(out="file",197                                fnames=fnames,198                                embeddings=video_embeddings,199                                frames=video_frames,200                                annotations=[annot_files],201                                test_fnames=None,202                                views=None,203                                conditions=None,204                                downsample_rate=downsample_rate)205    st.session_state.embeddings_df = embeddings_df206elif embeddings_csv is not None:207    embeddings_df = pd.read_csv(embeddings_csv)208    st.session_state.embeddings_df = embeddings_df209else:210    st.text('Please upload file(s).')211 212st.divider()213st.subheader("provide video file if not yet already provided")214 215uploaded_file = st.file_uploader("Choose a video file", type=['seq', 'mp4'])216 217st.divider()218if st.session_state.embeddings_df is not None and (uploaded_file is not None or seq_file is not None):219    if seq_file is not None:220        uploaded_file = seq_file221    io_reader = get_io_reader(uploaded_file)222    print("CONVERTED SEQ")223    label_list = st.session_state.embeddings_df['Label'].to_list()224    unique_label_list = get_unique_labels(label_list)225    print(f"unique_labels: {unique_label_list}")226    #unique_label_list = ['check_genital', 'wiggle', 'lordose', 'stay', 'turn', 'top_up', 'dart', 'sniff', 'approach', 'into_male_cage']227    #unique_label_list = ['into_male_cage', 'intromission', 'male_sniff', 'mount']228    kwargs = {'embeddings_df' : st.session_state.embeddings_df, 229                'specified_classes' : unique_label_list,230                'classes_to_remove' : None,231                'max_class_size' : None,232                'animal_state' : None,233                'view' : None,234                'shuffle_data' : False,235                'test_videos' : None}236    train_embeds, train_labels, train_images, _, _, _ = process_dataset_in_mem(**kwargs)237    print("PROCESSED DATASET")238    if "Images" in st.session_state.embeddings_df.keys():239        train_images = [i for i in range(len(train_images))]240    embedding_2d = get_2d_embedding(train_embeds)241else:242    st.text('Please generate embeddings and provide video file.')243    print("GOT 2D EMBEDS")244 245if uploaded_file is not None and st.session_state.embeddings_df is not None:246    st.subheader("t-SNE Projection")247    option = st.selectbox(248        "Select Color Option",249        ("By Label", "By Time", "By Cluster")250    )251    if embedding_2d is not None:252        if option is not None:253            if option == "By Label":254                color = 'label'255            elif option == "By Time":256                color = 'frame_no'257            else:258                color = 'cluster_label'259            260            if option in ["By Label", "By Time"]:261                edf = pd.DataFrame(embedding_2d,columns=['tsne_dim_1', 'tsne_dim_2'])262                edf.insert(2,'frame_no',np.array([int(x) for x in train_images]))263                edf.insert(3, 'label', train_labels)264                fig = px.scatter(265                    edf,266                    x="tsne_dim_1",267                    y="tsne_dim_2",268                    color=color,269                    hover_data=["frame_no"],270                    color_discrete_sequence=px.colors.qualitative.Dark24271                )272            else:273                r, _, _, _ = hdbscan_classification(train_embeds, embedding_2d, [4, 6])274                edf = pd.DataFrame(embedding_2d,columns=['tsne_dim_1', 'tsne_dim_2'])275                edf.insert(2,'frame_no',np.array([int(x) for x in train_images]))276                edf.insert(3, 'label', train_labels)277                edf.insert(4, 'cluster_label', [str(c_id) for c_id in r.labels_.tolist()])278                fig = px.scatter(279                    edf,280                    x="tsne_dim_1",281                    y="tsne_dim_2",282                    color=color,283                    hover_data=["frame_no"],284                    color_discrete_sequence=px.colors.qualitative.Dark24285                )286 287            event = st.plotly_chart(fig, key="df", on_select="rerun")288        else:289            st.text("No Color Option Selected")290    else:291        st.text('No Embeddings Loaded')292 293    event_dict = event.selection294 295    if event_dict is not None:296        custom_data = []297        for point in event_dict['points']:298            data = point["customdata"][0]299            custom_data.append(int(data))300        301        if len(custom_data) > 10:302            custom_data = random.sample(custom_data, 10)303        if len(custom_data) > 1:304            col_1, col_2 = st.columns(2)305            with col_1:306                for frame_no in custom_data[::2]:307                    st.image(get_image(io_reader, frame_no))308                    st.caption(f"Frame {frame_no}, {train_labels[frame_no]}")309            with col_2:310                for frame_no in custom_data[1::2]:311                    st.image(get_image(io_reader, frame_no))312                    st.caption(f"Frame {frame_no}, {train_labels[frame_no]}")313        elif len(custom_data) == 1:314            frame_no = custom_data[0]315            st.image(get_image(io_reader, frame_no))316            st.caption(f"Frame {frame_no}, {train_labels[frame_no]}")317        else:318            st.text('No Points Selected')319        320        if len(custom_data) == 1:321            frame_no = custom_data[0]322            image = get_image(io_reader, frame_no)323            system_prompt = SYSTEM_PROMPT324            label = train_labels[frame_no]325            question = f"The frame is annotated by a human observer with the label: {label}. Give evidence for this label using the posture of the mice and their current behavior. "\326                        "Also, designate a behavioral subtype of the given label that describes the current social interaction based on what you see about the posture of the mice and "\327                        "how they are positioned with respect to each other. Usually, the body parts (i.e., tail, genitals, face, body, ears, paws)" \328                        "of the mice that are closest to each other will give some clue. Please limit behavioral subtype to a 1-4 word phrase. limit your response to 4 sentences."329            with st.spinner("Loading LLaVA model. This can take 10 to 30 minutes. Please wait..."):330                tokenizer, model, image_processor = load_llava_model()331            response = ask_question_with_image_llava(image, system_prompt, question,332                                                     tokenizer, model, image_processor)333            st.markdown(response)334            335        elif len(custom_data) > 1:336            image_array = [get_image(io_reader, f_no) for f_no in custom_data]337            label_array = [train_labels[f_no] for f_no in custom_data]338            response = ask_summary_question(image_array, label_array, api_key)339            st.markdown(response)340