Showing posts with label artificial intelligence. Show all posts
Showing posts with label artificial intelligence. Show all posts

Thursday

Python code examples for implementing an ML ensemble using Redis

 

Important Setup Note: RedisAI and RedisML are no longer actively maintained as of 2025/2026. Therefore, Pattern B has evolved into standard deployment patterns using lightweight modern tools (like ONNX Runtime or FastAPI workers coupled directly with Redis), ensuring your pipeline remains production-grade.

Pattern A: Asynchronous Parallel Processing (Redis Streams)

Best for: Heavy models (Deep Learning, large Random Forests) that need separate workers or hardware (GPUs) to compute in parallel without locking your main API.

Architecture Flow

[Client Request] 
       │
       ▼
 ┌───────────┐       XADD       ┌───────────────┐
 │  FastAPI  │ ────────────────>│ Redis Stream  │──┐ (Model 1 Worker)
 │  Gateway  │                  │(ml:requests)  │──┼─> [Model 2 Worker]
 └───────────┘                  └───────────────┘──┘ (Model 3 Worker)
       │                                                   │
       │ (Polls responses via                              │ XADD
       │  unique Request ID)                               ▼
       │                        ┌───────────────┐  ┌───────────────┐
       └────────────────────────│ Redis Hash    │<─│ Ensemble      │
                                │(ml:results:ID)│  │ Aggregator    │
                                └───────────────┘  └───────────────┘

Python Implementation

You will need redis and scikit-learn for this pattern. Run pip install redis scikit-learn.

Python
import time
import json
import uuid
import threading
import redis
from sklearn.linear_model import LogisticRegression
import numpy as np

# Connect to Redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)

# 1. API GATEWAY FUNCTION (Pushes tasks, awaits final decision)
def mock_api_gateway(features):
    request_id = str(uuid.uuid4())
    payload = {"request_id": request_id, "features": json.dumps(features)}
    
    # Broadcast to the stream
    r.xadd("ml:requests", payload)
    print(f"[API] Dispatched request {request_id}")
    
    # Poll for the ensemble aggregator's final answer
    result_key = f"ml:results:{request_id}"
    while True:
        final_decision = r.hgetall(result_key)
        if final_decision:
            r.delete(result_key) # Clean up
            return final_decision
        time.sleep(0.01) # 10ms polling backoff

# 2. MODEL WORKERS (Simulating 2 different models processing concurrently)
def run_model_worker(model_name, weight_offset):
    # Dummy local model initialization
    model = LogisticRegression()
    
    while True:
        # Read from stream (simulating listening for real-time events)
        messages = r.xread({"ml:requests": "$"}, block=100)
        if not messages:
            continue
            
        for stream, msgs in messages:
            for msg_id, data in msgs:
                req_id = data["request_id"]
                features = json.loads(data["features"])
                
                # Mock prediction: calculate probability
                raw_prob = float(np.mean(features)) * weight_offset
                prob = min(max(raw_prob, 0.0), 1.0)
                
                # Write individual prediction back to a Redis Hash unique to this request
                r.hset(f"ml:preds:{req_id}", model_name, prob)

# 3. ENSEMBLE AGGREGATOR WORKER
def run_ensemble_aggregator():
    while True:
        # Scan for active prediction hashes
        for key in r.scan_iter("ml:preds:*"):
            req_id = key.split(":")[-1]
            predictions = r.hgetall(key)
            
            # Check if both expected model workers have responded
            if len(predictions) == 2:
                prob1 = float(predictions["model_alpha"])
                prob2 = float(predictions["model_beta"])
                
                # Ensemble Logic: Simple Average
                ensemble_prob = (prob1 + prob2) / 2
                decision = "Approved" if ensemble_prob > 0.5 else "Rejected"
                
                # Publish final outcome back to API
                r.hset(f"ml:results:{req_id}", mapping={
                    "decision": decision,
                    "probability": ensemble_prob
                })
                r.delete(key) # Clear intermediate predictions

# --- TEST EXECUTION LOOP ---
if __name__ == "__main__":
    # Flush old data for clean demo
    r.flushdb()
    
    # Start background threads for workers
    threading.Thread(target=run_model_worker, args=("model_alpha", 1.2), daemon=True).start()
    threading.Thread(target=run_model_worker, args=("model_beta", 0.8), daemon=True).start()
    threading.Thread(target=run_ensemble_aggregator, daemon=True).start()
    
    time.sleep(1) # Allow workers to boot
    
    # Simulate a client checking credit features
    mock_features = [0.4, 0.6, 0.55, 0.7] 
    output = mock_api_gateway(mock_features)
    print(f"[API] Final Ensemble Response: {output}")

Pattern B: Synchronous In-Memory Processing (Pipeline)

Best for: Light-to-medium models (like Scikit-Learn or XGBoost) where raw speed matters most. Instead of threading out across streams, your API queries a centralized Redis backend using a pipeline to get all required features at once, then locally runs predictions.

Architecture Flow

[Client Request] ──> [FastAPI Server]
                         │
                         ├─> Redis Pipeline (MGET Features) 
                         │       │
                         │       ▼
                         │   [Redis In-Memory Key Store]
                         │       │ (Returns user & context features <1ms)
                         ▼       ▼
                    Executes Model 1, 2, & 3 locally
                         │
                         ▼
                    Ensemble Aggregation ──> [Return Decision]

Python Implementation

Python
import redis
import json
import numpy as np

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

# Mock some feature store data inside Redis
r.hset("features:user_99", mapping={"risk_score": "0.34", "account_age_days": "120"})
r.hset("features:merchant_44", mapping={"fraud_velocity": "0.05", "trust_rating": "0.91"})

def predict_ensemble_sync(user_id, merchant_id):
    # 1. Pipeline Feature Store Retrieval (Single network round-trip)
    pipe = r.pipeline()
    pipe.hgetall(f"features:{user_id}")
    pipe.hgetall(f"features:{merchant_44}")
    user_feats, merchant_feats = pipe.execute()
    
    # Combine feature vectors
    base_features = [
        float(user_feats["risk_score"]),
        float(user_feats["account_age_days"]) / 365.0, # normalized
        float(merchant_feats["fraud_velocity"]),
        float(merchant_feats["trust_rating"])
    ]
    
    # 2. Synchronous Local Ensemble Execution
    # Model 1: Linear rule
    pred_1 = 1.0 if base_features[0] > 0.5 else 0.0
    # Model 2: Statistical weight
    pred_2 = (base_features[3] * 0.7) + (1 - base_features[2]) * 0.3
    
    # 3. Aggregation (Ensemble Rule: Weighted Voting)
    final_score = (pred_1 * 0.4) + (pred_2 * 0.6)
    return "Flagged Fraud" if final_score < 0.5 else "Authorized"

# Test synchronous run
decision = predict_ensemble_sync("user_99", "merchant_44")
print(f"[Sync API] Ensemble Outcome: {decision}")

Pattern C: Caching Decisions (The Shield)

Regardless of whether you use Pattern A or B, you should shield your models from processing repetitive inputs using an exact signature cache lookup.

Python
import hashlib
import redis

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

def get_ensemble_decision_with_cache(user_id, context_payload):
    # Generate a deterministic cache key based on inputs
    payload_string = json.dumps(context_payload, sort_keys=True)
    payload_hash = hashlib.sha256(payload_string.encode()).hexdigest()
    cache_key = f"cache:decision:{user_id}:{payload_hash}"
    
    # 1. Hit the cache layer
    cached_decision = r.get(cache_key)
    if cached_decision:
        print("[Cache] Match found! Zero model calculation needed.")
        return json.loads(cached_decision)
        
    # 2. Cache Miss: Run your actual ensemble pipeline (from Pattern A or B)
    print("[Cache] Miss. Running full ensemble inference...")
    computed_decision = {"status": "Approved", "confidence": 0.89}
    
    # 3. Save to cache with a 60-second Time-To-Live (TTL)
    r.setex(cache_key, 60, json.dumps(computed_decision))
    return computed_decision

# Test caching execution
payload = {"amount": 250.00, "location": "NY"}
print(get_ensemble_decision_with_cache("user_99", payload))
print(get_ensemble_decision_with_cache("user_99", payload)) # Secondary call hits cache

Building a Real-Time Feature Store with Redis This video outlines Redis' architectures, illustrating how it manages massive operational throughput for contextual data architectures in modern live-serving applications.

Sunday

Hyped IPOs From Overvalued Tech COs

 

                                                                 image generated by meta ai

SpaceX Anthropic OpenAI Are all those companies which have mammoth valuations on paper but return to investors are miser.

Big tech IPOs with high valuations but low or negative returns don’t just disappoint—they drain. By swallowing enormous sums of investor money, they redirect capital away from consistently profitable companies like Samsung and Walmart, as well as smaller, well-run firms that actually deliver returns. This misallocation doesn’t only hurt those better businesses; it risks creating a negative market trend, stalling development, and ultimately paving the way for a market crash.

This is a sharp observation, and on a real tension in how capital markets function. Let me break down the mechanism you’re describing and then add some nuance about when and why it does or doesn’t lead to a market crash.

How big, low-return IPOs can harm the broader market

Your logic follows a plausible chain:

1. Capital absorption – A massive IPO (e.g., a highly valued tech company with weak or negative earnings) sucks up tens of billions of dollars from public markets. Institutional investors, ETFs, and mutual funds reallocate to get their allocation.

2. Opportunity cost – That money could have gone into established profitable companies (Samsung, Walmart, etc.) or promising smaller firms with solid fundamentals.

3. Misallocation of capital – If the IPO money goes to a company that destroys value (overpriced stock, poor returns), that capital is effectively wasted. Over time, this lowers overall market efficiency.

4. Crowding out – Good companies may see their stock prices stagnate or fall, making it harder for them to raise follow-on capital. This slows job creation, R&D, and economic growth.

In an extreme scenario, if many such IPOs happen in a bubble, and then those stocks crash, they can indeed drag down indices (since big tech has high weightings) and trigger broader selling—especially if margin calls or leveraged positions unwind.

Why this doesn’t always cause a crash (countervailing forces)

Markets have mechanisms that partially correct the problem you describe:

- Price discovery – If a big IPO is overhyped but has poor fundamentals, it often debuts strongly, then drifts down over months. Patient capital (value investors) avoids it, so the “chunk of money” isn’t as large as feared—because much of the trading is speculative, not long-term committed.

- Liquidity is not fixed – New money enters markets via savings, pensions, and central bank policies. A large IPO doesn’t necessarily “crowd out” Walmart; it may simply absorb new inflows or come at the expense of other overvalued stocks, not solid profitable ones.

- Rotation, not disappearance – When investors sell profitable companies to buy a hyped IPO, they eventually realize the mistake and rotate back. Historically, quality value stocks (Walmart, Samsung) often outperform during IPO-heavy frothy periods, because defensive investors flee to them.

- Primary vs secondary markets – IPO proceeds go to the company (which may burn it). But secondary market trading mostly just transfers ownership. The real damage happens if the IPO company later raises more cash via dilutive offerings—but that’s a separate event.

Historical examples that support your concern

- Late 1999–2000 – Dozens of money-losing tech IPOs (e.g., TheGlobe.com, VA Linux) raised billions. Capital fled profitable old-economy names. When the bubble burst, the NASDAQ fell ~78%, and many solid companies were also dragged down temporarily, though they recovered faster.

- 2021 SPAC boom – Highly speculative electric vehicle and space startups went public at huge valuations, absorbing massive capital. Many collapsed by 2023. Meanwhile, well-run profitable companies saw muted returns until the speculative froth cleared.

When it doesn’t cause a crash

If the big IPO is Truly transformative (e.g., Google 2004, Amazon 1997, though neither was “low return” at IPO), the capital is actually productive.

If the IPO happens in a High liquidity environment (central bank easing), no crowding out occurs.

If Index composition changes slowly – The new big tech company won’t enter major indices immediately (e.g., S&P 500 requires profitability for 4 quarters as of 2025 rules for certain listings), so forced buying by passive funds is delayed.

The real danger is not one IPO, but a sustained pattern

Your scenario becomes dangerous when:

- Multiple large, low-return IPOs happen back-to-back (e.g., 2021: Rivian, Robinhood, Coinbase).

- Valuations detach from fundamentals across a whole sector.

- Leverage is high – Investors borrow to buy these IPOs.

- Profitability is ignored for years – Then the unwind is brutal.

But a few big tech IPO with poor returns (e.g., Uber 2019, Lyft 2019) usually just hurts its own shareholders, not the entire market, hopefully. However, this time it is really giant size and when the market is dull due to many reasons.

Conclusion

You are correct that capital misallocation to low-return, large IPOs can reduce overall market efficiency and hurt good companies’ access to investment. Over time, this can contribute to a negative trend and, in extreme bubbles, a crash. However, markets are resilient enough that one or two such IPOs won’t collapse the system—what you’re describing is essentially the bubble dynamic seen in 2000 or 2021. The key is whether the broader market has discipline (value investors, short sellers, profitability screens) to correct the mispricing before it becomes systemic.

House Based Manufacturing Micro Clustering

                                 image generated by meta ai House-based manufacturing micro-clustering in China refers to the hyper-local, v...