מודל TimesFM של צוות המחקר של Google הוא מודל בסיסי ליצירת תחזיות של סדרות זמנים. הוא עבר אימון מראש על מיליארדי נקודות זמן ממערכי נתונים רבים מהעולם האמיתי, כך שאפשר להחיל אותו על מערכי נתונים חדשים של תחזיות בתחומים רבים.
במדריך הזה נסביר איך לפרוס את TimesFM ב-GDC Sandbox. המדריך כולל את המטרות הבאות.
- יוצרים קונטיינר Docker שמריץ TimesFM,
- פריסת הקונטיינר באמצעות מעבדי GPU שסופקו על ידי מק"ט של GDC Sandbox שמותאם ל-AI, ו
- הפעלת פונקציות TimesFM באמצעות בקשות HTTP פשוטות.
לפני שמתחילים
ה-GPU ב-GDC Sandbox נכללים באשכול org-infra.
כדי להריץ פקודות מול אשכול התשתית של הארגון, צריך לוודא שיש לכם את קובץ ה-kubeconfig של אשכול
org-1-infra, כמו שמתואר במאמר עבודה עם אשכולות:- להגדיר ולאמת באמצעות שורת הפקודה
gdcloud, וגם - יוצרים את קובץ ה-kubeconfig עבור אשכול התשתית של הארגון, ומקצים את הנתיב שלו למשתנה הסביבה
KUBECONFIG.
- להגדיר ולאמת באמצעות שורת הפקודה
מוודאים שהוקצה למשתמש התפקיד
sandbox-gpu-adminבפרויקטsandbox-gpu-project. כברירת מחדל, התפקיד מוקצה למשתמשplatform-admin. כדי להקצות את התפקיד למשתמשים אחרים, צריך להיכנס לחשבון בתורplatform-adminולהריץ את הפקודה הבאה:kubectl --kubeconfig ${KUBECONFIG} create rolebinding ${NAME} --role=sandbox-gpu-admin \ --user=${USER} --namespace=sandbox-gpu-projectחשוב להגדיר מאגר Artifact Registry כמו שמתואר במאמר שימוש ב-Artifact Registry ולהיכנס לחשבון כדי להעביר בדחיפה ולמשוך קובצי אימג' ל-Artifact Registry.
פריסת מודל TimesFM
הפריסה מתבצעת באמצעות קבוצה של קובצי הגדרות של Kubernetes (מניפסטים של YAML), שכל אחד מהם מגדיר רכיב או שירות ספציפיים.
יוצרים סקריפט Python מבוסס-Flask
app.pyעם פונקציותpredictלחיזוי סדרות זמן וtimeseriesליצירת תצוגה חזותית על סמך נתוני הבדיקה.from flask import Flask, jsonify, request import numpy as np import pandas as pd from sklearn.preprocessing import StandardScaler # Initialize Flask application app = Flask(__name__) # Sample route to display a welcome message @app.route('/') def home(): return "Welcome to TimesFM! Use the API to interact with the app." # Example route for predictions (TimesFM might do time-series forecasting or music recommendations) @app.route('/predict', methods=['POST']) def predict(): data = request.get_json() # Ensure the data is in the right format if 'features' not in data: return jsonify({'error': 'No features provided'}), 400 # For this example, assume 'features' is a list of numbers that need to be scaled features = data['features'] features = np.array(features).reshape(1, -1) # Dummy model: Apply standard scaling (you would use an actual model here) scaler = StandardScaler() scaled_features = scaler.fit_transform(features) # You would normally load your model here (e.g., using pickle or joblib) # For simplicity, let's just return the scaled features as a placeholder for prediction result = scaled_features.tolist() return jsonify({'scaled_features': result}) # Example of a route for data visualization or analysis @app.route('/timeseries', methods=['GET']) def timeseries_analysis(): # Generate a dummy time series data (replace with actual data) time_series_data = pd.Series(np.random.randn(100), name="Random Data") # Example analysis: compute simple moving average moving_avg = time_series_data.rolling(window=10).mean() return jsonify({ 'time_series': time_series_data.tolist(), 'moving_average': moving_avg.tolist() }) # Run the app if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)יוצרים קובץ Dockerfile עם
timesfmמותקן שמפעיל את האפליקציה.# Use a base image with Python installed FROM python:3.11-slim # Set the working directory inside the container WORKDIR /app # Copy the requirements.txt (if any) and install dependencies COPY requirements.txt . RUN pip install --no-cache-dir numpy pandas timesfm huggingface_hub jax pytest flask scikit-learn # Copy the rest of the code into the container COPY . . # Expose the necessary port (default 5000 or whatever your app uses) EXPOSE 5000 # Define the entrypoint for the container CMD ["python", "app.py"] # Replace with the correct entry script for TimesFMיוצרים את קובץ האימג' של Docker ומעלים אותו למאגר ב-Artifact Registry.
docker build -t timesfm . docker tag timesfm "REGISTRY_REPOSITORY_URL"/timesfm:latest docker push "REGISTRY_REPOSITORY_URL"/timesfm:latestמחליפים את מה שכתוב בשדות הבאים:
-
REGISTRY_REPOSITORY_URL: כתובת ה-URL של המאגר.
-
יוצרים סוד כדי לשמור את פרטי הכניסה של Docker.
export SECRET="DOCKER_REGISTRY_SECRET" export DOCKER_TEST_CONFIG=~/.docker/config.json kubectl --kubeconfig ${KUBECONFIG} create secret docker-registry ${SECRET} --from-file=.dockerconfigjson=${DOCKER_TEST_CONFIG} -n sandbox-gpu-projectמחליפים את מה שכתוב בשדות הבאים:
-
DOCKER_REGISTRY_SECRETשם הסוד.
-
יוצרים קובץ
timesfm-deployment.yamlכדי לפרוס אתtimesfm.הפריסה של בקשות השרת
timesfmדורשת GPU אחד.apiVersion: apps/v1 kind: Deployment metadata: name: timesfm-deployment namespace: sandbox-gpu-project labels: app: timesfm spec: replicas: 1 # You can scale up depending on your needs selector: matchLabels: app: timesfm template: metadata: labels: app: timesfm spec: containers: - name: timesfm image: REGISTRY_REPOSITORY_URL/timesfm:latest ports: - containerPort: 5000 resources: requests: nvidia.com/gpu-pod-NVIDIA_H100_80GB_HBM3: 1 # Request 1 GPU limits: nvidia.com/gpu-pod-NVIDIA_H100_80GB_HBM3: 1 # Limit to 1 GPU env: - name: ENV value: "production" imagePullSecrets: - name: docker-registry-secretמחליפים את מה שכתוב בשדות הבאים:
-
REGISTRY_REPOSITORY_URL: כתובת ה-URL של המאגר. -
DOCKER_REGISTRY_SECRET: שם הסוד ב-Docker.
-
יוצרים קובץ
timesfm-service.yamlכדי לחשוף את שרתtimesfmבאופן פנימי.apiVersion: v1 kind: Service metadata: name: timesfm-service spec: selector: app: timesfm ports: - protocol: TCP port: 80 # External port exposed targetPort: 5000 # Internal container port for Flask type: LoadBalancer # Use NodePort for internal accessמחילים את קובצי המניפסט.
kubectl --kubeconfig ${KUBECONFIG} apply -f timesfm-deployment.yaml kubectl --kubeconfig ${KUBECONFIG} apply -f timesfm-service.yamlמוודאים שפודים
TimesFMפועלים.kubectl --kubeconfig ${KUBECONFIG} get deployments timesfm-deployment -n sandbox-gpu-project kubectl --kubeconfig ${KUBECONFIG} get service timesfm-service -n sandbox-gpu-projectיוצרים מדיניות רשת בפרויקט כדי לאפשר תנועה נכנסת מכתובות IP חיצוניות.
kubectl --kubeconfig ${KUBECONFIG} apply -f - <<EOF apiVersion: networking.global.gdc.goog/v1 kind: ProjectNetworkPolicy metadata: namespace: sandbox-gpu-project name: allow-inbound-traffic-from-external spec: policyType: Ingress subject: subjectType: UserWorkload ingress: - from: - ipBlock: cidr: 0.0.0.0/0 EOFמריצים את הפקודה הבאה כדי לזהות את כתובת ה-IP החיצונית של שירות TimesFM. חשוב לשמור את הערך הזה כדי להשתמש בו בשלבים הבאים, שבהם תצטרכו להחליף את הערך TIMESFM_END_POINT.
kubectl --kubeconfig ${KUBECONFIG} get service timesfm-service \ -n sandbox-gpu-project -o jsonpath='{.status.loadBalancer.ingress[*].ip}'
בודקים את השירות.
כדי לקבל תחזית, שולחים נתונים לשירות באמצעות פקודה
curl, ומחליפים את TIMESFM_END_POINT בכתובת בפועל של השירות ובערכי הקלט שלכם למאפיינים. הפעולה הזו מפעילה את הפונקציהpredictשמוגדרת ב-app.py, שתבצע מניפולציה מסוימת בנתוני הקלט ותחזיר אותם בפורמט JSON.curl -X POST http://TIMESFM_END_POINT/predict -H "Content-Type: application/json" -d '{"features": [1.2, 3.4, 5.6]}'כדי לראות דוגמה להמחשת נתונים באמצעות נתונים שנוצרו באופן אקראי, שולחים בקשת curl אל /timeseries. הפעולה הזו מפעילה את פונקציית סדרת הזמן שמוגדרת בקובץ app.py, שיוצרת סדרת זמן אקראית ומבצעת עליה ניתוח של ממוצע נע.
curl http://TIMESFM_END_POINT/timeseries